aboutsummaryrefslogtreecommitdiffstats
path: root/src/libhydra
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2012-03-26 15:00:14 +0200
committerTobias Brunner <tobias@strongswan.org>2012-03-27 10:44:21 +0200
commitcaae5a5c0f8f417b95e112774cc6356c0867d98c (patch)
treec9f199218029173690b0d47bc884d0dac49d8914 /src/libhydra
parent817ab8a8d428fe4854625ee0a804701449951833 (diff)
downloadstrongswan-caae5a5c0f8f417b95e112774cc6356c0867d98c.tar.bz2
strongswan-caae5a5c0f8f417b95e112774cc6356c0867d98c.tar.xz
Added support for the resolvconf framework in resolve plugin.
If /sbin/resolvconf is found nameservers are not written directly to /etc/resolv.conf but instead resolvconf is invoked.
Diffstat (limited to 'src/libhydra')
-rw-r--r--src/libhydra/plugins/resolve/resolve_handler.c201
1 files changed, 149 insertions, 52 deletions
diff --git a/src/libhydra/plugins/resolve/resolve_handler.c b/src/libhydra/plugins/resolve/resolve_handler.c
index 62376dcc6..18e46f196 100644
--- a/src/libhydra/plugins/resolve/resolve_handler.c
+++ b/src/libhydra/plugins/resolve/resolve_handler.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -15,12 +16,20 @@
#include "resolve_handler.h"
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <hydra.h>
#include <debug.h>
#include <threading/mutex.h>
+/* path to resolvconf executable */
+#define RESOLVCONF_EXEC "/sbin/resolvconf"
+
+/* prefix used for resolvconf interfaces */
+#define RESOLVCONF_PREFIX "lo.inet.ipsec."
+
typedef struct private_resolve_handler_t private_resolve_handler_t;
/**
@@ -39,47 +48,35 @@ struct private_resolve_handler_t {
char *file;
/**
+ * use resolvconf instead of writing directly to resolv.conf
+ */
+ bool use_resolvconf;
+
+ /**
* Mutex to access file exclusively
*/
mutex_t *mutex;
};
-METHOD(attribute_handler_t, handle, bool,
- private_resolve_handler_t *this, identification_t *server,
- configuration_attribute_type_t type, chunk_t data)
+/**
+ * Writes the given nameserver to resolv.conf
+ */
+static bool write_nameserver(private_resolve_handler_t *this,
+ identification_t *server, host_t *addr)
{
FILE *in, *out;
char buf[1024];
- host_t *addr;
size_t len;
bool handled = FALSE;
- switch (type)
- {
- case INTERNAL_IP4_DNS:
- addr = host_create_from_chunk(AF_INET, data, 0);
- break;
- case INTERNAL_IP6_DNS:
- addr = host_create_from_chunk(AF_INET6, data, 0);
- break;
- default:
- return FALSE;
- }
-
- if (!addr || addr->is_anyaddr(addr))
- {
- DESTROY_IF(addr);
- return FALSE;
- }
- this->mutex->lock(this->mutex);
-
in = fopen(this->file, "r");
/* allows us to stream from in to out */
unlink(this->file);
out = fopen(this->file, "w");
if (out)
{
- fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr, server);
+ fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr,
+ server);
DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
handled = TRUE;
@@ -97,38 +94,17 @@ METHOD(attribute_handler_t, handle, bool,
{
fclose(in);
}
- this->mutex->unlock(this->mutex);
- addr->destroy(addr);
-
- if (!handled)
- {
- DBG1(DBG_IKE, "adding DNS server failed", this->file);
- }
return handled;
}
-METHOD(attribute_handler_t, release,void,
- private_resolve_handler_t *this, identification_t *server,
- configuration_attribute_type_t type, chunk_t data)
+/**
+ * Removes the given nameserver from resolv.conf
+ */
+static void remove_nameserver(private_resolve_handler_t *this,
+ identification_t *server, host_t *addr)
{
FILE *in, *out;
char line[1024], matcher[512];
- host_t *addr;
- int family;
-
- switch (type)
- {
- case INTERNAL_IP4_DNS:
- family = AF_INET;
- break;
- case INTERNAL_IP6_DNS:
- family = AF_INET6;
- break;
- default:
- return;
- }
-
- this->mutex->lock(this->mutex);
in = fopen(this->file, "r");
if (in)
@@ -138,7 +114,6 @@ METHOD(attribute_handler_t, release,void,
out = fopen(this->file, "w");
if (out)
{
- addr = host_create_from_chunk(family, data, 0);
snprintf(matcher, sizeof(matcher),
"nameserver %H # by strongSwan, from %Y\n",
addr, server);
@@ -156,13 +131,129 @@ METHOD(attribute_handler_t, release,void,
fputs(line, out);
}
}
- addr->destroy(addr);
fclose(out);
}
fclose(in);
}
+}
+
+/**
+ * Add or remove the given nameserver by invoking resolvconf.
+ */
+static bool invoke_resolvconf(private_resolve_handler_t *this,
+ identification_t *server, host_t *addr,
+ bool install)
+{
+ char cmd[128];
+
+ /* we use the nameserver's IP address as part of the interface name to
+ * make them unique */
+ if (snprintf(cmd, sizeof(cmd), "%s %s %s%H", RESOLVCONF_EXEC,
+ install ? "-a" : "-d", RESOLVCONF_PREFIX, addr) >= sizeof(cmd))
+ {
+ return FALSE;
+ }
+
+ if (install)
+ {
+ FILE *out;
+ out = popen(cmd, "w");
+ if (!out)
+ {
+ return FALSE;
+ }
+ DBG1(DBG_IKE, "installing DNS server %H via resolvconf", addr);
+ fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr,
+ server);
+ if (ferror(out) || pclose(out))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ ignore_result(system(cmd));
+ }
+ return TRUE;
+}
+
+METHOD(attribute_handler_t, handle, bool,
+ private_resolve_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ host_t *addr;
+ bool handled;
+
+ switch (type)
+ {
+ case INTERNAL_IP4_DNS:
+ addr = host_create_from_chunk(AF_INET, data, 0);
+ break;
+ case INTERNAL_IP6_DNS:
+ addr = host_create_from_chunk(AF_INET6, data, 0);
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!addr || addr->is_anyaddr(addr))
+ {
+ DESTROY_IF(addr);
+ return FALSE;
+ }
+
+ this->mutex->lock(this->mutex);
+ if (this->use_resolvconf)
+ {
+ handled = invoke_resolvconf(this, server, addr, TRUE);
+ }
+ else
+ {
+ handled = write_nameserver(this, server, addr);
+ }
+ this->mutex->unlock(this->mutex);
+ addr->destroy(addr);
+
+ if (!handled)
+ {
+ DBG1(DBG_IKE, "adding DNS server failed");
+ }
+ return handled;
+}
+
+METHOD(attribute_handler_t, release, void,
+ private_resolve_handler_t *this, identification_t *server,
+ configuration_attribute_type_t type, chunk_t data)
+{
+ host_t *addr;
+ int family;
+
+ switch (type)
+ {
+ case INTERNAL_IP4_DNS:
+ family = AF_INET;
+ break;
+ case INTERNAL_IP6_DNS:
+ family = AF_INET6;
+ break;
+ default:
+ return;
+ }
+ addr = host_create_from_chunk(family, data, 0);
+
+ this->mutex->lock(this->mutex);
+ if (this->use_resolvconf)
+ {
+ invoke_resolvconf(this, server, addr, FALSE);
+ }
+ else
+ {
+ remove_nameserver(this, server, addr);
+ }
this->mutex->unlock(this->mutex);
+
+ addr->destroy(addr);
}
/**
@@ -226,6 +317,7 @@ METHOD(resolve_handler_t, destroy, void,
resolve_handler_t *resolve_handler_create()
{
private_resolve_handler_t *this;
+ struct stat st;
INIT(this,
.public = {
@@ -241,6 +333,11 @@ resolve_handler_t *resolve_handler_create()
RESOLV_CONF, hydra->daemon),
);
+ if (stat(RESOLVCONF_EXEC, &st) == 0)
+ {
+ this->use_resolvconf = TRUE;
+ }
+
return &this->public;
}