@@ -168,7 +168,7 @@ configuration.
::
dns search-domains domain [domain ...]
- dns server n address addr[:port] [addr[:port]]
+ dns server n address addr[:port] [addr[:port] ...]
dns server n resolve-domains|exclude-domains domain [domain ...]
dns server n dnssec yes|optional|no
dns server n transport DoH|DoT|plain
@@ -186,9 +186,10 @@ configuration.
lower numbers come first. DNS servers being pushed to a client replace
already configured DNS servers with the same server id.
- The ``address`` option configures the IPv4 and / or IPv6 address of
- the DNS server. Optionally a port can be appended after a colon. IPv6
- addresses need to be enclosed in brackets if a port is appended.
+ The ``address`` option configures the IPv4 and / or IPv6 address(es) of
+ the DNS server. Up to eight addresses can be specified per DNS server.
+ Optionally a port can be appended after a colon. IPv6 addresses need to
+ be enclosed in brackets if a port is appended.
The ``resolve-domains`` and ``exclude-domains`` options take one or
more DNS domains which are explicitly resolved or explicitly not resolved
@@ -660,10 +660,8 @@ instances.
::
dns_search_domain_{n}
- dns_server_{n}_address4
- dns_server_{n}_port4
- dns_server_{n}_address6
- dns_server_{n}_port6
+ dns_server_{n}_address_{m}
+ dns_server_{n}_port_{m}
dns_server_{n}_resolve_domain_{m}
dns_server_{n}_exclude_domain_{m}
dns_server_{n}_dnssec
@@ -64,7 +64,7 @@ dns_server_addr_parse(struct dns_server *server, const char *addr)
char addrcopy[INET6_ADDRSTRLEN] = {0};
size_t copylen = 0;
in_port_t port = 0;
- int af;
+ sa_family_t af;
char *first_colon = strchr(addr, ':');
char *last_colon = strrchr(addr, ':');
@@ -115,21 +115,26 @@ dns_server_addr_parse(struct dns_server *server, const char *addr)
return false;
}
+ if (server->addr_count >= SIZE(server->addr))
+ {
+ return false;
+ }
+
if (ai->ai_family == AF_INET)
{
struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
- server->addr4_defined = true;
- server->addr4.s_addr = ntohl(sin->sin_addr.s_addr);
- server->port4 = port;
+ server->addr[server->addr_count].in.a4.s_addr = ntohl(sin->sin_addr.s_addr);
}
else
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
- server->addr6_defined = true;
- server->addr6 = sin6->sin6_addr;
- server->port6 = port;
+ server->addr[server->addr_count].in.a6 = sin6->sin6_addr;
}
+ server->addr[server->addr_count].family = af;
+ server->addr[server->addr_count].port = port;
+ server->addr_count += 1;
+
freeaddrinfo(ai);
return true;
}
@@ -197,7 +202,7 @@ dns_options_verify(int msglevel, const struct dns_options *o)
o->servers ? o->servers : o->servers_prepull;
while (server)
{
- if (!server->addr4_defined && !server->addr6_defined)
+ if (server->addr_count == 0)
{
msg(msglevel, "ERROR: dns server %ld does not have an address assigned", server->priority);
return false;
@@ -376,26 +381,23 @@ setenv_dns_options(const struct dns_options *o, struct env_set *es)
for (i = 1, s = o->servers; s != NULL; i++, s = s->next)
{
- if (s->addr4_defined)
- {
- setenv_dns_option(es, "dns_server_%d_address4", i, -1,
- print_in_addr_t(s->addr4.s_addr, 0, &gc));
- }
- if (s->port4)
- {
- setenv_dns_option(es, "dns_server_%d_port4", i, -1,
- print_in_port_t(s->port4, &gc));
- }
-
- if (s->addr6_defined)
- {
- setenv_dns_option(es, "dns_server_%d_address6", i, -1,
- print_in6_addr(s->addr6, 0, &gc));
- }
- if (s->port6)
+ for (j = 0; j < s->addr_count; ++j)
{
- setenv_dns_option(es, "dns_server_%d_port6", i, -1,
- print_in_port_t(s->port6, &gc));
+ if (s->addr[j].family == AF_INET)
+ {
+ setenv_dns_option(es, "dns_server_%d_address_%d", i, j + 1,
+ print_in_addr_t(s->addr[j].in.a4.s_addr, 0, &gc));
+ }
+ else
+ {
+ setenv_dns_option(es, "dns_server_%d_address_%d", i, j + 1,
+ print_in6_addr(s->addr[j].in.a6, 0, &gc));
+ }
+ if (s->addr[j].port)
+ {
+ setenv_dns_option(es, "dns_server_%d_port_%d", i, j + 1,
+ print_in_port_t(s->addr[j].port, &gc));
+ }
}
if (s->domains)
@@ -439,30 +441,29 @@ show_dns_options(const struct dns_options *o)
{
msg(D_SHOW_PARMS, " DNS server #%d:", i++);
- if (server->addr4_defined)
+ for (int j = 0; j < server->addr_count; ++j)
{
- const char *addr = print_in_addr_t(server->addr4.s_addr, 0, &gc);
- if (server->port4)
+ const char *addr;
+ const char *fmt_port;
+ if (server->addr[j].family == AF_INET)
{
- const char *port = print_in_port_t(server->port4, &gc);
- msg(D_SHOW_PARMS, " address4 = %s:%s", addr, port);
+ addr = print_in_addr_t(server->addr[j].in.a4.s_addr, 0, &gc);
+ fmt_port = " address = %s:%s";
}
else
{
- msg(D_SHOW_PARMS, " address4 = %s", addr);
+ addr = print_in6_addr(server->addr[j].in.a6, 0, &gc);
+ fmt_port = " address = [%s]:%s";
}
- }
- if (server->addr6_defined)
- {
- const char *addr = print_in6_addr(server->addr6, 0, &gc);
- if (server->port6)
+
+ if (server->addr[j].port)
{
- const char *port = print_in_port_t(server->port6, &gc);
- msg(D_SHOW_PARMS, " address6 = [%s]:%s", addr, port);
+ const char *port = print_in_port_t(server->addr[j].port, &gc);
+ msg(D_SHOW_PARMS, fmt_port, addr, port);
}
else
{
- msg(D_SHOW_PARMS, " address6 = %s", addr);
+ msg(D_SHOW_PARMS, " address = %s", addr);
}
}
@@ -52,15 +52,21 @@ struct dns_domain {
const char *name;
};
+struct dns_server_addr
+{
+ union {
+ struct in_addr a4;
+ struct in6_addr a6;
+ } in;
+ sa_family_t family;
+ in_port_t port;
+};
+
struct dns_server {
struct dns_server *next;
long priority;
- bool addr4_defined;
- bool addr6_defined;
- struct in_addr addr4;
- struct in6_addr addr6;
- in_port_t port4;
- in_port_t port6;
+ size_t addr_count;
+ struct dns_server_addr addr[8];
struct dns_domain *domains;
enum dns_domain_type domain_type;
enum dns_security dnssec;
@@ -512,7 +512,7 @@ static const char usage_message[] =
" each filter is applied in the order of appearance.\n"
"--dns server <n> <option> <value> [value ...] : Configure option for DNS server #n\n"
" Valid options are :\n"
- " address <addr[:port]> [addr[:port]] : server address 4/6\n"
+ " address <addr[:port]> [addr[:port] ...] : server addresses 4/6\n"
" resolve-domains <domain> [domain ...] : split domains\n"
" exclude-domains <domain> [domain ...] : domains not to resolve\n"
" dnssec <yes|no|optional> : option to use DNSSEC\n"
@@ -1387,21 +1387,26 @@ tuntap_options_copy_dns(struct options *o)
const struct dns_server *server = dns->servers;
while (server)
{
- if (server->addr4_defined && tt->dns_len < N_DHCP_ADDR)
+ for (int i = 0; i < server->addr_count; ++i)
{
- tt->dns[tt->dns_len++] = server->addr4.s_addr;
- }
- else
- {
- overflow = true;
- }
- if (server->addr6_defined && tt->dns6_len < N_DHCP_ADDR)
- {
- tt->dns6[tt->dns6_len++] = server->addr6;
- }
- else
- {
- overflow = true;
+ if (server->addr[i].family == AF_INET)
+ {
+ if (tt->dns_len >= N_DHCP_ADDR)
+ {
+ overflow = true;
+ continue;
+ }
+ tt->dns[tt->dns_len++] = server->addr[i].in.a4.s_addr;
+ }
+ else
+ {
+ if (tt->dns6_len >= N_DHCP_ADDR)
+ {
+ overflow = true;
+ continue;
+ }
+ tt->dns6[tt->dns6_len++] = server->addr[i].in.a6;
+ }
}
server = server->next;
}
@@ -1448,23 +1453,26 @@ foreign_options_copy_dns(struct options *o, struct env_set *es)
while (server)
{
- if (server->addr4_defined)
- {
- const char *argv[] = {
- "dhcp-option",
- "DNS",
- print_in_addr_t(server->addr4.s_addr, 0, &gc)
- };
- setenv_foreign_option(o, argv, 3, es);
- }
- if (server->addr6_defined)
+ for (int i = 0; i < server->addr_count; ++i)
{
- const char *argv[] = {
- "dhcp-option",
- "DNS6",
- print_in6_addr(server->addr6, 0, &gc)
- };
- setenv_foreign_option(o, argv, 3, es);
+ if (server->addr[i].family == AF_INET)
+ {
+ const char *argv[] = {
+ "dhcp-option",
+ "DNS",
+ print_in_addr_t(server->addr[i].in.a4.s_addr, 0, &gc)
+ };
+ setenv_foreign_option(o, argv, 3, es);
+ }
+ else
+ {
+ const char *argv[] = {
+ "dhcp-option",
+ "DNS6",
+ print_in6_addr(server->addr[i].in.a6, 0, &gc)
+ };
+ setenv_foreign_option(o, argv, 3, es);
+ }
}
server = server->next;
}
@@ -8001,13 +8009,13 @@ add_option(struct options *options,
struct dns_server *server = dns_server_get(&options->dns_options.servers, priority, &options->dns_options.gc);
- if (streq(p[3], "address") && !p[6])
+ if (streq(p[3], "address") && p[4])
{
- for (int i = 4; p[i]; i++)
+ for (int i = 4; p[i]; ++i)
{
if (!dns_server_addr_parse(server, p[i]))
{
- msg(msglevel, "--dns server %ld: malformed or duplicate address '%s'", priority, p[i]);
+ msg(msglevel, "--dns server %ld: malformed address or maximum exceeded '%s'", priority, p[i]);
goto err;
}
}