resolve: Add refcounting for installed DNS servers
This fixes DNS server installation if make-before-break reauthentication is used as there the new SA and DNS server is installed before it then is removed again when the old IKE_SA is torn down.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/process.h>
|
#include <utils/process.h>
|
||||||
|
#include <collections/array.h>
|
||||||
#include <threading/mutex.h>
|
#include <threading/mutex.h>
|
||||||
|
|
||||||
/* path to resolvconf executable */
|
/* path to resolvconf executable */
|
||||||
@@ -48,12 +49,12 @@ struct private_resolve_handler_t {
|
|||||||
char *file;
|
char *file;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* use resolvconf instead of writing directly to resolv.conf
|
* Use resolvconf instead of writing directly to resolv.conf
|
||||||
*/
|
*/
|
||||||
bool use_resolvconf;
|
bool use_resolvconf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* prefix to be used for interface names sent to resolvconf
|
* Prefix to be used for interface names sent to resolvconf
|
||||||
*/
|
*/
|
||||||
char *iface_prefix;
|
char *iface_prefix;
|
||||||
|
|
||||||
@@ -61,13 +62,55 @@ struct private_resolve_handler_t {
|
|||||||
* Mutex to access file exclusively
|
* Mutex to access file exclusively
|
||||||
*/
|
*/
|
||||||
mutex_t *mutex;
|
mutex_t *mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference counting for DNS servers dns_server_t
|
||||||
|
*/
|
||||||
|
array_t *servers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference counting for DNS servers
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DNS server address
|
||||||
|
*/
|
||||||
|
host_t *server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference count
|
||||||
|
*/
|
||||||
|
u_int refcount;
|
||||||
|
|
||||||
|
} dns_server_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare a server and a stored reference
|
||||||
|
*/
|
||||||
|
static int dns_server_find(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
host_t *server = (host_t*)a;
|
||||||
|
dns_server_t *item = (dns_server_t*)b;
|
||||||
|
return chunk_compare(server->get_address(server),
|
||||||
|
item->server->get_address(item->server));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort references by DNS server
|
||||||
|
*/
|
||||||
|
static int dns_server_sort(const void *a, const void *b, void *user)
|
||||||
|
{
|
||||||
|
const dns_server_t *da = a, *db = b;
|
||||||
|
return chunk_compare(da->server->get_address(da->server),
|
||||||
|
db->server->get_address(db->server));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the given nameserver to resolv.conf
|
* Writes the given nameserver to resolv.conf
|
||||||
*/
|
*/
|
||||||
static bool write_nameserver(private_resolve_handler_t *this,
|
static bool write_nameserver(private_resolve_handler_t *this, host_t *addr)
|
||||||
identification_t *server, host_t *addr)
|
|
||||||
{
|
{
|
||||||
FILE *in, *out;
|
FILE *in, *out;
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@@ -80,8 +123,7 @@ static bool write_nameserver(private_resolve_handler_t *this,
|
|||||||
out = fopen(this->file, "w");
|
out = fopen(this->file, "w");
|
||||||
if (out)
|
if (out)
|
||||||
{
|
{
|
||||||
fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr,
|
fprintf(out, "nameserver %H # by strongSwan\n", addr);
|
||||||
server);
|
|
||||||
DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
|
DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
|
||||||
handled = TRUE;
|
handled = TRUE;
|
||||||
|
|
||||||
@@ -105,8 +147,7 @@ static bool write_nameserver(private_resolve_handler_t *this,
|
|||||||
/**
|
/**
|
||||||
* Removes the given nameserver from resolv.conf
|
* Removes the given nameserver from resolv.conf
|
||||||
*/
|
*/
|
||||||
static void remove_nameserver(private_resolve_handler_t *this,
|
static void remove_nameserver(private_resolve_handler_t *this, host_t *addr)
|
||||||
identification_t *server, host_t *addr)
|
|
||||||
{
|
{
|
||||||
FILE *in, *out;
|
FILE *in, *out;
|
||||||
char line[1024], matcher[512];
|
char line[1024], matcher[512];
|
||||||
@@ -120,8 +161,7 @@ static void remove_nameserver(private_resolve_handler_t *this,
|
|||||||
if (out)
|
if (out)
|
||||||
{
|
{
|
||||||
snprintf(matcher, sizeof(matcher),
|
snprintf(matcher, sizeof(matcher),
|
||||||
"nameserver %H # by strongSwan, from %Y\n",
|
"nameserver %H # by strongSwan\n", addr);
|
||||||
addr, server);
|
|
||||||
|
|
||||||
/* copy all, but matching line */
|
/* copy all, but matching line */
|
||||||
while (fgets(line, sizeof(line), in))
|
while (fgets(line, sizeof(line), in))
|
||||||
@@ -145,8 +185,7 @@ static void remove_nameserver(private_resolve_handler_t *this,
|
|||||||
/**
|
/**
|
||||||
* Add or remove the given nameserver by invoking resolvconf.
|
* Add or remove the given nameserver by invoking resolvconf.
|
||||||
*/
|
*/
|
||||||
static bool invoke_resolvconf(private_resolve_handler_t *this,
|
static bool invoke_resolvconf(private_resolve_handler_t *this, host_t *addr,
|
||||||
identification_t *server, host_t *addr,
|
|
||||||
bool install)
|
bool install)
|
||||||
{
|
{
|
||||||
process_t *process;
|
process_t *process;
|
||||||
@@ -219,7 +258,7 @@ static bool invoke_resolvconf(private_resolve_handler_t *this,
|
|||||||
{
|
{
|
||||||
if (install)
|
if (install)
|
||||||
{ /* revert changes when installing fails */
|
{ /* revert changes when installing fails */
|
||||||
invoke_resolvconf(this, server, addr, FALSE);
|
invoke_resolvconf(this, addr, FALSE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +269,7 @@ METHOD(attribute_handler_t, handle, bool,
|
|||||||
private_resolve_handler_t *this, ike_sa_t *ike_sa,
|
private_resolve_handler_t *this, ike_sa_t *ike_sa,
|
||||||
configuration_attribute_type_t type, chunk_t data)
|
configuration_attribute_type_t type, chunk_t data)
|
||||||
{
|
{
|
||||||
identification_t *server;
|
dns_server_t *found = NULL;
|
||||||
host_t *addr;
|
host_t *addr;
|
||||||
bool handled;
|
bool handled;
|
||||||
|
|
||||||
@@ -251,16 +290,34 @@ METHOD(attribute_handler_t, handle, bool,
|
|||||||
DESTROY_IF(addr);
|
DESTROY_IF(addr);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
server = ike_sa->get_other_id(ike_sa);
|
|
||||||
|
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
if (this->use_resolvconf)
|
if (array_bsearch(this->servers, addr, dns_server_find, &found) == -1)
|
||||||
{
|
{
|
||||||
handled = invoke_resolvconf(this, server, addr, TRUE);
|
if (this->use_resolvconf)
|
||||||
|
{
|
||||||
|
handled = invoke_resolvconf(this, addr, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handled = write_nameserver(this, addr);
|
||||||
|
}
|
||||||
|
if (handled)
|
||||||
|
{
|
||||||
|
INIT(found,
|
||||||
|
.server = addr->clone(addr),
|
||||||
|
.refcount = 1,
|
||||||
|
);
|
||||||
|
array_insert_create(&this->servers, ARRAY_TAIL, found);
|
||||||
|
array_sort(this->servers, dns_server_sort, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
handled = write_nameserver(this, server, addr);
|
DBG1(DBG_IKE, "DNS server %H already installed, increasing refcount",
|
||||||
|
addr);
|
||||||
|
found->refcount++;
|
||||||
|
handled = TRUE;
|
||||||
}
|
}
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
addr->destroy(addr);
|
addr->destroy(addr);
|
||||||
@@ -276,9 +333,9 @@ METHOD(attribute_handler_t, release, void,
|
|||||||
private_resolve_handler_t *this, ike_sa_t *ike_sa,
|
private_resolve_handler_t *this, ike_sa_t *ike_sa,
|
||||||
configuration_attribute_type_t type, chunk_t data)
|
configuration_attribute_type_t type, chunk_t data)
|
||||||
{
|
{
|
||||||
identification_t *server;
|
dns_server_t *found = NULL;
|
||||||
host_t *addr;
|
host_t *addr;
|
||||||
int family;
|
int family, idx;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@@ -292,16 +349,30 @@ METHOD(attribute_handler_t, release, void,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
addr = host_create_from_chunk(family, data, 0);
|
addr = host_create_from_chunk(family, data, 0);
|
||||||
server = ike_sa->get_other_id(ike_sa);
|
|
||||||
|
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
if (this->use_resolvconf)
|
idx = array_bsearch(this->servers, addr, dns_server_find, &found);
|
||||||
|
if (idx != -1)
|
||||||
{
|
{
|
||||||
invoke_resolvconf(this, server, addr, FALSE);
|
if (--found->refcount > 0)
|
||||||
}
|
{
|
||||||
else
|
DBG1(DBG_IKE, "DNS server %H still used, decreasing refcount",
|
||||||
{
|
addr);
|
||||||
remove_nameserver(this, server, addr);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (this->use_resolvconf)
|
||||||
|
{
|
||||||
|
invoke_resolvconf(this, addr, FALSE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remove_nameserver(this, addr);
|
||||||
|
}
|
||||||
|
array_remove(this->servers, idx, NULL);
|
||||||
|
found->server->destroy(found->server);
|
||||||
|
free(found);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
|
|
||||||
@@ -384,6 +455,7 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
|
|||||||
METHOD(resolve_handler_t, destroy, void,
|
METHOD(resolve_handler_t, destroy, void,
|
||||||
private_resolve_handler_t *this)
|
private_resolve_handler_t *this)
|
||||||
{
|
{
|
||||||
|
array_destroy(this->servers);
|
||||||
this->mutex->destroy(this->mutex);
|
this->mutex->destroy(this->mutex);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user