diff options
author | Armin Kuster <akuster@mvista.com> | 2021-09-10 15:16:48 -0700 |
---|---|---|
committer | Armin Kuster <akuster@mvista.com> | 2021-09-10 15:16:48 -0700 |
commit | 2e7e98cd0cb82db214b13224c71134b9335a719b (patch) | |
tree | 758e6fa5bef92a11521ea0a07b06ea40ab01887d | |
parent | 06d80777f47891ec876b55212790deb5fef9116e (diff) | |
download | meta-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.patch | 1040 | ||||
-rw-r--r-- | meta-networking/recipes-support/dnsmasq/dnsmasq_2.81.bb | 1 |
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 @@ | |||
1 | From 74d4fcd756a85bc1823232ea74334f7ccfb9d5d2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Simon Kelley <simon@thekelleys.org.uk> | ||
3 | Date: Mon, 15 Mar 2021 21:59:51 +0000 | ||
4 | Subject: [PATCH] Use random source ports where possible if source | ||
5 | addresses/interfaces in use. | ||
6 | |||
7 | CVE-2021-3448 applies. | ||
8 | |||
9 | It's possible to specify the source address or interface to be | ||
10 | used when contacting upstream nameservers: server=8.8.8.8@1.2.3.4 | ||
11 | or server=8.8.8.8@1.2.3.4#66 or server=8.8.8.8@eth0, and all of | ||
12 | these have, until now, used a single socket, bound to a fixed | ||
13 | port. This was originally done to allow an error (non-existent | ||
14 | interface, or non-local address) to be detected at start-up. This | ||
15 | means that any upstream servers specified in such a way don't use | ||
16 | random source ports, and are more susceptible to cache-poisoning | ||
17 | attacks. | ||
18 | |||
19 | We now use random ports where possible, even when the | ||
20 | source is specified, so server=8.8.8.8@1.2.3.4 or | ||
21 | server=8.8.8.8@eth0 will use random source | ||
22 | ports. server=8.8.8.8@1.2.3.4#66 or any use of --query-port will | ||
23 | use the explicitly configured port, and should only be done with | ||
24 | understanding of the security implications. | ||
25 | Note that this change changes non-existing interface, or non-local | ||
26 | source address errors from fatal to run-time. The error will be | ||
27 | logged and communiction with the server not possible. | ||
28 | |||
29 | Upstream-Status: Backport | ||
30 | CVE: CVE-2021-3448 | ||
31 | Signed-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 | |||
46 | Index: 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 | ||
59 | Index: 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 | ||
121 | Index: 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); | ||
206 | Index: 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; | ||
765 | Index: 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) | ||
804 | Index: 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, | ||
1001 | Index: 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 | ||
1015 | Index: 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); | ||
1028 | Index: 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 | " |