summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2023-03-20 22:30:11 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2023-03-20 22:30:11 +0000
commit3fb10cd0d8217b42071ab575c2edaae2554b1780 (patch)
tree1f850ab4ac7ad309bd9c5f7a839838ce2d09fc9b
parent0427e371160882a24825df6f4f963961257df952 (diff)
parentff28a485cf8b592a6c21b39bbb8e42f5bc390685 (diff)
downloaddnsmasq-3fb10cd0d8217b42071ab575c2edaae2554b1780.tar.gz
Merge branch 'master' into all-rr-type
-rw-r--r--CHANGELOG18
-rw-r--r--dbus/DBus-interface8
-rw-r--r--debian/changelog6
-rw-r--r--man/dnsmasq.813
-rw-r--r--src/config.h2
-rw-r--r--src/dbus.c14
-rw-r--r--src/dhcp-common.c6
-rw-r--r--src/dhcp.c6
-rw-r--r--src/dnsmasq.h4
-rw-r--r--src/domain-match.c5
-rw-r--r--src/edns0.c2
-rw-r--r--src/forward.c79
-rw-r--r--src/loop.c2
-rw-r--r--src/network.c13
-rw-r--r--src/option.c14
-rw-r--r--src/rfc1035.c90
-rw-r--r--src/rfc2131.c2
-rw-r--r--src/rfc3315.c6
-rw-r--r--src/rrfilter.c46
-rw-r--r--src/tftp.c2
20 files changed, 241 insertions, 97 deletions
diff --git a/CHANGELOG b/CHANGELOG
index de9c5e0..52d8678 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,21 @@
+version 2.90
+ Fix reversion in --rev-server introduced in 2.88 which
+ caused breakage if the prefix length is not exactly divisible
+ by 8 (IPv4) or 4 (IPv6).
+
+ Fix possible SEGV when there server(s) for a particular
+ domain are configured, but no server which is not qualified
+ for a particular domain. Thanks to Daniel Danzberger for
+ spotting this bug.
+
+ Set the default maximum DNS UDP packet sice to 1232. This
+ has been the recommended value since 2020 because it's the
+ largest value that avoid fragmentation, and fragmentation
+ is just not reliable on the modern internet, especially
+ for IPv6. It's still possible to override this with
+ --edns-packet-max for special circumstances.
+
+
version 2.89
Fix bug introduced in 2.88 (commit fe91134b) which can result
in corruption of the DNS cache internal data structures and
diff --git a/dbus/DBus-interface b/dbus/DBus-interface
index 59b41b1..00b4465 100644
--- a/dbus/DBus-interface
+++ b/dbus/DBus-interface
@@ -44,6 +44,14 @@ SetFilterWin2KOption
--------------------
Takes boolean, sets or resets the --filterwin2k option.
+SetFilterA
+------------------------
+Takes boolean, sets or resets the --filter-A option.
+
+SetFilterAAAA
+------------------------
+Takes boolean, sets or resets the --filter-AAAA option.
+
SetBogusPrivOption
------------------
Takes boolean, sets or resets the --bogus-priv option.
diff --git a/debian/changelog b/debian/changelog
index a1cf600..8996f88 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+dnsmasq (2.90-1) unstable; urgency=low
+
+ * New upstream. (closes: #1033165)
+
+ -- Simon Kelley <simon@thekelleys.org.uk> Mon, 6 Mar 2023 23:22:06 +0000
+
dnsmasq (2.89-1) unstable; urgency=low
* New upstream.
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 3d1d96a..5acb935 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -183,7 +183,8 @@ to zero completely disables DNS function, leaving only DHCP and/or TFTP.
.TP
.B \-P, --edns-packet-max=<size>
Specify the largest EDNS.0 UDP packet which is supported by the DNS
-forwarder. Defaults to 4096, which is the RFC5625-recommended size.
+forwarder. Defaults to 1232, which is the recommended size following the
+DNS flag day in 2020. Only increase if you know what you are doing.
.TP
.B \-Q, --query-port=<query_port>
Send outbound DNS queries from, and listen for their replies on, the
@@ -1297,7 +1298,15 @@ and to set the time-server address to 192.168.0.4, do
or
.B --dhcp-option = option:ntp-server, 192.168.0.4
The special address 0.0.0.0 is taken to mean "the address of the
-machine running dnsmasq".
+machine running dnsmasq".
+
+An option without data is valid, and includes just the option without data.
+(There is only one option with a zero length data field currently defined for DHCPv4, 80:rapid commit, so this feature is not very useful in practice). Options for which dnsmasq normally
+provides default values can be ommitted by defining the option with no data. These are
+netmask, broadcast, router, DNS server, domainname and hostname. Thus, for DHCPv4
+.B --dhcp-option = option:router
+will result in no router option being sent, rather than the default of the host on which dnsmasq is running. For DHCPv6, the same is true of the options DNS server and refresh time.
+
Data types allowed are comma separated
dotted-quad IPv4 addresses, []-wrapped IPv6 addresses, a decimal number, colon-separated hex digits
diff --git a/src/config.h b/src/config.h
index 1e7b30f..37b374e 100644
--- a/src/config.h
+++ b/src/config.h
@@ -19,7 +19,7 @@
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
-#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
+#define EDNS_PKTSZ 1232 /* default max EDNS.0 UDP packet from from /dnsflagday.net/2020 */
#define SAFE_PKTSZ 1232 /* "go anywhere" UDP packet size, see https://dnsflagday.net/2020/ */
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
diff --git a/src/dbus.c b/src/dbus.c
index fd5d1ca..4366b7e 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -52,6 +52,12 @@ const char* introspection_xml_template =
" <method name=\"SetFilterWin2KOption\">\n"
" <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
+" <method name=\"SetFilterA\">\n"
+" <arg name=\"filter-a\" direction=\"in\" type=\"b\"/>\n"
+" </method>\n"
+" <method name=\"SetFilterAAAA\">\n"
+" <arg name=\"filter-aaaa\" direction=\"in\" type=\"b\"/>\n"
+" </method>\n"
" <method name=\"SetLocaliseQueriesOption\">\n"
" <arg name=\"localise-queries\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
@@ -817,6 +823,14 @@ DBusHandlerResult message_handler(DBusConnection *connection,
{
reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
}
+ else if (strcmp(method, "SetFilterA") == 0)
+ {
+ reply = dbus_set_bool(message, OPT_FILTER_A, "filter-A");
+ }
+ else if (strcmp(method, "SetFilterAAAA") == 0)
+ {
+ reply = dbus_set_bool(message, OPT_FILTER_AAAA, "filter-AAAA");
+ }
else if (strcmp(method, "SetLocaliseQueriesOption") == 0)
{
reply = dbus_set_bool(message, OPT_LOCALISE, "localise-queries");
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index 84081ce..b4d255e 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -838,7 +838,7 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
{
char c = val[i];
- if (isprint((int)c))
+ if (isprint((unsigned char)c))
buf[j++] = c;
}
#ifdef HAVE_DHCP6
@@ -852,7 +852,7 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
{
char c = val[k];
- if (isprint((int)c))
+ if (isprint((unsigned char)c))
buf[j++] = c;
}
i = l;
@@ -873,7 +873,7 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
for (k = 0; k < len && j < buf_len; k++)
{
char c = *p++;
- if (isprint((int)c))
+ if (isprint((unsigned char)c))
buf[j++] = c;
}
i += len +2;
diff --git a/src/dhcp.c b/src/dhcp.c
index 42d819f..e578391 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -916,14 +916,14 @@ void dhcp_read_ethers(void)
lineno++;
- while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
+ while (strlen(buff) > 0 && isspace((unsigned char)buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0;
if ((*buff == '#') || (*buff == '+') || (*buff == 0))
continue;
- for (ip = buff; *ip && !isspace((int)*ip); ip++);
- for(; *ip && isspace((int)*ip); ip++)
+ for (ip = buff; *ip && !isspace((unsigned char)*ip); ip++);
+ for(; *ip && isspace((unsigned char)*ip); ip++)
*ip = 0;
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
{
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index fe9aa07..292a402 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1366,7 +1366,7 @@ void report_addresses(struct dns_header *header, size_t len, u32 mark);
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int have_pseudoheader,
- int *stale);
+ int *stale, int *filtered);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen);
@@ -1811,7 +1811,7 @@ void poll_listen(int fd, short event);
int do_poll(int timeout);
/* rrfilter.c */
-size_t rrfilter(struct dns_header *header, size_t plen, int mode);
+size_t rrfilter(struct dns_header *header, size_t *plen, int mode);
u16 *rrfilter_desc(int type);
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
/* modes. */
diff --git a/src/domain-match.c b/src/domain-match.c
index fe8e25a..9cc51e6 100644
--- a/src/domain-match.c
+++ b/src/domain-match.c
@@ -253,9 +253,10 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
if (highout)
*highout = nhigh;
- if (nlow == nhigh)
+ /* qlen == -1 when we failed to match even an empty query, if there are no default servers. */
+ if (nlow == nhigh || qlen == -1)
return 0;
-
+
return 1;
}
diff --git a/src/edns0.c b/src/edns0.c
index c498eb1..567101b 100644
--- a/src/edns0.c
+++ b/src/edns0.c
@@ -178,7 +178,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
memcpy(buff, datap, rdlen);
/* now, delete OPT RR */
- plen = rrfilter(header, plen, RRFILTER_EDNS0);
+ rrfilter(header, &plen, RRFILTER_EDNS0);
/* Now, force addition of a new one */
p = NULL;
diff --git a/src/forward.c b/src/forward.c
index 0f03818..d79cc56 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -721,7 +721,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
if (added_pheader)
{
/* client didn't send EDNS0, we added one, strip it off before returning answer. */
- n = rrfilter(header, n, RRFILTER_EDNS0);
+ rrfilter(header, &n, RRFILTER_EDNS0);
pheader = NULL;
}
else
@@ -811,16 +811,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
}
}
- /* Before extract_addresses() */
- if (rcode == NOERROR)
- {
- if (option_bool(OPT_FILTER_A))
- n = rrfilter(header, n, RRFILTER_A);
-
- if (option_bool(OPT_FILTER_AAAA))
- n = rrfilter(header, n, RRFILTER_AAAA);
- }
-
switch (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
{
case 1:
@@ -839,6 +829,20 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
break;
}
+ if (rcode == NOERROR)
+ {
+ size_t modified = 0;
+
+ if (option_bool(OPT_FILTER_A))
+ modified = rrfilter(header, &n, RRFILTER_A);
+
+ if (option_bool(OPT_FILTER_AAAA))
+ modified += rrfilter(header, &n, RRFILTER_AAAA);
+
+ if (modified > 0)
+ ede = EDE_FILTERED;
+ }
+
if (doctored)
cache_secure = 0;
}
@@ -860,7 +864,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
if (!do_bit)
- n = rrfilter(header, n, RRFILTER_DNSSEC);
+ rrfilter(header, &n, RRFILTER_DNSSEC);
}
#endif
@@ -1808,7 +1812,7 @@ void receive_query(struct listener *listen, time_t now)
#endif
else
{
- int stale;
+ int stale, filtered;
int ad_reqd = do_bit;
u16 hb3 = header->hb3, hb4 = header->hb4;
int fd = listen->fd;
@@ -1818,17 +1822,28 @@ void receive_query(struct listener *listen, time_t now)
ad_reqd = 1;
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
- dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale);
+ dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale, &filtered);
if (m >= 1)
{
- if (stale && have_pseudoheader)
+ if (have_pseudoheader)
{
- u16 swap = htons(EDE_STALE);
+ int ede = EDE_UNSET;
- m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
- EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
+ if (filtered)
+ ede = EDE_FILTERED;
+ else if (stale)
+ ede = EDE_STALE;
+
+ if (ede != EDE_UNSET)
+ {
+ u16 swap = htons(ede);
+
+ m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
+ EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
+ }
}
+
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd);
#endif
@@ -2098,7 +2113,7 @@ unsigned char *tcp_request(int confd, time_t now,
unsigned char *pheader;
unsigned int mark = 0;
int have_mark = 0;
- int first, last, stale, do_stale = 0;
+ int first, last, filtered, stale, do_stale = 0;
unsigned int flags = 0;
u16 hb3, hb4;
@@ -2292,7 +2307,7 @@ unsigned char *tcp_request(int confd, time_t now,
else
/* m > 0 if answered from cache */
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
- dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale);
+ dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale, &filtered);
/* Do this by steam now we're not in the select() loop */
check_log_writer(1);
@@ -2431,13 +2446,23 @@ unsigned char *tcp_request(int confd, time_t now,
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
}
}
- else if (stale)
- {
- u16 swap = htons((u16)EDE_STALE);
-
- m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
- }
-
+ else
+ {
+ ede = EDE_UNSET;
+
+ if (filtered)
+ ede = EDE_FILTERED;
+ else if (stale)
+ ede = EDE_STALE;
+
+ if (ede != EDE_UNSET)
+ {
+ u16 swap = htons((u16)ede);
+
+ m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
+ }
+ }
+
check_log_writer(1);
*length = htons(m);
diff --git a/src/loop.c b/src/loop.c
index cd4855e..19bfae0 100644
--- a/src/loop.c
+++ b/src/loop.c
@@ -92,7 +92,7 @@ int detect_loop(char *query, int type)
return 0;
for (i = 0; i < 8; i++)
- if (!isxdigit(query[i]))
+ if (!isxdigit((unsigned char)query[i]))
return 0;
uid = strtol(query, NULL, 16);
diff --git a/src/network.c b/src/network.c
index 1e41a78..a80d096 100644
--- a/src/network.c
+++ b/src/network.c
@@ -359,13 +359,8 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
struct in_addr newaddr = addr->in.sin_addr;
if (int_name->flags & INP4)
- {
- if (netmask.s_addr == 0xffffffff)
- continue;
-
- newaddr.s_addr = (addr->in.sin_addr.s_addr & netmask.s_addr) |
- (int_name->proto4.s_addr & ~netmask.s_addr);
- }
+ newaddr.s_addr = (addr->in.sin_addr.s_addr & netmask.s_addr) |
+ (int_name->proto4.s_addr & ~netmask.s_addr);
/* check for duplicates. */
for (lp = int_name->addr; lp; lp = lp->next)
@@ -398,10 +393,6 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
{
int i;
- /* No sense in doing /128. */
- if (prefixlen == 128)
- continue;
-
for (i = 0; i < 16; i++)
{
int bits = ((i+1)*8) - prefixlen;
diff --git a/src/option.c b/src/option.c
index e4810fd..2e208ba 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1159,6 +1159,9 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
}
else
{
+ /* Always reset server as valid here, so we can add the same upstream
+ server address multiple times for each x.y.z.in-addr.arpa */
+ sdetails.valid = 1;
while (parse_server_next(&sdetails))
{
if ((string = parse_server_addr(&sdetails)))
@@ -1244,6 +1247,9 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
}
else
{
+ /* Always reset server as valid here, so we can add the same upstream
+ server address multiple times for each x.y.z.ip6.arpa */
+ sdetails.valid = 1;
while (parse_server_next(&sdetails))
{
if ((string = parse_server_addr(&sdetails)))
@@ -2751,7 +2757,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err);
for (p = arg; *p; p++)
- if (!isxdigit((int)*p))
+ if (!isxdigit((unsigned char)*p))
ret_err(gen_err);
set_option_bool(OPT_UMBRELLA_DEVID);
@@ -4836,7 +4842,7 @@ err:
new->target = target;
new->ttl = ttl;
- for (arg += arglen+1; *arg && isspace(*arg); arg++);
+ for (arg += arglen+1; *arg && isspace((unsigned char)*arg); arg++);
}
break;
@@ -5227,7 +5233,7 @@ err:
unhide_metas(keyhex);
/* 4034: "Whitespace is allowed within digits" */
for (cp = keyhex; *cp; )
- if (isspace(*cp))
+ if (isspace((unsigned char)*cp))
for (cp1 = cp; *cp1; cp1++)
*cp1 = *(cp1+1);
else
@@ -5315,7 +5321,7 @@ static void read_file(char *file, FILE *f, int hard_opt, int from_script)
memmove(p, p+1, strlen(p+1)+1);
}
- if (isspace(*p))
+ if (isspace((unsigned char)*p))
{
*p = ' ';
white = 1;
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 5c0df56..ea21ffa 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -519,7 +519,7 @@ static int print_txt(struct dns_header *header, const size_t qlen, char *name,
/* make counted string zero-term and sanitise */
for (i = 0; i < len; i++)
{
- if (!isprint((int)*(p3+1)))
+ if (!isprint((unsigned char)*(p3+1)))
break;
*p3 = *(p3+1);
p3++;
@@ -880,7 +880,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
return 2;
}
else
- log_query(flags | F_FORWARD | secflag | F_UPSTREAM, name, &addr, NULL, aqtype);
+ {
+ int negflag = F_UPSTREAM;
+
+ /* We're filtering this RRtype. It will be removed from the
+ returned packet in process_reply() but gets cached here anyway
+ and will be filtered again on the way out of the cache. Here,
+ we just need to alter the logging. */
+ if (((flags & F_IPV4) && option_bool(OPT_FILTER_A)) || ((flags & F_IPV6) && option_bool(OPT_FILTER_AAAA)))
+ negflag = F_NEG | F_CONFIG;
+
+ log_query(negflag | flags | F_FORWARD | secflag, name, &addr, NULL, aqtype);
+ }
}
p1 = endrr;
@@ -894,9 +905,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
{
flags &= ~(F_IPV4 | F_IPV6 | F_SRV);
- /* Can store NXDOMAIN reply to CNAME or ANY query. */
- if (qtype == T_CNAME || qtype == T_ANY)
- insert = 1;
+ /* Can store NXDOMAIN reply for any qtype. */
+ insert = 1;
}
log_query(F_UPSTREAM | F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0), name, NULL, NULL, 0);
@@ -1409,7 +1419,7 @@ static int cache_validated(const struct crec *crecp)
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int have_pseudoheader,
- int *stale)
+ int *stale, int *filtered)
{
char *name = daemon->namebuff;
unsigned char *p, *ansp;
@@ -1427,6 +1437,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (stale)
*stale = 0;
+
+ if (filtered)
+ *filtered = 0;
/* never answer queries with RD unset, to avoid cache snooping. */
if (ntohs(header->ancount) != 0 ||
@@ -1695,8 +1708,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
continue;
-
-
+
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
@@ -1864,8 +1876,24 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
-
- if (crecp->flags & F_NEG)
+
+ if (!(crecp->flags & (F_HOSTS | F_DHCP)))
+ auth = 0;
+
+ if ((((flag & F_IPV4) && option_bool(OPT_FILTER_A)) || ((flag & F_IPV6) && option_bool(OPT_FILTER_AAAA))) &&
+ !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | F_NEG)))
+ {
+ /* We have a cached answer but we're filtering it. */
+ ans = 1;
+ sec_data = 0;
+
+ if (!dryrun)
+ log_query(F_NEG | F_CONFIG | flag, name, NULL, NULL, 0);
+
+ if (filtered)
+ *filtered = 1;
+ }
+ else if (crecp->flags & F_NEG)
{
ans = 1;
auth = 0;
@@ -1883,9 +1911,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
!is_same_net(crecp->addr.addr4, local_addr, local_netmask))
continue;
- if (!(crecp->flags & (F_HOSTS | F_DHCP)))
- auth = 0;
-
ans = 1;
if (!dryrun)
{
@@ -1911,6 +1936,27 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
anscount++;
}
}
+ else if (((flag & F_IPV4) && option_bool(OPT_FILTER_A)) || ((flag & F_IPV6) && option_bool(OPT_FILTER_AAAA)))
+ {
+ /* We don't have a cached answer and when we get an answer from upstream we're going to
+ filter it anyway. If we have a cached answer for the domain for another RRtype then
+ that may be enough to tell us if the answer should be NODATA and save the round trip.
+ Cached NXDOMAIN has already been handled, so here we look for any record for the domain,
+ since its existence allows us to return a NODATA answer. Note that we never set the AD flag,
+ since we didn't authentucate the record. */
+
+ if (cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_SRV))
+ {
+ ans = 1;
+ sec_data = auth = 0;
+
+ if (!dryrun)
+ log_query(F_NEG | F_CONFIG | flag, name, NULL, NULL, 0);
+
+ if (filtered)
+ *filtered = 1;
+ }
+ }
}
if (qtype == T_MX || qtype == T_ANY)
@@ -1921,6 +1967,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
{
ans = found = 1;
sec_data = 0;
+
if (!dryrun)
{
int offset;
@@ -2081,7 +2128,22 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
if (!ans)
- return 0; /* failed to answer a question */
+ {
+ /* We may know that the domain doesn't exist for any RRtype. */
+ if ((crecp = cache_find_by_name(NULL, name, now, F_NXDOMAIN)))
+ {
+ ans = nxdomain = 1;
+ auth = 0;
+
+ if (!(crecp->flags & F_DNSSECOK))
+ sec_data = 0;
+
+ if (!dryrun)
+ log_query(F_NXDOMAIN | F_NEG, name, NULL, NULL, 0);
+ }
+ else
+ return 0; /* failed to answer a question */
+ }
}
if (dryrun)
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 17e97b5..5190982 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -1678,7 +1678,7 @@ static int sanitise(unsigned char *opt, char *buf)
for (i = option_len(opt); i > 0; i--)
{
char c = *p++;
- if (isprint((int)c))
+ if (isprint((unsigned char)c))
*buf++ = c;
}
*buf = 0; /* add terminator */
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 8754481..477df91 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -353,7 +353,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
put_opt6_short(DHCP6USEMULTI);
put_opt6_string("Use multicast");
end_opt6(o1);
- return 1;
+ goto done;
}
/* match vendor and user class options */
@@ -1277,12 +1277,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
}
+ log_tags(tagif, state->xid);
+
+ done:
/* Fill in the message type. Note that we store the offset,
not a direct pointer, since the packet memory may have been
reallocated. */
((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype;
- log_tags(tagif, state->xid);
log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
return 1;
diff --git a/src/rrfilter.c b/src/rrfilter.c
index 42d9c21..3a5547a 100644
--- a/src/rrfilter.c
+++ b/src/rrfilter.c
@@ -156,41 +156,43 @@ static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, i
}
-/* mode may be remove EDNS0 or DNSSEC RRs or remove A or AAAA from answer section. */
-size_t rrfilter(struct dns_header *header, size_t plen, int mode)
+/* mode may be remove EDNS0 or DNSSEC RRs or remove A or AAAA from answer section.
+ * returns number of modified records. */
+size_t rrfilter(struct dns_header *header, size_t *plen, int mode)
{
static unsigned char **rrs = NULL;
static int rr_sz = 0;
unsigned char *p = (unsigned char *)(header+1);
- int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
+ size_t rr_found = 0;
+ int i, rdlen, qtype, qclass, chop_an, chop_ns, chop_ar;
if (ntohs(header->qdcount) != 1 ||
- !(p = skip_name(p, header, plen, 4)))
- return plen;
+ !(p = skip_name(p, header, *plen, 4)))
+ return 0;
GETSHORT(qtype, p);
GETSHORT(qclass, p);
/* First pass, find pointers to start and end of all the records we wish to elide:
records added for DNSSEC, unless explicitly queried for */
- for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
+ for (chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
i++)
{
unsigned char *pstart = p;
int type, class;
- if (!(p = skip_name(p, header, plen, 10)))
- return plen;
+ if (!(p = skip_name(p, header, *plen, 10)))
+ return rr_found;
GETSHORT(type, p);
GETSHORT(class, p);
p += 4; /* TTL */
GETSHORT(rdlen, p);
- if (!ADD_RDLEN(header, p, plen, rdlen))
- return plen;
+ if (!ADD_RDLEN(header, p, *plen, rdlen))
+ return rr_found;
if (mode == RRFILTER_EDNS0) /* EDNS */
{
@@ -225,7 +227,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
}
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
- return plen;
+ return rr_found;
rrs[rr_found++] = pstart;
rrs[rr_found++] = p;
@@ -240,7 +242,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
/* Nothing to do. */
if (rr_found == 0)
- return plen;
+ return rr_found;
/* Second pass, look for pointers in names in the records we're keeping and make sure they don't
point to records we're going to elide. This is theoretically possible, but unlikely. If
@@ -248,38 +250,38 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
p = (unsigned char *)(header+1);
/* question first */
- if (!check_name(&p, header, plen, 0, rrs, rr_found))
- return plen;
+ if (!check_name(&p, header, *plen, 0, rrs, rr_found))
+ return rr_found;
p += 4; /* qclass, qtype */
/* Now answers and NS */
- if (!check_rrs(p, header, plen, 0, rrs, rr_found))
- return plen;
+ if (!check_rrs(p, header, *plen, 0, rrs, rr_found))
+ return rr_found;
/* Third pass, actually fix up pointers in the records */
p = (unsigned char *)(header+1);
- check_name(&p, header, plen, 1, rrs, rr_found);
+ check_name(&p, header, *plen, 1, rrs, rr_found);
p += 4; /* qclass, qtype */
- check_rrs(p, header, plen, 1, rrs, rr_found);
+ check_rrs(p, header, *plen, 1, rrs, rr_found);
/* Fourth pass, elide records */
- for (p = rrs[0], i = 1; i < rr_found; i += 2)
+ for (p = rrs[0], i = 1; (unsigned)i < rr_found; i += 2)
{
unsigned char *start = rrs[i];
- unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
+ unsigned char *end = ((unsigned)i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + *plen;
memmove(p, start, end-start);
p += end-start;
}
- plen = p - (unsigned char *)header;
+ *plen = p - (unsigned char *)header;
header->ancount = htons(ntohs(header->ancount) - chop_an);
header->nscount = htons(ntohs(header->nscount) - chop_ns);
header->arcount = htons(ntohs(header->arcount) - chop_ar);
- return plen;
+ return rr_found;
}
/* This is used in the DNSSEC code too, hence it's exported */
diff --git a/src/tftp.c b/src/tftp.c
index 0861f37..8e1dc4a 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -405,7 +405,7 @@ void tftp_request(struct listener *listen, time_t now)
if (*p == '\\')
*p = '/';
else if (option_bool(OPT_TFTP_LC))
- *p = tolower(*p);
+ *p = tolower((unsigned char)*p);
strcpy(daemon->namebuff, "/");
if (prefix)