Compare commits

..
14 Commits
Author SHA1 Message Date
Simon Kelley 142456cfd0 Merge i18n strings. 2022-11-21 16:56:51 +00:00
Simon Kelley 207ce40db2 Add /etc/hosts gotcha to man page section for --dhcp-hosts. 2022-11-21 16:53:56 +00:00
Simon Kelley 881eaa4dbc Optimise readng large number --server options at start up.
When re-reading upstream servers from /etc/resolv.conf or other
sources that can change dnsmasq tries to avoid memory fragmentation by
re-using existing records that are being re-read unchanged. This
involves seaching all the server records for each new one installed.
During startup this search is pointless, and can cause long start
times with thousands of --server options because the work needed is
O(n^2). Handle this case more intelligently.  Thanks to Ye Zhou for
spotting the problem and an initial patch.
2022-11-21 16:40:53 +00:00
Matthias Andree d6d7527c95 Fix CHANGELOG typos. 2022-11-18 09:10:32 +00:00
Conrad Kostecki 11b4be2036 Update german translation for release 2.88. 2022-11-17 20:00:42 +00:00
Simon Kelley 3e306c1202 Fix SEGV on --local= added by immediately previous commit. 2022-11-17 19:51:15 +00:00
Simon Kelley 7f227a83f2 Fix struct hostinfo free code and BSD compile.
The code added in6 c596f1cc1d92b2b90ef5ce043ace314eefa868b
fails to free the returned datastructures from gethostinfo()
because sdetails.hostinfo is used to loop through the addresses
and ends up NULL. In some libc implementations this results
in a SEGV when freeaddrinfo() is called.

Also fix FTBFS under BSD. Thanks to Johnny S. Lee for the bug report.
2022-11-17 13:16:55 +00:00
Simon Kelley 9ed3ee67ec Handle DS records for unsupported crypto algorithms correctly.
Such a DS, as long as it is validated, should allow answers
in the domain is attests to be returned as unvalidated, and not
as a validation error.
2022-11-16 16:49:30 +00:00
Simon Kelley 1f9215f5f9 Fix GOST signature algorithms for DNSSEC validation.
Use CryptoPro version of the hash function.
Handle the little-endian wire format of key data.
Get the wire order of S and R correct.

Note that Nettle version 3.6 or later is required for GOST support.
2022-11-16 15:57:31 +00:00
Simon Kelley f52cfdd8c3 Handle known DNSSEC signature algorithms which are not supported.
This fixes a confusion if certain algorithms are not supported
because the version is the crypto library is too old.  The validation
should be treated the same as for a completely unknown algorithm,
(ie return unverified answer) and not as a validation failure
(ie return SERVFAIL).

The algorithems affected are GOST and ED448.
2022-11-13 15:55:09 +00:00
Simon Kelley 2fc904111d Fix --server=/domain/# 2022-11-07 23:24:31 +00:00
Simon Kelley 262dadf50e Fix --server with multiple domains. 2022-11-07 23:14:30 +00:00
Simon Kelley 6c596f1cc1 Make specifying nameservers by name work for DBus API. 2022-11-07 23:00:34 +00:00
Simon Kelley dafa16c400 Call freeaddrinfo() in domain_rev[46]() 2022-11-07 22:01:28 +00:00
19 changed files with 8271 additions and 6462 deletions

No files matched your search

+23 -8
View File
@@ -5,10 +5,10 @@ version 2.88
Add --fast-dns-retry option. This gives dnsmasq the ability
to originate retries for upstream DNS queries itself, rather
than relying on the downstream client. This is most useful
when doing DNSSEC over unreliable upstream network. It comes
when doing DNSSEC over unreliable upstream networks. It comes
with some cost in memory usage and network bandwidth.
Add -use-stale-cache option. When set, if a DNS name exists
Add --use-stale-cache option. When set, if a DNS name exists
in the cache, but its time-to-live has expired, dnsmasq will
return the data anyway. (It attempts to refresh the
data with an upstream query after returning the stale data.)
@@ -26,26 +26,41 @@ version 2.88
servers being removed from the configuration when reloading
server configuration from DBus, or re-reading /etc/resolv.conf
Only servers from the same source should be replaced, but some
servers from other sources (ie hard coded or another dynamic source)
servers from other sources (i.e., hard coded or another dynamic source)
could mysteriously disappear. Thanks to all reporting this,
but especially Christopher J. Masden who reduced the problem
to an easily reproducible case which saved mucg labour in
but especially Christopher J. Madsen who reduced the problem
to an easily reproducible case which saved much labour in
finding it.
Add --no-round-robin option.
Allow domain names as well as IP addresses when specifying
upstream DNS servers. There are some gotchas associated with this,
upstream DNS servers. There are some gotchas associated with this
(it will mysteriously fail to work if the dnsmasq instance
being started is in the path from the system resolver to the DNS)
being started is in the path from the system resolver to the DNS),
and a seemingly sensible configuration like
--server=domain.name@1.2.3.4 is unactionable if domain.name
only resolves to an IPv6 address). There are, however,
cases where is can be useful. Thanks to Dominik Derigs for
the patch.
Handle DS records for unsupported crypto algorithms correctly.
Such a DS, as long as it is validated, should allow answers
in the domain it attests to be returned as unvalidated, and not
as a validation error.
Optimise reading large numbers of --server options. When re-reading
upstream servers from /etc/resolv.conf or other sources that
can change dnsmasq tries to avoid memory fragmentation by re-using
existing records that are being re-read unchanged. This involves
seaching all the server records for each new one installed.
During startup this search is pointless, and can cause long
start times with thousands of --server options because the work
needed is O(n^2). Handle this case more intelligently.
Thanks to Ye Zhou for spotting the problem and an initial patch.
(version 2.87
version 2.87
Allow arbitrary prefix lengths in --rev-server and
--domain=....,local
+2 -1
View File
@@ -1166,7 +1166,8 @@ given in a
.B --dhcp-host
option, but aliases are possible by using CNAMEs. (See
.B --cname
).
). Note that /etc/hosts is NOT used when the DNS server side of dnsmasq
is disabled by setting the DNS server port to zero.
More than one
.B --dhcp-host
+709 -532
View File
File diff suppressed because it is too large. Load diff
+705 -528
View File
File diff suppressed because it is too large. Load diff
+846 -679
View File
File diff suppressed because it is too large. Load diff
+706 -528
View File
File diff suppressed because it is too large. Load diff
+716 -531
View File
File diff suppressed because it is too large. Load diff
+846 -679
View File
File diff suppressed because it is too large. Load diff
+554 -610
View File
File diff suppressed because it is too large. Load diff
+702 -527
View File
File diff suppressed because it is too large. Load diff
+705 -528
View File
File diff suppressed because it is too large. Load diff
+846 -679
View File
File diff suppressed because it is too large. Load diff
+702 -527
View File
File diff suppressed because it is too large. Load diff
+21 -8
View File
@@ -309,14 +309,14 @@ static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_l
mpz_init(y);
}
mpz_import(x, 32 , 1, 1, 0, 0, p);
mpz_import(y, 32 , 1, 1, 0, 0, p + 32);
mpz_import(x, 32, -1, 1, 0, 0, p);
mpz_import(y, 32, -1, 1, 0, 0, p + 32);
if (!ecc_point_set(gost_key, x, y))
return 0;
return 0;
mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig);
mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig + 32);
mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig);
mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig + 32);
return nettle_gostdsa_verify(gost_key, digest_len, digest, sig_struct);
}
@@ -390,7 +390,12 @@ static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key
return dnsmasq_ecdsa_verify;
#if MIN_VERSION(3, 1)
case 15: case 16:
case 15:
return dnsmasq_eddsa_verify;
#endif
#if MIN_VERSION(3, 6)
case 16:
return dnsmasq_eddsa_verify;
#endif
}
@@ -425,7 +430,9 @@ char *ds_digest_name(int digest)
{
case 1: return "sha1";
case 2: return "sha256";
case 3: return "gosthash94";
#if MIN_VERSION(3, 6)
case 3: return "gosthash94cp";
#endif
case 4: return "sha384";
default: return NULL;
}
@@ -444,11 +451,17 @@ char *algo_digest_name(int algo)
case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
case 8: return "sha256"; /* RSA/SHA-256 */
case 10: return "sha512"; /* RSA/SHA-512 */
case 12: return "gosthash94"; /* ECC-GOST */
#if MIN_VERSION(3, 6)
case 12: return "gosthash94cp"; /* ECC-GOST */
#endif
case 13: return "sha256"; /* ECDSAP256SHA256 */
case 14: return "sha384"; /* ECDSAP384SHA384 */
#if MIN_VERSION(3, 1)
case 15: return "null_hash"; /* ED25519 */
# if MIN_VERSION(3, 6)
case 16: return "null_hash"; /* ED448 */
# endif
#endif
default: return NULL;
}
}
+56 -18
View File
@@ -379,21 +379,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
strcpy(str_addr, str);
}
/* parse the IP address */
if ((addr_err = parse_server(str_addr, &sdetails)) ||
(addr_err = parse_server_addr(&sdetails)))
{
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s': %s",
str, addr_err);
break;
}
/* 0.0.0.0 for server address == NULL, for Dbus */
if (addr.in.sin_family == AF_INET &&
addr.in.sin_addr.s_addr == 0)
flags |= SERV_LITERAL_ADDRESS;
if (strings)
{
char *p;
@@ -407,7 +392,31 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
else
p = NULL;
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
if (strings && strlen(str_addr) == 0)
add_update_server(SERV_LITERAL_ADDRESS | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
else
{
if ((addr_err = parse_server(str_addr, &sdetails)))
{
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s': %s",
str, addr_err);
break;
}
while (parse_server_next(&sdetails))
{
if ((addr_err = parse_server_addr(&sdetails)))
{
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s': %s",
str, addr_err);
break;
}
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
}
}
} while ((str_domain = p));
}
else
@@ -421,11 +430,40 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
dbus_message_iter_get_basic(&string_iter, &str);
dbus_message_iter_next (&string_iter);
if ((addr_err = parse_server(str_addr, &sdetails)))
{
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s': %s",
str, addr_err);
break;
}
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
while (parse_server_next(&sdetails))
{
if ((addr_err = parse_server_addr(&sdetails)))
{
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s': %s",
str, addr_err);
break;
}
/* 0.0.0.0 for server address == NULL, for Dbus */
if (addr.in.sin_family == AF_INET &&
addr.in.sin_addr.s_addr == 0)
flags |= SERV_LITERAL_ADDRESS;
else
flags &= ~SERV_LITERAL_ADDRESS;
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
}
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
}
if (sdetails.orig_hostinfo)
freeaddrinfo(sdetails.orig_hostinfo);
/* jump to next element in outer array */
dbus_message_iter_next(&array_iter);
}
+3 -2
View File
@@ -1295,9 +1295,9 @@ extern struct daemon {
struct server_details {
union mysockaddr *addr, *source_addr;
struct addrinfo *hostinfo;
struct addrinfo *hostinfo, *orig_hostinfo;
char *interface, *source, *scope_id, *interface_opt;
int serv_port, source_port, addr_type, scope_index, valid, resolved;
int serv_port, source_port, addr_type, scope_index, valid;
u16 *flags;
};
@@ -1478,6 +1478,7 @@ void reset_option_bool(unsigned int opt);
struct hostsfile *expand_filelist(struct hostsfile *list);
char *parse_server(char *arg, struct server_details *sdetails);
char *parse_server_addr(struct server_details *sdetails);
int parse_server_next(struct server_details *sdetails);
int option_read_dynfile(char *file, int flags);
/* forward.c */
+37 -22
View File
@@ -979,10 +979,13 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
}
/* The DNS packet is expected to contain the answer to a DS query
Put all DSs in the answer which are valid into the cache.
Put all DSs in the answer which are valid and have hash and signature algos
we support into the cache.
Also handles replies which prove that there's no DS at this location,
either because the zone is unsigned or this isn't a zone cut. These are
cached too.
If none of the DS's are for supported algos, treat the answer as if
it's a proof of no DS at this location. RFC4035 para 5.2.
return codes:
STAT_OK At least one valid DS found and in cache.
STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
@@ -993,8 +996,8 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
{
unsigned char *p = (unsigned char *)(header+1);
int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0;
int aclass, atype, rdlen;
int qtype, qclass, rc, i, neganswer, nons, neg_ttl = 0, found_supported = 0;
int aclass, atype, rdlen, flags;
unsigned long ttl;
union all_addr a;
@@ -1065,14 +1068,22 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
algo = *p++;
digest = *p++;
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
if (!ds_digest_name(digest) || !ds_digest_name(digest))
{
a.log.keytag = keytag;
a.log.algo = algo;
a.log.digest = digest;
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
neg_ttl = ttl;
}
else if ((key = blockdata_alloc((char*)p, rdlen - 4)))
{
a.ds.digest = digest;
a.ds.keydata = key;
a.ds.algo = algo;
a.ds.keytag = keytag;
a.ds.keylen = rdlen - 4;
if (!cache_insert(name, &a, class, now, ttl, F_FORWARD | F_DS | F_DNSSECOK))
{
blockdata_free(key);
@@ -1083,26 +1094,29 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
a.log.keytag = keytag;
a.log.algo = algo;
a.log.digest = digest;
if (ds_digest_name(digest) && algo_digest_name(algo))
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
else
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
found_supported = 1;
}
}
p = psave;
}
if (!ADD_RDLEN(header, p, plen, rdlen))
return STAT_BOGUS; /* bad packet */
}
cache_end_insert();
/* Fall through if no supported algo DS found. */
if (found_supported)
return STAT_OK;
}
else
flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
if (neganswer)
{
int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
if (RCODE(header) == NXDOMAIN)
flags |= F_NXDOMAIN;
@@ -1110,17 +1124,18 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
to store presence/absence of NS. */
if (nons)
flags &= ~F_DNSSECOK;
cache_start_insert();
/* Use TTL from NSEC for negative cache entries */
if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
return STAT_BOGUS;
cache_end_insert();
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
}
cache_start_insert();
/* Use TTL from NSEC for negative cache entries */
if (!cache_insert(name, NULL, class, now, neg_ttl, flags))
return STAT_BOGUS;
cache_end_insert();
if (neganswer)
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
return STAT_OK;
}
+35 -20
View File
@@ -546,11 +546,23 @@ static int order_qsort(const void *a, const void *b)
return rc;
}
/* When loading large numbers of server=.... lines during startup,
there's no possibility that there will be server records that can be reused, but
searching a long list for each server added grows as O(n^2) and slows things down.
This flag is set only if is known there may be free server records that can be reused.
There's a call to mark_servers(0) in read_opts() to reset the flag before
main config read. */
static int maybe_free_servers = 0;
/* Must be called before add_update_server() to set daemon->servers_tail */
void mark_servers(int flag)
{
struct server *serv, **up;
maybe_free_servers = !!flag;
daemon->servers_tail = NULL;
/* mark everything with argument flag */
@@ -667,27 +679,30 @@ int add_update_server(int flags,
and move to the end of the list, for order. The entry found may already
be at the end. */
struct server **up, *tmp;
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
tmp = serv->next;
if ((serv->flags & SERV_MARK) &&
hostname_isequal(alloc_domain, serv->domain))
{
/* Need to move down? */
if (serv->next)
{
*up = serv->next;
daemon->servers_tail->next = serv;
daemon->servers_tail = serv;
serv->next = NULL;
}
break;
}
else
up = &serv->next;
}
serv = NULL;
if (maybe_free_servers)
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
tmp = serv->next;
if ((serv->flags & SERV_MARK) &&
hostname_isequal(alloc_domain, serv->domain))
{
/* Need to move down? */
if (serv->next)
{
*up = serv->next;
daemon->servers_tail->next = serv;
daemon->servers_tail = serv;
serv->next = NULL;
}
break;
}
else
up = &serv->next;
}
if (serv)
{
free(alloc_domain);
+57 -35
View File
@@ -860,14 +860,18 @@ char *parse_server(char *arg, struct server_details *sdetails)
sdetails->serv_port = NAMESERVER_PORT;
char *portno;
int ecode = 0;
struct addrinfo hints = { 0 };
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
*sdetails->interface = 0;
sdetails->addr_type = AF_UNSPEC;
if (strcmp(arg, "#") == 0)
{
if (sdetails->flags)
*sdetails->flags |= SERV_USE_RESOLV;
sdetails->addr_type = AF_LOCAL;
sdetails->valid = 1;
return NULL;
}
@@ -941,7 +945,7 @@ char *parse_server(char *arg, struct server_details *sdetails)
above, and returns a pointer to the start of the list in <hostinfo>.
The items in the linked list are linked by the <ai_next> field. */
sdetails->valid = 1;
sdetails->resolved = 1;
sdetails->orig_hostinfo = sdetails->hostinfo;
return NULL;
}
else
@@ -965,7 +969,7 @@ char *parse_server_addr(struct server_details *sdetails)
sdetails->addr->in.sin_port = htons(sdetails->serv_port);
sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET;
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr->in.sin_len = addr->in.sin_len = sizeof(struct sockaddr_in);
sdetails->source_addr->in.sin_len = sdetails->addr->in.sin_len = sizeof(struct sockaddr_in);
#endif
sdetails->source_addr->in.sin_addr.s_addr = INADDR_ANY;
sdetails->source_addr->in.sin_port = htons(daemon->query_port);
@@ -983,7 +987,7 @@ char *parse_server_addr(struct server_details *sdetails)
/* When resolving a server IP by hostname, we can simply skip mismatching
server / source IP pairs. Otherwise, when an IP address is given directly,
this is a fatal error. */
if (!sdetails->resolved)
if (!sdetails->orig_hostinfo)
return _("cannot use IPv4 server address with IPv6 source address");
}
else
@@ -1014,7 +1018,7 @@ char *parse_server_addr(struct server_details *sdetails)
sdetails->addr->sa.sa_family = sdetails->source_addr->sa.sa_family = AF_INET6;
sdetails->addr->in6.sin6_flowinfo = sdetails->source_addr->in6.sin6_flowinfo = 0;
#ifdef HAVE_SOCKADDR_SA_LEN
sdetails->addr->in6.sin6_len = sdetails->source_addr->in6.sin6_len = sizeof(addr->in6);
sdetails->addr->in6.sin6_len = sdetails->source_addr->in6.sin6_len = sizeof(sdetails->addr->in6);
#endif
if (sdetails->source)
{
@@ -1029,7 +1033,7 @@ char *parse_server_addr(struct server_details *sdetails)
/* When resolving a server IP by hostname, we can simply skip mismatching
server / source IP pairs. Otherwise, when an IP address is given directly,
this is a fatal error. */
if(!sdetails->resolved)
if(!sdetails->orig_hostinfo)
return _("cannot use IPv6 server address with IPv4 source address");
}
else
@@ -1047,12 +1051,13 @@ char *parse_server_addr(struct server_details *sdetails)
}
}
}
else
else if (sdetails->addr_type != AF_LOCAL)
return _("bad address");
return NULL;
}
static int parse_server_next(struct server_details *sdetails)
int parse_server_next(struct server_details *sdetails)
{
/* Looping over resolved addresses? */
if (sdetails->hostinfo)
@@ -1095,12 +1100,14 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
int count = 1, rem, addrbytes, addrbits;
struct server_details sdetails = { 0 };
struct server_details sdetails;
memset(&sdetails, 0, sizeof(struct server_details));
sdetails.addr = &serv_addr;
sdetails.source_addr = &source_addr;
sdetails.interface = interface;
sdetails.flags = &flags;
if (!server)
flags = SERV_LITERAL_ADDRESS;
else if ((string = parse_server(server, &sdetails)))
@@ -1157,6 +1164,9 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
return _("error");
}
if (sdetails.orig_hostinfo)
freeaddrinfo(sdetails.orig_hostinfo);
}
}
@@ -1173,12 +1183,14 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
int count = 1, rem, addrbytes, addrbits;
struct server_details sdetails = { 0 };
struct server_details sdetails;
memset(&sdetails, 0, sizeof(struct server_details));
sdetails.addr = &serv_addr;
sdetails.source_addr = &source_addr;
sdetails.interface = interface;
sdetails.flags = &flags;
if (!server)
flags = SERV_LITERAL_ADDRESS;
else if ((string = parse_server(server, &sdetails)))
@@ -1237,6 +1249,9 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
if (!add_update_server(flags, &serv_addr, &source_addr, interface, domain, NULL))
return _("error");
}
if (sdetails.orig_hostinfo)
freeaddrinfo(sdetails.orig_hostinfo);
}
}
@@ -2950,19 +2965,20 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_LOCAL: /* --local */
case 'A': /* --address */
{
char *lastdomain = NULL, *domain = "";
char *lastdomain = NULL, *domain = "", *cur_domain;
u16 flags = 0;
char *err;
union all_addr addr;
union mysockaddr serv_addr, source_addr;
char interface[IF_NAMESIZE+1];
struct server_details sdetails;
struct server_details sdetails = { 0 };
memset(&sdetails, 0, sizeof(struct server_details));
sdetails.addr = &serv_addr;
sdetails.source_addr = &source_addr;
sdetails.interface = interface;
sdetails.flags = &flags;
unhide_metas(arg);
/* split the domain args, if any and skip to the end of them. */
@@ -3001,9 +3017,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (servers_only && option == 'S')
flags |= SERV_FROM_FILE;
cur_domain = domain;
while ((flags & SERV_LITERAL_ADDRESS) || parse_server_next(&sdetails))
{
cur_domain = domain;
if (!(flags & SERV_LITERAL_ADDRESS) && (err = parse_server_addr(&sdetails)))
ret_err(err);
@@ -3015,32 +3034,32 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
/* server=//1.2.3.4 is special. */
if (lastdomain)
{
if (strlen(domain) == 0)
flags |= SERV_FOR_NODOTS;
else
flags &= ~SERV_FOR_NODOTS;
/* address=/#/ matches the same as without domain */
if (option == 'A' && domain[0] == '#' && domain[1] == 0)
domain[0] = 0;
}
if (!add_update_server(flags, sdetails.addr, sdetails.source_addr, sdetails.interface, domain, &addr))
{
if (strlen(cur_domain) == 0)
flags |= SERV_FOR_NODOTS;
else
flags &= ~SERV_FOR_NODOTS;
/* address=/#/ matches the same as without domain */
if (option == 'A' && cur_domain[0] == '#' && cur_domain[1] == 0)
cur_domain[0] = 0;
}
if (!add_update_server(flags, sdetails.addr, sdetails.source_addr, sdetails.interface, cur_domain, &addr))
ret_err(gen_err);
if (!lastdomain || domain == lastdomain)
if (!lastdomain || cur_domain == lastdomain)
break;
domain += strlen(domain) + 1;
cur_domain += strlen(cur_domain) + 1;
}
if (flags & SERV_LITERAL_ADDRESS)
break;
}
if (sdetails.resolved)
freeaddrinfo(sdetails.hostinfo);
if (sdetails.orig_hostinfo)
freeaddrinfo(sdetails.orig_hostinfo);
break;
}
@@ -5734,7 +5753,10 @@ void read_opts(int argc, char **argv, char *compile_opts)
#endif
add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
#endif
/* See comment above make_servers(). Optimises server-read code. */
mark_servers(0);
while (1)
{
#ifdef HAVE_GETOPT_LONG