blob: cf2da770417de2699b7ebcfa874b9f9c31aaa296 [file] [log] [blame]
Tarun Kundu12e3b2e2024-08-15 16:16:53 -07001/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
2
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
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 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.
12
13 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/>.
15*/
16
17#include "dnsmasq.h"
18
19static int order(char *qdomain, size_t qlen, struct server *serv);
20static int order_qsort(const void *a, const void *b);
21static int order_servers(struct server *s, struct server *s2);
22
23/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain. */
24#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
25
26void build_server_array(void)
27{
28 struct server *serv;
29 int count = 0;
30
31 for (serv = daemon->servers; serv; serv = serv->next)
32#ifdef HAVE_LOOP
33 if (!(serv->flags & SERV_LOOP))
34#endif
35 {
36 count++;
37 if (serv->flags & SERV_WILDCARD)
38 daemon->server_has_wildcard = 1;
39 }
40
41 for (serv = daemon->local_domains; serv; serv = serv->next)
42 {
43 count++;
44 if (serv->flags & SERV_WILDCARD)
45 daemon->server_has_wildcard = 1;
46 }
47
48 daemon->serverarraysz = count;
49
50 if (count > daemon->serverarrayhwm)
51 {
52 struct server **new;
53
54 count += 10; /* A few extra without re-allocating. */
55
56 if ((new = whine_malloc(count * sizeof(struct server *))))
57 {
58 if (daemon->serverarray)
59 free(daemon->serverarray);
60
61 daemon->serverarray = new;
62 daemon->serverarrayhwm = count;
63 }
64 }
65
66 count = 0;
67
68 for (serv = daemon->servers; serv; serv = serv->next)
69#ifdef HAVE_LOOP
70 if (!(serv->flags & SERV_LOOP))
71#endif
72 {
73 daemon->serverarray[count] = serv;
74 serv->serial = count;
75 serv->last_server = -1;
76 count++;
77 }
78
79 for (serv = daemon->local_domains; serv; serv = serv->next, count++)
80 daemon->serverarray[count] = serv;
81
82 qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
83
84 /* servers need the location in the array to find all the whole
85 set of equivalent servers from a pointer to a single one. */
86 for (count = 0; count < daemon->serverarraysz; count++)
87 if (!(daemon->serverarray[count]->flags & SERV_IS_LOCAL))
88 daemon->serverarray[count]->arrayposn = count;
89}
90
91/* we're looking for the server whose domain is the longest exact match
92 to the RH end of qdomain, or a local address if the flags match.
93 Add '.' to the LHS of the query string so
94 server=/.example.com/ works.
95
96 A flag of F_SERVER returns an upstream server only.
97 A flag of F_DNSSECOK returns a DNSSEC capable server only and
98 also disables NODOTS servers from consideration.
99 A flag of F_DOMAINSRV returns a domain-specific server only.
100 A flag of F_CONFIG returns anything that generates a local
101 reply of IPv4 or IPV6.
102 return 0 if nothing found, 1 otherwise.
103*/
104int lookup_domain(char *domain, int flags, int *lowout, int *highout)
105{
106 int rc, crop_query, nodots;
107 ssize_t qlen;
108 int try, high, low = 0;
109 int nlow = 0, nhigh = 0;
110 char *cp, *qdomain = domain;
111
112 /* may be no configured servers. */
113 if (daemon->serverarraysz == 0)
114 return 0;
115
116 /* find query length and presence of '.' */
117 for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
118 if (*cp == '.')
119 nodots = 0;
120
121 /* Handle empty name, and searches for DNSSEC queries without
122 diverting to NODOTS servers. */
123 if (qlen == 0 || flags & F_DNSSECOK)
124 nodots = 0;
125
126 /* Search shorter and shorter RHS substrings for a match */
127 while (qlen >= 0)
128 {
129 /* Note that when we chop off a label, all the possible matches
130 MUST be at a larger index than the nearest failing match with one more
131 character, since the array is sorted longest to smallest. Hence
132 we don't reset low to zero here, we can go further below and crop the
133 search string to the size of the largest remaining server
134 when this match fails. */
135 high = daemon->serverarraysz;
136 crop_query = 1;
137
138 /* binary search */
139 while (1)
140 {
141 try = (low + high)/2;
142
143 if ((rc = order(qdomain, qlen, daemon->serverarray[try])) == 0)
144 break;
145
146 if (rc < 0)
147 {
148 if (high == try)
149 {
150 /* qdomain is longer or same length as longest domain, and try == 0
151 crop the query to the longest domain. */
152 crop_query = qlen - daemon->serverarray[try]->domain_len;
153 break;
154 }
155 high = try;
156 }
157 else
158 {
159 if (low == try)
160 {
161 /* try now points to the last domain that sorts before the query, so
162 we know that a substring of the query shorter than it is required to match, so
163 find the largest domain that's shorter than try. Note that just going to
164 try+1 is not optimal, consider searching bbb in (aaa,ccc,bb). try will point
165 to aaa, since ccc sorts after bbb, but the first domain that has a chance to
166 match is bb. So find the length of the first domain later than try which is
167 is shorter than it.
168 There's a nasty edge case when qdomain sorts before _any_ of the
169 server domains, where try _doesn't point_ to the last domain that sorts
170 before the query, since no such domain exists. In that case, the loop
171 exits via the rc < 0 && high == try path above and this code is
172 not executed. */
173 ssize_t len, old = daemon->serverarray[try]->domain_len;
174 while (++try != daemon->serverarraysz)
175 {
176 if (old != (len = daemon->serverarray[try]->domain_len))
177 {
178 crop_query = qlen - len;
179 break;
180 }
181 }
182 break;
183 }
184 low = try;
185 }
186 };
187
188 if (rc == 0)
189 {
190 int found = 1;
191
192 if (daemon->server_has_wildcard)
193 {
194 /* if we have example.com and *example.com we need to check against *example.com,
195 but the binary search may have found either. Use the fact that example.com is sorted before *example.com
196 We favour example.com in the case that both match (ie www.example.com) */
197 while (try != 0 && order(qdomain, qlen, daemon->serverarray[try-1]) == 0)
198 try--;
199
200 if (!(qdomain == domain || *qdomain == 0 || *(qdomain-1) == '.'))
201 {
202 while (try < daemon->serverarraysz-1 && order(qdomain, qlen, daemon->serverarray[try+1]) == 0)
203 try++;
204
205 if (!(daemon->serverarray[try]->flags & SERV_WILDCARD))
206 found = 0;
207 }
208 }
209
210 if (found && filter_servers(try, flags, &nlow, &nhigh))
211 /* We have a match, but it may only be (say) an IPv6 address, and
212 if the query wasn't for an AAAA record, it's no good, and we need
213 to continue generalising */
214 {
215 /* We've matched a setting which says to use servers without a domain.
216 Continue the search with empty query. We set the F_SERVER flag
217 so that --address=/#/... doesn't match. */
218 if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
219 {
220 crop_query = qlen;
221 flags |= F_SERVER;
222 }
223 else
224 break;
225 }
226 }
227
228 /* crop_query must be at least one always. */
229 if (crop_query == 0)
230 crop_query = 1;
231
232 /* strip chars off the query based on the largest possible remaining match,
233 then continue to the start of the next label unless we have a wildcard
234 domain somewhere, in which case we have to go one at a time. */
235 qlen -= crop_query;
236 qdomain += crop_query;
237 if (!daemon->server_has_wildcard)
238 while (qlen > 0 && (*(qdomain-1) != '.'))
239 qlen--, qdomain++;
240 }
241
242 /* domain has no dots, and we have at least one server configured to handle such,
243 These servers always sort to the very end of the array.
244 A configured server eg server=/lan/ will take precdence. */
245 if (nodots &&
246 (daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
247 (nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
248 filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
249
250 if (lowout)
251 *lowout = nlow;
252
253 if (highout)
254 *highout = nhigh;
255
256 /* qlen == -1 when we failed to match even an empty query, if there are no default servers. */
257 if (nlow == nhigh || qlen == -1)
258 return 0;
259
260 return 1;
261}
262
263/* Return first server in group of equivalent servers; this is the "master" record. */
264int server_samegroup(struct server *a, struct server *b)
265{
266 return order_servers(a, b) == 0;
267}
268
269int filter_servers(int seed, int flags, int *lowout, int *highout)
270{
271 int nlow = seed, nhigh = seed;
272 int i;
273
274 /* expand nlow and nhigh to cover all the records with the same domain
275 nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
276 which can happen below. */
277 while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
278 nlow--;
279
280 while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
281 nhigh++;
282
283 nhigh++;
284
285#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
286
287 if (flags & F_CONFIG)
288 {
289 /* We're just lookin for any matches that return an RR. */
290 for (i = nlow; i < nhigh; i++)
291 if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
292 break;
293
294 /* failed, return failure. */
295 if (i == nhigh)
296 nhigh = nlow;
297 }
298 else
299 {
300 /* Now the servers are on order between low and high, in the order
301 IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
302
303 See which of those match our query in that priority order and narrow (low, high) */
304
305 for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
306
307 if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV6))
308 nhigh = i;
309 else
310 {
311 nlow = i;
312
313 for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
314
315 if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV4))
316 nhigh = i;
317 else
318 {
319 nlow = i;
320
321 for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
322
323 if (!(flags & F_SERVER) && i != nlow && (flags & (F_IPV4 | F_IPV6)))
324 nhigh = i;
325 else
326 {
327 nlow = i;
328
329 /* Short to resolv.conf servers */
330 for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
331
332 if (i != nlow)
333 nhigh = i;
334 else
335 {
336 /* now look for a server */
337 for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
338
339 if (i != nlow)
340 {
341 /* If we want a server that can do DNSSEC, and this one can't,
342 return nothing, similarly if were looking only for a server
343 for a particular domain. */
344 if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
345 nlow = nhigh;
346 else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
347 nlow = nhigh;
348 else
349 nhigh = i;
350 }
351 else
352 {
353 /* --local=/domain/, only return if we don't need a server. */
354 if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
355 nhigh = i;
356 }
357 }
358 }
359 }
360 }
361 }
362
363 *lowout = nlow;
364 *highout = nhigh;
365
366 return (nlow != nhigh);
367}
368
369int is_local_answer(time_t now, int first, char *name)
370{
371 int flags = 0;
372 int rc = 0;
373
374 if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
375 {
376 if (flags & SERV_4ADDR)
377 rc = F_IPV4;
378 else if (flags & SERV_6ADDR)
379 rc = F_IPV6;
380 else if (flags & SERV_ALL_ZEROS)
381 rc = F_IPV4 | F_IPV6;
382 else
383 {
384 /* argument first is the first struct server which matches the query type;
385 now roll back to the server which is just the same domain, to check if that
386 provides an answer of a different type. */
387
388 for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
389
390 if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
391 check_for_local_domain(name, now))
392 rc = F_NOERR;
393 else
394 rc = F_NXDOMAIN;
395 }
396 }
397
398 return rc;
399}
400
401size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
402{
403 int trunc = 0, anscount = 0;
404 unsigned char *p;
405 int start;
406 union all_addr addr;
407
408 if (flags & (F_NXDOMAIN | F_NOERR))
409 log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
410
411 setup_reply(header, flags, ede);
412
413 if (!(p = skip_questions(header, size)))
414 return 0;
415
416 if (flags & gotname & F_IPV4)
417 for (start = first; start != last; start++)
418 {
419 struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
420
421 if (srv->flags & SERV_ALL_ZEROS)
422 memset(&addr, 0, sizeof(addr));
423 else
424 addr.addr4 = srv->addr;
425
426 if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
427 anscount++;
428 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
429 }
430
431 if (flags & gotname & F_IPV6)
432 for (start = first; start != last; start++)
433 {
434 struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
435
436 if (srv->flags & SERV_ALL_ZEROS)
437 memset(&addr, 0, sizeof(addr));
438 else
439 addr.addr6 = srv->addr;
440
441 if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
442 anscount++;
443 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
444 }
445
446 if (trunc)
447 header->hb3 |= HB3_TC;
448 header->ancount = htons(anscount);
449
450 return p - (unsigned char *)header;
451}
452
453#ifdef HAVE_DNSSEC
454int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
455{
456 int first, last, index;
457
458 /* Find server to send DNSSEC query to. This will normally be the
459 same as for the original query, but may be another if
460 servers for domains are involved. */
461 if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
462 return -1;
463
464 for (index = first; index != last; index++)
465 if (daemon->serverarray[index] == server)
466 break;
467
468 /* No match to server used for original query.
469 Use newly looked up set. */
470 if (index == last)
471 index = daemon->serverarray[first]->last_server == -1 ?
472 first : daemon->serverarray[first]->last_server;
473
474 if (firstp)
475 *firstp = first;
476
477 if (lastp)
478 *lastp = last;
479
480 return index;
481}
482#endif
483
484/* order by size, then by dictionary order */
485static int order(char *qdomain, size_t qlen, struct server *serv)
486{
487 size_t dlen = 0;
488
489 /* servers for dotless names always sort last
490 searched for name is never dotless. */
491 if (serv->flags & SERV_FOR_NODOTS)
492 return -1;
493
494 dlen = serv->domain_len;
495
496 if (qlen < dlen)
497 return 1;
498
499 if (qlen > dlen)
500 return -1;
501
502 return hostname_order(qdomain, serv->domain);
503}
504
505static int order_servers(struct server *s1, struct server *s2)
506{
507 int rc;
508
509 /* need full comparison of dotless servers in
510 order_qsort() and filter_servers() */
511
512 if (s1->flags & SERV_FOR_NODOTS)
513 return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
514
515 if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
516 return rc;
517
518 /* For identical domains, sort wildcard ones first */
519 if (s1->flags & SERV_WILDCARD)
520 return (s2->flags & SERV_WILDCARD) ? 0 : 1;
521
522 return (s2->flags & SERV_WILDCARD) ? -1 : 0;
523}
524
525static int order_qsort(const void *a, const void *b)
526{
527 int rc;
528
529 struct server *s1 = *((struct server **)a);
530 struct server *s2 = *((struct server **)b);
531
532 rc = order_servers(s1, s2);
533
534 /* Sort all literal NODATA and local IPV4 or IPV6 responses together,
535 in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
536 so the order is IPv6 literal, IPv4 literal, all-zero literal,
537 unqualified servers, upstream server, NXDOMAIN literal. */
538 if (rc == 0)
539 rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
540 ((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
541
542 /* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
543 if (rc == 0)
544 if (!(s1->flags & SERV_LITERAL_ADDRESS))
545 rc = s1->serial - s2->serial;
546
547 return rc;
548}
549
550
551/* When loading large numbers of server=.... lines during startup,
552 there's no possibility that there will be server records that can be reused, but
553 searching a long list for each server added grows as O(n^2) and slows things down.
554 This flag is set only if is known there may be free server records that can be reused.
555 There's a call to mark_servers(0) in read_opts() to reset the flag before
556 main config read. */
557
558static int maybe_free_servers = 0;
559
560/* Must be called before add_update_server() to set daemon->servers_tail */
561void mark_servers(int flag)
562{
563 struct server *serv, *next, **up;
564
565 maybe_free_servers = !!flag;
566
567 daemon->servers_tail = NULL;
568
569 /* mark everything with argument flag */
570 for (serv = daemon->servers; serv; serv = serv->next)
571 {
572 if (serv->flags & flag)
573 serv->flags |= SERV_MARK;
574 else
575 serv->flags &= ~SERV_MARK;
576
577 daemon->servers_tail = serv;
578 }
579
580 /* --address etc is different: since they are expected to be
581 1) numerous and 2) not reloaded often. We just delete
582 and recreate. */
583 if (flag)
584 for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = next)
585 {
586 next = serv->next;
587
588 if (serv->flags & flag)
589 {
590 *up = next;
591 free(serv->domain);
592 free(serv);
593 }
594 else
595 up = &serv->next;
596 }
597}
598
599void cleanup_servers(void)
600{
601 struct server *serv, *tmp, **up;
602
603 /* unlink and free anything still marked. */
604 for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp)
605 {
606 tmp = serv->next;
607 if (serv->flags & SERV_MARK)
608 {
609 server_gone(serv);
610 *up = serv->next;
611 free(serv->domain);
612 free(serv);
613 }
614 else
615 {
616 up = &serv->next;
617 daemon->servers_tail = serv;
618 }
619 }
620}
621
622int add_update_server(int flags,
623 union mysockaddr *addr,
624 union mysockaddr *source_addr,
625 const char *interface,
626 const char *domain,
627 union all_addr *local_addr)
628{
629 struct server *serv = NULL;
630 char *alloc_domain;
631
632 if (!domain)
633 domain = "";
634
635 /* .domain == domain, for historical reasons. */
636 if (*domain == '.')
637 while (*domain == '.') domain++;
638 else if (*domain == '*')
639 {
640 domain++;
641 if (*domain != 0)
642 flags |= SERV_WILDCARD;
643 }
644
645 if (*domain == 0)
646 alloc_domain = whine_malloc(1);
647 else
648 alloc_domain = canonicalise((char *)domain, NULL);
649
650 if (!alloc_domain)
651 return 0;
652
653 if (flags & SERV_IS_LOCAL)
654 {
655 size_t size;
656
657 if (flags & SERV_6ADDR)
658 size = sizeof(struct serv_addr6);
659 else if (flags & SERV_4ADDR)
660 size = sizeof(struct serv_addr4);
661 else
662 size = sizeof(struct serv_local);
663
664 if (!(serv = whine_malloc(size)))
665 {
666 free(alloc_domain);
667 return 0;
668 }
669
670 serv->next = daemon->local_domains;
671 daemon->local_domains = serv;
672
673 if (flags & SERV_4ADDR)
674 ((struct serv_addr4*)serv)->addr = local_addr->addr4;
675
676 if (flags & SERV_6ADDR)
677 ((struct serv_addr6*)serv)->addr = local_addr->addr6;
678 }
679 else
680 {
681 /* Upstream servers. See if there is a suitable candidate, if so unmark
682 and move to the end of the list, for order. The entry found may already
683 be at the end. */
684 struct server **up, *tmp;
685
686 serv = NULL;
687
688 if (maybe_free_servers)
689 for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
690 {
691 tmp = serv->next;
692 if ((serv->flags & SERV_MARK) &&
693 hostname_isequal(alloc_domain, serv->domain))
694 {
695 /* Need to move down? */
696 if (serv->next)
697 {
698 *up = serv->next;
699 daemon->servers_tail->next = serv;
700 daemon->servers_tail = serv;
701 serv->next = NULL;
702 }
703 break;
704 }
705 else
706 up = &serv->next;
707 }
708
709 if (serv)
710 {
711 free(alloc_domain);
712 alloc_domain = serv->domain;
713 }
714 else
715 {
716 if (!(serv = whine_malloc(sizeof(struct server))))
717 {
718 free(alloc_domain);
719 return 0;
720 }
721
722 memset(serv, 0, sizeof(struct server));
723
724 /* Add to the end of the chain, for order */
725 if (daemon->servers_tail)
726 daemon->servers_tail->next = serv;
727 else
728 daemon->servers = serv;
729 daemon->servers_tail = serv;
730 }
731
732#ifdef HAVE_LOOP
733 serv->uid = rand32();
734#endif
735
736 if (interface)
737 safe_strncpy(serv->interface, interface, sizeof(serv->interface));
738 if (addr)
739 serv->addr = *addr;
740 if (source_addr)
741 serv->source_addr = *source_addr;
742 }
743
744 serv->flags = flags;
745 serv->domain = alloc_domain;
746 serv->domain_len = strlen(alloc_domain);
747
748 return 1;
749}
750