summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArmin Kuster <akuster@mvista.com>2021-09-10 15:16:48 -0700
committerArmin Kuster <akuster@mvista.com>2021-09-10 15:16:48 -0700
commit2e7e98cd0cb82db214b13224c71134b9335a719b (patch)
tree758e6fa5bef92a11521ea0a07b06ea40ab01887d
parent06d80777f47891ec876b55212790deb5fef9116e (diff)
downloadmeta-openembedded-2e7e98cd0cb82db214b13224c71134b9335a719b.tar.gz
dnsmasq: Security fix CVE-2021-3448
Source: https://thekelleys.org.uk/dnsmasq.git MR: 110238 Type: Security Fix Disposition: Backport from https://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=commit;h=74d4fcd756a85bc1823232ea74334f7ccfb9d5d2 ChangeID: 3365bcc47b0467b487f14fc6bfad89bc560cd818 Description: A flaw was found in dnsmasq in versions before 2.85. When configured to use a specific server for a given network interface, dnsmasq uses a fixed port while forwarding queries. An attacker on the network, able to find the outgoing port used by dnsmasq, only needs to guess the random transmission ID to forge a reply and get it accepted by dnsmasq. This flaw makes a DNS Cache Poisoning attack much easier. The highest threat from this vulnerability is to data integrity. Signed-off-by: Armin Kuster <akuster@mvista.com>
-rw-r--r--meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2021-3448.patch1040
-rw-r--r--meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb1
2 files changed, 1041 insertions, 0 deletions
diff --git a/meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2021-3448.patch b/meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2021-3448.patch
new file mode 100644
index 000000000..360931a83
--- /dev/null
+++ b/meta-networking/recipes-support/dnsmasq/dnsmasq/CVE-2021-3448.patch
@@ -0,0 +1,1040 @@
1From 74d4fcd756a85bc1823232ea74334f7ccfb9d5d2 Mon Sep 17 00:00:00 2001
2From: Simon Kelley <simon@thekelleys.org.uk>
3Date: Mon, 15 Mar 2021 21:59:51 +0000
4Subject: [PATCH] Use random source ports where possible if source
5 addresses/interfaces in use.
6
7CVE-2021-3448 applies.
8
9It's possible to specify the source address or interface to be
10used when contacting upstream nameservers: server=8.8.8.8@1.2.3.4
11or server=8.8.8.8@1.2.3.4#66 or server=8.8.8.8@eth0, and all of
12these have, until now, used a single socket, bound to a fixed
13port. This was originally done to allow an error (non-existent
14interface, or non-local address) to be detected at start-up. This
15means that any upstream servers specified in such a way don't use
16random source ports, and are more susceptible to cache-poisoning
17attacks.
18
19We now use random ports where possible, even when the
20source is specified, so server=8.8.8.8@1.2.3.4 or
21server=8.8.8.8@eth0 will use random source
22ports. server=8.8.8.8@1.2.3.4#66 or any use of --query-port will
23use the explicitly configured port, and should only be done with
24understanding of the security implications.
25Note that this change changes non-existing interface, or non-local
26source address errors from fatal to run-time. The error will be
27logged and communiction with the server not possible.
28
29Upstream-Status: Backport
30CVE: CVE-2021-3448
31Signed-off-by: Armin Kuster <akuster@mvista.com>
32
33---
34 CHANGELOG | 22 +++
35 man/dnsmasq.8 | 4 +-
36 src/dnsmasq.c | 31 ++--
37 src/dnsmasq.h | 26 ++--
38 src/forward.c | 392 ++++++++++++++++++++++++++++++--------------------
39 src/loop.c | 20 +--
40 src/network.c | 110 +++++---------
41 src/option.c | 3 +-
42 src/tftp.c | 6 +-
43 src/util.c | 2 +-
44 10 files changed, 344 insertions(+), 272 deletions(-)
45
46Index: dnsmasq-2.81/man/dnsmasq.8
47===================================================================
48--- dnsmasq-2.81.orig/man/dnsmasq.8
49+++ dnsmasq-2.81/man/dnsmasq.8
50@@ -489,7 +489,7 @@ source address specified but the port ma
51 part of the source address. Forcing queries to an interface is not
52 implemented on all platforms supported by dnsmasq.
53 .TP
54-.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<source-ip>|<interface>[#<port>]]
55+.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
56 This is functionally the same as
57 .B --server,
58 but provides some syntactic sugar to make specifying address-to-name queries easier. For example
59Index: dnsmasq-2.81/src/dnsmasq.c
60===================================================================
61--- dnsmasq-2.81.orig/src/dnsmasq.c
62+++ dnsmasq-2.81/src/dnsmasq.c
63@@ -1668,6 +1668,7 @@ static int set_dns_listeners(time_t now)
64 {
65 struct serverfd *serverfdp;
66 struct listener *listener;
67+ struct randfd_list *rfl;
68 int wait = 0, i;
69
70 #ifdef HAVE_TFTP
71@@ -1688,11 +1689,14 @@ static int set_dns_listeners(time_t now)
72 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
73 poll_listen(serverfdp->fd, POLLIN);
74
75- if (daemon->port != 0 && !daemon->osport)
76- for (i = 0; i < RANDOM_SOCKS; i++)
77- if (daemon->randomsocks[i].refcount != 0)
78- poll_listen(daemon->randomsocks[i].fd, POLLIN);
79-
80+ for (i = 0; i < RANDOM_SOCKS; i++)
81+ if (daemon->randomsocks[i].refcount != 0)
82+ poll_listen(daemon->randomsocks[i].fd, POLLIN);
83+
84+ /* Check overflow random sockets too. */
85+ for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
86+ poll_listen(rfl->rfd->fd, POLLIN);
87+
88 for (listener = daemon->listeners; listener; listener = listener->next)
89 {
90 /* only listen for queries if we have resources */
91@@ -1729,18 +1733,23 @@ static void check_dns_listeners(time_t n
92 {
93 struct serverfd *serverfdp;
94 struct listener *listener;
95+ struct randfd_list *rfl;
96 int i;
97 int pipefd[2];
98
99 for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
100 if (poll_check(serverfdp->fd, POLLIN))
101- reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
102+ reply_query(serverfdp->fd, now);
103
104- if (daemon->port != 0 && !daemon->osport)
105- for (i = 0; i < RANDOM_SOCKS; i++)
106- if (daemon->randomsocks[i].refcount != 0 &&
107- poll_check(daemon->randomsocks[i].fd, POLLIN))
108- reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
109+ for (i = 0; i < RANDOM_SOCKS; i++)
110+ if (daemon->randomsocks[i].refcount != 0 &&
111+ poll_check(daemon->randomsocks[i].fd, POLLIN))
112+ reply_query(daemon->randomsocks[i].fd, now);
113+
114+ /* Check overflow random sockets too. */
115+ for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
116+ if (poll_check(rfl->rfd->fd, POLLIN))
117+ reply_query(rfl->rfd->fd, now);
118
119 /* Races. The child process can die before we read all of the data from the
120 pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
121Index: dnsmasq-2.81/src/dnsmasq.h
122===================================================================
123--- dnsmasq-2.81.orig/src/dnsmasq.h
124+++ dnsmasq-2.81/src/dnsmasq.h
125@@ -542,13 +542,20 @@ struct serverfd {
126 };
127
128 struct randfd {
129+ struct server *serv;
130 int fd;
131- unsigned short refcount, family;
132+ unsigned short refcount; /* refcount == 0xffff means overflow record. */
133 };
134-
135+
136+struct randfd_list {
137+ struct randfd *rfd;
138+ struct randfd_list *next;
139+};
140+
141 struct server {
142 union mysockaddr addr, source_addr;
143 char interface[IF_NAMESIZE+1];
144+ unsigned int ifindex; /* corresponding to interface, above */
145 struct serverfd *sfd;
146 char *domain; /* set if this server only handles a domain. */
147 int flags, tcpfd, edns_pktsz;
148@@ -669,8 +676,7 @@ struct frec {
149 struct frec_src *next;
150 } frec_src;
151 struct server *sentto; /* NULL means free */
152- struct randfd *rfd4;
153- struct randfd *rfd6;
154+ struct randfd_list *rfds;
155 unsigned short new_id;
156 int fd, forwardall, flags;
157 time_t time;
158@@ -1100,11 +1106,12 @@ extern struct daemon {
159 int forwardcount;
160 struct server *srv_save; /* Used for resend on DoD */
161 size_t packet_len; /* " " */
162- struct randfd *rfd_save; /* " " */
163+ int fd_save; /* " " */
164 pid_t tcp_pids[MAX_PROCS];
165 int tcp_pipes[MAX_PROCS];
166 int pipe_to_parent;
167 struct randfd randomsocks[RANDOM_SOCKS];
168+ struct randfd_list *rfl_spare, *rfl_poll;
169 int v6pktinfo;
170 struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
171 int log_id, log_display_id; /* ids of transactions for logging */
172@@ -1275,7 +1282,7 @@ void safe_strncpy(char *dest, const char
173 void safe_pipe(int *fd, int read_noblock);
174 void *whine_malloc(size_t size);
175 int sa_len(union mysockaddr *addr);
176-int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
177+int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
178 int hostname_isequal(const char *a, const char *b);
179 int hostname_issubdomain(char *a, char *b);
180 time_t dnsmasq_time(void);
181@@ -1326,7 +1333,7 @@ char *parse_server(char *arg, union myso
182 int option_read_dynfile(char *file, int flags);
183
184 /* forward.c */
185-void reply_query(int fd, int family, time_t now);
186+void reply_query(int fd, time_t now);
187 void receive_query(struct listener *listen, time_t now);
188 unsigned char *tcp_request(int confd, time_t now,
189 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
190@@ -1336,13 +1343,12 @@ int send_from(int fd, int nowild, char *
191 union mysockaddr *to, union all_addr *source,
192 unsigned int iface);
193 void resend_query(void);
194-struct randfd *allocate_rfd(int family);
195-void free_rfd(struct randfd *rfd);
196+int allocate_rfd(struct randfd_list **fdlp, struct server *serv);
197+void free_rfds(struct randfd_list **fdlp);
198
199 /* network.c */
200 int indextoname(int fd, int index, char *name);
201 int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp);
202-int random_sock(int family);
203 void pre_allocate_sfds(void);
204 int reload_servers(char *fname);
205 void mark_servers(int flag);
206Index: dnsmasq-2.81/src/forward.c
207===================================================================
208--- dnsmasq-2.81.orig/src/forward.c
209+++ dnsmasq-2.81/src/forward.c
210@@ -16,7 +16,7 @@
211
212 #include "dnsmasq.h"
213
214-static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash);
215+static struct frec *lookup_frec(unsigned short id, int fd, void *hash);
216 static struct frec *lookup_frec_by_sender(unsigned short id,
217 union mysockaddr *addr,
218 void *hash);
219@@ -307,26 +307,18 @@ static int forward_query(int udpfd, unio
220 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
221 PUTSHORT(SAFE_PKTSZ, pheader);
222
223- if (forward->sentto->addr.sa.sa_family == AF_INET)
224- log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (union all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
225- else
226- log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (union all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
227-
228-
229- if (forward->sentto->sfd)
230- fd = forward->sentto->sfd->fd;
231- else
232+ if ((fd = allocate_rfd(&forward->rfds, forward->sentto)) != -1)
233 {
234- if (forward->sentto->addr.sa.sa_family == AF_INET6)
235- fd = forward->rfd6->fd;
236+ if (forward->sentto->addr.sa.sa_family == AF_INET)
237+ log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (union all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
238 else
239- fd = forward->rfd4->fd;
240+ log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (union all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
241+
242+ while (retry_send(sendto(fd, (char *)header, plen, 0,
243+ &forward->sentto->addr.sa,
244+ sa_len(&forward->sentto->addr))));
245 }
246
247- while (retry_send(sendto(fd, (char *)header, plen, 0,
248- &forward->sentto->addr.sa,
249- sa_len(&forward->sentto->addr))));
250-
251 return 1;
252 }
253 #endif
254@@ -501,49 +493,28 @@ static int forward_query(int udpfd, unio
255
256 while (1)
257 {
258+ int fd;
259+
260 /* only send to servers dealing with our domain.
261 domain may be NULL, in which case server->domain
262 must be NULL also. */
263
264 if (type == (start->flags & SERV_TYPE) &&
265 (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
266- !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
267+ !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) &&
268+ ((fd = allocate_rfd(&forward->rfds, start)) != -1))
269 {
270- int fd;
271-
272- /* find server socket to use, may need to get random one. */
273- if (start->sfd)
274- fd = start->sfd->fd;
275- else
276- {
277- if (start->addr.sa.sa_family == AF_INET6)
278- {
279- if (!forward->rfd6 &&
280- !(forward->rfd6 = allocate_rfd(AF_INET6)))
281- break;
282- daemon->rfd_save = forward->rfd6;
283- fd = forward->rfd6->fd;
284- }
285- else
286- {
287- if (!forward->rfd4 &&
288- !(forward->rfd4 = allocate_rfd(AF_INET)))
289- break;
290- daemon->rfd_save = forward->rfd4;
291- fd = forward->rfd4->fd;
292- }
293
294 #ifdef HAVE_CONNTRACK
295- /* Copy connection mark of incoming query to outgoing connection. */
296- if (option_bool(OPT_CONNTRACK))
297- {
298- unsigned int mark;
299- if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
300- setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
301- }
302-#endif
303+ /* Copy connection mark of incoming query to outgoing connection. */
304+ if (option_bool(OPT_CONNTRACK))
305+ {
306+ unsigned int mark;
307+ if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
308+ setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
309 }
310-
311+#endif
312+
313 #ifdef HAVE_DNSSEC
314 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
315 {
316@@ -574,6 +545,7 @@ static int forward_query(int udpfd, unio
317 /* Keep info in case we want to re-send this packet */
318 daemon->srv_save = start;
319 daemon->packet_len = plen;
320+ daemon->fd_save = fd;
321
322 if (!gotname)
323 strcpy(daemon->namebuff, "query");
324@@ -590,7 +562,7 @@ static int forward_query(int udpfd, unio
325 break;
326 forward->forwardall++;
327 }
328- }
329+ }
330
331 if (!(start = start->next))
332 start = daemon->servers;
333@@ -805,7 +777,7 @@ static size_t process_reply(struct dns_h
334 }
335
336 /* sets new last_server */
337-void reply_query(int fd, int family, time_t now)
338+void reply_query(int fd, time_t now)
339 {
340 /* packet from peer server, extract data for cache, and send to
341 original requester */
342@@ -820,9 +792,9 @@ void reply_query(int fd, int family, tim
343
344 /* packet buffer overwritten */
345 daemon->srv_save = NULL;
346-
347+
348 /* Determine the address of the server replying so that we can mark that as good */
349- if ((serveraddr.sa.sa_family = family) == AF_INET6)
350+ if (serveraddr.sa.sa_family == AF_INET6)
351 serveraddr.in6.sin6_flowinfo = 0;
352
353 header = (struct dns_header *)daemon->packet;
354@@ -845,7 +817,7 @@ void reply_query(int fd, int family, tim
355
356 hash = hash_questions(header, n, daemon->namebuff);
357
358- if (!(forward = lookup_frec(ntohs(header->id), fd, family, hash)))
359+ if (!(forward = lookup_frec(ntohs(header->id), fd, hash)))
360 return;
361
362 #ifdef HAVE_DUMPFILE
363@@ -900,25 +872,8 @@ void reply_query(int fd, int family, tim
364 }
365
366
367- if (start->sfd)
368- fd = start->sfd->fd;
369- else
370- {
371- if (start->addr.sa.sa_family == AF_INET6)
372- {
373- /* may have changed family */
374- if (!forward->rfd6)
375- forward->rfd6 = allocate_rfd(AF_INET6);
376- fd = forward->rfd6->fd;
377- }
378- else
379- {
380- /* may have changed family */
381- if (!forward->rfd4)
382- forward->rfd4 = allocate_rfd(AF_INET);
383- fd = forward->rfd4->fd;
384- }
385- }
386+ if ((fd = allocate_rfd(&forward->rfds, start)) == -1)
387+ return;
388
389 #ifdef HAVE_DUMPFILE
390 dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)plen, NULL, &start->addr);
391@@ -1126,8 +1081,7 @@ void reply_query(int fd, int family, tim
392 }
393
394 new->sentto = server;
395- new->rfd4 = NULL;
396- new->rfd6 = NULL;
397+ new->rfds = NULL;
398 new->frec_src.next = NULL;
399 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
400 new->forwardall = 0;
401@@ -1166,24 +1120,7 @@ void reply_query(int fd, int family, tim
402 /* Don't resend this. */
403 daemon->srv_save = NULL;
404
405- if (server->sfd)
406- fd = server->sfd->fd;
407- else
408- {
409- fd = -1;
410- if (server->addr.sa.sa_family == AF_INET6)
411- {
412- if (new->rfd6 || (new->rfd6 = allocate_rfd(AF_INET6)))
413- fd = new->rfd6->fd;
414- }
415- else
416- {
417- if (new->rfd4 || (new->rfd4 = allocate_rfd(AF_INET)))
418- fd = new->rfd4->fd;
419- }
420- }
421-
422- if (fd != -1)
423+ if ((fd = allocate_rfd(&new->rfds, server)) != -1)
424 {
425 #ifdef HAVE_CONNTRACK
426 /* Copy connection mark of incoming query to outgoing connection. */
427@@ -1344,7 +1281,7 @@ void receive_query(struct listener *list
428
429 /* packet buffer overwritten */
430 daemon->srv_save = NULL;
431-
432+
433 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
434 netmask.s_addr = 0;
435
436@@ -2207,9 +2144,8 @@ static struct frec *allocate_frec(time_t
437 f->next = daemon->frec_list;
438 f->time = now;
439 f->sentto = NULL;
440- f->rfd4 = NULL;
441+ f->rfds = NULL;
442 f->flags = 0;
443- f->rfd6 = NULL;
444 #ifdef HAVE_DNSSEC
445 f->dependent = NULL;
446 f->blocking_query = NULL;
447@@ -2221,46 +2157,192 @@ static struct frec *allocate_frec(time_t
448 return f;
449 }
450
451-struct randfd *allocate_rfd(int family)
452+/* return a UDP socket bound to a random port, have to cope with straying into
453+ occupied port nos and reserved ones. */
454+static int random_sock(struct server *s)
455+{
456+ int fd;
457+
458+ if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
459+ {
460+ if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
461+ return fd;
462+
463+ if (s->interface[0] == 0)
464+ (void)prettyprint_addr(&s->source_addr, daemon->namebuff);
465+ else
466+ strcpy(daemon->namebuff, s->interface);
467+
468+ my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
469+ daemon->namebuff, strerror(errno));
470+ close(fd);
471+ }
472+
473+ return -1;
474+}
475+
476+/* compare source addresses and interface, serv2 can be null. */
477+static int server_isequal(const struct server *serv1,
478+ const struct server *serv2)
479+{
480+ return (serv2 &&
481+ serv2->ifindex == serv1->ifindex &&
482+ sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
483+ strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
484+}
485+
486+/* fdlp points to chain of randomfds already in use by transaction.
487+ If there's already a suitable one, return it, else allocate a
488+ new one and add it to the list.
489+
490+ Not leaking any resources in the face of allocation failures
491+ is rather convoluted here.
492+
493+ Note that rfd->serv may be NULL, when a server goes away.
494+*/
495+int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
496 {
497 static int finger = 0;
498- int i;
499+ int i, j = 0;
500+ struct randfd_list *rfl;
501+ struct randfd *rfd = NULL;
502+ int fd = 0;
503+
504+ /* If server has a pre-allocated fd, use that. */
505+ if (serv->sfd)
506+ return serv->sfd->fd;
507+
508+ /* existing suitable random port socket linked to this transaction? */
509+ for (rfl = *fdlp; rfl; rfl = rfl->next)
510+ if (server_isequal(serv, rfl->rfd->serv))
511+ return rfl->rfd->fd;
512+
513+ /* No. need new link. */
514+ if ((rfl = daemon->rfl_spare))
515+ daemon->rfl_spare = rfl->next;
516+ else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
517+ return -1;
518
519 /* limit the number of sockets we have open to avoid starvation of
520 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
521-
522 for (i = 0; i < RANDOM_SOCKS; i++)
523 if (daemon->randomsocks[i].refcount == 0)
524 {
525- if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
526- break;
527-
528- daemon->randomsocks[i].refcount = 1;
529- daemon->randomsocks[i].family = family;
530- return &daemon->randomsocks[i];
531+ if ((fd = random_sock(serv)) != -1)
532+ {
533+ rfd = &daemon->randomsocks[i];
534+ rfd->serv = serv;
535+ rfd->fd = fd;
536+ rfd->refcount = 1;
537+ }
538+ break;
539 }
540
541 /* No free ones or cannot get new socket, grab an existing one */
542- for (i = 0; i < RANDOM_SOCKS; i++)
543+ if (!rfd)
544+ for (j = 0; j < RANDOM_SOCKS; j++)
545+ {
546+ i = (j + finger) % RANDOM_SOCKS;
547+ if (daemon->randomsocks[i].refcount != 0 &&
548+ server_isequal(serv, daemon->randomsocks[i].serv) &&
549+ daemon->randomsocks[i].refcount != 0xfffe)
550+ {
551+ finger = i + 1;
552+ rfd = &daemon->randomsocks[i];
553+ rfd->refcount++;
554+ break;
555+ }
556+ }
557+
558+ if (j == RANDOM_SOCKS)
559 {
560- int j = (i+finger) % RANDOM_SOCKS;
561- if (daemon->randomsocks[j].refcount != 0 &&
562- daemon->randomsocks[j].family == family &&
563- daemon->randomsocks[j].refcount != 0xffff)
564+ struct randfd_list *rfl_poll;
565+
566+ /* there are no free slots, and non with the same parameters we can piggy-back on.
567+ We're going to have to allocate a new temporary record, distinguished by
568+ refcount == 0xffff. This will exist in the frec randfd list, never be shared,
569+ and be freed when no longer in use. It will also be held on
570+ the daemon->rfl_poll list so the poll system can find it. */
571+
572+ if ((rfl_poll = daemon->rfl_spare))
573+ daemon->rfl_spare = rfl_poll->next;
574+ else
575+ rfl_poll = whine_malloc(sizeof(struct randfd_list));
576+
577+ if (!rfl_poll ||
578+ !(rfd = whine_malloc(sizeof(struct randfd))) ||
579+ (fd = random_sock(serv)) == -1)
580 {
581- finger = j;
582- daemon->randomsocks[j].refcount++;
583- return &daemon->randomsocks[j];
584+
585+ /* Don't leak anything we may already have */
586+ rfl->next = daemon->rfl_spare;
587+ daemon->rfl_spare = rfl;
588+
589+ if (rfl_poll)
590+ {
591+ rfl_poll->next = daemon->rfl_spare;
592+ daemon->rfl_spare = rfl_poll;
593+ }
594+
595+ if (rfd)
596+ free(rfd);
597+
598+ return -1; /* doom */
599 }
600+
601+ /* Note rfd->serv not set here, since it's not reused */
602+ rfd->fd = fd;
603+ rfd->refcount = 0xffff; /* marker for temp record */
604+
605+ rfl_poll->rfd = rfd;
606+ rfl_poll->next = daemon->rfl_poll;
607+ daemon->rfl_poll = rfl_poll;
608 }
609
610- return NULL; /* doom */
611+ rfl->rfd = rfd;
612+ rfl->next = *fdlp;
613+ *fdlp = rfl;
614+
615+ return rfl->rfd->fd;
616 }
617
618-void free_rfd(struct randfd *rfd)
619+void free_rfds(struct randfd_list **fdlp)
620 {
621- if (rfd && --(rfd->refcount) == 0)
622- close(rfd->fd);
623+ struct randfd_list *tmp, *rfl, *poll, *next, **up;
624+
625+ for (rfl = *fdlp; rfl; rfl = tmp)
626+ {
627+ if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
628+ close(rfl->rfd->fd);
629+
630+ /* temporary overflow record */
631+ if (rfl->rfd->refcount == 0xffff)
632+ {
633+ free(rfl->rfd);
634+
635+ /* go through the link of all these by steam to delete.
636+ This list is expected to be almost always empty. */
637+ for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
638+ {
639+ next = poll->next;
640+
641+ if (poll->rfd == rfl->rfd)
642+ {
643+ *up = poll->next;
644+ poll->next = daemon->rfl_spare;
645+ daemon->rfl_spare = poll;
646+ }
647+ else
648+ up = &poll->next;
649+ }
650+ }
651+
652+ tmp = rfl->next;
653+ rfl->next = daemon->rfl_spare;
654+ daemon->rfl_spare = rfl;
655+ }
656+
657+ *fdlp = NULL;
658 }
659
660 static void free_frec(struct frec *f)
661@@ -2276,12 +2358,9 @@ static void free_frec(struct frec *f)
662 }
663
664 f->frec_src.next = NULL;
665- free_rfd(f->rfd4);
666- f->rfd4 = NULL;
667+ free_rfds(&f->rfds);
668 f->sentto = NULL;
669 f->flags = 0;
670- free_rfd(f->rfd6);
671- f->rfd6 = NULL;
672
673 #ifdef HAVE_DNSSEC
674 if (f->stash)
675@@ -2389,26 +2468,39 @@ struct frec *get_new_frec(time_t now, in
676 }
677
678 /* crc is all-ones if not known. */
679-static struct frec *lookup_frec(unsigned short id, int fd, int family, void *hash)
680+static struct frec *lookup_frec(unsigned short id, int fd, void *hash)
681 {
682 struct frec *f;
683+ struct server *s;
684+ int type;
685+ struct randfd_list *fdl;
686
687 for(f = daemon->frec_list; f; f = f->next)
688 if (f->sentto && f->new_id == id &&
689 (memcmp(hash, f->hash, HASH_SIZE) == 0))
690 {
691 /* sent from random port */
692- if (family == AF_INET && f->rfd4 && f->rfd4->fd == fd)
693+ for (fdl = f->rfds; fdl; fdl = fdl->next)
694+ if (fdl->rfd->fd == fd)
695 return f;
696+ }
697
698- if (family == AF_INET6 && f->rfd6 && f->rfd6->fd == fd)
699- return f;
700+ /* Sent to upstream from socket associated with a server.
701+ Note we have to iterate over all the possible servers, since they may
702+ have different bound sockets. */
703+ type = f->sentto->flags & SERV_TYPE;
704+ s = f->sentto;
705+ do {
706+ if ((type == (s->flags & SERV_TYPE)) &&
707+ (type != SERV_HAS_DOMAIN ||
708+ (s->domain && hostname_isequal(f->sentto->domain, s->domain))) &&
709+ !(s->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) &&
710+ s->sfd && s->sfd->fd == fd)
711+ return f;
712+
713+ s = s->next ? s->next : daemon->servers;
714+ } while (s != f->sentto);
715
716- /* sent to upstream from bound socket. */
717- if (f->sentto->sfd && f->sentto->sfd->fd == fd)
718- return f;
719- }
720-
721 return NULL;
722 }
723
724@@ -2454,30 +2546,26 @@ static struct frec *lookup_frec_by_query
725 void resend_query()
726 {
727 if (daemon->srv_save)
728- {
729- int fd;
730-
731- if (daemon->srv_save->sfd)
732- fd = daemon->srv_save->sfd->fd;
733- else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
734- fd = daemon->rfd_save->fd;
735- else
736- return;
737-
738- while(retry_send(sendto(fd, daemon->packet, daemon->packet_len, 0,
739- &daemon->srv_save->addr.sa,
740- sa_len(&daemon->srv_save->addr))));
741- }
742+ while(retry_send(sendto(daemon->fd_save, daemon->packet, daemon->packet_len, 0,
743+ &daemon->srv_save->addr.sa,
744+ sa_len(&daemon->srv_save->addr))));
745 }
746
747 /* A server record is going away, remove references to it */
748 void server_gone(struct server *server)
749 {
750 struct frec *f;
751+ int i;
752
753 for (f = daemon->frec_list; f; f = f->next)
754 if (f->sentto && f->sentto == server)
755 free_frec(f);
756+
757+ /* If any random socket refers to this server, NULL the reference.
758+ No more references to the socket will be created in the future. */
759+ for (i = 0; i < RANDOM_SOCKS; i++)
760+ if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
761+ daemon->randomsocks[i].serv = NULL;
762
763 if (daemon->last_server == server)
764 daemon->last_server = NULL;
765Index: dnsmasq-2.81/src/loop.c
766===================================================================
767--- dnsmasq-2.81.orig/src/loop.c
768+++ dnsmasq-2.81/src/loop.c
769@@ -22,6 +22,7 @@ static ssize_t loop_make_probe(u32 uid);
770 void loop_send_probes()
771 {
772 struct server *serv;
773+ struct randfd_list *rfds = NULL;
774
775 if (!option_bool(OPT_LOOP_DETECT))
776 return;
777@@ -34,22 +35,15 @@ void loop_send_probes()
778 {
779 ssize_t len = loop_make_probe(serv->uid);
780 int fd;
781- struct randfd *rfd = NULL;
782
783- if (serv->sfd)
784- fd = serv->sfd->fd;
785- else
786- {
787- if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
788- continue;
789- fd = rfd->fd;
790- }
791+ if ((fd = allocate_rfd(&rfds, serv)) == -1)
792+ continue;
793
794 while (retry_send(sendto(fd, daemon->packet, len, 0,
795 &serv->addr.sa, sa_len(&serv->addr))));
796-
797- free_rfd(rfd);
798 }
799+
800+ free_rfds(&rfds);
801 }
802
803 static ssize_t loop_make_probe(u32 uid)
804Index: dnsmasq-2.81/src/network.c
805===================================================================
806--- dnsmasq-2.81.orig/src/network.c
807+++ dnsmasq-2.81/src/network.c
808@@ -545,6 +545,7 @@ int enumerate_interfaces(int reset)
809 #ifdef HAVE_AUTH
810 struct auth_zone *zone;
811 #endif
812+ struct server *serv;
813
814 /* Do this max once per select cycle - also inhibits netlink socket use
815 in TCP child processes. */
816@@ -562,7 +563,21 @@ int enumerate_interfaces(int reset)
817
818 if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
819 return 0;
820-
821+
822+ /* iface indexes can change when interfaces are created/destroyed.
823+ We use them in the main forwarding control path, when the path
824+ to a server is specified by an interface, so cache them.
825+ Update the cache here. */
826+ for (serv = daemon->servers; serv; serv = serv->next)
827+ if (strlen(serv->interface) != 0)
828+ {
829+ struct ifreq ifr;
830+
831+ safe_strncpy(ifr.ifr_name, serv->interface, IF_NAMESIZE);
832+ if (ioctl(param.fd, SIOCGIFINDEX, &ifr) != -1)
833+ serv->ifindex = ifr.ifr_ifindex;
834+ }
835+
836 /* Mark interfaces for garbage collection */
837 for (iface = daemon->interfaces; iface; iface = iface->next)
838 iface->found = 0;
839@@ -658,7 +673,7 @@ int enumerate_interfaces(int reset)
840
841 errno = errsave;
842 spare = param.spare;
843-
844+
845 return ret;
846 }
847
848@@ -798,10 +813,10 @@ int tcp_interface(int fd, int af)
849 /* use mshdr so that the CMSDG_* macros are available */
850 msg.msg_control = daemon->packet;
851 msg.msg_controllen = len = daemon->packet_buff_sz;
852-
853+
854 /* we overwrote the buffer... */
855 daemon->srv_save = NULL;
856-
857+
858 if (af == AF_INET)
859 {
860 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
861@@ -1102,59 +1117,6 @@ void join_multicast(int dienow)
862 }
863 #endif
864
865-/* return a UDP socket bound to a random port, have to cope with straying into
866- occupied port nos and reserved ones. */
867-int random_sock(int family)
868-{
869- int fd;
870-
871- if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)
872- {
873- union mysockaddr addr;
874- unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;
875- int tries = ports_avail < 30 ? 3 * ports_avail : 100;
876-
877- memset(&addr, 0, sizeof(addr));
878- addr.sa.sa_family = family;
879-
880- /* don't loop forever if all ports in use. */
881-
882- if (fix_fd(fd))
883- while(tries--)
884- {
885- unsigned short port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
886-
887- if (family == AF_INET)
888- {
889- addr.in.sin_addr.s_addr = INADDR_ANY;
890- addr.in.sin_port = port;
891-#ifdef HAVE_SOCKADDR_SA_LEN
892- addr.in.sin_len = sizeof(struct sockaddr_in);
893-#endif
894- }
895- else
896- {
897- addr.in6.sin6_addr = in6addr_any;
898- addr.in6.sin6_port = port;
899-#ifdef HAVE_SOCKADDR_SA_LEN
900- addr.in6.sin6_len = sizeof(struct sockaddr_in6);
901-#endif
902- }
903-
904- if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)
905- return fd;
906-
907- if (errno != EADDRINUSE && errno != EACCES)
908- break;
909- }
910-
911- close(fd);
912- }
913-
914- return -1;
915-}
916-
917-
918 int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
919 {
920 union mysockaddr addr_copy = *addr;
921@@ -1199,38 +1161,33 @@ int local_bind(int fd, union mysockaddr
922 return 1;
923 }
924
925-static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
926+static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsigned int ifindex)
927 {
928 struct serverfd *sfd;
929- unsigned int ifindex = 0;
930 int errsave;
931 int opt = 1;
932
933 /* when using random ports, servers which would otherwise use
934- the INADDR_ANY/port0 socket have sfd set to NULL */
935- if (!daemon->osport && intname[0] == 0)
936+ the INADDR_ANY/port0 socket have sfd set to NULL, this is
937+ anything without an explictly set source port. */
938+ if (!daemon->osport)
939 {
940 errno = 0;
941
942 if (addr->sa.sa_family == AF_INET &&
943- addr->in.sin_addr.s_addr == INADDR_ANY &&
944 addr->in.sin_port == htons(0))
945 return NULL;
946
947 if (addr->sa.sa_family == AF_INET6 &&
948- memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&
949 addr->in6.sin6_port == htons(0))
950 return NULL;
951 }
952
953- if (intname && strlen(intname) != 0)
954- ifindex = if_nametoindex(intname); /* index == 0 when not binding to an interface */
955-
956 /* may have a suitable one already */
957 for (sfd = daemon->sfds; sfd; sfd = sfd->next )
958- if (sockaddr_isequal(&sfd->source_addr, addr) &&
959- strcmp(intname, sfd->interface) == 0 &&
960- ifindex == sfd->ifindex)
961+ if (ifindex == sfd->ifindex &&
962+ sockaddr_isequal(&sfd->source_addr, addr) &&
963+ strcmp(intname, sfd->interface) == 0)
964 return sfd;
965
966 /* need to make a new one. */
967@@ -1281,7 +1238,7 @@ void pre_allocate_sfds(void)
968 #ifdef HAVE_SOCKADDR_SA_LEN
969 addr.in.sin_len = sizeof(struct sockaddr_in);
970 #endif
971- if ((sfd = allocate_sfd(&addr, "")))
972+ if ((sfd = allocate_sfd(&addr, "", 0)))
973 sfd->preallocated = 1;
974
975 memset(&addr, 0, sizeof(addr));
976@@ -1291,13 +1248,13 @@ void pre_allocate_sfds(void)
977 #ifdef HAVE_SOCKADDR_SA_LEN
978 addr.in6.sin6_len = sizeof(struct sockaddr_in6);
979 #endif
980- if ((sfd = allocate_sfd(&addr, "")))
981+ if ((sfd = allocate_sfd(&addr, "", 0)))
982 sfd->preallocated = 1;
983 }
984
985 for (srv = daemon->servers; srv; srv = srv->next)
986 if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
987- !allocate_sfd(&srv->source_addr, srv->interface) &&
988+ !allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
989 errno != 0 &&
990 option_bool(OPT_NOWILD))
991 {
992@@ -1506,7 +1463,7 @@ void check_servers(void)
993
994 /* Do we need a socket set? */
995 if (!serv->sfd &&
996- !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface)) &&
997+ !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
998 errno != 0)
999 {
1000 my_syslog(LOG_WARNING,
1001Index: dnsmasq-2.81/src/option.c
1002===================================================================
1003--- dnsmasq-2.81.orig/src/option.c
1004+++ dnsmasq-2.81/src/option.c
1005@@ -810,7 +810,8 @@ char *parse_server(char *arg, union myso
1006 if (interface_opt)
1007 {
1008 #if defined(SO_BINDTODEVICE)
1009- safe_strncpy(interface, interface_opt, IF_NAMESIZE);
1010+ safe_strncpy(interface, source, IF_NAMESIZE);
1011+ source = interface_opt;
1012 #else
1013 return _("interface binding not supported");
1014 #endif
1015Index: dnsmasq-2.81/src/tftp.c
1016===================================================================
1017--- dnsmasq-2.81.orig/src/tftp.c
1018+++ dnsmasq-2.81/src/tftp.c
1019@@ -601,7 +601,7 @@ void check_tftp_listeners(time_t now)
1020
1021 /* we overwrote the buffer... */
1022 daemon->srv_save = NULL;
1023-
1024+
1025 if ((len = get_block(daemon->packet, transfer)) == -1)
1026 {
1027 len = tftp_err_oops(daemon->packet, transfer->file->filename);
1028Index: dnsmasq-2.81/src/util.c
1029===================================================================
1030--- dnsmasq-2.81.orig/src/util.c
1031+++ dnsmasq-2.81/src/util.c
1032@@ -316,7 +316,7 @@ void *whine_malloc(size_t size)
1033 return ret;
1034 }
1035
1036-int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
1037+int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
1038 {
1039 if (s1->sa.sa_family == s2->sa.sa_family)
1040 {
diff --git a/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb b/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb
index a1dc0f3a0..2fb389915 100644
--- a/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb
+++ b/meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb
@@ -10,4 +10,5 @@ SRC_URI += "\
10 file://CVE-2020-25685-2.patch \ 10 file://CVE-2020-25685-2.patch \
11 file://CVE-2020-25686-1.patch \ 11 file://CVE-2020-25686-1.patch \
12 file://CVE-2020-25686-2.patch \ 12 file://CVE-2020-25686-2.patch \
13 file://CVE-2021-3448.patch \
13" 14"