diff options
author | Tobias Brunner <tobias@strongswan.org> | 2012-03-26 15:00:14 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2012-03-27 10:44:21 +0200 |
commit | caae5a5c0f8f417b95e112774cc6356c0867d98c (patch) | |
tree | c9f199218029173690b0d47bc884d0dac49d8914 /src/libhydra | |
parent | 817ab8a8d428fe4854625ee0a804701449951833 (diff) | |
download | strongswan-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.c | 201 |
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; } |