>>> Since Ubuntu 12.04 seems to come with resolvconf installed by default it
>>> would make sense to add support for it.  Which is what I did in the
>>> resolvconf branch of our repository (see [1]).  Would be great if you
>>> could try the patches (only [2] is really required).
>>>
>>
>> Thanks, will do and report back.
> 
> Unfortunately, sid is still at 4.5.2 and the patch doesn't apply cleanly
> against it, so I'll first try to backport it. 

The attached patch should apply cleanly to 4.5.2.

Regards,
Tobias
>From 1ad1c0f41311296d22fa183a7b7cba0b97dc03b3 Mon Sep 17 00:00:00 2001
From: Tobias Brunner <tob...@strongswan.org>
Date: Mon, 26 Mar 2012 15:00:14 +0200
Subject: [PATCH] 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.
---
 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 feb2fd0..21bc3af 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,49 +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;
 };
 
 /**
- * Implementation of attribute_handler_t.handle
+ * Writes the given nameserver to resolv.conf
  */
-static bool handle(private_resolve_handler_t *this, identification_t *server,
-				   configuration_attribute_type_t type, chunk_t data)
+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;
 
@@ -99,40 +94,17 @@ static bool handle(private_resolve_handler_t *this, identification_t *server,
 	{
 		fclose(in);
 	}
-	this->mutex->unlock(this->mutex);
-	addr->destroy(addr);
-
-	if (!handled)
-	{
-		DBG1(DBG_IKE, "adding DNS server failed", this->file);
-	}
 	return handled;
 }
 
 /**
- * Implementation of attribute_handler_t.release
+ * Removes the given nameserver from resolv.conf
  */
-static void release(private_resolve_handler_t *this, identification_t *server,
-					configuration_attribute_type_t type, chunk_t data)
+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)
@@ -142,7 +114,6 @@ static void release(private_resolve_handler_t *this, identification_t *server,
 		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);
@@ -160,13 +131,133 @@ static void release(private_resolve_handler_t *this, identification_t *server,
 					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;
+}
+
+/**
+ * Implementation of attribute_handler_t.handle
+ */
+static bool handle(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;
+}
+
+/**
+ * Implementation of attribute_handler_t.release
+ */
+static void release(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);
 }
 
 /**
@@ -237,6 +328,7 @@ static void destroy(private_resolve_handler_t *this)
 resolve_handler_t *resolve_handler_create()
 {
 	private_resolve_handler_t *this = malloc_thing(private_resolve_handler_t);
+	struct stat st;
 
 	this->public.handler.handle = (bool(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))handle;
 	this->public.handler.release = (void(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
@@ -247,6 +339,11 @@ resolve_handler_t *resolve_handler_create()
 	this->file = lib->settings->get_str(lib->settings,
 								"%s.plugins.resolve.file", RESOLV_CONF, hydra->daemon);
 
+	if (stat(RESOLVCONF_EXEC, &st) == 0)
+	{
+		this->use_resolvconf = TRUE;
+	}
+
 	return &this->public;
 }
 
-- 
1.7.4.1

Reply via email to