Compare commits

...

No commits in common. "c8" and "c10s" have entirely different histories.
c8 ... c10s

63 changed files with 783 additions and 11258 deletions

View File

@ -1 +0,0 @@
d4a1af08b02b27736954ce8b2db2da7799d75812 SOURCES/dnsmasq-2.79.tar.xz

1
.fmf/version Normal file
View File

@ -0,0 +1 @@
1

55
.gitignore vendored
View File

@ -1 +1,54 @@
SOURCES/dnsmasq-2.79.tar.xz
dnsmasq-2.52.tar.lzma
/dnsmasq-2.58.tar.lzma
/dnsmasq-2.59.tar.lzma
/dnsmasq-2.63.tar.gz
/dnsmasq-2.64.tar.gz
/dnsmasq-2.65.tar.gz
/dnsmasq-2.66rc1.tar.gz
/dnsmasq-2.66rc5.tar.gz
/dnsmasq-2.66.tar.gz
/dnsmasq-2.67test4.tar.gz
/dnsmasq-2.67test7.tar.gz
/dnsmasq-2.67test13.tar.xz
/dnsmasq-2.67test16.tar.xz
/dnsmasq-2.67rc2.tar.xz
/dnsmasq-2.67rc4.tar.xz
/dnsmasq-2.67.tar.xz
/dnsmasq-2.68rc3.tar.xz
/dnsmasq-2.68.tar.xz
/dnsmasq-2.69rc1.tar.xz
/dnsmasq-2.69.tar.xz
/dnsmasq-2.70.tar.xz
/dnsmasq-2.71.tar.xz
/dnsmasq-2.72.tar.xz
/dnsmasq-2.75.tar.xz
/dnsmasq-2.76.tar.xz
/dnsmasq-2.77rc2.tar.xz
/dnsmasq-2.77.tar.xz
/dnsmasq-2.78.tar.xz
/dnsmasq-2.79.tar.xz
/dnsmasq-2.80.tar.xz
/dnsmasq-2.81rc3.tar.xz
/dnsmasq-2.81rc3.tar.xz.asc
/dnsmasq-2.81.tar.xz
/dnsmasq-2.81.tar.xz.asc
/dnsmasq-2.82.tar.xz
/dnsmasq-2.82.tar.xz.asc
/dnsmasq-2.83.tar.xz
/dnsmasq-2.83.tar.xz.asc
/dnsmasq-2.84.tar.xz
/dnsmasq-2.84.tar.xz.asc
/dnsmasq-2.85rc2.tar.xz
/dnsmasq-2.85rc2.tar.xz.asc
/dnsmasq-2.85.tar.xz
/dnsmasq-2.85.tar.xz.asc
/dnsmasq-2.86.tar.xz
/dnsmasq-2.86.tar.xz.asc
/dnsmasq-2.87.tar.xz
/dnsmasq-2.87.tar.xz.asc
/dnsmasq-2.88.tar.xz
/dnsmasq-2.88.tar.xz.asc
/dnsmasq-2.89.tar.xz
/dnsmasq-2.89.tar.xz.asc
/dnsmasq-2.90.tar.xz
/dnsmasq-2.90.tar.xz.asc

View File

@ -1,52 +0,0 @@
From cae343c1f3bea9d1ca2e71d3709d3f02b799f94d Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Thu, 4 Jul 2019 20:28:08 +0200
Subject: [PATCH 1/5] Log listening on new interfaces
Log in debug mode listening on interfaces. They can be dynamically
found, include interface number, since it is checked on TCP connections.
Print also addresses found on them.
---
src/network.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/network.c b/src/network.c
index d75f560..fd90288 100644
--- a/src/network.c
+++ b/src/network.c
@@ -662,6 +662,13 @@ int enumerate_interfaces(int reset)
else
{
*up = l->next;
+ if (l->iface->done)
+ {
+ iface = l->iface;
+ (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
+ my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
+ iface->name, iface->index, daemon->addrbuff);
+ }
/* In case it ever returns */
l->iface->done = 0;
@@ -978,6 +985,9 @@ void create_bound_listeners(int dienow)
new->next = daemon->listeners;
daemon->listeners = new;
iface->done = 1;
+ (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
+ my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
+ iface->name, iface->index, daemon->addrbuff);
}
/* Check for --listen-address options that haven't been used because there's
@@ -997,6 +1007,8 @@ void create_bound_listeners(int dienow)
{
new->next = daemon->listeners;
daemon->listeners = new;
+ (void)prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
+ my_syslog(LOG_DEBUG, _("listening on %s"), daemon->addrbuff);
}
}
--
2.20.1

View File

@ -1,74 +0,0 @@
From 527029312cbe37c0285240943ad02352d64d403d Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Tue, 9 Jul 2019 14:05:59 +0200
Subject: [PATCH 3/5] Cleanup interfaces no longer available
Clean addresses and interfaces not found after enumerate. Free unused
records to speed up checking active interfaces and reduce used memory.
---
src/network.c | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/src/network.c b/src/network.c
index f247811..d6d4b01 100644
--- a/src/network.c
+++ b/src/network.c
@@ -553,7 +553,30 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
}
-
+
+/*
+ * Clean old interfaces no longer found.
+ */
+static void clean_interfaces()
+{
+ struct irec *iface;
+ struct irec **up = &daemon->interfaces;
+
+ for (iface = *up; iface; iface = *up)
+ {
+ if (!iface->found && !iface->done)
+ {
+ *up = iface->next;
+ free(iface->name);
+ free(iface);
+ }
+ else
+ {
+ up = &iface->next;
+ }
+ }
+}
+
int enumerate_interfaces(int reset)
{
static struct addrlist *spare = NULL;
@@ -653,6 +676,7 @@ int enumerate_interfaces(int reset)
in OPT_CLEVERBIND mode, that at listener will just disappear after
a call to enumerate_interfaces, this is checked OK on all calls. */
struct listener *l, *tmp, **up;
+ int freed = 0;
for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
{
@@ -682,10 +706,14 @@ int enumerate_interfaces(int reset)
close(l->tftpfd);
free(l);
+ freed = 1;
}
}
+
+ if (freed)
+ clean_interfaces();
}
-
+
errno = errsave;
spare = param.spare;
--
2.20.1

View File

@ -1,75 +0,0 @@
From 3d27384fc5f2a437b7bce128c8ba62e8d6e12df7 Mon Sep 17 00:00:00 2001
From: Brian Haley <haleyb.dev@gmail.com>
Date: Wed, 28 Aug 2019 16:13:23 -0400
Subject: [PATCH] Change dhcp_release to use default address when no IP subnet
matches
Currently, dhcp_release will only send a 'fake' release
when the address given is in the same subnet as an IP
on the interface that was given.
This doesn't work in an environment where dnsmasq is
managing leases for remote subnets via a DHCP relay, as
running dhcp_release locally will just cause it to
silently exit without doing anything, leaving the lease
in the database.
Change it to use the default IP on the interface, as the
dnsmasq source code at src/dhcp.c does, if no matching subnet
IP is found, as a fall-back. This fixes an issue we are
seeing in certain Openstack deployments where we are using
dnsmasq to provision baremetal systems in a datacenter.
While using Dbus might have seemed like an obvious solution,
because of our extensive use of network namespaces (which
Dbus doesn't support), this seemed like a better solution
than creating system.d policy files for each dnsmasq we
might spawn and using --enable-dbus=$id in order to isolate
messages to specific dnsmasq instances.
Signed-off-by: Brian Haley <haleyb.dev@gmail.com>
(cherry picked from commit d9f882bea2806799bf3d1f73937f5e72d0bfc650)
---
contrib/lease-tools/dhcp_release.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/contrib/lease-tools/dhcp_release.c b/contrib/lease-tools/dhcp_release.c
index a51f04b..1dd8d32 100644
--- a/contrib/lease-tools/dhcp_release.c
+++ b/contrib/lease-tools/dhcp_release.c
@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
}
-static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
+static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index, int ifrfd, struct ifreq *ifr)
{
struct sockaddr_nl addr;
struct nlmsghdr *h;
@@ -218,7 +218,13 @@ static struct in_addr find_interface(struct in_addr client, int fd, unsigned int
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_type == NLMSG_DONE)
- exit(0);
+ {
+ /* No match found, return first address as src/dhcp.c code does */
+ ifr->ifr_addr.sa_family = AF_INET;
+ if (ioctl(ifrfd, SIOCGIFADDR, ifr) != -1)
+ return ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
+ exit(0);
+ }
else if (h->nlmsg_type == RTM_NEWADDR)
{
struct ifaddrmsg *ifa = NLMSG_DATA(h);
@@ -284,7 +290,7 @@ int main(int argc, char **argv)
}
lease.s_addr = inet_addr(argv[2]);
- server = find_interface(lease, nl, if_nametoindex(argv[1]));
+ server = find_interface(lease, nl, if_nametoindex(argv[1]), fd, &ifr);
memset(&packet, 0, sizeof(packet));
--
2.20.1

View File

@ -1,63 +0,0 @@
From c82a594d95431e8615126621397ea595eb037a6b Mon Sep 17 00:00:00 2001
From: Doran Moppert <dmoppert@redhat.com>
Date: Tue, 26 Sep 2017 14:48:20 +0930
Subject: [PATCH] google patch hand-applied
---
src/edns0.c | 10 +++++-----
src/forward.c | 4 ++++
src/rfc1035.c | 2 ++
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/src/edns0.c b/src/edns0.c
index af33877..ba6ff0c 100644
--- a/src/edns0.c
+++ b/src/edns0.c
@@ -212,11 +212,11 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
/* Copy back any options */
if (buff)
{
- if (p + rdlen > limit)
- {
- free(buff);
- return plen; /* Too big */
- }
+ if (p + rdlen > limit)
+ {
+ free(buff);
+ return plen; /* Too big */
+ }
memcpy(p, buff, rdlen);
free(buff);
p += rdlen;
diff --git a/src/forward.c b/src/forward.c
index cdd11d3..3078f64 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -1438,6 +1438,10 @@ void receive_query(struct listener *listen, time_t now)
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
}
+ // Make sure the udp size is not smaller than the incoming message so that we
+ // do not underflow
+ if (udp_size < n) udp_size = n;
+
#ifdef HAVE_AUTH
if (auth_dns)
{
diff --git a/src/rfc1035.c b/src/rfc1035.c
index b078b59..777911b 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1281,6 +1281,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
struct mx_srv_record *rec;
size_t len;
+ // Make sure we do not underflow here too.
+ if (qlen > (limit - ((char *)header))) return 0;
if (ntohs(header->ancount) != 0 ||
ntohs(header->nscount) != 0 ||
--
2.14.3

View File

@ -1,364 +0,0 @@
From 6689e336042d2ca0b075f8db1fe30ed6b47c7d4c 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 1/4] 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 file changed, 152 insertions(+), 121 deletions(-)
diff --git a/src/dnssec.c b/src/dnssec.c
index 8143185..0c703ac 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -222,138 +222,147 @@ static int check_date_range(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);
@@ -549,15 +558,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;
@@ -566,12 +578,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++;
}
@@ -592,24 +603,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);
--
2.26.2

View File

@ -1,94 +0,0 @@
From 04ef96f428beebd07b457b51b5d2f26d3099f1a5 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 2/4] 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 file changed, 28 insertions(+), 9 deletions(-)
diff --git a/src/forward.c b/src/forward.c
index cdd11d3..85eab27 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);
@@ -780,7 +780,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;
/* log_query gets called indirectly all over the place, so
@@ -2195,14 +2195,25 @@ struct frec *get_new_frec(time_t now, int *wait, int 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;
}
@@ -2263,12 +2274,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;
+ }
}
--
2.26.2

View File

@ -1,586 +0,0 @@
From 6cbbae54c9232f182cc76f05962a07244d748b75 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 3/4] 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 | 3 +-
src/dnsmasq.h | 11 +-
src/dnssec.c | 31 -----
src/forward.c | 43 ++-----
src/hash_questions.c | 281 +++++++++++++++++++++++++++++++++++++++++++
src/rfc1035.c | 49 --------
7 files changed, 297 insertions(+), 124 deletions(-)
create mode 100644 src/hash_questions.c
diff --git a/Makefile b/Makefile
index 98ec760..cbbe5d7 100644
--- a/Makefile
+++ b/Makefile
@@ -76,7 +76,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
+ poll.o rrfilter.o edns0.o arp.o crypto.o \
+ hash_questions.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h
diff --git a/bld/Android.mk b/bld/Android.mk
index 80ec842..2db29c1 100644
--- a/bld/Android.mk
+++ b/bld/Android.mk
@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
- loop.c inotify.c poll.c rrfilter.c edns0.c arp.c crypto.c
+ loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
+ crypto.c hash_questions.c
LOCAL_MODULE := dnsmasq
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 6773b69..f31503d 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -615,11 +615,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;
@@ -1156,7 +1152,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,
@@ -1184,9 +1179,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
int check_unsigned, int *neganswer, int *nons);
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 0c703ac..b2dda1b 100644
--- a/src/dnssec.c
+++ b/src/dnssec.c
@@ -2095,35 +2095,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 85eab27..7ffcaf7 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -239,19 +239,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct 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);
(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.
@@ -741,9 +738,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;
@@ -773,12 +767,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;
@@ -1006,8 +995,7 @@ void reply_query(int fd, int family, time_t now)
nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
}
- 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 */
@@ -1840,15 +1828,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. */
@@ -1973,20 +1955,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,
@@ -2201,7 +2174,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 b078b59..d413f58 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -335,55 +335,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);
--
2.26.2

View File

@ -1,61 +0,0 @@
From e9db3fdf55cdf3175d96db90313c33f848985960 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 25ad8b1..c496f86 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -364,7 +364,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)
@@ -401,6 +404,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);
@@ -2262,16 +2266,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;
--
2.26.2

View File

@ -1,327 +0,0 @@
From 7d98347aeeb575a022ffae630ee02da215b6f37b 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 4/4] 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 | 141 ++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 132 insertions(+), 28 deletions(-)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index f31503d..6744e2b 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -613,21 +613,26 @@ 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;
- struct all_addr dest;
+ struct frec_src {
+ union mysockaddr source;
+ struct 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;
#ifdef HAVE_IPV6
struct randfd *rfd6;
#endif
- 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
@@ -1033,6 +1038,8 @@ extern struct daemon {
#endif
unsigned int local_answer, queries_forwarded, auth_answer;
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 7ffcaf7..db378a5 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);
@@ -238,15 +240,28 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
int type = SERV_DO_DNSSEC, norebind = 0;
struct 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
int do_dnssec = 0;
#endif
- unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
+ 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)))
{
@@ -322,6 +337,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);
@@ -329,22 +377,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, 0);
/* 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)
@@ -400,9 +448,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;
@@ -539,7 +587,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 */
}
@@ -774,8 +822,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))
@@ -978,6 +1026,7 @@ void reply_query(int fd, int family, time_t now)
#ifdef HAVE_IPV6
new->rfd6 = NULL;
#endif
+ new->frec_src.next = NULL;
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
new->dependent = forward; /* to find query awaiting new one. */
@@ -1099,9 +1148,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
@@ -1116,9 +1167,22 @@ void reply_query(int fd, int family, time_t now)
nn = resize_packet(header, nn, NULL, 0);
}
#endif
- send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
- &forward->source, &forward->dest, forward->iface);
+ for (src = &forward->frec_src; src; src = src->next)
+ {
+ header->id = htons(src->orig_id);
+
+ 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 */
}
}
@@ -2053,6 +2117,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;
@@ -2196,17 +2271,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()
{
--
2.26.2

View File

@ -1,107 +0,0 @@
From 268080fc19990711a1d1e1acd68a50aa2f6cb5fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Fri, 17 Sep 2021 20:12:21 +0200
Subject: [PATCH] Offer alternative DHCPv6 address if requested is taken
In some cases multiple requests might arrive from single DUID. It may
happen just one address is offered to different IAID requests. When
the first request confirms lease, another would be offered alternative
address instead of address in use error.
Includes check on such Rapid commit equivalents and returns NotOnLink
error, required by RFC 8145, if requested address were not on any
supported prefix.
---
src/rfc3315.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 5c2ff97..d1534ad 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -614,7 +614,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
case DHCP6SOLICIT:
{
- int address_assigned = 0;
+ int address_assigned = 0, ia_invalid = 0;
/* tags without all prefix-class tags */
struct dhcp_netid *solicit_tags;
struct dhcp_context *c;
@@ -697,6 +697,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
get_context_tag(state, c);
address_assigned = 1;
}
+ else
+ ia_invalid++;
}
/* Suggest configured address(es) */
@@ -782,11 +784,26 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
tagif = add_options(state, 0);
}
else
- {
+ {
+ char *errmsg;
/* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
- put_opt6_short(DHCP6NOADDRS);
- put_opt6_string(_("no addresses available"));
+ if (state->lease_allocate && ia_invalid)
+ {
+ /* RFC 8415, Section 18.3.2:
+ If any of the prefixes of the included addresses are not
+ appropriate for the link to which the client is connected,
+ the server MUST return the IA to the client with a Status
+ Code option with the value NotOnLink. */
+ put_opt6_short(DHCP6NOTONLINK);
+ errmsg = _("not on link");
+ }
+ else
+ {
+ put_opt6_short(DHCP6NOADDRS);
+ errmsg = _("no addresses available");
+ }
+ put_opt6_string(errmsg);
end_opt6(o1);
/* Some clients will ask repeatedly when we're not giving
@@ -795,7 +812,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (c = state->context; c; c = c->current)
if (!(c->flags & CONTEXT_RA_STATELESS))
{
- log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
+ log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, errmsg);
break;
}
}
@@ -831,7 +848,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
/* If we get a request with an IA_*A without addresses, treat it exactly like
a SOLICT with rapid commit set. */
save_counter(start);
- goto request_no_address;
+ goto request_no_address;
}
o = build_ia(state, &t1cntr);
@@ -861,11 +878,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
else if (!check_address(state, &req_addr))
{
- /* Address leased to another DUID/IAID */
- o1 = new_opt6(OPTION6_STATUS_CODE);
- put_opt6_short(DHCP6UNSPEC);
- put_opt6_string(_("address in use"));
- end_opt6(o1);
+ /* Address leased to another DUID/IAID.
+ Find another address for the client, treat it exactly like
+ a SOLICT with rapid commit set. */
+ save_counter(start);
+ goto request_no_address;
}
else
{
--
2.31.1

View File

@ -1,79 +0,0 @@
From 4348c43be45d20aba87ee5564ecdde10aff7e5e7 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.
(cherry picked from commit 04490bf622ac84891aad6f2dd2edf83725decdee)
Fix for 12af2b171de0d678d98583e2190789e544440e02
(cherry picked from commit 3f535da79e7a42104543ef5c7b5fa2bed819a78b)
---
src/dnsmasq.h | 3 ++-
src/forward.c | 5 +++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index f3bbb4e..e7e1693 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -632,6 +632,7 @@ struct frec {
union mysockaddr source;
struct all_addr dest;
unsigned int iface, log_id;
+ int fd;
unsigned short orig_id;
struct frec_src *next;
} frec_src;
@@ -641,7 +642,7 @@ struct frec {
struct randfd *rfd6;
#endif
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 9d249c0..82dd850 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -368,6 +368,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
new->dest = *dst_addr;
new->log_id = daemon->log_id;
new->iface = dst_iface;
+ new->fd = udpfd;
}
return 1;
@@ -392,8 +393,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;
@@ -1175,7 +1176,7 @@ void reply_query(int fd, int family, time_t now)
{
header->id = htons(src->orig_id);
- 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)
--
2.26.2

View File

@ -1,49 +0,0 @@
From dcb4fa04548ab2364f662b735be86e275bd50745 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Fri, 19 Jul 2019 14:00:08 +0200
Subject: [PATCH] Remove warnings in coverity
Change in dnsmasq should never occur, because ent_pw would not change.
But keep Coverity happy and prevent logic error. Second change avoids
warning from compiler.
---
src/dnsmasq.c | 9 ++++++++-
src/option.c | 2 +-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index ce44809..2984f55 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -608,7 +608,14 @@ int main (int argc, char **argv)
if (ent_pw && ent_pw->pw_uid != 0)
{
-#if defined(HAVE_LINUX_NETWORK)
+#if defined(HAVE_LINUX_NETWORK)
+ if (!hdr || !data)
+ {
+ /* Just failsafe for logic errors */
+ send_event(err_pipe[1], EVENT_CAP_ERR, ENOMEM, NULL);
+ _exit(0);
+ }
+
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
ports because of DAD, or we're doing it dynamically,
diff --git a/src/option.c b/src/option.c
index 9768efb..b12183b 100644
--- a/src/option.c
+++ b/src/option.c
@@ -4255,7 +4255,7 @@ err:
struct name_list *nl;
if (!canon)
{
- struct name_list *tmp = new->names, *next;
+ struct name_list *tmp, *next;
for (tmp = new->names; tmp; tmp = next)
{
next = tmp->next;
--
2.20.1

File diff suppressed because it is too large Load Diff

View File

@ -1,95 +0,0 @@
From 10642f9fb350e118d88e995b8dfa2badc7be1c30 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Wed, 11 Dec 2019 13:41:57 +0100
Subject: [PATCH] Restore ability to answer non-recursive requests
Instead, check only local configured entries are answered without
rdbit set. All cached replies are still denied, but locally configured
names are available with both recursion and without it.
---
src/rfc1035.c | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 6b3bb27..6a7c154 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1262,7 +1262,11 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
else
return daemon->max_ttl;
}
-
+
+static int cache_validated(const struct crec *crecp)
+{
+ return (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK));
+}
/* return zero if we can't answer from cache, or packet size if we can */
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
@@ -1281,6 +1285,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
struct mx_srv_record *rec;
size_t len;
+ int rd_bit;
// Make sure we do not underflow here too.
if (qlen > (limit - ((char *)header))) return 0;
@@ -1290,10 +1295,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
OPCODE(header) != QUERY )
return 0;
- /* always servfail queries with RD unset, to avoid cache snooping. */
- if (!(header->hb3 & HB3_RD))
- return setup_reply(header, qlen, NULL, F_SERVFAIL, 0);
-
+ rd_bit = (header->hb3 & HB3_RD);
+
/* Don't return AD set if checking disabled. */
if (header->hb4 & HB4_CD)
sec_data = 0;
@@ -1458,9 +1461,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* Don't use cache when DNSSEC data required, unless we know that
the zone is unsigned, which implies that we're doing
validation. */
- if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
- !do_bit ||
- (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
+ (rd_bit && (!do_bit || cache_validated(crecp)) ))
{
do
{
@@ -1657,8 +1659,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* If the client asked for DNSSEC don't use cached data. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
- !do_bit ||
- (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
+ (rd_bit && (!do_bit || cache_validated(crecp)) ))
do
{
/* don't answer wildcard queries with data not from /etc/hosts
@@ -1741,8 +1742,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (qtype == T_CNAME || qtype == T_ANY)
{
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
- (qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
- ((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
+ ((qtype == T_CNAME && rd_bit) || (crecp->flags & F_CONFIG)) &&
+ ((crecp->flags & F_CONFIG) || (!do_bit || cache_validated(crecp))))
{
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
@@ -1780,7 +1781,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
}
- if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
+ if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
{
ans = 1;
--
2.21.0

View File

@ -1,48 +0,0 @@
From 7e3250d52921b5f75bdbe0b794514bb78a209969 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Wed, 3 Jul 2019 17:02:16 +0200
Subject: [PATCH 2/5] Compare address and interface index for allowed interface
If interface is recreated with the same address but different index, it
would not change any other parameter.
Test also address family on incoming TCP queries.
---
src/dnsmasq.c | 3 ++-
src/network.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index f3d2671..7812be8 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -1667,7 +1667,8 @@ static void check_dns_listeners(time_t now)
#endif
for (iface = daemon->interfaces; iface; iface = iface->next)
- if (iface->index == if_index)
+ if (iface->index == if_index &&
+ iface->addr.sa.sa_family == tcp_addr.sa.sa_family)
break;
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
diff --git a/src/network.c b/src/network.c
index fd90288..f247811 100644
--- a/src/network.c
+++ b/src/network.c
@@ -404,10 +404,11 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
/* check whether the interface IP has been added already
we call this routine multiple times. */
for (iface = daemon->interfaces; iface; iface = iface->next)
- if (sockaddr_isequal(&iface->addr, addr))
+ if (sockaddr_isequal(&iface->addr, addr) && iface->index == if_index)
{
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
iface->found = 1; /* for garbage collection */
+ iface->netmask = netmask;
return 1;
}
--
2.20.1

View File

@ -1,188 +0,0 @@
From 11ab42e63f9089c4c14a391f30175d4c2d071e99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Mon, 15 Jul 2019 17:13:12 +0200
Subject: [PATCH 4/5] Handle listening on duplicate addresses
Save listening address into listener. Use it to find existing listeners
before creating new one. If it exist, increase just used counter.
Release only listeners not already used.
Duplicates family in listener.
---
src/dnsmasq.h | 3 +-
src/network.c | 115 ++++++++++++++++++++++++++++++++++++--------------
2 files changed, 85 insertions(+), 33 deletions(-)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 89d138a..3b3f6ef 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -552,7 +552,8 @@ struct irec {
};
struct listener {
- int fd, tcpfd, tftpfd, family;
+ int fd, tcpfd, tftpfd, family, used;
+ union mysockaddr addr;
struct irec *iface; /* only sometimes valid for non-wildcard */
struct listener *next;
};
diff --git a/src/network.c b/src/network.c
index d6d4b01..4bbd810 100644
--- a/src/network.c
+++ b/src/network.c
@@ -577,6 +577,56 @@ static void clean_interfaces()
}
}
+/** Release listener if no other interface needs it.
+ *
+ * @return 1 if released, 0 if still required
+ */
+static int release_listener(struct listener *l)
+{
+ if (l->used > 1)
+ {
+ struct irec *iface;
+ for (iface = daemon->interfaces; iface; iface = iface->next)
+ if (iface->done && sockaddr_isequal(&l->addr, &iface->addr))
+ {
+ if (iface->found)
+ {
+ /* update listener to point to active interface instead */
+ if (!l->iface->found)
+ l->iface = iface;
+ }
+ else
+ {
+ l->used--;
+ iface->done = 0;
+ }
+ }
+
+ /* Someone is still using this listener, skip its deletion */
+ if (l->used > 0)
+ return 0;
+ }
+
+ if (l->iface->done)
+ {
+ (void)prettyprint_addr(&l->iface->addr, daemon->addrbuff);
+ my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
+ l->iface->name, l->iface->index, daemon->addrbuff);
+ /* In case it ever returns */
+ l->iface->done = 0;
+ }
+
+ if (l->fd != -1)
+ close(l->fd);
+ if (l->tcpfd != -1)
+ close(l->tcpfd);
+ if (l->tftpfd != -1)
+ close(l->tftpfd);
+
+ free(l);
+ return 1;
+}
+
int enumerate_interfaces(int reset)
{
static struct addrlist *spare = NULL;
@@ -684,29 +734,10 @@ int enumerate_interfaces(int reset)
if (!l->iface || l->iface->found)
up = &l->next;
- else
+ else if (release_listener(l))
{
- *up = l->next;
- if (l->iface->done)
- {
- iface = l->iface;
- (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
- my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s"),
- iface->name, iface->index, daemon->addrbuff);
- }
-
- /* In case it ever returns */
- l->iface->done = 0;
-
- if (l->fd != -1)
- close(l->fd);
- if (l->tcpfd != -1)
- close(l->tcpfd);
- if (l->tftpfd != -1)
- close(l->tftpfd);
-
- free(l);
- freed = 1;
+ *up = tmp;
+ freed = 1;
}
}
@@ -959,7 +990,9 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
l->family = addr->sa.sa_family;
l->fd = fd;
l->tcpfd = tcpfd;
- l->tftpfd = tftpfd;
+ l->tftpfd = tftpfd;
+ l->addr = *addr;
+ l->used = 1;
l->iface = NULL;
}
@@ -1000,23 +1033,41 @@ void create_wildcard_listeners(void)
daemon->listeners = l;
}
+static struct listener *find_listener(union mysockaddr *addr)
+{
+ struct listener *l;
+ for (l = daemon->listeners; l; l = l->next)
+ if (sockaddr_isequal(&l->addr, addr))
+ return l;
+ return NULL;
+}
+
void create_bound_listeners(int dienow)
{
struct listener *new;
struct irec *iface;
struct iname *if_tmp;
+ struct listener *existing;
for (iface = daemon->interfaces; iface; iface = iface->next)
- if (!iface->done && !iface->dad && iface->found &&
- (new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
+ if (!iface->done && !iface->dad && iface->found)
{
- new->iface = iface;
- new->next = daemon->listeners;
- daemon->listeners = new;
- iface->done = 1;
- (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
- my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
- iface->name, iface->index, daemon->addrbuff);
+ existing = find_listener(&iface->addr);
+ if (existing)
+ {
+ iface->done = 1;
+ existing->used++; /* increase usage counter */
+ }
+ else if ((new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
+ {
+ new->iface = iface;
+ new->next = daemon->listeners;
+ daemon->listeners = new;
+ iface->done = 1;
+ (void)prettyprint_addr(&iface->addr, daemon->addrbuff);
+ my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s"),
+ iface->name, iface->index, daemon->addrbuff);
+ }
}
/* Check for --listen-address options that haven't been used because there's
--
2.20.1

View File

@ -1,22 +0,0 @@
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Wed, 14 Aug 2019 20:52:50 +0000 (+0100)
Subject: Fix breakage of dhcp_lease_time utility.
X-Git-Url: http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commitdiff_plain;h=225accd235a09413ca253e710d7d691a3475c523
Fix breakage of dhcp_lease_time utility.
---
diff --git a/contrib/lease-tools/dhcp_lease_time.c b/contrib/lease-tools/dhcp_lease_time.c
index 697d627..91edbfa 100644
--- a/contrib/lease-tools/dhcp_lease_time.c
+++ b/contrib/lease-tools/dhcp_lease_time.c
@@ -83,7 +83,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
if (p >= end - 2)
return NULL; /* malformed packet */
opt_len = option_len(p);
- if (end - p >= (2 + opt_len))
+ if (end - p < (2 + opt_len))
return NULL; /* malformed packet */
if (*p == opt && opt_len >= minsize)
return p;

View File

@ -1,34 +0,0 @@
From 8fda4b4620ca2b23152ca805d14c7cde1083fe31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Tue, 1 Oct 2019 16:08:28 +0200
Subject: [PATCH] Report error on dhcp_release
If no IPv4 address is present on given interface, the tool would not
send any request. It would not report any error at the same time. Report
error if request send failed.
Signed-off-by: Petr Mensik <pemensik@redhat.com>
---
contrib/lease-tools/dhcp_release.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/contrib/lease-tools/dhcp_release.c b/contrib/lease-tools/dhcp_release.c
index c866cd9..30e77c6 100644
--- a/contrib/lease-tools/dhcp_release.c
+++ b/contrib/lease-tools/dhcp_release.c
@@ -223,7 +223,11 @@ static struct in_addr find_interface(struct in_addr client, int fd, unsigned int
ifr->ifr_addr.sa_family = AF_INET;
if (ioctl(ifrfd, SIOCGIFADDR, ifr) != -1)
return ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
- exit(0);
+ else
+ {
+ fprintf(stderr, "error: local IPv4 address not found\n");
+ exit(1);
+ }
}
else if (h->nlmsg_type == RTM_NEWADDR)
{
--
2.20.1

View File

@ -1,99 +0,0 @@
From 4c5cbdfb82e668268a5f3713fe119fb077667c8e Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Mon, 22 Aug 2022 21:59:42 +0200
Subject: [PATCH] Ensure also server_domains_cleanup is called always
Fixes issue in patch dnsmasq-2.79-server-domain-rh1919894.patch.
When /etc/resolv.conf is changed, dnsmasq reloads used servers. But it
does not call cleanup of server domains in this case. It might cause
serv_domain->last_server to become non-null, but pointing released
server. Ensure it is checked before any cleanup_servers() action always
and from all other places, like dbus setting.
Caused unending loop in forward_query function, rhbz#2106361.
---
src/network.c | 49 +++++++++++++++++++++++++------------------------
1 file changed, 25 insertions(+), 24 deletions(-)
diff --git a/src/network.c b/src/network.c
index 4d140bb..96668fb 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1402,10 +1402,35 @@ void mark_servers(int flag)
}
}
+static void server_domains_cleanup(void)
+{
+ struct server_domain *sd, *tmp, **up;
+
+ /* unlink and free anything still marked. */
+ for (up = &daemon->server_domains, sd=*up; sd; sd = tmp)
+ {
+ tmp = sd->next;
+ if (sd->flags & SERV_MARK)
+ {
+ *up = sd->next;
+ if (sd->domain)
+ free(sd->domain);
+ free(sd);
+ }
+ else {
+ up = &sd->next;
+ if (sd->last_server && (sd->last_server->flags & SERV_MARK))
+ sd->last_server = NULL;
+ }
+ }
+}
+
void cleanup_servers(void)
{
struct server *serv, *tmp, **up;
+ server_domains_cleanup();
+
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
@@ -1428,29 +1453,6 @@ void cleanup_servers(void)
#endif
}
-void server_domains_cleanup(void)
-{
- struct server_domain *sd, *tmp, **up;
-
- /* unlink and free anything still marked. */
- for (up = &daemon->server_domains, sd=*up; sd; sd = tmp)
- {
- tmp = sd->next;
- if (sd->flags & SERV_MARK)
- {
- *up = sd->next;
- if (sd->domain)
- free(sd->domain);
- free(sd);
- }
- else {
- up = &sd->next;
- if (sd->last_server && (sd->last_server->flags & SERV_MARK))
- sd->last_server = NULL;
- }
- }
-}
-
void add_update_server(int flags,
union mysockaddr *addr,
union mysockaddr *source_addr,
@@ -1739,7 +1741,6 @@ void check_servers(void)
up = &sfd->next;
}
- server_domains_cleanup();
cleanup_servers();
}
--
2.37.2

View File

@ -1,473 +0,0 @@
From b15c92e5d793c9767591dbf8910bf3466aba92ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Mon, 19 Apr 2021 13:56:23 +0200
Subject: [PATCH] Use load-balancing also for --server=/domains/
Do not (yet) move servers to server_domain structure. Instead use
separate server_domains to store just last_server and requests count and
time.
Introduces domain information duplicity, but minimizes required changes
to daemon->servers usage.
Optimize server domain record
Set pointer to domain record when struct server is created. When
searching for domain pointer, use this pointer to make it quick.
---
src/dnsmasq.h | 18 +++++++--
src/forward.c | 54 ++++++++++++++++-----------
src/network.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++----
src/option.c | 5 +++
4 files changed, 147 insertions(+), 31 deletions(-)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 4beef35..27ff86a 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -531,6 +531,17 @@ struct randfd_list {
struct randfd_list *next;
};
+/* contains domain specific set of servers.
+ * If domain is NULL, just normal servers. */
+struct server_domain {
+ char *domain;
+ struct server *last_server;
+ time_t forwardtime;
+ int forwardcount;
+ unsigned int flags; /* server.flags alternative */
+ struct server_domain *next;
+};
+
struct server {
union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1];
@@ -543,6 +554,7 @@ struct server {
#ifdef HAVE_LOOP
u32 uid;
#endif
+ struct server_domain *serv_domain;
struct server *next;
};
@@ -995,6 +1007,7 @@ extern struct daemon {
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers;
+ struct server_domain *server_domains;
struct ipsets *ipsets;
int log_fac; /* log facility */
char *log_file; /* optional log file */
@@ -1061,9 +1074,6 @@ extern struct daemon {
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
- struct server *last_server;
- time_t forwardtime;
- int forwardcount;
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
int fd_save; /* " " */
@@ -1319,6 +1329,8 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
int label_exception(int index, int family, struct all_addr *addr);
int fix_fd(int fd);
int tcp_interface(int fd, int af);
+struct server_domain *server_domain_find_domain(const char *domain);
+struct server_domain *server_domain_new(struct server *serv);
#ifdef HAVE_IPV6
int set_ipv6pktinfo(int fd);
#endif
diff --git a/src/forward.c b/src/forward.c
index 11e0310..d8e845a 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -109,7 +109,8 @@ int send_from(int fd, int nowild, char *packet, size_t len,
}
static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype,
- char *qdomain, int *type, char **domain, int *norebind)
+ char *qdomain, int *type, char **domain, int *norebind,
+ struct server_domain **serv_domain)
{
/* If the query ends in the domain in one of our servers, set
@@ -121,6 +122,9 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
struct server *serv;
unsigned int flags = 0;
+ if (serv_domain)
+ *serv_domain = NULL;
+
for (serv = daemon->servers; serv; serv=serv->next)
if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
continue;
@@ -181,6 +185,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
{
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
*domain = serv->domain;
+ if (serv_domain)
+ *serv_domain = serv->serv_domain;
matchlen = domainlen;
if (serv->flags & SERV_NO_ADDR)
flags = F_NXDOMAIN;
@@ -228,6 +234,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
*type = 0; /* use normal servers for this domain */
*domain = NULL;
}
+ if (serv_domain && !*serv_domain)
+ *serv_domain = server_domain_find_domain(*domain);
return flags;
}
@@ -242,6 +250,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int flags = 0;
unsigned int fwd_flags = 0;
struct server *start = NULL;
+ struct server_domain *sd = NULL;
void *hash = hash_questions(header, plen, daemon->namebuff);
#ifdef HAVE_DNSSEC
int do_dnssec = 0;
@@ -313,8 +322,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->sentto->failed_queries++;
if (!option_bool(OPT_ORDER))
{
+ sd = forward->sentto->serv_domain;
forward->forwardall = 1;
- daemon->last_server = NULL;
+ if (sd)
+ sd->last_server = NULL;
}
type = forward->sentto->flags & SERV_TYPE;
#ifdef HAVE_DNSSEC
@@ -363,10 +374,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
return 1;
}
-
+
if (gotname)
- flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
-
+ flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
+
#ifdef HAVE_DNSSEC
do_dnssec = type & SERV_DO_DNSSEC;
#endif
@@ -407,18 +418,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
always try all the available servers,
otherwise, use the one last known to work. */
- if (type == 0)
+ if (sd)
{
if (option_bool(OPT_ORDER))
start = daemon->servers;
- else if (!(start = daemon->last_server) ||
- daemon->forwardcount++ > FORWARD_TEST ||
- difftime(now, daemon->forwardtime) > FORWARD_TIME)
+ else if (!(start = sd->last_server) ||
+ sd->forwardcount++ > FORWARD_TEST ||
+ difftime(now, sd->forwardtime) > FORWARD_TIME)
{
start = daemon->servers;
forward->forwardall = 1;
- daemon->forwardcount = 0;
- daemon->forwardtime = now;
+ sd->forwardcount = 0;
+ sd->forwardtime = now;
}
}
else
@@ -758,6 +769,7 @@ void reply_query(int fd, time_t now)
size_t nn;
struct server *server;
void *hash;
+ struct server_domain *sd;
/* packet buffer overwritten */
daemon->srv_save = NULL;
@@ -845,7 +857,8 @@ void reply_query(int fd, time_t now)
}
server = forward->sentto;
- if ((forward->sentto->flags & SERV_TYPE) == 0)
+ sd = server->serv_domain;
+ if (sd)
{
if (RCODE(header) == REFUSED)
server = NULL;
@@ -863,7 +876,7 @@ void reply_query(int fd, time_t now)
}
}
if (!option_bool(OPT_ALL_SERVERS))
- daemon->last_server = server;
+ sd->last_server = server;
}
/* We tried resending to this server with a smaller maximum size and got an answer.
@@ -964,7 +977,7 @@ void reply_query(int fd, time_t now)
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
- if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
+ if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL, &sd) == 0)
{
struct server *start = server, *new_server = NULL;
@@ -1541,7 +1554,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
- if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
+ if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL, NULL) != 0)
{
new_status = STAT_ABANDONED;
break;
@@ -1814,11 +1827,12 @@ unsigned char *tcp_request(int confd, time_t now,
int type = SERV_DO_DNSSEC;
char *domain = NULL;
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
+ struct server_domain *sd = NULL;
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
if (gotname)
- flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
+ flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
@@ -1839,10 +1853,10 @@ unsigned char *tcp_request(int confd, time_t now,
type &= ~SERV_DO_DNSSEC;
- if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
+ if (!sd || option_bool(OPT_ORDER) || !sd->last_server)
last_server = daemon->servers;
else
- last_server = daemon->last_server;
+ last_server = sd->last_server;
if (!flags && last_server)
{
@@ -2439,9 +2453,7 @@ void server_gone(struct server *server)
if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
daemon->randomsocks[i].serv = NULL;
- if (daemon->last_server == server)
- daemon->last_server = NULL;
-
+ /* last_server cleared by server_domain_cleanup */
if (daemon->srv_save == server)
daemon->srv_save = NULL;
}
diff --git a/src/network.c b/src/network.c
index 4eda1fd..4d140bb 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1428,6 +1428,29 @@ void cleanup_servers(void)
#endif
}
+void server_domains_cleanup(void)
+{
+ struct server_domain *sd, *tmp, **up;
+
+ /* unlink and free anything still marked. */
+ for (up = &daemon->server_domains, sd=*up; sd; sd = tmp)
+ {
+ tmp = sd->next;
+ if (sd->flags & SERV_MARK)
+ {
+ *up = sd->next;
+ if (sd->domain)
+ free(sd->domain);
+ free(sd);
+ }
+ else {
+ up = &sd->next;
+ if (sd->last_server && (sd->last_server->flags & SERV_MARK))
+ sd->last_server = NULL;
+ }
+ }
+}
+
void add_update_server(int flags,
union mysockaddr *addr,
union mysockaddr *source_addr,
@@ -1507,10 +1530,72 @@ void add_update_server(int flags,
}
}
+static const char *server_get_domain(const struct server *serv)
+{
+ const char *domain = serv->domain;
+
+ if (serv->flags & SERV_HAS_DOMAIN)
+ /* .example.com is valid */
+ while (*domain == '.')
+ domain++;
+
+ return domain;
+}
+
+struct server_domain *server_domain_find_domain(const char *domain)
+{
+ struct server_domain *sd;
+ for (sd = daemon->server_domains; sd; sd = sd->next)
+ if ((!domain && sd->domain == domain) || (domain && sd->domain && hostname_isequal(domain, sd->domain)))
+ return sd;
+ return NULL;
+}
+
+/**< Test structure has already set domain pointer.
+ *
+ * If not, create a new record. */
+struct server_domain *server_domain_new(struct server *serv)
+{
+ struct server_domain *sd;
+
+ if ((sd = whine_malloc(sizeof(struct server_domain))))
+ {
+ const char *domain = server_get_domain(serv);
+
+ /* Ensure all serv->domain values have own record in server_domain.
+ * Add a new record. */
+ if (domain)
+ {
+ size_t len = strlen(domain)+1;
+ sd->domain = whine_malloc(len);
+ if (sd->domain)
+ memcpy(sd->domain, domain, len);
+ }
+ sd->next = daemon->server_domains;
+ serv->serv_domain = sd;
+ daemon->server_domains = sd;
+ }
+ return sd;
+}
+
+/**< Test structure has already set domain pointer.
+ *
+ * If not, create a new record. */
+static void server_domain_check(struct server *serv)
+{
+ struct server_domain *sd = serv->serv_domain;
+
+ if (sd)
+ sd->flags &= (~SERV_MARK); /* found domain, mark active */
+ else
+ server_domain_new(serv);
+}
+
void check_servers(void)
{
struct irec *iface;
struct server *serv;
+ struct server_domain *sd;
struct serverfd *sfd, *tmp, **up;
int port = 0, count;
int locals = 0;
@@ -1522,10 +1607,14 @@ void check_servers(void)
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
sfd->used = 0;
+ for (sd = daemon->server_domains; sd; sd = sd->next)
+ sd->flags |= SERV_MARK;
+
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
{
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
{
+
/* Init edns_pktsz for newly created server records. */
if (serv->edns_pktsz == 0)
serv->edns_pktsz = daemon->edns_pktsz;
@@ -1541,12 +1630,8 @@ void check_servers(void)
if (serv->flags & SERV_HAS_DOMAIN)
{
struct ds_config *ds;
- char *domain = serv->domain;
-
- /* .example.com is valid */
- while (*domain == '.')
- domain++;
-
+ const char *domain = server_get_domain(serv);
+
for (ds = daemon->ds; ds; ds = ds->next)
if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
break;
@@ -1556,7 +1641,6 @@ void check_servers(void)
}
}
#endif
-
port = prettyprint_addr(&serv->addr, daemon->namebuff);
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
@@ -1591,6 +1675,8 @@ void check_servers(void)
if (serv->sfd)
serv->sfd->used = 1;
+
+ server_domain_check(serv);
}
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
@@ -1653,6 +1739,7 @@ void check_servers(void)
up = &sfd->next;
}
+ server_domains_cleanup();
cleanup_servers();
}
diff --git a/src/option.c b/src/option.c
index abc5a48..6fa7bbd 100644
--- a/src/option.c
+++ b/src/option.c
@@ -906,6 +906,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
p += sprintf(p, "in-addr.arpa");
serv->flags = SERV_HAS_DOMAIN;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
@@ -930,6 +931,7 @@ static struct server *add_rev6(struct in6_addr *addr, int msize)
p += sprintf(p, "ip6.arpa");
serv->flags = SERV_HAS_DOMAIN;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
@@ -2231,6 +2233,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
}
@@ -2275,6 +2278,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
}
@@ -2525,6 +2529,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
newlist = serv;
serv->domain = domain;
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
+ server_domain_new(serv);
arg = end;
if (rebind)
break;
--
2.34.1

View File

@ -1,73 +0,0 @@
From a997ca0da044719a0ce8a232d14da8b30022592b Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Fri, 29 Jun 2018 14:39:41 +0100
Subject: [PATCH] Fix sometimes missing DNSSEC RRs when DNSSEC validation not
enabled.
Dnsmasq does pass on the do-bit, and return DNSSEC RRs, irrespective
of of having DNSSEC validation compiled in or enabled.
The thing to understand here is that the cache does not store all the
DNSSEC RRs, and dnsmasq doesn't have the (very complex) logic required
to determine the set of DNSSEC RRs required in an answer. Therefore if
the client wants the DNSSEC RRs, the query can not be answered from
the cache. When DNSSEC validation is enabled, any query with the
do-bit set is never answered from the cache, unless the domain is
known not to be signed: the query is always forwarded. This ensures
that the DNSEC RRs are included.
The same thing should be true when DNSSEC validation is not enabled,
but there's a bug in the logic.
line 1666 of src/rfc1035.c looks like this
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
{ ...answer from cache ... }
So local stuff (hosts, DHCP, ) get answered. If the do_bit is not set
then the query is answered, and if the domain is known not to be
signed, the query is answered.
Unfortunately, if DNSSEC validation is not turned on then the
F_DNSSECOK bit is not valid, and it's always zero, so the question
always gets answered from the cache, even when the do-bit is set.
This code should look like that at line 1468, dealing with PTR queries
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
!do_bit ||
(option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
where the F_DNSSECOK bit is only used when validation is enabled.
---
src/rfc1035.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/rfc1035.c b/src/rfc1035.c
index ebb1f36..580f5ef 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1663,7 +1663,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
/* If the client asked for DNSSEC don't use cached data. */
- if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
+ if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
+ !do_bit ||
+ (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
do
{
/* don't answer wildcard queries with data not from /etc/hosts
@@ -1747,7 +1749,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
{
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
(qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
- ((crecp->flags & F_CONFIG) || !do_bit || !(crecp->flags & F_DNSSECOK)))
+ ((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
{
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
--
2.14.4

View File

@ -1,25 +0,0 @@
From 03212e533b1e07aba30d2f4112009dc3af867ea5 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Tue, 4 Sep 2018 17:52:28 +0100
Subject: [PATCH] Manpage typo.
---
man/dnsmasq.8 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index ebfadba..a62860e 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -27,7 +27,7 @@ TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP. The PXE
.PP
The dnsmasq DHCPv6 server provides the same set of features as the
DHCPv4 server, and in addition, it includes router advertisements and
-a neat feature which allows nameing for clients which use DHCPv4 and
+a neat feature which allows naming for clients which use DHCPv4 and
stateless autoconfiguration only for IPv6 configuration. There is support for doing address allocation (both DHCPv6 and RA) from subnets which are dynamically delegated via DHCPv6 prefix delegation.
.PP
Dnsmasq is coded with small embedded systems in mind. It aims for the smallest possible memory footprint compatible with the supported functions, and allows unneeded functions to be omitted from the compiled binary.
--
2.31.1

View File

@ -1,47 +0,0 @@
From 69bc94779c2f035a9fffdb5327a54c3aeca73ed5 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Wed, 14 Aug 2019 20:44:50 +0100
Subject: [PATCH] Fix memory leak in helper.c
Thanks to Xu Mingjie <xumingjie1995@outlook.com> for spotting this.
---
src/helper.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/helper.c b/src/helper.c
index 33ba120..c392eec 100644
--- a/src/helper.c
+++ b/src/helper.c
@@ -80,7 +80,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
pid_t pid;
int i, pipefd[2];
struct sigaction sigact;
-
+ unsigned char *alloc_buff = NULL;
+
/* create the pipe through which the main program sends us commands,
then fork our process. */
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
@@ -186,11 +187,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
struct script_data data;
char *p, *action_str, *hostname = NULL, *domain = NULL;
unsigned char *buf = (unsigned char *)daemon->namebuff;
- unsigned char *end, *extradata, *alloc_buff = NULL;
+ unsigned char *end, *extradata;
int is6, err = 0;
int pipeout[2];
- free(alloc_buff);
+ /* Free rarely-allocated memory from previous iteration. */
+ if (alloc_buff)
+ {
+ free(alloc_buff);
+ alloc_buff = NULL;
+ }
/* we read zero bytes when pipe closed: this is our signal to exit */
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
--
1.7.10.4

View File

@ -1,28 +0,0 @@
From 0a970b2a19c9fe5166e846d8a0c8b4f4fa5f1b4f Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Mon, 30 Jul 2018 14:55:39 +0100
Subject: [PATCH] Fix crash parsing a --synth-domain with no prefix. Problem
introduced in 2.79/6b2b564ac34cb3c862f168e6b1457f9f0b9ca69c
---
src/option.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/option.c b/src/option.c
index b22fc90..4e54afb 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2347,7 +2347,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
char *star;
new->next = daemon->synth_domains;
daemon->synth_domains = new;
- if ((star = strrchr(new->prefix, '*')) && *(star+1) == 0)
+ if (new->prefix &&
+ (star = strrchr(new->prefix, '*'))
+ && *(star+1) == 0)
{
*star = 0;
new->indexed = 1;
--
2.41.0

View File

@ -1,317 +0,0 @@
From 653481c6ebf46dcadb5a017085325d956dd04a28 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Tue, 21 Aug 2018 22:06:36 +0100
Subject: [PATCH] Properly deal with unaligned addresses in DHCPv6 packets.
Thanks to Vladislav Grishenko for spotting this.
(cherry picked from commit 97f876b64c22b2b18412e2e3d8506ee33e42db7c)
Conflicts:
src/rfc3315.c
---
src/rfc1035.c | 2 +-
src/rfc3315.c | 101 ++++++++++++++++++++++++++++++++++------------------------
2 files changed, 61 insertions(+), 42 deletions(-)
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 6b3bb27..ee5f7a0 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1376,7 +1376,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
t->class, C_IN, "t", t->len, t->txt))
- anscount ++;
+ anscount++;
}
}
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 21fcd9b..ee1cf17 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -639,9 +639,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
int plain_range = 1;
u32 lease_time;
struct dhcp_lease *ltmp;
- struct in6_addr *req_addr;
- struct in6_addr addr;
-
+ struct in6_addr req_addr, addr;
+
if (!check_ia(state, opt, &ia_end, &ia_option))
continue;
@@ -709,9 +708,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
- req_addr = opt6_ptr(ia_option, 0);
+ /* worry about alignment here. */
+ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
- if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
+ if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
{
lease_time = c->lease_time;
/* If the client asks for an address on the same network as a configured address,
@@ -719,14 +719,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
addresses automatic. */
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
{
- req_addr = &addr;
+ req_addr = addr;
mark_config_used(c, &addr);
if (have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
}
- else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
+ else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
continue; /* not an address we're allowed */
- else if (!check_address(state, req_addr))
+ else if (!check_address(state, &req_addr))
continue; /* address leased elsewhere */
/* add address to output packet */
@@ -734,8 +734,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c);
#endif
- add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
- mark_context_used(state, req_addr);
+ add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
+ mark_context_used(state, &req_addr);
get_context_tag(state, c);
address_assigned = 1;
}
@@ -768,15 +768,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ltmp = NULL;
while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
{
- req_addr = &ltmp->addr6;
- if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
+ req_addr = ltmp->addr6;
+ if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
{
#ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c);
#endif
- add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now);
- mark_context_used(state, req_addr);
+ add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
+ mark_context_used(state, &req_addr);
get_context_tag(state, c);
address_assigned = 1;
}
@@ -892,16 +892,19 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
- struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
+ struct in6_addr req_addr;
struct dhcp_context *dynamic, *c;
unsigned int lease_time;
struct in6_addr addr;
int config_ok = 0;
+
+ /* align. */
+ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
- if ((c = address6_valid(state->context, req_addr, tagif, 1)))
- config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
+ if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
+ config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr);
- if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
+ if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
{
if (!dynamic && !config_ok)
{
@@ -911,7 +914,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
put_opt6_string(_("address unavailable"));
end_opt6(o1);
}
- else if (!check_address(state, req_addr))
+ else if (!check_address(state, &req_addr))
{
/* Address leased to another DUID/IAID */
o1 = new_opt6(OPTION6_STATUS_CODE);
@@ -933,7 +936,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c);
#endif
- add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now);
+ add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
get_context_tag(state, dynamic);
address_assigned = 1;
}
@@ -996,15 +999,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct dhcp_lease *lease = NULL;
- struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
+ struct in6_addr req_addr;
unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
unsigned int valid_time = opt6_uint(ia_option, 20, 4);
char *message = NULL;
struct dhcp_context *this_context;
+
+ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if (!(lease = lease6_find(state->clid, state->clid_len,
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
- state->iaid, req_addr)))
+ state->iaid, &req_addr)))
{
/* If the server cannot find a client entry for the IA the server
returns the IA containing no addresses with a Status Code option set
@@ -1012,7 +1017,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
save_counter(iacntr);
t1cntr = 0;
- log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
+ log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
@@ -1024,15 +1029,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
- if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
- (this_context = address6_valid(state->context, req_addr, tagif, 1)))
+ if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
+ (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
{
struct in6_addr addr;
unsigned int lease_time;
get_context_tag(state, this_context);
- if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
+ if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
else
lease_time = this_context->lease_time;
@@ -1045,7 +1050,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
if (state->ia_type == OPTION6_IA_NA && state->hostname)
{
- char *addr_domain = get_domain6(req_addr);
+ char *addr_domain = get_domain6(&req_addr);
if (!state->send_domain)
state->send_domain = addr_domain;
lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
@@ -1063,12 +1068,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
if (message && (message != state->hostname))
- log6_packet(state, "DHCPREPLY", req_addr, message);
+ log6_packet(state, "DHCPREPLY", &req_addr, message);
else
- log6_quiet(state, "DHCPREPLY", req_addr, message);
+ log6_quiet(state, "DHCPREPLY", &req_addr, message);
o1 = new_opt6(OPTION6_IAADDR);
- put_opt6(req_addr, sizeof(*req_addr));
+ put_opt6(&req_addr, sizeof(req_addr));
put_opt6_long(preferred_time);
put_opt6_long(valid_time);
end_opt6(o1);
@@ -1100,19 +1105,23 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ia_option;
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
- struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
+ struct in6_addr req_addr;
+
+ /* alignment */
+ memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
- if (!address6_valid(state->context, req_addr, tagif, 1))
+ if (!address6_valid(state->context, &req_addr, tagif, 1))
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOTONLINK);
put_opt6_string(_("confirm failed"));
end_opt6(o1);
+ log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
return 1;
}
good_addr = 1;
- log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
+ log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
}
}
@@ -1171,9 +1180,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct dhcp_lease *lease;
-
+ struct in6_addr addr;
+
+ /* align */
+ memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
- state->iaid, opt6_ptr(ia_option, 0))))
+ state->iaid, &addr)))
lease_prune(lease, now);
else
{
@@ -1233,12 +1245,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct dhcp_lease *lease;
- struct in6_addr *addrp = opt6_ptr(ia_option, 0);
+ struct in6_addr addr;
- if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
+ /* align */
+ memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
+
+ if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
{
prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
- inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
+ inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
daemon->addrbuff, daemon->dhcp_buff3);
config->flags |= CONFIG_DECLINED;
@@ -1250,7 +1265,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
context_tmp->addr_epoch++;
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
- state->iaid, opt6_ptr(ia_option, 0))))
+ state->iaid, &addr)))
lease_prune(lease, now);
else
{
@@ -1267,7 +1282,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
o1 = new_opt6(OPTION6_IAADDR);
- put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
+ put_opt6(&addr, IN6ADDRSZ);
put_opt6_long(0);
put_opt6_long(0);
end_opt6(o1);
@@ -1935,7 +1950,11 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
}
else if (type == OPTION6_IAADDR)
{
- inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
+ struct in6_addr addr;
+
+ /* align */
+ memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
+ inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
sprintf(daemon->namebuff, "%s PL=%u VL=%u",
daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
optname = "iaaddr";
--
1.8.3.1

View File

@ -1,44 +0,0 @@
From 6307208c806f9b968eca178931b3d77c4ed83c54 Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Fri, 6 Mar 2020 15:37:23 +0100
Subject: [PATCH] Correct range check of dhcp-host prefix
It incorrectly works with 32 bit integer only when counting number of
addresses in range. It works correctly only between prefixlen 96 and
128. Use 64bit shift to work with well with numbers higher than 64.
Fixes commit 79aba0f10ad0157fb4f48afbbcb03f094caff97a error.
---
src/option.c | 2 +-
src/rfc3315.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/option.c b/src/option.c
index 88cd2ab..79122df 100644
--- a/src/option.c
+++ b/src/option.c
@@ -3247,7 +3247,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (!atoi_check(pref, &new_addr->prefixlen) ||
new_addr->prefixlen > 128 ||
- (((1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
+ ((((u64)1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
{
dhcp_config_free(new);
ret_err(_("bad IPv6 prefix"));
diff --git a/src/rfc3315.c b/src/rfc3315.c
index a0067e9..f59aedc 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -1798,7 +1798,7 @@ static int config_valid(struct dhcp_config *config, struct dhcp_context *context
addresses = 1;
if (addr_list->flags & ADDRLIST_PREFIX)
- addresses = 1<<(128-addr_list->prefixlen);
+ addresses = (u64)1<<(128-addr_list->prefixlen);
if ((addr_list->flags & ADDRLIST_WILDCARD))
{
--
2.21.1

View File

@ -1,56 +0,0 @@
From f8c77edbdffb8ada7753ea9fa104f0f6da70cfe3 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Thu, 10 Jan 2019 21:58:18 +0000
Subject: [PATCH] Fix removal of DHCP_CLIENT_MAC options from DHCPv6 relay
replies.
---
src/rfc3315.c | 30 +++++++++++++++++-------------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/src/rfc3315.c b/src/rfc3315.c
index d3c1722..79b2a86 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -219,21 +219,25 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
return 0;
- int o = new_opt6(opt6_type(opt));
- if (opt6_type(opt) == OPTION6_RELAY_MSG)
+ /* Don't copy MAC address into reply. */
+ if (opt6_type(opt) != OPTION6_CLIENT_MAC)
{
- struct in6_addr align;
- /* the packet data is unaligned, copy to aligned storage */
- memcpy(&align, inbuff + 2, IN6ADDRSZ);
- state->link_address = &align;
- /* zero is_unicast since that is now known to refer to the
- relayed packet, not the original sent by the client */
- if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
- return 0;
+ int o = new_opt6(opt6_type(opt));
+ if (opt6_type(opt) == OPTION6_RELAY_MSG)
+ {
+ struct in6_addr align;
+ /* the packet data is unaligned, copy to aligned storage */
+ memcpy(&align, inbuff + 2, IN6ADDRSZ);
+ state->link_address = &align;
+ /* zero is_unicast since that is now known to refer to the
+ relayed packet, not the original sent by the client */
+ if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
+ return 0;
+ }
+ else
+ put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
+ end_opt6(o);
}
- else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
- put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
- end_opt6(o);
}
return 1;
--
2.39.1

View File

@ -1,25 +0,0 @@
From 3052ce208acf602f0163166dcefb7330d537cedb Mon Sep 17 00:00:00 2001
From: Jiri Slaby <jslaby@suse.cz>
Date: Wed, 24 Jul 2019 17:34:48 +0100
Subject: [PATCH] Fix build after y2038 changes in glib.
SIOCGSTAMP is defined in linux/sockios.h, not asm/sockios.h now.
---
src/dnsmasq.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index ff3204a..3ef04ad 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -137,6 +137,7 @@ typedef unsigned long long u64;
#endif
#if defined(HAVE_LINUX_NETWORK)
+#include <linux/sockios.h>
#include <linux/capability.h>
/* There doesn't seem to be a universally-available
userspace header for these. */
--
2.36.1

View File

@ -1,45 +0,0 @@
From 595b2e2e87f152c4ade7e2d66cb78915096f60c2 Mon Sep 17 00:00:00 2001
From: Donald Sharp <donaldsharp72@gmail.com>
Date: Mon, 2 Mar 2020 11:23:36 -0500
Subject: [PATCH] Ignore routes in non-main tables
Route lookup in Linux is bounded by `ip rules` as well
as the contents of specific routing tables. With the
advent of vrf's(l3mdev's) non-default tables are regularly being
used for routing purposes.
dnsmasq listens to all route changes on the box and responds
to each one with an event. This is *expensive* when a full
BGP routing table is placed into the linux kernel, moreso
when dnsmasq is responding to events in tables that it will
never actually need to respond to, since dnsmasq at this
point in time has no concept of vrf's and would need
to be programmed to understand them. Help alleviate this load
by reducing the set of data that dnsmasq pays attention to
when we know there are events that are not useful at this
point in time.
Signed-off-by: Donald Sharp <donaldsharp72@gmail.com>
(cherry picked from commit b2ed691eb3ca6488a8878f5f3dd950a07b14a9db)
---
src/netlink.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/netlink.c b/src/netlink.c
index 8cd51af..0a3da3e 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -363,7 +363,9 @@ static void nl_async(struct nlmsghdr *h)
failing. */
struct rtmsg *rtm = NLMSG_DATA(h);
- if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
+ 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);
}
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
--
2.26.2

View File

@ -1,132 +0,0 @@
commit 98c6998116e33f9f34b798682e0695f4166bd86d
Author: Simon Kelley <simon@thekelleys.org.uk>
Date: Mon Mar 2 17:10:25 2020 +0000
Optimise closing file descriptors.
Dnsmasq needs to close all the file descriptors it inherits, for security
reasons. This is traditionally done by calling close() on every possible
file descriptor (most of which won't be open.) On big servers where
"every possible file descriptor" is a rather large set, this gets
rather slow, so we use the /proc/<pid>/fd directory to get a list
of the fds which are acually open.
This only works on Linux. On other platforms, and on Linux systems
without a /proc filesystem, we fall back to the old way.
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 573aac0..10f19ea 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -138,20 +138,18 @@ int main (int argc, char **argv)
}
#endif
- /* Close any file descriptors we inherited apart from std{in|out|err}
-
- Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
+ /* Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
otherwise file descriptors we create can end up being 0, 1, or 2
and then get accidentally closed later when we make 0, 1, and 2
open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
but it's not guaranteed. By opening /dev/null three times, we
ensure that we're not using those fds for real stuff. */
- for (i = 0; i < max_fd; i++)
- if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
- close(i);
- else
- open("/dev/null", O_RDWR);
-
+ for (i = 0; i < 3; i++)
+ open("/dev/null", O_RDWR);
+
+ /* Close any file descriptors we inherited apart from std{in|out|err} */
+ close_fds(max_fd, -1, -1, -1);
+
#ifndef HAVE_LINUX_NETWORK
# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
if (!option_bool(OPT_NOWILD))
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 6103eb5..c46bfeb 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1283,7 +1283,7 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len,
int expand_buf(struct iovec *iov, size_t size);
char *print_mac(char *buff, unsigned char *mac, int len);
int read_write(int fd, unsigned char *packet, int size, int rw);
-
+void close_fds(long max_fd, int spare1, int spare2, int spare3);
int wildcard_match(const char* wildcard, const char* match);
int wildcard_matchn(const char* wildcard, const char* match, int num);
diff --git a/src/helper.c b/src/helper.c
index 1b260a1..7072cf4 100644
--- a/src/helper.c
+++ b/src/helper.c
@@ -131,12 +131,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
Don't close err_fd, in case the lua-init fails.
Note that we have to do this before lua init
so we don't close any lua fds. */
- for (max_fd--; max_fd >= 0; max_fd--)
- if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
- max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
- max_fd != event_fd && max_fd != err_fd)
- close(max_fd);
-
+ close_fds(max_fd, pipefd[0], event_fd, err_fd);
+
#ifdef HAVE_LUASCRIPT
if (daemon->luascript)
{
diff --git a/src/util.c b/src/util.c
index 73bf62a..f058c92 100644
--- a/src/util.c
+++ b/src/util.c
@@ -705,6 +705,47 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
return 1;
}
+/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
+void close_fds(long max_fd, int spare1, int spare2, int spare3)
+{
+ /* On Linux, use the /proc/ filesystem to find which files
+ are actually open, rather than iterate over the whole space,
+ for efficiency reasons. If this fails we drop back to the dumb code. */
+#ifdef HAVE_LINUX_NETWORK
+ DIR *d;
+
+ if ((d = opendir("/proc/self/fd")))
+ {
+ struct dirent *de;
+
+ while ((de = readdir(d)))
+ {
+ long fd;
+ char *e = NULL;
+
+ errno = 0;
+ fd = strtol(de->d_name, &e, 10);
+
+ if (errno != 0 || !e || *e || fd == dirfd(d) ||
+ fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == STDIN_FILENO ||
+ fd == spare1 || fd == spare2 || fd == spare3)
+ continue;
+
+ close(fd);
+ }
+
+ closedir(d);
+ return;
+ }
+#endif
+
+ /* fallback, dumb code. */
+ for (max_fd--; max_fd >= 0; max_fd--)
+ if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&
+ max_fd != spare1 && max_fd != spare2 && max_fd != spare3)
+ close(max_fd);
+}
+
/* Basically match a string value against a wildcard pattern. */
int wildcard_match(const char* wildcard, const char* match)
{

View File

@ -1,161 +0,0 @@
From 03936d309782da038a2982b08fce7be85d884f0e Mon Sep 17 00:00:00 2001
From: Vladislav Grishenko <themiron@mail.ru>
Date: Sun, 8 Mar 2020 15:34:34 +0000
Subject: [PATCH] Add DHCPv6 ntp-server (56) option handling.
There was discussion in the past regarding DHCPv6 NTP server option
which needs special subclassing per RFC5908.
Patch adds support for unicast, multicast IPv6 address and for FQDN string,
preserving possibly used (as suggested earlier) hex value.
Unfortunately it's still not fully free from limitations - only address list or
only fqdn value list is possible, not mixed due current
state option parsing & flagging.
(cherry picked from commit dded78b2338147daf69064d6d48c16b12744e441)
---
src/dhcp-common.c | 2 +-
src/dhcp6-protocol.h | 4 ++++
src/option.c | 19 ++++++++++++++++---
src/rfc3315.c | 24 ++++++++++++++++++++----
4 files changed, 41 insertions(+), 8 deletions(-)
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index 368d686..242a5a1 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -642,7 +642,7 @@ static const struct opttab_t opttab6[] = {
{ "sntp-server", 31, OT_ADDR_LIST },
{ "information-refresh-time", 32, OT_TIME },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
- { "ntp-server", 56, 0 },
+ { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
{ "client-arch", 61, 2 | OT_DEC }, /* RFC 5970 */
diff --git a/src/dhcp6-protocol.h b/src/dhcp6-protocol.h
index fee5d28..05560e8 100644
--- a/src/dhcp6-protocol.h
+++ b/src/dhcp6-protocol.h
@@ -59,12 +59,16 @@
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
+#define OPTION6_NTP_SERVER 56
#define OPTION6_CLIENT_MAC 79
/* replace this with the real number when allocated.
defining this also enables the relevant code. */
/* #define OPTION6_PREFIX_CLASS 99 */
+#define NTP_SUBOPTION_SRV_ADDR 1
+#define NTP_SUBOPTION_MC_ADDR 2
+#define NTP_SUBOPTION_SRV_FQDN 3
#define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1
diff --git a/src/option.c b/src/option.c
index 6fa7bbd..1382c55 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1245,6 +1245,12 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
if (!found_dig)
is_dec = is_addr = 0;
+#ifdef HAVE_DHCP6
+ /* NTP server option takes hex, addresses or FQDN */
+ if (is6 && new->opt == OPTION6_NTP_SERVER && !is_hex)
+ opt_len |= is_addr6 ? OT_ADDR_LIST : OT_RFC1035_NAME;
+#endif
+
/* We know that some options take addresses */
if (opt_len & OT_ADDR_LIST)
{
@@ -1505,8 +1511,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
else if (comma && (opt_len & OT_RFC1035_NAME))
{
- unsigned char *p = NULL, *newp, *end;
+ unsigned char *p = NULL, *q, *newp, *end;
int len = 0;
+ int header_size = (is6 && new->opt == OPTION6_NTP_SERVER) ? 4 : 0;
arg = comma;
comma = split(arg);
@@ -1516,7 +1523,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
if (!dom)
goto_err(_("bad domain in dhcp-option"));
- newp = opt_malloc(len + strlen(dom) + 2);
+ newp = opt_malloc(len + header_size + strlen(dom) + 2);
if (p)
{
@@ -1525,8 +1532,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
p = newp;
- end = do_rfc1035_name(p + len, dom, NULL);
+ q = p + len;
+ end = do_rfc1035_name(q + header_size, dom, NULL);
*end++ = 0;
+ if (is6 && new->opt == OPTION6_NTP_SERVER)
+ {
+ PUTSHORT(NTP_SUBOPTION_SRV_FQDN, q);
+ PUTSHORT(end - q - 2, q);
+ }
len = end - p;
free(dom);
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 1f1aad8..0fa12ad 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -1380,23 +1380,39 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
{
+ struct in6_addr *p = NULL;
+
if (IN6_IS_ADDR_UNSPECIFIED(a))
{
if (!add_local_addrs(state->context))
- put_opt6(state->fallback, IN6ADDRSZ);
+ p = state->fallback;
}
else if (IN6_IS_ADDR_ULA_ZERO(a))
{
if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
- put_opt6(state->ula_addr, IN6ADDRSZ);
+ p = state->ula_addr;
}
else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
{
if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
- put_opt6(state->ll_addr, IN6ADDRSZ);
+ p = state->ll_addr;
+ }
+ else
+ p = a;
+
+ if (!p)
+ continue;
+ else if (opt_cfg->opt == OPTION6_NTP_SERVER)
+ {
+ if (IN6_IS_ADDR_MULTICAST(p))
+ o1 = new_opt6(NTP_SUBOPTION_MC_ADDR);
+ else
+ o1 = new_opt6(NTP_SUBOPTION_SRV_ADDR);
+ put_opt6(p, IN6ADDRSZ);
+ end_opt6(o1);
}
else
- put_opt6(a, IN6ADDRSZ);
+ put_opt6(p, IN6ADDRSZ);
}
end_opt6(o);
--
2.36.1

View File

@ -1,895 +0,0 @@
From 9b200103342c0909def9f8d9b97cfd889be6bfd8 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Mon, 3 Feb 2020 23:58:45 +0000
Subject: [PATCH] Support prefixed ranges of ipv6 addresses in dhcp-host.
When a request matching the clid or mac address is
recieved the server will iterate over all candidate
addresses until it find's one that is not already
leased to a different clid/iaid and advertise
this address.
Using multiple reservations for a single host makes it
possible to maintain a static leases only configuration
which support network booting systems with UEFI firmware
that request a new address (a new SOLICIT with a new IA_NA
option using a new IAID) for different boot modes, for
instance 'PXE over IPv6', and 'HTTP-Boot over IPv6'. Open
Virtual Machine Firmware (OVMF) and most UEFI firmware
build on the EDK2 code base exhibit this behaviour.
(cherry picked from commit 79aba0f10ad0157fb4f48afbbcb03f094caff97a)
Conflicts:
CHANGELOG
src/dhcp-common.c
src/dnsmasq.h
src/dhcp6.c
Extend 79aba0f10ad0157fb4f48afbbcb03f094caff97a for multiple IPv6 addresses.
(cherry picked from commit 137286e9baecf6a3ba97722ef1b49c851b531810)
Conflicts:
man/dnsmasq.8
src/dhcp-common.c
src/dhcp6.c
src/rfc3315.c
src/option.c
Fix bug with prefixed wildcard addresses in 137286e9baecf6a3ba97722ef1b49c851b531810
(cherry picked from commit f064188032a829efdcf3988b24ac795ff52785ec)
Conflicts:
src/rfc3315.c
---
man/dnsmasq.8 | 13 +-
src/dhcp-common.c | 56 +++++---
src/dhcp6.c | 51 +++----
src/dnsmasq.h | 17 +--
src/option.c | 402 ++++++++++++++++++++++++++++++------------------------
src/rfc3315.c | 83 ++++++++++-
6 files changed, 370 insertions(+), 252 deletions(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index f52762f..2c9d9f6 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -985,13 +985,20 @@ allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,.....
A single
-.B dhcp-host
-may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
+.B --dhcp-host
+may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 addresses must be bracketed by square brackets thus:
.B --dhcp-host=laptop,[1234::56]
IPv6 addresses may contain only the host-identifier part:
.B --dhcp-host=laptop,[::56]
in which case they act as wildcards in constructed dhcp ranges, with
-the appropriate network part inserted.
+the appropriate network part inserted. For IPv6, an address may include a prefix length:
+.B --dhcp-host=laptop,[1234:50/126]
+which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability
+to specify multiple addresses) is useful
+when a host presents either a consistent name or hardware-ID, but varying DUIDs, since it allows
+dnsmasq to honour the static address allocation but assign a different adddress for each DUID. This
+typically occurs when chain netbooting, as each stage of the chain gets in turn allocates an address.
+
Note that in IPv6 DHCP, the hardware address may not be
available, though it normally is for direct-connected clients, or
clients using DHCP relays which support RFC 6939.
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index d9719d1..5d437dd 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -271,26 +271,35 @@ 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;
-
- if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
- return 1;
#ifdef HAVE_DHCP6
- if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD))
- return 1;
-#endif
+ if (context->flags & CONTEXT_V6)
+ {
+ struct addrlist *addr_list;
- for (; context; context = context->current)
-#ifdef HAVE_DHCP6
- if (context->flags & CONTEXT_V6)
- {
- if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix))
- return 1;
- }
- else
+ if (!(config->flags & CONFIG_ADDR6))
+ return 1;
+
+ for (; context; context = context->current)
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
+ {
+ if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
+ return 1;
+
+ if (is_same_net6(&addr_list->addr.addr.addr6, &context->start6, context->prefix))
+ return 1;
+ }
+ }
+ else
#endif
- if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
+ {
+ if (!(config->flags & CONFIG_ADDR))
return 1;
+
+ for (; context; context = context->current)
+ if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
+ return 1;
+ }
return 0;
}
@@ -418,10 +427,21 @@ void dhcp_update_configs(struct dhcp_config *configs)
#ifdef HAVE_DHCP6
if (prot == AF_INET6 &&
- (!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
+ (!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr.addr.addr6)) || conf_tmp == config))
{
- memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
- config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
+ /* host must have exactly one address if comming from /etc/hosts. */
+ if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist))))
+ {
+ config->addr6->next = NULL;
+ config->addr6->flags = 0;
+ }
+
+ if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX)))
+ {
+ memcpy(&config->addr6->addr.addr.addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
+ config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
+ }
+
continue;
}
#endif
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 0853664..6f1f54e 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -384,21 +384,26 @@ static int complete_context6(struct in6_addr *local, int prefix,
return 1;
}
-struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
+struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, struct in6_addr *addr)
{
struct dhcp_config *config;
for (config = configs; config; config = config->next)
- if ((config->flags & CONFIG_ADDR6) &&
- is_same_net6(&config->addr6, net, prefix) &&
- (prefix == 128 || addr6part(&config->addr6) == addr))
- return config;
+ if (config->flags & CONFIG_ADDR6)
+ {
+ struct addrlist *addr_list;
+
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
+ if ((!net || is_same_net6(&addr_list->addr.addr.addr6, net, prefix) || ((addr_list->flags & ADDRLIST_WILDCARD) && prefix == 64)) &&
+ is_same_net6(&addr_list->addr.addr.addr6, addr, (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128))
+ return config;
+ }
return NULL;
}
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
- int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
+ unsigned int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
@@ -453,16 +458,15 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
for (d = context; d; d = d->current)
if (addr == addr6part(&d->local6))
break;
+
+ *ans = c->start6;
+ setaddr6part (ans, addr);
if (!d &&
!lease6_find_by_addr(&c->start6, c->prefix, addr) &&
- !config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
- {
- *ans = c->start6;
- setaddr6part (ans, addr);
- return c;
- }
-
+ !config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, ans))
+ return c;
+
addr++;
if (addr == addr6part(&c->end6) + 1)
@@ -516,27 +520,6 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
return NULL;
}
-int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
-{
- if (!config || !(config->flags & CONFIG_ADDR6))
- return 0;
-
- if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
- {
- *addr = context->start6;
- setaddr6part(addr, addr6part(&config->addr6));
- return 1;
- }
-
- if (is_same_net6(&context->start6, &config->addr6, context->prefix))
- {
- *addr = config->addr6;
- return 1;
- }
-
- return 0;
-}
-
void make_duid(time_t now)
{
(void)now;
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 6b18bb7..9437226 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -343,9 +343,11 @@ struct ds_config {
struct ds_config *next;
};
-#define ADDRLIST_LITERAL 1
-#define ADDRLIST_IPV6 2
-#define ADDRLIST_REVONLY 4
+#define ADDRLIST_LITERAL 1
+#define ADDRLIST_IPV6 2
+#define ADDRLIST_REVONLY 4
+#define ADDRLIST_PREFIX 8
+#define ADDRLIST_WILDCARD 16
struct addrlist {
struct all_addr addr;
@@ -748,7 +750,7 @@ struct dhcp_config {
char *hostname, *domain;
struct dhcp_netid_list *netid;
#ifdef HAVE_DHCP6
- struct in6_addr addr6;
+ struct addrlist *addr6;
#endif
struct in_addr addr;
time_t decline_time;
@@ -770,7 +772,7 @@ struct dhcp_config {
#define CONFIG_DECLINED 1024 /* address declined by client */
#define CONFIG_BANK 2048 /* from dhcp hosts file */
#define CONFIG_ADDR6 4096
-#define CONFIG_WILDCARD 8192
+#define CONFIG_ADDR6_HOSTS 16384 /* address added by from /etc/hosts */
struct dhcp_opt {
int opt, len, flags;
@@ -1463,8 +1465,7 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
void dhcp6_init(void);
void dhcp6_packet(time_t now);
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
- int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
-int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
+ unsigned int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids,
@@ -1474,7 +1475,7 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
struct dhcp_netid *netids,
int plain_range);
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
- int prefix, u64 addr);
+ int prefix, struct in6_addr *addr);
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
diff --git a/src/option.c b/src/option.c
index b12183b..ea70ee3 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1010,15 +1010,30 @@ static void dhcp_config_free(struct dhcp_config *config)
if (config)
{
struct hwaddr_config *hwaddr = config->hwaddr;
+
while (hwaddr)
{
struct hwaddr_config *tmp = hwaddr;
hwaddr = hwaddr->next;
free(tmp);
}
+
dhcp_netid_list_free(config->netid);
+
if (config->flags & CONFIG_CLID)
free(config->clid);
+
+ if (config->flags & CONFIG_ADDR6)
+ {
+ struct addrlist *addr, *tmp;
+
+ for (addr = config->addr6; addr; addr = tmp)
+ {
+ tmp = addr->next;
+ free(addr);
+ }
+ }
+
free(config);
}
}
@@ -3143,8 +3158,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_BANK:
case 'G': /* --dhcp-host */
{
- int j, k = 0;
- char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
struct dhcp_config *new;
struct in_addr in;
@@ -3155,197 +3168,222 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->hwaddr = NULL;
new->netid = NULL;
new->clid = NULL;
+ new->addr6 = NULL;
- if ((a[0] = arg))
- for (k = 1; k < 7; k++)
- if (!(a[k] = split(a[k-1])))
- break;
-
- for (j = 0; j < k; j++)
- if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
- {
- char *arg = a[j];
-
- if ((arg[0] == 'i' || arg[0] == 'I') &&
- (arg[1] == 'd' || arg[1] == 'D') &&
- arg[2] == ':')
- {
- if (arg[3] == '*')
- new->flags |= CONFIG_NOCLID;
- else
- {
- int len;
- arg += 3; /* dump id: */
- if (strchr(arg, ':'))
- len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
- else
- {
- unhide_metas(arg);
- len = (int) strlen(arg);
- }
-
- if (len == -1)
- {
- dhcp_config_free(new);
- ret_err(_("bad hex constant"));
- }
- else if ((new->clid = opt_malloc(len)))
- {
- new->flags |= CONFIG_CLID;
- new->clid_len = len;
- memcpy(new->clid, arg, len);
- }
- }
- }
- /* dhcp-host has strange backwards-compat needs. */
- else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
- {
- struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
- newlist->next = new->netid;
- new->netid = newlist;
- newlist->list = dhcp_netid_create(arg+4, NULL);
- }
- else if (strstr(arg, "tag:") == arg)
- {
-
- dhcp_config_free(new);
- ret_err(_("cannot match tags in --dhcp-host"));
- }
+ while (arg)
+ {
+ comma = split(arg);
+ if (strchr(arg, ':')) /* ethernet address, netid or binary CLID */
+ {
+ if ((arg[0] == 'i' || arg[0] == 'I') &&
+ (arg[1] == 'd' || arg[1] == 'D') &&
+ arg[2] == ':')
+ {
+ if (arg[3] == '*')
+ new->flags |= CONFIG_NOCLID;
+ else
+ {
+ int len;
+ arg += 3; /* dump id: */
+ if (strchr(arg, ':'))
+ len = parse_hex(arg, (unsigned char *)arg, -1, NULL, NULL);
+ else
+ {
+ unhide_metas(arg);
+ len = (int) strlen(arg);
+ }
+
+ if (len == -1)
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad hex constant"));
+ }
+ else if ((new->clid = opt_malloc(len)))
+ {
+ new->flags |= CONFIG_CLID;
+ new->clid_len = len;
+ memcpy(new->clid, arg, len);
+ }
+ }
+ }
+ /* dhcp-host has strange backwards-compat needs. */
+ else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
+ {
+ struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
+ newlist->next = new->netid;
+ new->netid = newlist;
+ newlist->list = dhcp_netid_create(arg+4, NULL);
+ }
+ else if (strstr(arg, "tag:") == arg)
+ {
+
+ dhcp_config_free(new);
+ ret_err(_("cannot match tags in --dhcp-host"));
+ }
#ifdef HAVE_DHCP6
- else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
- {
- arg[strlen(arg)-1] = 0;
- arg++;
-
- if (!inet_pton(AF_INET6, arg, &new->addr6))
- {
- dhcp_config_free(new);
- ret_err(_("bad IPv6 address"));
- }
-
- for (i= 0; i < 8; i++)
- if (new->addr6.s6_addr[i] != 0)
- break;
+ else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
+ {
+ char *pref;
+ struct in6_addr in6;
+ struct addrlist *new_addr;
+
+ arg[strlen(arg)-1] = 0;
+ arg++;
+ pref = split_chr(arg, '/');
+
+ if (!inet_pton(AF_INET6, arg, &in6))
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad IPv6 address"));
+ }
- /* set WILDCARD if network part all zeros */
- if (i == 8)
- new->flags |= CONFIG_WILDCARD;
+ new_addr = opt_malloc(sizeof(struct addrlist));
+ new_addr->next = new->addr6;
+ new_addr->flags = 0;
+ new_addr->addr.addr.addr6 = in6;
+ new->addr6 = new_addr;
+
+ if (pref)
+ {
+ u64 addrpart = addr6part(&in6);
+
+ if (!atoi_check(pref, &new_addr->prefixlen) ||
+ new_addr->prefixlen > 128 ||
+ (((1<<(128-new_addr->prefixlen))-1) & addrpart) != 0)
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad IPv6 prefix"));
+ }
+
+ new_addr->flags |= ADDRLIST_PREFIX;
+ }
- new->flags |= CONFIG_ADDR6;
- }
+ for (i= 0; i < 8; i++)
+ if (in6.s6_addr[i] != 0)
+ break;
+
+ /* set WILDCARD if network part all zeros */
+ if (i == 8)
+ new_addr->flags |= ADDRLIST_WILDCARD;
+
+ new->flags |= CONFIG_ADDR6;
+ }
#endif
- else
- {
- struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
- if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
- &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
- {
- free(newhw);
- dhcp_config_free(new);
- ret_err(_("bad hex constant"));
- }
- else
- {
- newhw->next = new->hwaddr;
- new->hwaddr = newhw;
- }
- }
- }
- else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
- {
- struct dhcp_config *configs;
-
- new->addr = in;
- new->flags |= CONFIG_ADDR;
-
- /* If the same IP appears in more than one host config, then DISCOVER
- for one of the hosts will get the address, but REQUEST will be NAKed,
- since the address is reserved by the other one -> protocol loop. */
- for (configs = daemon->dhcp_conf; configs; configs = configs->next)
- if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
+ else
{
- sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
- return 0;
- }
- }
- else
- {
- char *cp, *lastp = NULL, last = 0;
- int fac = 1, isdig = 0;
-
- if (strlen(a[j]) > 1)
- {
- lastp = a[j] + strlen(a[j]) - 1;
- last = *lastp;
- switch (last)
+ struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
+ if ((newhw->hwaddr_len = parse_hex(arg, newhw->hwaddr, DHCP_CHADDR_MAX,
+ &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
+ {
+ free(newhw);
+ dhcp_config_free(new);
+ ret_err(_("bad hex constant"));
+ }
+ else
+ {
+ newhw->next = new->hwaddr;
+ new->hwaddr = newhw;
+ }
+ }
+ }
+ else if (strchr(arg, '.') && (inet_pton(AF_INET, arg, &in) > 0))
+ {
+ struct dhcp_config *configs;
+
+ new->addr = in;
+ new->flags |= CONFIG_ADDR;
+
+ /* If the same IP appears in more than one host config, then DISCOVER
+ for one of the hosts will get the address, but REQUEST will be NAKed,
+ since the address is reserved by the other one -> protocol loop. */
+ for (configs = daemon->dhcp_conf; configs; configs = configs->next)
+ if ((configs->flags & CONFIG_ADDR) && configs->addr.s_addr == in.s_addr)
{
- case 'w':
- case 'W':
- fac *= 7;
- /* fall through */
- case 'd':
- case 'D':
- fac *= 24;
- /* fall through */
- case 'h':
- case 'H':
- fac *= 60;
- /* fall through */
- case 'm':
- case 'M':
- fac *= 60;
- /* fall through */
- case 's':
- case 'S':
- *lastp = 0;
- }
- }
-
- for (cp = a[j]; *cp; cp++)
- if (isdigit((unsigned char)*cp))
- isdig = 1;
- else if (*cp != ' ')
- break;
+ sprintf(errstr, _("duplicate dhcp-host IP address %s"), inet_ntoa(in));
+ return 0;
+ }
+ }
+ else
+ {
+ char *cp, *lastp = NULL, last = 0;
+ int fac = 1, isdig = 0;
+
+ if (strlen(arg) > 1)
+ {
+ lastp = arg + strlen(arg) - 1;
+ last = *lastp;
+ switch (last)
+ {
+ case 'w':
+ case 'W':
+ fac *= 7;
+ /* fall through */
+ case 'd':
+ case 'D':
+ fac *= 24;
+ /* fall through */
+ case 'h':
+ case 'H':
+ fac *= 60;
+ /* fall through */
+ case 'm':
+ case 'M':
+ fac *= 60;
+ /* fall through */
+ case 's':
+ case 'S':
+ *lastp = 0;
+ }
+ }
+
+ for (cp = arg; *cp; cp++)
+ if (isdigit((unsigned char)*cp))
+ isdig = 1;
+ else if (*cp != ' ')
+ break;
+
+ if (*cp)
+ {
+ if (lastp)
+ *lastp = last;
+ if (strcmp(arg, "infinite") == 0)
+ {
+ new->lease_time = 0xffffffff;
+ new->flags |= CONFIG_TIME;
+ }
+ else if (strcmp(arg, "ignore") == 0)
+ new->flags |= CONFIG_DISABLE;
+ else
+ {
+ if (!(new->hostname = canonicalise_opt(arg)) ||
+ !legal_hostname(new->hostname))
+ {
+ dhcp_config_free(new);
+ ret_err(_("bad DHCP host name"));
+ }
+
+ new->flags |= CONFIG_NAME;
+ new->domain = strip_hostname(new->hostname);
+ }
+ }
+ else if (isdig)
+ {
+ new->lease_time = atoi(arg) * fac;
+ /* Leases of a minute or less confuse
+ some clients, notably Apple's */
+ if (new->lease_time < 120)
+ new->lease_time = 120;
+ new->flags |= CONFIG_TIME;
+ }
+ }
+
+ arg = comma;
+ }
- if (*cp)
- {
- if (lastp)
- *lastp = last;
- if (strcmp(a[j], "infinite") == 0)
- {
- new->lease_time = 0xffffffff;
- new->flags |= CONFIG_TIME;
- }
- else if (strcmp(a[j], "ignore") == 0)
- new->flags |= CONFIG_DISABLE;
- else
- {
- if (!(new->hostname = canonicalise_opt(a[j])) ||
- !legal_hostname(new->hostname))
- {
- dhcp_config_free(new);
- ret_err(_("bad DHCP host name"));
- }
-
- new->flags |= CONFIG_NAME;
- new->domain = strip_hostname(new->hostname);
- }
- }
- else if (isdig)
- {
- new->lease_time = atoi(a[j]) * fac;
- /* Leases of a minute or less confuse
- some clients, notably Apple's */
- if (new->lease_time < 120)
- new->lease_time = 120;
- new->flags |= CONFIG_TIME;
- }
- }
-
daemon->dhcp_conf = new;
break;
}
-
+
case LOPT_TAG_IF: /* --tag-if */
{
struct tag_if *new = opt_malloc(sizeof(struct tag_if));
diff --git a/src/rfc3315.c b/src/rfc3315.c
index ee1cf17..ee58b57 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -55,6 +55,8 @@ static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte
static void mark_context_used(struct state *state, struct in6_addr *addr);
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
static int check_address(struct state *state, struct in6_addr *addr);
+static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state);
+static int config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
unsigned int *min_time, struct in6_addr *addr, time_t now);
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
@@ -717,7 +719,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
/* If the client asks for an address on the same network as a configured address,
offer the configured address instead, to make moving to newly-configured
addresses automatic. */
- if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
+ if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state))
{
req_addr = addr;
mark_config_used(c, &addr);
@@ -745,8 +747,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (c = state->context; c; c = c->current)
if (!(c->flags & CONTEXT_CONF_USED) &&
match_netid(c->filter, solicit_tags, plain_range) &&
- config_valid(config, c, &addr) &&
- check_address(state, &addr))
+ config_valid(config, c, &addr, state))
{
mark_config_used(state->context, &addr);
if (have_config(config, CONFIG_TIME))
@@ -895,14 +896,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
struct in6_addr req_addr;
struct dhcp_context *dynamic, *c;
unsigned int lease_time;
- struct in6_addr addr;
int config_ok = 0;
/* align. */
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
- config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr);
+ config_ok = config_implies(config, c, &req_addr);
if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
{
@@ -1032,12 +1032,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
(this_context = address6_valid(state->context, &req_addr, tagif, 1)))
{
- struct in6_addr addr;
unsigned int lease_time;
get_context_tag(state, this_context);
- if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
+ if (config_implies(config, this_context, &req_addr) && have_config(config, CONFIG_TIME))
lease_time = config->lease_time;
else
lease_time = this_context->lease_time;
@@ -1760,6 +1759,76 @@ static int check_address(struct state *state, struct in6_addr *addr)
}
+/* return true of *addr could have been generated from config. */
+static int config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
+{
+ int prefix;
+ struct in6_addr wild_addr;
+ struct addrlist *addr_list;
+
+ if (!config || !(config->flags & CONFIG_ADDR6))
+ return 0;
+
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
+ {
+ prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128;
+ wild_addr = addr_list->addr.addr.addr6;
+
+ if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
+ {
+ wild_addr = context->start6;
+ setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr.addr6));
+ }
+ else if (!is_same_net6(&context->start6, addr, context->prefix))
+ continue;
+
+ if (is_same_net6(&wild_addr, addr, prefix))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state)
+{
+ u64 addrpart, i, addresses;
+ struct addrlist *addr_list;
+
+ if (!config || !(config->flags & CONFIG_ADDR6))
+ return 0;
+
+ for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
+ {
+ addrpart = addr6part(&addr_list->addr.addr.addr6);
+ addresses = 1;
+
+ if (addr_list->flags & ADDRLIST_PREFIX)
+ addresses = 1<<(128-addr_list->prefixlen);
+
+ if ((addr_list->flags & ADDRLIST_WILDCARD))
+ {
+ if (context->prefix != 64)
+ continue;
+
+ *addr = context->start6;
+ }
+ else if (is_same_net6(&context->start6, &addr_list->addr.addr.addr6, context->prefix))
+ *addr = addr_list->addr.addr.addr6;
+ else
+ continue;
+
+ for (i = 0 ; i < addresses; i++)
+ {
+ setaddr6part(addr, addrpart+i);
+
+ if (check_address(state, addr))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* Calculate valid and preferred times to send in leases/renewals.
Inputs are:
--
1.8.3.1

View File

@ -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.
---
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))
--
2.25.4

View File

@ -1,322 +0,0 @@
From dd04a0d90d2fca66b5f91952ae7286c5de1714f1 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Fri, 7 Feb 2020 21:05:54 +0000
Subject: [PATCH] Add tag filtering of dhcp-host directives.
(cherry picked from commit 52ec7836139e7a11374971905e5ac0d2d02e32c0)
Conflicts:
CHANGELOG
src/rfc3315.c
---
man/dnsmasq.8 | 5 ++++-
src/dhcp-common.c | 42 ++++++++++++++++++++++++++++++++----------
src/dnsmasq.h | 4 +++-
src/lease.c | 2 +-
src/option.c | 14 ++++++--------
src/rfc2131.c | 6 +++---
src/rfc3315.c | 49 ++++++++++++++++++++++---------------------------
7 files changed, 71 insertions(+), 51 deletions(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 2c9d9f6..a59b06f 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -953,7 +953,7 @@ is also included, as described in RFC-3775 section 7.3.
tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
.TP
-.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
+.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
Specify per host parameters for the DHCP server. This allows a machine
with a particular hardware address to be always allocated the same
hostname, IP address and lease time. A hostname specified like this
@@ -1038,6 +1038,9 @@ ignore requests from unknown machines using
.B --dhcp-ignore=tag:!known
If the host matches only a dhcp-host directive which cannot
be used because it specifies an address on different subnet, the tag "known-othernet" is set.
+
+The tag:<tag> construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones.
+
Ethernet addresses (but not client-ids) may have
wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index 5d437dd..71e9e5b 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -304,11 +304,12 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_config
return 0;
}
-struct dhcp_config *find_config(struct dhcp_config *configs,
- struct dhcp_context *context,
- unsigned char *clid, int clid_len,
- unsigned char *hwaddr, int hw_len,
- int hw_type, char *hostname)
+static struct dhcp_config *find_config_match(struct dhcp_config *configs,
+ struct dhcp_context *context,
+ unsigned char *clid, int clid_len,
+ unsigned char *hwaddr, int hw_len,
+ int hw_type, char *hostname,
+ struct dhcp_netid *tags, int tag_not_needed)
{
int count, new;
struct dhcp_config *config, *candidate;
@@ -320,7 +321,9 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
- is_config_in_context(context, config))
+ is_config_in_context(context, config) &&
+ match_netid(config->filter, tags, tag_not_needed))
+
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
@@ -328,7 +331,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
see lease_update_from_configs() */
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
- is_config_in_context(context, config))
+ is_config_in_context(context, config) &&
+ match_netid(config->filter, tags, tag_not_needed))
return config;
}
@@ -336,14 +340,16 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
if (hwaddr)
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
- is_config_in_context(context, config))
+ is_config_in_context(context, config) &&
+ match_netid(config->filter, tags, tag_not_needed))
return config;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
- is_config_in_context(context, config))
+ is_config_in_context(context, config) &&
+ match_netid(config->filter, tags, tag_not_needed))
return config;
@@ -352,7 +358,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
- if (is_config_in_context(context, config))
+ if (is_config_in_context(context, config) &&
+ match_netid(config->filter, tags, tag_not_needed))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
@@ -366,6 +373,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
return candidate;
}
+/* Find tagged configs first. */
+struct dhcp_config *find_config(struct dhcp_config *configs,
+ struct dhcp_context *context,
+ unsigned char *clid, int clid_len,
+ unsigned char *hwaddr, int hw_len,
+ int hw_type, char *hostname, struct dhcp_netid *tags)
+{
+ struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
+
+ if (!ret)
+ ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
+
+ return ret;
+}
+
void dhcp_update_configs(struct dhcp_config *configs)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 9437226..055a0d1 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -749,6 +749,7 @@ struct dhcp_config {
unsigned char *clid; /* clientid */
char *hostname, *domain;
struct dhcp_netid_list *netid;
+ struct dhcp_netid *filter;
#ifdef HAVE_DHCP6
struct addrlist *addr6;
#endif
@@ -1514,7 +1515,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
- int hw_type, char *hostname);
+ int hw_type, char *hostname,
+ struct dhcp_netid *filter);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void);
diff --git a/src/lease.c b/src/lease.c
index 5c33df7..00c82f6 100644
--- a/src/lease.c
+++ b/src/lease.c
@@ -222,7 +222,7 @@ void lease_update_from_configs(void)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
- lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
+ lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
diff --git a/src/option.c b/src/option.c
index ea70ee3..88cd2ab 100644
--- a/src/option.c
+++ b/src/option.c
@@ -953,8 +953,7 @@ static char *set_prefix(char *arg)
return arg;
}
-static struct dhcp_netid *
-dhcp_netid_create(const char *net, struct dhcp_netid *next)
+static struct dhcp_netid *dhcp_netid_create(const char *net, struct dhcp_netid *next)
{
struct dhcp_netid *tt;
tt = opt_malloc(sizeof (struct dhcp_netid));
@@ -1019,7 +1018,8 @@ static void dhcp_config_free(struct dhcp_config *config)
}
dhcp_netid_list_free(config->netid);
-
+ dhcp_netid_free(config->filter);
+
if (config->flags & CONFIG_CLID)
free(config->clid);
@@ -3167,6 +3167,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
new->hwaddr = NULL;
new->netid = NULL;
+ new->filter = NULL;
new->clid = NULL;
new->addr6 = NULL;
@@ -3215,11 +3216,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
newlist->list = dhcp_netid_create(arg+4, NULL);
}
else if (strstr(arg, "tag:") == arg)
- {
-
- dhcp_config_free(new);
- ret_err(_("cannot match tags in --dhcp-host"));
- }
+ new->filter = dhcp_netid_create(arg+4, new->filter);
+
#ifdef HAVE_DHCP6
else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
{
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 997575a..a741f9f 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -479,7 +479,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->op = BOOTREPLY;
config = find_config(daemon->dhcp_conf, context, clid, clid_len,
- mess->chaddr, mess->hlen, mess->htype, NULL);
+ mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid));
/* set "known" tag for known hosts */
if (config)
@@ -489,7 +489,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid = &known_id;
}
else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len,
- mess->chaddr, mess->hlen, mess->htype, NULL))
+ mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid)))
{
known_id.net = "known-othernet";
known_id.next = netid;
@@ -725,7 +725,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
to avoid impersonation by name. */
struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
mess->chaddr, mess->hlen,
- mess->htype, hostname);
+ mess->htype, hostname, run_tag_if(netid));
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
{
config = new;
diff --git a/src/rfc3315.c b/src/rfc3315.c
index ee58b57..a0067e9 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -486,35 +486,29 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
}
- if (state->clid)
+ if (state->clid &&
+ (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len,
+ state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags))) &&
+ have_config(config, CONFIG_NAME))
{
- config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);
-
- if (have_config(config, CONFIG_NAME))
- {
- state->hostname = config->hostname;
- state->domain = config->domain;
- state->hostname_auth = 1;
- }
- else if (state->client_hostname)
- {
- state->domain = strip_hostname(state->client_hostname);
+ state->hostname = config->hostname;
+ state->domain = config->domain;
+ state->hostname_auth = 1;
+ }
+ else if (state->client_hostname)
+ {
+ state->domain = strip_hostname(state->client_hostname);
- if (strlen(state->client_hostname) != 0)
- {
- state->hostname = state->client_hostname;
- if (!config)
- {
- /* Search again now we have a hostname.
- Only accept configs without CLID here, (it won't match)
- to avoid impersonation by name. */
- struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
- if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
- config = new;
- }
- }
+ if (strlen(state->client_hostname) != 0)
+ {
+ /* Search again now we have a hostname.
+ Only accept configs without CLID here, (it won't match)
+ to avoid impersonation by name. */
+ struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, run_tag_if(state->tags));
+ if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
+ config = new;
}
- }
+ }
if (config)
{
@@ -535,7 +529,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ignore = 1;
}
else if (state->clid &&
- find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
+ find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len,
+ state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags)))
{
known_id.net = "known-othernet";
known_id.next = state->tags;
--
1.8.3.1

View File

@ -1,237 +0,0 @@
From 5010c42c47b7b5a3d68d83369d6c17ed0bc11cff Mon Sep 17 00:00:00 2001
From: Petr Mensik <pemensik@redhat.com>
Date: Wed, 17 Feb 2021 11:47:28 +0100
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.
Request sending ENOBUFS again
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 | 67 ++++++++++++++++++++++++++++++++++++---------------
src/network.c | 11 +++++++--
2 files changed, 57 insertions(+), 21 deletions(-)
diff --git a/src/netlink.c b/src/netlink.c
index ac1a1c5..f95f3e8 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -32,13 +32,21 @@
#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);
void netlink_init(void)
{
@@ -135,7 +143,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;
@@ -143,6 +153,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;
@@ -154,7 +165,6 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr.nl_groups = 0;
addr.nl_pid = 0; /* address to kernel */
- again:
if (family == AF_UNSPEC)
req.nlh.nlmsg_type = RTM_GETNEIGH;
else if (family == AF_LOCAL)
@@ -181,8 +191,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;
}
@@ -191,7 +201,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)
{
@@ -327,26 +337,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)
{
@@ -354,7 +374,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.
@@ -366,10 +387,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 c6e7d89..47caf38 100644
--- a/src/network.c
+++ b/src/network.c
@@ -656,7 +656,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;
@@ -709,10 +710,16 @@ int enumerate_interfaces(int reset)
#ifdef HAVE_IPV6
ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
+ if (ret < 0)
+ goto again;
#endif
if (ret)
- ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
+ {
+ ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
+ if (ret < 0)
+ goto again;
+ }
errsave = errno;
close(param.fd);
--
2.26.2

File diff suppressed because it is too large Load Diff

View File

@ -1,106 +0,0 @@
From 4cab3d930f9236408b838adfdaaeb6508a928bbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Fri, 9 Jun 2023 22:11:01 +0200
Subject: [PATCH] Use serv_domain only for regular servers
Do not try to use it for --local=/x/ or --address=/x/#. Some users use
quite long list of blocks, which slows down walking trough domain list
considerably. But searching by server_domain_find_domain is needed only
for normal servers, which may store there last used server and number
of recent forwarded queries. Local addresses overrides store there no
useful information, avoid searching and adding new domains for such
records.
Would also speed up searching servers when blocklists are used, because
only domains of servers are tested.
Resolves: rhbz#2209031
---
src/forward.c | 4 ++--
src/option.c | 13 ++++++++-----
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/src/forward.c b/src/forward.c
index d8e845a..989fb61 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -234,8 +234,8 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
*type = 0; /* use normal servers for this domain */
*domain = NULL;
}
- if (serv_domain && !*serv_domain)
- *serv_domain = server_domain_find_domain(*domain);
+ if (serv_domain && !*serv_domain && (*type & SERV_HAS_DOMAIN)==0)
+ *serv_domain = server_domain_find_domain(NULL);
return flags;
}
diff --git a/src/option.c b/src/option.c
index 1382c55..b22fc90 100644
--- a/src/option.c
+++ b/src/option.c
@@ -906,7 +906,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
p += sprintf(p, "in-addr.arpa");
serv->flags = SERV_HAS_DOMAIN;
- server_domain_new(serv);
+ serv->serv_domain = NULL;
serv->next = daemon->servers;
daemon->servers = serv;
@@ -931,7 +931,7 @@ static struct server *add_rev6(struct in6_addr *addr, int msize)
p += sprintf(p, "ip6.arpa");
serv->flags = SERV_HAS_DOMAIN;
- server_domain_new(serv);
+ serv->serv_domain = NULL;
serv->next = daemon->servers;
daemon->servers = serv;
@@ -2246,7 +2246,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
- server_domain_new(serv);
+ serv->serv_domain = NULL;
serv->next = daemon->servers;
daemon->servers = serv;
}
@@ -2291,7 +2291,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
- server_domain_new(serv);
+ serv->serv_domain = NULL;
serv->next = daemon->servers;
daemon->servers = serv;
}
@@ -2542,7 +2542,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
newlist = serv;
serv->domain = domain;
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
- server_domain_new(serv);
+ serv->serv_domain = NULL;
arg = end;
if (rebind)
break;
@@ -2594,6 +2594,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
server_list_free(newlist);
ret_err(err);
}
+ if ((newlist->flags & SERV_LITERAL_ADDRESS)==0)
+ server_domain_new(newlist);
}
serv = newlist;
@@ -2637,6 +2639,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
ret_err(gen_err);
+ server_domain_new(serv);
string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
if (string)
--
2.41.0

View File

@ -1,83 +0,0 @@
From 312e9f812a6b2f5ca2c2db866ffed3a0b289b945 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Wed, 10 May 2023 12:57:17 +0200
Subject: [PATCH] fixup! Correct releasing of serv_domain
---
src/dnsmasq.h | 2 +-
src/network.c | 20 +++++++++++---------
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index e8a1320..711ffd3 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1331,7 +1331,7 @@ int label_exception(int index, int family, struct all_addr *addr);
int fix_fd(int fd);
int tcp_interface(int fd, int af);
struct server_domain *server_domain_find_domain(const char *domain);
-struct server_domain *server_domain_new(struct server *serv);
+void server_domain_new(struct server *serv);
#ifdef HAVE_IPV6
int set_ipv6pktinfo(int fd);
#endif
diff --git a/src/network.c b/src/network.c
index b8d77fe..6faaad4 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1544,6 +1544,7 @@ void add_update_server(int flags,
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
+ server_domain_new(serv);
}
}
@@ -1571,14 +1572,20 @@ struct server_domain *server_domain_find_domain(const char *domain)
/**< Test structure has already set domain pointer.
*
* If not, create a new record. */
-struct server_domain *server_domain_new(struct server *serv)
+void server_domain_new(struct server *serv)
{
struct server_domain *sd;
+ const char *domain = server_get_domain(serv);
- if ((sd = whine_malloc(sizeof(struct server_domain))))
+ sd = server_domain_find_domain(domain);
+ if (sd)
{
- const char *domain = server_get_domain(serv);
+ serv->serv_domain = sd;
+ return;
+ }
+ if ((sd = whine_malloc(sizeof(struct server_domain))))
+ {
/* Ensure all serv->domain values have own record in server_domain.
* Add a new record. */
if (domain)
@@ -1592,7 +1599,6 @@ struct server_domain *server_domain_new(struct server *serv)
serv->serv_domain = sd;
daemon->server_domains = sd;
}
- return sd;
}
/**< Test structure has already set domain pointer.
@@ -1605,11 +1611,7 @@ static void server_domain_check(struct server *serv)
if (sd)
sd->flags &= (~SERV_MARK); /* found domain, mark active */
else
- {
- sd = server_domain_find_domain(serv->domain);
- if (!sd)
- server_domain_new(serv);
- }
+ server_domain_new(serv);
}
void check_servers(void)
--
2.40.1

View File

@ -1,108 +0,0 @@
From c0e0202736f55195104dad9fec98c20d0d15df21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Fri, 21 Apr 2023 17:04:53 +0200
Subject: [PATCH] Correct releasing of serv_domain
In case the server->serv_domain points to domain also when it is not the
last server used, ensure the reference to last_server is always reset.
Some records might reference the server_domain, but cannot ever become
last_server. Such as server=/example.com/#
Correct detection of used server_domains for standard resolvers case.
Mark domain used even in that case, so it is not freed during
resolv.conf reading or other nameservers change.
---
src/network.c | 40 +++++++++++++++++++++++++++++++---------
1 file changed, 31 insertions(+), 9 deletions(-)
diff --git a/src/network.c b/src/network.c
index cf2f2e2..8152cac 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1511,7 +1511,18 @@ void mark_servers(int flag)
}
}
-static void server_domains_cleanup(void)
+static void server_domains_pre_cleanup(void)
+{
+ struct server_domain *sd;
+
+ /* reset removed last_server. */
+ for (sd = daemon->server_domains; sd; sd = sd->next)
+ if ((sd->flags & SERV_MARK) == 0 && sd->last_server &&
+ (sd->last_server->flags & SERV_MARK) != 0)
+ sd->last_server = NULL;
+}
+
+static void server_domains_post_cleanup(void)
{
struct server_domain *sd, *tmp, **up;
@@ -1528,8 +1539,6 @@ static void server_domains_cleanup(void)
}
else {
up = &sd->next;
- if (sd->last_server && (sd->last_server->flags & SERV_MARK))
- sd->last_server = NULL;
}
}
}
@@ -1538,7 +1547,7 @@ void cleanup_servers(void)
{
struct server *serv, *tmp, **up;
- server_domains_cleanup();
+ server_domains_pre_cleanup();
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
@@ -1552,10 +1561,16 @@ void cleanup_servers(void)
free(serv->domain);
free(serv);
}
- else
- up = &serv->next;
+ else
+ {
+ up = &serv->next;
+ if (serv->serv_domain && (serv->serv_domain->flags & SERV_MARK) != 0)
+ serv->serv_domain = NULL;
+ }
}
+ server_domains_post_cleanup();
+
#ifdef HAVE_LOOP
/* Now we have a new set of servers, test for loops. */
loop_send_probes();
@@ -1699,7 +1714,11 @@ static void server_domain_check(struct server *serv)
if (sd)
sd->flags &= (~SERV_MARK); /* found domain, mark active */
else
- server_domain_new(serv);
+ {
+ sd = server_domain_find_domain(serv->domain);
+ if (!sd)
+ server_domain_new(serv);
+ }
}
void check_servers(void)
@@ -1808,8 +1827,11 @@ void check_servers(void)
else if (strlen(serv->domain) == 0)
s1 = _("default"), s2 = "";
else
- s1 = _("domain"), s2 = serv->domain;
-
+ {
+ s1 = _("domain"), s2 = serv->domain;
+ server_domain_check(serv);
+ }
+
if (serv->flags & SERV_NO_ADDR)
{
count--;
--
2.39.2

View File

@ -1,28 +0,0 @@
From 9e2b6474f2074511c3911b2f777e8e8704782670 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Wed, 22 Sep 2021 14:54:01 +0200
Subject: [PATCH] Add support for option6 names of RFC 5970
Client Network Interface Identifier and Client System Architecture Type
options were not understood by dnsmasq. Add it to supported option
types.
---
src/dhcp-common.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index 224c4d6..368d686 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -645,6 +645,8 @@ static const struct opttab_t opttab6[] = {
{ "ntp-server", 56, 0 },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
+ { "client-arch", 61, 2 | OT_DEC }, /* RFC 5970 */
+ { "client-interface-id", 62, 1 | OT_DEC }, /* RFC 5970 */
{ NULL, 0, 0 }
};
#endif
--
2.31.1

View File

@ -1,172 +0,0 @@
From 471cd540e755d2a5e92b4e8cd2ab2027beaba449 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Thu, 31 Mar 2022 21:35:20 +0100
Subject: [PATCH] Fix write-after-free error in DHCPv6 code. CVE-2022-0934
refers.
---
src/rfc3315.c | 48 +++++++++++++++++++++++++++---------------------
1 file changed, 27 insertions(+), 21 deletions(-)
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 554b1fe..bc77fbf 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -36,9 +36,9 @@ struct state {
#endif
};
-static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
+static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
struct in6_addr *client_addr, int is_unicast, time_t now);
-static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);
+static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now);
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
@@ -110,12 +110,12 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
}
/* This cost me blood to write, it will probably cost you blood to understand - srk. */
-static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
+static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
struct in6_addr *client_addr, int is_unicast, time_t now)
{
void *end = inbuff + sz;
void *opts = inbuff + 34;
- int msg_type = *((unsigned char *)inbuff);
+ int msg_type = *inbuff;
unsigned char *outmsgtypep;
void *opt;
struct dhcp_vendor *vendor;
@@ -241,15 +241,15 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
return 1;
}
-static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now)
+static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now)
{
void *opt;
- int i, o, o1, start_opts;
+ int i, o, o1, start_opts, start_msg;
struct dhcp_opt *opt_cfg;
struct dhcp_netid *tagif;
struct dhcp_config *config = NULL;
struct dhcp_netid known_id, iface_id, v6_id;
- unsigned char *outmsgtypep;
+ unsigned char outmsgtype;
struct dhcp_vendor *vendor;
struct dhcp_context *context_tmp;
struct dhcp_mac *mac_opt;
@@ -285,12 +285,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
v6_id.next = state->tags;
state->tags = &v6_id;
- /* copy over transaction-id, and save pointer to message type */
- if (!(outmsgtypep = put_opt6(inbuff, 4)))
+ start_msg = save_counter(-1);
+ /* copy over transaction-id */
+ if (!put_opt6(inbuff, 4))
return 0;
start_opts = save_counter(-1);
- state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
-
+ state->xid = inbuff[3] | inbuff[2] << 8 | inbuff[1] << 16;
+
/* We're going to be linking tags from all context we use.
mark them as unused so we don't link one twice and break the list */
for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
@@ -336,7 +337,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
{
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6USEMULTI);
put_opt6_string("Use multicast");
@@ -600,11 +601,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
struct dhcp_netid *solicit_tags;
struct dhcp_context *c;
- *outmsgtypep = DHCP6ADVERTISE;
+ outmsgtype = DHCP6ADVERTISE;
if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
{
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
state->lease_allocate = 1;
o = new_opt6(OPTION6_RAPID_COMMIT);
end_opt6(o);
@@ -876,7 +877,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
int start = save_counter(-1);
/* set reply message type */
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
state->lease_allocate = 1;
log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
@@ -992,7 +993,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
case DHCP6RENEW:
{
/* set reply message type */
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
log6_quiet(state, "DHCPRENEW", NULL, NULL);
@@ -1104,7 +1105,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
int good_addr = 0;
/* set reply message type */
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
@@ -1168,7 +1169,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
if (ignore)
return 0;
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
tagif = add_options(state, 1);
break;
}
@@ -1177,7 +1178,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
case DHCP6RELEASE:
{
/* set reply message type */
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
log6_quiet(state, "DHCPRELEASE", NULL, NULL);
@@ -1242,7 +1243,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
case DHCP6DECLINE:
{
/* set reply message type */
- *outmsgtypep = DHCP6REPLY;
+ outmsgtype = DHCP6REPLY;
log6_quiet(state, "DHCPDECLINE", NULL, NULL);
@@ -1321,7 +1322,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
}
-
+
+ /* Fill in the message type. Note that we store the offset,
+ not a direct pointer, since the packet memory may have been
+ reallocated. */
+ ((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype;
+
log_tags(tagif, state->xid);
log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
--
2.39.1

View File

@ -1,64 +0,0 @@
From e342e4d5c3093d8dd9e2d622e46d36f67bfb4925 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Mon, 10 Jan 2022 12:34:42 +0100
Subject: [PATCH] Add root group writeable flag to log file
Some systems strips even root process capability of writing to different
users file. That include systemd under Fedora. When
log-facility=/var/log/dnsmasq.log is used, log file with mode 0640
is created. But restart then fails, because such log file can be used
only when created new. Existing file cannot be opened by root when
starting, causing fatal error. Avoid that by adding root group writeable flag.
Ensure group is always root when granting write access. If it is
anything else, administrator has to configure correct rights.
(cherry picked from commit 1f8f78a49b8fd6b2862a3882053b1c6e6e111e5c)
---
src/log.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/src/log.c b/src/log.c
index 1ec3447..bcd6e52 100644
--- a/src/log.c
+++ b/src/log.c
@@ -100,10 +100,23 @@ int log_start(struct passwd *ent_pw, int errfd)
/* If we're running as root and going to change uid later,
change the ownership here so that the file is always owned by
the dnsmasq user. Then logrotate can just copy the owner.
- Failure of the chown call is OK, (for instance when started as non-root) */
- if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0 &&
- fchown(log_fd, ent_pw->pw_uid, -1) != 0)
- ret = errno;
+ Failure of the chown call is OK, (for instance when started as non-root).
+
+ If we've created a file with group-id root, we also make
+ the file group-writable. This gives processes in the root group
+ write access to the file and avoids the problem that on some systems,
+ once the file is owned by the dnsmasq user, it can't be written
+ whilst dnsmasq is running as root during startup.
+ */
+ if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0)
+ {
+ struct stat ls;
+ if (getgid() == 0 && fstat(log_fd, &ls) == 0 && ls.st_gid == 0 &&
+ (ls.st_mode & S_IWGRP) == 0)
+ (void)fchmod(log_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+ if (fchown(log_fd, ent_pw->pw_uid, -1) != 0)
+ ret = errno;
+ }
return ret;
}
@@ -118,7 +131,7 @@ int log_reopen(char *log_file)
/* NOTE: umask is set to 022 by the time this gets called */
if (log_file)
- log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
+ log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
else
{
#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
--
2.40.1

View File

@ -1,45 +0,0 @@
From 9d8270be2e2b31437684f2d87add9a28a41f0c75 Mon Sep 17 00:00:00 2001
From: Simon Kelley <simon@thekelleys.org.uk>
Date: Tue, 7 Mar 2023 22:07:46 +0000
Subject: [PATCH] Set the default maximum DNS UDP packet size to 1232.
http://www.dnsflagday.net/2020/ refers.
Thanks to Xiang Li for the prompt.
(cherry picked from commit eb92fb32b746f2104b0f370b5b295bb8dd4bd5e5)
---
man/dnsmasq.8 | 3 ++-
src/config.h | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index fce580f..4b0b180 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -171,7 +171,8 @@ to zero completely disables DNS function, leaving only DHCP and/or TFTP.
.TP
.B \-P, --edns-packet-max=<size>
Specify the largest EDNS.0 UDP packet which is supported by the DNS
-forwarder. Defaults to 4096, which is the RFC5625-recommended size.
+forwarder. Defaults to 1232, which is the recommended size following the
+DNS flag day in 2020. Only increase if you know what you are doing.
.TP
.B \-Q, --query-port=<query_port>
Send outbound DNS queries from, and listen for their replies on, the
diff --git a/src/config.h b/src/config.h
index 8c41943..62b7fa1 100644
--- a/src/config.h
+++ b/src/config.h
@@ -19,7 +19,7 @@
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
-#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
+#define EDNS_PKTSZ 1232 /* default max EDNS.0 UDP packet from from /dnsflagday.net/2020 */
#define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
--
2.39.2

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +0,0 @@
[Unit]
Description=DNS caching server.
After=network.target
[Service]
ExecStart=/usr/sbin/dnsmasq -k
[Install]
WantedBy=multi-user.target

1
ci.fmf Normal file
View File

@ -0,0 +1 @@
resultsdb-testcase: separate

View File

@ -0,0 +1,50 @@
From 6fda9cd7cba519a8aa96b43ebc34cb6c46b3bfe7 Mon Sep 17 00:00:00 2001
From: Doran Moppert <dmoppert@redhat.com>
Date: Tue, 26 Sep 2017 14:48:20 +0930
Subject: [PATCH] google patch hand-applied
---
src/edns0.c | 10 +++++-----
src/rfc1035.c | 5 ++++-
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/edns0.c b/src/edns0.c
index 598478f..72127e5 100644
--- a/src/edns0.c
+++ b/src/edns0.c
@@ -209,11 +209,11 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
/* Copy back any options */
if (buff)
{
- if (p + rdlen > limit)
- {
- free(buff);
- return plen; /* Too big */
- }
+ if (p + rdlen > limit)
+ {
+ free(buff);
+ return plen; /* Too big */
+ }
memcpy(p, buff, rdlen);
free(buff);
p += rdlen;
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 387d894..7fb1468 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -1581,7 +1581,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
size_t len;
int rd_bit = (header->hb3 & HB3_RD);
int count = 255; /* catch loops */
-
+
+ // Make sure we do not underflow here too.
+ if (qlen > (limit - ((char *)header))) return 0;
+
if (stale)
*stale = 0;
--
2.43.0

View File

@ -1,4 +1,4 @@
From 89f57e39b69f92beacb6bad9c68d61f9c4fb0e77 Mon Sep 17 00:00:00 2001
From 7b1cce1d0bdb61c09946978d4bdeb05a3cd4202a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Fri, 2 Mar 2018 13:17:04 +0100
Subject: [PATCH] Print warning on FIPS machine with dnssec enabled. Dnsmasq
@ -9,7 +9,7 @@ Subject: [PATCH] Print warning on FIPS machine with dnssec enabled. Dnsmasq
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index ce44809..9f6c020 100644
index 480c5f9..5fd229e 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -187,6 +187,7 @@ int main (int argc, char **argv)
@ -20,10 +20,10 @@ index ce44809..9f6c020 100644
#else
die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
#endif
@@ -769,7 +770,10 @@ int main (int argc, char **argv)
}
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
@@ -786,7 +787,10 @@ int main (int argc, char **argv)
my_syslog(LOG_INFO, _("DNSSEC validation enabled but all unsigned answers are trusted"));
else
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
-
+
+ if (access("/etc/system-fips", F_OK) == 0)

View File

@ -0,0 +1,91 @@
From cba77f08dbded8af45de2ee985200b12de7c8d13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Tue, 30 Jun 2020 18:06:29 +0200
Subject: [PATCH] Modify upstream configuration to safe defaults
Most important change would be to listen only on localhost. Default
configuration should not listen to request from remote hosts. Match also
user and paths to directories shipped in Fedora.
---
dnsmasq.conf.example | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example
index 0cbf572..6c47c3c 100644
--- a/dnsmasq.conf.example
+++ b/dnsmasq.conf.example
@@ -22,7 +22,7 @@
# Uncomment these to enable DNSSEC validation and caching:
# (Requires dnsmasq to be built with DNSSEC option.)
-#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
+#conf-file=/usr/share/dnsmasq/trust-anchors.conf
#dnssec
# Replies which are not DNSSEC signed may be legitimate, because the domain
@@ -106,8 +106,8 @@
# If you want dnsmasq to change uid and gid to something other
# than the default, edit the following lines.
-#user=
-#group=
+user=dnsmasq
+group=dnsmasq
# If you want dnsmasq to listen for DHCP and DNS requests only on
# specified interfaces (and the loopback) give the name of the
@@ -124,6 +124,14 @@
# disable DHCP and TFTP on it.
#no-dhcp-interface=
+# Serve DNS and DHCP only to networks directly connected to this machine.
+# Any interface= line will override it.
+#local-service
+# Accept queries in default configuration only from localhost
+# Comment out following option or explicitly configure interfaces or
+# listen-address
+local-service=host
+
# On systems which support it, dnsmasq binds the wildcard address,
# even when it is listening on only some interfaces. It then discards
# requests that it shouldn't reply to. This has the advantage of
@@ -131,7 +139,15 @@
# want dnsmasq to really bind only the interfaces it is listening on,
# uncomment this option. About the only time you may need this is when
# running another nameserver on the same machine.
+#
+# To listen only on localhost and do not receive packets on other
+# interfaces, bind only to lo device. Comment out to bind on single
+# wildcard socket.
#bind-interfaces
+# Comment out above line and uncoment following 2 lines.
+# Update interface name, use ip link to get its name.
+#bind-dynamic
+#interface=eno1
# If you don't want dnsmasq to read /etc/hosts, uncomment the
# following line.
@@ -545,7 +561,7 @@
# The DHCP server needs somewhere on disk to keep its lease database.
# This defaults to a sane location, but if you want to change it, use
# the line below.
-#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
+#dhcp-leasefile=/var/lib/dnsmasq/dnsmasq.leases
# Set the DHCP server to authoritative mode. In this mode it will barge in
# and take over the lease for any client which broadcasts on the network,
@@ -683,7 +699,11 @@
# Include all files in a directory which end in .conf
#conf-dir=/etc/dnsmasq.d/,*.conf
+# Include all files in /etc/dnsmasq.d except RPM backup files
+conf-dir=/etc/dnsmasq.d,.rpmnew,.rpmsave,.rpmorig
+
# If a DHCP client claims that its name is "wpad", ignore that.
# This fixes a security hole. see CERT Vulnerability VU#598349
#dhcp-name-match=set:wpad-ignore,wpad
#dhcp-ignore-names=tag:wpad-ignore
+
--
2.43.0

View File

@ -0,0 +1,67 @@
From 3ae3f53359a6e40535dac1cfd4887e80331a48fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Wed, 13 Oct 2021 16:58:39 +0200
Subject: [PATCH] Ensure serverarray is rebuilt once server can be removed
Because cleanup_servers is called from each place which can remove
server, use that function to refresh serverarray after changes. Make it
static, since it does not have to be called from other places.
---
src/dnsmasq.h | 1 -
src/domain-match.c | 8 +++++++-
src/network.c | 1 -
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 36d17fe..e46dba2 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1810,7 +1810,6 @@ void dump_packet_icmp(int mask, void *packet, size_t len, union mysockaddr *src,
#endif
/* domain-match.c */
-void build_server_array(void);
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout);
int filter_servers(int seed, int flags, int *lowout, int *highout);
int is_local_answer(time_t now, int first, char *name);
diff --git a/src/domain-match.c b/src/domain-match.c
index f7db0fe..d5840d9 100644
--- a/src/domain-match.c
+++ b/src/domain-match.c
@@ -23,7 +23,7 @@ static int order_servers(struct server *s, struct server *s2);
/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain. */
#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
-void build_server_array(void)
+static void build_server_array(void)
{
struct server *serv;
int count = 0;
@@ -602,6 +602,12 @@ void cleanup_servers(void)
daemon->servers_tail = serv;
}
}
+
+ /* If we're delaying things, we don't call check_servers(), but
+ reload_servers() may have deleted some servers, rendering the server_array
+ invalid, so just rebuild that here. Once reload_servers() succeeds,
+ we call check_servers() above, which calls build_server_array itself. */
+ build_server_array();
}
int add_update_server(int flags,
diff --git a/src/network.c b/src/network.c
index 6166484..f9dbcd8 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1701,7 +1701,6 @@ void check_servers(int no_loop_check)
}
cleanup_servers(); /* remove servers we just deleted. */
- build_server_array();
}
/* Return zero if no servers found, in that case we keep polling.
--
2.37.3

15
dnsmasq.service Normal file
View File

@ -0,0 +1,15 @@
[Unit]
Description=DNS caching server.
Before=nss-lookup.target
Wants=nss-lookup.target
After=network.target
; Use bind-dynamic or uncomment following to listen on non-local IP address
;After=network-online.target
[Service]
ExecStart=/usr/sbin/dnsmasq
Type=forking
PIDFile=/run/dnsmasq.pid
[Install]
WantedBy=multi-user.target

View File

@ -1,3 +1,5 @@
%bcond_without i18n
%define testrelease 0
%define releasecandidate 0
%if 0%{testrelease}
@ -10,109 +12,62 @@
%endif
%define _hardened_build 1
# path to upstream git repository
%global forgeurl0 git://thekelleys.org.uk/dnsmasq.git
# tag of selected version
%global gittag v%{version}%{?extraversion}
# Attempt to prepare source-git with downstream repos
%bcond_with sourcegit
Name: dnsmasq
Version: 2.79
Release: 33%{?extraversion:.%{extraversion}}%{?dist}
Version: 2.90
Release: 3%{?extraversion:.%{extraversion}}%{?dist}
Summary: A lightweight DHCP/caching DNS server
License: GPLv2 or GPLv3
# SPDX identifiers already
License: GPL-2.0-only OR GPL-3.0-only
URL: http://www.thekelleys.org.uk/dnsmasq/
Source0: http://www.thekelleys.org.uk/dnsmasq/%{?extrapath}%{name}-%{version}%{?extraversion}.tar.xz
VCS: git:%{forgeurl0}
Source0: %{url}%{?extrapath}%{name}-%{version}%{?extraversion}.tar.xz
Source1: %{name}.service
Source2: dnsmasq-systemd-sysusers.conf
Source3: %{url}%{?extrapath}%{name}-%{version}%{?extraversion}.tar.xz.asc
# GPG public key
%if 0%{?testrelease} || 0%{?releasecandidate}
Source4: %{url}%{?extrapath}test-release-public-key
%else
Source4: http://www.thekelleys.org.uk/srkgpg.txt
%endif
# https://bugzilla.redhat.com/show_bug.cgi?id=1495409
Patch1: dnsmasq-2.77-underflow.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1852373
Patch2: dnsmasq-2.81-configuration.patch
Patch3: dnsmasq-2.78-fips.patch
Patch4: dnsmasq-2.80-dnssec.patch
Patch5: dnsmasq-2.79-rh1602477.patch
# Few changes not yet in upstream
Patch6: dnsmasq-2.79-rh1602477-2.patch
# commit 60ac10d8d86e6f95ab0f06abe6c42596adcedcb8
Patch7: dnsmasq-2.76-rh1752569.patch
# Report failure when no release would be sent
Patch8: dnsmasq-2.79-rh1749092-fail.patch
Patch9: dnsmasq-2.76-rh1728698-1.patch
Patch10: dnsmasq-2.79-rh1728698-2.patch
Patch11: dnsmasq-2.76-rh1728698-3.patch
Patch12: dnsmasq-2.79-rh1728698-4.patch
Patch13: dnsmasq-2.79-rh1746411.patch
Patch14: dnsmasq-2.79-rh1700916.patch
Patch15: dnsmasq-2.80-rh1795370.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1779187
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=97f876b64c22b2b18412e2e3d8506ee33e42db7c
Patch16: dnsmasq-2.80-unaligned-addresses-in-DHCPv6-packet.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=f064188032a829efdcf3988b24ac795ff52785ec
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=137286e9baecf6a3ba97722ef1b49c851b531810
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=79aba0f10ad0157fb4f48afbbcb03f094caff97a
Patch17: dnsmasq-2.81-prefix-ranges-or-list-of-ipv6-addresses.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=52ec7836139e7a11374971905e5ac0d2d02e32c0
Patch18: dnsmasq-2.81-tag-filtering-of-dhcp-host-directives.patch
Patch19: dnsmasq-2.81-correct-range-check-of-dhcp-host-prefix.patch
Patch20: dnsmasq-2.81-optimize-fds-close.patch
Patch21: dnsmasq-2.81-rh1829448.patch
Patch22: dnsmasq-2.79-CVE-2020-25681.patch
Patch23: dnsmasq-2.79-CVE-2020-25684.patch
Patch24: dnsmasq-2.79-CVE-2020-25685.patch
Patch25: dnsmasq-2.79-CVE-2020-25686.patch
Patch26: dnsmasq-2.79-CVE-2020-25686-2.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=3f535da79e7a42104543ef5c7b5fa2bed819a78b
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=04490bf622ac84891aad6f2dd2edf83725decdee
Patch27: dnsmasq-2.79-mixed-family-failed.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=b2ed691eb3ca6488a8878f5f3dd950a07b14a9db
Patch28: dnsmasq-2.81-netlink-table.patch
Patch29: dnsmasq-2.84-bind-dynamic-netlink.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=74d4fcd756a85bc1823232ea74334f7ccfb9d5d2
Patch30: dnsmasq-2.85-CVE-2021-3448.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=03212e533b1e07aba30d2f4112009dc3af867ea5
Patch31: dnsmasq-2.80-man-nameing.patch
Patch32: dnsmasq-2.79-alternative-lease.patch
Patch33: dnsmasq-2.86-dhcpv6-client-arch.patch
# Downstream only patch; https://bugzilla.redhat.com/show_bug.cgi?id=1919894
# Similar functionality is implemented since 2.86 in upstream, but introduced
# several regressions. This implements just limited change in different way.
Patch34: dnsmasq-2.79-server-domain-rh1919894.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=03345ecefeb0d82e3c3a4c28f27c3554f0611b39
Patch35: dnsmasq-2.87-CVE-2022-0934.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=dded78b2338147daf69064d6d48c16b12744e441
Patch36: dnsmasq-2.81-option6-ntp-server-suboption.patch
# https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;h=3052ce208acf602f0163166dcefb7330d537cedb
Patch37: dnsmasq-2.81-linux-SIOCGSTAMP.patch
# Downstream only patch; fixes Patch34 change
Patch38: dnsmasq-2.79-server-domain-fixup.patch
# https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;h=f8c77edbdffb8ada7753ea9fa104f0f6da70cfe3
Patch39: dnsmasq-2.81-dhcpv6-relay-link-address.patch
# https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;h=eb92fb32b746f2104b0f370b5b295bb8dd4bd5e5
Patch40: dnsmasq-2.89-edns0-size.patch
# Downstream only patch; https://bugzilla.redhat.com/show_bug.cgi?id=2186481
# Fixes issue in Patch4
Patch41: dnsmasq-2.85-serv_domain-rh2186481.patch
# Downstream only patch; https://bugzilla.redhat.com/show_bug.cgi?id=2186481
# complements patch10
Patch42: dnsmasq-2.85-serv_domain-rh2186481-2.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=1f8f78a49b8fd6b2862a3882053b1c6e6e111e5c
Patch43: dnsmasq-2.87-log-root-writeable.patch
# Downstream only patch; https://bugzilla.redhat.com/show_bug.cgi?id=2209031
# complements patch42
Patch44: dnsmasq-2.85-domain-blocklist-speedup.patch
# http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=dd33e98da09c487a58b6cb6693b8628c0b234a3b
Patch45: dnsmasq-2.80-synth-domain-RHEL-15216.patch
# https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=214a046f47b9f7dd56f5eef3a8678ccbd6e973b7
Patch46: dnsmasq-2.90-CVE-2023-50387-CVE-2023-50868.patch
# This is workaround to nettle bug #1549190
# https://bugzilla.redhat.com/show_bug.cgi?id=1549190
Requires: nettle >= 3.4
Requires: nettle
BuildRequires: dbus-devel
BuildRequires: pkgconfig
BuildRequires: libidn2-devel
BuildRequires: pkgconfig(libnetfilter_conntrack)
BuildRequires: nettle-devel
Buildrequires: gcc
BuildRequires: gnupg2
BuildRequires: systemd
%{?systemd_requires}
BuildRequires: systemd-rpm-macros
%{?systemd_ordering}
%if %{with sourcegit}
BuildRequires: git-core
%endif
BuildRequires: make
%if %{with i18n}
BuildRequires: gettext
%endif
%description
Dnsmasq is lightweight, easy to configure DNS forwarder and DHCP server.
@ -121,7 +76,7 @@ It can serve the names of local machines which are not in the global
DNS. The DHCP server integrates with the DNS server and allows machines
with DHCP-allocated addresses to appear in the DNS with names configured
either in each host or in a central configuration file. Dnsmasq supports
static and dynamic DHCP leases and BOOTP for network booting of diskless
static and dynamic DHCP leases and BOOTP for network booting of disk-less
machines.
%package utils
@ -131,86 +86,63 @@ Summary: Utilities for manipulating DHCP server leases
Utilities that use the standard DHCP protocol to query/remove a DHCP
server's leases.
%if %{with i18n}
%package langpack
Summary: Translations for few languages
License: LicenseRef-Fedora-Public-Domain AND GPL-2.0-or-later
BuildArch: noarch
Requires: %{name} = %{version}-%{release}
# Will not do separate packages for every single language, those translations are small enough
Supplements: (%{name} = %{version}-%{release} and (langpacks-de or langpacks-es or langpacks-fi or langpacks-fr or langpacks-id or langpacks-it or langpacks-ka or langpacks-no or langpacks-pl or langpacks-pt_BR or langpacks-ro) )
%description langpack
Translations for few languages on dnsmasq.
%endif
%prep
%setup -q -n %{name}-%{version}%{?extraversion}
%patch1 -p1 -b .underflow
%patch3 -p1 -b .fips
%patch4 -p1 -b .dnssec
%patch5 -p1 -b .rh1602477
%patch6 -p1 -b .rh1602477-2
%patch7 -p1 -b .rh1752569
%patch8 -p1 -b .rh1752569
%patch9 -p1 -b .rh1728698-1
%patch10 -p1 -b .rh1728698-2
%patch11 -p1 -b .rh1728698-3
%patch12 -p1 -b .rh1728698-4
%patch13 -p1 -b .rh1746411
%patch14 -p1 -b .rh1700916
%patch15 -p1 -b .rh1795370
%patch16 -p1 -b .rh1779187-1
%patch17 -p1 -b .rh1779187-2
%patch18 -p1 -b .rh1779187-3
%patch19 -p1 -b .rh1779187-4
%patch20 -p1 -b .rh1816613
%patch21 -p1 -b .rh1829448
%patch22 -p1 -b .CVE-2020-25681
%patch23 -p1 -b .CVE-2020-25684
%patch24 -p1 -b .CVE-2020-25685
%patch25 -p1 -b .CVE-2020-25686
%patch26 -p1 -b .CVE-2020-25686-2
%patch27 -p1 -b .rh1921153
%patch28 -p1 -b .rh1887649-table
%patch29 -p1 -b .rh1887649
%patch30 -p1 -b .CVE-2021-3448
%patch31 -p1 -b .rh1947039
%patch32 -p1 -b .rh1998448
%patch33 -p1 -b .dhcpv6-client-arch
%patch34 -p1 -b .rh1919894
%patch35 -p1 -b .CVE-2022-0934
%patch36 -p1 -b .rh2049691
%patch37 -p1 -b .SIOCGSTAMP
%patch38 -p1 -b .rh2120357
%patch39 -p1 -b .rh2169355
%patch40 -p1 -b .CVE-2023-28450
%patch41 -p1 -b .rh2186481
%patch42 -p1 -b .rh2186481-2
%patch43 -p1 -b .rh2156789
%patch44 -p1 -b .rh2209031
%patch45 -p1 -b .RHEL-15216
%patch46 -p1 -b .CVE-2023-50387-CVE-2023-50868
%if 0%{?fedora}
%gpgverify -k 4 -s 3 -d 0
%endif
%if %{with sourcegit}
%autosetup -n %{name}-%{version}%{?extraversion} -N -S git_am
# If preparing with sourcegit, drop again source directory
# and clone git repository
# FIXME: deleting just unpacked sources is dangerous
# But using %%setup changes used directories in %%build and %%install
rm -rf %{_builddir}/%{name}-%{version}%{?extraversion}
cd %{_builddir}
git clone -b %{gittag} %{forgeurl0} %{name}-%{version}%{?extraversion}
cd %{name}-%{version}%{?extraversion}
git checkout -b rpmbuild
%else
%autosetup -n %{name}-%{version}%{?extraversion} -N
%endif
# Apply patches on top
%autopatch -p1
# use /var/lib/dnsmasq instead of /var/lib/misc
for file in dnsmasq.conf.example man/dnsmasq.8 man/es/dnsmasq.8 src/config.h; do
sed -i 's|/var/lib/misc/dnsmasq.leases|/var/lib/dnsmasq/dnsmasq.leases|g' "$file"
done
# fix the path to the trust anchor
sed -i 's|%%%%PREFIX%%%%|%{_prefix}|' dnsmasq.conf.example
#set dnsmasq user / group
sed -i 's|#user=|user=dnsmasq|' dnsmasq.conf.example
sed -i 's|#group=|group=dnsmasq|' dnsmasq.conf.example
#set default user /group in src/config.h
sed -i 's|#define CHUSER "nobody"|#define CHUSER "dnsmasq"|' src/config.h
sed -i 's|#define CHGRP "dip"|#define CHGRP "dnsmasq"|' src/config.h
sed -i "s|\(#\s*define RUNFILE\) \"/var/run/dnsmasq.pid\"|\1 \"%{_rundir}/dnsmasq.pid\"|" src/config.h
# optional parts
sed -i 's|^COPTS[[:space:]]*=|\0 -DHAVE_DBUS -DHAVE_LIBIDN2 -DHAVE_DNSSEC|' Makefile
#enable /etc/dnsmasq.d fix bz 526703, ignore RPM backup files
cat << EOF >> dnsmasq.conf.example
# Include all files in /etc/dnsmasq.d except RPM backup files
conf-dir=/etc/dnsmasq.d,.rpmnew,.rpmsave,.rpmorig
EOF
sed -i 's|^COPTS[[:space:]]*=|\0 -DHAVE_DBUS -DHAVE_LIBIDN2 -DHAVE_DNSSEC -DHAVE_CONNTRACK|' Makefile
%build
%make_build CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
%make_build CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS" \
%if %{with i18n}
all-i18n
%else
all
%endif
%make_build -C contrib/lease-tools CFLAGS="$RPM_OPT_FLAGS" LDFLAGS="$RPM_LD_FLAGS"
%install
# normally i'd do 'make install'...it's a bit messy, though
mkdir -p $RPM_BUILD_ROOT%{_sbindir} \
@ -240,14 +172,18 @@ install -m644 %{SOURCE1} %{buildroot}%{_unitdir}
rm -rf %{buildroot}%{_initrddir}
#install systemd sysuser file
install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/dnsmasq.conf
install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/%{name}.conf
%if %{with i18n}
%make_install PREFIX=/usr install-i18n
%find_lang %{name} --with-man
%endif
%pre
#precreate users so that rpm can install files owned by that user
%sysusers_create_package %{name} %{SOURCE2}
%sysusers_create_compat %{SOURCE2}
%post
#https://fedoraproject.org/wiki/Changes/SystemdSysusers
%systemd_post dnsmasq.service
%preun
@ -259,11 +195,9 @@ install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/dnsmasq.conf
%files
%doc CHANGELOG FAQ doc.html setup.html dbus/DBus-interface
%license COPYING COPYING-v3
%defattr(0644,root,dnsmasq,0755)
%config(noreplace) %{_sysconfdir}/dnsmasq.conf
%dir %{_sysconfdir}/dnsmasq.d
%dir %{_var}/lib/dnsmasq
%defattr(-,root,root,-)
%dir %attr(0755,root,dnsmasq) %{_var}/lib/dnsmasq
%config(noreplace) %{_sysconfdir}/dbus-1/system.d/dnsmasq.conf
%{_unitdir}/%{name}.service
%{_sbindir}/dnsmasq
@ -277,101 +211,216 @@ install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/dnsmasq.conf
%{_bindir}/dhcp_*
%{_mandir}/man1/dhcp_*
%if %{with i18n}
%files langpack -f %{name}.lang
%endif
%changelog
* Mon Mar 18 2024 Tomas Korbar <tkorbar@redhat.com> - 2.79-33
- Fix CVE 2023-50387 and CVE 2023-50868
- Resolves: RHEL-25667
- Resolves: RHEL-25629
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 2.90-3
- Bump release for June 2024 mass rebuild
* Wed Nov 01 2023 Petr Menšík <pemensik@redhat.com> - 2.79-32
- Do not crash on invalid domain in --synth-domain option (RHEL-15216)
* Thu May 09 2024 Petr Menšík <pemensik@redhat.com> - 2.90-2
- Update SPDX in license tag to use uppercase conjunction
* Wed Jun 14 2023 Petr Menšík <pemensik@redhat.com> - 2.79-31
- Do not create and search --local and --address=/x/# domains (#2233542)
* Tue Feb 13 2024 Petr Menšík <pemensik@redhat.com> - 2.90-1
- Update to 2.90 (#2264049)
* Wed Jun 14 2023 Petr Menšík <pemensik@redhat.com> - 2.79-30
- Make create logfile writeable by root (#2156789)
* Wed Jan 24 2024 Fedora Release Engineering <releng@fedoraproject.org> - 2.89-9
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Wed May 10 2023 Petr Menšík <pemensik@redhat.com> - 2.79-29
- Fix also dynamically set resolvers over dbus (#2186481)
* Fri Jan 19 2024 Fedora Release Engineering <releng@fedoraproject.org> - 2.89-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Fri Apr 21 2023 Petr Menšík <pemensik@redhat.com> - 2.79-28
- Correct possible crashes when server=/example.net/# is used (#2186481)
* Fri Jan 12 2024 Petr Menšík <pemensik@redhat.com> - 2.89-7
- Use local-service=host for initial configuration (#2258062)
* Mon Apr 03 2023 Petr Menšík <pemensik@redhat.com> - 2.79-27
- Limit offered EDNS0 size to 1232 (CVE-2023-28450)
* Wed Jul 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 2.89-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Wed Feb 15 2023 Petr Menšík <pemensik@redhat.com> - 2.79-26
- Avoid DHCPv6 relayed replies with Client Link-Layer Address (#2169355)
* Thu Apr 27 2023 Petr Menšík <pemensik@redhat.com> - 2.89-5
- Prevent crash on dbus reconnection (#2186468)
* Thu Jan 26 2023 Petr Menšík <pemensik@redhat.com> - 2.79-25
- Use upstream change for CVE-2022-0934 (#2164859)
* Thu Apr 27 2023 Petr Menšík <pemensik@redhat.com> - 2.89-4
- Actually enable localization support in dnsmasq (#2131681)
* Mon Aug 22 2022 Petr Menšík <pemensik@redhat.com> - 2.79-24
- Prevent endless loop in forward_query (#2120357)
* Wed Apr 05 2023 Petr Menšík <pemensik@redhat.com> - 2.89-3
- Add separate SPDX licenses also to translations
- Include localized man pages simpler way, make them noarch
* Thu May 12 2022 Petr Menšík <pemensik@redhat.com> - 2.79-23
- Add IPv6 ntp-server suboptions support (#2049691)
* Mon Apr 03 2023 Petr Menšík <pemensik@redhat.com> - 2.89-2
- Limit offered EDNS0 size 1232 (CVE-2023-28450)
* Fri Mar 25 2022 Petr Menšík <pemensik@redhat.com> - 2.79-22
- Prevent use after free in dhcp6_no_relay (CVE-2022-0934)
* Mon Feb 13 2023 Petr Menšík <pemensik@redhat.com> - 2.89-1
- Update to 2.89 (#2167121)
* Thu Jan 27 2022 Petr Menšík <pemensik@redhat.com> - 2.79-21
- Send queries only to best domain-specific server (#1919894)
* Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 2.88-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Mon Sep 20 2021 Petr Menšík <pemensik@redhat.com> - 2.79-20
- Offer alternate DHCPv6 address if requested is already leased (#1998448)
* Thu Dec 08 2022 Petr Menšík <pemensik@redhat.com> - 2.88-2
- Create dnsmasq-langpack subpackage with translations (#2131681)
* Tue Jun 29 2021 Petr Menšík <pemensik@redhat.com> - 2.79-19
- Correct typo in man page (#1947039)
* Tue Dec 06 2022 Petr Menšík <pemensik@redhat.com> - 2.88-1
- Update to 2.88 (#2150667)
* Thu Mar 18 2021 Petr Menšík <pemensik@redhat.com> - 2.79-18
- Properly randomize outgoing ports also with bound interface (CVE-2021-3448)
* Fri Nov 25 2022 Petr Menšík <pemensik@redhat.com> - 2.87-3
- Fix regression removing config statements on DBus change (#2148301)
* Fri Feb 12 2021 Petr Menšík <pemensik@redhat.com> - 2.79-17
- Fix sporadic bind-dynamic failures (#1887649)
* Fri Sep 30 2022 Petr Menšík <pemensik@redhat.com> - 2.87-2
- Update License tag to SPDX identifier
* Wed Jan 27 2021 Petr Menšík <pemensik@redhat.com> - 2.79-16
- Fix network errors on queries both from ipv4 and ipv6 (#1921153)
* Tue Sep 27 2022 Petr Menšík <pemensik@redhat.com> - 2.87-1
- Update to 2.87 (#2129658)
* Wed Nov 25 2020 Petr Menšík <pemensik@redhat.com> - 2.79-15
- Fix various issues in dnssec validation (CVE-2020-25681)
- Accept responses only on correct sockets (CVE-2020-25684)
- Use strong verification on queries (CVE-2020-25685)
* Thu Jul 21 2022 Fedora Release Engineering <releng@fedoraproject.org> - 2.86-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Wed Aug 26 2020 Tomas Korbar <tkorbar@redhat.com> - 2.79-14
- Honor sysusers.d during installation (#1819684)
* Fri Jul 08 2022 Petr Menšík <pemensik@redhat.com> - 2.86-10
- Do not own configuration by dnsmasq group (#2104973)
* Tue May 05 2020 Petr Menšík <pemensik@redhat.com> - 2.79-13
- Fix mixed address family reservations on DHCP (#1829448)
* Fri Jun 17 2022 Petr Menšík <pemensik@redhat.com> - 2.86-9
- Do not drop static forwarders on DBus reconfiguration (#2061944)
* Mon Mar 30 2020 Tomas Korbar <tkorbar@redhat.com> - 2.79-12
- Minimize count of close syscalls on startup (#1816613)
* Fri Apr 29 2022 Anssi Hannula <anssi.hannula@iki.fi> - 2.86-8
- Enable conntrack support
* Mon Mar 02 2020 Petr Menšík <pemensik@redhat.com> - 2.79-11
- Support multiple static leases for single mac on IPv6 (#1779187)
* Fri Apr 29 2022 Petr Menšík <pemensik@redhat.com> - 2.86-7
- Correct GNU address in license file
* Mon Feb 17 2020 Tomas Korbar <tkorbar@redhat.com> - 2.79-10
- Fix memory leak in helper.c (#1795370)
* Wed Feb 23 2022 Petr Menšík <pemensik@redhat.com> - 2.86-6
- Fix errors on server reload
* Tue Dec 10 2019 Tomas Korbar <tkorbar@redhat.com> - 2.79-9
- Fix replies to non-recursive queries (#1700916)
* Thu Jan 20 2022 Fedora Release Engineering <releng@fedoraproject.org> - 2.86-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Mon Dec 09 2019 Tomas Korbar <tkorbar@redhat.com> - 2.79-8
- Fix dhcp_lease_time (#1746411)
* Sun Jan 16 2022 Petr Menšík <pemensik@redhat.com> - 2.86-4
- Add writeable group flag to log file (#2024166)
* Mon Dec 09 2019 Tomas Korbar <tkorbar@redhat.com> - 2.79-7
- Fix TCP queries after interface recreation (#1728698)
* Thu Oct 14 2021 Petr Menšík <pemensik@redhat.com> - 2.86-3
- Rebuild server_array on any server change (#2009975)
- Compare case-insensitive also TCP queries (#2014019)
* Mon Sep 30 2019 Petr Menšík <pemensik@redhat.com> - 2.79-6
- Send dhcp_release even for addresses not on local network (#1749092)
* Thu Sep 23 2021 Petr Menšík <pemensik@redhat.com> - 2.86-2
- Attempt to fix regression found on recent release (#2006367)
* Thu Jul 18 2019 Petr Menšík <pemensik@redhat.com> - 2.79-5
- Fix Coverity detected issues (#1602477)
* Thu Sep 09 2021 Petr Menšík <pemensik@redhat.com> - 2.86-1
- Update to 2.86 (#2002475)
- Apply coverity detected issues patches
* Thu Jul 26 2018 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 2.79-4
* Wed Aug 04 2021 Petr Menšík <pemensik@redhat.com> - 2.85-6
- Do not require systemd
* Thu Jul 22 2021 Petr Menšík <pemensik@redhat.com> - 2.85-5
- Start before nss-lookup.target, hint modification to listen on IP (#1984618)
* Thu Jul 22 2021 Petr Menšík <pemensik@redhat.com> - 2.85-4
- Update lease if hostname is assigned to a new lease (#1978718)
* Wed Jul 21 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.85-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Thu Apr 08 2021 Petr Menšík <pemensik@redhat.com> - 2.85-2
- Update to 2.85 (#1947198)
* Wed Mar 31 2021 Petr Menšík <pemensik@redhat.com> - 2.85-1.rc2
- Update to 2.85rc2 (CVE-2021-3448)
- Switch systemd unit to forking, reports error on startup (#1774028)
* Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 2.84-2
- Rebuilt for updated systemd-rpm-macros
See https://pagure.io/fesco/issue/2583.
* Tue Jan 26 2021 Petr Menšík <pemensik@redhat.com> - 2.84-1
- Update to 2.84
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.83-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Tue Jan 19 2021 Petr Menšík <pemensik@redhat.com> - 2.83-1
- Update to 2.83, fix CVE-2020-25681-7
* Fri Oct 09 2020 Petr Menšík <pemensik@redhat.com> - 2.82-4
- Remove uninitialized condition from downstream patch
* Wed Sep 30 2020 Petr Menšík <pemensik@redhat.com> - 2.82-3
- Listen only on localhost interface, return port unreachable on all others
(#1852373)
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.82-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 20 2020 Petr Menšík <pemensik@redhat.com> - 2.82-1
- Update to 2.82
* Tue Jun 30 2020 Petr Menšík <pemensik@redhat.com> - 2.81-4
- Accept queries only from localhost (CVE-2020-14312)
* Mon May 11 2020 Petr Menšík <pemensik@redhat.com> - 2.81-3
- Correct multiple entries with the same mac address (#1834454)
* Thu Apr 16 2020 Petr Menšík <pemensik@redhat.com> - 2.81-2
- Update to 2.81 (#1823139)
* Mon Mar 23 2020 Petr Menšík <pemensik@redhat.com> - 2.81-1.rc3
- Update to 2.81rc3
* Mon Mar 23 2020 Petr Menšík <pemensik@redhat.com> - 2.80-14
- Fix last build breakage of DNS (#1814468)
* Tue Mar 10 2020 Petr Menšík <pemensik@redhat.com> - 2.80-13
- Respond to any local name also withou rd bit set (#1647464)
* Wed Mar 04 2020 Petr Menšík <pemensik@redhat.com> - 2.80-12
- Support multiple static leases for single mac on IPv6 (#1810172)
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.80-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Wed Aug 28 2019 Petr Menšík <pemensik@redhat.com> - 2.80-10
- Fix CPU intensive RA flood (#1739797)
* Fri Aug 09 2019 Petr Menšík <pemensik@redhat.com> - 2.80-9
- Remove SO_TIMESTAMP support, DHCP was broken (#1739081)
* Wed Jul 31 2019 Petr Menšík <pemensik@redhat.com> - 2.80-8
- Compile with nettle 3.5
- Support missing SIOCGSTAMP ioctl
* Wed Jul 31 2019 Petr Menšík <pemensik@redhat.com> - 2.80-7
- Fix TCP listener after interface recreated (#1728701)
* Wed Jul 24 2019 Petr Menšík <pemensik@redhat.com> - 2.80-6
- Do not return NXDOMAIN on empty non-terminals (#1674067)
* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.80-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Mon Apr 08 2019 Petr Menšík <pemensik@redhat.com> - 2.80-4
- Use more recent macro to create dnsmasq user
* Fri Feb 15 2019 Petr Menšík <pemensik@redhat.com> - 2.80-3
- Apply patches by autosetup
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.80-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Mon Aug 20 2018 Petr Menšík <pemensik@redhat.com> - 2.80-1
- Update to 2.80
* Thu Aug 09 2018 Petr Menšík <pemensik@redhat.com> - 2.79-8
- Better randomize ports
* Tue Jul 31 2018 Florian Weimer <fweimer@redhat.com> - 2.79-7
- Rebuild with fixed binutils
* Fri Jul 27 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 2.79-6
- Rebuild for new binutils
* Thu Jul 26 2018 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 2.79-5
- Fix %%pre scriptlet (#1548050)
* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.79-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Mon Jul 02 2018 Petr Menšík <pemensik@redhat.com> - 2.79-3
- Make dnsmasq leases writeable by root again (#1554390)

26
gating.yaml Normal file
View File

@ -0,0 +1,26 @@
--- !Policy
product_versions:
- fedora-*
decision_context: bodhi_update_push_testing
subject_type: koji_build
rules:
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
#Rawhide
--- !Policy
product_versions:
- fedora-*
decision_context: bodhi_update_push_stable
subject_type: koji_build
rules:
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
#gating rhel
--- !Policy
product_versions:
- rhel-*
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-public.functional}
- !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-internal.functional}
- !PassingTestCaseRule {test_case_name: osci.brew-build./nm.functional}

11
nm.fmf Normal file
View File

@ -0,0 +1,11 @@
summary: Run Network Manager tests
prepare:
how: install
packages: git-core
execute:
how: tmt
script: |
dnf install -y git-core
git clone https://gitlab.freedesktop.org/NetworkManager/NetworkManager-ci.git
cd NetworkManager-ci
./run/osci/run-tests dnsmasq

35
plans.fmf Normal file
View File

@ -0,0 +1,35 @@
/tier1-internal:
plan:
import:
url: https://src.fedoraproject.org/tests/dnsmasq.git
name: /plans/tier1/internal
/tier1-public:
plan:
import:
url: https://src.fedoraproject.org/tests/dnsmasq.git
name: /plans/tier1/public
/tier2-tier3-internal:
plan:
import:
url: https://src.fedoraproject.org/tests/dnsmasq.git
name: /plans/tier2-tier3/internal
/tier2-tier3-public:
plan:
import:
url: https://src.fedoraproject.org/tests/dnsmasq.git
name: /plans/tier2-tier3/public
/others-internal:
plan:
import:
url: https://src.fedoraproject.org/tests/dnsmasq.git
name: /plans/others/internal
/others-public:
plan:
import:
url: https://src.fedoraproject.org/tests/dnsmasq.git
name: /plans/others/public

10
rpminspect.yaml Normal file
View File

@ -0,0 +1,10 @@
---
badfuncs:
# Those functions are used in IPv4-only handling functions in dnsmasq.
# It handles also IPv6, but in different code paths with different calls.
#- inet_addr
#- inet_ntoa
ignore:
- /usr/sbin/dnsmasq
- /usr/bin/dhcp_lease_time
- /usr/bin/dhcp_release

2
sources Normal file
View File

@ -0,0 +1,2 @@
SHA512 (dnsmasq-2.90.tar.xz) = e169de1892f935e219b0f49d90107f95cba42b40bca20bd3c973313c2cd4df58b929af6628cd988419051d81c3b4ccf8e9f816274df7d0840e79f5bf49602442
SHA512 (dnsmasq-2.90.tar.xz.asc) = a1d5d1f8ccf1a0bfe6fc19025e616e38f1aea617f5d1b2deead55735608960eca73a8f8ca9c92897cf893df37ac0b7e8c4481992b3e57e0746f55180d2ef4bd0

117
srkgpg.txt Normal file
View File

@ -0,0 +1,117 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)
mQINBFMbjUMBEACsU1Xk8+uu/EsGVJTh9Tn31C2e0ycd0voBVT7cTdtXpzeiNR+o
/zUAi95ds7FiecpZJp1nRO4vNzvaaAPZhFsFVLzZYyIVABgTXsskT88xbZvzb4W5
KKRWVhoTQxVDgj1+dXLUXULTB6rg02WEhqnix/qf/zFdM9I4/3pRHJn9k+3XKygR
on+nYtljfn3AKBelCo1y28istC6wCncoH11b/qdQtlfxVXaJY4HF27V0MqFFmDMg
cuhOHR7DnhymeDh7GmLfTHJ4LUFG+TecqCjiYhyWcuv2wuSb0EPXUKHJQVViQ8qg
KyPm1ly6uFP0CYdVavO7/oJwKFBIChECrj7BQ4GsImMHeuSzfWno7qy6Fxoxx2+g
0F9cdXWvcxFDGPQsL5vXp8KYNwBrzmijRzQ2ZAnrbG+ilFCkJCbxXcrhzpd4tKwE
0dgcyPL1Ma/lrznhL4ZuOzjVMgLNne7WiPpBNRqI1GoT0pUn6as4pU3En8B+K7zy
MLVfHvI1+iH45fP5bZwYSbXCa85v4+xqljYrzs9giaROEsXe/tsXvuc6JPCcmJXk
CUO3c3QVxqDFt9OYuTHIR8hqehDPLgFgzKqVuoAwMkhTf/zZNGlsy4jvKXQNcZ50
uD4mWO3e+gykNW/OH+88IoCR0rgjQ6trMLOceZFnrtvxwRL//lMndGCTYQARAQAB
tCZTaW1vbiBLZWxsZXkgPHNpbW9uQHRoZWtlbGxleXMub3JnLnVrPokCOgQTAQgA
JAIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCUyDDjgIZAQAKCRAVzdpq4ZE1
otpmD/49HjUnc/uiYa/pcP5OIBd8lChHlF/NCh4s1RASeKv9cG6WDjnbTdxgcS6t
yESFJOfZ/hZW0WDEmuAh3tcZh1/yghkiMF3zZ+nB0zCFt9y//qKrNYvT7a9o+YGo
TuLANNq0jzzyrlPJemkZ7wvn9WNfRoG+ZUg/IQT0EVBqz6+/lvJSRTnjYXE8Ckay
/RbQ/WkppsuXQXsi08U+5oPT4rWTAGtZu4aEEoxX2MYcHip1f/bUUFzOAB/cn3In
ba+bqisLDCGm3F174NKfu+pk2MO0cauRRYPMoBAHLWDgGZOXoihWBgplcBUEYy1h
SNL7zRVX5AT2Z5Wqa1fVokkSd/T8FF2/0J4PjqFkCvBfCL8BYWzfTSkR/PBwL71P
nFzeOVJ1h1bF5ANXtfArZUI6HGMWpOb56E/YaHXhZ+lzfiM32Mwnc6jDHM3mJnEZ
jOQcsWEz7QgoR5YSPFFY6gmBXk+Y28bsgFvO3w73GjnnSHsmZdlWx9KmQWnMk/LQ
+7PUl7If+eIJ4PAqSEQddBOT/g74Q4NHGu4lvAhgZ47aU18+fYdxvVoe9JyXHsYY
5gPMjiM3RRxiugmm8dlT7RfYKWkJMBbkiyGAeQ6R1RDVztL7nM9N4ttb6nFOVtYK
UDQ1gxtKfrz/+L8Myy3IETC1NZgkuaDlXcdbNF3/oHApl8NK64hGBBARCAAGBQJT
G43BAAoJECj8hpoom4K3QrUAn1VftUxazQQJ/j6HJ/p3Soa60fJyAJ4xLJCBpov9
duJRuE9rF1OBaMZDeIhGBBARCAAGBQJTIekzAAoJECnhT5k5GzkoyOgAnjreKaWc
cEpEZSZnjlnc7DEnHuS+AJ4+Xq87WVKj9cJ05o8TRSkKxJYlEIkCHAQQAQgABgUC
UyHp8gAKCRAC0CBFCPsO9yHSD/9xYHSECwwneMFAO4nEGHyAQnhvyDzX3RutZeX1
9pc+qOm5iLUD+1EVx8+AvjTw0337yIHOa5nZI3CpgmBhmj18Q9vEgmtZn6EMXaRE
CvedsRjUSd3Q5+CF0AUbo1JQqZhVUdYLEZYcvfNgEmKl6IoVHwP8moH/cxDFc5Y6
GdlFAeJylynPdZ3Lb94DEya8VQc2mSG8L6y6ZDW8yf6M8npQG7f1cyJb9lPJJqlH
ZaFnpK2Df1DvOJXB88FQH1qW++w9uIoszdWjDOSGmwOuazO3GMmpfZPJPkH5lXoF
XKN5BO/l/gvEQ1jsmp14VZHJqdcO7HRHksLQLvNDQSi3am4ok2xm3Kn2NryJ1K2Q
mUBGrWu4CtwabgvhoKGxr0GADCQJVlLqRCC+UIp97J0kOsZj8FYjwA3I1U5w8wJi
SUqw8u+8OCCFGm1rS6XQy/wbGDPwZjCZnaNHICSj8zeXE9YkhTf2fMs/S8NLQUPy
u1g3/IoIGNnadETzEmAd02FJncUlUo05yDAcVg/IqwgM8atJQqEWLYE0QHrcqOWi
eaCCJ9+fx2KhxKnRqpKAXSov+M0KYDkIV9OQE+KioGzxdlrN2ZFmbfIKLLYMwH0s
xMkgJjbbhP8KhfxDIUoSky9gUTwwyrpJVjKkXZ6yNFpSo+Mtn8OHL12nLqzyQONT
waerx4hGBBARCAAGBQJTL0SDAAoJEBbi9PX8geFZBbUAnR3I/MdzG4kBtCecwePz
MvKdKS1SAJ9CyGUhzb8coURtMzbIlH9F7jm6L4kCHAQQAQgABgUCUy9EpAAKCRBj
ziC6xJxBSLhYD/9qBBxVex2nxavrMV4Vd0AhYJa5iI148NbqD7EZLnuCDWwi+wrq
nfMi0ToUHlh1Lp36vXd06W8JySHIiAxL0zDpq6tdT65f6iOTRZ6W6xuebxKgqC3k
ZsxcEzceYR1dOCKlRhQAsZ7Q9BJP/ZafSD/NOm2sxdPOneYm8IA4QXwWDVOayrV8
FOIDBkBLmPhm1BGNErdhCBCYsvqYSN7gFJBNszXciNMJtBmXWNyTsHtNAeKIQuzE
RgYCC2/LuTOIloeI6z6mM7mVZuPsraqRa5iGITvGI4qeQziTp+xqIu8YPQrE67iQ
MqSZZCxv3aheiiJd06l4FFpEYEg5H4FMD9JW4rvnaxLwXc8x1/ZVQQhylughetE9
j7oPQbA353oyUCCAukd4UiNYtULNCbZzfKdKCFCajnIfIY8IqNGuWvmujKViDAk2
7bIlKQeyNKExIx8Jkr4WPQBLFmXCkT+jYQMJx/R6SoNwrpa50SofTT+y+43GpSQ5
5e3Kffky0SZk+O/m7oW7gKPjwzh/UmLsOb9INXJ3gYS/CDT3fwA+UsAA+gXneT3I
ygYqfU8dnk2umV20gIm8q/SQYiyhMM+PZCkKXeHyoeU/SbO72DWKw/ZtZI/1b9xX
ruc1HBKJ/UXNPJRyoHIi4dZ/ARQ/zk839beBMnGm0AsB1y1+leTlrNZM5rQdU2lt
b24gS2VsbGV5IDxzcmtAZGViaWFuLm9yZz6JAjcEEwEIACEFAlMgw3QCGwMFCwkI
BwMFFQoJCAsFFgIDAQACHgECF4AACgkQFc3aauGRNaKhRg//S5G2RYoHNY22ecyG
5hpBr354lqdZiYRHKYCjX29jDIrtZSlC3HCL31ciGOVg666aD5xy54WAPTlx3MFQ
AxgWsqFTkICHj6zFdFduLmI1IffvcxkcEKwi6NK5f5dOxih9EtXcQ1HsoSUWGRmB
Kltvt1wyaiG37A80pjzQso1b6kr5JLdGMrjWx9PnFRKCdUNh5nxIb4HeC5R2Q8oT
FaipSppZwmvA5ocCvhMsyYCyiE6o8QTtzTqj5mGZafIqy18hwB9bA2n2gcEY1fXD
V9ky08J98A3VJqAMDM9Y6KYv+tQNJBIJRDWGmvjR/1J6n1jqO64l7mTcBlT/xfyp
TFfiXVzGN+H3EiEDFpPXKcc4abjiY8IaCu4P8qvKvee/EF7+FUep3R/i3hw0a5th
bZ4of1LfLp6qg7XjCZ3d2MUitxKe/FoFQS/ctkKNwsimOlUl5bIVmaJMMq8FUvLi
6iBgFMy8LCk2ItZ5rA2+5kGalGzwcWDdpq66A+z69f1wFfKDccOpfOJ838zmxCrz
WSxbVnLTaRSV4VobZvwHkAXZGCnDMk68ELfUNFzGClBhNOVPqAHbU74AkSS5bas5
recjKUz53DZl1aAOWLxFXQlOvxsaZ9wHmvHJAZiKscUGNUBXRK9p78TzQEm5Lxwz
Q6/V1JSkA6o4Xq7qygSARIigjJyIRgQQEQgABgUCUyHpMwAKCRAp4U+ZORs5KI+v
AKC2OnBT8TZ5cnTQwleYshUsxJddkQCgpecrsb8ysVtau7lXBgrA/X/Wef2JAhwE
EAEIAAYFAlMh6fIACgkQAtAgRQj7DvcWsQ//SF+g3zMRYeZ+qNC3m7slibJNCPdM
Cied05owZfN6oHhfBaRDc7nAC6mSdwFF76ird5/bSg2HzR6Tp4hIy/5M5WXFv4jt
m+0KXYKnDjHv1297sSALFoYKlm4K4lnE7T/qJknc/mGlLWfWm5Y5jV/QfV9Zwxvy
kT5Oh5xxzeNiOdvkmV4pCCk+bt15tGD0pII2n/TMPVfDVADLlhrWBrBp7laKyn6Q
5VvI4GiVBnHSiKsGVEaX0yUuDYzGZSU2RLaJG4BPNHqlHqSQYvsyo6QHPpHg0K6v
WWZFpgFOXHlLYMNJ91NS+DX7BqlEib2ndWQqCYzZtgRUJK/Dd6G6r2e60/5CPn6H
CwqQZr1MRdY6vEJS9Lpd5uGIOeQFTEDBZ22pcUAb20cZNdK1J+BgilfVuMvLAs2W
7fANxLtAHsXdNCvlkqr68odMI8C6w3Zd4R6XL4tfoYXl9emOKiN5SiCpK9HHJNxS
AuX6vH3lTyR+/sG1haxntu4Tn1T2zBJRgh2DiKuJLH6hnn7F7pf1fZEUUE/A6VSf
bmp+a6CXfn9mvgnF51QylKkFCauXhV5WsusEtWlNACeJjKXBg+d8LkA6FmJecMbY
ZzBTdcaN5OwLfXRpAkCsODWk2lXJNlhOntmVfa6MLDnll64S/3j+1wnKOHihf+c2
exRMy5eQCUKwqVSIRgQQEQgABgUCUy9EgwAKCRAW4vT1/IHhWZwLAJwLPSUf/VMW
NUJ1hRwNo+7kpUGLdQCeMzNtz3H0smfUn84CSRBFYIJDIhCJAhwEEAEIAAYFAlMv
RKoACgkQY84gusScQUiSfxAAuNSMXCUGs02xdJvnQRc10HkJxm/wg7YngVa4WZfd
eqyP2tQOjTdf65OMSIOCIrfpWHPDscJfsP3fjbHojFfx81iJnFmOdxx9aqB9KD15
FD4Whgq+Eyk8TiPZUEHiVU9RR8N6T/7mIe+lVNJ6GZ1iSk29D1g6+oM56Gox2d3y
0c8FnCK1Ts6D1peRiIiMq+gjGccdVJyim/yZI3WqzHvul//WmdEFzwgXqh03wbx3
iQS2zXdvwgyB+gBbVpk+6axOIbYupAvTNXYQV9Hz4imWoDFlXGdYzCMzb6QyH46R
NgfElAb8UcCknQjLwnawAjXPEHgrH6yaruYR9H1LBLxYIHA4oBYQCUxmn4ArDLOF
6kZ68eM8efBxVu4uAtklil9X8NUynhyI9DDWJoQET52ekojtOr31NCXHCtUmTkYb
PEwJxAORMBf3JEPlz2brGRgcSbacJG5RE4Qw2hfKJTOQTiNk4DpLwYrChLK8Ctmn
RS7jAZth3U2W7Fqc7OFfKs3zuo/2RRRCG3fjOVX7aIOp4Cnobvk0NxXDhEtUpMeP
0o7qPW8OdxrFyQ3YCoxu94ix1S6da3m143OujdmlM0Gs7Acyeq4bN3FokLzrMxci
oO6swXzgh9RGCzMkRrBztWgEpXQf8PbcBliF+sDV2aYerGBN9qmbN9FX30IKGaWn
QsK5Ag0EUyDDoQEQAMfQfa2tw3+OJFGMQEzLJSoXYN8/HnZEgKNlcMuYzhheQLgu
/MfcQJ7mnCIdn6xdPaalfLmYx63tM47/NGEM1+MSEvovPiRG0OLxzSgwei9DiGeN
EgsPTLXSZ5EVSXCM1+e9mT1ExT9aGLNnpCd6kIyWIcKCVMot+XC70R9prWLeyKSh
0FAZ0Pwv9i23osJVGOtJjND+WZ0uCeN29ocfN0b64yF4nPRc9IbcmYIDgNU3RybK
2Z/dupbthTisRjHRI3iX3/tiymXF3J0sSvsCluWIJWmyltS3Xyk/wfKVJz6OouiJ
jTj5utXVnCGptCDw+DCcj89vx1N0+0Dhm1cQcNZvXjMbVDTsuU+eVpJbxU6y8N+n
XpAXjEw4jMi3zNpqKtkyv2YpoqY5HhGLybgrY0zwSQOyMNf9lZ5J7znq5gEmiMXn
G9OPEw7PPSvm6QfbHPY/jAOgxsu7Fme7k303D5KkyGkkbzQiYyEtMZvbOMH/uECi
2uHGB72qiGpEYjMtHhihaRCBl+0bY8sH83He690qNQHSdStjaKXcecduE/v5iO0m
OYIHdsEHhKlWsE1GXXVLofBr68UBhYV6/AGXko4Pr+dXLzauN4kALDx6WltFu3qU
voD+uEoLq7IXULMo5Pyd7bO4qGQMKykaXTb5o6dqdu4GzWIUw1fr9kLEmo29ABEB
AAGJAh8EGAEIAAkFAlMgw6ECGwwACgkQFc3aauGRNaIjqA/+PXuaM6JHuudLycmB
0iKAwyB5csOFGpF3b9FgMR68TC4jzi5J5hJZASl0cO/e0ytQsrDUBbH74y+WaA4l
dwBVYr0j/2hqzIjrnGMtgWeHFPLV3sKw8DGuNx1/cOoljJXzi1WWSHIwDvaj3uZ9
CwHt+4/abR7kdvMcnFhQVA4zuzZWFqpp+CDkkJNVwB9zxtAQwGTGF4cQ0IvTkhCo
6DQhZZVTeyn+nBKxzzWijniWc0LyRsum03MxZ6E7UVIInCTjdXTalnO8wColwIx5
FV4nTMxdsKKgnIXmLexBdd03bW9TkowWf2C2XfDN+pDS8X3MzO6zAyogqJhAiBFj
nRzkOw0cw1VTL00o8uiWdMeu7OKOKeQbUilMAn4MweKB57mc582kjeGmwdZgWFA4
BJ2eiH7HwjxiynwMdZwQEBdOTNLbggHk3/mScF8U1KcJhjAFf7Ne+Z0feG/8GgKl
5aj3ucl821+dfpzB79lLo+kmd1qkDyDiUR5yN6P8l8k6IAUJz2KUe0BjtO6VFFw0
xni05dkrXdfo7IO79ictHmEn+g3QO8ZLUGRwdtZ1cMhTkm7FhH8Bdby0y4Soqluv
Hbri++cC91i1I3a92kHi/8O45rnLhVt+sOfxY1QnSIYh5OFwGMqMCNDTEL7ESiFa
FhSXkmzzVntlyvOBMlgz3IGh2hA=
=TM0e
-----END PGP PUBLIC KEY BLOCK-----

32
test-release-public-key Normal file
View File

@ -0,0 +1,32 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFM4adMBCADDTxhfWayeNd99OtOZyzzq5OSR3FeL4mWXWPFwRAwXfJwWuJot
HTU5dqEega18LyFlR/aGivCj9iUiWuUBJgK8zoRccgp/QxfiFZbY9myZwQRCtQvp
j/AgSNSsJmtbOvjFNKpaYXDtky1zhGoyit/05CGj1h4floWJhHD8rnuRCABZrwN8
I3GgHDnPzMMUKacTLCqRR4O6XXn4jCxVHoPQYk9lzINcKG32tgVQLl9qPNSx/twA
0Y0yf3FcwQr2svhBAYvQk6yhGqDe6PMhj9NHyQJEGZzMfC+z7EK9ZzvbCQIfulu+
UL/0gsXKiZpZu93Eow1/+0muaa0pfxY6867fABEBAAG0QVNpbW9uIEtlbGxleSAo
dGVzdCByZWxlYXNlIHNpZ25pbmcga2V5KSA8c2ltb25AdGhla2VsbGV5cy5vcmcu
dWs+iQE3BBMBCAAhBQJTOGnTAhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJ
ENP8mkR/fvI0+g0H/j4Y4IUraDCo9FKV15mgelyCyCBsbTvyODMwc83ueALp9Osp
in2ytYShha2T1LqnrXHCGKogecpNYjVbCKI4x1L6TXOw2IB/x3LBHFu9ycj2w6ml
bExz35jcDvZg2c/3WNWjZQKewQEZ/8Go/AAcwW2zwv5DwB/30IaPNSTQrvIwuTpr
Txjxybz64s+IiUDpqMxfPGNzcnWLWZVmUEjxyhGtp8ZPOF72FeVW2FBI8TCnrXXI
UazVLIMr1aS/QFHi5iExZ2ipeyC2ZZnKruUlFIzWE70922xR97lTU+326xlFzJyv
zMQjtSvdaZCvGGV9N3Coj7iJT1KhKy1wzVrJzz+IRgQQEQgABgUCUzhqLwAKCRAo
/IaaKJuCt8ovAJ0fR2hGPR7LpGb8zEpJ1YQM/z6ziACgghldWFdy4i0KQ270UvkY
zU6eMbqJAhwEEAEIAAYFAlkgZjwACgkQFc3aauGRNaI/WA/+KdJGRtMBX8RQN9yq
Ltf9p9/aZ+k7P3xgQIwnD12vz32+F/dkl3IBniwrKKjG51M59qXJ3b7/44xyQ9v3
kc9PhQGRUaNfmGzUeQ5qOovgSvZjlbREQAlGWQmkC+0fMgB7TbmDOVe6/MdGWTAn
COG192OlGnzCgrIwY9iBnqs8wFYKCfGUGAHL+Oa+MTkUYkpMldEPJ3HkR5/gvLjH
LHoHHycJZ4xXDCx/KDPTBcj0w/40D5xkQvb1SJ/K4HR4Nd+DewRgkLGBqnceQd+t
f4SIFBZ2Yik2j3yDbtht5Gi4s41ZV2pjx/EQwXgHqk7eWII1k8hl0uBr4DVt4tLD
nc6/YfEuseQDv+TMdzenMN2UdHEDOMxAxoY5Vm2w0hGW8C0t/Qcuo67tDoqfpW+K
smd1GdeAwxpF32y5ITCJw19voZvCGYMpSWBgvZnHhdIyITCqN7fmp67gbDACc78f
T81ICeGfiHLt1vPpYXD4ZVSlUc6bImdE6/BbvkXVhqS9pZ59vVnyMxQwQmQCNyz5
/flT2WC95iEjcFE4jZIc4itBRGb+p3Wr56fANy8kJmjD5ulpqsrUOAtzRLiEOvkm
mekUSwe61xooeWNfUO0zNnwPg6BR3rQYYnOW56cxSwe1BIaDhivwoDXob377fqs2
z/99c0hz1iAchDiArEHfqlFy+YQ=
=UI2C
-----END PGP PUBLIC KEY BLOCK-----