resolve: Don't install individual servers via resolvconf

The resolvconf implementation provided by systemd via resolvectl strips
everything after the interface name, so each additional server that's
installed replaces the previous one.  And even for other resolvconf
implementations installing them individually doesn't seem necessary as
we track and refcount them anyway.

Closes strongswan/strongswan#1353
This commit is contained in:
Tobias Brunner
2022-12-19 16:14:25 +01:00
parent bd6014a97b
commit 17fd304e60
2 changed files with 50 additions and 56 deletions
+6 -7
View File
@@ -1,14 +1,13 @@
charon.plugins.resolve.file = /etc/resolv.conf charon.plugins.resolve.file = /etc/resolv.conf
File where to add DNS server entries if not using resolvconf(8). File where to add DNS server entries if not using resolvconf(8).
charon.plugins.resolve.resolvconf.iface_prefix = lo.ipsec charon.plugins.resolve.resolvconf.iface = lo.ipsec
Prefix used for interface names sent to resolvconf(8). Interface name/protocol sent to resolvconf(8).
Prefix used for interface names sent to **resolvconf**(8). The nameserver The interface name and protocol sent to **resolvconf**(8). This has to be a
address is appended to this prefix to make it unique. The result has to be valid interface name according to the rules defined by resolvconf. Also, it
a valid interface name according to the rules defined by resolvconf. Also, should have a high priority according to the order defined in
it should have a high priority according to the order defined in **interface-order**(5) if relevant on the system.
**interface-order**(5).
charon.plugins.resolve.resolvconf.path = /sbin/resolvconf charon.plugins.resolve.resolvconf.path = /sbin/resolvconf
Path/command for resolvconf(8). Path/command for resolvconf(8).
+44 -49
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012-2016 Tobias Brunner * Copyright (C) 2012-2022 Tobias Brunner
* Copyright (C) 2009 Martin Willi * Copyright (C) 2009 Martin Willi
* *
* Copyright (C) secunet Security Networks AG * Copyright (C) secunet Security Networks AG
@@ -29,8 +29,8 @@
/* path to resolvconf executable */ /* path to resolvconf executable */
#define RESOLVCONF_EXEC "/sbin/resolvconf" #define RESOLVCONF_EXEC "/sbin/resolvconf"
/* default prefix used for resolvconf interfaces (should have high prio) */ /* default interface/protocol used for resolvconf (should have high prio) */
#define RESOLVCONF_PREFIX "lo.ipsec" #define RESOLVCONF_IFACE "lo.ipsec"
typedef struct private_resolve_handler_t private_resolve_handler_t; typedef struct private_resolve_handler_t private_resolve_handler_t;
@@ -55,9 +55,9 @@ struct private_resolve_handler_t {
char *resolvconf; char *resolvconf;
/** /**
* Prefix to be used for interface names sent to resolvconf * Interface name sent to resolvconf
*/ */
char *iface_prefix; char *iface;
/** /**
* Mutex to access file exclusively * Mutex to access file exclusively
@@ -184,39 +184,33 @@ static void remove_nameserver(private_resolve_handler_t *this, host_t *addr)
} }
/** /**
* Add or remove the given nameserver by invoking resolvconf. * Install the given nameservers by invoking resolvconf. If the array is empty,
* remove the config.
*/ */
static bool invoke_resolvconf(private_resolve_handler_t *this, host_t *addr, static bool invoke_resolvconf(private_resolve_handler_t *this, array_t *servers)
bool install)
{ {
process_t *process; process_t *process;
dns_server_t *dns;
FILE *shell; FILE *shell;
char buf[BUF_LEN]; int in, out, retval, i;
int in, out, retval;
if (snprintf(buf, sizeof(buf), "%H", addr) >= sizeof(buf))
{
return FALSE;
}
translate(buf, ".:", "__");
/* we use the nameserver's IP address as part of the interface name to
* make them unique */
process = process_start_shell(NULL, install ? &in : NULL, &out, NULL,
"2>&1 %s %s %s%s", this->resolvconf,
install ? "-a" : "-d", this->iface_prefix, buf);
process = process_start_shell(NULL, array_count(servers) ? &in : NULL, &out,
NULL, "2>&1 %s %s %s", this->resolvconf,
array_count(servers) ? "-a" : "-d", this->iface);
if (!process) if (!process)
{ {
return FALSE; return FALSE;
} }
if (install) if (array_count(servers))
{ {
shell = fdopen(in, "w"); shell = fdopen(in, "w");
if (shell) if (shell)
{ {
DBG1(DBG_IKE, "installing DNS server %H via resolvconf", addr); for (i = 0; i < array_count(servers); i++)
fprintf(shell, "nameserver %H\n", addr); {
array_get(servers, i, &dns);
fprintf(shell, "nameserver %H\n", dns->server);
}
fclose(shell); fclose(shell);
} }
else else
@@ -229,7 +223,7 @@ static bool invoke_resolvconf(private_resolve_handler_t *this, host_t *addr,
} }
else else
{ {
DBG1(DBG_IKE, "removing DNS server %H via resolvconf", addr); DBG1(DBG_IKE, "removing DNS servers via resolvconf");
} }
shell = fdopen(out, "r"); shell = fdopen(out, "r");
if (shell) if (shell)
@@ -262,15 +256,7 @@ static bool invoke_resolvconf(private_resolve_handler_t *this, host_t *addr,
{ {
close(out); close(out);
} }
if (!process->wait(process, &retval) || retval != EXIT_SUCCESS) return process->wait(process, &retval) && retval == EXIT_SUCCESS;
{
if (install)
{ /* revert changes when installing fails */
invoke_resolvconf(this, addr, FALSE);
return FALSE;
}
}
return TRUE;
} }
METHOD(attribute_handler_t, handle, bool, METHOD(attribute_handler_t, handle, bool,
@@ -302,22 +288,27 @@ METHOD(attribute_handler_t, handle, bool,
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
if (array_bsearch(this->servers, addr, dns_server_find, &found) == -1) if (array_bsearch(this->servers, addr, dns_server_find, &found) == -1)
{ {
INIT(found,
.server = addr->clone(addr),
.refcount = 1,
);
array_insert_create(&this->servers, ARRAY_TAIL, found);
array_sort(this->servers, dns_server_sort, NULL);
if (this->resolvconf) if (this->resolvconf)
{ {
handled = invoke_resolvconf(this, addr, TRUE); DBG1(DBG_IKE, "installing DNS server %H via resolvconf", addr);
handled = invoke_resolvconf(this, this->servers);
} }
else else
{ {
handled = write_nameserver(this, addr); handled = write_nameserver(this, addr);
} }
if (handled) if (!handled)
{ {
INIT(found, array_remove(this->servers, ARRAY_TAIL, NULL);
.server = addr->clone(addr), found->server->destroy(found->server);
.refcount = 1, free(found);
);
array_insert_create(&this->servers, ARRAY_TAIL, found);
array_sort(this->servers, dns_server_sort, NULL);
} }
} }
else else
@@ -369,17 +360,19 @@ METHOD(attribute_handler_t, release, void,
} }
else else
{ {
array_remove(this->servers, idx, NULL);
found->server->destroy(found->server);
free(found);
if (this->resolvconf) if (this->resolvconf)
{ {
invoke_resolvconf(this, addr, FALSE); DBG1(DBG_IKE, "removing DNS server %H via resolvconf", addr);
invoke_resolvconf(this, this->servers);
} }
else else
{ {
remove_nameserver(this, addr); 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);
@@ -495,9 +488,11 @@ resolve_handler_t *resolve_handler_create()
.resolvconf = lib->settings->get_str(lib->settings, .resolvconf = lib->settings->get_str(lib->settings,
"%s.plugins.resolve.resolvconf.path", "%s.plugins.resolve.resolvconf.path",
NULL, lib->ns), NULL, lib->ns),
.iface_prefix = lib->settings->get_str(lib->settings, .iface = lib->settings->get_str(lib->settings,
"%s.plugins.resolve.resolvconf.iface",
lib->settings->get_str(lib->settings,
"%s.plugins.resolve.resolvconf.iface_prefix", "%s.plugins.resolve.resolvconf.iface_prefix",
RESOLVCONF_PREFIX, lib->ns), RESOLVCONF_IFACE, lib->ns), lib->ns),
); );
if (!this->resolvconf && stat(RESOLVCONF_EXEC, &st) == 0) if (!this->resolvconf && stat(RESOLVCONF_EXEC, &st) == 0)