update dnsmasq to 2.85
This commit is contained in:
parent
eac41ba838
commit
07044bb4e6
@ -1,361 +0,0 @@
|
||||
From 25e63f1e56f5acdcf91893a1b92ad1e0f2f552d8 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 25 Nov 2020 21:17:52 +0000
|
||||
Subject: [PATCH] Handle caching with EDNS options better.
|
||||
|
||||
If we add the EDNS client subnet option, or the client's
|
||||
MAC address, then the reply we get back may very depending on
|
||||
that. Since the cache is ignorant of such things, it's not safe to
|
||||
cache such replies. This patch determines when a dangerous EDNS
|
||||
option is being added and disables caching.
|
||||
|
||||
Note that for much the same reason, we can't combine multiple
|
||||
queries for the same question when dangerous EDNS options are
|
||||
being added, and the code now handles that in the same way. This
|
||||
query combining is required for security against cache poisoning,
|
||||
so disabling the cache has a security function as well as a
|
||||
correctness one.
|
||||
---
|
||||
man/dnsmasq.8 | 4 ++--
|
||||
src/dnsmasq.h | 3 ++-
|
||||
src/edns0.c | 75 +++++++++++++++++++++++++++++++++++++----------------------
|
||||
src/forward.c | 41 +++++++++++++++++++++-----------
|
||||
4 files changed, 78 insertions(+), 45 deletions(-)
|
||||
|
||||
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
|
||||
index 7c6b405..ac7c9fa 100644
|
||||
--- a/man/dnsmasq.8
|
||||
+++ b/man/dnsmasq.8
|
||||
@@ -692,8 +692,8 @@ 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.
|
||||
+does not take account. Caching is therefore disabled for such replies,
|
||||
+unless the subnet address being added is constant.
|
||||
|
||||
For example,
|
||||
.B --add-subnet=24,96
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index fa8c5ea..9f74c7a 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -655,6 +655,7 @@ struct hostsfile {
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
#define FREC_HAS_PHEADER 1024
|
||||
+#define FREC_NO_CACHE 2048
|
||||
|
||||
#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
@@ -1658,7 +1659,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
- union mysockaddr *source, time_t now, int *check_subnet);
|
||||
+ union mysockaddr *source, time_t now, int *check_subnet, int *cacheable);
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
|
||||
/* arp.c */
|
||||
diff --git a/src/edns0.c b/src/edns0.c
|
||||
index d75d3cc..53cfe24 100644
|
||||
--- a/src/edns0.c
|
||||
+++ b/src/edns0.c
|
||||
@@ -264,7 +264,8 @@ static void encoder(unsigned char *in, char *out)
|
||||
out[3] = char64(in[2]);
|
||||
}
|
||||
|
||||
-static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
+static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
+ union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
@@ -273,6 +274,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
|
||||
{
|
||||
replace = 1;
|
||||
+ *cacheablep = 0;
|
||||
|
||||
if (option_bool(OPT_MAC_HEX))
|
||||
print_mac(encode, mac, maclen);
|
||||
@@ -288,14 +290,18 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
|
||||
}
|
||||
|
||||
|
||||
-static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
+static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
+ union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
|
||||
- plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
-
|
||||
+ {
|
||||
+ *cacheablep = 0;
|
||||
+ plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
+ }
|
||||
+
|
||||
return plen;
|
||||
}
|
||||
|
||||
@@ -313,17 +319,18 @@ static void *get_addrp(union mysockaddr *addr, const short family)
|
||||
return &addr->in.sin_addr;
|
||||
}
|
||||
|
||||
-static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
+static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp = NULL;
|
||||
int sa_family = source->sa.sa_family;
|
||||
-
|
||||
+ int cacheable = 0;
|
||||
+
|
||||
opt->source_netmask = 0;
|
||||
opt->scope_netmask = 0;
|
||||
-
|
||||
+
|
||||
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet6->mask;
|
||||
@@ -331,6 +338,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
sa_family = daemon->add_subnet6->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
|
||||
+ cacheable = 1;
|
||||
}
|
||||
else
|
||||
addrp = &source->in6.sin6_addr;
|
||||
@@ -343,6 +351,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
sa_family = daemon->add_subnet4->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
|
||||
+ cacheable = 1; /* Address is constant */
|
||||
}
|
||||
else
|
||||
addrp = &source->in.sin_addr;
|
||||
@@ -350,8 +359,6 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
|
||||
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
|
||||
- len = 0;
|
||||
-
|
||||
if (addrp && opt->source_netmask != 0)
|
||||
{
|
||||
len = ((opt->source_netmask - 1) >> 3) + 1;
|
||||
@@ -359,18 +366,26 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
if (opt->source_netmask & 7)
|
||||
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
|
||||
}
|
||||
+ else
|
||||
+ {
|
||||
+ cacheable = 1; /* No address ever supplied. */
|
||||
+ len = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (cacheablep)
|
||||
+ *cacheablep = cacheable;
|
||||
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
-static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
|
||||
+static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
struct subnet_opt opt;
|
||||
|
||||
- len = calc_subnet_opt(&opt, source);
|
||||
+ len = calc_subnet_opt(&opt, source, cacheable);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
|
||||
}
|
||||
|
||||
@@ -383,18 +398,18 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
unsigned char *p;
|
||||
int code, i, rdlen;
|
||||
|
||||
- calc_len = calc_subnet_opt(&opt, peer);
|
||||
-
|
||||
- if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
- return 1;
|
||||
-
|
||||
- p += 8; /* skip UDP length and RCODE */
|
||||
+ calc_len = calc_subnet_opt(&opt, peer, NULL);
|
||||
|
||||
- GETSHORT(rdlen, p);
|
||||
- if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
- return 1; /* bad packet */
|
||||
-
|
||||
- /* check if option there */
|
||||
+ if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
+ return 1;
|
||||
+
|
||||
+ p += 8; /* skip UDP length and RCODE */
|
||||
+
|
||||
+ GETSHORT(rdlen, p);
|
||||
+ if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
+ return 1; /* bad packet */
|
||||
+
|
||||
+ /* check if option there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
@@ -412,24 +427,28 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
return 1;
|
||||
}
|
||||
|
||||
+/* Set *check_subnet if we add a client subnet option, which needs to checked
|
||||
+ in the reply. Set *cacheable to zero if we add an option which the answer
|
||||
+ may depend on. */
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
- union mysockaddr *source, time_t now, int *check_subnet)
|
||||
+ union mysockaddr *source, time_t now, int *check_subnet, int *cacheable)
|
||||
{
|
||||
*check_subnet = 0;
|
||||
-
|
||||
+ *cacheable = 1;
|
||||
+
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
- plen = add_mac(header, plen, limit, source, now);
|
||||
+ plen = add_mac(header, plen, limit, source, now, cacheable);
|
||||
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
|
||||
- plen = add_dns_client(header, plen, limit, source, now);
|
||||
-
|
||||
+ plen = add_dns_client(header, plen, limit, source, now, cacheable);
|
||||
+
|
||||
if (daemon->dns_client_id)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
- plen = add_source_addr(header, plen, limit, source);
|
||||
+ plen = add_source_addr(header, plen, limit, source, cacheable);
|
||||
*check_subnet = 1;
|
||||
}
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index d9b32b3..70b84d7 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -352,13 +352,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
{
|
||||
/* Query from new source, but the same query may be in progress
|
||||
from another source. If so, just add this client to the
|
||||
- list that will get the reply.
|
||||
+ list that will get the reply.*/
|
||||
|
||||
- Note that is the EDNS client subnet option is in use, we can't do this,
|
||||
- as the clients (and therefore query EDNS options) will be different
|
||||
- for each query. The EDNS subnet code has checks to avoid
|
||||
- attacks in this case. */
|
||||
- if (!option_bool(OPT_CLIENT_SUBNET) && (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
+ if (!option_bool(OPT_ADD_MAC) && !option_bool(OPT_MAC_B64) &&
|
||||
+ (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
{
|
||||
/* Note whine_malloc() zeros memory. */
|
||||
if (!daemon->free_frec_src &&
|
||||
@@ -455,18 +452,21 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (!flags && forward)
|
||||
{
|
||||
struct server *firstsentto = start;
|
||||
- int subnet, forwarded = 0;
|
||||
+ int subnet, cacheable, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
unsigned char *pheader;
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
forward->frec_src.log_id = daemon->log_id;
|
||||
|
||||
- plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet);
|
||||
+ plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
|
||||
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
-
|
||||
+
|
||||
+ if (!cacheable)
|
||||
+ forward->flags |= FREC_NO_CACHE;
|
||||
+
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
|
||||
{
|
||||
@@ -650,7 +650,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
}
|
||||
#endif
|
||||
-
|
||||
+
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
|
||||
{
|
||||
/* Get extended RCODE. */
|
||||
@@ -1260,6 +1260,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->hb4 |= HB4_CD;
|
||||
else
|
||||
header->hb4 &= ~HB4_CD;
|
||||
+
|
||||
+ /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||
+ since the cache is ignorant of such things. */
|
||||
+ if (forward->flags & FREC_NO_CACHE)
|
||||
+ no_cache_dnssec = 1;
|
||||
|
||||
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||
@@ -1821,7 +1826,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
int local_auth = 0;
|
||||
#endif
|
||||
int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
|
||||
- int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
+ int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
size_t m;
|
||||
unsigned short qtype;
|
||||
unsigned int gotname;
|
||||
@@ -1992,7 +1997,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
char *domain = NULL;
|
||||
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
|
||||
|
||||
- size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||
+ size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
@@ -2171,6 +2176,11 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
break;
|
||||
}
|
||||
|
||||
+ /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
|
||||
+ since the cache is ignorant of such things. */
|
||||
+ if (!cacheable)
|
||||
+ no_cache_dnssec = 1;
|
||||
+
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||
@@ -2435,10 +2445,13 @@ static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
|
||||
struct frec *f;
|
||||
|
||||
/* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
||||
- ensures that no frec created for internal DNSSEC query can be returned here. */
|
||||
+ ensures that no frec created for internal DNSSEC query can be returned here.
|
||||
+
|
||||
+ Similarly FREC_NO_CACHE is never set in flags, so a query which is
|
||||
+ contigent on a particular source address EDNS0 option will never be matched. */
|
||||
|
||||
#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
|
||||
- | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY)
|
||||
+ | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto &&
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
From 12af2b171de0d678d98583e2190789e544440e02 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 22 Jan 2021 18:24:03 +0000
|
||||
Subject: [PATCH] Fix to 75e2f0aec33e58ef5b8d4d107d821c215a52827c
|
||||
|
||||
---
|
||||
src/forward.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 43d0ae7..1def931 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -378,6 +378,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
new->dest = *dst_addr;
|
||||
new->log_id = daemon->log_id;
|
||||
new->iface = dst_iface;
|
||||
+ forward->frec_src.fd = udpfd;
|
||||
}
|
||||
|
||||
return 1;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
From 3f535da79e7a42104543ef5c7b5fa2bed819a78b Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 22 Jan 2021 22:26:25 +0000
|
||||
Subject: [PATCH] Fix for 12af2b171de0d678d98583e2190789e544440e02
|
||||
|
||||
---
|
||||
src/forward.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 1def931..5c9cbbb 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -378,7 +378,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
new->dest = *dst_addr;
|
||||
new->log_id = daemon->log_id;
|
||||
new->iface = dst_iface;
|
||||
- forward->frec_src.fd = udpfd;
|
||||
+ new->fd = udpfd;
|
||||
}
|
||||
|
||||
return 1;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,126 +0,0 @@
|
||||
From 141a26f979b4bc959d8e866a295e24f8cf456920 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 17 Feb 2021 23:56:32 +0000
|
||||
Subject: [PATCH] Fix problem with DNS retries in 2.83/2.84.
|
||||
|
||||
The new logic in 2.83/2.84 which merges distinct requests for the
|
||||
same domain causes problems with clients which do retries as distinct
|
||||
requests (differing IDs and/or source ports.) The retries just get
|
||||
piggy-backed on the first, failed, request.
|
||||
|
||||
The logic is now changed so that distinct requests for repeated
|
||||
queries still get merged into a single ID/source port, but they now
|
||||
always trigger a re-try upstream.
|
||||
|
||||
Thanks to Nicholas Mu for his analysis.
|
||||
---
|
||||
src/forward.c | 79 ++++++++++++++++++++++++++++++++---------------------------
|
||||
1 file changed, 43 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 8fb0327..e82e14a 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -278,8 +278,46 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
fwd_flags |= FREC_DO_QUESTION;
|
||||
#endif
|
||||
|
||||
- /* may be no servers available. */
|
||||
- if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
|
||||
+ /* Check for retry on existing query from same source */
|
||||
+ if (!forward && (!(forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
||||
+ {
|
||||
+ /* Maybe query from new source, but the same query may be in progress
|
||||
+ from another source. If so, just add this client to the
|
||||
+ list that will get the reply.*/
|
||||
+
|
||||
+ if (!option_bool(OPT_ADD_MAC) && !option_bool(OPT_MAC_B64) &&
|
||||
+ (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
+ {
|
||||
+ struct frec_src *new;
|
||||
+
|
||||
+ /* Note whine_malloc() zeros memory. */
|
||||
+ if (!daemon->free_frec_src &&
|
||||
+ daemon->frec_src_count < daemon->ftabsize &&
|
||||
+ (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
||||
+ {
|
||||
+ daemon->frec_src_count++;
|
||||
+ daemon->free_frec_src->next = NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* If we've been spammed with many duplicates, just drop the query. */
|
||||
+ if (!daemon->free_frec_src)
|
||||
+ return 0;
|
||||
+
|
||||
+ new = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = new->next;
|
||||
+ new->next = forward->frec_src.next;
|
||||
+ forward->frec_src.next = new;
|
||||
+ new->orig_id = ntohs(header->id);
|
||||
+ new->source = *udpaddr;
|
||||
+ new->dest = *dst_addr;
|
||||
+ new->log_id = daemon->log_id;
|
||||
+ new->iface = dst_iface;
|
||||
+ new->fd = udpfd;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* retry existing query */
|
||||
+ if (forward)
|
||||
{
|
||||
/* If we didn't get an answer advertising a maximal packet in EDNS,
|
||||
fall back to 1280, which should work everywhere on IPv6.
|
||||
@@ -350,40 +388,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
else
|
||||
{
|
||||
- /* Query from new source, but the same query may be in progress
|
||||
- from another source. If so, just add this client to the
|
||||
- list that will get the reply.*/
|
||||
-
|
||||
- if (!option_bool(OPT_ADD_MAC) && !option_bool(OPT_MAC_B64) &&
|
||||
- (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
- {
|
||||
- /* Note whine_malloc() zeros memory. */
|
||||
- if (!daemon->free_frec_src &&
|
||||
- daemon->frec_src_count < daemon->ftabsize &&
|
||||
- (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
||||
- {
|
||||
- daemon->frec_src_count++;
|
||||
- daemon->free_frec_src->next = NULL;
|
||||
- }
|
||||
-
|
||||
- /* If we've been spammed with many duplicates, just drop the query. */
|
||||
- if (daemon->free_frec_src)
|
||||
- {
|
||||
- struct frec_src *new = daemon->free_frec_src;
|
||||
- daemon->free_frec_src = new->next;
|
||||
- new->next = forward->frec_src.next;
|
||||
- forward->frec_src.next = new;
|
||||
- new->orig_id = ntohs(header->id);
|
||||
- new->source = *udpaddr;
|
||||
- new->dest = *dst_addr;
|
||||
- new->log_id = daemon->log_id;
|
||||
- new->iface = dst_iface;
|
||||
- new->fd = udpfd;
|
||||
- }
|
||||
-
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
+ /* new query */
|
||||
+
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
@@ -392,6 +398,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
#endif
|
||||
type &= ~SERV_DO_DNSSEC;
|
||||
|
||||
+ /* may be no servers available. */
|
||||
if (daemon->servers && !flags)
|
||||
forward = get_new_frec(now, NULL, NULL);
|
||||
/* table full - flags == 0, return REFUSED */
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,114 +0,0 @@
|
||||
From 305cb79c5754d5554729b18a2c06fe7ce699687a Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 18 Feb 2021 21:35:09 +0000
|
||||
Subject: [PATCH] Simplify preceding fix.
|
||||
|
||||
Remove distinction between retry with same QID/SP and
|
||||
retry for same query with different QID/SP. If the
|
||||
QID/SP are the same as an existing one, simply retry,
|
||||
if a new QID/SP is seen, add to the list to be replied to.
|
||||
---
|
||||
src/forward.c | 64 ++++++++++++++++++++---------------------------------------
|
||||
1 file changed, 22 insertions(+), 42 deletions(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index e82e14a..6bbf8a4 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -17,9 +17,6 @@
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
|
||||
-static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
- union mysockaddr *addr,
|
||||
- void *hash);
|
||||
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
|
||||
|
||||
static unsigned short get_id(void);
|
||||
@@ -278,18 +275,20 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
fwd_flags |= FREC_DO_QUESTION;
|
||||
#endif
|
||||
|
||||
- /* Check for retry on existing query from same source */
|
||||
- if (!forward && (!(forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
||||
+ /* Check for retry on existing query */
|
||||
+ if (!forward && (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
{
|
||||
- /* Maybe query from new source, but the same query may be in progress
|
||||
- from another source. If so, just add this client to the
|
||||
- list that will get the reply.*/
|
||||
-
|
||||
- if (!option_bool(OPT_ADD_MAC) && !option_bool(OPT_MAC_B64) &&
|
||||
- (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
- {
|
||||
- struct frec_src *new;
|
||||
+ struct frec_src *src;
|
||||
+
|
||||
+ for (src = &forward->frec_src; src; src = src->next)
|
||||
+ if (src->orig_id == ntohs(header->id) &&
|
||||
+ sockaddr_isequal(&src->source, udpaddr))
|
||||
+ break;
|
||||
|
||||
+ /* Existing query, but from new source, just add this
|
||||
+ client to the list that will get the reply.*/
|
||||
+ if (!src)
|
||||
+ {
|
||||
/* Note whine_malloc() zeros memory. */
|
||||
if (!daemon->free_frec_src &&
|
||||
daemon->frec_src_count < daemon->ftabsize &&
|
||||
@@ -303,16 +302,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (!daemon->free_frec_src)
|
||||
return 0;
|
||||
|
||||
- new = daemon->free_frec_src;
|
||||
- daemon->free_frec_src = new->next;
|
||||
- new->next = forward->frec_src.next;
|
||||
- forward->frec_src.next = new;
|
||||
- new->orig_id = ntohs(header->id);
|
||||
- new->source = *udpaddr;
|
||||
- new->dest = *dst_addr;
|
||||
- new->log_id = daemon->log_id;
|
||||
- new->iface = dst_iface;
|
||||
- new->fd = udpfd;
|
||||
+ src = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = src->next;
|
||||
+ src->next = forward->frec_src.next;
|
||||
+ forward->frec_src.next = src;
|
||||
+ src->orig_id = ntohs(header->id);
|
||||
+ src->source = *udpaddr;
|
||||
+ src->dest = *dst_addr;
|
||||
+ src->log_id = daemon->log_id;
|
||||
+ src->iface = dst_iface;
|
||||
+ src->fd = udpfd;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2433,25 +2432,6 @@ static struct frec *lookup_frec(unsigned short id, int fd, int family, void *has
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
- union mysockaddr *addr,
|
||||
- void *hash)
|
||||
-{
|
||||
- struct frec *f;
|
||||
- struct frec_src *src;
|
||||
-
|
||||
- for (f = daemon->frec_list; f; f = f->next)
|
||||
- if (f->sentto &&
|
||||
- !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) &&
|
||||
- memcmp(hash, f->hash, HASH_SIZE) == 0)
|
||||
- for (src = &f->frec_src; src; src = src->next)
|
||||
- if (src->orig_id == id &&
|
||||
- sockaddr_isequal(&src->source, addr))
|
||||
- return f;
|
||||
-
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
|
||||
{
|
||||
struct frec *f;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
From cc0b4489c782f6b90ca118abb18e716a7a831289 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 15 Jan 2021 22:21:52 +0000
|
||||
Subject: [PATCH] Update to new struct frec fields in conntrack code.
|
||||
|
||||
---
|
||||
src/forward.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index f94c4cf..7a95ddf 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -538,7 +538,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
- if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
|
||||
+ if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
@@ -1193,7 +1193,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
- if (get_incoming_mark(&orig->source, &orig->dest, 0, &mark))
|
||||
+ if (get_incoming_mark(&orig->frec_src.source, &orig->frec_src.dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,84 +0,0 @@
|
||||
From a2a7e040b128a8ec369ba8f22beca2705435b85b Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sat, 12 Dec 2020 23:26:45 +0000
|
||||
Subject: [PATCH] Use the values of --min-port and --max-port in TCP
|
||||
connections.
|
||||
|
||||
Rather that letting the kernel pick source ports, do it ourselves
|
||||
so that the --min-port and --max-port parameters are be obeyed.
|
||||
---
|
||||
CHANGELOG | 5 +++++
|
||||
src/network.c | 37 +++++++++++++++++++++++++++++++++----
|
||||
2 files changed, 38 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/CHANGELOG b/CHANGELOG
|
||||
index e6a2231..34ad22e 100644
|
||||
--- a/CHANGELOG
|
||||
+++ b/CHANGELOG
|
||||
@@ -1,3 +1,8 @@
|
||||
+version 2.83
|
||||
+ Use the values of --min-port and --max-port in outgoing
|
||||
+ TCP connections to upstream DNS servers.
|
||||
+
|
||||
+
|
||||
version 2.82
|
||||
Improve behaviour in the face of network interfaces which come
|
||||
and go and change index. Thanks to Petr Mensik for the patch.
|
||||
diff --git a/src/network.c b/src/network.c
|
||||
index c7d002b..7cf2546 100644
|
||||
--- a/src/network.c
|
||||
+++ b/src/network.c
|
||||
@@ -1262,17 +1262,46 @@ int random_sock(int family)
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
|
||||
{
|
||||
union mysockaddr addr_copy = *addr;
|
||||
+ unsigned short port;
|
||||
+ int tries = 1, done = 0;
|
||||
+ unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
|
||||
+
|
||||
+ if (addr_copy.sa.sa_family == AF_INET)
|
||||
+ port = addr_copy.in.sin_port;
|
||||
+ else
|
||||
+ port = addr_copy.in6.sin6_port;
|
||||
|
||||
/* cannot set source _port_ for TCP connections. */
|
||||
if (is_tcp)
|
||||
+ port = 0;
|
||||
+
|
||||
+ /* Bind a random port within the range given by min-port and max-port */
|
||||
+ if (port == 0)
|
||||
+ {
|
||||
+ tries = ports_avail < 30 ? 3 * ports_avail : 100;
|
||||
+ port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
|
||||
+ }
|
||||
+
|
||||
+ while (tries--)
|
||||
{
|
||||
if (addr_copy.sa.sa_family == AF_INET)
|
||||
- addr_copy.in.sin_port = 0;
|
||||
+ addr_copy.in.sin_port = port;
|
||||
else
|
||||
- addr_copy.in6.sin6_port = 0;
|
||||
+ addr_copy.in6.sin6_port = port;
|
||||
+
|
||||
+ if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) != -1)
|
||||
+ {
|
||||
+ done = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (errno != EADDRINUSE && errno != EACCES)
|
||||
+ return 0;
|
||||
+
|
||||
+ port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
|
||||
}
|
||||
-
|
||||
- if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
|
||||
+
|
||||
+ if (!done)
|
||||
return 0;
|
||||
|
||||
if (!is_tcp && ifindex > 0)
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,252 +0,0 @@
|
||||
From 4c0aecc68524c5fd74053244a605e905dc644228 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
|
||||
Date: Tue, 2 Mar 2021 18:21:32 +0000
|
||||
Subject: [PATCH] Correct occasional --bind-dynamic synchronization break
|
||||
|
||||
Request only one re-read of addresses and/or routes
|
||||
|
||||
Previous implementation re-reads systemd addresses exactly the same
|
||||
number of time equal number of notifications received.
|
||||
This is not necessary, we need just notification of change, then re-read
|
||||
the current state and adapt listeners. Repeated re-reading slows netlink
|
||||
processing and highers CPU usage on mass interface changes.
|
||||
|
||||
Continue reading multicast events from netlink, even when ENOBUFS
|
||||
arrive. Broadcasts are not trusted anyway and refresh would be done in
|
||||
iface_enumerate. Save queued events sent again.
|
||||
|
||||
Remove sleeping on netlink ENOBUFS
|
||||
|
||||
With reduced number of written events netlink should receive ENOBUFS
|
||||
rarely. It does not make sense to wait if it is received. It is just a
|
||||
signal some packets got missing. Fast reading all pending packets is required,
|
||||
seq checking ensures it already. Finishes changes by
|
||||
commit 1d07667ac77c55b9de56b1b2c385167e0e0ec27a.
|
||||
|
||||
Move restart from iface_enumerate to enumerate_interfaces
|
||||
|
||||
When ENOBUFS is received, restart of reading addresses is done. But
|
||||
previously found addresses might not have been found this time. In order
|
||||
to catch this, restart both IPv4 and IPv6 enumeration with clearing
|
||||
found interfaces first. It should deliver up-to-date state also after
|
||||
ENOBUFS.
|
||||
|
||||
Read all netlink messages before netlink restart
|
||||
|
||||
Before writing again into netlink socket, try fetching all pending
|
||||
messages. They would be ignored, only might trigger new address
|
||||
synchronization. Should ensure new try has better chance to succeed.
|
||||
|
||||
ENOBUFS error handling was improved. Netlink is correctly drained before
|
||||
sending a new request again. It seems ENOBUFS supression is no longer
|
||||
necessary or wanted. Let kernel tell us when it failed and handle it a
|
||||
good way.
|
||||
---
|
||||
src/netlink.c | 72 +++++++++++++++++++++++++++++++++++++++--------------------
|
||||
src/network.c | 14 ++++++++----
|
||||
2 files changed, 58 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/src/netlink.c b/src/netlink.c
|
||||
index 0494070..3ad18a6 100644
|
||||
--- a/src/netlink.c
|
||||
+++ b/src/netlink.c
|
||||
@@ -41,19 +41,26 @@
|
||||
|
||||
#ifndef NDA_RTA
|
||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||
-#endif
|
||||
+#endif
|
||||
+
|
||||
+/* Used to request refresh of addresses or routes just once,
|
||||
+ * when multiple changes might be announced. */
|
||||
+enum async_states {
|
||||
+ STATE_NEWADDR = (1 << 0),
|
||||
+ STATE_NEWROUTE = (1 << 1),
|
||||
+};
|
||||
|
||||
|
||||
static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
-static void nl_async(struct nlmsghdr *h);
|
||||
+static unsigned nl_async(struct nlmsghdr *h, unsigned state);
|
||||
+static void nl_multicast_state(unsigned state);
|
||||
|
||||
char *netlink_init(void)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
- int opt = 1;
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
@@ -92,10 +99,6 @@ char *netlink_init(void)
|
||||
iov.iov_len = 100;
|
||||
iov.iov_base = safe_malloc(iov.iov_len);
|
||||
|
||||
- if (daemon->kernel_version >= KERNEL_VERSION(2,6,30) &&
|
||||
- setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1)
|
||||
- return _("warning: failed to set NETLINK_NO_ENOBUFS on netlink socket");
|
||||
-
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -151,7 +154,9 @@ static ssize_t netlink_recv(void)
|
||||
|
||||
|
||||
/* family = AF_UNSPEC finds ARP table entries.
|
||||
- family = AF_LOCAL finds MAC addresses. */
|
||||
+ family = AF_LOCAL finds MAC addresses.
|
||||
+ returns 0 on failure, 1 on success, -1 when restart is required
|
||||
+*/
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
@@ -159,6 +164,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
ssize_t len;
|
||||
static unsigned int seq = 0;
|
||||
int callback_ok = 1;
|
||||
+ unsigned state = 0;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
@@ -170,7 +176,6 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
|
||||
- again:
|
||||
if (family == AF_UNSPEC)
|
||||
req.nlh.nlmsg_type = RTM_GETNEIGH;
|
||||
else if (family == AF_LOCAL)
|
||||
@@ -197,8 +202,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
if (errno == ENOBUFS)
|
||||
{
|
||||
- sleep(1);
|
||||
- goto again;
|
||||
+ nl_multicast_state(state);
|
||||
+ return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -207,7 +212,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
/* May be multicast arriving async */
|
||||
- nl_async(h);
|
||||
+ state = nl_async(h, state);
|
||||
}
|
||||
else if (h->nlmsg_seq != seq)
|
||||
{
|
||||
@@ -341,26 +346,36 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
}
|
||||
|
||||
-void netlink_multicast(void)
|
||||
+static void nl_multicast_state(unsigned state)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
int flags;
|
||||
-
|
||||
- /* don't risk blocking reading netlink messages here. */
|
||||
+
|
||||
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
return;
|
||||
+
|
||||
+ do {
|
||||
+ /* don't risk blocking reading netlink messages here. */
|
||||
+ while ((len = netlink_recv()) != -1)
|
||||
|
||||
- if ((len = netlink_recv()) != -1)
|
||||
- for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
- nl_async(h);
|
||||
-
|
||||
+ for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
+ state = nl_async(h, state);
|
||||
+ } while (errno == ENOBUFS);
|
||||
+
|
||||
/* restore non-blocking status */
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||
}
|
||||
|
||||
-static void nl_async(struct nlmsghdr *h)
|
||||
+void netlink_multicast(void)
|
||||
+{
|
||||
+ unsigned state = 0;
|
||||
+ nl_multicast_state(state);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static unsigned nl_async(struct nlmsghdr *h, unsigned state)
|
||||
{
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
@@ -368,7 +383,8 @@ static void nl_async(struct nlmsghdr *h)
|
||||
if (err->error != 0)
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
}
|
||||
- else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
|
||||
+ else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE &&
|
||||
+ (state & STATE_NEWROUTE)==0)
|
||||
{
|
||||
/* We arrange to receive netlink multicast messages whenever the network route is added.
|
||||
If this happens and we still have a DNS packet in the buffer, we re-send it.
|
||||
@@ -380,10 +396,18 @@ static void nl_async(struct nlmsghdr *h)
|
||||
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
|
||||
(rtm->rtm_table == RT_TABLE_MAIN ||
|
||||
rtm->rtm_table == RT_TABLE_LOCAL))
|
||||
- queue_event(EVENT_NEWROUTE);
|
||||
+ {
|
||||
+ queue_event(EVENT_NEWROUTE);
|
||||
+ state |= STATE_NEWROUTE;
|
||||
+ }
|
||||
+ }
|
||||
+ else if ((h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) &&
|
||||
+ (state & STATE_NEWADDR)==0)
|
||||
+ {
|
||||
+ queue_event(EVENT_NEWADDR);
|
||||
+ state |= STATE_NEWADDR;
|
||||
}
|
||||
- else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
|
||||
- queue_event(EVENT_NEWADDR);
|
||||
+ return state;
|
||||
}
|
||||
#endif
|
||||
|
||||
diff --git a/src/network.c b/src/network.c
|
||||
index 6cf15a9..77eb6ad 100644
|
||||
--- a/src/network.c
|
||||
+++ b/src/network.c
|
||||
@@ -638,7 +638,8 @@ int enumerate_interfaces(int reset)
|
||||
|
||||
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
-
|
||||
+
|
||||
+again:
|
||||
/* Mark interfaces for garbage collection */
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
iface->found = 0;
|
||||
@@ -690,9 +691,14 @@ int enumerate_interfaces(int reset)
|
||||
param.spare = spare;
|
||||
|
||||
ret = iface_enumerate(AF_INET6, ¶m, iface_allowed_v6);
|
||||
-
|
||||
- if (ret)
|
||||
- ret = iface_enumerate(AF_INET, ¶m, iface_allowed_v4);
|
||||
+ if (ret < 0)
|
||||
+ goto again;
|
||||
+ else if (ret)
|
||||
+ {
|
||||
+ ret = iface_enumerate(AF_INET, ¶m, iface_allowed_v4);
|
||||
+ if (ret < 0)
|
||||
+ goto again;
|
||||
+ }
|
||||
|
||||
errsave = errno;
|
||||
close(param.fd);
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
From 04490bf622ac84891aad6f2dd2edf83725decdee Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 22 Jan 2021 16:49:12 +0000
|
||||
Subject: [PATCH] Move fd into frec_src, fixes
|
||||
15b60ddf935a531269bb8c68198de012a4967156
|
||||
|
||||
If identical queries from IPv4 and IPv6 sources are combined by the
|
||||
new code added in 15b60ddf935a531269bb8c68198de012a4967156 then replies
|
||||
can end up being sent via the wrong family of socket. The ->fd
|
||||
should be per query, not per-question.
|
||||
|
||||
In bind-interfaces mode, this could also result in replies being sent
|
||||
via the wrong socket even when IPv4/IPV6 issues are not in play.
|
||||
---
|
||||
src/dnsmasq.h | 3 ++-
|
||||
src/forward.c | 4 ++--
|
||||
2 files changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 914f469..360c226 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -664,6 +664,7 @@ struct frec {
|
||||
union mysockaddr source;
|
||||
union all_addr dest;
|
||||
unsigned int iface, log_id;
|
||||
+ int fd;
|
||||
unsigned short orig_id;
|
||||
struct frec_src *next;
|
||||
} frec_src;
|
||||
@@ -671,7 +672,7 @@ struct frec {
|
||||
struct randfd *rfd4;
|
||||
struct randfd *rfd6;
|
||||
unsigned short new_id;
|
||||
- int fd, forwardall, flags;
|
||||
+ int forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 7a95ddf..43d0ae7 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -402,8 +402,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->frec_src.dest = *dst_addr;
|
||||
forward->frec_src.iface = dst_iface;
|
||||
forward->frec_src.next = NULL;
|
||||
+ forward->frec_src.fd = udpfd;
|
||||
forward->new_id = get_id();
|
||||
- forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
forward->forwardall = 0;
|
||||
forward->flags = fwd_flags;
|
||||
@@ -1300,7 +1300,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
|
||||
#endif
|
||||
|
||||
- send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
+ send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&src->source, &src->dest, src->iface);
|
||||
|
||||
if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,71 +0,0 @@
|
||||
From 824461192ca5098043f9ca4ddeba7df1f65b30ba Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sun, 15 Nov 2020 22:13:25 +0000
|
||||
Subject: [PATCH] Add missing check for NULL return from allocate_rfd().
|
||||
|
||||
Conflict:NA
|
||||
Reference:https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=824461192ca5098043f9ca4ddeba7df1f65b30ba
|
||||
---
|
||||
src/forward.c | 18 ++++++++++--------
|
||||
1 file changed, 10 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 4f9a963..50da095 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -823,7 +823,6 @@ void reply_query(int fd, int family, time_t now)
|
||||
int is_sign;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
- /* For DNSSEC originated queries, just retry the query to the same server. */
|
||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
||||
{
|
||||
struct server *start;
|
||||
@@ -849,6 +848,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
|
||||
|
||||
+ fd = -1;
|
||||
+
|
||||
if (start->sfd)
|
||||
fd = start->sfd->fd;
|
||||
else
|
||||
@@ -856,19 +857,21 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (start->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
/* may have changed family */
|
||||
- if (!forward->rfd6)
|
||||
- forward->rfd6 = allocate_rfd(AF_INET6);
|
||||
- fd = forward->rfd6->fd;
|
||||
+ if (forward->rfd6 || (forward->rfd6 = allocate_rfd(AF_INET6)))
|
||||
+ fd = forward->rfd6->fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* may have changed family */
|
||||
- if (!forward->rfd4)
|
||||
- forward->rfd4 = allocate_rfd(AF_INET);
|
||||
- fd = forward->rfd4->fd;
|
||||
+ if (forward->rfd4 || (forward->rfd4 = allocate_rfd(AF_INET)))
|
||||
+ fd = forward->rfd4->fd;
|
||||
}
|
||||
}
|
||||
|
||||
+ /* Can't get socket. */
|
||||
+ if (fd == -1)
|
||||
+ return;
|
||||
+
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)plen, NULL, &start->addr);
|
||||
#endif
|
||||
@@ -2311,7 +2314,6 @@ struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
|
||||
return f; /* OK if malloc fails and this is NULL */
|
||||
}
|
||||
|
||||
-/* crc is all-ones if not known. */
|
||||
static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,364 +0,0 @@
|
||||
From 4e96a4be685c9e4445f6ee79ad0b36b9119b502a Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 11 Nov 2020 23:25:04 +0000
|
||||
Subject: [PATCH] Fix remote buffer overflow CERT VU#434904
|
||||
|
||||
The problem is in the sort_rrset() function and allows a remote
|
||||
attacker to overwrite memory. Any dnsmasq instance with DNSSEC
|
||||
enabled is vulnerable.
|
||||
---
|
||||
src/dnssec.c | 273 +++++++++++++++++++++++++++++++++--------------------------
|
||||
1 files changed, 151 insertions(+), 122 deletions(-)
|
||||
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index db5c2d1..e95aa34 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -223,138 +223,147 @@ static int check_date_range(unsigned long curtime, u32 date_start, u32 date_end)
|
||||
&& serial_compare_32(curtime, date_end) == SERIAL_LT;
|
||||
}
|
||||
|
||||
-/* 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,
|
||||
- unsigned char **p, u16 **desc)
|
||||
+/* Return bytes of canonicalised rrdata one by one.
|
||||
+ Init state->ip with the RR, and state->end with the end of same.
|
||||
+ Init state->op to NULL.
|
||||
+ Init state->desc to RR descriptor.
|
||||
+ Init state->buff with a MAXDNAME * 2 buffer.
|
||||
+
|
||||
+ After each call which returns 1, state->op points to the next byte of data.
|
||||
+ On returning 0, the end has been reached.
|
||||
+*/
|
||||
+struct rdata_state {
|
||||
+ u16 *desc;
|
||||
+ size_t c;
|
||||
+ unsigned char *end, *ip, *op;
|
||||
+ char *buff;
|
||||
+};
|
||||
+
|
||||
+static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state *state)
|
||||
{
|
||||
- int d = **desc;
|
||||
+ int d;
|
||||
|
||||
- /* No more data needs mangling */
|
||||
- if (d == (u16)-1)
|
||||
+ if (state->op && state->c != 1)
|
||||
{
|
||||
- /* If there's more data than we have space for, just return what fits,
|
||||
- we'll get called again for more chunks */
|
||||
- if (end - *p > bufflen)
|
||||
- {
|
||||
- memcpy(buff, *p, bufflen);
|
||||
- *p += bufflen;
|
||||
- return bufflen;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
+ state->op++;
|
||||
+ state->c--;
|
||||
+ return 1;
|
||||
}
|
||||
-
|
||||
- (*desc)++;
|
||||
-
|
||||
- if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
|
||||
- /* domain-name, canonicalise */
|
||||
- return to_wire(buff);
|
||||
- else
|
||||
- {
|
||||
- /* plain data preceding a domain-name, don't run off the end of the data */
|
||||
- if ((end - *p) < d)
|
||||
- d = end - *p;
|
||||
+
|
||||
+ while (1)
|
||||
+ {
|
||||
+ d = *(state->desc);
|
||||
|
||||
- if (d != 0)
|
||||
+ if (d == (u16)-1)
|
||||
{
|
||||
- memcpy(buff, *p, d);
|
||||
- *p += d;
|
||||
+ /* all the bytes to the end. */
|
||||
+ if ((state->c = state->end - state->ip) != 0)
|
||||
+ {
|
||||
+ state->op = state->ip;
|
||||
+ state->ip = state->end;;
|
||||
+ }
|
||||
+ else
|
||||
+ return 0;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ state->desc++;
|
||||
+
|
||||
+ if (d == (u16)0)
|
||||
+ {
|
||||
+ /* domain-name, canonicalise */
|
||||
+ int len;
|
||||
+
|
||||
+ if (!extract_name(header, plen, &state->ip, state->buff, 1, 0) ||
|
||||
+ (len = to_wire(state->buff)) == 0)
|
||||
+ continue;
|
||||
+
|
||||
+ state->c = len;
|
||||
+ state->op = (unsigned char *)state->buff;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* plain data preceding a domain-name, don't run off the end of the data */
|
||||
+ if ((state->end - state->ip) < d)
|
||||
+ d = state->end - state->ip;
|
||||
+
|
||||
+ if (d == 0)
|
||||
+ continue;
|
||||
+
|
||||
+ state->op = state->ip;
|
||||
+ state->c = d;
|
||||
+ state->ip += d;
|
||||
+ }
|
||||
}
|
||||
|
||||
- return d;
|
||||
+ 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.
|
||||
- The domain-names may have different lengths in each RR, but sort equal
|
||||
-
|
||||
- ------------
|
||||
- |abcde|fghi|
|
||||
- ------------
|
||||
- |abcd|efghi|
|
||||
- ------------
|
||||
-
|
||||
- leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
|
||||
-*/
|
||||
+/* Bubble sort the RRset into the canonical order. */
|
||||
|
||||
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
{
|
||||
- int swap, quit, i, j;
|
||||
+ int swap, i, j;
|
||||
|
||||
do
|
||||
{
|
||||
for (swap = 0, i = 0; i < rrsetidx-1; i++)
|
||||
{
|
||||
- int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
|
||||
- u16 *dp1, *dp2;
|
||||
- unsigned char *end1, *end2;
|
||||
+ int rdlen1, rdlen2;
|
||||
+ struct rdata_state state1, state2;
|
||||
+
|
||||
/* Note that these have been determined to be OK previously,
|
||||
so we don't need to check for NULL return here. */
|
||||
- unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
|
||||
- unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
|
||||
-
|
||||
- p1 += 8; /* skip class, type, ttl */
|
||||
- GETSHORT(rdlen1, p1);
|
||||
- end1 = p1 + rdlen1;
|
||||
-
|
||||
- p2 += 8; /* skip class, type, ttl */
|
||||
- GETSHORT(rdlen2, p2);
|
||||
- end2 = p2 + rdlen2;
|
||||
+ state1.ip = skip_name(rrset[i], header, plen, 10);
|
||||
+ state2.ip = skip_name(rrset[i+1], header, plen, 10);
|
||||
+ state1.op = state2.op = NULL;
|
||||
+ state1.buff = buff1;
|
||||
+ state2.buff = buff2;
|
||||
+ state1.desc = state2.desc = rr_desc;
|
||||
|
||||
- dp1 = dp2 = rr_desc;
|
||||
+ state1.ip += 8; /* skip class, type, ttl */
|
||||
+ GETSHORT(rdlen1, state1.ip);
|
||||
+ if (!CHECK_LEN(header, state1.ip, plen, rdlen1))
|
||||
+ return rrsetidx; /* short packet */
|
||||
+ state1.end = state1.ip + rdlen1;
|
||||
|
||||
- for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
|
||||
+ state2.ip += 8; /* skip class, type, ttl */
|
||||
+ GETSHORT(rdlen2, state2.ip);
|
||||
+ if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
|
||||
+ return rrsetidx; /* short packet */
|
||||
+ state2.end = state2.ip + rdlen2;
|
||||
+
|
||||
+ while (1)
|
||||
{
|
||||
- if (left1 != 0)
|
||||
- memmove(buff1, buff1 + len1 - left1, left1);
|
||||
+ int ok1, ok2;
|
||||
|
||||
- if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
|
||||
- {
|
||||
- quit = 1;
|
||||
- len1 = end1 - p1;
|
||||
- memcpy(buff1 + left1, p1, len1);
|
||||
- }
|
||||
- len1 += left1;
|
||||
-
|
||||
- if (left2 != 0)
|
||||
- memmove(buff2, buff2 + len2 - left2, left2);
|
||||
-
|
||||
- if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
|
||||
- {
|
||||
- quit = 1;
|
||||
- len2 = end2 - p2;
|
||||
- memcpy(buff2 + left2, p2, len2);
|
||||
- }
|
||||
- len2 += left2;
|
||||
-
|
||||
- if (len1 > len2)
|
||||
- left1 = len1 - len2, left2 = 0, len = len2;
|
||||
- else
|
||||
- left2 = len2 - len1, left1 = 0, len = len1;
|
||||
-
|
||||
- rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
|
||||
-
|
||||
- if (rc > 0 || (rc == 0 && quit && len1 > len2))
|
||||
- {
|
||||
- unsigned char *tmp = rrset[i+1];
|
||||
- rrset[i+1] = rrset[i];
|
||||
- rrset[i] = tmp;
|
||||
- swap = quit = 1;
|
||||
- }
|
||||
- else if (rc == 0 && quit && len1 == len2)
|
||||
+ ok1 = get_rdata(header, plen, &state1);
|
||||
+ ok2 = get_rdata(header, plen, &state2);
|
||||
+
|
||||
+ if (!ok1 && !ok2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
+ break;
|
||||
+ }
|
||||
+ else if (ok1 && (!ok2 || *state1.op > *state2.op))
|
||||
+ {
|
||||
+ unsigned char *tmp = rrset[i+1];
|
||||
+ rrset[i+1] = rrset[i];
|
||||
+ rrset[i] = tmp;
|
||||
+ swap = 1;
|
||||
+ break;
|
||||
}
|
||||
- else if (rc < 0)
|
||||
- quit = 1;
|
||||
+ else if (ok2 && (!ok1 || *state2.op > *state1.op))
|
||||
+ break;
|
||||
+
|
||||
+ /* arrive here when bytes are equal, go round the loop again
|
||||
+ and compare the next ones. */
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
@@ -569,15 +578,18 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
wire_len = to_wire(keyname);
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
|
||||
from_wire(keyname);
|
||||
+
|
||||
+#define RRBUFLEN 300 /* Most RRs are smaller than this. */
|
||||
|
||||
for (i = 0; i < rrsetidx; ++i)
|
||||
{
|
||||
- int seg;
|
||||
- unsigned char *end, *cp;
|
||||
- u16 len, *dp;
|
||||
+ int j;
|
||||
+ struct rdata_state state;
|
||||
+ u16 len;
|
||||
+ unsigned char rrbuf[RRBUFLEN];
|
||||
|
||||
p = rrset[i];
|
||||
-
|
||||
+
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -586,12 +598,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
/* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
|
||||
if (labels < name_labels)
|
||||
{
|
||||
- int k;
|
||||
- for (k = name_labels - labels; k != 0; k--)
|
||||
+ for (j = name_labels - labels; j != 0; j--)
|
||||
{
|
||||
while (*name_start != '.' && *name_start != 0)
|
||||
name_start++;
|
||||
- if (k != 1 && *name_start == '.')
|
||||
+ if (j != 1 && *name_start == '.')
|
||||
name_start++;
|
||||
}
|
||||
|
||||
@@ -612,24 +623,44 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS;
|
||||
|
||||
- end = p + rdlen;
|
||||
+ /* canonicalise rdata and calculate length of same, use
|
||||
+ name buffer as workspace for get_rdata. */
|
||||
+ state.ip = p;
|
||||
+ state.op = NULL;
|
||||
+ state.desc = rr_desc;
|
||||
+ state.buff = name;
|
||||
+ state.end = p + rdlen;
|
||||
|
||||
- /* canonicalise rdata and calculate length of same, use name buffer as workspace.
|
||||
- Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
|
||||
- cp = p;
|
||||
- dp = rr_desc;
|
||||
- for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
|
||||
- len += end - cp;
|
||||
- len = htons(len);
|
||||
+ for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
+ if (j < RRBUFLEN)
|
||||
+ rrbuf[j] = *state.op;
|
||||
+
|
||||
+ len = htons((u16)j);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
+
|
||||
+ /* If the RR is shorter than RRBUFLEN (most of them, in practice)
|
||||
+ then we can just digest it now. If it exceeds RRBUFLEN we have to
|
||||
+ go back to the start and do it in chunks. */
|
||||
+ if (j >= RRBUFLEN)
|
||||
+ {
|
||||
+ state.ip = p;
|
||||
+ state.op = NULL;
|
||||
+ state.desc = rr_desc;
|
||||
+
|
||||
+ for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
+ {
|
||||
+ rrbuf[j] = *state.op;
|
||||
+
|
||||
+ if (j == RRBUFLEN - 1)
|
||||
+ {
|
||||
+ hash->update(ctx, RRBUFLEN, rrbuf);
|
||||
+ j = -1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- /* Now canonicalise again and digest. */
|
||||
- cp = p;
|
||||
- dp = rr_desc;
|
||||
- while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
|
||||
- hash->update(ctx, seg, (unsigned char *)name);
|
||||
- if (cp != end)
|
||||
- hash->update(ctx, end - cp, cp);
|
||||
+ if (j != 0)
|
||||
+ hash->update(ctx, j, rrbuf);
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,94 +0,0 @@
|
||||
From 257ac0c5f7732cbc6aa96fdd3b06602234593aca Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 12 Nov 2020 18:49:23 +0000
|
||||
Subject: [PATCH] Check destination of DNS UDP query replies.
|
||||
|
||||
At any time, dnsmasq will have a set of sockets open, bound to
|
||||
random ports, on which it sends queries to upstream nameservers.
|
||||
This patch fixes the existing problem that a reply for ANY in-flight
|
||||
query would be accepted via ANY open port, which increases the
|
||||
chances of an attacker flooding answers "in the blind" in an
|
||||
attempt to poison the DNS cache. CERT VU#434904 refers.
|
||||
---
|
||||
src/forward.c | 37 ++++++++++++++++++++++++++++---------
|
||||
1 files changed, 27 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 9c2b2c6..134e0fc 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
-static struct frec *lookup_frec(unsigned short id, void *hash);
|
||||
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
|
||||
static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
union mysockaddr *addr,
|
||||
void *hash);
|
||||
@@ -805,7 +805,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
crc = questions_crc(header, n, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
- if (!(forward = lookup_frec(ntohs(header->id), hash)))
|
||||
+ if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
|
||||
return;
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
@@ -2339,14 +2339,25 @@ struct frec *get_new_frec(time_t now, int *wait, struct frec *force)
|
||||
}
|
||||
|
||||
/* crc is all-ones if not known. */
|
||||
-static struct frec *lookup_frec(unsigned short id, void *hash)
|
||||
+static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->new_id == id &&
|
||||
(!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
- return f;
|
||||
+ {
|
||||
+ /* sent from random port */
|
||||
+ if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
|
||||
+ return f;
|
||||
+
|
||||
+ if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
|
||||
+ return f;
|
||||
+
|
||||
+ /* sent to upstream from bound socket. */
|
||||
+ if (f->sentto->sfd && f->sentto->sfd->fd == fd)
|
||||
+ return f;
|
||||
+ }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -2407,12 +2418,20 @@ void server_gone(struct server *server)
|
||||
static unsigned short get_id(void)
|
||||
{
|
||||
unsigned short ret = 0;
|
||||
+ struct frec *f;
|
||||
|
||||
- do
|
||||
- ret = rand16();
|
||||
- while (lookup_frec(ret, NULL));
|
||||
-
|
||||
- return ret;
|
||||
+ while (1)
|
||||
+ {
|
||||
+ ret = rand16();
|
||||
+
|
||||
+ /* ensure id is unique. */
|
||||
+ for (f = daemon->frec_list; f; f = f->next)
|
||||
+ if (f->sentto && f->new_id == ret)
|
||||
+ break;
|
||||
+
|
||||
+ if (!f)
|
||||
+ return ret;
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,584 +0,0 @@
|
||||
From 2d765867c597db18be9d876c9c17e2c0fe1953cd Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Thu, 12 Nov 2020 22:06:07 +0000
|
||||
Subject: [PATCH] Use SHA-256 to provide security against DNS cache poisoning.
|
||||
|
||||
Use the SHA-256 hash function to verify that DNS answers
|
||||
received are for the questions originally asked. This replaces
|
||||
the slightly insecure SHA-1 (when compiled with DNSSEC) or
|
||||
the very insecure CRC32 (otherwise). Refer: CERT VU#434904.
|
||||
---
|
||||
Makefile | 3 +-
|
||||
bld/Android.mk | 2 +-
|
||||
src/dnsmasq.h | 11 +-
|
||||
src/dnssec.c | 31 ------
|
||||
src/forward.c | 43 ++------
|
||||
src/hash_questions.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
src/rfc1035.c | 49 ---------
|
||||
7 files changed, 296 insertions(+), 124 deletions(-)
|
||||
create mode 100644 src/hash_questions.c
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 78e25f0..0354e0f 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -77,7 +77,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.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 rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
|
||||
+ poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
||||
+ metrics.o hash_questions.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
diff --git a/bld/Android.mk b/bld/Android.mk
|
||||
index 080a615..f924be9 100644
|
||||
--- a/bld/Android.mk
|
||||
+++ b/bld/Android.mk
|
||||
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.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 rrfilter.c edns0.c arp.c \
|
||||
- crypto.c dump.c ubus.c
|
||||
+ crypto.c dump.c ubus.c metrics.c hash_questions.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 4d78c37..0a7639f 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -655,11 +655,7 @@ struct hostsfile {
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
-#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
-#else
|
||||
-#define HASH_SIZE sizeof(int)
|
||||
-#endif
|
||||
+#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
@@ -1229,7 +1225,6 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *baddr, time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
-unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
@@ -1254,9 +1249,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int check_unsigned, int *neganswer, int *nons, int *nsec_ttl);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
-unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
|
||||
+/* hash_questions.c */
|
||||
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
+
|
||||
/* crypto.c */
|
||||
const struct nettle_hash *hash_find(char *name);
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
|
||||
diff --git a/src/dnssec.c b/src/dnssec.c
|
||||
index e95aa34..9410a7e 100644
|
||||
--- a/src/dnssec.c
|
||||
+++ b/src/dnssec.c
|
||||
@@ -2087,35 +2087,4 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
|
||||
return ret;
|
||||
}
|
||||
|
||||
-unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
-{
|
||||
- int q;
|
||||
- unsigned int len;
|
||||
- unsigned char *p = (unsigned char *)(header+1);
|
||||
- const struct nettle_hash *hash;
|
||||
- void *ctx;
|
||||
- unsigned char *digest;
|
||||
-
|
||||
- if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
|
||||
- return NULL;
|
||||
-
|
||||
- for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
- {
|
||||
- if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
- break; /* bad packet */
|
||||
-
|
||||
- len = to_wire(name);
|
||||
- hash->update(ctx, len, (unsigned char *)name);
|
||||
- /* CRC the class and type as well */
|
||||
- hash->update(ctx, 4, p);
|
||||
-
|
||||
- p += 4;
|
||||
- if (!CHECK_LEN(header, p, plen, 0))
|
||||
- break; /* bad packet */
|
||||
- }
|
||||
-
|
||||
- hash->digest(ctx, hash->digest_size, digest);
|
||||
- return digest;
|
||||
-}
|
||||
-
|
||||
#endif /* HAVE_DNSSEC */
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 134e0fc..4f9a963 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -256,19 +256,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
union all_addr *addrp = NULL;
|
||||
unsigned int flags = 0;
|
||||
struct server *start = NULL;
|
||||
-#ifdef HAVE_DNSSEC
|
||||
void *hash = hash_questions(header, plen, daemon->namebuff);
|
||||
+#ifdef HAVE_DNSSEC
|
||||
int do_dnssec = 0;
|
||||
-#else
|
||||
- unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
- void *hash = &crc;
|
||||
#endif
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
(void)do_bit;
|
||||
|
||||
/* may be no servers available. */
|
||||
- if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
||||
+ if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
|
||||
{
|
||||
/* If we didn't get an answer advertising a maximal packet in EDNS,
|
||||
fall back to 1280, which should work everywhere on IPv6.
|
||||
@@ -769,9 +766,6 @@ void reply_query(int fd, int family, time_t now)
|
||||
size_t nn;
|
||||
struct server *server;
|
||||
void *hash;
|
||||
-#ifndef HAVE_DNSSEC
|
||||
- unsigned int crc;
|
||||
-#endif
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -798,12 +792,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
|
||||
server->edns_pktsz = daemon->edns_pktsz;
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
hash = hash_questions(header, n, daemon->namebuff);
|
||||
-#else
|
||||
- hash = &crc;
|
||||
- crc = questions_crc(header, n, daemon->namebuff);
|
||||
-#endif
|
||||
|
||||
if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
|
||||
return;
|
||||
@@ -1115,8 +1104,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, daemon->keyname, (union all_addr *)&(server->addr.in6.sin6_addr),
|
||||
querystr("dnssec-query", querytype));
|
||||
|
||||
- if ((hash = hash_questions(header, nn, daemon->namebuff)))
|
||||
- memcpy(new->hash, hash, HASH_SIZE);
|
||||
+ memcpy(new->hash, hash_questions(header, nn, daemon->namebuff), HASH_SIZE);
|
||||
new->new_id = get_id();
|
||||
header->id = htons(new->new_id);
|
||||
/* Save query for retransmission */
|
||||
@@ -1970,15 +1958,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (!flags && last_server)
|
||||
{
|
||||
struct server *firstsendto = NULL;
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- unsigned char *newhash, hash[HASH_SIZE];
|
||||
- if ((newhash = hash_questions(header, (unsigned int)size, daemon->namebuff)))
|
||||
- memcpy(hash, newhash, HASH_SIZE);
|
||||
- else
|
||||
- memset(hash, 0, HASH_SIZE);
|
||||
-#else
|
||||
- unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
|
||||
-#endif
|
||||
+ unsigned char hash[HASH_SIZE];
|
||||
+ memcpy(hash, hash_questions(header, (unsigned int)size, daemon->namebuff), HASH_SIZE);
|
||||
+
|
||||
/* Loop round available servers until we succeed in connecting to one.
|
||||
Note that this code subtly ensures that consecutive queries on this connection
|
||||
which can go to the same server, do so. */
|
||||
@@ -2117,20 +2099,11 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* If the crc of the question section doesn't match the crc we sent, then
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
-#ifdef HAVE_DNSSEC
|
||||
- newhash = hash_questions(header, (unsigned int)m, daemon->namebuff);
|
||||
- if (!newhash || memcmp(hash, newhash, HASH_SIZE) != 0)
|
||||
+ if (memcmp(hash, hash_questions(header, (unsigned int)m, daemon->namebuff), HASH_SIZE) != 0)
|
||||
{
|
||||
m = 0;
|
||||
break;
|
||||
}
|
||||
-#else
|
||||
- if (crc != questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
- {
|
||||
- m = 0;
|
||||
- break;
|
||||
- }
|
||||
-#endif
|
||||
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
@@ -2345,7 +2318,7 @@ static struct frec *lookup_frec(unsigned short id, int fd, int family, void *has
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto && f->new_id == id &&
|
||||
- (!hash || memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
+ (memcmp(hash, f->hash, HASH_SIZE) == 0))
|
||||
{
|
||||
/* sent from random port */
|
||||
if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
|
||||
diff --git a/src/hash_questions.c b/src/hash_questions.c
|
||||
new file mode 100644
|
||||
index 0000000..ae112ac
|
||||
--- /dev/null
|
||||
+++ b/src/hash_questions.c
|
||||
@@ -0,0 +1,281 @@
|
||||
+/* Copyright (c) 2012-2020 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/>.
|
||||
+*/
|
||||
+
|
||||
+
|
||||
+/* Hash the question section. This is used to safely detect query
|
||||
+ retransmission and to detect answers to questions we didn't ask, which
|
||||
+ might be poisoning attacks. Note that we decode the name rather
|
||||
+ than CRC the raw bytes, since replies might be compressed differently.
|
||||
+ We ignore case in the names for the same reason.
|
||||
+
|
||||
+ The hash used is SHA-256. If we're building with DNSSEC support,
|
||||
+ we use the Nettle cypto library. If not, we prefer not to
|
||||
+ add a dependency on Nettle, and use a stand-alone implementaion.
|
||||
+*/
|
||||
+
|
||||
+#include "dnsmasq.h"
|
||||
+
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
+{
|
||||
+ int q;
|
||||
+ unsigned char *p = (unsigned char *)(header+1);
|
||||
+ const struct nettle_hash *hash;
|
||||
+ void *ctx;
|
||||
+ unsigned char *digest;
|
||||
+
|
||||
+ if (!(hash = hash_find("sha256")) || !hash_init(hash, &ctx, &digest))
|
||||
+ {
|
||||
+ /* don't think this can ever happen. */
|
||||
+ static unsigned char dummy[HASH_SIZE];
|
||||
+ static int warned = 0;
|
||||
+
|
||||
+ if (warned)
|
||||
+ my_syslog(LOG_ERR, _("Failed to create SHA-256 hash object"));
|
||||
+ warned = 1;
|
||||
+
|
||||
+ return dummy;
|
||||
+ }
|
||||
+
|
||||
+ for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
+ {
|
||||
+ char *cp, c;
|
||||
+
|
||||
+ if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
+ break; /* bad packet */
|
||||
+
|
||||
+ for (cp = name; (c = *cp); cp++)
|
||||
+ if (c >= 'A' && c <= 'Z')
|
||||
+ *cp += 'a' - 'A';
|
||||
+
|
||||
+ hash->update(ctx, cp - name, (unsigned char *)name);
|
||||
+ /* CRC the class and type as well */
|
||||
+ hash->update(ctx, 4, p);
|
||||
+
|
||||
+ p += 4;
|
||||
+ if (!CHECK_LEN(header, p, plen, 0))
|
||||
+ break; /* bad packet */
|
||||
+ }
|
||||
+
|
||||
+ hash->digest(ctx, hash->digest_size, digest);
|
||||
+ return digest;
|
||||
+}
|
||||
+
|
||||
+#else /* HAVE_DNSSEC */
|
||||
+
|
||||
+#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
|
||||
+typedef unsigned char BYTE; // 8-bit byte
|
||||
+typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
|
||||
+
|
||||
+typedef struct {
|
||||
+ BYTE data[64];
|
||||
+ WORD datalen;
|
||||
+ unsigned long long bitlen;
|
||||
+ WORD state[8];
|
||||
+} SHA256_CTX;
|
||||
+
|
||||
+static void sha256_init(SHA256_CTX *ctx);
|
||||
+static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
|
||||
+static void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
|
||||
+
|
||||
+
|
||||
+unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
+{
|
||||
+ int q;
|
||||
+ unsigned char *p = (unsigned char *)(header+1);
|
||||
+ SHA256_CTX ctx;
|
||||
+ static BYTE digest[SHA256_BLOCK_SIZE];
|
||||
+
|
||||
+ sha256_init(&ctx);
|
||||
+
|
||||
+ for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
+ {
|
||||
+ char *cp, c;
|
||||
+
|
||||
+ if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
+ break; /* bad packet */
|
||||
+
|
||||
+ for (cp = name; (c = *cp); cp++)
|
||||
+ if (c >= 'A' && c <= 'Z')
|
||||
+ *cp += 'a' - 'A';
|
||||
+
|
||||
+ sha256_update(&ctx, (BYTE *)name, cp - name);
|
||||
+ /* CRC the class and type as well */
|
||||
+ sha256_update(&ctx, (BYTE *)p, 4);
|
||||
+
|
||||
+ p += 4;
|
||||
+ if (!CHECK_LEN(header, p, plen, 0))
|
||||
+ break; /* bad packet */
|
||||
+ }
|
||||
+
|
||||
+ sha256_final(&ctx, digest);
|
||||
+ return (unsigned char *)digest;
|
||||
+}
|
||||
+
|
||||
+/* Code from here onwards comes from https://github.com/B-Con/crypto-algorithms
|
||||
+ and was written by Brad Conte (brad@bradconte.com), to whom all credit is given.
|
||||
+
|
||||
+ This code is in the public domain, and the copyright notice at the head of this
|
||||
+ file does not apply to it.
|
||||
+*/
|
||||
+
|
||||
+
|
||||
+/****************************** MACROS ******************************/
|
||||
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
|
||||
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
|
||||
+
|
||||
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
|
||||
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
|
||||
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
|
||||
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
|
||||
+
|
||||
+/**************************** VARIABLES *****************************/
|
||||
+static const WORD k[64] = {
|
||||
+ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
+};
|
||||
+
|
||||
+/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
+static void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
|
||||
+{
|
||||
+ WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
|
||||
+
|
||||
+ for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
+ m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
|
||||
+ for ( ; i < 64; ++i)
|
||||
+ m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
+
|
||||
+ a = ctx->state[0];
|
||||
+ b = ctx->state[1];
|
||||
+ c = ctx->state[2];
|
||||
+ d = ctx->state[3];
|
||||
+ e = ctx->state[4];
|
||||
+ f = ctx->state[5];
|
||||
+ g = ctx->state[6];
|
||||
+ h = ctx->state[7];
|
||||
+
|
||||
+ for (i = 0; i < 64; ++i)
|
||||
+ {
|
||||
+ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
|
||||
+ t2 = EP0(a) + MAJ(a,b,c);
|
||||
+ h = g;
|
||||
+ g = f;
|
||||
+ f = e;
|
||||
+ e = d + t1;
|
||||
+ d = c;
|
||||
+ c = b;
|
||||
+ b = a;
|
||||
+ a = t1 + t2;
|
||||
+ }
|
||||
+
|
||||
+ ctx->state[0] += a;
|
||||
+ ctx->state[1] += b;
|
||||
+ ctx->state[2] += c;
|
||||
+ ctx->state[3] += d;
|
||||
+ ctx->state[4] += e;
|
||||
+ ctx->state[5] += f;
|
||||
+ ctx->state[6] += g;
|
||||
+ ctx->state[7] += h;
|
||||
+}
|
||||
+
|
||||
+static void sha256_init(SHA256_CTX *ctx)
|
||||
+{
|
||||
+ ctx->datalen = 0;
|
||||
+ ctx->bitlen = 0;
|
||||
+ ctx->state[0] = 0x6a09e667;
|
||||
+ ctx->state[1] = 0xbb67ae85;
|
||||
+ ctx->state[2] = 0x3c6ef372;
|
||||
+ ctx->state[3] = 0xa54ff53a;
|
||||
+ ctx->state[4] = 0x510e527f;
|
||||
+ ctx->state[5] = 0x9b05688c;
|
||||
+ ctx->state[6] = 0x1f83d9ab;
|
||||
+ ctx->state[7] = 0x5be0cd19;
|
||||
+}
|
||||
+
|
||||
+static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
|
||||
+{
|
||||
+ WORD i;
|
||||
+
|
||||
+ for (i = 0; i < len; ++i)
|
||||
+ {
|
||||
+ ctx->data[ctx->datalen] = data[i];
|
||||
+ ctx->datalen++;
|
||||
+ if (ctx->datalen == 64) {
|
||||
+ sha256_transform(ctx, ctx->data);
|
||||
+ ctx->bitlen += 512;
|
||||
+ ctx->datalen = 0;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
+{
|
||||
+ WORD i;
|
||||
+
|
||||
+ i = ctx->datalen;
|
||||
+
|
||||
+ // Pad whatever data is left in the buffer.
|
||||
+ if (ctx->datalen < 56)
|
||||
+ {
|
||||
+ ctx->data[i++] = 0x80;
|
||||
+ while (i < 56)
|
||||
+ ctx->data[i++] = 0x00;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ ctx->data[i++] = 0x80;
|
||||
+ while (i < 64)
|
||||
+ ctx->data[i++] = 0x00;
|
||||
+ sha256_transform(ctx, ctx->data);
|
||||
+ memset(ctx->data, 0, 56);
|
||||
+ }
|
||||
+
|
||||
+ // Append to the padding the total message's length in bits and transform.
|
||||
+ ctx->bitlen += ctx->datalen * 8;
|
||||
+ ctx->data[63] = ctx->bitlen;
|
||||
+ ctx->data[62] = ctx->bitlen >> 8;
|
||||
+ ctx->data[61] = ctx->bitlen >> 16;
|
||||
+ ctx->data[60] = ctx->bitlen >> 24;
|
||||
+ ctx->data[59] = ctx->bitlen >> 32;
|
||||
+ ctx->data[58] = ctx->bitlen >> 40;
|
||||
+ ctx->data[57] = ctx->bitlen >> 48;
|
||||
+ ctx->data[56] = ctx->bitlen >> 56;
|
||||
+ sha256_transform(ctx, ctx->data);
|
||||
+
|
||||
+ // Since this implementation uses little endian byte ordering and SHA uses big endian,
|
||||
+ // reverse all the bytes when copying the final state to the output hash.
|
||||
+ for (i = 0; i < 4; ++i)
|
||||
+ {
|
||||
+ hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index fefe63d..a8cdc6e 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -333,55 +333,6 @@ unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *h
|
||||
return ansp;
|
||||
}
|
||||
|
||||
-/* CRC the question section. This is used to safely detect query
|
||||
- retransmission and to detect answers to questions we didn't ask, which
|
||||
- might be poisoning attacks. Note that we decode the name rather
|
||||
- than CRC the raw bytes, since replies might be compressed differently.
|
||||
- We ignore case in the names for the same reason. Return all-ones
|
||||
- if there is not question section. */
|
||||
-#ifndef HAVE_DNSSEC
|
||||
-unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
|
||||
-{
|
||||
- int q;
|
||||
- unsigned int crc = 0xffffffff;
|
||||
- unsigned char *p1, *p = (unsigned char *)(header+1);
|
||||
-
|
||||
- for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
- {
|
||||
- if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
- return crc; /* bad packet */
|
||||
-
|
||||
- for (p1 = (unsigned char *)name; *p1; p1++)
|
||||
- {
|
||||
- int i = 8;
|
||||
- char c = *p1;
|
||||
-
|
||||
- if (c >= 'A' && c <= 'Z')
|
||||
- c += 'a' - 'A';
|
||||
-
|
||||
- crc ^= c << 24;
|
||||
- while (i--)
|
||||
- crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
|
||||
- }
|
||||
-
|
||||
- /* CRC the class and type as well */
|
||||
- for (p1 = p; p1 < p+4; p1++)
|
||||
- {
|
||||
- int i = 8;
|
||||
- crc ^= *p1 << 24;
|
||||
- while (i--)
|
||||
- crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
|
||||
- }
|
||||
-
|
||||
- p += 4;
|
||||
- if (!CHECK_LEN(header, p, plen, 0))
|
||||
- return crc; /* bad packet */
|
||||
- }
|
||||
-
|
||||
- return crc;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
{
|
||||
unsigned char *ansp = skip_questions(header, plen);
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,196 +0,0 @@
|
||||
From 2024f9729713fd657d65e64c2e4e471baa0a3e5b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
|
||||
Date: Wed, 25 Nov 2020 17:18:55 +0100
|
||||
Subject: [PATCH] Support hash function from nettle (only)
|
||||
|
||||
Unlike COPTS=-DHAVE_DNSSEC, allow usage of just sha256 function from
|
||||
nettle, but keep DNSSEC disabled at build time. Skips use of internal
|
||||
hash implementation without support for validation built-in.
|
||||
---
|
||||
Makefile | 8 +++++---
|
||||
bld/pkg-wrapper | 41 ++++++++++++++++++++++-------------------
|
||||
src/config.h | 8 ++++++++
|
||||
src/crypto.c | 7 +++++++
|
||||
src/dnsmasq.h | 2 +-
|
||||
src/hash_questions.c | 2 +-
|
||||
6 files changed, 44 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 0354e0f..7d2afd1 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -53,7 +53,7 @@ top?=$(CURDIR)
|
||||
|
||||
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
-ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy -lubox -lubus`
|
||||
+ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy '-lubox -lubus'`
|
||||
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
|
||||
@@ -62,8 +62,10 @@ ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CON
|
||||
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
|
||||
-nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
|
||||
-nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
|
||||
+nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
|
||||
+ HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
|
||||
+nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs 'nettle hogweed' \
|
||||
+ HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
diff --git a/bld/pkg-wrapper b/bld/pkg-wrapper
|
||||
index 704bdd3..89713b4 100755
|
||||
--- a/bld/pkg-wrapper
|
||||
+++ b/bld/pkg-wrapper
|
||||
@@ -1,35 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
-search=$1
|
||||
-shift
|
||||
-pkg=$1
|
||||
-shift
|
||||
-op=$1
|
||||
-shift
|
||||
-
|
||||
in=`cat`
|
||||
|
||||
-if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep $search >/dev/null 2>&1; then
|
||||
+search()
|
||||
+{
|
||||
+ grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null 2>&1 || \
|
||||
+ echo $in | grep $1 >/dev/null 2>&1
|
||||
+}
|
||||
+
|
||||
+while [ "$#" -gt 0 ]; do
|
||||
+ search=$1
|
||||
+ pkg=$2
|
||||
+ op=$3
|
||||
+ lib=$4
|
||||
+ shift 4
|
||||
+if search "$search"; then
|
||||
+
|
||||
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
if [ -z "$pkg" ]; then
|
||||
- pkg="$*"
|
||||
- elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
+ pkg="$lib"
|
||||
+ elif search "$pkg"; then
|
||||
pkg=""
|
||||
else
|
||||
- pkg="$*"
|
||||
+ pkg="$lib"
|
||||
fi
|
||||
- elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
- pkg=`$pkg --static $op $*`
|
||||
+ elif search "${search}_STATIC"; then
|
||||
+ pkg=`$pkg --static $op $lib`
|
||||
else
|
||||
- pkg=`$pkg $op $*`
|
||||
+ pkg=`$pkg $op $lib`
|
||||
fi
|
||||
|
||||
- if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
- echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
+ if search "${search}_STATIC"; then
|
||||
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
|
||||
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
|
||||
else
|
||||
@@ -40,3 +42,4 @@ if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
fi
|
||||
fi
|
||||
|
||||
+done
|
||||
diff --git a/src/config.h b/src/config.h
|
||||
index 7187ffa..e71a117 100644
|
||||
--- a/src/config.h
|
||||
+++ b/src/config.h
|
||||
@@ -120,6 +120,9 @@ HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
+HAVE_NETTLEHASH
|
||||
+ include just hash function from nettle, but no DNSSEC.
|
||||
+
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
||||
@@ -187,6 +190,7 @@ RESOLVFILE
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_LIBIDN2 */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
+/* #define HAVE_NETTLEHASH */
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
|
||||
@@ -420,6 +424,10 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"auth "
|
||||
+#if !defined(HAVE_NETTLEHASH) && !defined(HAVE_DNSSEC)
|
||||
+"no-"
|
||||
+#endif
|
||||
+"nettlehash "
|
||||
#ifndef HAVE_DNSSEC
|
||||
"no-"
|
||||
#endif
|
||||
diff --git a/src/crypto.c b/src/crypto.c
|
||||
index ca63111..09525d2 100644
|
||||
--- a/src/crypto.c
|
||||
+++ b/src/crypto.c
|
||||
@@ -25,6 +25,9 @@
|
||||
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
|
||||
# include <nettle/gostdsa.h>
|
||||
#endif
|
||||
+#endif
|
||||
+
|
||||
+#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
@@ -167,6 +170,10 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
|
||||
|
||||
return 1;
|
||||
}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+#ifdef HAVE_DNSSEC
|
||||
|
||||
static int dnsmasq_rsa_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)
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 9f74c7a..914f469 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -157,7 +157,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
+#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
diff --git a/src/hash_questions.c b/src/hash_questions.c
|
||||
index ae112ac..917c18e 100644
|
||||
--- a/src/hash_questions.c
|
||||
+++ b/src/hash_questions.c
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
-#ifdef HAVE_DNSSEC
|
||||
+#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,328 +0,0 @@
|
||||
From 15b60ddf935a531269bb8c68198de012a4967156 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Wed, 18 Nov 2020 18:34:55 +0000
|
||||
Subject: [PATCH] Handle multiple identical near simultaneous DNS queries
|
||||
better.
|
||||
|
||||
Previously, such queries would all be forwarded
|
||||
independently. This is, in theory, inefficent but in practise
|
||||
not a problem, _except_ that is means that an answer for any
|
||||
of the forwarded queries will be accepted and cached.
|
||||
An attacker can send a query multiple times, and for each repeat,
|
||||
another {port, ID} becomes capable of accepting the answer he is
|
||||
sending in the blind, to random IDs and ports. The chance of a
|
||||
succesful attack is therefore multiplied by the number of repeats
|
||||
of the query. The new behaviour detects repeated queries and
|
||||
merely stores the clients sending repeats so that when the
|
||||
first query completes, the answer can be sent to all the
|
||||
clients who asked. Refer: CERT VU#434904.
|
||||
---
|
||||
src/dnsmasq.h | 19 +++++---
|
||||
src/forward.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++----------
|
||||
2 files changed, 132 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
|
||||
index 0a7639f..fa8c5ea 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -653,19 +653,24 @@ struct hostsfile {
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
-#define FREC_HAS_EXTRADATA 512
|
||||
+#define FREC_HAS_EXTRADATA 512
|
||||
+#define FREC_HAS_PHEADER 1024
|
||||
|
||||
#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
struct frec {
|
||||
- union mysockaddr source;
|
||||
- union all_addr dest;
|
||||
+ struct frec_src {
|
||||
+ union mysockaddr source;
|
||||
+ union all_addr dest;
|
||||
+ unsigned int iface, log_id;
|
||||
+ unsigned short orig_id;
|
||||
+ struct frec_src *next;
|
||||
+ } frec_src;
|
||||
struct server *sentto; /* NULL means free */
|
||||
struct randfd *rfd4;
|
||||
struct randfd *rfd6;
|
||||
- unsigned int iface;
|
||||
- unsigned short orig_id, new_id;
|
||||
- int log_id, fd, forwardall, flags;
|
||||
+ unsigned short new_id;
|
||||
+ int fd, forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -1093,6 +1098,8 @@ extern struct daemon {
|
||||
int back_to_the_future;
|
||||
#endif
|
||||
struct frec *frec_list;
|
||||
+ struct frec_src *free_frec_src;
|
||||
+ int frec_src_count;
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
struct listener *listeners;
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 50da095..d9b32b3 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -20,6 +20,8 @@ static struct frec *lookup_frec(unsigned short id, int fd, int family, void *has
|
||||
static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
union mysockaddr *addr,
|
||||
void *hash);
|
||||
+static struct frec *lookup_frec_by_query(void *hash, unsigned int flags);
|
||||
+
|
||||
static unsigned short get_id(void);
|
||||
static void free_frec(struct frec *f);
|
||||
|
||||
@@ -255,6 +257,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
int type = SERV_DO_DNSSEC, norebind = 0;
|
||||
union all_addr *addrp = NULL;
|
||||
unsigned int flags = 0;
|
||||
+ unsigned int fwd_flags = 0;
|
||||
struct server *start = NULL;
|
||||
void *hash = hash_questions(header, plen, daemon->namebuff);
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -263,7 +266,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
(void)do_bit;
|
||||
-
|
||||
+
|
||||
+ if (header->hb4 & HB4_CD)
|
||||
+ fwd_flags |= FREC_CHECKING_DISABLED;
|
||||
+ if (ad_reqd)
|
||||
+ fwd_flags |= FREC_AD_QUESTION;
|
||||
+ if (oph)
|
||||
+ fwd_flags |= FREC_HAS_PHEADER;
|
||||
+#ifdef HAVE_DNSSEC
|
||||
+ if (do_bit)
|
||||
+ fwd_flags |= FREC_DO_QUESTION;
|
||||
+#endif
|
||||
+
|
||||
/* may be no servers available. */
|
||||
if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))
|
||||
{
|
||||
@@ -336,6 +350,39 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
else
|
||||
{
|
||||
+ /* Query from new source, but the same query may be in progress
|
||||
+ from another source. If so, just add this client to the
|
||||
+ list that will get the reply.
|
||||
+
|
||||
+ Note that is the EDNS client subnet option is in use, we can't do this,
|
||||
+ as the clients (and therefore query EDNS options) will be different
|
||||
+ for each query. The EDNS subnet code has checks to avoid
|
||||
+ attacks in this case. */
|
||||
+ if (!option_bool(OPT_CLIENT_SUBNET) && (forward = lookup_frec_by_query(hash, fwd_flags)))
|
||||
+ {
|
||||
+ /* Note whine_malloc() zeros memory. */
|
||||
+ if (!daemon->free_frec_src &&
|
||||
+ daemon->frec_src_count < daemon->ftabsize &&
|
||||
+ (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
||||
+ daemon->frec_src_count++;
|
||||
+
|
||||
+ /* If we've been spammed with many duplicates, just drop the query. */
|
||||
+ if (daemon->free_frec_src)
|
||||
+ {
|
||||
+ struct frec_src *new = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = new->next;
|
||||
+ new->next = forward->frec_src.next;
|
||||
+ forward->frec_src.next = new;
|
||||
+ new->orig_id = ntohs(header->id);
|
||||
+ new->source = *udpaddr;
|
||||
+ new->dest = *dst_addr;
|
||||
+ new->log_id = daemon->log_id;
|
||||
+ new->iface = dst_iface;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
@@ -343,22 +390,22 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
do_dnssec = type & SERV_DO_DNSSEC;
|
||||
#endif
|
||||
type &= ~SERV_DO_DNSSEC;
|
||||
-
|
||||
+
|
||||
if (daemon->servers && !flags)
|
||||
forward = get_new_frec(now, NULL, NULL);
|
||||
/* table full - flags == 0, return REFUSED */
|
||||
|
||||
if (forward)
|
||||
{
|
||||
- forward->source = *udpaddr;
|
||||
- forward->dest = *dst_addr;
|
||||
- forward->iface = dst_iface;
|
||||
- forward->orig_id = ntohs(header->id);
|
||||
+ forward->frec_src.source = *udpaddr;
|
||||
+ forward->frec_src.orig_id = ntohs(header->id);
|
||||
+ forward->frec_src.dest = *dst_addr;
|
||||
+ forward->frec_src.iface = dst_iface;
|
||||
forward->new_id = get_id();
|
||||
forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
forward->forwardall = 0;
|
||||
- forward->flags = 0;
|
||||
+ forward->flags = fwd_flags;
|
||||
if (norebind)
|
||||
forward->flags |= FREC_NOREBIND;
|
||||
if (header->hb4 & HB4_CD)
|
||||
@@ -413,9 +460,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
unsigned char *pheader;
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
- forward->log_id = daemon->log_id;
|
||||
+ forward->frec_src.log_id = daemon->log_id;
|
||||
|
||||
- plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
|
||||
+ plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet);
|
||||
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
@@ -552,7 +599,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
return 1;
|
||||
|
||||
/* could not send on, prepare to return */
|
||||
- header->id = htons(forward->orig_id);
|
||||
+ header->id = htons(forward->frec_src.orig_id);
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
|
||||
@@ -804,8 +851,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
/* log_query gets called indirectly all over the place, so
|
||||
pass these in global variables - sorry. */
|
||||
- daemon->log_display_id = forward->log_id;
|
||||
- daemon->log_source_addr = &forward->source;
|
||||
+ daemon->log_display_id = forward->frec_src.log_id;
|
||||
+ daemon->log_source_addr = &forward->frec_src.source;
|
||||
|
||||
if (daemon->ignore_addr && RCODE(header) == NOERROR &&
|
||||
check_for_ignored_address(header, n, daemon->ignore_addr))
|
||||
@@ -1080,6 +1127,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
new->sentto = server;
|
||||
new->rfd4 = NULL;
|
||||
new->rfd6 = NULL;
|
||||
+ new->frec_src.next = NULL;
|
||||
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
|
||||
new->forwardall = 0;
|
||||
|
||||
@@ -1215,9 +1263,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||
- forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||
+ forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
|
||||
{
|
||||
- header->id = htons(forward->orig_id);
|
||||
+ struct frec_src *src;
|
||||
+
|
||||
+ header->id = htons(forward->frec_src.orig_id);
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
|
||||
@@ -1233,13 +1283,26 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
#endif
|
||||
|
||||
+ for (src = &forward->frec_src; src; src = src->next)
|
||||
+ {
|
||||
+ header->id = htons(src->orig_id);
|
||||
+
|
||||
#ifdef HAVE_DUMPFILE
|
||||
- dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &forward->source);
|
||||
+ dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
|
||||
#endif
|
||||
-
|
||||
- send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
- &forward->source, &forward->dest, forward->iface);
|
||||
+
|
||||
+ send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
+ &src->source, &src->dest, src->iface);
|
||||
+
|
||||
+ if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
+ {
|
||||
+ daemon->log_display_id = src->log_id;
|
||||
+ daemon->log_source_addr = &src->source;
|
||||
+ log_query(F_UPSTREAM, "query", NULL, "duplicate");
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
}
|
||||
@@ -2202,6 +2265,17 @@ void free_rfd(struct randfd *rfd)
|
||||
|
||||
static void free_frec(struct frec *f)
|
||||
{
|
||||
+ struct frec_src *src, *tmp;
|
||||
+
|
||||
+ /* add back to freelist of not the record builtin to every frec. */
|
||||
+ for (src = f->frec_src.next; src; src = tmp)
|
||||
+ {
|
||||
+ tmp = src->next;
|
||||
+ src->next = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = src;
|
||||
+ }
|
||||
+
|
||||
+ f->frec_src.next = NULL;
|
||||
free_rfd(f->rfd4);
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
@@ -2342,17 +2416,39 @@ static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||
void *hash)
|
||||
{
|
||||
struct frec *f;
|
||||
+ struct frec_src *src;
|
||||
+
|
||||
+ for (f = daemon->frec_list; f; f = f->next)
|
||||
+ if (f->sentto &&
|
||||
+ !(f->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) &&
|
||||
+ memcmp(hash, f->hash, HASH_SIZE) == 0)
|
||||
+ for (src = &f->frec_src; src; src = src->next)
|
||||
+ if (src->orig_id == id &&
|
||||
+ sockaddr_isequal(&src->source, addr))
|
||||
+ return f;
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static struct frec *lookup_frec_by_query(void *hash, unsigned int flags)
|
||||
+{
|
||||
+ struct frec *f;
|
||||
+
|
||||
+ /* FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
||||
+ ensures that no frec created for internal DNSSEC query can be returned here. */
|
||||
+
|
||||
+#define FLAGMASK (FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION \
|
||||
+ | FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY)
|
||||
|
||||
for(f = daemon->frec_list; f; f = f->next)
|
||||
if (f->sentto &&
|
||||
- f->orig_id == id &&
|
||||
- memcmp(hash, f->hash, HASH_SIZE) == 0 &&
|
||||
- sockaddr_isequal(&f->source, addr))
|
||||
+ (f->flags & FLAGMASK) == flags &&
|
||||
+ memcmp(hash, f->hash, HASH_SIZE) == 0)
|
||||
return f;
|
||||
-
|
||||
+
|
||||
return NULL;
|
||||
}
|
||||
-
|
||||
+
|
||||
/* Send query packet again, if we can. */
|
||||
void resend_query()
|
||||
{
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
From 6a6e06fbb0d4690507ceaf2bb6f0d8910f3d4914 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Fri, 4 Dec 2020 18:35:11 +0000
|
||||
Subject: [PATCH] Small cleanups in frec_src datastucture handling.
|
||||
|
||||
---
|
||||
src/forward.c | 22 +++++++++++++---------
|
||||
1 file changed, 13 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index 70b84d7..f94c4cf 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -361,7 +361,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (!daemon->free_frec_src &&
|
||||
daemon->frec_src_count < daemon->ftabsize &&
|
||||
(daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
|
||||
- daemon->frec_src_count++;
|
||||
+ {
|
||||
+ daemon->frec_src_count++;
|
||||
+ daemon->free_frec_src->next = NULL;
|
||||
+ }
|
||||
|
||||
/* If we've been spammed with many duplicates, just drop the query. */
|
||||
if (daemon->free_frec_src)
|
||||
@@ -398,6 +401,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->frec_src.orig_id = ntohs(header->id);
|
||||
forward->frec_src.dest = *dst_addr;
|
||||
forward->frec_src.iface = dst_iface;
|
||||
+ forward->frec_src.next = NULL;
|
||||
forward->new_id = get_id();
|
||||
forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
@@ -2275,16 +2279,16 @@ void free_rfd(struct randfd *rfd)
|
||||
|
||||
static void free_frec(struct frec *f)
|
||||
{
|
||||
- struct frec_src *src, *tmp;
|
||||
-
|
||||
- /* add back to freelist of not the record builtin to every frec. */
|
||||
- for (src = f->frec_src.next; src; src = tmp)
|
||||
+ struct frec_src *last;
|
||||
+
|
||||
+ /* add back to freelist if not the record builtin to every frec. */
|
||||
+ for (last = f->frec_src.next; last && last->next; last = last->next) ;
|
||||
+ if (last)
|
||||
{
|
||||
- tmp = src->next;
|
||||
- src->next = daemon->free_frec_src;
|
||||
- daemon->free_frec_src = src;
|
||||
+ last->next = daemon->free_frec_src;
|
||||
+ daemon->free_frec_src = f->frec_src.next;
|
||||
}
|
||||
-
|
||||
+
|
||||
f->frec_src.next = NULL;
|
||||
free_rfd(f->rfd4);
|
||||
f->rfd4 = NULL;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
From 1eb6cedb03cb335071fda22ee7c623b2298d3729 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Date: Sat, 14 Nov 2020 15:29:34 +0000
|
||||
Subject: [PATCH] Fix DNS reply when asking for DNSSEC and a validated CNAME is
|
||||
already cached.
|
||||
|
||||
Conflict:NA
|
||||
Reference:https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=1eb6cedb03cb335071fda22ee7c623b2298d3729
|
||||
---
|
||||
src/rfc1035.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/rfc1035.c b/src/rfc1035.c
|
||||
index a8cdc6e..79af53f 100644
|
||||
--- a/src/rfc1035.c
|
||||
+++ b/src/rfc1035.c
|
||||
@@ -1359,6 +1359,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
}
|
||||
+ else
|
||||
+ return 0; /* give up if any cached CNAME in chain can't be used for DNSSEC reasons. */
|
||||
|
||||
strcpy(name, cname_target);
|
||||
}
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
From 3d113137fd64cd0723cbecab6a36a75d3ecfb0a6 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Harald=20Jens=C3=A5s?= <hjensas@redhat.com>
|
||||
Date: Thu, 7 May 2020 00:33:54 +0200
|
||||
Subject: [PATCH 1/1] Fix regression in s_config_in_context() method
|
||||
|
||||
Prior to commit 137286e9baecf6a3ba97722ef1b49c851b531810
|
||||
a config would not be considered in context if:
|
||||
a) it has no address family flags set
|
||||
b) it has the address family flag of current context set
|
||||
|
||||
Since above commit config is considered in context if the
|
||||
address family is the opposite of current context.
|
||||
|
||||
The result is that a config with two dhcp-host records,
|
||||
one for IPv6 and another for IPv4 no longer works, for
|
||||
example with the below config the config with the IPv6
|
||||
address would be considered in context for a DHCP(v4)
|
||||
request.
|
||||
dhcp-host=52:54:00:bc:c3:fd,172.20.0.11,host2
|
||||
dhcp-host=52:54:00:bc:c3:fd,[fd12:3456:789a:1::aadd],host2
|
||||
|
||||
This commit restores the previous behavior.
|
||||
|
||||
https://src.fedoraproject.org/rpms/dnsmasq/blob/master/f/dnsmasq-2.81-rh1834454.patch
|
||||
---
|
||||
src/dhcp-common.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
|
||||
index eae9886..ffc78ca 100644
|
||||
--- a/src/dhcp-common.c
|
||||
+++ b/src/dhcp-common.c
|
||||
@@ -280,14 +280,18 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
|
||||
{
|
||||
if (!context) /* called via find_config() from lease_update_from_configs() */
|
||||
return 1;
|
||||
-
|
||||
+
|
||||
+ /* No address present in config == in context */
|
||||
+ if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
|
||||
+ return 1;
|
||||
+
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_V6)
|
||||
{
|
||||
struct addrlist *addr_list;
|
||||
|
||||
if (!(config->flags & CONFIG_ADDR6))
|
||||
- return 1;
|
||||
+ return 0;
|
||||
|
||||
for (; context; context = context->current)
|
||||
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
||||
@@ -303,7 +307,7 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
|
||||
#endif
|
||||
{
|
||||
if (!(config->flags & CONFIG_ADDR))
|
||||
- return 1;
|
||||
+ return 0;
|
||||
|
||||
for (; context; context = context->current)
|
||||
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
|
||||
@ -31,12 +31,12 @@ index 68e6287..e7f1a0d 100644
|
||||
--- a/src/dnsmasq.h
|
||||
+++ b/src/dnsmasq.h
|
||||
@@ -269,7 +269,8 @@ struct event_desc {
|
||||
#define OPT_IGNORE_CLID 59
|
||||
#define OPT_SINGLE_PORT 60
|
||||
#define OPT_LEASE_RENEW 61
|
||||
-#define OPT_LAST 62
|
||||
+#define OPT_BIND_MAC_IP6 62
|
||||
+#define OPT_LAST 63
|
||||
#define OPT_LOG_DEBUG 62
|
||||
-#define OPT_LAST 63
|
||||
+#define OPT_BIND_MAC_IP6 63
|
||||
+#define OPT_LAST 64
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@ -53,19 +53,19 @@ index 1f698da..f02d389 100644
|
||||
--- a/src/option.c
|
||||
+++ b/src/option.c
|
||||
@@ -167,7 +167,8 @@ struct myoption {
|
||||
#define LOPT_IGNORE_CLID 358
|
||||
#define LOPT_SINGLE_PORT 359
|
||||
#define LOPT_SCRIPT_TIME 360
|
||||
#define LOPT_PXE_VENDOR 361
|
||||
#define LOPT_DYNHOST 362
|
||||
#define LOPT_LOG_DEBUG 363
|
||||
-
|
||||
+#define LOPT_BIND_MAC_IP6 361
|
||||
+#define LOPT_BIND_MAC_IP6 364
|
||||
+
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
#else
|
||||
@@ -339,6 +340,7 @@ static const struct myoption opts[] =
|
||||
{ "dumpfile", 1, 0, LOPT_DUMPFILE },
|
||||
{ "dumpmask", 1, 0, LOPT_DUMPMASK },
|
||||
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
|
||||
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
|
||||
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
|
||||
+ { "bind-mac-with-ip6", 0, 0 , LOPT_BIND_MAC_IP6 },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
Binary file not shown.
BIN
dnsmasq-2.85.tar.xz
Normal file
BIN
dnsmasq-2.85.tar.xz
Normal file
Binary file not shown.
26
dnsmasq.spec
26
dnsmasq.spec
@ -1,6 +1,6 @@
|
||||
Name: dnsmasq
|
||||
Version: 2.82
|
||||
Release: 9
|
||||
Version: 2.85
|
||||
Release: 1
|
||||
Summary: Dnsmasq provides network infrastructure for small networks
|
||||
License: GPLv2 or GPLv3
|
||||
URL: http://www.thekelleys.org.uk/dnsmasq/
|
||||
@ -12,26 +12,7 @@ Patch1: dnsmasq-2.77-underflow.patch
|
||||
Patch2: dnsmasq-2.78-fips.patch
|
||||
Patch3: bugfix-allow-binding-mac-with-ipv6.patch
|
||||
Patch4: bugfix-deal-with-CONFRIM-when-binding-mac-with-ipv6.patch
|
||||
Patch5: backport-CVE-2020-25681_CVE-2020-25682_CVE-2020-25683_CVE-2020-25687.patch
|
||||
Patch6: backport-CVE-2020-25684.patch
|
||||
Patch7: backport-CVE-2020-25685_1.patch
|
||||
Patch8: backport-CVE-2020-25685_2.patch
|
||||
Patch9: backport-CVE-2020-25686_1.patch
|
||||
Patch10: backport-CVE-2020-25686_2.patch
|
||||
Patch11: backport-fix-regression-in-s_config_in_context-method.patch
|
||||
Patch12: backport-Add-missing-check-for-NULL-return-from-allocate_rfd.patch
|
||||
Patch13: backport-Fix-DNS-reply-when-asking-for-DNSSEC-and-a-validated.patch
|
||||
Patch14: backport-Handle-DHCPREBIND-requests-in-the-DHCPv6-server.patch
|
||||
Patch15: backport-0001-Handle-caching-with-EDNS-options-better.patch
|
||||
Patch16: backport-0002-Fix-to-75e2f0aec33e58ef5b8d4d107d821c215a52827c.patch
|
||||
Patch17: backport-0003-Fix-for-12af2b171de0d678d98583e2190789e544440e02.patch
|
||||
Patch18: backport-0004-Fix-problem-with-DNS-retries-in-2.83-2.84.patch
|
||||
Patch19: backport-0005-Simplify-preceding-fix.patch
|
||||
Patch20: backport-0006-Update-to-new-struct-frec-fields-in-conntrack-code.patch
|
||||
Patch21: backport-0007-Use-the-values-of-min-port-and-max-port-in-TCP-conne.patch
|
||||
Patch22: backport-0008-Correct-occasional-bind-dynamic-synchronization-brea.patch
|
||||
Patch23: backport-0009-Move-fd-into-frec_src-fixes-15b60ddf935a531269bb8c68.patch
|
||||
Patch24: backport-0010-CVE-2021-3448.patch
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: dbus-devel pkgconfig libidn2-devel nettle-devel systemd
|
||||
@ -125,6 +106,9 @@ install -Dpm644 %{SOURCE2} $RPM_BUILD_ROOT%{_sysusersdir}/dnsmasq.conf
|
||||
%{_mandir}/man8/dnsmasq*
|
||||
|
||||
%changelog
|
||||
* Wed Jul 14 2021 gaihuiying <gaihuiying1@huawei.com> - 2.85-1
|
||||
- update dnsmasq to 2.85
|
||||
|
||||
* Wed May 26 2021 liuyumeng <liuyumeng5@huawei.com> - 2.82-9
|
||||
- Add a BuildRequires for gcc
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user