::
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
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
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, ':');
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;
}
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;
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)
{
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);
}
}
" 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"
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;
}
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;
}
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;
}
}