mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-05-11 09:48:24 +02:00
dnsmasq: 2.76test10 with latest patches (001-004)
This is 'dnsmasq 2.76test10', based on current 'next', containing latest patches. Signed-off-by: Matthias Fischer <matthias.fischer@ipfire.org> Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
This commit is contained in:
committed by
Michael Tremer
parent
43747fae33
commit
3b9815eb87
@@ -0,0 +1,265 @@
|
||||
From df3d54f776a3c9b60735b45c0b7fd88b66a2d5c4 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 24 Feb 2016 21:03:38 +0000
|
||||
Subject: [PATCH] Add TTL parameter to --host-record and --cname.
|
||||
|
||||
---
|
||||
man/dnsmasq.8 | 12 ++++++++++--
|
||||
src/cache.c | 7 +++++++
|
||||
src/dnsmasq.h | 2 ++
|
||||
src/option.c | 46 ++++++++++++++++++++++++++++++++++++++--------
|
||||
src/rfc1035.c | 6 +++++-
|
||||
5 files changed, 62 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
|
||||
index b782eaf..7bc1394 100644
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -529,7 +529,7 @@ zone files: the port, weight and priority numbers are in a different
|
||||
order. More than one SRV record for a given service/domain is allowed,
|
||||
all that match are returned.
|
||||
.TP
|
||||
-.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>]
|
||||
+.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>][,<TTL>]
|
||||
Add A, AAAA and PTR records to the DNS. This adds one or more names to
|
||||
the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
|
||||
appear in more than one
|
||||
@@ -546,6 +546,10 @@ is in effect. Short and long names may appear in the same
|
||||
.B host-record,
|
||||
eg.
|
||||
.B --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
|
||||
+
|
||||
+If the time-to-live is given, it overrides the default, which is zero
|
||||
+or the value of --local-ttl. The value is a positive integer and gives
|
||||
+the time-to-live in seconds.
|
||||
.TP
|
||||
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
||||
Return a TXT DNS record. The value of TXT record is a set of strings,
|
||||
@@ -559,7 +563,7 @@ Return a PTR DNS record.
|
||||
.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
|
||||
Return an NAPTR DNS record, as specified in RFC3403.
|
||||
.TP
|
||||
-.B --cname=<cname>,<target>
|
||||
+.B --cname=<cname>,<target>[,<TTL>]
|
||||
Return a CNAME record which indicates that <cname> is really
|
||||
<target>. There are significant limitations on the target; it must be a
|
||||
DNS name which is known to dnsmasq from /etc/hosts (or additional
|
||||
@@ -568,6 +572,10 @@ hosts files), from DHCP, from --interface-name or from another
|
||||
If the target does not satisfy this
|
||||
criteria, the whole cname is ignored. The cname must be unique, but it
|
||||
is permissable to have more than one cname pointing to the same target.
|
||||
+
|
||||
+If the time-to-live is given, it overrides the default, which is zero
|
||||
+or the value of -local-ttl. The value is a positive integer and gives
|
||||
+the time-to-live in seconds.
|
||||
.TP
|
||||
.B --dns-rr=<name>,<RR-number>,[<hex data>]
|
||||
Return an arbitrary DNS Resource Record. The number is the type of the
|
||||
diff --git a/src/cache.c b/src/cache.c
|
||||
index a9eaa65..4ecd535 100644
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -778,6 +778,7 @@ static void add_hosts_cname(struct crec *target)
|
||||
(crec = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
|
||||
+ crec->ttd = a->ttl;
|
||||
crec->name.namep = a->alias;
|
||||
crec->addr.cname.target.cache = target;
|
||||
crec->addr.cname.uid = target->uid;
|
||||
@@ -981,6 +982,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
strcat(cache->name.sname, ".");
|
||||
strcat(cache->name.sname, domain_suffix);
|
||||
cache->flags = flags;
|
||||
+ cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
}
|
||||
@@ -988,6 +990,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
{
|
||||
strcpy(cache->name.sname, canon);
|
||||
cache->flags = flags;
|
||||
+ cache->ttd = daemon->local_ttl;
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
}
|
||||
@@ -1057,6 +1060,7 @@ void cache_reload(void)
|
||||
((cache = whine_malloc(sizeof(struct crec)))))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||
+ cache->ttd = a->ttl;
|
||||
cache->name.namep = a->alias;
|
||||
cache->addr.cname.target.int_name = intr;
|
||||
cache->addr.cname.uid = SRC_INTERFACE;
|
||||
@@ -1071,6 +1075,7 @@ void cache_reload(void)
|
||||
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||
+ cache->ttd = daemon->local_ttl;
|
||||
cache->name.namep = ds->name;
|
||||
cache->addr.ds.keylen = ds->digestlen;
|
||||
cache->addr.ds.algo = ds->algo;
|
||||
@@ -1095,6 +1100,7 @@ void cache_reload(void)
|
||||
(cache = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
+ cache->ttd = hr->ttl;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
@@ -1103,6 +1109,7 @@ void cache_reload(void)
|
||||
(cache = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
+ cache->ttd = hr->ttl;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 6d1c5ae..6344df5 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -308,6 +308,7 @@ struct ptr_record {
|
||||
};
|
||||
|
||||
struct cname {
|
||||
+ int ttl;
|
||||
char *alias, *target;
|
||||
struct cname *next;
|
||||
};
|
||||
@@ -344,6 +345,7 @@ struct auth_zone {
|
||||
|
||||
|
||||
struct host_record {
|
||||
+ int ttl;
|
||||
struct name_list {
|
||||
char *name;
|
||||
struct name_list *next;
|
||||
diff --git a/src/option.c b/src/option.c
|
||||
index c98bdc9..7c5e6bc 100644
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -448,20 +448,20 @@ static struct {
|
||||
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
||||
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
||||
{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
|
||||
- { LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
||||
+ { LOPT_CNAME, ARG_DUP, "<alias>,<target>[,<ttl>]", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
||||
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
||||
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
||||
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
|
||||
{ LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
|
||||
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
|
||||
- { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
|
||||
+ { LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
|
||||
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
|
||||
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
|
||||
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
|
||||
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
|
||||
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
|
||||
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
|
||||
- { LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
||||
+ { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
||||
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
|
||||
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
|
||||
{ LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
|
||||
@@ -3692,12 +3692,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case LOPT_CNAME: /* --cname */
|
||||
{
|
||||
struct cname *new;
|
||||
- char *alias;
|
||||
- char *target;
|
||||
+ char *alias, *target, *ttls;
|
||||
+ int ttl = -1;
|
||||
|
||||
if (!(comma = split(arg)))
|
||||
ret_err(gen_err);
|
||||
|
||||
+ if ((ttls = split(comma)) && !atoi_check(ttls, &ttl))
|
||||
+ ret_err(_("bad TTL"));
|
||||
+
|
||||
alias = canonicalise_opt(arg);
|
||||
target = canonicalise_opt(comma);
|
||||
|
||||
@@ -3713,6 +3716,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->cnames = new;
|
||||
new->alias = alias;
|
||||
new->target = target;
|
||||
+ new->ttl = ttl;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -3913,14 +3917,22 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
struct host_record *new = opt_malloc(sizeof(struct host_record));
|
||||
memset(new, 0, sizeof(struct host_record));
|
||||
-
|
||||
+ new->ttl = -1;
|
||||
+
|
||||
if (!arg || !(comma = split(arg)))
|
||||
ret_err(_("Bad host-record"));
|
||||
|
||||
while (arg)
|
||||
{
|
||||
struct all_addr addr;
|
||||
- if (inet_pton(AF_INET, arg, &addr))
|
||||
+ char *dig;
|
||||
+
|
||||
+ for (dig = arg; *dig != 0; dig++)
|
||||
+ if (*dig < '0' || *dig > '9')
|
||||
+ break;
|
||||
+ if (*dig == 0)
|
||||
+ new->ttl = atoi(arg);
|
||||
+ else if (inet_pton(AF_INET, arg, &addr))
|
||||
new->addr = addr.addr.addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &addr))
|
||||
@@ -4601,7 +4613,25 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
+
|
||||
+ if (daemon->host_records)
|
||||
+ {
|
||||
+ struct host_record *hr;
|
||||
+
|
||||
+ for (hr = daemon->host_records; hr; hr = hr->next)
|
||||
+ if (hr->ttl == -1)
|
||||
+ hr->ttl = daemon->local_ttl;
|
||||
+ }
|
||||
+
|
||||
+ if (daemon->cnames)
|
||||
+ {
|
||||
+ struct cname *cn;
|
||||
+
|
||||
+ for (cn = daemon->cnames; cn; cn = cn->next)
|
||||
+ if (cn->ttl == -1)
|
||||
+ cn->ttl = daemon->local_ttl;
|
||||
+ }
|
||||
+
|
||||
if (daemon->if_addrs)
|
||||
{
|
||||
struct iname *tmp;
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index 9c0ddb5..3535a71 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1169,9 +1169,13 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
/* Return 0 ttl for DHCP entries, which might change
|
||||
before the lease expires. */
|
||||
|
||||
- if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||
+ if (crecp->flags & F_DHCP)
|
||||
return daemon->local_ttl;
|
||||
|
||||
+ /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
|
||||
+ if (crecp->flags & F_IMMORTAL)
|
||||
+ return crecp->ttd;
|
||||
+
|
||||
/* Return the Max TTL value if it is lower then the actual TTL */
|
||||
if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
|
||||
return crecp->ttd - now;
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
From d2aa7dfbb6d1088dcbea9fecc61b9293b320eb95 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Mon, 3 Aug 2015 21:52:12 +0100
|
||||
Subject: [PATCH] Include 0.0.0.0/8 in DNS rebind checks.
|
||||
|
||||
---
|
||||
CHANGELOG | 7 +++++++
|
||||
src/rfc1035.c | 3 ++-
|
||||
2 files changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/CHANGELOG b/CHANGELOG
|
||||
index 901da47..3f4026d 100644
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -1,3 +1,10 @@
|
||||
+version 2.76
|
||||
+ Include 0.0.0.0/8 in DNS rebind checks. This range
|
||||
+ translates to hosts on the local network, or, at
|
||||
+ least, 0.0.0.0 accesses the local host, so could
|
||||
+ be targets for DNS rebinding. See RFC 5735 section 3
|
||||
+ for details. Thanks to Stephen Röttger for the bug report.
|
||||
+
|
||||
version 2.75
|
||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||
dhcp-script is configured. Thanks to Adrian Davey for
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index 56647b0..29e9e65 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -728,7 +728,8 @@ int private_net(struct in_addr addr, int ban_localhost)
|
||||
in_addr_t ip_addr = ntohl(addr.s_addr);
|
||||
|
||||
return
|
||||
- (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
|
||||
+ (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
|
||||
+ ((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. "here" network */ ||
|
||||
((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
||||
((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
|
||||
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
||||
--
|
||||
1.7.10.4
|
||||
117
src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
Normal file
117
src/patches/dnsmasq/002-Add_--dhcp-ttl_option.patch
Normal file
@@ -0,0 +1,117 @@
|
||||
From 832e47beab95c2918b5264f0504f2fe6fe523e4c Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 24 Feb 2016 21:24:45 +0000
|
||||
Subject: [PATCH] Add --dhcp-ttl option.
|
||||
|
||||
---
|
||||
man/dnsmasq.8 | 5 ++++-
|
||||
src/dnsmasq.h | 2 +-
|
||||
src/option.c | 13 +++++++++++--
|
||||
src/rfc1035.c | 2 +-
|
||||
4 files changed, 17 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
|
||||
index 7bc1394..2bcce20 100644
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -60,7 +60,7 @@ in the same way as for DHCP-derived names. Note that this does not
|
||||
apply to domain names in cnames, PTR records, TXT records etc.
|
||||
.TP
|
||||
.B \-T, --local-ttl=<time>
|
||||
-When replying with information from /etc/hosts or the DHCP leases
|
||||
+When replying with information from /etc/hosts or configuration or the DHCP leases
|
||||
file dnsmasq by default sets the time-to-live field to zero, meaning
|
||||
that the requester should not itself cache the information. This is
|
||||
the correct thing to do in almost all situations. This option allows a
|
||||
@@ -68,6 +68,9 @@ time-to-live (in seconds) to be given for these replies. This will
|
||||
reduce the load on the server at the expense of clients using stale
|
||||
data under some circumstances.
|
||||
.TP
|
||||
+.B --dhcp-ttl=<time>
|
||||
+As for --local-ttl, but affects only replies with information from DHCP leases. If both are given, --dhcp-ttl applies for DHCP information, and --local-ttl for others. Setting this to zero eliminates the effect of --local-ttl for DHCP.
|
||||
+.TP
|
||||
.B --neg-ttl=<time>
|
||||
Negative replies from upstream servers normally contain time-to-live
|
||||
information in SOA records which dnsmasq uses for caching. If the
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 6344df5..9f73c3b 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -955,7 +955,7 @@ extern struct daemon {
|
||||
int max_logs; /* queue limit */
|
||||
int cachesize, ftabsize;
|
||||
int port, query_port, min_port, max_port;
|
||||
- unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
|
||||
+ unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
|
||||
char *dns_client_id;
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp, *dhcp6;
|
||||
diff --git a/src/option.c b/src/option.c
|
||||
index 7c5e6bc..3f6d162 100644
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -157,6 +157,7 @@ struct myoption {
|
||||
#define LOPT_MAXPORT 345
|
||||
#define LOPT_CPE_ID 346
|
||||
#define LOPT_SCRIPT_ARP 347
|
||||
+#define LOPT_DHCPTTL 348
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -319,6 +320,7 @@ static const struct myoption opts[] =
|
||||
{ "quiet-ra", 0, 0, LOPT_QUIET_RA },
|
||||
{ "dns-loop-detect", 0, 0, LOPT_LOOP_DETECT },
|
||||
{ "script-arp", 0, 0, LOPT_SCRIPT_ARP },
|
||||
+ { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -485,9 +487,10 @@ static struct {
|
||||
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
|
||||
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
|
||||
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
|
||||
- { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
|
||||
- { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops"), NULL },
|
||||
+ { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks."), NULL },
|
||||
+ { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops."), NULL },
|
||||
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
|
||||
+ { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -2580,6 +2583,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case LOPT_MINCTTL: /* --min-cache-ttl */
|
||||
case LOPT_MAXCTTL: /* --max-cache-ttl */
|
||||
case LOPT_AUTHTTL: /* --auth-ttl */
|
||||
+ case LOPT_DHCPTTL: /* --dhcp-ttl */
|
||||
{
|
||||
int ttl;
|
||||
if (!atoi_check(arg, &ttl))
|
||||
@@ -2598,6 +2602,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->max_cache_ttl = (unsigned long)ttl;
|
||||
else if (option == LOPT_AUTHTTL)
|
||||
daemon->auth_ttl = (unsigned long)ttl;
|
||||
+ else if (option == LOPT_DHCPTTL)
|
||||
+ {
|
||||
+ daemon->dhcp_ttl = (unsigned long)ttl;
|
||||
+ daemon->use_dhcp_ttl = 1;
|
||||
+ }
|
||||
else
|
||||
daemon->local_ttl = (unsigned long)ttl;
|
||||
break;
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index 3535a71..8f1e3b4 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1170,7 +1170,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
before the lease expires. */
|
||||
|
||||
if (crecp->flags & F_DHCP)
|
||||
- return daemon->local_ttl;
|
||||
+ return daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
|
||||
|
||||
/* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
|
||||
if (crecp->flags & F_IMMORTAL)
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,271 +0,0 @@
|
||||
From a7369bef8abd241c3d85633fa9c870943f091e76 Mon Sep 17 00:00:00 2001
|
||||
From: Ed Bardsley <ebardsley@google.com>
|
||||
Date: Wed, 5 Aug 2015 21:17:18 +0100
|
||||
Subject: [PATCH] Enhance --add-subnet to allow arbitary subnet addresses.
|
||||
|
||||
---
|
||||
CHANGELOG | 4 ++++
|
||||
man/dnsmasq.8 | 32 ++++++++++++++++++++-----------
|
||||
src/dnsmasq.h | 13 ++++++++++---
|
||||
src/option.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
src/rfc1035.c | 39 +++++++++++++++++++++++++++++++-------
|
||||
5 files changed, 121 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/CHANGELOG b/CHANGELOG
|
||||
index 3f4026d..bbc2834 100644
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -4,6 +4,10 @@ version 2.76
|
||||
least, 0.0.0.0 accesses the local host, so could
|
||||
be targets for DNS rebinding. See RFC 5735 section 3
|
||||
for details. Thanks to Stephen Röttger for the bug report.
|
||||
+
|
||||
+ Enhance --add-subnet to allow arbitrary subnet addresses.
|
||||
+ Thanks to Ed Barsley for the patch.
|
||||
+
|
||||
|
||||
version 2.75
|
||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
|
||||
index c8913b5..a23c898 100644
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -604,17 +604,27 @@ experimental. Also note that exposing MAC addresses in this way may
|
||||
have security and privacy implications. The warning about caching
|
||||
given for --add-subnet applies to --add-mac too.
|
||||
.TP
|
||||
-.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>]
|
||||
-Add the subnet address of the requestor to the DNS queries which are
|
||||
-forwarded upstream. The amount of the address forwarded depends on the
|
||||
-prefix length parameter: 32 (128 for IPv6) forwards the whole address,
|
||||
-zero forwards none of it but still marks the request so that no
|
||||
-upstream nameserver will add client address information either. The
|
||||
-default is zero for both IPv4 and IPv6. Note that upstream nameservers
|
||||
-may be configured to return different results based on this
|
||||
-information, but the dnsmasq cache does not take account. If a dnsmasq
|
||||
-instance is configured such that different results may be encountered,
|
||||
-caching should be disabled.
|
||||
+.B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]
|
||||
+Add a subnet address to the DNS queries which are forwarded
|
||||
+upstream. If an address is specified in the flag, it will be used,
|
||||
+otherwise, the address of the requestor will be used. The amount of
|
||||
+the address forwarded depends on the prefix length parameter: 32 (128
|
||||
+for IPv6) forwards the whole address, zero forwards none of it but
|
||||
+still marks the request so that no upstream nameserver will add client
|
||||
+address information either. The default is zero for both IPv4 and
|
||||
+IPv6. Note that upstream nameservers may be configured to return
|
||||
+different results based on this information, but the dnsmasq cache
|
||||
+does not take account. If a dnsmasq instance is configured such that
|
||||
+different results may be encountered, caching should be disabled.
|
||||
+
|
||||
+For example,
|
||||
+.B --add-subnet=24,96
|
||||
+will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors, respectively.
|
||||
+.B --add-subnet=1.2.3.4/24
|
||||
+will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
|
||||
+.B --add-subnet=1.2.3.4/24,1.2.3.4/24
|
||||
+will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
|
||||
+
|
||||
.TP
|
||||
.B \-c, --cache-size=<cachesize>
|
||||
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index cf1a782..f42acdb 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -541,6 +541,13 @@ struct iname {
|
||||
struct iname *next;
|
||||
};
|
||||
|
||||
+/* subnet parameters from command line */
|
||||
+struct mysubnet {
|
||||
+ union mysockaddr addr;
|
||||
+ int addr_used;
|
||||
+ int mask;
|
||||
+};
|
||||
+
|
||||
/* resolv-file parms from command-line */
|
||||
struct resolvc {
|
||||
struct resolvc *next;
|
||||
@@ -935,9 +942,9 @@ extern struct daemon {
|
||||
struct auth_zone *auth_zones;
|
||||
struct interface_name *int_names;
|
||||
char *mxtarget;
|
||||
- int addr4_netmask;
|
||||
- int addr6_netmask;
|
||||
- char *lease_file;
|
||||
+ struct mysubnet *add_subnet4;
|
||||
+ struct mysubnet *add_subnet6;
|
||||
+ char *lease_file;
|
||||
char *username, *groupname, *scriptuser;
|
||||
char *luascript;
|
||||
char *authserver, *hostmaster;
|
||||
diff --git a/src/option.c b/src/option.c
|
||||
index ecc2619..746cd11 100644
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -445,7 +445,7 @@ static struct {
|
||||
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
||||
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
|
||||
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
|
||||
- { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add requestor's IP subnet to forwarded DNS queries."), NULL },
|
||||
+ { LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
|
||||
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
|
||||
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
|
||||
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
|
||||
@@ -722,6 +722,20 @@ static void do_usage(void)
|
||||
|
||||
#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
|
||||
|
||||
+static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
|
||||
+{
|
||||
+ if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
|
||||
+ addr->sa.sa_family = AF_INET;
|
||||
+#ifdef HAVE_IPV6
|
||||
+ else if (inet_pton(AF_INET6, arg, &addr->in6.sin6_addr) > 0)
|
||||
+ addr->sa.sa_family = AF_INET6;
|
||||
+#endif
|
||||
+ else
|
||||
+ return _("bad address");
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
|
||||
{
|
||||
int source_port = 0, serv_port = NAMESERVER_PORT;
|
||||
@@ -1585,7 +1599,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
li = match_suffix->next;
|
||||
free(match_suffix->suffix);
|
||||
free(match_suffix);
|
||||
- }
|
||||
+ }
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1593,10 +1607,45 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
set_option_bool(OPT_CLIENT_SUBNET);
|
||||
if (arg)
|
||||
{
|
||||
+ char *err, *end;
|
||||
comma = split(arg);
|
||||
- if (!atoi_check(arg, &daemon->addr4_netmask) ||
|
||||
- (comma && !atoi_check(comma, &daemon->addr6_netmask)))
|
||||
- ret_err(gen_err);
|
||||
+
|
||||
+ struct mysubnet* new = opt_malloc(sizeof(struct mysubnet));
|
||||
+ if ((end = split_chr(arg, '/')))
|
||||
+ {
|
||||
+ /* has subnet+len */
|
||||
+ err = parse_mysockaddr(arg, &new->addr);
|
||||
+ if (err)
|
||||
+ ret_err(err);
|
||||
+ if (!atoi_check(end, &new->mask))
|
||||
+ ret_err(gen_err);
|
||||
+ new->addr_used = 1;
|
||||
+ }
|
||||
+ else if (!atoi_check(arg, &new->mask))
|
||||
+ ret_err(gen_err);
|
||||
+
|
||||
+ daemon->add_subnet4 = new;
|
||||
+
|
||||
+ new = opt_malloc(sizeof(struct mysubnet));
|
||||
+ if (comma)
|
||||
+ {
|
||||
+ if ((end = split_chr(comma, '/')))
|
||||
+ {
|
||||
+ /* has subnet+len */
|
||||
+ err = parse_mysockaddr(comma, &new->addr);
|
||||
+ if (err)
|
||||
+ ret_err(err);
|
||||
+ if (!atoi_check(end, &new->mask))
|
||||
+ ret_err(gen_err);
|
||||
+ new->addr_used = 1;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ if (!atoi_check(comma, &new->mask))
|
||||
+ ret_err(gen_err);
|
||||
+ }
|
||||
+ }
|
||||
+ daemon->add_subnet6 = new;
|
||||
}
|
||||
break;
|
||||
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index 29e9e65..6a51b30 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -629,26 +629,47 @@ struct subnet_opt {
|
||||
#endif
|
||||
};
|
||||
|
||||
+static void *get_addrp(union mysockaddr *addr, const short family)
|
||||
+{
|
||||
+#ifdef HAVE_IPV6
|
||||
+ if (family == AF_INET6)
|
||||
+ return &addr->in6.sin6_addr;
|
||||
+#endif
|
||||
+
|
||||
+ return &addr->in.sin_addr;
|
||||
+}
|
||||
+
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp;
|
||||
+ int sa_family = source->sa.sa_family;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (source->sa.sa_family == AF_INET6)
|
||||
{
|
||||
- opt->family = htons(2);
|
||||
- opt->source_netmask = daemon->addr6_netmask;
|
||||
- addrp = &source->in6.sin6_addr;
|
||||
+ opt->source_netmask = daemon->add_subnet6->mask;
|
||||
+ if (daemon->add_subnet6->addr_used)
|
||||
+ {
|
||||
+ sa_family = daemon->add_subnet6->addr.sa.sa_family;
|
||||
+ addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
|
||||
+ }
|
||||
+ else
|
||||
+ addrp = &source->in6.sin6_addr;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
- opt->family = htons(1);
|
||||
- opt->source_netmask = daemon->addr4_netmask;
|
||||
- addrp = &source->in.sin_addr;
|
||||
+ opt->source_netmask = daemon->add_subnet4->mask;
|
||||
+ if (daemon->add_subnet4->addr_used)
|
||||
+ {
|
||||
+ sa_family = daemon->add_subnet4->addr.sa.sa_family;
|
||||
+ addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
|
||||
+ }
|
||||
+ else
|
||||
+ addrp = &source->in.sin_addr;
|
||||
}
|
||||
|
||||
opt->scope_netmask = 0;
|
||||
@@ -656,6 +677,11 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
|
||||
if (opt->source_netmask != 0)
|
||||
{
|
||||
+#ifdef HAVE_IPV6
|
||||
+ opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
+#else
|
||||
+ opt->family = htons(1);
|
||||
+#endif
|
||||
len = ((opt->source_netmask - 1) >> 3) + 1;
|
||||
memcpy(opt->addr, addrp, len);
|
||||
if (opt->source_netmask & 7)
|
||||
@@ -2335,4 +2361,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
return len;
|
||||
}
|
||||
-
|
||||
--
|
||||
1.7.10.4
|
||||
17
src/patches/dnsmasq/003-Update_CHANGELOG.patch
Normal file
17
src/patches/dnsmasq/003-Update_CHANGELOG.patch
Normal file
@@ -0,0 +1,17 @@
|
||||
X-Git-Url: http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=blobdiff_plain;f=CHANGELOG;h=6d9ba490488f80ef565f459cef3c110bdf31212c;hp=14354f2506a7fbf8360cd32c96e1d7ce1bfeb3f9;hb=e06e6e34bffd781b7cefa49b25fb8ae863654ca2;hpb=832e47beab95c2918b5264f0504f2fe6fe523e4c
|
||||
|
||||
diff --git a/CHANGELOG b/CHANGELOG
|
||||
index 14354f2..6d9ba49 100644
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -48,6 +48,10 @@ version 2.76
|
||||
(ie xx::0 to xx::ffff:ffff:ffff:ffff)
|
||||
Thanks to Laurent Bendel for spotting this problem.
|
||||
|
||||
+ Add support for a TTL parameter in --host-record and
|
||||
+ --cname.
|
||||
+
|
||||
+ Add --dhcp-ttl option.
|
||||
|
||||
version 2.75
|
||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||
@@ -1,34 +0,0 @@
|
||||
From 3a3965ac21b1b759eab8799b6edb09195b671306 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 9 Aug 2015 17:45:06 +0100
|
||||
Subject: [PATCH] Don't answer non-auth queries for auth zones locally when
|
||||
--localise-queries set.
|
||||
|
||||
---
|
||||
src/forward.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 2731b90..b76a974 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -1365,7 +1365,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* find queries for zones we're authoritative for, and answer them directly */
|
||||
- if (!auth_dns)
|
||||
+ if (!auth_dns && !option_bool(OPT_LOCALISE))
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, daemon->namebuff, NULL))
|
||||
{
|
||||
@@ -1904,7 +1904,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* find queries for zones we're authoritative for, and answer them directly */
|
||||
- if (!auth_dns)
|
||||
+ if (!auth_dns && !option_bool(OPT_LOCALISE))
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
if (in_zone(zone, daemon->namebuff, NULL))
|
||||
{
|
||||
--
|
||||
1.7.10.4
|
||||
136
src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
Normal file
136
src/patches/dnsmasq/004-Add_--tftp-mtu_option.patch
Normal file
@@ -0,0 +1,136 @@
|
||||
From bec366b4041df72b559e713f1c924177676e6eb0 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 24 Feb 2016 22:03:26 +0000
|
||||
Subject: [PATCH] Add --tftp-mtu option.
|
||||
|
||||
---
|
||||
CHANGELOG | 4 ++++
|
||||
man/dnsmasq.8 | 4 ++++
|
||||
src/dnsmasq.h | 2 +-
|
||||
src/option.c | 10 +++++++++-
|
||||
src/tftp.c | 14 ++++++++++++--
|
||||
5 files changed, 30 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/CHANGELOG b/CHANGELOG
|
||||
index 6d9ba49..9218b8c 100644
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -53,6 +53,10 @@ version 2.76
|
||||
|
||||
Add --dhcp-ttl option.
|
||||
|
||||
+ Add --tftp-mtu option. Thanks to Patrick McLean for the
|
||||
+ initial patch.
|
||||
+
|
||||
+
|
||||
version 2.75
|
||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||
dhcp-script is configured. Thanks to Adrian Davey for
|
||||
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
|
||||
index 2bcce20..3cf48cd 100644
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -1810,6 +1810,10 @@ require about (2*n) + 10 descriptors. If
|
||||
.B --tftp-port-range
|
||||
is given, that can affect the number of concurrent connections.
|
||||
.TP
|
||||
+.B --tftp-mtu=<mtu size>
|
||||
+Use size as the ceiling of the MTU supported by the intervening network when
|
||||
+negotiating TFTP blocksize, overriding the MTU setting of the local interface if it is larger.
|
||||
+.TP
|
||||
.B --tftp-no-blocksize
|
||||
Stop the TFTP server from negotiating the "blocksize" option with a
|
||||
client. Some buggy clients request this option but then behave badly
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 9f73c3b..280ad9d 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -975,7 +975,7 @@ extern struct daemon {
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||||
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs;
|
||||
- int dhcp_max, tftp_max;
|
||||
+ int dhcp_max, tftp_max, tftp_mtu;
|
||||
int dhcp_server_port, dhcp_client_port;
|
||||
int start_tftp_port, end_tftp_port;
|
||||
unsigned int min_leasetime;
|
||||
diff --git a/src/option.c b/src/option.c
|
||||
index 3f6d162..765965f 100644
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -158,7 +158,8 @@ struct myoption {
|
||||
#define LOPT_CPE_ID 346
|
||||
#define LOPT_SCRIPT_ARP 347
|
||||
#define LOPT_DHCPTTL 348
|
||||
-
|
||||
+#define LOPT_TFTP_MTU 349
|
||||
+
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
#else
|
||||
@@ -244,6 +245,7 @@ static const struct myoption opts[] =
|
||||
{ "tftp-unique-root", 0, 0, LOPT_APREF },
|
||||
{ "tftp-root", 1, 0, LOPT_PREFIX },
|
||||
{ "tftp-max", 1, 0, LOPT_TFTP_MAX },
|
||||
+ { "tftp-mtu", 1, 0, LOPT_TFTP_MTU },
|
||||
{ "tftp-lowercase", 0, 0, LOPT_TFTP_LC },
|
||||
{ "ptr-record", 1, 0, LOPT_PTR },
|
||||
{ "naptr-record", 1, 0, LOPT_NAPTR },
|
||||
@@ -432,6 +434,7 @@ static struct {
|
||||
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
|
||||
{ LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
|
||||
{ LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
|
||||
+ { LOPT_TFTP_MTU, ARG_ONE, "<integer>", gettext_noop("Maximum MTU to use for TFTP transfers."), NULL },
|
||||
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
|
||||
{ LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
|
||||
{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
|
||||
@@ -2625,6 +2628,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(gen_err);
|
||||
break;
|
||||
|
||||
+ case LOPT_TFTP_MTU: /* --tftp-mtu */
|
||||
+ if (!atoi_check(arg, &daemon->tftp_mtu))
|
||||
+ ret_err(gen_err);
|
||||
+ break;
|
||||
+
|
||||
case LOPT_PREFIX: /* --tftp-prefix */
|
||||
comma = split(arg);
|
||||
if (comma)
|
||||
diff --git a/src/tftp.c b/src/tftp.c
|
||||
index 00ed2fc..dc4aa85 100644
|
||||
--- a/src/tftp.c
|
||||
+++ b/src/tftp.c
|
||||
@@ -103,8 +103,10 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (listen->iface)
|
||||
{
|
||||
addr = listen->iface->addr;
|
||||
- mtu = listen->iface->mtu;
|
||||
name = listen->iface->name;
|
||||
+ mtu = listen->iface->mtu;
|
||||
+ if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
|
||||
+ mtu = daemon->tftp_mtu;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -234,9 +236,17 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
|
||||
- mtu = ifr.ifr_mtu;
|
||||
+ {
|
||||
+ mtu = ifr.ifr_mtu;
|
||||
+ if (daemon->tftp_mtu != 0 && daemon->tftp_mtu < mtu)
|
||||
+ mtu = daemon->tftp_mtu;
|
||||
+ }
|
||||
}
|
||||
|
||||
+ /* Failed to get interface mtu - can use configured value. */
|
||||
+ if (mtu == 0)
|
||||
+ mtu = daemon->tftp_mtu;
|
||||
+
|
||||
if (name)
|
||||
{
|
||||
/* check for per-interface prefix */
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
From 5e3e464ac4022ee0b3794513abe510817e2cf3ca Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 25 Aug 2015 23:08:39 +0100
|
||||
Subject: [PATCH] Fix behaviour of empty dhcp-option=option6:dns-server, which
|
||||
should inhibit sending option.
|
||||
|
||||
---
|
||||
src/rfc3315.c | 9 +++++----
|
||||
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/rfc3315.c b/src/rfc3315.c
|
||||
index 2665d0d..3f1f9ee 100644
|
||||
--- a/src/rfc3315.c
|
||||
+++ b/src/rfc3315.c
|
||||
@@ -1320,15 +1320,16 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
|
||||
|
||||
if (opt_cfg->opt == OPTION6_REFRESH_TIME)
|
||||
done_refresh = 1;
|
||||
+
|
||||
+ if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
+ done_dns = 1;
|
||||
|
||||
- if (opt_cfg->flags & DHOPT_ADDR6)
|
||||
+ /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */
|
||||
+ if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
{
|
||||
int len, j;
|
||||
struct in6_addr *a;
|
||||
|
||||
- if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
- done_dns = 1;
|
||||
-
|
||||
for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
|
||||
j < opt_cfg->len; j += IN6ADDRSZ, a++)
|
||||
if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
From 9cdcfe9f19ffd45bac4e5b459879bf7c50a287ed Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 26 Aug 2015 22:38:08 +0100
|
||||
Subject: [PATCH] Suggest solution to ENOMEM error with IPv6 multicast.
|
||||
|
||||
---
|
||||
src/network.c | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/network.c b/src/network.c
|
||||
index a1d90c8..819302f 100644
|
||||
--- a/src/network.c
|
||||
+++ b/src/network.c
|
||||
@@ -1076,23 +1076,30 @@ void join_multicast(int dienow)
|
||||
|
||||
if ((daemon->doing_dhcp6 || daemon->relay6) &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
- err = 1;
|
||||
+ err = errno;
|
||||
|
||||
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_dhcp6 &&
|
||||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
- err = 1;
|
||||
+ err = errno;
|
||||
|
||||
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
|
||||
|
||||
if (daemon->doing_ra &&
|
||||
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||
- err = 1;
|
||||
+ err = errno;
|
||||
|
||||
if (err)
|
||||
{
|
||||
char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
|
||||
+ errno = err;
|
||||
+
|
||||
+#ifdef HAVE_LINUX_NETWORK
|
||||
+ if (errno == ENOMEM)
|
||||
+ my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max"));
|
||||
+#endif
|
||||
+
|
||||
if (dienow)
|
||||
die(s, iface->name, EC_BADNET);
|
||||
else
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
From 20fd11e11a9d09edcea94de135396ae1541fbbab Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 26 Aug 2015 22:48:13 +0100
|
||||
Subject: [PATCH] Clarify man page on RDNSS set in router advertisement.
|
||||
|
||||
---
|
||||
man/dnsmasq.8 | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
|
||||
index a23c898..d51b10f 100644
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -1687,15 +1687,15 @@ creation are handled by a different protocol. When DHCP is in use,
|
||||
only a subset of this is needed, and dnsmasq can handle it, using
|
||||
existing DHCP configuration to provide most data. When RA is enabled,
|
||||
dnsmasq will advertise a prefix for each dhcp-range, with default
|
||||
-router and recursive DNS server as the relevant link-local address on
|
||||
-the machine running dnsmasq. By default, he "managed address" bits are set, and
|
||||
+router as the relevant link-local address on
|
||||
+the machine running dnsmasq. By default, the "managed address" bits are set, and
|
||||
the "use SLAAC" bit is reset. This can be changed for individual
|
||||
subnets with the mode keywords described in
|
||||
.B --dhcp-range.
|
||||
RFC6106 DNS parameters are included in the advertisements. By default,
|
||||
the relevant link-local address of the machine running dnsmasq is sent
|
||||
as recursive DNS server. If provided, the DHCPv6 options dns-server and
|
||||
-domain-search are used for RDNSS and DNSSL.
|
||||
+domain-search are used for the DNS server (RDNSS) and the domain serach list (DNSSL).
|
||||
.TP
|
||||
.B --ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
|
||||
Set non-default values for router advertisements sent via an
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
From 6de81f1250fd323c9155de065d5a9dc200a6f20b Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 9 Sep 2015 22:51:13 +0100
|
||||
Subject: [PATCH] Handle signed dangling CNAME replies to DS queries.
|
||||
|
||||
---
|
||||
src/dnssec.c | 7 ++-----
|
||||
1 file changed, 2 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 4deda24..67ce486 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1232,11 +1232,8 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
|
||||
/* If we return STAT_NO_SIG, name contains the name of the DS query */
|
||||
if (val == STAT_NO_SIG)
|
||||
- {
|
||||
- *keyname = 0;
|
||||
- return val;
|
||||
- }
|
||||
-
|
||||
+ return val;
|
||||
+
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||
from the DS's zone, and not the parent zone. */
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
From 102208df695e886a3086754d32bf7f8c541fbe46 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 10 Sep 2015 21:50:00 +0100
|
||||
Subject: [PATCH] DHCPv6 option 56 does not hold an address list. (RFC 5908).
|
||||
|
||||
---
|
||||
src/dhcp-common.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
|
||||
index bc48f41..8fc171a 100644
|
||||
--- a/src/dhcp-common.c
|
||||
+++ b/src/dhcp-common.c
|
||||
@@ -599,7 +599,7 @@ static const struct opttab_t opttab6[] = {
|
||||
{ "sntp-server", 31, OT_ADDR_LIST },
|
||||
{ "information-refresh-time", 32, OT_TIME },
|
||||
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
|
||||
- { "ntp-server", 56, OT_ADDR_LIST },
|
||||
+ { "ntp-server", 56, 0 },
|
||||
{ "bootfile-url", 59, OT_NAME },
|
||||
{ "bootfile-param", 60, OT_CSTRING },
|
||||
{ NULL, 0, 0 }
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
From 77607cbea0ad0f876dfb79c8b2c121ee400d57d0 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 10 Sep 2015 23:08:43 +0100
|
||||
Subject: [PATCH] Respect the --no-resolv flag in inotify code.
|
||||
|
||||
---
|
||||
CHANGELOG | 7 ++++++-
|
||||
debian/changelog | 6 ++++++
|
||||
src/inotify.c | 3 +++
|
||||
3 files changed, 15 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/CHANGELOG b/CHANGELOG
|
||||
index bbc2834..d6e309f 100644
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -7,8 +7,13 @@ version 2.76
|
||||
|
||||
Enhance --add-subnet to allow arbitrary subnet addresses.
|
||||
Thanks to Ed Barsley for the patch.
|
||||
+
|
||||
+ Respect the --no-resolv flag in inotify code. Fixes bug
|
||||
+ which caused dnsmasq to fail to start if a resolv-file
|
||||
+ was a dangling symbolic link, even of --no-resolv set.
|
||||
+ Thanks to Alexander Kurtz for spotting the problem.
|
||||
+
|
||||
|
||||
-
|
||||
version 2.75
|
||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||
dhcp-script is configured. Thanks to Adrian Davey for
|
||||
diff --git a/src/inotify.c b/src/inotify.c
|
||||
index 52d412f..ef05c58 100644
|
||||
--- a/src/inotify.c
|
||||
+++ b/src/inotify.c
|
||||
@@ -90,6 +90,9 @@ void inotify_dnsmasq_init()
|
||||
|
||||
if (daemon->inotifyfd == -1)
|
||||
die(_("failed to create inotify: %s"), NULL, EC_MISC);
|
||||
+
|
||||
+ if (option_bool(OPT_NO_RESOLV))
|
||||
+ return;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
{
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
From 27b78d990b7cd901866ad6f1a17b9d633a95fdce Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sat, 26 Sep 2015 21:40:45 +0100
|
||||
Subject: [PATCH] Rationalise 5e3e464ac4022ee0b3794513abe510817e2cf3ca
|
||||
|
||||
---
|
||||
src/rfc3315.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/rfc3315.c b/src/rfc3315.c
|
||||
index 3f1f9ee..3ed8623 100644
|
||||
--- a/src/rfc3315.c
|
||||
+++ b/src/rfc3315.c
|
||||
@@ -1324,8 +1324,7 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
|
||||
if (opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
done_dns = 1;
|
||||
|
||||
- /* Empty DNS_SERVER option will not set DHOPT_ADDR6 */
|
||||
- if ((opt_cfg->flags & DHOPT_ADDR6) || opt_cfg->opt == OPTION6_DNS_SERVER)
|
||||
+ if (opt_cfg->flags & DHOPT_ADDR6)
|
||||
{
|
||||
int len, j;
|
||||
struct in6_addr *a;
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
From 98079ea89851da1df4966dfdfa1852a98da02912 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 13 Oct 2015 20:30:32 +0100
|
||||
Subject: [PATCH] Catch errors from sendmsg in DHCP code. Logs, eg, iptables
|
||||
DROPS of dest 255.255.255.255
|
||||
|
||||
---
|
||||
src/dhcp.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/dhcp.c b/src/dhcp.c
|
||||
index e6fceb1..1c85e42 100644
|
||||
--- a/src/dhcp.c
|
||||
+++ b/src/dhcp.c
|
||||
@@ -452,8 +452,13 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
#endif
|
||||
|
||||
while(retry_send(sendmsg(fd, &msg, 0)));
|
||||
+
|
||||
+ /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
|
||||
+ if (errno != 0)
|
||||
+ my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
|
||||
+ inet_ntoa(dest.sin_addr), strerror(errno));
|
||||
}
|
||||
-
|
||||
+
|
||||
/* check against secondary interface addresses */
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
From 90477fb79420a34124b66ebd808c578817a30e4c Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 20 Oct 2015 21:21:32 +0100
|
||||
Subject: [PATCH] Update list of subnet for --bogus-priv
|
||||
|
||||
RFC6303 specifies & recommends following zones not be forwarded
|
||||
to globally facing servers.
|
||||
+------------------------------+-----------------------+
|
||||
| Zone | Description |
|
||||
+------------------------------+-----------------------+
|
||||
| 0.IN-ADDR.ARPA | IPv4 "THIS" NETWORK |
|
||||
| 127.IN-ADDR.ARPA | IPv4 Loopback NETWORK |
|
||||
| 254.169.IN-ADDR.ARPA | IPv4 LINK LOCAL |
|
||||
| 2.0.192.IN-ADDR.ARPA | IPv4 TEST-NET-1 |
|
||||
| 100.51.198.IN-ADDR.ARPA | IPv4 TEST-NET-2 |
|
||||
| 113.0.203.IN-ADDR.ARPA | IPv4 TEST-NET-3 |
|
||||
| 255.255.255.255.IN-ADDR.ARPA | IPv4 BROADCAST |
|
||||
+------------------------------+-----------------------+
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
|
||||
---
|
||||
src/rfc1035.c | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index 6a51b30..4eb1772 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -756,10 +756,14 @@ int private_net(struct in_addr addr, int ban_localhost)
|
||||
return
|
||||
(((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
|
||||
((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. "here" network */ ||
|
||||
- ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
||||
((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
|
||||
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
|
||||
- ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
|
||||
+ ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
|
||||
+ ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
|
||||
+ ((ip_addr & 0xFFFFFF00) == 0xC0000200) /* 192.0.2.0/24 (test-net) */ ||
|
||||
+ ((ip_addr & 0xFFFFFF00) == 0xC6336400) /* 198.51.100.0/24(test-net) */ ||
|
||||
+ ((ip_addr & 0xFFFFFF00) == 0xCB007100) /* 203.0.113.0/24 (test-net) */ ||
|
||||
+ ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 (broadcast)*/ ;
|
||||
}
|
||||
|
||||
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
From 41a8d9e99be9f2cc8b02051dd322cb45e0faac87 Mon Sep 17 00:00:00 2001
|
||||
From: =?utf8?q?Edwin=20T=C3=B6r=C3=B6k?= <edwin+ml-cerowrt@etorok.net>
|
||||
Date: Sat, 14 Nov 2015 17:45:48 +0000
|
||||
Subject: [PATCH] Fix crash when empty address from DNS overlays A record from
|
||||
hosts.
|
||||
|
||||
---
|
||||
CHANGELOG | 5 +++++
|
||||
src/cache.c | 2 +-
|
||||
2 files changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/CHANGELOG b/CHANGELOG
|
||||
index d6e309f..93c73d0 100644
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -13,6 +13,11 @@ version 2.76
|
||||
was a dangling symbolic link, even of --no-resolv set.
|
||||
Thanks to Alexander Kurtz for spotting the problem.
|
||||
|
||||
+ Fix crash when an A or AAAA record is defined locally,
|
||||
+ in a hosts file, and an upstream server sends a reply
|
||||
+ that the same name is empty. Thanks to Edwin Török for
|
||||
+ the patch.
|
||||
+
|
||||
|
||||
version 2.75
|
||||
Fix reversion on 2.74 which caused 100% CPU use when a
|
||||
diff --git a/src/cache.c b/src/cache.c
|
||||
index 178d654..1b76b67 100644
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -481,7 +481,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
existing record is for an A or AAAA and
|
||||
the record we're trying to insert is the same,
|
||||
just drop the insert, but don't error the whole process. */
|
||||
- if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD))
|
||||
+ if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
|
||||
{
|
||||
if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
|
||||
new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From 67ab3285b5d9a1b1e20e034cf272867fdab8a0f9 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 20 Nov 2015 23:20:47 +0000
|
||||
Subject: [PATCH] Handle unknown DS hash algos correctly.
|
||||
|
||||
When we can validate a DS RRset, but don't speak the hash algo it
|
||||
contains, treat that the same as an NSEC/3 proving that the DS
|
||||
doesn't exist. 4025 5.2
|
||||
---
|
||||
src/dnssec.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 67ce486..b4dc14e 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1005,6 +1005,19 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (crecp->flags & F_NEG)
|
||||
return STAT_INSECURE_DS;
|
||||
|
||||
+ /* 4035 5.2
|
||||
+ If the validator does not support any of the algorithms listed in an
|
||||
+ authenticated DS RRset, then the resolver has no supported
|
||||
+ authentication path leading from the parent to the child. The
|
||||
+ resolver should treat this case as it would the case of an
|
||||
+ authenticated NSEC RRset proving that no DS RRset exists, */
|
||||
+ for (recp1 = crecp; recp1; recp1 = cache_find_by_name(recp1, name, now, F_DS))
|
||||
+ if (hash_find(ds_digest_name(recp1->addr.ds.digest)))
|
||||
+ break;
|
||||
+
|
||||
+ if (!recp1)
|
||||
+ return STAT_INSECURE_DS;
|
||||
+
|
||||
/* NOTE, we need to find ONE DNSKEY which matches the DS */
|
||||
for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
|
||||
{
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
From 0007ee90646a5a78a96ee729932e89d31c69513a Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sat, 21 Nov 2015 21:47:41 +0000
|
||||
Subject: [PATCH] Fix crash at start up with conf-dir=/path,*
|
||||
|
||||
Thanks to Brian Carpenter and American Fuzzy Lop for finding the bug.
|
||||
---
|
||||
src/option.c | 14 ++++++++++----
|
||||
1 file changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/option.c b/src/option.c
|
||||
index 746cd11..71beb98 100644
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -1515,10 +1515,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
li = opt_malloc(sizeof(struct list));
|
||||
if (*arg == '*')
|
||||
{
|
||||
- li->next = match_suffix;
|
||||
- match_suffix = li;
|
||||
- /* Have to copy: buffer is overwritten */
|
||||
- li->suffix = opt_string_alloc(arg+1);
|
||||
+ /* "*" with no suffix is a no-op */
|
||||
+ if (arg[1] == 0)
|
||||
+ free(li);
|
||||
+ else
|
||||
+ {
|
||||
+ li->next = match_suffix;
|
||||
+ match_suffix = li;
|
||||
+ /* Have to copy: buffer is overwritten */
|
||||
+ li->suffix = opt_string_alloc(arg+1);
|
||||
+ }
|
||||
}
|
||||
else
|
||||
{
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,612 +0,0 @@
|
||||
From 93be5b1e023b0c661e1ec2cd6d811a8ec9055c49 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 15 Dec 2015 12:04:40 +0000
|
||||
Subject: [PATCH] Abandon caching RRSIGs and returning them from cache.
|
||||
|
||||
The list of exceptions to being able to locally answer
|
||||
cached data for validated records when DNSSEC data is requested
|
||||
was getting too long, so don't ever do that. This means
|
||||
that the cache no longer has to hold RRSIGS and allows
|
||||
us to lose lots of code. Note that cached validated
|
||||
answers are still returned as long as do=0
|
||||
---
|
||||
src/cache.c | 38 ++---------
|
||||
src/dnsmasq.h | 10 +--
|
||||
src/dnssec.c | 94 ++++-----------------------
|
||||
src/rfc1035.c | 197 ++++++---------------------------------------------------
|
||||
4 files changed, 42 insertions(+), 297 deletions(-)
|
||||
|
||||
diff --git a/src/cache.c b/src/cache.c
|
||||
index 1b76b67..51ba7cc 100644
|
||||
--- a/src/cache.c
|
||||
+++ b/src/cache.c
|
||||
@@ -189,12 +189,7 @@ static void cache_hash(struct crec *crecp)
|
||||
static void cache_blockdata_free(struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_DNSKEY)
|
||||
- {
|
||||
- if (crecp->flags & F_DS)
|
||||
- blockdata_free(crecp->addr.sig.keydata);
|
||||
- else
|
||||
- blockdata_free(crecp->addr.key.keydata);
|
||||
- }
|
||||
+ blockdata_free(crecp->addr.key.keydata);
|
||||
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
blockdata_free(crecp->addr.ds.keydata);
|
||||
}
|
||||
@@ -369,13 +364,8 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
- /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
|
||||
- type-covered sensitive for RRSIG */
|
||||
- if ((flags & (F_DNSKEY | F_DS)) &&
|
||||
- (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
|
||||
- crecp->uid == addr->addr.dnssec.class &&
|
||||
- (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
|
||||
- crecp->addr.sig.type_covered == addr->addr.dnssec.type))
|
||||
+ /* Deletion has to be class-sensitive for DS and DNSKEY */
|
||||
+ if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
|
||||
{
|
||||
if (crecp->flags & F_CONFIG)
|
||||
return crecp;
|
||||
@@ -532,13 +522,9 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
struct all_addr free_addr = new->addr.addr;;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
- /* For DNSSEC records, addr holds class and type_covered for RRSIG */
|
||||
+ /* For DNSSEC records, addr holds class. */
|
||||
if (new->flags & (F_DS | F_DNSKEY))
|
||||
- {
|
||||
- free_addr.addr.dnssec.class = new->uid;
|
||||
- if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
|
||||
- free_addr.addr.dnssec.type = new->addr.sig.type_covered;
|
||||
- }
|
||||
+ free_addr.addr.dnssec.class = new->uid;
|
||||
#endif
|
||||
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
@@ -653,9 +639,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
if ((crecp->flags & F_FORWARD) &&
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
|
||||
-#endif
|
||||
(crecp->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
@@ -713,9 +696,6 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
|
||||
if (ans &&
|
||||
(ans->flags & F_FORWARD) &&
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
|
||||
-#endif
|
||||
(ans->flags & prot) &&
|
||||
hostname_isequal(cache_get_name(ans), name))
|
||||
return ans;
|
||||
@@ -1472,11 +1452,7 @@ void dump_cache(time_t now)
|
||||
#ifdef HAVE_DNSSEC
|
||||
else if (cache->flags & F_DS)
|
||||
{
|
||||
- if (cache->flags & F_DNSKEY)
|
||||
- /* RRSIG */
|
||||
- sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
|
||||
- cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
|
||||
- else if (!(cache->flags & F_NEG))
|
||||
+ if (!(cache->flags & F_NEG))
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
}
|
||||
@@ -1502,8 +1478,6 @@ void dump_cache(time_t now)
|
||||
else if (cache->flags & F_CNAME)
|
||||
t = "C";
|
||||
#ifdef HAVE_DNSSEC
|
||||
- else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
|
||||
- t = "G"; /* DNSKEY and DS set -> RRISG */
|
||||
else if (cache->flags & F_DS)
|
||||
t = "S";
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 023a1cf..4344cae 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -398,14 +398,9 @@ struct crec {
|
||||
unsigned char algo;
|
||||
unsigned char digest;
|
||||
} ds;
|
||||
- struct {
|
||||
- struct blockdata *keydata;
|
||||
- unsigned short keylen, type_covered, keytag;
|
||||
- char algo;
|
||||
- } sig;
|
||||
} addr;
|
||||
time_t ttd; /* time to die */
|
||||
- /* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
|
||||
+ /* used as class if DNSKEY/DS, index to source for F_HOSTS */
|
||||
unsigned int uid;
|
||||
unsigned short flags;
|
||||
union {
|
||||
@@ -445,8 +440,7 @@ struct crec {
|
||||
#define F_SECSTAT (1u<<24)
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
-#define F_NSIGMATCH (1u<<27)
|
||||
-#define F_NOEXTRA (1u<<28)
|
||||
+#define F_NOEXTRA (1u<<27)
|
||||
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index de7b335..1ae03a6 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1004,7 +1004,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
{
|
||||
unsigned char *psave, *p = (unsigned char *)(header+1);
|
||||
struct crec *crecp, *recp1;
|
||||
- int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag, type_covered;
|
||||
+ int rc, j, qtype, qclass, ttl, rdlen, flags, algo, valid, keytag;
|
||||
struct blockdata *key;
|
||||
struct all_addr a;
|
||||
|
||||
@@ -1115,7 +1115,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
if (valid)
|
||||
{
|
||||
- /* DNSKEY RRset determined to be OK, now cache it and the RRsigs that sign it. */
|
||||
+ /* DNSKEY RRset determined to be OK, now cache it. */
|
||||
cache_start_insert();
|
||||
|
||||
p = skip_questions(header, plen);
|
||||
@@ -1155,7 +1155,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
{
|
||||
if (!(recp1 = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DNSSECOK)))
|
||||
- blockdata_free(key);
|
||||
+ {
|
||||
+ blockdata_free(key);
|
||||
+ return STAT_BOGUS;
|
||||
+ }
|
||||
else
|
||||
{
|
||||
a.addr.keytag = keytag;
|
||||
@@ -1169,38 +1172,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
}
|
||||
}
|
||||
- else if (qtype == T_RRSIG)
|
||||
- {
|
||||
- /* RRSIG, cache if covers DNSKEY RRset */
|
||||
- if (rdlen < 18)
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
-
|
||||
- GETSHORT(type_covered, p);
|
||||
-
|
||||
- if (type_covered == T_DNSKEY)
|
||||
- {
|
||||
- a.addr.dnssec.class = class;
|
||||
- a.addr.dnssec.type = type_covered;
|
||||
-
|
||||
- algo = *p++;
|
||||
- p += 13; /* labels, orig_ttl, expiration, inception */
|
||||
- GETSHORT(keytag, p);
|
||||
- if ((key = blockdata_alloc((char*)psave, rdlen)))
|
||||
- {
|
||||
- if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
|
||||
- blockdata_free(key);
|
||||
- else
|
||||
- {
|
||||
- crecp->addr.sig.keydata = key;
|
||||
- crecp->addr.sig.keylen = rdlen;
|
||||
- crecp->addr.sig.keytag = keytag;
|
||||
- crecp->addr.sig.type_covered = type_covered;
|
||||
- crecp->addr.sig.algo = algo;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
+
|
||||
p = psave;
|
||||
}
|
||||
|
||||
@@ -1326,7 +1298,8 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
cache_start_insert();
|
||||
|
||||
a.addr.dnssec.class = class;
|
||||
- cache_insert(name, &a, now, ttl, flags);
|
||||
+ if (!cache_insert(name, &a, now, ttl, flags))
|
||||
+ return STAT_BOGUS;
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
@@ -2028,14 +2001,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
/* Not done, validate now */
|
||||
if (j == i)
|
||||
{
|
||||
- int ttl, keytag, algo, digest, type_covered, sigcnt, rrcnt;
|
||||
+ int ttl, keytag, algo, digest, sigcnt, rrcnt;
|
||||
unsigned char *psave;
|
||||
struct all_addr a;
|
||||
struct blockdata *key;
|
||||
struct crec *crecp;
|
||||
char *wildname;
|
||||
- int have_wildcard = 0;
|
||||
-
|
||||
+
|
||||
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -2096,8 +2068,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
if (rc == STAT_SECURE_WILDCARD)
|
||||
{
|
||||
- have_wildcard = 1;
|
||||
-
|
||||
/* An attacker replay a wildcard answer with a different
|
||||
answer and overlay a genuine RR. To prove this
|
||||
hasn't happened, the answer must prove that
|
||||
@@ -2119,7 +2089,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
return rc;
|
||||
}
|
||||
|
||||
- /* Cache RRsigs in answer section, and if we just validated a DS RRset, cache it */
|
||||
+ /* If we just validated a DS RRset, cache it */
|
||||
/* Also note if the RRset is the answer to the question, or the target of a CNAME */
|
||||
cache_start_insert();
|
||||
|
||||
@@ -2168,45 +2138,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
}
|
||||
}
|
||||
- else if (type2 == T_RRSIG)
|
||||
- {
|
||||
- if (rdlen2 < 18)
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
-
|
||||
- GETSHORT(type_covered, p2);
|
||||
-
|
||||
- if (type_covered == type1 &&
|
||||
- (type_covered == T_A || type_covered == T_AAAA ||
|
||||
- type_covered == T_CNAME || type_covered == T_DS ||
|
||||
- type_covered == T_DNSKEY || type_covered == T_PTR))
|
||||
- {
|
||||
- a.addr.dnssec.type = type_covered;
|
||||
- a.addr.dnssec.class = class1;
|
||||
-
|
||||
- algo = *p2++;
|
||||
- p2 += 13; /* labels, orig_ttl, expiration, inception */
|
||||
- GETSHORT(keytag, p2);
|
||||
-
|
||||
- /* We don't cache sigs for wildcard answers, because to reproduce the
|
||||
- answer from the cache will require one or more NSEC/NSEC3 records
|
||||
- which we don't cache. The lack of the RRSIG ensures that a query for
|
||||
- this RRset asking for a secure answer will always be forwarded. */
|
||||
- if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
|
||||
- {
|
||||
- if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
|
||||
- blockdata_free(key);
|
||||
- else
|
||||
- {
|
||||
- crecp->addr.sig.keydata = key;
|
||||
- crecp->addr.sig.keylen = rdlen2;
|
||||
- crecp->addr.sig.keytag = keytag;
|
||||
- crecp->addr.sig.type_covered = type_covered;
|
||||
- crecp->addr.sig.algo = algo;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
+
|
||||
p2 = psave;
|
||||
}
|
||||
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index 4eb1772..def8fa0 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1275,11 +1275,9 @@ int check_for_local_domain(char *name, time_t now)
|
||||
struct naptr *naptr;
|
||||
|
||||
/* Note: the call to cache_find_by_name is intended to find any record which matches
|
||||
- ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
|
||||
- cache_find_by name ordinarily only returns records with an exact match on those bits (ie
|
||||
- for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
|
||||
+ ie A, AAAA, CNAME. */
|
||||
|
||||
- if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
|
||||
+ if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
return 1;
|
||||
|
||||
@@ -1566,9 +1564,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
GETSHORT(flags, pheader);
|
||||
|
||||
if ((sec_reqd = flags & 0x8000))
|
||||
- *do_bit = 1;/* do bit */
|
||||
+ {
|
||||
+ *do_bit = 1;/* do bit */
|
||||
+ *ad_reqd = 1;
|
||||
+ }
|
||||
|
||||
- *ad_reqd = 1;
|
||||
dryrun = 1;
|
||||
}
|
||||
|
||||
@@ -1636,98 +1636,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
}
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
|
||||
- {
|
||||
- int gotone = 0;
|
||||
- struct blockdata *keydata;
|
||||
-
|
||||
- /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
|
||||
- if (sec_reqd)
|
||||
- {
|
||||
- crecp = NULL;
|
||||
- while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
|
||||
- if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- if (!sec_reqd || crecp)
|
||||
- {
|
||||
- if (qtype == T_DS)
|
||||
- {
|
||||
- crecp = NULL;
|
||||
- while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
|
||||
- if (crecp->uid == qclass)
|
||||
- {
|
||||
- gotone = 1;
|
||||
- if (!dryrun)
|
||||
- {
|
||||
- if (crecp->flags & F_NEG)
|
||||
- {
|
||||
- if (crecp->flags & F_NXDOMAIN)
|
||||
- nxdomain = 1;
|
||||
- log_query(F_UPSTREAM, name, NULL, "no DS");
|
||||
- }
|
||||
- else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
|
||||
- {
|
||||
- struct all_addr a;
|
||||
- a.addr.keytag = crecp->addr.ds.keytag;
|
||||
- log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
|
||||
- if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
- crec_ttl(crecp, now), &nameoffset,
|
||||
- T_DS, qclass, "sbbt",
|
||||
- crecp->addr.ds.keytag, crecp->addr.ds.algo,
|
||||
- crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
|
||||
- anscount++;
|
||||
-
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- else /* DNSKEY */
|
||||
- {
|
||||
- crecp = NULL;
|
||||
- while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
|
||||
- if (crecp->uid == qclass)
|
||||
- {
|
||||
- gotone = 1;
|
||||
- if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
|
||||
- {
|
||||
- struct all_addr a;
|
||||
- a.addr.keytag = crecp->addr.key.keytag;
|
||||
- log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
|
||||
- if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
- crec_ttl(crecp, now), &nameoffset,
|
||||
- T_DNSKEY, qclass, "sbbt",
|
||||
- crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
|
||||
- anscount++;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /* Now do RRSIGs */
|
||||
- if (gotone)
|
||||
- {
|
||||
- ans = 1;
|
||||
- auth = 0;
|
||||
- if (!dryrun && sec_reqd)
|
||||
- {
|
||||
- crecp = NULL;
|
||||
- while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
|
||||
- if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
|
||||
- (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
|
||||
- {
|
||||
- add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
- crec_ttl(crecp, now), &nameoffset,
|
||||
- T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
|
||||
- anscount++;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-#endif
|
||||
-
|
||||
if (qclass == C_IN)
|
||||
{
|
||||
struct txt_record *t;
|
||||
@@ -1736,6 +1644,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
|
||||
{
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
|
||||
@@ -1792,6 +1701,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
if (intr)
|
||||
{
|
||||
+ sec_data = 0;
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
@@ -1805,6 +1715,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
else if (ptr)
|
||||
{
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
|
||||
@@ -1819,38 +1730,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
{
|
||||
- if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
|
||||
- {
|
||||
- if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
|
||||
- crecp = NULL;
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- else if (crecp->flags & F_DNSSECOK)
|
||||
- {
|
||||
- int gotsig = 0;
|
||||
- struct crec *rr_crec = NULL;
|
||||
-
|
||||
- while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
|
||||
- {
|
||||
- if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
|
||||
- {
|
||||
- char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
|
||||
- gotsig = 1;
|
||||
-
|
||||
- if (!dryrun &&
|
||||
- add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
- rr_crec->ttd - now, &nameoffset,
|
||||
- T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
|
||||
- anscount++;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!gotsig)
|
||||
- crecp = NULL;
|
||||
- }
|
||||
-#endif
|
||||
- }
|
||||
-
|
||||
- if (crecp)
|
||||
+ /* Don't use cache when DNSSEC data required. */
|
||||
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
|
||||
{
|
||||
do
|
||||
{
|
||||
@@ -1860,19 +1741,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
-
|
||||
+
|
||||
+ ans = 1;
|
||||
+
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
- ans = 1;
|
||||
auth = 0;
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
|
||||
}
|
||||
- else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
|
||||
+ else
|
||||
{
|
||||
- ans = 1;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
auth = 0;
|
||||
if (!dryrun)
|
||||
@@ -1892,6 +1773,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
else if (is_rev_synth(is_arpa, &addr, name))
|
||||
{
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
|
||||
@@ -1908,6 +1790,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
{
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
nxdomain = 1;
|
||||
if (!dryrun)
|
||||
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
|
||||
@@ -1955,6 +1838,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (i == 4)
|
||||
{
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
addr.addr.addr4.s_addr = htonl(a);
|
||||
@@ -1993,6 +1877,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
continue;
|
||||
#endif
|
||||
ans = 1;
|
||||
+ sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
gotit = 1;
|
||||
@@ -2032,48 +1917,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
crecp = save;
|
||||
}
|
||||
|
||||
- /* If the client asked for DNSSEC and we can't provide RRSIGs, either
|
||||
- because we've not doing DNSSEC or the cached answer is signed by negative,
|
||||
- don't answer from the cache, forward instead. */
|
||||
- if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
|
||||
- {
|
||||
- if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
|
||||
- crecp = NULL;
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- else if (crecp->flags & F_DNSSECOK)
|
||||
- {
|
||||
- /* We're returning validated data, need to return the RRSIG too. */
|
||||
- struct crec *rr_crec = NULL;
|
||||
- int sigtype = type;
|
||||
- /* The signature may have expired even though the data is still in cache,
|
||||
- forward instead of answering from cache if so. */
|
||||
- int gotsig = 0;
|
||||
-
|
||||
- if (crecp->flags & F_CNAME)
|
||||
- sigtype = T_CNAME;
|
||||
-
|
||||
- while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
|
||||
- {
|
||||
- if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
|
||||
- {
|
||||
- char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
|
||||
- gotsig = 1;
|
||||
-
|
||||
- if (!dryrun &&
|
||||
- add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
- rr_crec->ttd - now, &nameoffset,
|
||||
- T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
|
||||
- anscount++;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!gotsig)
|
||||
- crecp = NULL;
|
||||
- }
|
||||
-#endif
|
||||
- }
|
||||
-
|
||||
- if (crecp)
|
||||
+ /* If the client asked for DNSSEC don't use cached data. */
|
||||
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
|
||||
do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,269 +0,0 @@
|
||||
From d64c81fff7faf4392b688223ef3a617c5c07e7dc Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 15 Dec 2015 16:11:06 +0000
|
||||
Subject: [PATCH] Move code which caches DS records to a more logical place.
|
||||
|
||||
---
|
||||
src/dnssec.c | 179 +++++++++++++++++++++++++++++-----------------------------
|
||||
1 file changed, 90 insertions(+), 89 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 1ae03a6..359231f 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1204,7 +1204,10 @@ 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, val, i, neganswer, nons;
|
||||
+ int qtype, qclass, rc, i, neganswer, nons;
|
||||
+ int aclass, atype, rdlen;
|
||||
+ unsigned long ttl;
|
||||
+ struct all_addr a;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
!(p = skip_name(p, header, plen, 4)))
|
||||
@@ -1214,40 +1217,100 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qtype != T_DS || qclass != class)
|
||||
- val = STAT_BOGUS;
|
||||
+ rc = STAT_BOGUS;
|
||||
else
|
||||
- val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
|
||||
+ rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
|
||||
/* Note dnssec_validate_reply() will have cached positive answers */
|
||||
|
||||
- if (val == STAT_INSECURE)
|
||||
- val = STAT_BOGUS;
|
||||
-
|
||||
+ if (rc == STAT_INSECURE)
|
||||
+ rc = STAT_BOGUS;
|
||||
+
|
||||
p = (unsigned char *)(header+1);
|
||||
extract_name(header, plen, &p, name, 1, 4);
|
||||
p += 4; /* qtype, qclass */
|
||||
|
||||
- if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
||||
- val = STAT_BOGUS;
|
||||
-
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||
from the DS's zone, and not the parent zone. */
|
||||
- if (val == STAT_BOGUS || (val == STAT_NEED_KEY && hostname_isequal(name, keyname)))
|
||||
+ if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
|
||||
{
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
- if (val != STAT_SECURE)
|
||||
- return val;
|
||||
-
|
||||
- /* By here, the answer is proved secure, and a positive answer has been cached. */
|
||||
- if (neganswer)
|
||||
+ if (rc != STAT_SECURE)
|
||||
+ return rc;
|
||||
+
|
||||
+ if (!neganswer)
|
||||
{
|
||||
- int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
|
||||
- unsigned long ttl, minttl = ULONG_MAX;
|
||||
- struct all_addr a;
|
||||
+ cache_start_insert();
|
||||
+
|
||||
+ for (i = 0; i < ntohs(header->ancount); i++)
|
||||
+ {
|
||||
+ if (!(rc = extract_name(header, plen, &p, name, 0, 10)))
|
||||
+ return STAT_BOGUS; /* bad packet */
|
||||
+
|
||||
+ GETSHORT(atype, p);
|
||||
+ GETSHORT(aclass, p);
|
||||
+ GETLONG(ttl, p);
|
||||
+ GETSHORT(rdlen, p);
|
||||
+
|
||||
+ if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
+ return STAT_BOGUS; /* bad packet */
|
||||
+
|
||||
+ if (aclass == class && atype == T_DS && rc == 1)
|
||||
+ {
|
||||
+ int algo, digest, keytag;
|
||||
+ unsigned char *psave = p;
|
||||
+ struct blockdata *key;
|
||||
+ struct crec *crecp;
|
||||
|
||||
+ if (rdlen < 4)
|
||||
+ return STAT_BOGUS; /* bad packet */
|
||||
+
|
||||
+ GETSHORT(keytag, p);
|
||||
+ algo = *p++;
|
||||
+ digest = *p++;
|
||||
+
|
||||
+ /* Cache needs to known class for DNSSEC stuff */
|
||||
+ a.addr.dnssec.class = class;
|
||||
+
|
||||
+ if ((key = blockdata_alloc((char*)p, rdlen - 4)))
|
||||
+ {
|
||||
+ if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
|
||||
+ {
|
||||
+ blockdata_free(key);
|
||||
+ return STAT_BOGUS;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ a.addr.keytag = keytag;
|
||||
+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
|
||||
+ crecp->addr.ds.digest = digest;
|
||||
+ crecp->addr.ds.keydata = key;
|
||||
+ crecp->addr.ds.algo = algo;
|
||||
+ crecp->addr.ds.keytag = keytag;
|
||||
+ crecp->addr.ds.keylen = rdlen - 4;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ p = psave;
|
||||
+
|
||||
+ if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
+ return STAT_BOGUS; /* bad packet */
|
||||
+ }
|
||||
+
|
||||
+ cache_end_insert();
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ int flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
|
||||
+ unsigned long minttl = ULONG_MAX;
|
||||
+
|
||||
+ if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
||||
+ return STAT_BOGUS;
|
||||
+
|
||||
if (RCODE(header) == NXDOMAIN)
|
||||
flags |= F_NXDOMAIN;
|
||||
|
||||
@@ -1261,20 +1324,20 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
if (!(p = skip_name(p, header, plen, 0)))
|
||||
return STAT_BOGUS;
|
||||
|
||||
- GETSHORT(qtype, p);
|
||||
- GETSHORT(qclass, p);
|
||||
+ GETSHORT(atype, p);
|
||||
+ GETSHORT(aclass, p);
|
||||
GETLONG(ttl, p);
|
||||
GETSHORT(rdlen, p);
|
||||
-
|
||||
+
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
-
|
||||
- if (qclass != class || qtype != T_SOA)
|
||||
+
|
||||
+ if (aclass != class || atype != T_SOA)
|
||||
{
|
||||
p += rdlen;
|
||||
continue;
|
||||
}
|
||||
-
|
||||
+
|
||||
if (ttl < minttl)
|
||||
minttl = ttl;
|
||||
|
||||
@@ -1306,7 +1369,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
|
||||
}
|
||||
}
|
||||
-
|
||||
+
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
@@ -2001,11 +2064,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
/* Not done, validate now */
|
||||
if (j == i)
|
||||
{
|
||||
- int ttl, keytag, algo, digest, sigcnt, rrcnt;
|
||||
- unsigned char *psave;
|
||||
- struct all_addr a;
|
||||
- struct blockdata *key;
|
||||
- struct crec *crecp;
|
||||
+ int sigcnt, rrcnt;
|
||||
char *wildname;
|
||||
|
||||
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
|
||||
@@ -2032,6 +2091,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
Can't overwrite name here. */
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
||||
+
|
||||
if (rc != STAT_SECURE)
|
||||
{
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
@@ -2088,65 +2148,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (rc == STAT_BOGUS)
|
||||
return rc;
|
||||
}
|
||||
-
|
||||
- /* If we just validated a DS RRset, cache it */
|
||||
- /* Also note if the RRset is the answer to the question, or the target of a CNAME */
|
||||
- cache_start_insert();
|
||||
-
|
||||
- for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
|
||||
- {
|
||||
- if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
-
|
||||
- GETSHORT(type2, p2);
|
||||
- GETSHORT(class2, p2);
|
||||
- GETLONG(ttl, p2);
|
||||
- GETSHORT(rdlen2, p2);
|
||||
-
|
||||
- if (!CHECK_LEN(header, p2, plen, rdlen2))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
-
|
||||
- if (class2 == class1 && rc == 1)
|
||||
- {
|
||||
- psave = p2;
|
||||
-
|
||||
- if (type1 == T_DS && type2 == T_DS)
|
||||
- {
|
||||
- if (rdlen2 < 4)
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
-
|
||||
- GETSHORT(keytag, p2);
|
||||
- algo = *p2++;
|
||||
- digest = *p2++;
|
||||
-
|
||||
- /* Cache needs to known class for DNSSEC stuff */
|
||||
- a.addr.dnssec.class = class2;
|
||||
-
|
||||
- if ((key = blockdata_alloc((char*)p2, rdlen2 - 4)))
|
||||
- {
|
||||
- if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DS | F_DNSSECOK)))
|
||||
- blockdata_free(key);
|
||||
- else
|
||||
- {
|
||||
- a.addr.keytag = keytag;
|
||||
- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
|
||||
- crecp->addr.ds.digest = digest;
|
||||
- crecp->addr.ds.keydata = key;
|
||||
- crecp->addr.ds.algo = algo;
|
||||
- crecp->addr.ds.keytag = keytag;
|
||||
- crecp->addr.ds.keylen = rdlen2 - 4;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- p2 = psave;
|
||||
- }
|
||||
-
|
||||
- if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
- }
|
||||
-
|
||||
- cache_end_insert();
|
||||
}
|
||||
}
|
||||
}
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,755 +0,0 @@
|
||||
From c2bcd1e183bcc5fdd63811c045355fc57e36ecfd Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Tue, 15 Dec 2015 17:25:21 +0000
|
||||
Subject: [PATCH] Generalise RR-filtering code, for use with EDNS0.
|
||||
|
||||
---
|
||||
Makefile | 3 +-
|
||||
bld/Android.mk | 2 +-
|
||||
src/dnsmasq.h | 5 +
|
||||
src/dnssec.c | 307 +-------------------------------------------------
|
||||
src/forward.c | 2 +-
|
||||
src/rrfilter.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
6 files changed, 349 insertions(+), 309 deletions(-)
|
||||
create mode 100644 src/rrfilter.c
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 4c87ea9..b664160 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -73,7 +73,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
- domain.o dnssec.o blockdata.o tables.o loop.o inotify.o poll.o
|
||||
+ domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
+ poll.o rrfilter.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h
|
||||
diff --git a/bld/Android.mk b/bld/Android.mk
|
||||
index 5364ee7..67b9c4b 100644
|
||||
--- a/bld/Android.mk
|
||||
+++ b/bld/Android.mk
|
||||
@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
- loop.c inotify.c poll.c
|
||||
+ loop.c inotify.c poll.c rrfilter.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 4344cae..39a930c 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -1513,3 +1513,8 @@ int poll_check(int fd, short event);
|
||||
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);
|
||||
+u16 *rrfilter_desc(int type);
|
||||
+int expand_workspace(unsigned char ***wkspc, int *szp, int new);
|
||||
+
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 359231f..fa3eb81 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -507,50 +507,6 @@ static int check_date_range(unsigned long date_start, unsigned long date_end)
|
||||
&& serial_compare_32(curtime, date_end) == SERIAL_LT;
|
||||
}
|
||||
|
||||
-static u16 *get_desc(int type)
|
||||
-{
|
||||
- /* List of RRtypes which include domains in the data.
|
||||
- 0 -> domain
|
||||
- integer -> no of plain bytes
|
||||
- -1 -> end
|
||||
-
|
||||
- zero is not a valid RRtype, so the final entry is returned for
|
||||
- anything which needs no mangling.
|
||||
- */
|
||||
-
|
||||
- static u16 rr_desc[] =
|
||||
- {
|
||||
- T_NS, 0, -1,
|
||||
- T_MD, 0, -1,
|
||||
- T_MF, 0, -1,
|
||||
- T_CNAME, 0, -1,
|
||||
- T_SOA, 0, 0, -1,
|
||||
- T_MB, 0, -1,
|
||||
- T_MG, 0, -1,
|
||||
- T_MR, 0, -1,
|
||||
- T_PTR, 0, -1,
|
||||
- T_MINFO, 0, 0, -1,
|
||||
- T_MX, 2, 0, -1,
|
||||
- T_RP, 0, 0, -1,
|
||||
- T_AFSDB, 2, 0, -1,
|
||||
- T_RT, 2, 0, -1,
|
||||
- T_SIG, 18, 0, -1,
|
||||
- T_PX, 2, 0, 0, -1,
|
||||
- T_NXT, 0, -1,
|
||||
- T_KX, 2, 0, -1,
|
||||
- T_SRV, 6, 0, -1,
|
||||
- T_DNAME, 0, -1,
|
||||
- 0, -1 /* wildcard/catchall */
|
||||
- };
|
||||
-
|
||||
- u16 *p = rr_desc;
|
||||
-
|
||||
- while (*p != type && *p != 0)
|
||||
- while (*p++ != (u16)-1);
|
||||
-
|
||||
- return p+1;
|
||||
-}
|
||||
-
|
||||
/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
|
||||
data, pointed to by *p, should be used raw. */
|
||||
static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
|
||||
@@ -594,34 +550,6 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
|
||||
}
|
||||
}
|
||||
|
||||
-static int expand_workspace(unsigned char ***wkspc, int *szp, int new)
|
||||
-{
|
||||
- unsigned char **p;
|
||||
- int old = *szp;
|
||||
-
|
||||
- if (old >= new+1)
|
||||
- return 1;
|
||||
-
|
||||
- if (new >= 100)
|
||||
- return 0;
|
||||
-
|
||||
- new += 5;
|
||||
-
|
||||
- if (!(p = whine_malloc(new * sizeof(unsigned char **))))
|
||||
- return 0;
|
||||
-
|
||||
- if (old != 0 && *wkspc)
|
||||
- {
|
||||
- memcpy(p, *wkspc, old * sizeof(unsigned char **));
|
||||
- free(*wkspc);
|
||||
- }
|
||||
-
|
||||
- *wkspc = p;
|
||||
- *szp = new;
|
||||
-
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
/* Bubble sort the RRset into the canonical order.
|
||||
Note that the byte-streams from two RRs may get unsynced: consider
|
||||
RRs which have two domain-names at the start and then other data.
|
||||
@@ -849,7 +777,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
int rdlen, j, name_labels;
|
||||
struct crec *crecp = NULL;
|
||||
int algo, labels, orig_ttl, key_tag;
|
||||
- u16 *rr_desc = get_desc(type);
|
||||
+ u16 *rr_desc = rrfilter_desc(type);
|
||||
|
||||
if (wildcard_out)
|
||||
*wildcard_out = NULL;
|
||||
@@ -2266,239 +2194,6 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
|
||||
return ret;
|
||||
}
|
||||
|
||||
-/* Go through a domain name, find "pointers" and fix them up based on how many bytes
|
||||
- we've chopped out of the packet, or check they don't point into an elided part. */
|
||||
-static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
|
||||
-{
|
||||
- unsigned char *ansp = *namep;
|
||||
-
|
||||
- while(1)
|
||||
- {
|
||||
- unsigned int label_type;
|
||||
-
|
||||
- if (!CHECK_LEN(header, ansp, plen, 1))
|
||||
- return 0;
|
||||
-
|
||||
- label_type = (*ansp) & 0xc0;
|
||||
-
|
||||
- if (label_type == 0xc0)
|
||||
- {
|
||||
- /* pointer for compression. */
|
||||
- unsigned int offset;
|
||||
- int i;
|
||||
- unsigned char *p;
|
||||
-
|
||||
- if (!CHECK_LEN(header, ansp, plen, 2))
|
||||
- return 0;
|
||||
-
|
||||
- offset = ((*ansp++) & 0x3f) << 8;
|
||||
- offset |= *ansp++;
|
||||
-
|
||||
- p = offset + (unsigned char *)header;
|
||||
-
|
||||
- for (i = 0; i < rr_count; i++)
|
||||
- if (p < rrs[i])
|
||||
- break;
|
||||
- else
|
||||
- if (i & 1)
|
||||
- offset -= rrs[i] - rrs[i-1];
|
||||
-
|
||||
- /* does the pointer end up in an elided RR? */
|
||||
- if (i & 1)
|
||||
- return 0;
|
||||
-
|
||||
- /* No, scale the pointer */
|
||||
- if (fixup)
|
||||
- {
|
||||
- ansp -= 2;
|
||||
- *ansp++ = (offset >> 8) | 0xc0;
|
||||
- *ansp++ = offset & 0xff;
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
- else if (label_type == 0x80)
|
||||
- return 0; /* reserved */
|
||||
- else if (label_type == 0x40)
|
||||
- {
|
||||
- /* Extended label type */
|
||||
- unsigned int count;
|
||||
-
|
||||
- if (!CHECK_LEN(header, ansp, plen, 2))
|
||||
- return 0;
|
||||
-
|
||||
- if (((*ansp++) & 0x3f) != 1)
|
||||
- return 0; /* we only understand bitstrings */
|
||||
-
|
||||
- count = *(ansp++); /* Bits in bitstring */
|
||||
-
|
||||
- if (count == 0) /* count == 0 means 256 bits */
|
||||
- ansp += 32;
|
||||
- else
|
||||
- ansp += ((count-1)>>3)+1;
|
||||
- }
|
||||
- else
|
||||
- { /* label type == 0 Bottom six bits is length */
|
||||
- unsigned int len = (*ansp++) & 0x3f;
|
||||
-
|
||||
- if (!ADD_RDLEN(header, ansp, plen, len))
|
||||
- return 0;
|
||||
-
|
||||
- if (len == 0)
|
||||
- break; /* zero length label marks the end. */
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- *namep = ansp;
|
||||
-
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
-/* Go through RRs and check or fixup the domain names contained within */
|
||||
-static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
|
||||
-{
|
||||
- int i, type, class, rdlen;
|
||||
- unsigned char *pp;
|
||||
-
|
||||
- for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
|
||||
- {
|
||||
- pp = p;
|
||||
-
|
||||
- if (!(p = skip_name(p, header, plen, 10)))
|
||||
- return 0;
|
||||
-
|
||||
- GETSHORT(type, p);
|
||||
- GETSHORT(class, p);
|
||||
- p += 4; /* TTL */
|
||||
- GETSHORT(rdlen, p);
|
||||
-
|
||||
- if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
|
||||
- {
|
||||
- /* fixup name of RR */
|
||||
- if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
|
||||
- return 0;
|
||||
-
|
||||
- if (class == C_IN)
|
||||
- {
|
||||
- u16 *d;
|
||||
-
|
||||
- for (pp = p, d = get_desc(type); *d != (u16)-1; d++)
|
||||
- {
|
||||
- if (*d != 0)
|
||||
- pp += *d;
|
||||
- else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
|
||||
- return 0;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
-
|
||||
-size_t filter_rrsigs(struct dns_header *header, size_t plen)
|
||||
-{
|
||||
- static unsigned char **rrs;
|
||||
- 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;
|
||||
-
|
||||
- if (ntohs(header->qdcount) != 1 ||
|
||||
- !(p = skip_name(p, header, plen, 4)))
|
||||
- return plen;
|
||||
-
|
||||
- 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 explicity queried for */
|
||||
- for (rr_found = 0, 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;
|
||||
-
|
||||
- GETSHORT(type, p);
|
||||
- GETSHORT(class, p);
|
||||
- p += 4; /* TTL */
|
||||
- GETSHORT(rdlen, p);
|
||||
-
|
||||
- if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) &&
|
||||
- (type != qtype || class != qclass))
|
||||
- {
|
||||
- if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
|
||||
- return plen;
|
||||
-
|
||||
- rrs[rr_found++] = pstart;
|
||||
-
|
||||
- if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
- return plen;
|
||||
-
|
||||
- rrs[rr_found++] = p;
|
||||
-
|
||||
- if (i < ntohs(header->ancount))
|
||||
- chop_an++;
|
||||
- else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
|
||||
- chop_ns++;
|
||||
- else
|
||||
- chop_ar++;
|
||||
- }
|
||||
- else if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
- return plen;
|
||||
- }
|
||||
-
|
||||
- /* Nothing to do. */
|
||||
- if (rr_found == 0)
|
||||
- return plen;
|
||||
-
|
||||
- /* 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
|
||||
- it happens, we give up and leave the answer unchanged. */
|
||||
- p = (unsigned char *)(header+1);
|
||||
-
|
||||
- /* question first */
|
||||
- if (!check_name(&p, header, plen, 0, rrs, rr_found))
|
||||
- return plen;
|
||||
- p += 4; /* qclass, qtype */
|
||||
-
|
||||
- /* Now answers and NS */
|
||||
- if (!check_rrs(p, header, plen, 0, rrs, rr_found))
|
||||
- return plen;
|
||||
-
|
||||
- /* Third pass, elide records */
|
||||
- for (p = rrs[0], i = 1; i < rr_found; i += 2)
|
||||
- {
|
||||
- unsigned char *start = rrs[i];
|
||||
- unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
|
||||
-
|
||||
- memmove(p, start, end-start);
|
||||
- p += end-start;
|
||||
- }
|
||||
-
|
||||
- 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);
|
||||
-
|
||||
- /* Fourth pass, fix up pointers in the remaining records */
|
||||
- p = (unsigned char *)(header+1);
|
||||
-
|
||||
- check_name(&p, header, plen, 1, rrs, rr_found);
|
||||
- p += 4; /* qclass, qtype */
|
||||
-
|
||||
- check_rrs(p, header, plen, 1, rrs, rr_found);
|
||||
-
|
||||
- return plen;
|
||||
-}
|
||||
-
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index dd22a62..3e801c8 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -662,7 +662,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 = filter_rrsigs(header, n);
|
||||
+ n = rrfilter(header, n, 1);
|
||||
#endif
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
diff --git a/src/rrfilter.c b/src/rrfilter.c
|
||||
new file mode 100644
|
||||
index 0000000..ae12261
|
||||
--- /dev/null
|
||||
+++ b/src/rrfilter.c
|
||||
@@ -0,0 +1,339 @@
|
||||
+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
|
||||
+
|
||||
+ This program is free software; you can redistribute it and/or modify
|
||||
+ it under the terms of the GNU General Public License as published by
|
||||
+ the Free Software Foundation; version 2 dated June, 1991, or
|
||||
+ (at your option) version 3 dated 29 June, 2007.
|
||||
+
|
||||
+ This program is distributed in the hope that it will be useful,
|
||||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ GNU General Public License for more details.
|
||||
+
|
||||
+ You should have received a copy of the GNU General Public License
|
||||
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+*/
|
||||
+
|
||||
+/* Code to safely remove RRs from an DNS answer */
|
||||
+
|
||||
+#include "dnsmasq.h"
|
||||
+
|
||||
+/* Go through a domain name, find "pointers" and fix them up based on how many bytes
|
||||
+ we've chopped out of the packet, or check they don't point into an elided part. */
|
||||
+static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
|
||||
+{
|
||||
+ unsigned char *ansp = *namep;
|
||||
+
|
||||
+ while(1)
|
||||
+ {
|
||||
+ unsigned int label_type;
|
||||
+
|
||||
+ if (!CHECK_LEN(header, ansp, plen, 1))
|
||||
+ return 0;
|
||||
+
|
||||
+ label_type = (*ansp) & 0xc0;
|
||||
+
|
||||
+ if (label_type == 0xc0)
|
||||
+ {
|
||||
+ /* pointer for compression. */
|
||||
+ unsigned int offset;
|
||||
+ int i;
|
||||
+ unsigned char *p;
|
||||
+
|
||||
+ if (!CHECK_LEN(header, ansp, plen, 2))
|
||||
+ return 0;
|
||||
+
|
||||
+ offset = ((*ansp++) & 0x3f) << 8;
|
||||
+ offset |= *ansp++;
|
||||
+
|
||||
+ p = offset + (unsigned char *)header;
|
||||
+
|
||||
+ for (i = 0; i < rr_count; i++)
|
||||
+ if (p < rrs[i])
|
||||
+ break;
|
||||
+ else
|
||||
+ if (i & 1)
|
||||
+ offset -= rrs[i] - rrs[i-1];
|
||||
+
|
||||
+ /* does the pointer end up in an elided RR? */
|
||||
+ if (i & 1)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* No, scale the pointer */
|
||||
+ if (fixup)
|
||||
+ {
|
||||
+ ansp -= 2;
|
||||
+ *ansp++ = (offset >> 8) | 0xc0;
|
||||
+ *ansp++ = offset & 0xff;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (label_type == 0x80)
|
||||
+ return 0; /* reserved */
|
||||
+ else if (label_type == 0x40)
|
||||
+ {
|
||||
+ /* Extended label type */
|
||||
+ unsigned int count;
|
||||
+
|
||||
+ if (!CHECK_LEN(header, ansp, plen, 2))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (((*ansp++) & 0x3f) != 1)
|
||||
+ return 0; /* we only understand bitstrings */
|
||||
+
|
||||
+ count = *(ansp++); /* Bits in bitstring */
|
||||
+
|
||||
+ if (count == 0) /* count == 0 means 256 bits */
|
||||
+ ansp += 32;
|
||||
+ else
|
||||
+ ansp += ((count-1)>>3)+1;
|
||||
+ }
|
||||
+ else
|
||||
+ { /* label type == 0 Bottom six bits is length */
|
||||
+ unsigned int len = (*ansp++) & 0x3f;
|
||||
+
|
||||
+ if (!ADD_RDLEN(header, ansp, plen, len))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (len == 0)
|
||||
+ break; /* zero length label marks the end. */
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ *namep = ansp;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+/* Go through RRs and check or fixup the domain names contained within */
|
||||
+static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
|
||||
+{
|
||||
+ int i, j, type, class, rdlen;
|
||||
+ unsigned char *pp;
|
||||
+
|
||||
+ for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
|
||||
+ {
|
||||
+ pp = p;
|
||||
+
|
||||
+ if (!(p = skip_name(p, header, plen, 10)))
|
||||
+ return 0;
|
||||
+
|
||||
+ GETSHORT(type, p);
|
||||
+ GETSHORT(class, p);
|
||||
+ p += 4; /* TTL */
|
||||
+ GETSHORT(rdlen, p);
|
||||
+
|
||||
+ /* If this RR is to be elided, don't fix up its contents */
|
||||
+ for (j = 0; j < rr_count; j += 2)
|
||||
+ if (rrs[j] == pp)
|
||||
+ break;
|
||||
+
|
||||
+ if (j >= rr_count)
|
||||
+ {
|
||||
+ /* fixup name of RR */
|
||||
+ if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (class == C_IN)
|
||||
+ {
|
||||
+ u16 *d;
|
||||
+
|
||||
+ for (pp = p, d = rrfilter_desc(type); *d != (u16)-1; d++)
|
||||
+ {
|
||||
+ if (*d != 0)
|
||||
+ pp += *d;
|
||||
+ else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
|
||||
+size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
+{
|
||||
+ static unsigned char **rrs;
|
||||
+ 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;
|
||||
+
|
||||
+ if (ntohs(header->qdcount) != 1 ||
|
||||
+ !(p = skip_name(p, header, plen, 4)))
|
||||
+ return plen;
|
||||
+
|
||||
+ 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 explicity queried for */
|
||||
+ for (rr_found = 0, 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;
|
||||
+
|
||||
+ GETSHORT(type, p);
|
||||
+ GETSHORT(class, p);
|
||||
+ p += 4; /* TTL */
|
||||
+ GETSHORT(rdlen, p);
|
||||
+
|
||||
+ if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
+ return plen;
|
||||
+
|
||||
+ /* Don't remove the answer. */
|
||||
+ if (i < ntohs(header->ancount) && type == qtype && class == qclass)
|
||||
+ continue;
|
||||
+
|
||||
+ if (mode == 0) /* EDNS */
|
||||
+ {
|
||||
+ /* EDNS mode, remove T_OPT from additional section only */
|
||||
+ if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
|
||||
+ continue;
|
||||
+ }
|
||||
+ else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
|
||||
+ /* DNSSEC mode, remove SIGs and NSECs from all three sections. */
|
||||
+ continue;
|
||||
+
|
||||
+
|
||||
+ if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
|
||||
+ return plen;
|
||||
+
|
||||
+ rrs[rr_found++] = pstart;
|
||||
+ rrs[rr_found++] = p;
|
||||
+
|
||||
+ if (i < ntohs(header->ancount))
|
||||
+ chop_an++;
|
||||
+ else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
|
||||
+ chop_ns++;
|
||||
+ else
|
||||
+ chop_ar++;
|
||||
+ }
|
||||
+
|
||||
+ /* Nothing to do. */
|
||||
+ if (rr_found == 0)
|
||||
+ return plen;
|
||||
+
|
||||
+ /* 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
|
||||
+ it happens, we give up and leave the answer unchanged. */
|
||||
+ p = (unsigned char *)(header+1);
|
||||
+
|
||||
+ /* question first */
|
||||
+ if (!check_name(&p, header, plen, 0, rrs, rr_found))
|
||||
+ return plen;
|
||||
+ p += 4; /* qclass, qtype */
|
||||
+
|
||||
+ /* Now answers and NS */
|
||||
+ if (!check_rrs(p, header, plen, 0, rrs, rr_found))
|
||||
+ return plen;
|
||||
+
|
||||
+ /* Third pass, elide records */
|
||||
+ for (p = rrs[0], i = 1; i < rr_found; i += 2)
|
||||
+ {
|
||||
+ unsigned char *start = rrs[i];
|
||||
+ unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
|
||||
+
|
||||
+ memmove(p, start, end-start);
|
||||
+ p += end-start;
|
||||
+ }
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ /* Fourth pass, fix up pointers in the remaining records */
|
||||
+ p = (unsigned char *)(header+1);
|
||||
+
|
||||
+ check_name(&p, header, plen, 1, rrs, rr_found);
|
||||
+ p += 4; /* qclass, qtype */
|
||||
+
|
||||
+ check_rrs(p, header, plen, 1, rrs, rr_found);
|
||||
+
|
||||
+ return plen;
|
||||
+}
|
||||
+
|
||||
+/* This is used in the DNSSEC code too, hence it's exported */
|
||||
+u16 *rrfilter_desc(int type)
|
||||
+{
|
||||
+ /* List of RRtypes which include domains in the data.
|
||||
+ 0 -> domain
|
||||
+ integer -> no of plain bytes
|
||||
+ -1 -> end
|
||||
+
|
||||
+ zero is not a valid RRtype, so the final entry is returned for
|
||||
+ anything which needs no mangling.
|
||||
+ */
|
||||
+
|
||||
+ static u16 rr_desc[] =
|
||||
+ {
|
||||
+ T_NS, 0, -1,
|
||||
+ T_MD, 0, -1,
|
||||
+ T_MF, 0, -1,
|
||||
+ T_CNAME, 0, -1,
|
||||
+ T_SOA, 0, 0, -1,
|
||||
+ T_MB, 0, -1,
|
||||
+ T_MG, 0, -1,
|
||||
+ T_MR, 0, -1,
|
||||
+ T_PTR, 0, -1,
|
||||
+ T_MINFO, 0, 0, -1,
|
||||
+ T_MX, 2, 0, -1,
|
||||
+ T_RP, 0, 0, -1,
|
||||
+ T_AFSDB, 2, 0, -1,
|
||||
+ T_RT, 2, 0, -1,
|
||||
+ T_SIG, 18, 0, -1,
|
||||
+ T_PX, 2, 0, 0, -1,
|
||||
+ T_NXT, 0, -1,
|
||||
+ T_KX, 2, 0, -1,
|
||||
+ T_SRV, 6, 0, -1,
|
||||
+ T_DNAME, 0, -1,
|
||||
+ 0, -1 /* wildcard/catchall */
|
||||
+ };
|
||||
+
|
||||
+ u16 *p = rr_desc;
|
||||
+
|
||||
+ while (*p != type && *p != 0)
|
||||
+ while (*p++ != (u16)-1);
|
||||
+
|
||||
+ return p+1;
|
||||
+}
|
||||
+
|
||||
+int expand_workspace(unsigned char ***wkspc, int *szp, int new)
|
||||
+{
|
||||
+ unsigned char **p;
|
||||
+ int old = *szp;
|
||||
+
|
||||
+ if (old >= new+1)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (new >= 100)
|
||||
+ return 0;
|
||||
+
|
||||
+ new += 5;
|
||||
+
|
||||
+ if (!(p = whine_malloc(new * sizeof(unsigned char **))))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (old != 0 && *wkspc)
|
||||
+ {
|
||||
+ memcpy(p, *wkspc, old * sizeof(unsigned char **));
|
||||
+ free(*wkspc);
|
||||
+ }
|
||||
+
|
||||
+ *wkspc = p;
|
||||
+ *szp = new;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
From 2dbba34b2c1289a108f876c78b84889f2a93115d Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 16 Dec 2015 13:41:58 +0000
|
||||
Subject: [PATCH] DNSSEC validation tweak.
|
||||
|
||||
A zone which has at least one key with an algorithm we don't
|
||||
support should be considered as insecure.
|
||||
---
|
||||
src/dnssec.c | 82 ++++++++++++++++++++++++++++++++++++++--------------------
|
||||
1 file changed, 54 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index fa3eb81..dc563e0 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -763,10 +763,10 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
|
||||
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
|
||||
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
|
||||
|
||||
- if key is non-NULL, use that key, which has the algo and tag given in the params of those names,
|
||||
+ If key is non-NULL, use that key, which has the algo and tag given in the params of those names,
|
||||
otherwise find the key in the cache.
|
||||
|
||||
- name is unchanged on exit. keyname is used as workspace and trashed.
|
||||
+ Name is unchanged on exit. keyname is used as workspace and trashed.
|
||||
|
||||
Call explore_rrset first to find and count RRs and sigs.
|
||||
*/
|
||||
@@ -919,6 +919,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
+
|
||||
/* The DNS packet is expected to contain the answer to a DNSKEY query.
|
||||
Put all DNSKEYs in the answer which are valid into the cache.
|
||||
return codes:
|
||||
@@ -1831,15 +1832,15 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
|
||||
/* Check signing status of name.
|
||||
returns:
|
||||
- STAT_SECURE zone is signed.
|
||||
- STAT_INSECURE zone proved unsigned.
|
||||
- STAT_NEED_DS require DS record of name returned in keyname.
|
||||
-
|
||||
+ STAT_SECURE zone is signed.
|
||||
+ STAT_INSECURE zone proved unsigned.
|
||||
+ STAT_NEED_DS require DS record of name returned in keyname.
|
||||
+ STAT_NEED_DNSKEY require DNSKEY record of name returned in keyname.
|
||||
name returned unaltered.
|
||||
*/
|
||||
static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
{
|
||||
- int name_start = strlen(name);
|
||||
+ int secure_ds, name_start = strlen(name);
|
||||
struct crec *crecp;
|
||||
char *p;
|
||||
|
||||
@@ -1850,27 +1851,52 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
|
||||
return STAT_NEED_DS;
|
||||
else
|
||||
- do
|
||||
- {
|
||||
- if (crecp->uid == (unsigned int)class)
|
||||
- {
|
||||
- /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
|
||||
- F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
|
||||
- but that's because there's no NS record either, ie this isn't the start
|
||||
- of a zone. We only prove that the DNS tree below a node is unsigned when
|
||||
- we prove that we're at a zone cut AND there's no DS record.
|
||||
- */
|
||||
- if (crecp->flags & F_NEG)
|
||||
- {
|
||||
- if (crecp->flags & F_DNSSECOK)
|
||||
- return STAT_INSECURE; /* proved no DS here */
|
||||
- }
|
||||
- else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
|
||||
- return STAT_INSECURE; /* algo we can't use - insecure */
|
||||
- }
|
||||
- }
|
||||
- while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
|
||||
-
|
||||
+ {
|
||||
+ secure_ds = 0;
|
||||
+
|
||||
+ do
|
||||
+ {
|
||||
+ if (crecp->uid == (unsigned int)class)
|
||||
+ {
|
||||
+ /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
|
||||
+ F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
|
||||
+ but that's because there's no NS record either, ie this isn't the start
|
||||
+ of a zone. We only prove that the DNS tree below a node is unsigned when
|
||||
+ we prove that we're at a zone cut AND there's no DS record.
|
||||
+ */
|
||||
+ if (crecp->flags & F_NEG)
|
||||
+ {
|
||||
+ if (crecp->flags & F_DNSSECOK)
|
||||
+ return STAT_INSECURE; /* proved no DS here */
|
||||
+ }
|
||||
+ else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
|
||||
+ return STAT_INSECURE; /* algo we can't use - insecure */
|
||||
+ else
|
||||
+ secure_ds = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
|
||||
+ }
|
||||
+
|
||||
+ if (secure_ds)
|
||||
+ {
|
||||
+ /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
|
||||
+ that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
|
||||
+ one we can use. However the DNSKEY RRset may contain more than one key and
|
||||
+ one of the other keys may use an algorithm we don't support. If that's
|
||||
+ the case the zone is insecure for us. */
|
||||
+
|
||||
+ if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
|
||||
+ return STAT_NEED_KEY;
|
||||
+
|
||||
+ do
|
||||
+ {
|
||||
+ if (crecp->uid == (unsigned int)class && !algo_digest_name(crecp->addr.key.algo))
|
||||
+ return STAT_INSECURE;
|
||||
+ }
|
||||
+ while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
|
||||
+ }
|
||||
+
|
||||
if (name_start == 0)
|
||||
break;
|
||||
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
From dd4ad9ac7ea6d51dcc34a1f2cd2da14efbb87714 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 17 Dec 2015 10:44:58 +0000
|
||||
Subject: [PATCH] Tweaks to EDNS0 handling in DNS replies.
|
||||
|
||||
---
|
||||
src/dnssec.c | 20 +++++++++-----------
|
||||
src/rfc1035.c | 57 +++++++++++++++++++++++++++++++++------------------------
|
||||
2 files changed, 42 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index dc563e0..012b2a6 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -2129,18 +2129,16 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
- else
|
||||
+
|
||||
+ rc = zone_status(name, qclass, keyname, now);
|
||||
+ if (rc != STAT_SECURE)
|
||||
{
|
||||
- rc = zone_status(name, qclass, keyname, now);
|
||||
- if (rc != STAT_SECURE)
|
||||
- {
|
||||
- if (class)
|
||||
- *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
|
||||
- return rc;
|
||||
- }
|
||||
-
|
||||
- return STAT_BOGUS; /* signed zone, no NSECs */
|
||||
- }
|
||||
+ if (class)
|
||||
+ *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ return STAT_BOGUS; /* signed zone, no NSECs */
|
||||
}
|
||||
|
||||
if (nsec_type == T_NSEC)
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index def8fa0..188d05f 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1539,7 +1539,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
|
||||
struct mx_srv_record *rec;
|
||||
size_t len;
|
||||
-
|
||||
+
|
||||
+ if (ntohs(header->ancount) != 0 ||
|
||||
+ ntohs(header->nscount) != 0 ||
|
||||
+ ntohs(header->qdcount) == 0 ||
|
||||
+ OPCODE(header) != QUERY )
|
||||
+ return 0;
|
||||
+
|
||||
/* Don't return AD set if checking disabled. */
|
||||
if (header->hb4 & HB4_CD)
|
||||
sec_data = 0;
|
||||
@@ -1548,33 +1554,32 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
*ad_reqd = header->hb4 & HB4_AD;
|
||||
*do_bit = 0;
|
||||
|
||||
- /* If there is an RFC2671 pseudoheader then it will be overwritten by
|
||||
+ /* If there is an additional data section then it will be overwritten by
|
||||
partial replies, so we have to do a dry run to see if we can answer
|
||||
- the query. We check to see if the do bit is set, if so we always
|
||||
- forward rather than answering from the cache, which doesn't include
|
||||
- security information, unless we're in DNSSEC validation mode. */
|
||||
+ the query. */
|
||||
|
||||
- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
|
||||
- {
|
||||
- unsigned short flags;
|
||||
-
|
||||
- have_pseudoheader = 1;
|
||||
+ if (ntohs(header->arcount) != 0)
|
||||
+ {
|
||||
+ dryrun = 1;
|
||||
|
||||
- pheader += 4; /* udp size, ext_rcode */
|
||||
- GETSHORT(flags, pheader);
|
||||
-
|
||||
- if ((sec_reqd = flags & 0x8000))
|
||||
- {
|
||||
- *do_bit = 1;/* do bit */
|
||||
- *ad_reqd = 1;
|
||||
+ /* If there's an additional section, there might be an EDNS(0) pseudoheader */
|
||||
+ if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
|
||||
+ {
|
||||
+ unsigned short flags;
|
||||
+
|
||||
+ have_pseudoheader = 1;
|
||||
+
|
||||
+ pheader += 4; /* udp size, ext_rcode */
|
||||
+ GETSHORT(flags, pheader);
|
||||
+
|
||||
+ if ((sec_reqd = flags & 0x8000))
|
||||
+ {
|
||||
+ *do_bit = 1;/* do bit */
|
||||
+ *ad_reqd = 1;
|
||||
+ }
|
||||
}
|
||||
-
|
||||
- dryrun = 1;
|
||||
}
|
||||
|
||||
- if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||
- return 0;
|
||||
-
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
rec->offset = 0;
|
||||
|
||||
@@ -1730,8 +1735,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||
{
|
||||
- /* Don't use cache when DNSSEC data required. */
|
||||
- if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
|
||||
+ /* Don't use cache when DNSSEC data required, unless we know that
|
||||
+ the zone is unsigned, which implies that we're doing
|
||||
+ validation. */
|
||||
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||
+ !sec_reqd ||
|
||||
+ (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
|
||||
{
|
||||
do
|
||||
{
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,409 +0,0 @@
|
||||
From b40f26c0199235073abc37e1e1d6ed93bed372f5 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 17 Dec 2015 11:57:26 +0000
|
||||
Subject: [PATCH] Tidy up DNSSEC non-existence code. Check zone status is NSEC
|
||||
proof bad.
|
||||
|
||||
---
|
||||
src/dnssec.c | 207 +++++++++++++++++++++++++---------------------------------
|
||||
1 file changed, 90 insertions(+), 117 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 012b2a6..ddae497 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1367,59 +1367,6 @@ static int hostname_cmp(const char *a, const char *b)
|
||||
}
|
||||
}
|
||||
|
||||
-/* Find all the NSEC or NSEC3 records in a reply.
|
||||
- return an array of pointers to them. */
|
||||
-static int find_nsec_records(struct dns_header *header, size_t plen, unsigned char ***nsecsetp, int *nsecsetl, int class_reqd)
|
||||
-{
|
||||
- static unsigned char **nsecset = NULL;
|
||||
- static int nsecset_sz = 0;
|
||||
-
|
||||
- int type_found = 0;
|
||||
- unsigned char *p = skip_questions(header, plen);
|
||||
- int type, class, rdlen, i, nsecs_found;
|
||||
-
|
||||
- /* Move to NS section */
|
||||
- if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
||||
- return 0;
|
||||
-
|
||||
- for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
|
||||
- {
|
||||
- unsigned char *pstart = p;
|
||||
-
|
||||
- if (!(p = skip_name(p, header, plen, 10)))
|
||||
- return 0;
|
||||
-
|
||||
- GETSHORT(type, p);
|
||||
- GETSHORT(class, p);
|
||||
- p += 4; /* TTL */
|
||||
- GETSHORT(rdlen, p);
|
||||
-
|
||||
- if (class == class_reqd && (type == T_NSEC || type == T_NSEC3))
|
||||
- {
|
||||
- /* No mixed NSECing 'round here, thankyouverymuch */
|
||||
- if (type_found == T_NSEC && type == T_NSEC3)
|
||||
- return 0;
|
||||
- if (type_found == T_NSEC3 && type == T_NSEC)
|
||||
- return 0;
|
||||
-
|
||||
- type_found = type;
|
||||
-
|
||||
- if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
|
||||
- return 0;
|
||||
-
|
||||
- nsecset[nsecs_found++] = pstart;
|
||||
- }
|
||||
-
|
||||
- if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- *nsecsetp = nsecset;
|
||||
- *nsecsetl = nsecs_found;
|
||||
-
|
||||
- return type_found;
|
||||
-}
|
||||
-
|
||||
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
|
||||
char *workspace1, char *workspace2, char *name, int type, int *nons)
|
||||
{
|
||||
@@ -1436,12 +1383,12 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
{
|
||||
p = nsecs[i];
|
||||
if (!extract_name(header, plen, &p, workspace1, 1, 10))
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
p += 8; /* class, type, TTL */
|
||||
GETSHORT(rdlen, p);
|
||||
psave = p;
|
||||
if (!extract_name(header, plen, &p, workspace2, 1, 10))
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
rc = hostname_cmp(workspace1, name);
|
||||
|
||||
@@ -1449,7 +1396,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
{
|
||||
/* 4035 para 5.4. Last sentence */
|
||||
if (type == T_NSEC || type == T_RRSIG)
|
||||
- return STAT_SECURE;
|
||||
+ return 1;
|
||||
|
||||
/* NSEC with the same name as the RR we're testing, check
|
||||
that the type in question doesn't appear in the type map */
|
||||
@@ -1465,24 +1412,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
/* A CNAME answer would also be valid, so if there's a CNAME is should
|
||||
have been returned. */
|
||||
if ((p[2] & (0x80 >> T_CNAME)) != 0)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
/* If the SOA bit is set for a DS record, then we have the
|
||||
DS from the wrong side of the delegation. */
|
||||
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
while (rdlen >= 2)
|
||||
{
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
if (p[0] == type >> 8)
|
||||
{
|
||||
/* Does the NSEC say our type exists? */
|
||||
if (offset < p[1] && (p[offset+2] & mask) != 0)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
break; /* finshed checking */
|
||||
}
|
||||
@@ -1491,24 +1438,24 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
p += p[1];
|
||||
}
|
||||
|
||||
- return STAT_SECURE;
|
||||
+ return 1;
|
||||
}
|
||||
else if (rc == -1)
|
||||
{
|
||||
/* Normal case, name falls between NSEC name and next domain name,
|
||||
wrap around case, name falls between NSEC name (rc == -1) and end */
|
||||
if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
|
||||
- return STAT_SECURE;
|
||||
+ return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wrap around case, name falls between start and next domain name */
|
||||
if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
|
||||
- return STAT_SECURE;
|
||||
+ return 1;
|
||||
}
|
||||
}
|
||||
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* return digest length, or zero on error */
|
||||
@@ -1701,7 +1648,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
for (i = 0; i < nsec_count; i++)
|
||||
{
|
||||
if (!(p = skip_name(nsecs[i], header, plen, 15)))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
+ return 0; /* bad packet */
|
||||
|
||||
p += 10; /* type, class, TTL, rdlen */
|
||||
algo = *p++;
|
||||
@@ -1712,14 +1659,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
|
||||
/* No usable NSEC3s */
|
||||
if (i == nsec_count)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
p++; /* flags */
|
||||
GETSHORT (iterations, p);
|
||||
salt_len = *p++;
|
||||
salt = p;
|
||||
if (!CHECK_LEN(header, salt, plen, salt_len))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
+ return 0; /* bad packet */
|
||||
|
||||
/* Now prune so we only have NSEC3 records with same iterations, salt and algo */
|
||||
for (i = 0; i < nsec_count; i++)
|
||||
@@ -1730,7 +1677,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
nsecs[i] = NULL; /* Speculative, will be restored if OK. */
|
||||
|
||||
if (!(p = skip_name(nsec3p, header, plen, 15)))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
+ return 0; /* bad packet */
|
||||
|
||||
p += 10; /* type, class, TTL, rdlen */
|
||||
|
||||
@@ -1747,7 +1694,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
continue;
|
||||
|
||||
if (!CHECK_LEN(header, p, plen, salt_len))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
+ return 0; /* bad packet */
|
||||
|
||||
if (memcmp(p, salt, salt_len) != 0)
|
||||
continue;
|
||||
@@ -1758,13 +1705,13 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
|
||||
/* Algo is checked as 1 above */
|
||||
if (!(hash = hash_find("sha1")))
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
|
||||
- return STAT_SECURE;
|
||||
+ return 1;
|
||||
|
||||
/* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
|
||||
or an answer inferred from a wildcard record. */
|
||||
@@ -1780,14 +1727,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
break;
|
||||
|
||||
if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
for (i = 0; i < nsec_count; i++)
|
||||
if ((p = nsecs[i]))
|
||||
{
|
||||
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
|
||||
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
if (digest_len == base32_len &&
|
||||
memcmp(digest, workspace2, digest_len) == 0)
|
||||
@@ -1802,32 +1749,81 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
while ((closest_encloser = strchr(closest_encloser, '.')));
|
||||
|
||||
if (!closest_encloser)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
/* Look for NSEC3 that proves the non-existence of the next-closest encloser */
|
||||
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
/* Finally, check that there's no seat of wildcard synthesis */
|
||||
if (!wildname)
|
||||
{
|
||||
if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
wildcard--;
|
||||
*wildcard = '*';
|
||||
|
||||
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
|
||||
- return STAT_BOGUS;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
- return STAT_SECURE;
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
|
||||
+{
|
||||
+ static unsigned char **nsecset = NULL;
|
||||
+ static int nsecset_sz = 0;
|
||||
+
|
||||
+ int type_found = 0;
|
||||
+ unsigned char *p = skip_questions(header, plen);
|
||||
+ int type, class, rdlen, i, nsecs_found;
|
||||
+
|
||||
+ /* Move to NS section */
|
||||
+ if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
||||
+ return 0;
|
||||
+
|
||||
+ for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
|
||||
+ {
|
||||
+ unsigned char *pstart = p;
|
||||
+
|
||||
+ if (!(p = skip_name(p, header, plen, 10)))
|
||||
+ return 0;
|
||||
+
|
||||
+ GETSHORT(type, p);
|
||||
+ GETSHORT(class, p);
|
||||
+ p += 4; /* TTL */
|
||||
+ GETSHORT(rdlen, p);
|
||||
+
|
||||
+ if (class == qclass && (type == T_NSEC || type == T_NSEC3))
|
||||
+ {
|
||||
+ /* No mixed NSECing 'round here, thankyouverymuch */
|
||||
+ if (type_found != 0 && type_found != type)
|
||||
+ return 0;
|
||||
+
|
||||
+ type_found = type;
|
||||
+
|
||||
+ if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
|
||||
+ return 0;
|
||||
+
|
||||
+ nsecset[nsecs_found++] = pstart;
|
||||
+ }
|
||||
+
|
||||
+ if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (type_found == T_NSEC)
|
||||
+ return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
|
||||
+ else
|
||||
+ return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
|
||||
}
|
||||
|
||||
/* Check signing status of name.
|
||||
@@ -1925,10 +1921,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
static unsigned char **targets = NULL;
|
||||
static int target_sz = 0;
|
||||
|
||||
- unsigned char *ans_start, *p1, *p2, **nsecs;
|
||||
+ unsigned char *ans_start, *p1, *p2;
|
||||
int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
|
||||
- int i, j, rc, nsec_count;
|
||||
- int nsec_type;
|
||||
+ int i, j, rc;
|
||||
|
||||
if (neganswer)
|
||||
*neganswer = 0;
|
||||
@@ -2080,28 +2075,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
targets[j] = NULL;
|
||||
}
|
||||
|
||||
- if (rc == STAT_SECURE_WILDCARD)
|
||||
- {
|
||||
- /* An attacker replay a wildcard answer with a different
|
||||
- answer and overlay a genuine RR. To prove this
|
||||
- hasn't happened, the answer must prove that
|
||||
- the gennuine record doesn't exist. Check that here. */
|
||||
- if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, class1)))
|
||||
- return STAT_BOGUS; /* No NSECs or bad packet */
|
||||
-
|
||||
- /* Note that we may not yet have validated the NSEC/NSEC3 RRsets. Since the check
|
||||
- below returns either SECURE or BOGUS, that's not a problem. If the RRsets later fail
|
||||
- we'll return BOGUS then. */
|
||||
-
|
||||
- if (nsec_type == T_NSEC)
|
||||
- rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
|
||||
- else
|
||||
- rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename,
|
||||
- keyname, name, type1, wildname, NULL);
|
||||
-
|
||||
- if (rc == STAT_BOGUS)
|
||||
- return rc;
|
||||
- }
|
||||
+ /* An attacker replay a wildcard answer with a different
|
||||
+ answer and overlay a genuine RR. To prove this
|
||||
+ hasn't happened, the answer must prove that
|
||||
+ the gennuine record doesn't exist. Check that here.
|
||||
+ Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
+ That's not a problem since if the RRsets later fail
|
||||
+ we'll return BOGUS then. */
|
||||
+ if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
|
||||
+ return STAT_BOGUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2124,14 +2106,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
/* For anything other than a DS record, this situation is OK if either
|
||||
the answer is in an unsigned zone, or there's a NSEC records. */
|
||||
- if (!(nsec_type = find_nsec_records(header, plen, &nsecs, &nsec_count, qclass)))
|
||||
+ if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
|
||||
{
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
|
||||
- rc = zone_status(name, qclass, keyname, now);
|
||||
- if (rc != STAT_SECURE)
|
||||
+ if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
|
||||
{
|
||||
if (class)
|
||||
*class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
|
||||
@@ -2140,14 +2121,6 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
return STAT_BOGUS; /* signed zone, no NSECs */
|
||||
}
|
||||
-
|
||||
- if (nsec_type == T_NSEC)
|
||||
- rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
|
||||
- else
|
||||
- rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
|
||||
-
|
||||
- if (rc != STAT_SECURE)
|
||||
- return rc;
|
||||
}
|
||||
|
||||
return STAT_SECURE;
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
From 3b799c826db05fc2da1c6d15cbe372e394209d27 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 17 Dec 2015 16:58:04 +0000
|
||||
Subject: [PATCH] Fix brace botch in dnssec_validate_ds()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Thanks to MichaÅ KÄpieÅ for spotting this.
|
||||
---
|
||||
src/dnssec.c | 34 +++++++++++++++++-----------------
|
||||
1 file changed, 17 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index ddae497..1f8c954 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -923,11 +923,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
/* The DNS packet is expected to contain the answer to a DNSKEY query.
|
||||
Put all DNSKEYs in the answer which are valid into the cache.
|
||||
return codes:
|
||||
- STAT_OK Done, key(s) in cache.
|
||||
- STAT_BOGUS No DNSKEYs found, which can be validated with DS,
|
||||
- or self-sign for DNSKEY RRset is not valid, bad packet.
|
||||
- STAT_NEED_DS DS records to validate a key not found, name in keyname
|
||||
- STAT_NEED_DNSKEY DNSKEY records to validate a key not found, name in keyname
|
||||
+ STAT_OK Done, key(s) in cache.
|
||||
+ STAT_BOGUS No DNSKEYs found, which can be validated with DS,
|
||||
+ or self-sign for DNSKEY RRset is not valid, bad packet.
|
||||
+ STAT_NEED_DS DS records to validate a key not found, name in keyname
|
||||
+ STAT_NEED_KEY DNSKEY records to validate a key not found, name in keyname
|
||||
*/
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
|
||||
{
|
||||
@@ -1224,13 +1224,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
}
|
||||
|
||||
p = psave;
|
||||
-
|
||||
- if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
- return STAT_BOGUS; /* bad packet */
|
||||
}
|
||||
-
|
||||
- cache_end_insert();
|
||||
+ if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
+ return STAT_BOGUS; /* bad packet */
|
||||
}
|
||||
+
|
||||
+ cache_end_insert();
|
||||
+
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1828,10 +1828,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
|
||||
/* Check signing status of name.
|
||||
returns:
|
||||
- STAT_SECURE zone is signed.
|
||||
- STAT_INSECURE zone proved unsigned.
|
||||
- STAT_NEED_DS require DS record of name returned in keyname.
|
||||
- STAT_NEED_DNSKEY require DNSKEY record of name returned in keyname.
|
||||
+ STAT_SECURE zone is signed.
|
||||
+ STAT_INSECURE zone proved unsigned.
|
||||
+ STAT_NEED_DS require DS record of name returned in keyname.
|
||||
+ STAT_NEED_KEY require DNSKEY record of name returned in keyname.
|
||||
name returned unaltered.
|
||||
*/
|
||||
static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
@@ -2028,7 +2028,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (rc == STAT_SECURE)
|
||||
rc = STAT_BOGUS;
|
||||
if (class)
|
||||
- *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
|
||||
+ *class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
@@ -2045,7 +2045,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
{
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (class)
|
||||
- *class = class1; /* Class for NEED_DS or NEED_DNSKEY */
|
||||
+ *class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2115,7 +2115,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
|
||||
{
|
||||
if (class)
|
||||
- *class = qclass; /* Class for NEED_DS or NEED_DNSKEY */
|
||||
+ *class = qclass; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
From 14a4ae883d51130d33da7133287e8867c64bab65 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 17 Dec 2015 17:23:03 +0000
|
||||
Subject: [PATCH] Do a better job of determining which DNSSEC sig algos are
|
||||
supported.
|
||||
|
||||
---
|
||||
src/dnssec.c | 52 +++++++++++++++++++++++++++++++++++++---------------
|
||||
1 file changed, 37 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 1f8c954..82394ee 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -65,10 +65,9 @@ static char *algo_digest_name(int algo)
|
||||
case 8: return "sha256";
|
||||
case 10: return "sha512";
|
||||
case 12: return "gosthash94";
|
||||
-#ifndef NO_NETTLE_ECC
|
||||
case 13: return "sha256";
|
||||
case 14: return "sha384";
|
||||
-#endif
|
||||
+
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
@@ -129,13 +128,15 @@ static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
- unsigned char *digest, int algo)
|
||||
+ unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
+
|
||||
+ (void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
@@ -181,7 +182,7 @@ static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
}
|
||||
|
||||
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
- unsigned char *digest, int algo)
|
||||
+ unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
@@ -189,6 +190,8 @@ static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
static struct dsa_public_key *key = NULL;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
+ (void)digest_len;
|
||||
+
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
@@ -292,26 +295,45 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
|
||||
}
|
||||
#endif
|
||||
|
||||
-static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
- unsigned char *digest, size_t digest_len, int algo)
|
||||
+static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
+ unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
- (void)digest_len;
|
||||
-
|
||||
+
|
||||
+ /* Enure at runtime that we have support for this digest */
|
||||
+ if (!hash_find(algo_digest_name(algo)))
|
||||
+ return NULL;
|
||||
+
|
||||
+ /* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 1: case 5: case 7: case 8: case 10:
|
||||
- return dnsmasq_rsa_verify(key_data, key_len, sig, sig_len, digest, algo);
|
||||
+ return dnsmasq_rsa_verify;
|
||||
|
||||
case 3: case 6:
|
||||
- return dnsmasq_dsa_verify(key_data, key_len, sig, sig_len, digest, algo);
|
||||
+ return dnsmasq_dsa_verify;
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
case 13: case 14:
|
||||
- return dnsmasq_ecdsa_verify(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
+ return dnsmasq_ecdsa_verify;
|
||||
#endif
|
||||
}
|
||||
|
||||
- return 0;
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
+ unsigned char *digest, size_t digest_len, int algo)
|
||||
+{
|
||||
+
|
||||
+ int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
+ unsigned char *digest, size_t digest_len, int algo);
|
||||
+
|
||||
+ func = verify_func(algo);
|
||||
+
|
||||
+ if (!func)
|
||||
+ return 0;
|
||||
+
|
||||
+ return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* Convert from presentation format to wire format, in place.
|
||||
@@ -732,7 +754,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
|
||||
if (check_date_range(sig_inception, sig_expiration) &&
|
||||
labels <= name_labels &&
|
||||
type_covered == type &&
|
||||
- algo_digest_name(algo))
|
||||
+ verify_func(algo))
|
||||
{
|
||||
if (!expand_workspace(&sigs, &sig_sz, sigidx))
|
||||
return 0;
|
||||
@@ -1865,7 +1887,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
if (crecp->flags & F_DNSSECOK)
|
||||
return STAT_INSECURE; /* proved no DS here */
|
||||
}
|
||||
- else if (!ds_digest_name(crecp->addr.ds.digest) || !algo_digest_name(crecp->addr.ds.algo))
|
||||
+ else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
|
||||
return STAT_INSECURE; /* algo we can't use - insecure */
|
||||
else
|
||||
secure_ds = 1;
|
||||
@@ -1887,7 +1909,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
|
||||
do
|
||||
{
|
||||
- if (crecp->uid == (unsigned int)class && !algo_digest_name(crecp->addr.key.algo))
|
||||
+ if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
|
||||
return STAT_INSECURE;
|
||||
}
|
||||
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,643 +0,0 @@
|
||||
From fa14bec83b2db010fd076910fddab56957b9375d Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 20 Dec 2015 17:12:16 +0000
|
||||
Subject: [PATCH] Major tidy up of EDNS0 handling and computation/use of udp
|
||||
packet size.
|
||||
|
||||
---
|
||||
src/auth.c | 8 ++-
|
||||
src/dnsmasq.h | 7 ++-
|
||||
src/dnssec.c | 1 -
|
||||
src/forward.c | 184 ++++++++++++++++++++++++++++++++++++++++----------------
|
||||
src/netlink.c | 3 +-
|
||||
src/rfc1035.c | 81 +++++++------------------
|
||||
src/rrfilter.c | 2 +-
|
||||
7 files changed, 168 insertions(+), 118 deletions(-)
|
||||
|
||||
diff --git a/src/auth.c b/src/auth.c
|
||||
index 2b0b7d6..85bd5e7 100644
|
||||
--- a/src/auth.c
|
||||
+++ b/src/auth.c
|
||||
@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut)
|
||||
}
|
||||
|
||||
|
||||
-size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query)
|
||||
+size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr,
|
||||
+ int local_query, int do_bit, int have_pseudoheader)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(authcount);
|
||||
header->arcount = htons(0);
|
||||
+
|
||||
+ /* Advertise our packet size limit in our reply */
|
||||
+ if (have_pseudoheader)
|
||||
+ return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
|
||||
+
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 39a930c..abb34c5 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
int no_cache, int secure, int *doctored);
|
||||
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);
|
||||
+ time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
|
||||
@@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
+ unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost);
|
||||
/* auth.c */
|
||||
#ifdef HAVE_AUTH
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen,
|
||||
- time_t now, union mysockaddr *peer_addr, int local_query);
|
||||
+ time_t now, union mysockaddr *peer_addr, int local_query,
|
||||
+ int do_bit, int have_pseudoheader);
|
||||
int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 82394ee..299ca64 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo)
|
||||
case 12: return "gosthash94";
|
||||
case 13: return "sha256";
|
||||
case 14: return "sha384";
|
||||
-
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 3e801c8..041353c 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -244,7 +244,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
void *hash = &crc;
|
||||
#endif
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
- unsigned char *pheader;
|
||||
|
||||
(void)do_bit;
|
||||
|
||||
@@ -264,7 +263,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
there's no point retrying the query, retry the key query instead...... */
|
||||
if (forward->blocking_query)
|
||||
{
|
||||
- int fd;
|
||||
+ int fd, is_sign;
|
||||
+ unsigned char *pheader;
|
||||
|
||||
forward->flags &= ~FREC_TEST_PKTSZ;
|
||||
|
||||
@@ -276,8 +276,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
|
||||
- if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
|
||||
- PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader);
|
||||
+ if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign)
|
||||
+ PUTSHORT(SAFE_PKTSZ, pheader);
|
||||
|
||||
if (forward->sentto->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
|
||||
@@ -394,32 +394,40 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->log_id = daemon->log_id;
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
- plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
|
||||
-
|
||||
+ {
|
||||
+ size_t new = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
|
||||
+ if (new != plen)
|
||||
+ {
|
||||
+ plen = new;
|
||||
+ forward->flags |= FREC_ADDED_PHEADER;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
size_t new = add_source_addr(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
|
||||
if (new != plen)
|
||||
{
|
||||
plen = new;
|
||||
- forward->flags |= FREC_HAS_SUBNET;
|
||||
+ forward->flags |= FREC_HAS_SUBNET | FREC_ADDED_PHEADER;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
- size_t new_plen = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
|
||||
+ size_t new = add_do_bit(header, plen, ((char *) header) + daemon->packet_buff_sz);
|
||||
|
||||
+ if (new != plen)
|
||||
+ forward->flags |= FREC_ADDED_PHEADER;
|
||||
+
|
||||
+ plen = new;
|
||||
+
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
header->hb4 |= HB4_CD;
|
||||
|
||||
- if (new_plen != plen)
|
||||
- forward->flags |= FREC_ADDED_PHEADER;
|
||||
-
|
||||
- plen = new_plen;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -469,10 +477,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
-
|
||||
- if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
|
||||
- PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader);
|
||||
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
|
||||
+ {
|
||||
+ /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
|
||||
+ packet size to 512. But that won't provide space for the RRSIGS in many cases.
|
||||
+ The RRSIGS will be stripped out before the answer goes back, so the packet should
|
||||
+ shrink again. So, if we added a do-bit, bump the udp packet size to the value
|
||||
+ known to be OK for this server. Maybe check returned size after stripping and set
|
||||
+ the truncated bit? */
|
||||
+ unsigned char *pheader;
|
||||
+ int is_sign;
|
||||
+ if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign))
|
||||
+ PUTSHORT(start->edns_pktsz, pheader);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (retry_send(sendto(fd, (char *)header, plen, 0,
|
||||
&start->addr.sa,
|
||||
sa_len(&start->addr))))
|
||||
@@ -563,30 +584,34 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
#endif
|
||||
|
||||
- /* If upstream is advertising a larger UDP packet size
|
||||
- than we allow, trim it so that we don't get overlarge
|
||||
- requests for the client. We can't do this for signed packets. */
|
||||
-
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
|
||||
{
|
||||
- unsigned short udpsz;
|
||||
- unsigned char *psave = sizep;
|
||||
-
|
||||
- GETSHORT(udpsz, sizep);
|
||||
-
|
||||
- if (!is_sign && udpsz > daemon->edns_pktsz)
|
||||
- PUTSHORT(daemon->edns_pktsz, psave);
|
||||
-
|
||||
if (check_subnet && !check_source(header, plen, pheader, query_source))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (added_pheader)
|
||||
+ if (!is_sign)
|
||||
{
|
||||
- pheader = 0;
|
||||
- header->arcount = htons(0);
|
||||
+ if (added_pheader)
|
||||
+ {
|
||||
+ /* client didn't send EDNS0, we added one, strip it off before returning answer. */
|
||||
+ n = rrfilter(header, n, 0);
|
||||
+ pheader = NULL;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* If upstream is advertising a larger UDP packet size
|
||||
+ than we allow, trim it so that we don't get overlarge
|
||||
+ requests for the client. We can't do this for signed packets. */
|
||||
+ unsigned short udpsz;
|
||||
+ unsigned char *psave = sizep;
|
||||
+
|
||||
+ GETSHORT(udpsz, sizep);
|
||||
+ if (udpsz > daemon->edns_pktsz)
|
||||
+ PUTSHORT(daemon->edns_pktsz, psave);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,14 +680,16 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
- header->hb4 &= ~HB4_AD;
|
||||
-
|
||||
- if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
|
||||
- header->hb4 |= HB4_AD;
|
||||
-
|
||||
- /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
||||
- if (!do_bit)
|
||||
- n = rrfilter(header, n, 1);
|
||||
+ {
|
||||
+ header->hb4 &= ~HB4_AD;
|
||||
+
|
||||
+ if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
|
||||
+ header->hb4 |= HB4_AD;
|
||||
+
|
||||
+ /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
||||
+ if (!do_bit)
|
||||
+ n = rrfilter(header, n, 1);
|
||||
+ }
|
||||
#endif
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
@@ -761,8 +788,14 @@ void reply_query(int fd, int family, time_t now)
|
||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||
{
|
||||
header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
|
||||
- header->hb4 &= ~(HB4_RA | HB4_RCODE);
|
||||
- forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
|
||||
+ header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
|
||||
+ if (forward->flags |= FREC_CHECKING_DISABLED)
|
||||
+ header->hb4 |= HB4_CD;
|
||||
+ if (forward->flags |= FREC_AD_QUESTION)
|
||||
+ header->hb4 |= HB4_AD;
|
||||
+ if (forward->flags & FREC_DO_QUESTION)
|
||||
+ add_do_bit(header, nn, (char *)pheader + plen);
|
||||
+ forward_query(-1, NULL, NULL, 0, header, nn, now, forward, forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1007,12 +1040,13 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||
union mysockaddr source_addr;
|
||||
- unsigned short type;
|
||||
+ unsigned char *pheader;
|
||||
+ unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
|
||||
struct all_addr dst_addr;
|
||||
struct in_addr netmask, dst_addr_4;
|
||||
size_t m;
|
||||
ssize_t n;
|
||||
- int if_index = 0, auth_dns = 0;
|
||||
+ int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
|
||||
#ifdef HAVE_AUTH
|
||||
int local_auth = 0;
|
||||
#endif
|
||||
@@ -1279,10 +1313,30 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
+ if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL))
|
||||
+ {
|
||||
+ unsigned short flags;
|
||||
+
|
||||
+ have_pseudoheader = 1;
|
||||
+ GETSHORT(udp_size, pheader);
|
||||
+ pheader += 2; /* ext_rcode */
|
||||
+ GETSHORT(flags, pheader);
|
||||
+
|
||||
+ if (flags & 0x8000)
|
||||
+ do_bit = 1;/* do bit */
|
||||
+
|
||||
+ /* If the client provides an EDNS0 UDP size, use that to limit our reply.
|
||||
+ (bounded by the maximum configured). If no EDNS0, then it
|
||||
+ defaults to 512 */
|
||||
+ if (udp_size > daemon->edns_pktsz)
|
||||
+ udp_size = daemon->edns_pktsz;
|
||||
+ }
|
||||
+
|
||||
#ifdef HAVE_AUTH
|
||||
if (auth_dns)
|
||||
{
|
||||
- m = answer_auth(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n, now, &source_addr, local_auth);
|
||||
+ m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
|
||||
+ local_auth, do_bit, have_pseudoheader);
|
||||
if (m >= 1)
|
||||
{
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
@@ -1293,9 +1347,13 @@ void receive_query(struct listener *listen, time_t now)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
- int ad_reqd, do_bit;
|
||||
- m = answer_request(header, ((char *) header) + daemon->packet_buff_sz, (size_t)n,
|
||||
- dst_addr_4, netmask, now, &ad_reqd, &do_bit);
|
||||
+ int ad_reqd = do_bit;
|
||||
+ /* RFC 6840 5.7 */
|
||||
+ if (header->hb4 & HB4_AD)
|
||||
+ 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);
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
@@ -1397,7 +1455,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#ifdef HAVE_AUTH
|
||||
int local_auth = 0;
|
||||
#endif
|
||||
- int checking_disabled, ad_question, do_bit, added_pheader = 0;
|
||||
+ int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
|
||||
int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
size_t m;
|
||||
unsigned short qtype;
|
||||
@@ -1414,6 +1472,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr peer_addr;
|
||||
socklen_t peer_len = sizeof(union mysockaddr);
|
||||
int query_count = 0;
|
||||
+ unsigned char *pheader;
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
@@ -1508,15 +1567,35 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
else
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
+ do_bit = 0;
|
||||
+
|
||||
+ if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL))
|
||||
+ {
|
||||
+ unsigned short flags;
|
||||
+
|
||||
+ have_pseudoheader = 1;
|
||||
+ pheader += 4; /* udp_size, ext_rcode */
|
||||
+ GETSHORT(flags, pheader);
|
||||
+
|
||||
+ if (flags & 0x8000)
|
||||
+ do_bit = 1;/* do bit */
|
||||
+ }
|
||||
+
|
||||
#ifdef HAVE_AUTH
|
||||
if (auth_dns)
|
||||
- m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
|
||||
+ m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
|
||||
+ local_auth, do_bit, have_pseudoheader);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
- /* m > 0 if answered from cache */
|
||||
- m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||
- dst_addr_4, netmask, now, &ad_question, &do_bit);
|
||||
+ int ad_reqd = do_bit;
|
||||
+ /* RFC 6840 5.7 */
|
||||
+ if (header->hb4 & HB4_AD)
|
||||
+ ad_reqd = 1;
|
||||
+
|
||||
+ /* 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);
|
||||
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(1);
|
||||
@@ -1615,6 +1694,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
+ added_pheader = 0;
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
size_t new_size = add_do_bit(header, size, ((char *) header) + 65536);
|
||||
@@ -1719,7 +1799,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
- ad_question, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||
+ ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||
|
||||
break;
|
||||
}
|
||||
diff --git a/src/netlink.c b/src/netlink.c
|
||||
index 753784d..3376d68 100644
|
||||
--- a/src/netlink.c
|
||||
+++ b/src/netlink.c
|
||||
@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
- if (inaddr && mac && callback_ok)
|
||||
+ if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
|
||||
+ inaddr && mac && callback_ok)
|
||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index 188d05f..18858a8 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -489,8 +489,8 @@ struct macparm {
|
||||
union mysockaddr *l3;
|
||||
};
|
||||
|
||||
-static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
- int optno, unsigned char *opt, size_t optlen, int set_do)
|
||||
+size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
+ unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
|
||||
{
|
||||
unsigned char *lenp, *datap, *p;
|
||||
int rdlen, is_sign;
|
||||
@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
|
||||
return plen;
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
- PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */
|
||||
+ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
|
||||
PUTSHORT(0, p); /* extended RCODE and version */
|
||||
PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
|
||||
lenp = p;
|
||||
@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
|
||||
if (!match)
|
||||
return 1; /* continue */
|
||||
|
||||
- parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
|
||||
+ parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
|
||||
|
||||
return 0; /* done */
|
||||
}
|
||||
@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
|
||||
{
|
||||
struct macparm parm;
|
||||
|
||||
-/* Must have an existing pseudoheader as the only ar-record,
|
||||
- or have no ar-records. Must also not be signed */
|
||||
-
|
||||
- if (ntohs(header->arcount) > 1)
|
||||
- return plen;
|
||||
-
|
||||
parm.header = header;
|
||||
parm.limit = (unsigned char *)limit;
|
||||
parm.plen = plen;
|
||||
@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
|
||||
struct subnet_opt opt;
|
||||
|
||||
len = calc_subnet_opt(&opt, source);
|
||||
- return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
|
||||
+ return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
|
||||
{
|
||||
- return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
|
||||
+ return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
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)
|
||||
+ time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
- unsigned char *p, *ansp, *pheader;
|
||||
+ unsigned char *p, *ansp;
|
||||
unsigned int qtype, qclass;
|
||||
struct all_addr addr;
|
||||
int nameoffset;
|
||||
unsigned short flag;
|
||||
int q, ans, anscount = 0, addncount = 0;
|
||||
- int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
|
||||
+ int dryrun = 0;
|
||||
struct crec *crecp;
|
||||
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
|
||||
struct mx_srv_record *rec;
|
||||
@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (header->hb4 & HB4_CD)
|
||||
sec_data = 0;
|
||||
|
||||
- /* RFC 6840 5.7 */
|
||||
- *ad_reqd = header->hb4 & HB4_AD;
|
||||
- *do_bit = 0;
|
||||
-
|
||||
/* If there is an additional data section then it will be overwritten by
|
||||
partial replies, so we have to do a dry run to see if we can answer
|
||||
the query. */
|
||||
-
|
||||
if (ntohs(header->arcount) != 0)
|
||||
- {
|
||||
- dryrun = 1;
|
||||
-
|
||||
- /* If there's an additional section, there might be an EDNS(0) pseudoheader */
|
||||
- if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
|
||||
- {
|
||||
- unsigned short flags;
|
||||
-
|
||||
- have_pseudoheader = 1;
|
||||
-
|
||||
- pheader += 4; /* udp size, ext_rcode */
|
||||
- GETSHORT(flags, pheader);
|
||||
-
|
||||
- if ((sec_reqd = flags & 0x8000))
|
||||
- {
|
||||
- *do_bit = 1;/* do bit */
|
||||
- *ad_reqd = 1;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
+ dryrun = 1;
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
rec->offset = 0;
|
||||
@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
- /* Don't filter RRSIGS from answers to ANY queries, even if do-bit
|
||||
- not set. */
|
||||
- if (qtype == T_ANY)
|
||||
- *do_bit = 1;
|
||||
-
|
||||
ans = 0; /* have we answered this question */
|
||||
|
||||
if (qtype == T_TXT || qtype == T_ANY)
|
||||
@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
the zone is unsigned, which implies that we're doing
|
||||
validation. */
|
||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||
- !sec_reqd ||
|
||||
+ !do_bit ||
|
||||
(option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
|
||||
{
|
||||
do
|
||||
@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
/* If the client asked for DNSSEC don't use cached data. */
|
||||
- if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK))
|
||||
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
|
||||
do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts
|
||||
@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
- /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
|
||||
- is cached and the client wants DNSSEC, forward rather than answering from the cache */
|
||||
- if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
|
||||
- {
|
||||
- ans = 1;
|
||||
- auth = 0;
|
||||
- if (crecp->flags & F_NXDOMAIN)
|
||||
- nxdomain = 1;
|
||||
- if (!dryrun)
|
||||
- log_query(crecp->flags, name, NULL, NULL);
|
||||
- }
|
||||
+ ans = 1;
|
||||
+ auth = 0;
|
||||
+ if (crecp->flags & F_NXDOMAIN)
|
||||
+ nxdomain = 1;
|
||||
+ if (!dryrun)
|
||||
+ log_query(crecp->flags, name, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
len = ansp - (unsigned char *)header;
|
||||
|
||||
+ /* Advertise our packet size limit in our reply */
|
||||
if (have_pseudoheader)
|
||||
- len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
|
||||
+ len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
|
||||
|
||||
- if (*ad_reqd && sec_data)
|
||||
+ if (ad_reqd && sec_data)
|
||||
header->hb4 |= HB4_AD;
|
||||
else
|
||||
header->hb4 &= ~HB4_AD;
|
||||
diff --git a/src/rrfilter.c b/src/rrfilter.c
|
||||
index ae12261..b26b39f 100644
|
||||
--- a/src/rrfilter.c
|
||||
+++ b/src/rrfilter.c
|
||||
@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
for (p = rrs[0], i = 1; i < rr_found; i += 2)
|
||||
{
|
||||
unsigned char *start = rrs[i];
|
||||
- unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
|
||||
+ unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
|
||||
|
||||
memmove(p, start, end-start);
|
||||
p += end-start;
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
From d67ecac59d58f249707d26e38d49c29b552af4d8 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 20 Dec 2015 20:44:23 +0000
|
||||
Subject: [PATCH] More tweaks in handling unknown DNSSEC algorithms.
|
||||
|
||||
---
|
||||
src/dnssec.c | 128 +++++++++++++++++++++++++++++-----------------------------
|
||||
1 file changed, 63 insertions(+), 65 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 299ca64..e09f304 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -70,7 +70,17 @@ static char *algo_digest_name(int algo)
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
-
|
||||
+
|
||||
+/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
+static char *nsec3_digest_name(int digest)
|
||||
+{
|
||||
+ switch (digest)
|
||||
+ {
|
||||
+ case 1: return "sha1";
|
||||
+ default: return NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
static const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
@@ -667,7 +677,6 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
|
||||
static int rrset_sz = 0, sig_sz = 0;
|
||||
unsigned char *p;
|
||||
int rrsetidx, sigidx, j, rdlen, res;
|
||||
- int name_labels = count_labels(name); /* For 4035 5.3.2 check */
|
||||
int gotkey = 0;
|
||||
|
||||
if (!(p = skip_questions(header, plen)))
|
||||
@@ -678,7 +687,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
|
||||
j != 0; j--)
|
||||
{
|
||||
unsigned char *pstart, *pdata;
|
||||
- int stype, sclass, algo, type_covered, labels, sig_expiration, sig_inception;
|
||||
+ int stype, sclass, type_covered;
|
||||
|
||||
pstart = p;
|
||||
|
||||
@@ -712,12 +721,7 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(type_covered, p);
|
||||
- algo = *p++;
|
||||
- labels = *p++;
|
||||
- p += 4; /* orig_ttl */
|
||||
- GETLONG(sig_expiration, p);
|
||||
- GETLONG(sig_inception, p);
|
||||
- p += 2; /* key_tag */
|
||||
+ p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
|
||||
|
||||
if (gotkey)
|
||||
{
|
||||
@@ -749,11 +753,8 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
|
||||
}
|
||||
}
|
||||
|
||||
- /* Don't count signatures for algos we don't support */
|
||||
- if (check_date_range(sig_inception, sig_expiration) &&
|
||||
- labels <= name_labels &&
|
||||
- type_covered == type &&
|
||||
- verify_func(algo))
|
||||
+
|
||||
+ if (type_covered == type)
|
||||
{
|
||||
if (!expand_workspace(&sigs, &sig_sz, sigidx))
|
||||
return 0;
|
||||
@@ -795,7 +796,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
|
||||
{
|
||||
unsigned char *p;
|
||||
- int rdlen, j, name_labels;
|
||||
+ int rdlen, j, name_labels, sig_expiration, sig_inception;
|
||||
struct crec *crecp = NULL;
|
||||
int algo, labels, orig_ttl, key_tag;
|
||||
u16 *rr_desc = rrfilter_desc(type);
|
||||
@@ -828,13 +829,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
algo = *p++;
|
||||
labels = *p++;
|
||||
GETLONG(orig_ttl, p);
|
||||
- p += 8; /* sig_expiration, sig_inception already checked */
|
||||
+ GETLONG(sig_expiration, p);
|
||||
+ GETLONG(sig_inception, p);
|
||||
GETSHORT(key_tag, p);
|
||||
|
||||
if (!extract_name(header, plen, &p, keyname, 1, 0))
|
||||
return STAT_BOGUS;
|
||||
|
||||
- if (!(hash = hash_find(algo_digest_name(algo))) ||
|
||||
+ if (!check_date_range(sig_inception, sig_expiration) ||
|
||||
+ labels > name_labels ||
|
||||
+ !(hash = hash_find(algo_digest_name(algo))) ||
|
||||
!hash_init(hash, &ctx, &digest))
|
||||
continue;
|
||||
|
||||
@@ -1112,7 +1116,10 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
else
|
||||
{
|
||||
a.addr.keytag = keytag;
|
||||
- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
|
||||
+ if (verify_func(algo))
|
||||
+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
|
||||
+ else
|
||||
+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u (not supported)");
|
||||
|
||||
recp1->addr.key.keylen = rdlen - 4;
|
||||
recp1->addr.key.keydata = key;
|
||||
@@ -1235,7 +1242,11 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
else
|
||||
{
|
||||
a.addr.keytag = keytag;
|
||||
- log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
|
||||
+ if (hash_find(ds_digest_name(digest)) && verify_func(algo))
|
||||
+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
|
||||
+ else
|
||||
+ log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u (not supported)");
|
||||
+
|
||||
crecp->addr.ds.digest = digest;
|
||||
crecp->addr.ds.keydata = key;
|
||||
crecp->addr.ds.algo = algo;
|
||||
@@ -1660,7 +1671,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
*nons = 1;
|
||||
|
||||
/* Look though the NSEC3 records to find the first one with
|
||||
- an algorithm we support (currently only algo == 1).
|
||||
+ an algorithm we support.
|
||||
|
||||
Take the algo, iterations, and salt of that record
|
||||
as the ones we're going to use, and prune any
|
||||
@@ -1674,7 +1685,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
p += 10; /* type, class, TTL, rdlen */
|
||||
algo = *p++;
|
||||
|
||||
- if (algo == 1)
|
||||
+ if ((hash = hash_find(nsec3_digest_name(algo))))
|
||||
break; /* known algo */
|
||||
}
|
||||
|
||||
@@ -1724,10 +1735,6 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
nsecs[i] = nsec3p;
|
||||
}
|
||||
|
||||
- /* Algo is checked as 1 above */
|
||||
- if (!(hash = hash_find("sha1")))
|
||||
- return 0;
|
||||
-
|
||||
if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
return 0;
|
||||
|
||||
@@ -1843,8 +1850,10 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
|
||||
if (type_found == T_NSEC)
|
||||
return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
|
||||
- else
|
||||
+ else if (type_found == T_NSEC3)
|
||||
return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
|
||||
+ else
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Check signing status of name.
|
||||
@@ -1857,7 +1866,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
*/
|
||||
static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
{
|
||||
- int secure_ds, name_start = strlen(name);
|
||||
+ int name_start = strlen(name);
|
||||
struct crec *crecp;
|
||||
char *p;
|
||||
|
||||
@@ -1867,51 +1876,40 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
|
||||
if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DS)))
|
||||
return STAT_NEED_DS;
|
||||
+
|
||||
+ /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
|
||||
+ F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
|
||||
+ but that's because there's no NS record either, ie this isn't the start
|
||||
+ of a zone. We only prove that the DNS tree below a node is unsigned when
|
||||
+ we prove that we're at a zone cut AND there's no DS record. */
|
||||
+ if (crecp->flags & F_NEG)
|
||||
+ {
|
||||
+ if (crecp->flags & F_DNSSECOK)
|
||||
+ return STAT_INSECURE; /* proved no DS here */
|
||||
+ }
|
||||
else
|
||||
{
|
||||
- secure_ds = 0;
|
||||
-
|
||||
+ int gotone = 0;
|
||||
+
|
||||
+ /* If all the DS records have digest and/or sig algos we don't support,
|
||||
+ then the zone is insecure. Note that if an algo
|
||||
+ appears in the DS, then RRSIGs for that algo MUST
|
||||
+ exist for each RRset: 4035 para 2.2 So if we find
|
||||
+ a DS here with digest and sig we can do, we're entitled
|
||||
+ to assume we can validate the zone and if we can't later,
|
||||
+ because an RRSIG is missing we return BOGUS.
|
||||
+ */
|
||||
do
|
||||
{
|
||||
- if (crecp->uid == (unsigned int)class)
|
||||
- {
|
||||
- /* F_DNSSECOK misused in DS cache records to non-existance of NS record.
|
||||
- F_NEG && !F_DNSSECOK implies that we've proved there's no DS record here,
|
||||
- but that's because there's no NS record either, ie this isn't the start
|
||||
- of a zone. We only prove that the DNS tree below a node is unsigned when
|
||||
- we prove that we're at a zone cut AND there's no DS record.
|
||||
- */
|
||||
- if (crecp->flags & F_NEG)
|
||||
- {
|
||||
- if (crecp->flags & F_DNSSECOK)
|
||||
- return STAT_INSECURE; /* proved no DS here */
|
||||
- }
|
||||
- else if (!hash_find(ds_digest_name(crecp->addr.ds.digest)) || !verify_func(crecp->addr.ds.algo))
|
||||
- return STAT_INSECURE; /* algo we can't use - insecure */
|
||||
- else
|
||||
- secure_ds = 1;
|
||||
- }
|
||||
+ if (crecp->uid == (unsigned int)class &&
|
||||
+ hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
|
||||
+ verify_func(crecp->addr.ds.algo))
|
||||
+ gotone = 1;
|
||||
}
|
||||
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
|
||||
- }
|
||||
-
|
||||
- if (secure_ds)
|
||||
- {
|
||||
- /* We've found only DS records that attest to the DNSKEY RRset in the zone, so we believe
|
||||
- that RRset is good. Furthermore the DNSKEY whose hash is proved by the DS record is
|
||||
- one we can use. However the DNSKEY RRset may contain more than one key and
|
||||
- one of the other keys may use an algorithm we don't support. If that's
|
||||
- the case the zone is insecure for us. */
|
||||
-
|
||||
- if (!(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
|
||||
- return STAT_NEED_KEY;
|
||||
|
||||
- do
|
||||
- {
|
||||
- if (crecp->uid == (unsigned int)class && !verify_func(crecp->addr.key.algo))
|
||||
- return STAT_INSECURE;
|
||||
- }
|
||||
- while ((crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY)));
|
||||
+ if (!gotone)
|
||||
+ return STAT_INSECURE;
|
||||
}
|
||||
|
||||
if (name_start == 0)
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
From 3e86d316c4bb406ed813aa5256615c8a95cac6d8 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 20 Dec 2015 20:50:05 +0000
|
||||
Subject: [PATCH] Nasty, rare and obscure off-by-one in DNSSEC hostname_cmp().
|
||||
|
||||
---
|
||||
src/dnssec.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index e09f304..29848e1 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1394,8 +1394,8 @@ static int hostname_cmp(const char *a, const char *b)
|
||||
if (sb == b)
|
||||
return 1;
|
||||
|
||||
- ea = sa--;
|
||||
- eb = sb--;
|
||||
+ ea = --sa;
|
||||
+ eb = --sb;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From a86fdf437ecc29398f9715ceb5240442a17ac014 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 20 Dec 2015 21:19:20 +0000
|
||||
Subject: [PATCH] Minor tweak to previous commit.
|
||||
|
||||
---
|
||||
src/dnssec.c | 6 ++----
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 29848e1..9fa64b6 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1889,8 +1889,6 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
}
|
||||
else
|
||||
{
|
||||
- int gotone = 0;
|
||||
-
|
||||
/* If all the DS records have digest and/or sig algos we don't support,
|
||||
then the zone is insecure. Note that if an algo
|
||||
appears in the DS, then RRSIGs for that algo MUST
|
||||
@@ -1904,11 +1902,11 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
if (crecp->uid == (unsigned int)class &&
|
||||
hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
|
||||
verify_func(crecp->addr.ds.algo))
|
||||
- gotone = 1;
|
||||
+ break;
|
||||
}
|
||||
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
|
||||
|
||||
- if (!gotone)
|
||||
+ if (!crecp)
|
||||
return STAT_INSECURE;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
From ce5732e84fc46d7f99c152f736cfb4ef5ec98a01 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 20 Dec 2015 21:39:19 +0000
|
||||
Subject: [PATCH] NSEC3 check: RFC5155 para 8.2
|
||||
|
||||
---
|
||||
src/dnssec.c | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index 9fa64b6..486e422 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -1704,7 +1704,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
for (i = 0; i < nsec_count; i++)
|
||||
{
|
||||
unsigned char *nsec3p = nsecs[i];
|
||||
- int this_iter;
|
||||
+ int this_iter, flags;
|
||||
|
||||
nsecs[i] = NULL; /* Speculative, will be restored if OK. */
|
||||
|
||||
@@ -1716,8 +1716,12 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if (*p++ != algo)
|
||||
continue;
|
||||
|
||||
- p++; /* flags */
|
||||
+ flags = *p++; /* flags */
|
||||
|
||||
+ /* 5155 8.2 */
|
||||
+ if (flags != 0 && flags != 1)
|
||||
+ continue;
|
||||
+
|
||||
GETSHORT(this_iter, p);
|
||||
if (this_iter != iterations)
|
||||
continue;
|
||||
--
|
||||
1.7.10.4
|
||||
|
||||
Reference in New Issue
Block a user