blob: 44501bf7593fbe3b1bddee15bdda729f756602ef [file] [log] [blame]
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
Simon Kelley9e4abcb2004-01-22 19:47:41 +000017#include "dnsmasq.h"
18
Tarun Kundu12e3b2e2024-08-15 16:16:53 -070019static struct frec *get_new_frec(time_t now, struct server *serv, int force);
20static struct frec *lookup_frec(unsigned short id, int fd, void *hash, int *firstp, int *lastp);
21static struct frec *lookup_frec_by_query(void *hash, unsigned int flags, unsigned int flagmask);
22#ifdef HAVE_DNSSEC
23static struct frec *lookup_frec_dnssec(char *target, int class, int flags, struct dns_header *header);
24#endif
Simon Kelley15b60dd2020-11-18 18:34:55 +000025
Simon Kelley8a9be9e2014-01-25 23:17:21 +000026static unsigned short get_id(void);
Simon Kelley1a6bca82008-07-11 11:11:42 +010027static void free_frec(struct frec *f);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -070028static void query_full(time_t now, char *domain);
29
30static void return_reply(time_t now, struct frec *forward, struct dns_header *header, ssize_t n, int status);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000031
Simon Kelley824af852008-02-12 20:43:05 +000032/* Send a UDP packet with its source address set as "source"
Simon Kelley44a2a312004-03-10 20:04:35 +000033 unless nowild is true, when we just send it with the kernel default */
Simon Kelley29689cf2012-03-22 14:01:00 +000034int send_from(int fd, int nowild, char *packet, size_t len,
Simon Kelleycc921df2019-01-02 22:48:59 +000035 union mysockaddr *to, union all_addr *source,
Simon Kelley50303b12012-04-04 22:13:17 +010036 unsigned int iface)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000037{
Simon Kelley44a2a312004-03-10 20:04:35 +000038 struct msghdr msg;
39 struct iovec iov[1];
Simon Kelley44a2a312004-03-10 20:04:35 +000040 union {
41 struct cmsghdr align; /* this ensures alignment */
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010042#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +000043 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
44#elif defined(IP_SENDSRCADDR)
45 char control[CMSG_SPACE(sizeof(struct in_addr))];
46#endif
Simon Kelley44a2a312004-03-10 20:04:35 +000047 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley44a2a312004-03-10 20:04:35 +000048 } control_u;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010049
Simon Kelley44a2a312004-03-10 20:04:35 +000050 iov[0].iov_base = packet;
51 iov[0].iov_len = len;
52
Simon Kelleyfeba5c12004-07-27 20:28:58 +010053 msg.msg_control = NULL;
54 msg.msg_controllen = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +000055 msg.msg_flags = 0;
56 msg.msg_name = to;
57 msg.msg_namelen = sa_len(to);
58 msg.msg_iov = iov;
59 msg.msg_iovlen = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010060
Simon Kelley26128d22004-11-14 16:43:54 +000061 if (!nowild)
Simon Kelleyfeba5c12004-07-27 20:28:58 +010062 {
Simon Kelley26128d22004-11-14 16:43:54 +000063 struct cmsghdr *cmptr;
Simon Kelleyfeba5c12004-07-27 20:28:58 +010064 msg.msg_control = &control_u;
65 msg.msg_controllen = sizeof(control_u);
Simon Kelley26128d22004-11-14 16:43:54 +000066 cmptr = CMSG_FIRSTHDR(&msg);
Simon Kelley44a2a312004-03-10 20:04:35 +000067
Simon Kelley26128d22004-11-14 16:43:54 +000068 if (to->sa.sa_family == AF_INET)
69 {
Simon Kelley5e9e0ef2006-04-17 14:24:29 +010070#if defined(HAVE_LINUX_NETWORK)
Simon Kelley8ef5ada2010-06-03 19:42:45 +010071 struct in_pktinfo p;
72 p.ipi_ifindex = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +000073 p.ipi_spec_dst = source->addr4;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010074 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010075 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010076 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
Simon Kelleyc72daea2012-01-05 21:33:27 +000077 cmptr->cmsg_level = IPPROTO_IP;
Simon Kelley26128d22004-11-14 16:43:54 +000078 cmptr->cmsg_type = IP_PKTINFO;
79#elif defined(IP_SENDSRCADDR)
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010080 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
Simon Kelleycc921df2019-01-02 22:48:59 +000081 memcpy(CMSG_DATA(cmptr), &(source->addr4), sizeof(source->addr4));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010082 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
Simon Kelley26128d22004-11-14 16:43:54 +000083 cmptr->cmsg_level = IPPROTO_IP;
84 cmptr->cmsg_type = IP_SENDSRCADDR;
Simon Kelley44a2a312004-03-10 20:04:35 +000085#endif
Simon Kelley26128d22004-11-14 16:43:54 +000086 }
Simon Kelley26128d22004-11-14 16:43:54 +000087 else
88 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +010089 struct in6_pktinfo p;
90 p.ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
Simon Kelleycc921df2019-01-02 22:48:59 +000091 p.ipi6_addr = source->addr6;
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010092 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
Simon Kelley8ef5ada2010-06-03 19:42:45 +010093 memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
Jérémie Courrèges-Anglasc6cc4552019-03-22 10:56:13 +010094 cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
Simon Kelley316e2732010-01-22 20:16:09 +000095 cmptr->cmsg_type = daemon->v6pktinfo;
Simon Kelleyc72daea2012-01-05 21:33:27 +000096 cmptr->cmsg_level = IPPROTO_IPV6;
Simon Kelley26128d22004-11-14 16:43:54 +000097 }
Simon Kelley26128d22004-11-14 16:43:54 +000098 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +010099
Simon Kelleyff841eb2015-03-11 21:36:30 +0000100 while (retry_send(sendmsg(fd, &msg, 0)));
101
Brad Smithea3c60a2020-03-08 14:53:59 +0000102 if (errno != 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100103 {
Brad Smithea3c60a2020-03-08 14:53:59 +0000104#ifdef HAVE_LINUX_NETWORK
105 /* If interface is still in DAD, EINVAL results - ignore that. */
106 if (errno != EINVAL)
107 my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
108#endif
Simon Kelley29689cf2012-03-22 14:01:00 +0000109 return 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100110 }
Simon Kelley29d28dd2012-12-03 14:05:59 +0000111
Simon Kelley29689cf2012-03-22 14:01:00 +0000112 return 1;
Simon Kelley44a2a312004-03-10 20:04:35 +0000113}
114
Petr Menšík6c0bf792021-03-18 00:07:45 +0100115#ifdef HAVE_CONNTRACK
116static void set_outgoing_mark(struct frec *forward, int fd)
117{
118 /* Copy connection mark of incoming query to outgoing connection. */
119 unsigned int mark;
120 if (get_incoming_mark(&forward->frec_src.source, &forward->frec_src.dest, 0, &mark))
121 setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
122}
123#endif
124
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700125static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg, unsigned short type)
Petr Menšík6c0bf792021-03-18 00:07:45 +0100126{
127 if (addr->sa.sa_family == AF_INET)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700128 {
129 if (flags & F_SERVER)
130 type = ntohs(addr->in.sin_port);
131 log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg, type);
132 }
Petr Menšík6c0bf792021-03-18 00:07:45 +0100133 else
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700134 {
135 if (flags & F_SERVER)
136 type = ntohs(addr->in6.sin6_port);
137 log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg, type);
138 }
Petr Menšík6c0bf792021-03-18 00:07:45 +0100139}
140
Petr Menšík51f7bc92021-03-18 01:05:43 +0100141static void server_send(struct server *server, int fd,
142 const void *header, size_t plen, int flags)
143{
144 while (retry_send(sendto(fd, header, plen, flags,
145 &server->addr.sa,
146 sa_len(&server->addr))));
147}
148
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700149static int domain_no_rebind(char *domain)
Petr Menšík51f7bc92021-03-18 01:05:43 +0100150{
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700151 struct rebind_domain *rbd;
152 size_t tlen, dlen = strlen(domain);
153 char *dots = strchr(domain, '.');
Petr Menšík51f7bc92021-03-18 01:05:43 +0100154
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700155 /* Match whole labels only. Empty domain matches no dots (any single label) */
156 for (rbd = daemon->no_rebind; rbd; rbd = rbd->next)
157 {
158 if (dlen >= (tlen = strlen(rbd->domain)) &&
159 hostname_isequal(rbd->domain, &domain[dlen - tlen]) &&
160 (dlen == tlen || domain[dlen - tlen - 1] == '.'))
161 return 1;
162
163 if (tlen == 0 && !dots)
164 return 1;
165 }
166
167 return 0;
Petr Menšíke10a9232021-03-15 11:20:49 +0100168}
169
Simon Kelley824af852008-02-12 20:43:05 +0000170static int forward_query(int udpfd, union mysockaddr *udpaddr,
Simon Kelleycc921df2019-01-02 22:48:59 +0000171 union all_addr *dst_addr, unsigned int dst_iface,
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700172 struct dns_header *header, size_t plen, char *limit, time_t now,
173 struct frec *forward, int ad_reqd, int do_bit, int fast_retry)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000174{
Simon Kelley28866e92011-02-14 20:19:14 +0000175 unsigned int flags = 0;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000176 unsigned int fwd_flags = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700177 int is_dnssec = forward && (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY));
178 struct server *master;
Simon Kelley8a9be9e2014-01-25 23:17:21 +0000179 void *hash = hash_questions(header, plen, daemon->namebuff);
Simon Kelley1682d152018-08-03 20:38:18 +0100180 unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
181 unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700182 int old_src = 0, old_reply = 0;
183 int first, last, start = 0;
184 int cacheable, forwarded = 0;
185 size_t edns0_len;
186 unsigned char *pheader;
187 int ede = EDE_UNSET;
Simon Kelley1682d152018-08-03 20:38:18 +0100188 (void)do_bit;
Simon Kelley15b60dd2020-11-18 18:34:55 +0000189
190 if (header->hb4 & HB4_CD)
191 fwd_flags |= FREC_CHECKING_DISABLED;
192 if (ad_reqd)
193 fwd_flags |= FREC_AD_QUESTION;
194 if (oph)
195 fwd_flags |= FREC_HAS_PHEADER;
196#ifdef HAVE_DNSSEC
197 if (do_bit)
198 fwd_flags |= FREC_DO_QUESTION;
199#endif
200
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700201 /* Check for retry on existing query.
202 FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
203 ensures that no frec created for internal DNSSEC query can be returned here.
204
205 Similarly FREC_NO_CACHE is never set in flags, so a query which is
206 contigent on a particular source address EDNS0 option will never be matched. */
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100207 if (forward)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700208 {
209 old_src = 1;
210 old_reply = 1;
211 }
212 else if ((forward = lookup_frec_by_query(hash, fwd_flags,
213 FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
214 FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
Simon Kelley141a26f2021-02-17 23:56:32 +0000215 {
Simon Kelley305cb792021-02-18 21:35:09 +0000216 struct frec_src *src;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100217
Simon Kelley305cb792021-02-18 21:35:09 +0000218 for (src = &forward->frec_src; src; src = src->next)
219 if (src->orig_id == ntohs(header->id) &&
220 sockaddr_isequal(&src->source, udpaddr))
221 break;
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100222
223 if (src)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700224 {
225 old_src = 1;
226 /* If a query is retried, use the log_id for the retry when logging the answer. */
227 src->log_id = daemon->log_id;
228 }
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100229 else
Simon Kelley305cb792021-02-18 21:35:09 +0000230 {
Simon Kelleyea6b0b22021-04-05 21:01:09 +0100231 /* Existing query, but from new source, just add this
232 client to the list that will get the reply.*/
233
Simon Kelley141a26f2021-02-17 23:56:32 +0000234 /* Note whine_malloc() zeros memory. */
235 if (!daemon->free_frec_src &&
236 daemon->frec_src_count < daemon->ftabsize &&
237 (daemon->free_frec_src = whine_malloc(sizeof(struct frec_src))))
238 {
239 daemon->frec_src_count++;
240 daemon->free_frec_src->next = NULL;
241 }
242
Simon Kelley961daf82021-04-06 23:52:09 +0100243 /* If we've been spammed with many duplicates, return REFUSED. */
Simon Kelley141a26f2021-02-17 23:56:32 +0000244 if (!daemon->free_frec_src)
Simon Kelley961daf82021-04-06 23:52:09 +0100245 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700246 query_full(now, NULL);
247 /* This is tricky; if we're blasted with the same query
248 over and over, we'll end up taking this path each time
249 and never resetting until the frec gets deleted by
250 aging followed by the receipt of a different query. This
251 is a bit of a DoS vuln. Avoid by explicitly deleting the
252 frec once it expires. */
253 if (difftime(now, forward->time) >= TIMEOUT)
254 free_frec(forward);
255 goto reply;
Simon Kelley961daf82021-04-06 23:52:09 +0100256 }
Simon Kelley141a26f2021-02-17 23:56:32 +0000257
Simon Kelley305cb792021-02-18 21:35:09 +0000258 src = daemon->free_frec_src;
259 daemon->free_frec_src = src->next;
260 src->next = forward->frec_src.next;
261 forward->frec_src.next = src;
262 src->orig_id = ntohs(header->id);
263 src->source = *udpaddr;
264 src->dest = *dst_addr;
265 src->log_id = daemon->log_id;
266 src->iface = dst_iface;
267 src->fd = udpfd;
Simon Kelley64a16cb2021-04-06 23:29:46 +0100268
269 /* closely spaced identical queries cannot be a try and a retry, so
270 it's safe to wait for the reply from the first without
271 forwarding the second. */
272 if (difftime(now, forward->time) < 2)
273 return 0;
Simon Kelley141a26f2021-02-17 23:56:32 +0000274 }
275 }
276
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700277 /* new query */
278 if (!forward)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000279 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700280 /* If the query is malformed, we can't forward it because
281 we can't get a reliable hash to recognise the answer. */
282 if (!hash)
283 {
284 flags = 0;
285 ede = EDE_INVALID_DATA;
286 goto reply;
287 }
288
289 if (lookup_domain(daemon->namebuff, gotname, &first, &last))
290 flags = is_local_answer(now, first, daemon->namebuff);
291 else
292 {
293 /* no available server. */
294 ede = EDE_NOT_READY;
295 flags = 0;
296 }
297
298 /* don't forward A or AAAA queries for simple names, except the empty name */
299 if (!flags &&
300 option_bool(OPT_NODOTS_LOCAL) &&
301 (gotname & (F_IPV4 | F_IPV6)) &&
302 !strchr(daemon->namebuff, '.') &&
303 strlen(daemon->namebuff) != 0)
304 flags = check_for_local_domain(daemon->namebuff, now) ? F_NOERR : F_NXDOMAIN;
305
306 /* Configured answer. */
307 if (flags || ede == EDE_NOT_READY)
308 goto reply;
309
310 master = daemon->serverarray[first];
311
312 if (!(forward = get_new_frec(now, master, 0)))
313 goto reply;
314 /* table full - flags == 0, return REFUSED */
315
316 /* Keep copy of query if we're doing fast retry. */
317 if (daemon->fast_retry_time != 0)
318 {
319 forward->stash = blockdata_alloc((char *)header, plen);
320 forward->stash_len = plen;
321 }
322
323 forward->frec_src.log_id = daemon->log_id;
324 forward->frec_src.source = *udpaddr;
325 forward->frec_src.orig_id = ntohs(header->id);
326 forward->frec_src.dest = *dst_addr;
327 forward->frec_src.iface = dst_iface;
328 forward->frec_src.next = NULL;
329 forward->frec_src.fd = udpfd;
330 forward->new_id = get_id();
331 memcpy(forward->hash, hash, HASH_SIZE);
332 forward->forwardall = 0;
333 forward->flags = fwd_flags;
334 if (domain_no_rebind(daemon->namebuff))
335 forward->flags |= FREC_NOREBIND;
336 if (header->hb4 & HB4_CD)
337 forward->flags |= FREC_CHECKING_DISABLED;
338 if (ad_reqd)
339 forward->flags |= FREC_AD_QUESTION;
340#ifdef HAVE_DNSSEC
341 forward->work_counter = daemon->limit[LIMIT_WORK];
342 forward->validate_counter = daemon->limit[LIMIT_CRYPTO];
343 if (do_bit)
344 forward->flags |= FREC_DO_QUESTION;
345#endif
346
347 start = first;
348
349 if (option_bool(OPT_ALL_SERVERS))
350 forward->forwardall = 1;
351
352 if (!option_bool(OPT_ORDER))
353 {
354 if (master->forwardcount++ > FORWARD_TEST ||
355 difftime(now, master->forwardtime) > FORWARD_TIME ||
356 master->last_server == -1)
357 {
358 master->forwardtime = now;
359 master->forwardcount = 0;
360 forward->forwardall = 1;
361 }
362 else
363 start = master->last_server;
364 }
365 }
366 else
367 {
368#ifdef HAVE_DNSSEC
369 /* If we've already got an answer to this query, but we're awaiting keys for validation,
370 there's no point retrying the query, retry the key query instead...... */
371 while (forward->blocking_query)
372 forward = forward->blocking_query;
373
374 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
375 {
376 int is_sign;
377 unsigned char *pheader;
378
379 /* log_id should match previous DNSSEC query. */
380 daemon->log_display_id = forward->frec_src.log_id;
381
382 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
383 plen = forward->stash_len;
384 /* get query for logging. */
385 extract_request(header, plen, daemon->namebuff, NULL);
386
387 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
388 PUTSHORT(SAFE_PKTSZ, pheader);
389
390 /* Find suitable servers: should never fail. */
391 if (!filter_servers(forward->sentto->arrayposn, F_DNSSECOK, &first, &last))
392 return 0;
393
394 is_dnssec = 1;
395 forward->forwardall = 1;
396 }
397 else
398#endif
399 {
400 /* retry on existing query, from original source. Send to all available servers */
401 if (udpfd == -1 && !fast_retry)
402 forward->sentto->failed_queries++;
403 else
404 forward->sentto->retrys++;
405
406 if (!filter_servers(forward->sentto->arrayposn, F_SERVER, &first, &last))
407 goto reply;
408
409 master = daemon->serverarray[first];
410
411 /* Forward to all available servers on retry of query from same host. */
412 if (!option_bool(OPT_ORDER) && old_src && !fast_retry)
413 forward->forwardall = 1;
414 else
415 {
416 start = forward->sentto->arrayposn;
417
418 if (option_bool(OPT_ORDER) && !fast_retry)
419 {
420 /* In strict order mode, there must be a server later in the list
421 left to send to, otherwise without the forwardall mechanism,
422 code further on will cycle around the list forwever if they
423 all return REFUSED. If at the last, give up.
424 Note that we can get here EITHER because a client retried,
425 or an upstream server returned REFUSED. The above only
426 applied in the later case. For client retries,
427 keep trying the last server.. */
428 if (++start == last)
429 {
430 if (old_reply)
431 goto reply;
432 else
433 start--;
434 }
435 }
436 }
437 }
438
Simon Kelleya77cec82015-05-08 16:25:38 +0100439 /* If we didn't get an answer advertising a maximal packet in EDNS,
440 fall back to 1280, which should work everywhere on IPv6.
441 If that generates an answer, it will become the new default
442 for this server */
443 forward->flags |= FREC_TEST_PKTSZ;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700444 }
Petr Menšík51f7bc92021-03-18 01:05:43 +0100445
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700446 /* We may be resending a DNSSEC query here, for which the below processing is not necessary. */
447 if (!is_dnssec)
448 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000449 header->id = htons(forward->new_id);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700451 plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &cacheable);
Simon Kelley15b60dd2020-11-18 18:34:55 +0000452
Simon Kelley25e63f12020-11-25 21:17:52 +0000453 if (!cacheable)
454 forward->flags |= FREC_NO_CACHE;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700455
Simon Kelley3a237152013-12-12 12:15:50 +0000456#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700457 if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
Simon Kelley0fc2f312014-01-08 10:26:58 +0000458 {
Simon Kelley6fd5d792017-10-13 22:26:40 +0100459 plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700460
Simon Kelley5b3bf922014-01-25 17:03:07 +0000461 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
462 this allows it to select auth servers when one is returning bad data. */
463 if (option_bool(OPT_DNSSEC_DEBUG))
464 header->hb4 |= HB4_CD;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700465
Simon Kelley0fc2f312014-01-08 10:26:58 +0000466 }
Simon Kelley3a237152013-12-12 12:15:50 +0000467#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700468
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000469 if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
Simon Kelley6fd5d792017-10-13 22:26:40 +0100470 {
471 /* If there wasn't a PH before, and there is now, we added it. */
472 if (!oph)
473 forward->flags |= FREC_ADDED_PHEADER;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700474
Simon Kelley6fd5d792017-10-13 22:26:40 +0100475 /* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
476 if (edns0_len > 11)
477 forward->flags |= FREC_HAS_EXTRADATA;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700478
Simon Kelleyc1a4e252018-01-19 22:00:05 +0000479 /* Reduce udp size on retransmits. */
480 if (forward->flags & FREC_TEST_PKTSZ)
481 PUTSHORT(SAFE_PKTSZ, pheader);
Simon Kelley6fd5d792017-10-13 22:26:40 +0100482 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700483 }
484
485 if (forward->forwardall)
486 start = first;
487
488 forwarded = 0;
489
490 /* check for send errors here (no route to host)
491 if we fail to send to all nameservers, send back an error
492 packet straight away (helps modem users when offline) */
493
494 while (1)
495 {
496 int fd;
497 struct server *srv = daemon->serverarray[start];
Simon Kelleya77cec82015-05-08 16:25:38 +0100498
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700499 if ((fd = allocate_rfd(&forward->rfds, srv)) != -1)
500 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000501
Simon Kelley7de060b2011-08-26 17:24:52 +0100502#ifdef HAVE_CONNTRACK
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700503 /* Copy connection mark of incoming query to outgoing connection. */
504 if (option_bool(OPT_CONNTRACK))
505 set_outgoing_mark(forward, fd);
506#endif
507
508#ifdef HAVE_DNSSEC
509 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
510 {
511 /* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
512 packet size to 512. But that won't provide space for the RRSIGS in many cases.
513 The RRSIGS will be stripped out before the answer goes back, so the packet should
514 shrink again. So, if we added a do-bit, bump the udp packet size to the value
515 known to be OK for this server. We check returned size after stripping and set
516 the truncated bit if it's still too big. */
517 unsigned char *pheader;
518 int is_sign;
519 if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
520 PUTSHORT(srv->edns_pktsz, pheader);
521 }
522#endif
523
Tarun Kundu567116b2024-08-15 16:22:58 -0700524 if (udpaddr &&
525 (srv->addr.in.sin_addr.s_addr != udpaddr->in.sin_addr.s_addr) &&
526 (retry_send(sendto(fd, (char *)header, plen, 0,
527 &srv->addr.sa,
528 sa_len(&srv->addr)))))
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700529 continue;
530
531 if (errno == 0)
532 {
533#ifdef HAVE_DUMPFILE
534 dump_packet_udp(DUMP_UP_QUERY, (void *)header, plen, NULL, &srv->addr, fd);
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000535#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +0100536
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700537 /* Keep info in case we want to re-send this packet */
538 daemon->srv_save = srv;
539 daemon->packet_len = plen;
540 daemon->fd_save = fd;
541
542 if (!(forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000543 {
Simon Kelleyde379512004-06-22 20:23:33 +0100544 if (!gotname)
Simon Kelley3be34542004-09-11 19:12:13 +0100545 strcpy(daemon->namebuff, "query");
Petr Menšík6c0bf792021-03-18 00:07:45 +0100546 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff,
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700547 &srv->addr, NULL, 0);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000548 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700549#ifdef HAVE_DNSSEC
550 else
551 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, daemon->namebuff, &srv->addr,
552 (forward->flags & FREC_DNSKEY_QUERY) ? "dnssec-retry[DNSKEY]" : "dnssec-retry[DS]", 0);
553#endif
554
555 srv->queries++;
556 forwarded = 1;
557 forward->sentto = srv;
558 if (!forward->forwardall)
559 break;
560 forward->forwardall++;
Simon Kelley74d4fcd2021-03-15 21:59:51 +0000561 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000562 }
563
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700564 if (++start == last)
565 break;
566 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000567
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700568 if (forwarded || is_dnssec)
569 {
570 forward->forward_timestamp = dnsmasq_milliseconds();
571 return 1;
572 }
573
574 /* could not send on, prepare to return */
575 header->id = htons(forward->frec_src.orig_id);
576 free_frec(forward); /* cancel */
577 ede = EDE_NETERR;
578
579 reply:
Simon Kelleyb8187c82005-11-26 21:46:27 +0000580 if (udpfd != -1)
581 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700582 if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, limit, first, last, ede)))
583 return 0;
584
Simon Kelley1682d152018-08-03 20:38:18 +0100585 if (oph)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700586 {
587 u16 swap = htons((u16)ede);
588
589 if (ede != EDE_UNSET)
590 plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
591 else
592 plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
593 }
594
595#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
596 if (option_bool(OPT_CMARK_ALST_EN))
597 {
598 unsigned int mark;
599 int have_mark = get_incoming_mark(udpaddr, dst_addr, /* istcp: */ 0, &mark);
600 if (have_mark && ((u32)mark & daemon->allowlist_mask))
601 report_addresses(header, plen, mark);
602 }
603#endif
604
Simon Kelley54dd3932012-06-20 11:23:38 +0100605 send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000606 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700607
Simon Kelley824af852008-02-12 20:43:05 +0000608 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000609}
610
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700611/* Check if any frecs need to do a retry, and action that if so.
612 Return time in milliseconds until he next retry will be required,
613 or -1 if none. */
614int fast_retry(time_t now)
615{
616 struct frec *f;
617 int ret = -1;
618
619 if (daemon->fast_retry_time != 0)
620 {
621 u32 millis = dnsmasq_milliseconds();
622
623 for (f = daemon->frec_list; f; f = f->next)
624 if (f->sentto && f->stash && difftime(now, f->time) < daemon->fast_retry_timeout)
625 {
626#ifdef HAVE_DNSSEC
627 if (f->blocking_query)
628 continue;
629#endif
630 /* t is milliseconds since last query sent. */
631 int to_run, t = (int)(millis - f->forward_timestamp);
632
633 if (t < f->forward_delay)
634 to_run = f->forward_delay - t;
635 else
636 {
637 unsigned char *udpsz;
638 unsigned short udp_size = PACKETSZ; /* default if no EDNS0 */
639 struct dns_header *header = (struct dns_header *)daemon->packet;
640
641 /* packet buffer overwritten */
642 daemon->srv_save = NULL;
643
644 blockdata_retrieve(f->stash, f->stash_len, (void *)header);
645
646 /* UDP size already set in saved query. */
647 if (find_pseudoheader(header, f->stash_len, NULL, &udpsz, NULL, NULL))
648 GETSHORT(udp_size, udpsz);
649
650 daemon->log_display_id = f->frec_src.log_id;
651
652 forward_query(-1, NULL, NULL, 0, header, f->stash_len, ((char *) header) + udp_size, now, f,
653 f->flags & FREC_AD_QUESTION, f->flags & FREC_DO_QUESTION, 1);
654
655 to_run = f->forward_delay = 2 * f->forward_delay;
656 }
657
658 if (ret == -1 || ret > to_run)
659 ret = to_run;
660 }
661
662 }
663 return ret;
664}
665
666static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domain) {
667 /* Similar algorithm to search_servers. */
668 struct ipsets *ipset_pos, *ret = NULL;
669 unsigned int namelen = strlen(domain);
670 unsigned int matchlen = 0;
Tarun Kundu567116b2024-08-15 16:22:58 -0700671 if (daemon->ipsets)
672 for (ipset_pos = setlist; ipset_pos; ipset_pos = ipset_pos->next)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700673 {
674 unsigned int domainlen = strlen(ipset_pos->domain);
675 const char *matchstart = domain + namelen - domainlen;
676 if (namelen >= domainlen && hostname_isequal(matchstart, ipset_pos->domain) &&
677 (domainlen == 0 || namelen == domainlen || *(matchstart - 1) == '.' ) &&
678 domainlen >= matchlen)
679 {
680 matchlen = domainlen;
681 ret = ipset_pos;
682 }
683 }
684
685 return ret;
686}
687
Simon Kelleyed4c0762013-10-08 20:46:34 +0100688static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
Simon Kelleyfe3992f2015-04-03 21:25:05 +0100689 int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700690 union mysockaddr *query_source, unsigned char *limit, int ede)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100691{
Simon Kelley36717ee2004-09-20 19:20:58 +0100692 unsigned char *pheader, *sizep;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700693 struct ipsets *ipsets = NULL, *nftsets = NULL;
694 int is_sign;
Simon Kelley07ed5852018-05-04 21:52:22 +0100695 unsigned int rcode = RCODE(header);
Simon Kelleycdeda282006-03-16 20:16:06 +0000696 size_t plen;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700697
Simon Kelley83349b82014-02-10 21:02:01 +0000698 (void)ad_reqd;
Simon Kelley982faf42015-04-03 21:42:30 +0100699 (void)do_bit;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700700
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000701#ifdef HAVE_IPSET
Tarun Kundu567116b2024-08-15 16:22:58 -0700702 if (extract_request(header, n, daemon->namebuff, NULL))
703 {
704 if (header && (ntohs(header->arcount)))
705 n = process_appid_catid(header, n);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700706 ipsets = domain_find_sets(daemon->ipsets, daemon->namebuff);
Tarun Kundu567116b2024-08-15 16:22:58 -0700707 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700708#endif
709
710#ifdef HAVE_NFTSET
711 if (daemon->nftsets && extract_request(header, n, daemon->namebuff, NULL))
712 nftsets = domain_find_sets(daemon->nftsets, daemon->namebuff);
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000713#endif
Simon Kelley25e63f12020-11-25 21:17:52 +0000714
Simon Kelley5bb88f02015-12-21 16:23:47 +0000715 if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100716 {
Simon Kelley07ed5852018-05-04 21:52:22 +0100717 /* Get extended RCODE. */
718 rcode |= sizep[2] << 4;
719
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700720 if (option_bool(OPT_CLIENT_SUBNET) && !check_source(header, plen, pheader, query_source))
Simon Kelleyed4c0762013-10-08 20:46:34 +0100721 {
722 my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
723 return 0;
724 }
Simon Kelley613ad152014-02-25 23:02:28 +0000725
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000726 if (!is_sign)
Simon Kelley613ad152014-02-25 23:02:28 +0000727 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000728 if (added_pheader)
729 {
730 /* client didn't send EDNS0, we added one, strip it off before returning answer. */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700731 rrfilter(header, &n, RRFILTER_EDNS0);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000732 pheader = NULL;
733 }
734 else
735 {
736 /* If upstream is advertising a larger UDP packet size
737 than we allow, trim it so that we don't get overlarge
738 requests for the client. We can't do this for signed packets. */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700739 unsigned short udpsz;
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000740 GETSHORT(udpsz, sizep);
741 if (udpsz > daemon->edns_pktsz)
Simon Kelley33702ab2015-12-28 23:17:15 +0000742 {
743 sizep -= 2;
744 PUTSHORT(daemon->edns_pktsz, sizep);
745 }
746
747#ifdef HAVE_DNSSEC
748 /* If the client didn't set the do bit, but we did, reset it. */
749 if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
750 {
751 unsigned short flags;
752 sizep += 2; /* skip RCODE */
753 GETSHORT(flags, sizep);
754 flags &= ~0x8000;
755 sizep -= 2;
756 PUTSHORT(flags, sizep);
757 }
758#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000759 }
Simon Kelley613ad152014-02-25 23:02:28 +0000760 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100761 }
Simon Kelley83349b82014-02-10 21:02:01 +0000762
Simon Kelley28866e92011-02-14 20:19:14 +0000763 /* RFC 4035 sect 4.6 para 3 */
Giovanni Bajo237724c2012-04-05 02:46:52 +0200764 if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
Simon Kelley795501b2014-01-08 18:11:55 +0000765 header->hb4 &= ~HB4_AD;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700766
767 header->hb4 |= HB4_RA; /* recursion if available */
768
Simon Kelley07ed5852018-05-04 21:52:22 +0100769 if (OPCODE(header) != QUERY)
Simon Kelley8938ae02014-05-01 17:46:25 +0100770 return resize_packet(header, n, pheader, plen);
Simon Kelley07ed5852018-05-04 21:52:22 +0100771
772 if (rcode != NOERROR && rcode != NXDOMAIN)
773 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000774 union all_addr a;
775 a.log.rcode = rcode;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700776 a.log.ede = ede;
777 log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL, 0);
Simon Kelley07ed5852018-05-04 21:52:22 +0100778
779 return resize_packet(header, n, pheader, plen);
780 }
Simon Kelley36717ee2004-09-20 19:20:58 +0100781
Simon Kelley0a852542005-03-23 20:28:59 +0000782 /* Complain loudly if the upstream server is non-recursive. */
Simon Kelley07ed5852018-05-04 21:52:22 +0100783 if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
Simon Kelley0a852542005-03-23 20:28:59 +0000784 server && !(server->flags & SERV_WARNED_RECURSIVE))
785 {
Petr Mensik51cdd1a2019-07-04 20:28:08 +0200786 (void)prettyprint_addr(&server->addr, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +0100787 my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
Simon Kelley28866e92011-02-14 20:19:14 +0000788 if (!option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000789 server->flags |= SERV_WARNED_RECURSIVE;
790 }
Giovanni Bajoe292e932012-04-22 14:32:02 +0200791
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700792 if (header->hb3 & HB3_TC)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100793 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700794 log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
795 header->ancount = htons(0);
796 header->nscount = htons(0);
797 header->arcount = htons(0);
Simon Kelley36717ee2004-09-20 19:20:58 +0100798 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700799
800 if (!(header->hb3 & HB3_TC) && (!bogusanswer || (header->hb4 & HB4_CD)))
Simon Kelley36717ee2004-09-20 19:20:58 +0100801 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700802 if (rcode == NXDOMAIN && extract_request(header, n, daemon->namebuff, NULL) &&
803 (check_for_local_domain(daemon->namebuff, now) || lookup_domain(daemon->namebuff, F_CONFIG, NULL, NULL)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100804 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100805 /* if we forwarded a query for a locally known name (because it was for
806 an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
807 since we know that the domain exists, even if upstream doesn't */
Simon Kelley572b41e2011-02-18 18:11:18 +0000808 header->hb3 |= HB3_AA;
809 SET_RCODE(header, NOERROR);
Simon Kelley6938f342014-01-26 22:47:39 +0000810 cache_secure = 0;
Simon Kelley36717ee2004-09-20 19:20:58 +0100811 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000812
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700813 if (daemon->doctors && do_doctor(header, n, daemon->namebuff))
Simon Kelley6938f342014-01-26 22:47:39 +0000814 cache_secure = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700815
816 /* check_for_bogus_wildcard() does it's own caching, so
817 don't call extract_addresses() if it triggers. */
818 if (daemon->bogus_addr && rcode != NXDOMAIN &&
819 check_for_bogus_wildcard(header, n, daemon->namebuff, now))
820 {
821 header->ancount = htons(0);
822 header->nscount = htons(0);
823 header->arcount = htons(0);
824 SET_RCODE(header, NXDOMAIN);
825 header->hb3 &= ~HB3_AA;
826 cache_secure = 0;
827 ede = EDE_BLOCKED;
828 }
829 else
830 {
831 int rc = extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure);
832
833 if (rc != 0)
834 {
835 header->ancount = htons(0);
836 header->nscount = htons(0);
837 header->arcount = htons(0);
838 cache_secure = 0;
839 }
840
841 if (rc == 1)
842 {
843 my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
844 ede = EDE_BLOCKED;
845 }
846
847 if (rc == 2)
848 {
849 /* extract_addresses() found a malformed answer. */
850 SET_RCODE(header, SERVFAIL);
851 ede = EDE_OTHER;
852 }
853 }
854
855 if (RCODE(header) == NOERROR && rrfilter(header, &n, RRFILTER_CONF) > 0)
856 ede = EDE_FILTERED;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100857 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100858
Simon Kelleya25720a2014-01-14 23:13:55 +0000859#ifdef HAVE_DNSSEC
Simon Kelley6938f342014-01-26 22:47:39 +0000860 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000861 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700862 if (bogusanswer)
863 {
864 if (!(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
865 {
866 /* Bogus reply, turn into SERVFAIL */
867 SET_RCODE(header, SERVFAIL);
868 header->ancount = htons(0);
869 header->nscount = htons(0);
870 header->arcount = htons(0);
871 ede = EDE_DNSSEC_BOGUS;
872 }
873 }
874 else if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000875 header->hb4 |= HB4_AD;
876
877 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
878 if (!do_bit)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700879 rrfilter(header, &n, RRFILTER_DNSSEC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +0000880 }
Simon Kelleya25720a2014-01-14 23:13:55 +0000881#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700883 /* the code above can elide sections of the packet. Find the new length here
884 and put back pseudoheader if it was removed. */
885 n = resize_packet(header, n, pheader, plen);
886
887 if (pheader && ede != EDE_UNSET)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100888 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -0700889 u16 swap = htons((u16)ede);
890 n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
891 }
892
893 if (RCODE(header) == NXDOMAIN)
894 server->nxdomain_replies++;
895
896 return n;
897}
898
899#ifdef HAVE_DNSSEC
900static void dnssec_validate(struct frec *forward, struct dns_header *header,
901 ssize_t plen, int status, time_t now)
902{
903 struct frec *orig;
904 int log_resource = 0;
905
906 daemon->log_display_id = forward->frec_src.log_id;
907
908 /* We've had a reply already, which we're validating. Ignore this duplicate */
909 if (forward->blocking_query)
910 return;
911
912 /* If all replies to a query are REFUSED, give up. */
913 if (RCODE(header) == REFUSED)
914 status = STAT_ABANDONED;
915 else if (header->hb3 & HB3_TC)
916 {
917 /* Truncated answer can't be validated.
918 If this is an answer to a DNSSEC-generated query, we still
919 need to get the client to retry over TCP, so return
920 an answer with the TC bit set, even if the actual answer fits.
921 */
922 status = STAT_TRUNCATED;
923 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
924 {
925 unsigned char *p = (unsigned char *)(header+1);
926 if (extract_name(header, plen, &p, daemon->namebuff, 0, 4) == 1)
927 log_query(F_UPSTREAM | F_NOEXTRA, daemon->namebuff, NULL, "truncated", (forward->flags & FREC_DNSKEY_QUERY) ? T_DNSKEY : T_DS);
928 }
929 }
930
931 /* Find the original query that started it all.... */
932 for (orig = forward; orig->dependent; orig = orig->dependent);
933
934 /* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
935 would invite infinite loops, since the answers to DNSKEY and DS queries
936 will not be cached, so they'll be repeated. */
937 if (!STAT_ISEQUAL(status, STAT_BOGUS) && !STAT_ISEQUAL(status, STAT_TRUNCATED) && !STAT_ISEQUAL(status, STAT_ABANDONED))
938 {
939 if (forward->flags & FREC_DNSKEY_QUERY)
940 status = dnssec_validate_by_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class, &orig->validate_counter);
941 else if (forward->flags & FREC_DS_QUERY)
942 status = dnssec_validate_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class, &orig->validate_counter);
943 else
944 status = dnssec_validate_reply(now, header, plen, daemon->namebuff, daemon->keyname, &forward->class,
945 !option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
946 NULL, NULL, NULL, &orig->validate_counter);
947 }
948
949 if (STAT_ISEQUAL(status, STAT_ABANDONED))
950 log_resource = 1;
951
952 /* Can't validate, as we're missing key data. Put this
953 answer aside, whilst we get that. */
954 if (STAT_ISEQUAL(status, STAT_NEED_DS) || STAT_ISEQUAL(status, STAT_NEED_KEY))
955 {
956 struct frec *new = NULL;
957 struct blockdata *stash;
958
959 /* Now save reply pending receipt of key data */
960 if ((stash = blockdata_alloc((char *)header, plen)))
961 {
962 /* validate routines leave name of required record in daemon->keyname */
963 unsigned int flags = STAT_ISEQUAL(status, STAT_NEED_KEY) ? FREC_DNSKEY_QUERY : FREC_DS_QUERY;
964
965 if ((new = lookup_frec_dnssec(daemon->keyname, forward->class, flags, header)))
966 {
967 /* This is tricky; it detects loops in the dependency
968 graph for DNSSEC validation, say validating A requires DS B
969 and validating DS B requires DNSKEY C and validating DNSKEY C requires DS B.
970 This should never happen in correctly signed records, but it's
971 likely the case that sufficiently broken ones can cause our validation
972 code requests to exhibit cycles. The result is that the ->blocking_query list
973 can form a cycle, and under certain circumstances that can lock us in
974 an infinite loop. Here we transform the situation into ABANDONED. */
975 struct frec *f;
976 for (f = new; f; f = f->blocking_query)
977 if (f == forward)
978 break;
979
980 if (!f)
981 {
982 forward->next_dependent = new->dependent;
983 new->dependent = forward;
984 /* Make consistent, only replace query copy with unvalidated answer
985 when we set ->blocking_query. */
986 if (forward->stash)
987 blockdata_free(forward->stash);
988 forward->blocking_query = new;
989 forward->stash_len = plen;
990 forward->stash = stash;
991 return;
992 }
993 }
994 else if (orig->work_counter-- == 0)
995 {
996 my_syslog(LOG_WARNING, _("limit exceeded: per-query subqueries"));
997 log_resource = 1;
998 }
999 else
1000 {
1001 struct server *server;
1002 void *hash;
1003 size_t nn;
1004 int serverind, fd;
1005 struct randfd_list *rfds = NULL;
1006
1007 /* Make sure we don't expire and free the orig frec during the
1008 allocation of a new one: third arg of get_new_frec() does that. */
1009 if ((serverind = dnssec_server(forward->sentto, daemon->keyname, NULL, NULL)) != -1 &&
1010 (server = daemon->serverarray[serverind]) &&
1011 (nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
1012 daemon->keyname, forward->class,
1013 STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz)) &&
1014 (hash = hash_questions(header, nn, daemon->namebuff)) &&
1015 (fd = allocate_rfd(&rfds, server)) != -1 &&
1016 (new = get_new_frec(now, server, 1)))
1017 {
1018 struct frec *next = new->next;
1019
1020 *new = *forward; /* copy everything, then overwrite */
1021 new->next = next;
1022 new->blocking_query = NULL;
1023
1024 new->frec_src.log_id = daemon->log_display_id = ++daemon->log_id;
1025 new->sentto = server;
1026 new->rfds = rfds;
1027 new->frec_src.next = NULL;
1028 new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
1029 new->flags |= flags;
1030 new->forwardall = 0;
1031
1032 forward->next_dependent = NULL;
1033 new->dependent = forward; /* to find query awaiting new one. */
1034
1035 /* Make consistent, only replace query copy with unvalidated answer
1036 when we set ->blocking_query. */
1037 forward->blocking_query = new;
1038 if (forward->stash)
1039 blockdata_free(forward->stash);
1040 forward->stash_len = plen;
1041 forward->stash = stash;
1042
1043 memcpy(new->hash, hash, HASH_SIZE);
1044 new->new_id = get_id();
1045 header->id = htons(new->new_id);
1046 /* Save query for retransmission and de-dup */
1047 new->stash = blockdata_alloc((char *)header, nn);
1048 new->stash_len = nn;
1049 if (daemon->fast_retry_time != 0)
1050 new->forward_timestamp = dnsmasq_milliseconds();
1051
1052 /* Don't resend this. */
1053 daemon->srv_save = NULL;
1054
1055#ifdef HAVE_CONNTRACK
1056 if (option_bool(OPT_CONNTRACK))
1057 set_outgoing_mark(orig, fd);
1058#endif
1059
1060 server_send(server, fd, header, nn, 0);
1061 server->queries++;
1062#ifdef HAVE_DUMPFILE
1063 dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd);
1064#endif
1065 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, daemon->keyname, &server->addr,
1066 STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
1067 return;
1068 }
1069
1070 free_rfds(&rfds); /* error unwind */
1071 }
1072
1073 blockdata_free(stash); /* don't leak this on failure. */
1074 }
1075
1076 /* sending DNSSEC query failed or loop detected. */
1077 status = STAT_ABANDONED;
1078 }
1079
1080 if (log_resource)
1081 {
1082 /* Log the actual validation that made us barf. */
1083 unsigned char *p = (unsigned char *)(header+1);
1084 if (extract_name(header, plen, &p, daemon->namebuff, 0, 4) == 1)
1085 my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
1086 daemon->namebuff[0] ? daemon->namebuff : ".");
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001087 }
1088
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001089#ifdef HAVE_DUMPFILE
1090 if (STAT_ISEQUAL(status, STAT_BOGUS) || STAT_ISEQUAL(status, STAT_ABANDONED))
1091 dump_packet_udp((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
1092 header, (size_t)plen, &forward->sentto->addr, NULL, -daemon->port);
1093#endif
1094
1095 /* Validated original answer, all done. */
1096 if (!forward->dependent)
1097 return_reply(now, forward, header, plen, status);
1098 else
1099 {
1100 /* validated subsidiary query/queries, (and cached result)
1101 pop that and return to the previous query/queries we were working on. */
1102 struct frec *prev, *nxt = forward->dependent;
1103
1104 free_frec(forward);
1105
1106 while ((prev = nxt))
1107 {
1108 /* ->next_dependent will have changed after return from recursive call below. */
1109 nxt = prev->next_dependent;
1110 prev->blocking_query = NULL; /* already gone */
1111 blockdata_retrieve(prev->stash, prev->stash_len, (void *)header);
1112 dnssec_validate(prev, header, prev->stash_len, status, now);
1113 }
1114 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001115}
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001116#endif
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001117
Simon Kelley3be34542004-09-11 19:12:13 +01001118/* sets new last_server */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001119void reply_query(int fd, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001120{
1121 /* packet from peer server, extract data for cache, and send to
1122 original requester */
Simon Kelley572b41e2011-02-18 18:11:18 +00001123 struct dns_header *header;
Simon Kelleyde379512004-06-22 20:23:33 +01001124 union mysockaddr serveraddr;
Simon Kelley832af0b2007-01-21 20:01:28 +00001125 struct frec *forward;
Simon Kelleyde379512004-06-22 20:23:33 +01001126 socklen_t addrlen = sizeof(serveraddr);
Simon Kelley60b68062014-01-08 12:10:28 +00001127 ssize_t n = recvfrom(fd, daemon->packet, daemon->packet_buff_sz, 0, &serveraddr.sa, &addrlen);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001128 struct server *server;
Simon Kelley8a9be9e2014-01-25 23:17:21 +00001129 void *hash;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001130 int first, last, c;
1131
Simon Kelleycdeda282006-03-16 20:16:06 +00001132 /* packet buffer overwritten */
1133 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001134
Simon Kelleyde379512004-06-22 20:23:33 +01001135 /* Determine the address of the server replying so that we can mark that as good */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001136 if (serveraddr.sa.sa_family == AF_INET6)
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001137 serveraddr.in6.sin6_flowinfo = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001138
Simon Kelley490f9072014-03-24 22:04:42 +00001139 header = (struct dns_header *)daemon->packet;
Simon Kelley6b173352018-05-08 18:32:14 +01001140
Simon Kelley490f9072014-03-24 22:04:42 +00001141 if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
1142 return;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001143
1144 hash = hash_questions(header, n, daemon->namebuff);
Simon Kelley490f9072014-03-24 22:04:42 +00001145
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001146 if (!(forward = lookup_frec(ntohs(header->id), fd, hash, &first, &last)))
1147 return;
1148
1149 /* spoof check: answer must come from known server, also
1150 we may have sent the same query to multiple servers from
1151 the same local socket, and would like to know which one has answered. */
1152 for (c = first; c != last; c++)
1153 if (sockaddr_isequal(&daemon->serverarray[c]->addr, &serveraddr))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001154 break;
Simon Kelley490f9072014-03-24 22:04:42 +00001155
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001156 if (c == last)
Simon Kelley490f9072014-03-24 22:04:42 +00001157 return;
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001158
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001159 server = daemon->serverarray[c];
1160
1161 if (RCODE(header) != REFUSED)
1162 daemon->serverarray[first]->last_server = c;
1163 else if (daemon->serverarray[first]->last_server == c)
1164 daemon->serverarray[first]->last_server = -1;
1165
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001166 /* If sufficient time has elapsed, try and expand UDP buffer size again. */
1167 if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
1168 server->edns_pktsz = daemon->edns_pktsz;
1169
Simon Kelley25cf5e32015-01-09 15:53:03 +00001170 /* log_query gets called indirectly all over the place, so
1171 pass these in global variables - sorry. */
Simon Kelley15b60dd2020-11-18 18:34:55 +00001172 daemon->log_display_id = forward->frec_src.log_id;
1173 daemon->log_source_addr = &forward->frec_src.source;
Simon Kelley25cf5e32015-01-09 15:53:03 +00001174
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001175#ifdef HAVE_DUMPFILE
1176 dump_packet_udp((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
1177 (void *)header, n, &serveraddr, NULL, fd);
1178#endif
1179
Glen Huang32fc6db2014-12-27 15:28:12 +00001180 if (daemon->ignore_addr && RCODE(header) == NOERROR &&
Simon Kelley9eaa91b2021-03-17 20:31:06 +00001181 check_for_ignored_address(header, n))
Glen Huang32fc6db2014-12-27 15:28:12 +00001182 return;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001183
Simon Kelleyd3a8b392015-12-23 12:27:37 +00001184 /* Note: if we send extra options in the EDNS0 header, we can't recreate
1185 the query from the reply. */
Simon Kelley34e26e12018-05-10 20:54:57 +01001186 if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
Simon Kelleyd3a8b392015-12-23 12:27:37 +00001187 forward->forwardall == 0 &&
1188 !(forward->flags & FREC_HAS_EXTRADATA))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001189 /* for broken servers, attempt to send to another one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001190 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001191 unsigned char *pheader, *udpsz;
1192 unsigned short udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelley1a6bca82008-07-11 11:11:42 +01001193 size_t plen;
1194 int is_sign;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001195 size_t nn = 0;
1196
Simon Kelley1f60a182018-05-11 16:44:16 +01001197#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001198 /* The query MAY have got a good answer, and be awaiting
1199 the results of further queries, in which case
1200 The Stash contains something else and we don't need to retry anyway. */
1201 if (forward->blocking_query)
1202 return;
1203
Simon Kelleya0088e82018-05-10 21:43:14 +01001204 if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
1205 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001206 /* DNSSEC queries have a copy of the original query stashed. */
Simon Kelleya0088e82018-05-10 21:43:14 +01001207 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001208 nn = forward->stash_len;
1209 udp_size = daemon->edns_pktsz;
Simon Kelleya0088e82018-05-10 21:43:14 +01001210 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001211 else
Simon Kelley1f60a182018-05-11 16:44:16 +01001212#endif
Simon Kelley832af0b2007-01-21 20:01:28 +00001213 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001214 /* in fast retry mode, we have a copy of the query. */
1215 if (daemon->fast_retry_time != 0 && forward->stash)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001216 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001217 blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
1218 nn = forward->stash_len;
1219 /* UDP size already set in saved query. */
1220 if (find_pseudoheader(header, (size_t)n, NULL, &udpsz, NULL, NULL))
1221 GETSHORT(udp_size, udpsz);
1222 }
1223 else
1224 {
1225 /* recreate query from reply */
1226 if ((pheader = find_pseudoheader(header, (size_t)n, &plen, &udpsz, &is_sign, NULL)))
1227 GETSHORT(udp_size, udpsz);
1228
1229 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1230 (bounded by the maximum configured). If no EDNS0, then it
1231 defaults to 512 */
1232 if (udp_size > daemon->edns_pktsz)
1233 udp_size = daemon->edns_pktsz;
1234 else if (udp_size < PACKETSZ)
1235 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
1236
1237 header->ancount = htons(0);
1238 header->nscount = htons(0);
1239 header->arcount = htons(0);
swiggerbd7bfa22015-06-01 20:54:59 +01001240 header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001241 header->hb4 &= ~(HB4_RA | HB4_RCODE | HB4_CD | HB4_AD);
Simon Kelley1801a292016-01-17 21:53:57 +00001242 if (forward->flags & FREC_CHECKING_DISABLED)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001243 header->hb4 |= HB4_CD;
Simon Kelley1801a292016-01-17 21:53:57 +00001244 if (forward->flags & FREC_AD_QUESTION)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001245 header->hb4 |= HB4_AD;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001246
1247 if (!is_sign &&
1248 (nn = resize_packet(header, (size_t)n, pheader, plen)) &&
1249 (forward->flags & FREC_DO_QUESTION))
Simon Kelley33702ab2015-12-28 23:17:15 +00001250 add_do_bit(header, nn, (unsigned char *)pheader + plen);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001251 }
1252 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001253
1254 if (nn)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001255 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001256 forward_query(-1, NULL, NULL, 0, header, nn, ((char *) header) + udp_size, now, forward,
1257 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, 0);
1258 return;
1259 }
Simon Kelley22dee512017-10-13 22:54:00 +01001260 }
Simon Kelleyc1a4e252018-01-19 22:00:05 +00001261
Simon Kelley1a6bca82008-07-11 11:11:42 +01001262 /* If the answer is an error, keep the forward record in place in case
1263 we get a good reply from another server. Kill it when we've
1264 had replies from all to avoid filling the forwarding table when
1265 everything is broken */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001266
1267 /* decrement count of replies recieved if we sent to more than one server. */
1268 if (forward->forwardall && (--forward->forwardall > 1) && RCODE(header) == REFUSED)
1269 return;
1270
1271 /* We tried resending to this server with a smaller maximum size and got an answer.
1272 Make that permanent. To avoid reduxing the packet size for a single dropped packet,
1273 only do this when we get a truncated answer, or one larger than the safe size. */
1274 if (server->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
1275 ((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
Simon Kelley1a6bca82008-07-11 11:11:42 +01001276 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001277 server->edns_pktsz = SAFE_PKTSZ;
1278 server->pktsz_reduced = now;
1279 (void)prettyprint_addr(&server->addr, daemon->addrbuff);
1280 my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
1281 }
1282
1283 forward->sentto = server;
1284
1285 /* We have a good answer, and will now validate it or return it.
1286 It may be some time before this the validation completes, but we don't need
1287 any more answers, so close the socket(s) on which we were expecting
1288 answers, to conserve file descriptors, and to save work reading and
1289 discarding answers for other upstreams. */
1290 free_rfds(&forward->rfds);
1291
1292 /* calculate modified moving average of server latency */
1293 if (server->query_latency == 0)
1294 server->mma_latency = (dnsmasq_milliseconds() - forward->forward_timestamp) * 128; /* init */
1295 else
1296 server->mma_latency += dnsmasq_milliseconds() - forward->forward_timestamp - server->query_latency;
1297 /* denominator controls how many queries we average over. */
1298 server->query_latency = server->mma_latency/128;
1299
1300
Simon Kelley3a237152013-12-12 12:15:50 +00001301#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001302 if ((forward->sentto->flags & SERV_DO_DNSSEC) &&
1303 option_bool(OPT_DNSSEC_VALID) &&
1304 !(forward->flags & FREC_CHECKING_DISABLED))
1305 dnssec_validate(forward, header, n, STAT_OK, now);
1306 else
1307#endif
1308 return_reply(now, forward, header, n, STAT_OK);
1309}
1310
1311static void return_reply(time_t now, struct frec *forward, struct dns_header *header, ssize_t n, int status)
1312{
1313 int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
1314 size_t nn;
1315 int ede = EDE_UNSET;
1316
1317 (void)status;
1318
1319 daemon->log_display_id = forward->frec_src.log_id;
1320 daemon->log_source_addr = &forward->frec_src.source;
1321
1322 /* Don't cache replies where DNSSEC validation was turned off, either
1323 the upstream server told us so, or the original query specified it. */
1324 if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
1325 no_cache_dnssec = 1;
1326
1327#ifdef HAVE_DNSSEC
1328 if (!STAT_ISEQUAL(status, STAT_OK))
1329 {
1330 /* status is STAT_OK when validation not turned on. */
1331 no_cache_dnssec = 0;
1332
1333 if (STAT_ISEQUAL(status, STAT_TRUNCATED))
Simon Kelley3a237152013-12-12 12:15:50 +00001334 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001335 header->hb3 |= HB3_TC;
1336 log_query(F_SECSTAT, "result", NULL, "TRUNCATED", 0);
1337 }
1338 else
1339 {
1340 char *result, *domain = "result";
1341 union all_addr a;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001342
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001343 a.log.ede = ede = errflags_to_ede(status);
1344
1345 if (STAT_ISEQUAL(status, STAT_ABANDONED))
Simon Kelley00a5b5d2014-02-28 18:10:55 +00001346 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001347 result = "ABANDONED";
1348 status = STAT_BOGUS;
Simon Kelley3a237152013-12-12 12:15:50 +00001349 }
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001350 else
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001351 result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
Simon Kelley5d3b87a2014-01-20 11:57:23 +00001352
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001353 if (STAT_ISEQUAL(status, STAT_SECURE))
Simon Kelley3a237152013-12-12 12:15:50 +00001354 cache_secure = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001355 else if (STAT_ISEQUAL(status, STAT_BOGUS))
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001356 {
1357 no_cache_dnssec = 1;
1358 bogusanswer = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001359
1360 if (extract_request(header, n, daemon->namebuff, NULL))
1361 domain = daemon->namebuff;
Simon Kelleyfe3992f2015-04-03 21:25:05 +01001362 }
Simon Kelley3a237152013-12-12 12:15:50 +00001363
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001364 log_query(F_SECSTAT, domain, &a, result, 0);
1365 }
1366 }
Simon Kelley15b60dd2020-11-18 18:34:55 +00001367
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001368 if ((daemon->limit[LIMIT_CRYPTO] - forward->validate_counter) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
1369 daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - forward->validate_counter;
1370
1371 if ((daemon->limit[LIMIT_WORK] - forward->work_counter) > (int)daemon->metrics[METRIC_WORK_HWM])
1372 daemon->metrics[METRIC_WORK_HWM] = daemon->limit[LIMIT_WORK] - forward->work_counter;
1373#endif
1374
1375 if (option_bool(OPT_NO_REBIND))
1376 check_rebind = !(forward->flags & FREC_NOREBIND);
1377
1378 /* restore CD bit to the value in the query */
1379 if (forward->flags & FREC_CHECKING_DISABLED)
1380 header->hb4 |= HB4_CD;
1381 else
1382 header->hb4 &= ~HB4_CD;
1383
1384 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
1385 since the cache is ignorant of such things. */
1386 if (forward->flags & FREC_NO_CACHE)
1387 no_cache_dnssec = 1;
1388
1389 if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
1390 forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
1391 forward->flags & FREC_ADDED_PHEADER, &forward->frec_src.source,
1392 ((unsigned char *)header) + daemon->edns_pktsz, ede)))
1393 {
1394 struct frec_src *src;
1395
1396 header->id = htons(forward->frec_src.orig_id);
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001397#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001398 /* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
1399 greater than the no-EDNS0-implied 512 to have space for the RRSIGS. If, having stripped them and the EDNS0
1400 header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
1401 if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
1402 {
1403 header->ancount = htons(0);
1404 header->nscount = htons(0);
1405 header->arcount = htons(0);
1406 header->hb3 |= HB3_TC;
1407 nn = resize_packet(header, nn, NULL, 0);
1408 }
1409#endif
1410
1411 for (src = &forward->frec_src; src; src = src->next)
1412 {
1413 header->id = htons(src->orig_id);
1414
1415#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
1416 if (option_bool(OPT_CMARK_ALST_EN))
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001417 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001418 unsigned int mark;
1419 int have_mark = get_incoming_mark(&src->source, &src->dest, /* istcp: */ 0, &mark);
1420 if (have_mark && ((u32)mark & daemon->allowlist_mask))
1421 report_addresses(header, nn, mark);
Simon Kelley5aa5f0f2015-12-21 17:20:35 +00001422 }
1423#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001424
1425 if (src->fd != -1)
Simon Kelley15b60dd2020-11-18 18:34:55 +00001426 {
Simon Kelley6b173352018-05-08 18:32:14 +01001427#ifdef HAVE_DUMPFILE
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001428 dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd);
1429#endif
Simon Kelley04490bf2021-01-22 16:49:12 +00001430 send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
Simon Kelley15b60dd2020-11-18 18:34:55 +00001431 &src->source, &src->dest, src->iface);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001432
Simon Kelley15b60dd2020-11-18 18:34:55 +00001433 if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
1434 {
1435 daemon->log_display_id = src->log_id;
1436 daemon->log_source_addr = &src->source;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001437 log_query(F_UPSTREAM, "query", NULL, "duplicate", 0);
Simon Kelley15b60dd2020-11-18 18:34:55 +00001438 }
1439 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001440 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001441 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001442
1443 free_frec(forward); /* cancel */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001444}
Simon Kelley44a2a312004-03-10 20:04:35 +00001445
Simon Kelley1a6bca82008-07-11 11:11:42 +01001446
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001447#ifdef HAVE_CONNTRACK
1448static int is_query_allowed_for_mark(u32 mark, const char *name)
1449{
1450 int is_allowable_name, did_validate_name = 0;
1451 struct allowlist *allowlists;
1452 char **patterns_pos;
1453
1454 for (allowlists = daemon->allowlists; allowlists; allowlists = allowlists->next)
1455 if (allowlists->mark == (mark & daemon->allowlist_mask & allowlists->mask))
1456 for (patterns_pos = allowlists->patterns; *patterns_pos; patterns_pos++)
1457 {
1458 if (!strcmp(*patterns_pos, "*"))
1459 return 1;
1460 if (!did_validate_name)
1461 {
1462 is_allowable_name = name ? is_valid_dns_name(name) : 0;
1463 did_validate_name = 1;
1464 }
1465 if (is_allowable_name && is_dns_name_matching_pattern(name, *patterns_pos))
1466 return 1;
1467 }
1468 return 0;
1469}
1470
1471static size_t answer_disallowed(struct dns_header *header, size_t qlen, u32 mark, const char *name)
1472{
1473 unsigned char *p;
1474 (void)name;
1475 (void)mark;
1476
1477#ifdef HAVE_UBUS
1478 if (name)
1479 ubus_event_bcast_connmark_allowlist_refused(mark, name);
1480#endif
1481
1482 setup_reply(header, /* flags: */ 0, EDE_BLOCKED);
1483
1484 if (!(p = skip_questions(header, qlen)))
1485 return 0;
1486 return p - (unsigned char *)header;
1487}
1488#endif
1489
Simon Kelley5aabfc72007-08-29 11:24:47 +01001490void receive_query(struct listener *listen, time_t now)
Simon Kelley44a2a312004-03-10 20:04:35 +00001491{
Simon Kelley572b41e2011-02-18 18:11:18 +00001492 struct dns_header *header = (struct dns_header *)daemon->packet;
Simon Kelley44a2a312004-03-10 20:04:35 +00001493 union mysockaddr source_addr;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001494 unsigned char *pheader;
1495 unsigned short type, udp_size = PACKETSZ; /* default if no EDNS0 */
Simon Kelleycc921df2019-01-02 22:48:59 +00001496 union all_addr dst_addr;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001497 struct in_addr netmask, dst_addr_4;
Simon Kelleycdeda282006-03-16 20:16:06 +00001498 size_t m;
1499 ssize_t n;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001500 int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001501#ifdef HAVE_CONNTRACK
1502 unsigned int mark = 0;
1503 int have_mark = 0;
1504 int is_single_query = 0, allowed = 1;
1505#endif
Vladislav Grishenko3b195962013-11-26 11:08:21 +00001506#ifdef HAVE_AUTH
1507 int local_auth = 0;
1508#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001509 struct iovec iov[1];
1510 struct msghdr msg;
1511 struct cmsghdr *cmptr;
Simon Kelley44a2a312004-03-10 20:04:35 +00001512 union {
1513 struct cmsghdr align; /* this ensures alignment */
Simon Kelley44a2a312004-03-10 20:04:35 +00001514 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001515#if defined(HAVE_LINUX_NETWORK)
Simon Kelley44a2a312004-03-10 20:04:35 +00001516 char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
Simon Kelley824af852008-02-12 20:43:05 +00001517#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
1518 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1519 CMSG_SPACE(sizeof(unsigned int))];
Simon Kelley44a2a312004-03-10 20:04:35 +00001520#elif defined(IP_RECVDSTADDR)
1521 char control[CMSG_SPACE(sizeof(struct in_addr)) +
1522 CMSG_SPACE(sizeof(struct sockaddr_dl))];
1523#endif
1524 } control_u;
Petr Menšík1c1b9252019-07-15 17:16:44 +02001525 int family = listen->addr.sa.sa_family;
Simon Kelley2329bef2013-12-03 13:41:16 +00001526 /* Can always get recvd interface for IPv6 */
Petr Menšík1c1b9252019-07-15 17:16:44 +02001527 int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001528
Simon Kelleycdeda282006-03-16 20:16:06 +00001529 /* packet buffer overwritten */
1530 daemon->srv_save = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00001531
Simon Kelleycc921df2019-01-02 22:48:59 +00001532 dst_addr_4.s_addr = dst_addr.addr4.s_addr = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001533 netmask.s_addr = 0;
1534
Simon Kelley7e5664b2013-04-05 16:57:41 +01001535 if (option_bool(OPT_NOWILD) && listen->iface)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001536 {
Simon Kelley4f7b3042012-11-28 21:27:02 +00001537 auth_dns = listen->iface->dns_auth;
1538
Petr Menšík1c1b9252019-07-15 17:16:44 +02001539 if (family == AF_INET)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001540 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001541 dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001542 netmask = listen->iface->netmask;
1543 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001544 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001545
Simon Kelley3be34542004-09-11 19:12:13 +01001546 iov[0].iov_base = daemon->packet;
1547 iov[0].iov_len = daemon->edns_pktsz;
Simon Kelley44a2a312004-03-10 20:04:35 +00001548
1549 msg.msg_control = control_u.control;
1550 msg.msg_controllen = sizeof(control_u);
1551 msg.msg_flags = 0;
1552 msg.msg_name = &source_addr;
1553 msg.msg_namelen = sizeof(source_addr);
1554 msg.msg_iov = iov;
1555 msg.msg_iovlen = 1;
1556
Simon Kelleyde379512004-06-22 20:23:33 +01001557 if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
Simon Kelley3be34542004-09-11 19:12:13 +01001558 return;
Simon Kelley44a2a312004-03-10 20:04:35 +00001559
Simon Kelley572b41e2011-02-18 18:11:18 +00001560 if (n < (int)sizeof(struct dns_header) ||
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001561 (msg.msg_flags & MSG_TRUNC) ||
Simon Kelley572b41e2011-02-18 18:11:18 +00001562 (header->hb3 & HB3_QR))
Simon Kelley3be34542004-09-11 19:12:13 +01001563 return;
Simon Kelley63437ff2017-09-06 22:34:21 +01001564
1565 /* Clear buffer beyond request to avoid risk of
1566 information disclosure. */
1567 memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
Simon Kelley44a2a312004-03-10 20:04:35 +00001568
Petr Menšík1c1b9252019-07-15 17:16:44 +02001569 source_addr.sa.sa_family = family;
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001570
Petr Menšík1c1b9252019-07-15 17:16:44 +02001571 if (family == AF_INET)
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001572 {
1573 /* Source-port == 0 is an error, we can't send back to that.
1574 http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
1575 if (source_addr.in.sin_port == 0)
1576 return;
1577 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001578 else
1579 {
1580 /* Source-port == 0 is an error, we can't send back to that. */
1581 if (source_addr.in6.sin6_port == 0)
1582 return;
1583 source_addr.in6.sin6_flowinfo = 0;
1584 }
Simon Kelley2a7a2b82014-03-22 19:18:06 +00001585
Simon Kelleyc8a80482014-03-05 14:29:54 +00001586 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
1587 if (option_bool(OPT_LOCAL_SERVICE))
1588 {
1589 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01001590
Petr Menšík1c1b9252019-07-15 17:16:44 +02001591 if (family == AF_INET6)
Simon Kelleyc8a80482014-03-05 14:29:54 +00001592 {
1593 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1594 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001595 is_same_net6(&addr->addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001596 break;
1597 }
1598 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00001599 {
1600 struct in_addr netmask;
1601 for (addr = daemon->interface_addrs; addr; addr = addr->next)
1602 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01001603 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00001604 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001605 is_same_net(addr->addr.addr4, source_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00001606 break;
1607 }
1608 }
1609 if (!addr)
1610 {
Simon Kelley0c8584e2014-03-12 20:12:56 +00001611 static int warned = 0;
1612 if (!warned)
1613 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001614 prettyprint_addr(&source_addr, daemon->addrbuff);
1615 my_syslog(LOG_WARNING, _("ignoring query from non-local network %s (logged only once)"), daemon->addrbuff);
Simon Kelley0c8584e2014-03-12 20:12:56 +00001616 warned = 1;
1617 }
Simon Kelleyc8a80482014-03-05 14:29:54 +00001618 return;
1619 }
1620 }
1621
Simon Kelley2329bef2013-12-03 13:41:16 +00001622 if (check_dst)
Simon Kelley44a2a312004-03-10 20:04:35 +00001623 {
Simon Kelley8a911cc2004-03-16 18:35:52 +00001624 struct ifreq ifr;
1625
Simon Kelley26128d22004-11-14 16:43:54 +00001626 if (msg.msg_controllen < sizeof(struct cmsghdr))
1627 return;
1628
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001629#if defined(HAVE_LINUX_NETWORK)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001630 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001631 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001632 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Simon Kelley26128d22004-11-14 16:43:54 +00001633 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001634 union {
1635 unsigned char *c;
1636 struct in_pktinfo *p;
1637 } p;
1638 p.c = CMSG_DATA(cmptr);
Simon Kelleycc921df2019-01-02 22:48:59 +00001639 dst_addr_4 = dst_addr.addr4 = p.p->ipi_spec_dst;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001640 if_index = p.p->ipi_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001641 }
1642#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
Petr Menšík1c1b9252019-07-15 17:16:44 +02001643 if (family == AF_INET)
Simon Kelley26128d22004-11-14 16:43:54 +00001644 {
1645 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001646 {
1647 union {
1648 unsigned char *c;
1649 unsigned int *i;
1650 struct in_addr *a;
1651#ifndef HAVE_SOLARIS_NETWORK
1652 struct sockaddr_dl *s;
Simon Kelley824af852008-02-12 20:43:05 +00001653#endif
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001654 } p;
1655 p.c = CMSG_DATA(cmptr);
1656 if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
Simon Kelleycc921df2019-01-02 22:48:59 +00001657 dst_addr_4 = dst_addr.addr4 = *(p.a);
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001658 else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
1659#ifdef HAVE_SOLARIS_NETWORK
1660 if_index = *(p.i);
1661#else
1662 if_index = p.s->sdl_index;
1663#endif
1664 }
Simon Kelley26128d22004-11-14 16:43:54 +00001665 }
1666#endif
1667
Petr Menšík1c1b9252019-07-15 17:16:44 +02001668 if (family == AF_INET6)
Simon Kelley26128d22004-11-14 16:43:54 +00001669 {
1670 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
Simon Kelleyc72daea2012-01-05 21:33:27 +00001671 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
Simon Kelley26128d22004-11-14 16:43:54 +00001672 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001673 union {
1674 unsigned char *c;
1675 struct in6_pktinfo *p;
1676 } p;
1677 p.c = CMSG_DATA(cmptr);
1678
Simon Kelleycc921df2019-01-02 22:48:59 +00001679 dst_addr.addr6 = p.p->ipi6_addr;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001680 if_index = p.p->ipi6_ifindex;
Simon Kelley26128d22004-11-14 16:43:54 +00001681 }
1682 }
Simon Kelley26128d22004-11-14 16:43:54 +00001683
1684 /* enforce available interface configuration */
1685
Simon Kelleye25db1f2013-01-29 22:10:26 +00001686 if (!indextoname(listen->fd, if_index, ifr.ifr_name))
Simon Kelley832af0b2007-01-21 20:01:28 +00001687 return;
1688
Petr Menšík1c1b9252019-07-15 17:16:44 +02001689 if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001690 {
1691 if (!option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001692 enumerate_interfaces(0);
Petr Menšík1c1b9252019-07-15 17:16:44 +02001693 if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
1694 !label_exception(if_index, family, &dst_addr))
Simon Kelleye25db1f2013-01-29 22:10:26 +00001695 return;
1696 }
1697
Petr Menšík1c1b9252019-07-15 17:16:44 +02001698 if (family == AF_INET && option_bool(OPT_LOCALISE))
Simon Kelley552af8b2012-02-29 20:10:31 +00001699 {
1700 struct irec *iface;
1701
Josh Soref730c6742017-02-06 16:14:04 +00001702 /* get the netmask of the interface which has the address we were sent to.
klemens43517fc2017-02-19 15:53:37 +00001703 This is no necessarily the interface we arrived on. */
Simon Kelley552af8b2012-02-29 20:10:31 +00001704
1705 for (iface = daemon->interfaces; iface; iface = iface->next)
1706 if (iface->addr.sa.sa_family == AF_INET &&
1707 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1708 break;
1709
1710 /* interface may be new */
Simon Kelleye25db1f2013-01-29 22:10:26 +00001711 if (!iface && !option_bool(OPT_CLEVERBIND))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001712 enumerate_interfaces(0);
Simon Kelley552af8b2012-02-29 20:10:31 +00001713
1714 for (iface = daemon->interfaces; iface; iface = iface->next)
1715 if (iface->addr.sa.sa_family == AF_INET &&
1716 iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
1717 break;
1718
1719 /* If we failed, abandon localisation */
1720 if (iface)
1721 netmask = iface->netmask;
1722 else
1723 dst_addr_4.s_addr = 0;
1724 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001725 }
Simon Kelley25cf5e32015-01-09 15:53:03 +00001726
1727 /* log_query gets called indirectly all over the place, so
1728 pass these in global variables - sorry. */
1729 daemon->log_display_id = ++daemon->log_id;
1730 daemon->log_source_addr = &source_addr;
Simon Kelley6b173352018-05-08 18:32:14 +01001731
1732#ifdef HAVE_DUMPFILE
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001733 dump_packet_udp(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL, listen->fd);
1734#endif
1735
1736#ifdef HAVE_CONNTRACK
1737 if (option_bool(OPT_CMARK_ALST_EN))
1738 have_mark = get_incoming_mark(&source_addr, &dst_addr, /* istcp: */ 0, &mark);
Simon Kelley6b173352018-05-08 18:32:14 +01001739#endif
1740
Simon Kelleycdeda282006-03-16 20:16:06 +00001741 if (extract_request(header, (size_t)n, daemon->namebuff, &type))
Simon Kelley44a2a312004-03-10 20:04:35 +00001742 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01001743#ifdef HAVE_AUTH
1744 struct auth_zone *zone;
1745#endif
Petr Menšík6c0bf792021-03-18 00:07:45 +01001746 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001747 &source_addr, auth_dns ? "auth" : "query", type);
1748
1749#ifdef HAVE_CONNTRACK
1750 is_single_query = 1;
1751#endif
Simon Kelley44a2a312004-03-10 20:04:35 +00001752
Simon Kelley4820dce2012-12-18 18:30:30 +00001753#ifdef HAVE_AUTH
Simon Kelleyb485ed92013-10-18 22:00:39 +01001754 /* find queries for zones we're authoritative for, and answer them directly */
Simon Kelley3a3965a2015-08-09 17:45:06 +01001755 if (!auth_dns && !option_bool(OPT_LOCALISE))
Simon Kelley6008bdb2013-10-21 21:47:03 +01001756 for (zone = daemon->auth_zones; zone; zone = zone->next)
1757 if (in_zone(zone, daemon->namebuff, NULL))
1758 {
1759 auth_dns = 1;
1760 local_auth = 1;
1761 break;
1762 }
Simon Kelleyb485ed92013-10-18 22:00:39 +01001763#endif
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01001764
1765#ifdef HAVE_LOOP
1766 /* Check for forwarding loop */
1767 if (detect_loop(daemon->namebuff, type))
1768 return;
1769#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001770 }
1771
Simon Kelley5bb88f02015-12-21 16:23:47 +00001772 if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001773 {
1774 unsigned short flags;
1775
1776 have_pseudoheader = 1;
1777 GETSHORT(udp_size, pheader);
1778 pheader += 2; /* ext_rcode */
1779 GETSHORT(flags, pheader);
1780
1781 if (flags & 0x8000)
1782 do_bit = 1;/* do bit */
1783
1784 /* If the client provides an EDNS0 UDP size, use that to limit our reply.
1785 (bounded by the maximum configured). If no EDNS0, then it
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001786 defaults to 512. We write this value into the query packet too, so that
1787 if it's forwarded, we don't specify a maximum size greater than we can handle. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001788 if (udp_size > daemon->edns_pktsz)
1789 udp_size = daemon->edns_pktsz;
Simon Kelleya3303e12017-09-07 20:45:00 +01001790 else if (udp_size < PACKETSZ)
1791 udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001792
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001793 pheader -= 6; /* ext_class */
1794 PUTSHORT(udp_size, pheader); /* Bounding forwarded queries to maximum configured */
1795 }
1796
1797#ifdef HAVE_CONNTRACK
Simon Kelleyb485ed92013-10-18 22:00:39 +01001798#ifdef HAVE_AUTH
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001799 if (!auth_dns || local_auth)
1800#endif
1801 if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
1802 allowed = is_query_allowed_for_mark((u32)mark, is_single_query ? daemon->namebuff : NULL);
1803#endif
1804
1805 if (0);
1806#ifdef HAVE_CONNTRACK
1807 else if (!allowed)
1808 {
1809 u16 swap = htons(EDE_BLOCKED);
1810
1811 m = answer_disallowed(header, (size_t)n, (u32)mark, is_single_query ? daemon->namebuff : NULL);
1812
1813 if (have_pseudoheader && m != 0)
1814 m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
1815 EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
1816
1817 if (m >= 1)
1818 {
1819#ifdef HAVE_DUMPFILE
1820 dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd);
1821#endif
1822 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1823 (char *)header, m, &source_addr, &dst_addr, if_index);
1824 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
1825 }
1826 }
1827#endif
1828#ifdef HAVE_AUTH
1829 else if (auth_dns)
Simon Kelley824af852008-02-12 20:43:05 +00001830 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001831 m = answer_auth(header, ((char *) header) + udp_size, (size_t)n, now, &source_addr,
1832 local_auth, do_bit, have_pseudoheader);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001833 if (m >= 1)
Simon Kelleyb485ed92013-10-18 22:00:39 +01001834 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001835#ifdef HAVE_DUMPFILE
1836 dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd);
1837#endif
1838#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
1839 if (local_auth)
1840 if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
1841 report_addresses(header, m, mark);
1842#endif
Simon Kelleyb485ed92013-10-18 22:00:39 +01001843 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1844 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001845 daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
Simon Kelleyb485ed92013-10-18 22:00:39 +01001846 }
Simon Kelley824af852008-02-12 20:43:05 +00001847 }
Simon Kelley4820dce2012-12-18 18:30:30 +00001848#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001849 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00001850 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001851 int stale, filtered;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001852 int ad_reqd = do_bit;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001853 int fd = listen->fd;
1854 struct blockdata *saved_question = blockdata_alloc((char *) header, (size_t)n);
1855
1856 /* RFC 6840 5.7 */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001857 if (header->hb4 & HB4_AD)
1858 ad_reqd = 1;
1859
1860 m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001861 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale, &filtered);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001862
1863 if (m >= 1)
1864 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001865 if (have_pseudoheader)
1866 {
1867 int ede = EDE_UNSET;
1868
1869 if (filtered)
1870 ede = EDE_FILTERED;
1871 else if (stale)
1872 ede = EDE_STALE;
1873
1874 if (ede != EDE_UNSET)
1875 {
1876 u16 swap = htons(ede);
1877
1878 m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
1879 EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
1880 }
1881 }
1882
1883#ifdef HAVE_DUMPFILE
1884 dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd);
1885#endif
1886#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
1887 if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
1888 report_addresses(header, m, mark);
1889#endif
Simon Kelley4f7b3042012-11-28 21:27:02 +00001890 send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
1891 (char *)header, m, &source_addr, &dst_addr, if_index);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001892 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001893 if (stale)
1894 daemon->metrics[METRIC_DNS_STALE_ANSWERED]++;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001895 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001896
1897 if (stale)
1898 {
1899 /* We answered with stale cache data, so forward the query anyway to
1900 refresh that. */
1901 m = 0;
1902
1903 /* We've already answered the client, so don't send it the answer
1904 when it comes back. */
1905 fd = -1;
1906 }
1907
1908 if (saved_question)
1909 {
1910 if (m == 0)
1911 {
1912 blockdata_retrieve(saved_question, (size_t)n, header);
1913
1914 if (forward_query(fd, &source_addr, &dst_addr, if_index,
1915 header, (size_t)n, ((char *) header) + udp_size, now, NULL, ad_reqd, do_bit, 0))
1916 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
1917 else
1918 daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
1919 }
1920
1921 blockdata_free(saved_question);
1922 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001923 }
Simon Kelley44a2a312004-03-10 20:04:35 +00001924}
1925
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001926/* Send query in packet, qsize to a server determined by first,last,start and
1927 get the reply. return reply size. */
1928static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, size_t qsize,
1929 int have_mark, unsigned int mark, struct server **servp)
1930{
1931 int firstsendto = -1;
1932 u16 *length = (u16 *)packet;
1933 unsigned char *payload = &packet[2];
1934 struct dns_header *header = (struct dns_header *)payload;
1935 unsigned char c1, c2;
1936 unsigned char hash[HASH_SIZE], *hashp;
1937 unsigned int rsize;
1938
1939 (void)mark;
1940 (void)have_mark;
1941
1942 if (!(hashp = hash_questions(header, (unsigned int)qsize, daemon->namebuff)))
1943 return 0;
1944
1945 memcpy(hash, hashp, HASH_SIZE);
1946
1947 while (1)
1948 {
1949 int data_sent = 0, timedout = 0;
1950 struct server *serv;
1951
1952 if (firstsendto == -1)
1953 firstsendto = start;
1954 else
1955 {
1956 start++;
1957
1958 if (start == last)
1959 start = first;
1960
1961 if (start == firstsendto)
1962 break;
1963 }
1964
1965 serv = daemon->serverarray[start];
1966
1967 retry:
1968 *length = htons(qsize);
1969
1970 if (serv->tcpfd == -1)
1971 {
1972 if ((serv->tcpfd = socket(serv->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
1973 continue;
1974
1975#ifdef HAVE_CONNTRACK
1976 /* Copy connection mark of incoming query to outgoing connection. */
1977 if (have_mark)
1978 setsockopt(serv->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
1979#endif
1980
1981 if ((!local_bind(serv->tcpfd, &serv->source_addr, serv->interface, 0, 1)))
1982 {
1983 close(serv->tcpfd);
1984 serv->tcpfd = -1;
1985 continue;
1986 }
1987
1988#ifdef TCP_SYNCNT
1989 /* TCP connections by default take ages to time out.
1990 At least on Linux, we can reduce that to only two attempts
1991 to get a reply. For DNS, that's more sensible. */
1992 mark = 2;
1993 setsockopt(serv->tcpfd, IPPROTO_TCP, TCP_SYNCNT, &mark, sizeof(unsigned int));
1994#endif
1995
1996#ifdef MSG_FASTOPEN
1997 server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN);
1998
1999 if (errno == 0)
2000 data_sent = 1;
2001 else if (errno == ETIMEDOUT || errno == EHOSTUNREACH)
2002 timedout = 1;
2003#endif
2004
2005 /* If fastopen failed due to lack of reply, then there's no point in
2006 trying again in non-FASTOPEN mode. */
2007 if (timedout || (!data_sent && connect(serv->tcpfd, &serv->addr.sa, sa_len(&serv->addr)) == -1))
2008 {
2009 close(serv->tcpfd);
2010 serv->tcpfd = -1;
2011 continue;
2012 }
2013
2014 daemon->serverarray[first]->last_server = start;
2015 serv->flags &= ~SERV_GOT_TCP;
2016 }
2017
2018 if ((!data_sent && !read_write(serv->tcpfd, packet, qsize + sizeof(u16), 0)) ||
2019 !read_write(serv->tcpfd, &c1, 1, 1) ||
2020 !read_write(serv->tcpfd, &c2, 1, 1) ||
2021 !read_write(serv->tcpfd, payload, (rsize = (c1 << 8) | c2), 1))
2022 {
2023 close(serv->tcpfd);
2024 serv->tcpfd = -1;
2025 /* We get data then EOF, reopen connection to same server,
2026 else try next. This avoids DoS from a server which accepts
2027 connections and then closes them. */
2028 if (serv->flags & SERV_GOT_TCP)
2029 goto retry;
2030 else
2031 continue;
2032 }
2033
2034 /* If the hash of the question section doesn't match the crc we sent, then
2035 someone might be attempting to insert bogus values into the cache by
2036 sending replies containing questions and bogus answers.
2037 Try another server, or give up */
2038 if (!(hashp = hash_questions(header, rsize, daemon->namebuff)) || memcmp(hash, hashp, HASH_SIZE) != 0)
2039 continue;
2040
2041 serv->flags |= SERV_GOT_TCP;
2042
2043 *servp = serv;
2044 return rsize;
2045 }
2046
2047 return 0;
2048}
2049
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002050#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002051/* Recurse down the key hierarchy */
Simon Kelley7fa836e2014-02-10 20:11:24 +00002052static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002053 int class, char *name, char *keyname, struct server *server,
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002054 int have_mark, unsigned int mark, int *keycount, int *validatecount)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002055{
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002056 int first, last, start, new_status;
Simon Kelley9a31b682015-12-15 10:20:39 +00002057 unsigned char *packet = NULL;
Simon Kelley9a31b682015-12-15 10:20:39 +00002058 struct dns_header *new_header = NULL;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002059
Simon Kelley9a31b682015-12-15 10:20:39 +00002060 while (1)
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002061 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002062 size_t m;
2063 int log_save;
2064
Simon Kelley9a31b682015-12-15 10:20:39 +00002065 /* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002066 if (STAT_ISEQUAL(status, STAT_NEED_KEY))
2067 new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class, validatecount);
2068 else if (STAT_ISEQUAL(status, STAT_NEED_DS))
2069 new_status = dnssec_validate_ds(now, header, n, name, keyname, class, validatecount);
Simon Kelley9a31b682015-12-15 10:20:39 +00002070 else
James Bottomleye33b4872017-03-17 21:44:10 +00002071 new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
Simon Kelleya6918532018-04-15 16:20:52 +01002072 !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002073 NULL, NULL, NULL, validatecount);
Simon Kelley00a5b5d2014-02-28 18:10:55 +00002074
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002075 if (!STAT_ISEQUAL(new_status, STAT_NEED_DS) && !STAT_ISEQUAL(new_status, STAT_NEED_KEY) && !STAT_ISEQUAL(new_status, STAT_ABANDONED))
Simon Kelley9a31b682015-12-15 10:20:39 +00002076 break;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002077
2078 if ((*keycount)-- == 0)
2079 {
2080 my_syslog(LOG_WARNING, _("limit exceeded: per-query subqueries"));
2081 new_status = STAT_ABANDONED;
2082 }
2083
2084 if (STAT_ISEQUAL(new_status, STAT_ABANDONED))
2085 {
2086 /* Log the actual validation that made us barf. */
2087 unsigned char *p = (unsigned char *)(header+1);
2088 if (extract_name(header, n, &p, daemon->namebuff, 0, 4) == 1)
2089 my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
2090 daemon->namebuff[0] ? daemon->namebuff : ".");
2091 break;
2092 }
2093
Simon Kelley9a31b682015-12-15 10:20:39 +00002094 /* Can't validate because we need a key/DS whose name now in keyname.
2095 Make query for same, and recurse to validate */
Simon Kelley7fa836e2014-02-10 20:11:24 +00002096 if (!packet)
Simon Kelley9a31b682015-12-15 10:20:39 +00002097 {
2098 packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002099 new_header = (struct dns_header *)&packet[2];
Simon Kelley9a31b682015-12-15 10:20:39 +00002100 }
2101
2102 if (!packet)
2103 {
2104 new_status = STAT_ABANDONED;
2105 break;
2106 }
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002107
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002108 m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
2109 STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz);
2110
2111 if ((start = dnssec_server(server, daemon->keyname, &first, &last)) == -1 ||
2112 (m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0)
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002113 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002114 new_status = STAT_ABANDONED;
2115 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002116 }
Simon Kelleye1791f32018-10-06 23:23:23 +01002117
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002118 log_save = daemon->log_display_id;
2119 daemon->log_display_id = ++daemon->log_id;
Simon Kelley9a31b682015-12-15 10:20:39 +00002120
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002121 log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, keyname, &server->addr,
2122 STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
2123
2124 new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server,
2125 have_mark, mark, keycount, validatecount);
2126
2127 daemon->log_display_id = log_save;
2128
2129 if (!STAT_ISEQUAL(new_status, STAT_OK))
Simon Kelley9a31b682015-12-15 10:20:39 +00002130 break;
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002131 }
Simon Kelley361dfe52017-02-10 21:12:30 +00002132
Simon Kelley9a31b682015-12-15 10:20:39 +00002133 if (packet)
2134 free(packet);
2135
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002136 return new_status;
2137}
2138#endif
2139
2140
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002141/* The daemon forks before calling this: it should deal with one connection,
Josh Soref730c6742017-02-06 16:14:04 +00002142 blocking as necessary, and then return. Note, need to be a bit careful
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002143 about resources for debug mode, when the fork is suppressed: that's
2144 done by the caller. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01002145unsigned char *tcp_request(int confd, time_t now,
Simon Kelley4f7b3042012-11-28 21:27:02 +00002146 union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002147{
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002148 size_t size = 0, saved_size = 0;
2149 int norebind;
2150#ifdef HAVE_CONNTRACK
2151 int is_single_query = 0, allowed = 1;
2152#endif
Vladislav Grishenko3b195962013-11-26 11:08:21 +00002153#ifdef HAVE_AUTH
Simon Kelley19b16892013-10-20 10:19:39 +01002154 int local_auth = 0;
Vladislav Grishenko3b195962013-11-26 11:08:21 +00002155#endif
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002156 int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002157 int cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
Simon Kelleycdeda282006-03-16 20:16:06 +00002158 size_t m;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002159 struct blockdata *saved_question = NULL;
Simon Kelleyee86ce62012-12-07 11:54:46 +00002160 unsigned short qtype;
2161 unsigned int gotname;
Simon Kelley4b5ea122013-04-22 10:18:26 +01002162 /* Max TCP packet + slop + size */
2163 unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
2164 unsigned char *payload = &packet[2];
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002165 unsigned char c1, c2;
Simon Kelley4b5ea122013-04-22 10:18:26 +01002166 /* largest field in header is 16-bits, so this is still sufficiently aligned */
2167 struct dns_header *header = (struct dns_header *)payload;
2168 u16 *length = (u16 *)packet;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002169 struct server *serv;
Simon Kelley7de060b2011-08-26 17:24:52 +01002170 struct in_addr dst_addr_4;
2171 union mysockaddr peer_addr;
2172 socklen_t peer_len = sizeof(union mysockaddr);
Simon Kelley25cf5e32015-01-09 15:53:03 +00002173 int query_count = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002174 unsigned char *pheader;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002175 unsigned int mark = 0;
2176 int have_mark = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002177 int first, last, filtered, stale, do_stale = 0;
2178 unsigned int flags = 0;
2179
2180 if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
Simon Kelley7de060b2011-08-26 17:24:52 +01002181 return packet;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002182
2183#ifdef HAVE_CONNTRACK
2184 /* Get connection mark of incoming query to set on outgoing connections. */
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002185 if (option_bool(OPT_CONNTRACK) || option_bool(OPT_CMARK_ALST_EN))
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002186 {
Simon Kelleycc921df2019-01-02 22:48:59 +00002187 union all_addr local;
Simon Kelleyee875042018-10-23 22:10:17 +01002188
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002189 if (local_addr->sa.sa_family == AF_INET6)
Simon Kelleycc921df2019-01-02 22:48:59 +00002190 local.addr6 = local_addr->in6.sin6_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002191 else
Simon Kelleycc921df2019-01-02 22:48:59 +00002192 local.addr4 = local_addr->in.sin_addr;
Simon Kelleyf344dbc2016-01-18 18:04:17 +00002193
2194 have_mark = get_incoming_mark(&peer_addr, &local, 1, &mark);
2195 }
2196#endif
2197
Simon Kelleyc8a80482014-03-05 14:29:54 +00002198 /* We can be configured to only accept queries from at-most-one-hop-away addresses. */
2199 if (option_bool(OPT_LOCAL_SERVICE))
2200 {
2201 struct addrlist *addr;
Simon Kelleyee875042018-10-23 22:10:17 +01002202
Simon Kelleyc8a80482014-03-05 14:29:54 +00002203 if (peer_addr.sa.sa_family == AF_INET6)
2204 {
2205 for (addr = daemon->interface_addrs; addr; addr = addr->next)
2206 if ((addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00002207 is_same_net6(&addr->addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
Simon Kelleyc8a80482014-03-05 14:29:54 +00002208 break;
2209 }
2210 else
Simon Kelleyc8a80482014-03-05 14:29:54 +00002211 {
2212 struct in_addr netmask;
2213 for (addr = daemon->interface_addrs; addr; addr = addr->next)
2214 {
Richard Genoud15b1b7e2014-09-17 21:12:00 +01002215 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
Simon Kelleyc8a80482014-03-05 14:29:54 +00002216 if (!(addr->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00002217 is_same_net(addr->addr.addr4, peer_addr.in.sin_addr, netmask))
Simon Kelleyc8a80482014-03-05 14:29:54 +00002218 break;
2219 }
2220 }
2221 if (!addr)
2222 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002223 prettyprint_addr(&peer_addr, daemon->addrbuff);
2224 my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
Simon Kelleyc8a80482014-03-05 14:29:54 +00002225 return packet;
2226 }
2227 }
Simon Kelley7de060b2011-08-26 17:24:52 +01002228
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002229 while (1)
2230 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002231 int ede = EDE_UNSET;
2232
2233 if (!do_stale)
2234 {
2235 if (query_count == TCP_MAX_QUERIES)
2236 break;
2237
2238 if (!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
2239 !(size = c1 << 8 | c2) ||
2240 !read_write(confd, payload, size, 1))
2241 break;
2242 }
2243
Simon Kelley572b41e2011-02-18 18:11:18 +00002244 if (size < (int)sizeof(struct dns_header))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002245 continue;
Simon Kelley63437ff2017-09-06 22:34:21 +01002246
2247 /* Clear buffer beyond request to avoid risk of
2248 information disclosure. */
2249 memset(payload + size, 0, 65536 - size);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002250
Simon Kelley25cf5e32015-01-09 15:53:03 +00002251 query_count++;
2252
2253 /* log_query gets called indirectly all over the place, so
2254 pass these in global variables - sorry. */
2255 daemon->log_display_id = ++daemon->log_id;
2256 daemon->log_source_addr = &peer_addr;
2257
Simon Kelley28866e92011-02-14 20:19:14 +00002258 /* save state of "cd" flag in query */
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002259 if ((checking_disabled = header->hb4 & HB4_CD))
2260 no_cache_dnssec = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00002261
Simon Kelley3be34542004-09-11 19:12:13 +01002262 if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002263 {
Simon Kelleyb485ed92013-10-18 22:00:39 +01002264#ifdef HAVE_AUTH
2265 struct auth_zone *zone;
2266#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002267
2268#ifdef HAVE_CONNTRACK
2269 is_single_query = 1;
Simon Kelleyb485ed92013-10-18 22:00:39 +01002270#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002271
2272 if (!do_stale)
2273 {
2274 log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
2275 &peer_addr, auth_dns ? "auth" : "query", qtype);
2276
2277#ifdef HAVE_AUTH
2278 /* find queries for zones we're authoritative for, and answer them directly */
2279 if (!auth_dns && !option_bool(OPT_LOCALISE))
2280 for (zone = daemon->auth_zones; zone; zone = zone->next)
2281 if (in_zone(zone, daemon->namebuff, NULL))
2282 {
2283 auth_dns = 1;
2284 local_auth = 1;
2285 break;
2286 }
2287#endif
2288 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002289 }
2290
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002291 norebind = domain_no_rebind(daemon->namebuff);
2292
Simon Kelley7de060b2011-08-26 17:24:52 +01002293 if (local_addr->sa.sa_family == AF_INET)
2294 dst_addr_4 = local_addr->in.sin_addr;
2295 else
2296 dst_addr_4.s_addr = 0;
2297
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002298 do_bit = 0;
2299
Simon Kelley5bb88f02015-12-21 16:23:47 +00002300 if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002301 {
2302 unsigned short flags;
2303
2304 have_pseudoheader = 1;
2305 pheader += 4; /* udp_size, ext_rcode */
2306 GETSHORT(flags, pheader);
2307
2308 if (flags & 0x8000)
Simon Kelley5bb88f02015-12-21 16:23:47 +00002309 do_bit = 1; /* do bit */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002310 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002311
2312#ifdef HAVE_CONNTRACK
Simon Kelley4820dce2012-12-18 18:30:30 +00002313#ifdef HAVE_AUTH
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002314 if (!auth_dns || local_auth)
2315#endif
2316 if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
2317 allowed = is_query_allowed_for_mark((u32)mark, is_single_query ? daemon->namebuff : NULL);
2318#endif
2319
2320 if (0);
2321#ifdef HAVE_CONNTRACK
2322 else if (!allowed)
2323 {
2324 u16 swap = htons(EDE_BLOCKED);
2325
2326 m = answer_disallowed(header, size, (u32)mark, is_single_query ? daemon->namebuff : NULL);
2327
2328 if (have_pseudoheader && m != 0)
2329 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz,
2330 EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
2331 }
2332#endif
2333#ifdef HAVE_AUTH
2334 else if (auth_dns)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002335 m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr,
2336 local_auth, do_bit, have_pseudoheader);
Simon Kelley4820dce2012-12-18 18:30:30 +00002337#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002338 else
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002339 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002340 int ad_reqd = do_bit;
2341 /* RFC 6840 5.7 */
2342 if (header->hb4 & HB4_AD)
2343 ad_reqd = 1;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002344
2345 if (do_stale)
2346 m = 0;
2347 else
2348 {
2349 if (saved_question)
2350 blockdata_free(saved_question);
2351
2352 saved_question = blockdata_alloc((char *) header, (size_t)size);
2353 saved_size = size;
2354
2355 /* m > 0 if answered from cache */
2356 m = answer_request(header, ((char *) header) + 65536, (size_t)size,
2357 dst_addr_4, netmask, now, ad_reqd, do_bit, have_pseudoheader, &stale, &filtered);
2358 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002359 /* Do this by steam now we're not in the select() loop */
Simon Kelleyb842bc92015-07-12 21:09:11 +01002360 check_log_writer(1);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002361
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002362 if (m == 0 && saved_question)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002363 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002364 struct server *master;
2365 int start;
Simon Kelleyed4c0762013-10-08 20:46:34 +01002366
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002367 blockdata_retrieve(saved_question, (size_t)saved_size, header);
2368 size = saved_size;
Simon Kelley367341f2016-01-12 15:58:23 +00002369
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002370 if (lookup_domain(daemon->namebuff, gotname, &first, &last))
2371 flags = is_local_answer(now, first, daemon->namebuff);
Simon Kelley4f7b3042012-11-28 21:27:02 +00002372 else
Simon Kelley4f7b3042012-11-28 21:27:02 +00002373 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002374 /* No configured servers */
2375 ede = EDE_NOT_READY;
2376 flags = 0;
2377 }
2378
2379 /* don't forward A or AAAA queries for simple names, except the empty name */
2380 if (!flags &&
2381 option_bool(OPT_NODOTS_LOCAL) &&
2382 (gotname & (F_IPV4 | F_IPV6)) &&
2383 !strchr(daemon->namebuff, '.') &&
2384 strlen(daemon->namebuff) != 0)
2385 flags = check_for_local_domain(daemon->namebuff, now) ? F_NOERR : F_NXDOMAIN;
2386
2387 if (!flags && ede != EDE_NOT_READY)
2388 {
2389 master = daemon->serverarray[first];
2390
2391 if (option_bool(OPT_ORDER) || master->last_server == -1)
2392 start = first;
2393 else
2394 start = master->last_server;
2395
2396 size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
2397
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002398#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002399 if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
2400 {
2401 size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
2402
2403 /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
2404 this allows it to select auth servers when one is returning bad data. */
2405 if (option_bool(OPT_DNSSEC_DEBUG))
Simon Kelley7d7b7b32014-01-08 15:53:35 +00002406 header->hb4 |= HB4_CD;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002407 }
2408#endif
2409
2410 /* Check if we added a pheader on forwarding - may need to
2411 strip it from the reply. */
2412 if (!have_pseudoheader && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
2413 added_pheader = 1;
2414
2415 /* Loop round available servers until we succeed in connecting to one. */
2416 if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0)
2417 {
2418 ede = EDE_NETERR;
Simon Kelley4f7b3042012-11-28 21:27:02 +00002419 break;
2420 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002421
2422 /* get query name again for logging - may have been overwritten */
2423 if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
2424 strcpy(daemon->namebuff, "query");
2425 log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
2426
2427#ifdef HAVE_DNSSEC
2428 if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (master->flags & SERV_DO_DNSSEC))
2429 {
2430 int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
2431 int validatecount = daemon->limit[LIMIT_CRYPTO];
2432 int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
2433 serv, have_mark, mark, &keycount, &validatecount);
2434 char *result, *domain = "result";
2435
2436 union all_addr a;
2437 a.log.ede = ede = errflags_to_ede(status);
2438
2439 if (STAT_ISEQUAL(status, STAT_ABANDONED))
2440 {
2441 result = "ABANDONED";
2442 status = STAT_BOGUS;
2443 }
2444 else
2445 result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
2446
2447 if (STAT_ISEQUAL(status, STAT_SECURE))
2448 cache_secure = 1;
2449 else if (STAT_ISEQUAL(status, STAT_BOGUS))
2450 {
2451 no_cache_dnssec = 1;
2452 bogusanswer = 1;
2453
2454 if (extract_request(header, m, daemon->namebuff, NULL))
2455 domain = daemon->namebuff;
2456 }
2457
2458 log_query(F_SECSTAT, domain, &a, result, 0);
2459
2460 if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
2461 daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - validatecount;
2462
2463 if ((daemon->limit[LIMIT_WORK] - keycount) > (int)daemon->metrics[METRIC_WORK_HWM])
2464 daemon->metrics[METRIC_WORK_HWM] = daemon->limit[LIMIT_WORK] - keycount;
2465 }
2466#endif
2467
2468 /* restore CD bit to the value in the query */
2469 if (checking_disabled)
2470 header->hb4 |= HB4_CD;
2471 else
2472 header->hb4 &= ~HB4_CD;
2473
2474 /* Never cache answers which are contingent on the source or MAC address EDSN0 option,
2475 since the cache is ignorant of such things. */
2476 if (!cacheable)
2477 no_cache_dnssec = 1;
2478
2479 m = process_reply(header, now, serv, (unsigned int)m,
2480 option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
2481 ad_reqd, do_bit, added_pheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002482 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002483 }
2484 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002485
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002486 if (do_stale)
2487 break;
2488
2489 /* In case of local answer or no connections made. */
2490 if (m == 0)
2491 {
2492 if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff,
2493 ((char *) header) + 65536, first, last, ede)))
2494 break;
2495
2496 if (have_pseudoheader)
2497 {
2498 u16 swap = htons((u16)ede);
2499
2500 if (ede != EDE_UNSET)
2501 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
2502 else
2503 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
2504 }
2505 }
2506 else if (have_pseudoheader)
2507 {
2508 ede = EDE_UNSET;
2509
2510 if (filtered)
2511 ede = EDE_FILTERED;
2512 else if (stale)
2513 ede = EDE_STALE;
2514
2515 if (ede != EDE_UNSET)
2516 {
2517 u16 swap = htons((u16)ede);
2518
2519 m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002520 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002521 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00002522
Simon Kelleyb842bc92015-07-12 21:09:11 +01002523 check_log_writer(1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002524
Simon Kelley4b5ea122013-04-22 10:18:26 +01002525 *length = htons(m);
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002526
2527#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
2528#ifdef HAVE_AUTH
2529 if (!auth_dns || local_auth)
Simon Kelley3a237152013-12-12 12:15:50 +00002530#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002531 if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
2532 report_addresses(header, m, mark);
2533#endif
2534 if (!read_write(confd, packet, m + sizeof(u16), 0))
2535 break;
2536
2537 /* If we answered with stale data, this process will now try and get fresh data into
2538 the cache and cannot therefore accept new queries. Close the incoming
2539 connection to signal that to the client. Then set do_stale and loop round
2540 once more to try and get fresh data, after which we exit. */
2541 if (stale)
2542 {
2543 shutdown(confd, SHUT_RDWR);
2544 close(confd);
2545 do_stale = 1;
2546 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002547 }
Simon Kelley16972692006-10-16 20:04:18 +01002548
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002549 /* If we ran once to get fresh data, confd is already closed. */
2550 if (!do_stale)
2551 {
2552 shutdown(confd, SHUT_RDWR);
2553 close(confd);
2554 }
2555
2556 if (saved_question)
2557 blockdata_free(saved_question);
2558
2559 return packet;
Simon Kelley16972692006-10-16 20:04:18 +01002560}
2561
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002562/* return a UDP socket bound to a random port, have to cope with straying into
2563 occupied port nos and reserved ones. */
2564static int random_sock(struct server *s)
2565{
2566 int fd;
2567
2568 if ((fd = socket(s->source_addr.sa.sa_family, SOCK_DGRAM, 0)) != -1)
2569 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002570 /* We need to set IPV6ONLY so we can use the same ports
2571 for IPv4 and IPV6, otherwise, in restriced port situations,
2572 we can end up with all our available ports in use for
2573 one address family, and the other address family cannot be used. */
2574 if (s->source_addr.sa.sa_family == AF_INET6)
2575 {
2576 int opt = 1;
2577
2578 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
2579 {
2580 close(fd);
2581 return -1;
2582 }
2583 }
2584
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002585 if (local_bind(fd, &s->source_addr, s->interface, s->ifindex, 0))
2586 return fd;
2587
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002588 /* don't log errors due to running out of available ports, we handle those. */
2589 if (!sockaddr_isnull(&s->source_addr) || errno != EADDRINUSE)
2590 {
2591 if (s->interface[0] == 0)
2592 (void)prettyprint_addr(&s->source_addr, daemon->addrbuff);
2593 else
2594 safe_strncpy(daemon->addrbuff, s->interface, ADDRSTRLEN);
2595
2596 my_syslog(LOG_ERR, _("failed to bind server socket to %s: %s"),
2597 daemon->addrbuff, strerror(errno));
2598 }
2599
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002600 close(fd);
2601 }
2602
2603 return -1;
2604}
2605
2606/* compare source addresses and interface, serv2 can be null. */
2607static int server_isequal(const struct server *serv1,
2608 const struct server *serv2)
2609{
2610 return (serv2 &&
2611 serv2->ifindex == serv1->ifindex &&
2612 sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
2613 strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
2614}
2615
2616/* fdlp points to chain of randomfds already in use by transaction.
2617 If there's already a suitable one, return it, else allocate a
2618 new one and add it to the list.
2619
2620 Not leaking any resources in the face of allocation failures
2621 is rather convoluted here.
2622
2623 Note that rfd->serv may be NULL, when a server goes away.
2624*/
2625int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002626{
2627 static int finger = 0;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002628 int i, j = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002629 int ports_full = 0;
2630 struct randfd_list **up, *rfl, *found, **found_link;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002631 struct randfd *rfd = NULL;
2632 int fd = 0;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002633 int ports_avail = 0;
2634
2635 /* We can't have more randomsocks for this AF available than ports in our port range,
2636 so check that here, to avoid trying and failing to bind every port
2637 in local_bind(), called from random_sock(). The actual check is below when
2638 ports_avail != 0 */
2639 if (daemon->max_port != 0)
2640 {
2641 ports_avail = daemon->max_port - daemon->min_port + 1;
2642 if (ports_avail >= SMALL_PORT_RANGE)
2643 ports_avail = 0;
2644 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002645
2646 /* If server has a pre-allocated fd, use that. */
2647 if (serv->sfd)
2648 return serv->sfd->fd;
2649
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002650 /* existing suitable random port socket linked to this transaction?
2651 Find the last one in the list and count how many there are. */
2652 for (found = NULL, found_link = NULL, i = 0, up = fdlp, rfl = *fdlp; rfl; up = &rfl->next, rfl = rfl->next)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002653 if (server_isequal(serv, rfl->rfd->serv))
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002654 {
2655 i++;
2656 found = rfl;
2657 found_link = up;
2658 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002659
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002660 /* We have the maximum number for this query already. Promote
2661 the last one on the list to the head, to circulate them,
2662 and return it. */
2663 if (found && i >= daemon->randport_limit)
2664 {
2665 *found_link = found->next;
2666 found->next = *fdlp;
2667 *fdlp = found;
2668 return found->rfd->fd;
2669 }
2670
2671 /* check for all available ports in use. */
2672 if (ports_avail != 0)
2673 {
2674 int ports_inuse;
2675
2676 for (ports_inuse = 0, i = 0; i < daemon->numrrand; i++)
2677 if (daemon->randomsocks[i].refcount != 0 &&
2678 daemon->randomsocks[i].serv->source_addr.sa.sa_family == serv->source_addr.sa.sa_family &&
2679 ++ports_inuse >= ports_avail)
2680 {
2681 ports_full = 1;
2682 break;
2683 }
2684 }
2685
2686 /* limit the number of sockets we have open to avoid starvation of
2687 (eg) TFTP. Once we have a reasonable number, randomness should be OK */
2688 if (!ports_full)
2689 for (i = 0; i < daemon->numrrand; i++)
2690 if (daemon->randomsocks[i].refcount == 0)
2691 {
2692 if ((fd = random_sock(serv)) != -1)
2693 {
2694 rfd = &daemon->randomsocks[i];
2695 rfd->serv = serv;
2696 rfd->fd = fd;
2697 rfd->refcount = 1;
2698 }
2699 break;
2700 }
2701
2702 /* No good existing. Need new link. */
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002703 if ((rfl = daemon->rfl_spare))
2704 daemon->rfl_spare = rfl->next;
2705 else if (!(rfl = whine_malloc(sizeof(struct randfd_list))))
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002706 {
2707 /* malloc failed, don't leak allocated sock */
2708 if (rfd)
2709 {
2710 close(rfd->fd);
2711 rfd->refcount = 0;
2712 }
2713
2714 return -1;
2715 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002716
2717 /* No free ones or cannot get new socket, grab an existing one */
2718 if (!rfd)
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002719 for (j = 0; j < daemon->numrrand; j++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002720 {
Simon Kelleyea28d0e2021-03-26 22:02:04 +00002721 i = (j + finger) % daemon->numrrand;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002722 if (daemon->randomsocks[i].refcount != 0 &&
2723 server_isequal(serv, daemon->randomsocks[i].serv) &&
2724 daemon->randomsocks[i].refcount != 0xfffe)
2725 {
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002726 struct randfd_list *rl;
2727 /* Don't pick one we already have. */
2728 for (rl = *fdlp; rl; rl = rl->next)
2729 if (rl->rfd == &daemon->randomsocks[i])
2730 break;
2731
2732 if (!rl)
2733 {
2734 finger = i + 1;
2735 rfd = &daemon->randomsocks[i];
2736 rfd->refcount++;
2737 break;
2738 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002739 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002740 }
2741
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002742 if (!rfd) /* should be when j == daemon->numrrand */
Simon Kelley1a6bca82008-07-11 11:11:42 +01002743 {
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002744 struct randfd_list *rfl_poll;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002745
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002746 /* there are no free slots, and non with the same parameters we can piggy-back on.
2747 We're going to have to allocate a new temporary record, distinguished by
2748 refcount == 0xffff. This will exist in the frec randfd list, never be shared,
2749 and be freed when no longer in use. It will also be held on
2750 the daemon->rfl_poll list so the poll system can find it. */
2751
2752 if ((rfl_poll = daemon->rfl_spare))
2753 daemon->rfl_spare = rfl_poll->next;
2754 else
2755 rfl_poll = whine_malloc(sizeof(struct randfd_list));
2756
2757 if (!rfl_poll ||
2758 !(rfd = whine_malloc(sizeof(struct randfd))) ||
2759 (fd = random_sock(serv)) == -1)
2760 {
2761
2762 /* Don't leak anything we may already have */
2763 rfl->next = daemon->rfl_spare;
2764 daemon->rfl_spare = rfl;
2765
2766 if (rfl_poll)
2767 {
2768 rfl_poll->next = daemon->rfl_spare;
2769 daemon->rfl_spare = rfl_poll;
2770 }
2771
2772 if (rfd)
2773 free(rfd);
2774
2775 return -1; /* doom */
2776 }
2777
2778 /* Note rfd->serv not set here, since it's not reused */
2779 rfd->fd = fd;
2780 rfd->refcount = 0xffff; /* marker for temp record */
2781
2782 rfl_poll->rfd = rfd;
2783 rfl_poll->next = daemon->rfl_poll;
2784 daemon->rfl_poll = rfl_poll;
2785 }
2786
2787 rfl->rfd = rfd;
2788 rfl->next = *fdlp;
2789 *fdlp = rfl;
2790
2791 return rfl->rfd->fd;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002792}
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002793
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002794void free_rfds(struct randfd_list **fdlp)
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002795{
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002796 struct randfd_list *tmp, *rfl, *poll, *next, **up;
2797
2798 for (rfl = *fdlp; rfl; rfl = tmp)
2799 {
2800 if (rfl->rfd->refcount == 0xffff || --(rfl->rfd->refcount) == 0)
2801 close(rfl->rfd->fd);
2802
2803 /* temporary overflow record */
2804 if (rfl->rfd->refcount == 0xffff)
2805 {
2806 free(rfl->rfd);
2807
2808 /* go through the link of all these by steam to delete.
2809 This list is expected to be almost always empty. */
2810 for (poll = daemon->rfl_poll, up = &daemon->rfl_poll; poll; poll = next)
2811 {
2812 next = poll->next;
2813
2814 if (poll->rfd == rfl->rfd)
2815 {
2816 *up = poll->next;
2817 poll->next = daemon->rfl_spare;
2818 daemon->rfl_spare = poll;
2819 }
2820 else
2821 up = &poll->next;
2822 }
2823 }
2824
2825 tmp = rfl->next;
2826 rfl->next = daemon->rfl_spare;
2827 daemon->rfl_spare = rfl;
2828 }
2829
2830 *fdlp = NULL;
Simon Kelleyb5ea1cc2014-07-29 16:34:14 +01002831}
2832
Simon Kelley1a6bca82008-07-11 11:11:42 +01002833static void free_frec(struct frec *f)
2834{
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002835 struct frec_src *last;
Simon Kelley15b60dd2020-11-18 18:34:55 +00002836
Simon Kelley6a6e06f2020-12-04 18:35:11 +00002837 /* add back to freelist if not the record builtin to every frec. */
2838 for (last = f->frec_src.next; last && last->next; last = last->next) ;
2839 if (last)
2840 {
2841 last->next = daemon->free_frec_src;
2842 daemon->free_frec_src = f->frec_src.next;
2843 }
2844
Simon Kelley15b60dd2020-11-18 18:34:55 +00002845 f->frec_src.next = NULL;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002846 free_rfds(&f->rfds);
Simon Kelley1a6bca82008-07-11 11:11:42 +01002847 f->sentto = NULL;
Simon Kelley28866e92011-02-14 20:19:14 +00002848 f->flags = 0;
Simon Kelley3a237152013-12-12 12:15:50 +00002849
Simon Kelley3a237152013-12-12 12:15:50 +00002850 if (f->stash)
Simon Kelley0fc2f312014-01-08 10:26:58 +00002851 {
2852 blockdata_free(f->stash);
2853 f->stash = NULL;
2854 }
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002855
2856#ifdef HAVE_DNSSEC
Simon Kelley3a237152013-12-12 12:15:50 +00002857 /* Anything we're waiting on is pointless now, too */
2858 if (f->blocking_query)
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002859 {
2860 struct frec *n, **up;
2861
2862 /* unlink outselves from the blocking query's dependents list. */
2863 for (n = f->blocking_query->dependent, up = &f->blocking_query->dependent; n; n = n->next_dependent)
2864 if (n == f)
2865 {
2866 *up = n->next_dependent;
2867 break;
2868 }
2869 else
2870 up = &n->next_dependent;
2871
2872 /* If we were the only/last dependent, free the blocking query too. */
2873 if (!f->blocking_query->dependent)
2874 free_frec(f->blocking_query);
2875 }
2876
Simon Kelley3a237152013-12-12 12:15:50 +00002877 f->blocking_query = NULL;
Simon Kelley39048ad2014-01-21 17:33:58 +00002878 f->dependent = NULL;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002879 f->next_dependent = NULL;
Simon Kelley3a237152013-12-12 12:15:50 +00002880#endif
Simon Kelley1a6bca82008-07-11 11:11:42 +01002881}
2882
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002883
2884
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002885/* Impose an absolute
Simon Kelley3a237152013-12-12 12:15:50 +00002886 limit of 4*TIMEOUT before we wipe things (for random sockets).
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002887 If force is set, always return a result, even if we have
2888 to allocate above the limit, and don'y free any records.
2889 This is set when allocating for DNSSEC to avoid cutting off
2890 the branch we are sitting on. */
2891static struct frec *get_new_frec(time_t now, struct server *master, int force)
Simon Kelley16972692006-10-16 20:04:18 +01002892{
Simon Kelley1a6bca82008-07-11 11:11:42 +01002893 struct frec *f, *oldest, *target;
Simon Kelley16972692006-10-16 20:04:18 +01002894 int count;
2895
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002896 /* look for free records, garbage collect old records and count number in use by our server-group. */
2897 for (f = daemon->frec_list, oldest = NULL, target = NULL, count = 0; f; f = f->next)
2898 {
2899 if (!f->sentto)
2900 target = f;
2901 else
2902 {
Simon Kelley9a31b682015-12-15 10:20:39 +00002903#ifdef HAVE_DNSSEC
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002904 /* Don't free DNSSEC sub-queries here, as we may end up with
2905 dangling references to them. They'll go when their "real" query
2906 is freed. */
2907 if (!f->dependent && !force)
Simon Kelley9a31b682015-12-15 10:20:39 +00002908#endif
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002909 {
2910 if (difftime(now, f->time) >= 4*TIMEOUT)
2911 {
2912 daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
2913 free_frec(f);
2914 target = f;
2915 }
2916 else if (!oldest || difftime(f->time, oldest->time) <= 0)
2917 oldest = f;
2918 }
2919 }
2920
2921 if (f->sentto && ((int)difftime(now, f->time)) < TIMEOUT && server_samegroup(f->sentto, master))
2922 count++;
2923 }
2924
2925 if (!force && count >= daemon->ftabsize)
2926 {
2927 query_full(now, master->domain);
2928 return NULL;
2929 }
2930
2931 if (!target && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
2932 {
2933 /* can't find empty one, use oldest if there is one and it's older than timeout */
2934 daemon->metrics[METRIC_DNS_UNANSWERED_QUERY]++;
2935 free_frec(oldest);
2936 target = oldest;
2937 }
2938
2939 if (!target && (target = (struct frec *)whine_malloc(sizeof(struct frec))))
2940 {
2941 target->next = daemon->frec_list;
2942 daemon->frec_list = target;
2943 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002944
2945 if (target)
2946 {
2947 target->time = now;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002948 target->forward_delay = daemon->fast_retry_time;
Simon Kelley1a6bca82008-07-11 11:11:42 +01002949 }
Simon Kelley16972692006-10-16 20:04:18 +01002950
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002951 return target;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002952}
Simon Kelley09f3b2c2017-05-09 01:34:02 +01002953
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002954static void query_full(time_t now, char *domain)
Simon Kelleyf61afcf2021-04-07 20:54:36 +01002955{
2956 static time_t last_log = 0;
2957
2958 if ((int)difftime(now, last_log) > 5)
2959 {
2960 last_log = now;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002961 if (!domain || strlen(domain) == 0)
2962 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
2963 else
2964 my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries to %s reached (max: %d)"), domain, daemon->ftabsize);
Simon Kelleyf61afcf2021-04-07 20:54:36 +01002965 }
2966}
2967
2968
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002969static struct frec *lookup_frec(unsigned short id, int fd, void *hash, int *firstp, int *lastp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002970{
2971 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002972 struct server *s;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002973 int first, last;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002974 struct randfd_list *fdl;
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002975
2976 if (hash)
2977 for (f = daemon->frec_list; f; f = f->next)
2978 if (f->sentto && f->new_id == id &&
2979 (memcmp(hash, f->hash, HASH_SIZE) == 0))
2980 {
2981 filter_servers(f->sentto->arrayposn, F_SERVER, firstp, lastp);
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002982
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07002983 /* sent from random port */
2984 for (fdl = f->rfds; fdl; fdl = fdl->next)
2985 if (fdl->rfd->fd == fd)
2986 return f;
2987
2988 /* Sent to upstream from socket associated with a server.
2989 Note we have to iterate over all the possible servers, since they may
2990 have different bound sockets. */
2991 for (first = *firstp, last = *lastp; first != last; first++)
2992 {
2993 s = daemon->serverarray[first];
2994 if (s->sfd && s->sfd->fd == fd)
2995 return f;
2996 }
2997 }
Simon Kelley74d4fcd2021-03-15 21:59:51 +00002998
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002999 return NULL;
3000}
3001
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07003002static struct frec *lookup_frec_by_query(void *hash, unsigned int flags, unsigned int flagmask)
Simon Kelley15b60dd2020-11-18 18:34:55 +00003003{
3004 struct frec *f;
3005
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07003006 if (hash)
3007 for (f = daemon->frec_list; f; f = f->next)
3008 if (f->sentto &&
3009 (f->flags & flagmask) == flags &&
3010 memcmp(hash, f->hash, HASH_SIZE) == 0)
3011 return f;
Simon Kelley15b60dd2020-11-18 18:34:55 +00003012
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003013 return NULL;
3014}
Simon Kelley15b60dd2020-11-18 18:34:55 +00003015
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07003016#ifdef HAVE_DNSSEC
3017/* DNSSEC frecs have the complete query in the block stash.
3018 Search for an existing query using that. */
3019static struct frec *lookup_frec_dnssec(char *target, int class, int flags, struct dns_header *header)
3020{
3021 struct frec *f;
3022
3023 for (f = daemon->frec_list; f; f = f->next)
3024 if (f->sentto &&
3025 (f->flags & flags) &&
3026 blockdata_retrieve(f->stash, f->stash_len, (void *)header))
3027 {
3028 unsigned char *p = (unsigned char *)(header+1);
3029 int hclass;
3030
3031 if (extract_name(header, f->stash_len, &p, target, 0, 4) != 1)
3032 continue;
3033
3034 p += 2; /* type, known from flags */
3035 GETSHORT(hclass, p);
3036
3037 if (class != hclass)
3038 continue;
3039
3040 return f;
3041 }
3042
3043 return NULL;
3044}
3045#endif
3046
Simon Kelley47a95162014-07-08 22:22:02 +01003047/* Send query packet again, if we can. */
3048void resend_query()
3049{
3050 if (daemon->srv_save)
Petr Menšík51f7bc92021-03-18 01:05:43 +01003051 server_send(daemon->srv_save, daemon->fd_save,
3052 daemon->packet, daemon->packet_len, 0);
Simon Kelley47a95162014-07-08 22:22:02 +01003053}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003054
Simon Kelley849a8352006-06-09 21:02:31 +01003055/* A server record is going away, remove references to it */
Simon Kelley5aabfc72007-08-29 11:24:47 +01003056void server_gone(struct server *server)
Simon Kelley849a8352006-06-09 21:02:31 +01003057{
3058 struct frec *f;
Simon Kelley74d4fcd2021-03-15 21:59:51 +00003059 int i;
Simon Kelley849a8352006-06-09 21:02:31 +01003060
Simon Kelley1a6bca82008-07-11 11:11:42 +01003061 for (f = daemon->frec_list; f; f = f->next)
Simon Kelley832af0b2007-01-21 20:01:28 +00003062 if (f->sentto && f->sentto == server)
Simon Kelley1a6bca82008-07-11 11:11:42 +01003063 free_frec(f);
Simon Kelley74d4fcd2021-03-15 21:59:51 +00003064
3065 /* If any random socket refers to this server, NULL the reference.
3066 No more references to the socket will be created in the future. */
Simon Kelleyea28d0e2021-03-26 22:02:04 +00003067 for (i = 0; i < daemon->numrrand; i++)
Simon Kelley74d4fcd2021-03-15 21:59:51 +00003068 if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
3069 daemon->randomsocks[i].serv = NULL;
Simon Kelley849a8352006-06-09 21:02:31 +01003070
Simon Kelley849a8352006-06-09 21:02:31 +01003071 if (daemon->srv_save == server)
3072 daemon->srv_save = NULL;
3073}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003074
Simon Kelley316e2732010-01-22 20:16:09 +00003075/* return unique random ids. */
Simon Kelley8a9be9e2014-01-25 23:17:21 +00003076static unsigned short get_id(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003077{
3078 unsigned short ret = 0;
Simon Kelley257ac0c2020-11-12 18:49:23 +00003079 struct frec *f;
Simon Kelley832af0b2007-01-21 20:01:28 +00003080
Simon Kelley257ac0c2020-11-12 18:49:23 +00003081 while (1)
3082 {
3083 ret = rand16();
3084
3085 /* ensure id is unique. */
3086 for (f = daemon->frec_list; f; f = f->next)
3087 if (f->sentto && f->new_id == ret)
3088 break;
3089
3090 if (!f)
3091 return ret;
3092 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00003093}