blob: f8e4796678b7a40602430c8330a59db2ecfbcbdc [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* dnsmasq is Copyright (c) 2000-2021 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)
211 {
212 /* We've matched a setting which says to use servers without a domain.
213 Continue the search with empty query */
214 if (daemon->serverarray[try]->flags & SERV_USE_RESOLV)
215 crop_query = qlen;
216 else if (filter_servers(try, flags, &nlow, &nhigh))
217 /* We have a match, but it may only be (say) an IPv6 address, and
218 if the query wasn't for an AAAA record, it's no good, and we need
219 to continue generalising */
220 break;
221 }
222 }
223
224 /* crop_query must be at least one always. */
225 if (crop_query == 0)
226 crop_query = 1;
227
228 /* strip chars off the query based on the largest possible remaining match,
229 then continue to the start of the next label unless we have a wildcard
230 domain somewhere, in which case we have to go one at a time. */
231 qlen -= crop_query;
232 qdomain += crop_query;
233 if (!daemon->server_has_wildcard)
234 while (qlen > 0 && (*(qdomain-1) != '.'))
235 qlen--, qdomain++;
236 }
237
238 /* domain has no dots, and we have at least one server configured to handle such,
239 These servers always sort to the very end of the array.
240 A configured server eg server=/lan/ will take precdence. */
241 if (nodots &&
242 (daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
243 (nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
244 filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
245
246 if (lowout)
247 *lowout = nlow;
248
249 if (highout)
250 *highout = nhigh;
251
252 if (nlow == nhigh)
253 return 0;
254
255 return 1;
256}
257
258/* Return first server in group of equivalent servers; this is the "master" record. */
259int server_samegroup(struct server *a, struct server *b)
260{
261 return order_servers(a, b) == 0;
262}
263
264int filter_servers(int seed, int flags, int *lowout, int *highout)
265{
266 int nlow = seed, nhigh = seed;
267 int i;
268
269 /* expand nlow and nhigh to cover all the records with the same domain
270 nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
271 which can happen below. */
272 while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
273 nlow--;
274
275 while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
276 nhigh++;
277
278 nhigh++;
279
280#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
281
282 if (flags & F_CONFIG)
283 {
284 /* We're just lookin for any matches that return an RR. */
285 for (i = nlow; i < nhigh; i++)
286 if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
287 break;
288
289 /* failed, return failure. */
290 if (i == nhigh)
291 nhigh = nlow;
292 }
293 else
294 {
295 /* Now the servers are on order between low and high, in the order
296 IPv6 addr, IPv4 addr, return zero for both, send upstream, no-data return.
297
298 See which of those match our query in that priority order and narrow (low, high) */
299
300 for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
301
302 if (i != nlow && (flags & F_IPV6))
303 nhigh = i;
304 else
305 {
306 nlow = i;
307
308 for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
309
310 if (i != nlow && (flags & F_IPV4))
311 nhigh = i;
312 else
313 {
314 nlow = i;
315
316 for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
317
318 if (i != nlow && (flags & (F_IPV4 | F_IPV6)))
319 nhigh = i;
320 else
321 {
322 nlow = i;
323
324 /* now look for a server */
325 for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
326
327 if (i != nlow)
328 {
329 /* If we want a server that can do DNSSEC, and this one can't,
330 return nothing, similarly if were looking only for a server
331 for a particular domain. */
332 if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
333 nlow = nhigh;
334 else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
335 nlow = nhigh;
336 else
337 nhigh = i;
338 }
339 else
340 {
341 /* --local=/domain/, only return if we don't need a server. */
342 if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
343 nhigh = i;
344 }
345 }
346 }
347 }
348 }
349
350 *lowout = nlow;
351 *highout = nhigh;
352
353 return (nlow != nhigh);
354}
355
356int is_local_answer(time_t now, int first, char *name)
357{
358 int flags = 0;
359 int rc = 0;
360
361 if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
362 {
363 if (flags & SERV_4ADDR)
364 rc = F_IPV4;
365 else if (flags & SERV_6ADDR)
366 rc = F_IPV6;
367 else if (flags & SERV_ALL_ZEROS)
368 rc = F_IPV4 | F_IPV6;
369 else
370 {
371 /* argument first is the first struct server which matches the query type;
372 now roll back to the server which is just the same domain, to check if that
373 provides an answer of a different type. */
374
375 for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
376
377 if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
378 check_for_local_domain(name, now))
379 rc = F_NOERR;
380 else
381 rc = F_NXDOMAIN;
382 }
383 }
384
385 return rc;
386}
387
388size_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)
389{
390 int trunc = 0;
391 unsigned char *p;
392 int start;
393 union all_addr addr;
394
395 if (flags & (F_NXDOMAIN | F_NOERR))
396 log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL);
397
398 setup_reply(header, flags, ede);
399
400 if (!(p = skip_questions(header, size)))
401 return 0;
402
403 if (flags & gotname & F_IPV4)
404 for (start = first; start != last; start++)
405 {
406 struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
407
408 if (srv->flags & SERV_ALL_ZEROS)
409 memset(&addr, 0, sizeof(addr));
410 else
411 addr.addr4 = srv->addr;
412
413 header->ancount = htons(ntohs(header->ancount) + 1);
414 add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr);
415 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL);
416 }
417
418 if (flags & gotname & F_IPV6)
419 for (start = first; start != last; start++)
420 {
421 struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
422
423 if (srv->flags & SERV_ALL_ZEROS)
424 memset(&addr, 0, sizeof(addr));
425 else
426 addr.addr6 = srv->addr;
427
428 header->ancount = htons(ntohs(header->ancount) + 1);
429 add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr);
430 log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL);
431 }
432
433 if (trunc)
434 header->hb3 |= HB3_TC;
435
436 return p - (unsigned char *)header;
437}
438
439#ifdef HAVE_DNSSEC
440int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
441{
442 int first, last, index;
443
444 /* Find server to send DNSSEC query to. This will normally be the
445 same as for the original query, but may be another if
446 servers for domains are involved. */
447 if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
448 return -1;
449
450 for (index = first; index != last; index++)
451 if (daemon->serverarray[index] == server)
452 break;
453
454 /* No match to server used for original query.
455 Use newly looked up set. */
456 if (index == last)
457 index = daemon->serverarray[first]->last_server == -1 ?
458 first : daemon->serverarray[first]->last_server;
459
460 if (firstp)
461 *firstp = first;
462
463 if (lastp)
464 *lastp = last;
465
466 return index;
467}
468#endif
469
470/* order by size, then by dictionary order */
471static int order(char *qdomain, size_t qlen, struct server *serv)
472{
473 size_t dlen = 0;
474
475 /* servers for dotless names always sort last
476 searched for name is never dotless. */
477 if (serv->flags & SERV_FOR_NODOTS)
478 return -1;
479
480 dlen = serv->domain_len;
481
482 if (qlen < dlen)
483 return 1;
484
485 if (qlen > dlen)
486 return -1;
487
488 return strcmp(qdomain, serv->domain);
489}
490
491static int order_servers(struct server *s1, struct server *s2)
492{
493 int rc;
494
495 /* need full comparison of dotless servers in
496 order_qsort() and filter_servers() */
497
498 if (s1->flags & SERV_FOR_NODOTS)
499 return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
500
501 if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
502 return rc;
503
504 /* For identical domains, sort wildcard ones first */
505 if (s1->flags & SERV_WILDCARD)
506 return (s2->flags & SERV_WILDCARD) ? 0 : 1;
507
508 return (s2->flags & SERV_WILDCARD) ? -1 : 0;
509}
510
511static int order_qsort(const void *a, const void *b)
512{
513 int rc;
514
515 struct server *s1 = *((struct server **)a);
516 struct server *s2 = *((struct server **)b);
517
518 rc = order_servers(s1, s2);
519
520 /* Sort all literal NODATA and local IPV4 or IPV6 responses together,
521 in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
522 so the order is IPv6 literal, IPv4 literal, all-zero literal,
523 upstream server, NXDOMAIN literal. */
524 if (rc == 0)
525 rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
526 ((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
527
528 /* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
529 if (rc == 0)
530 if (!(s1->flags & SERV_LITERAL_ADDRESS))
531 rc = s1->serial - s2->serial;
532
533 return rc;
534}
535
536void mark_servers(int flag)
537{
538 struct server *serv;
539
540 /* mark everything with argument flag */
541 for (serv = daemon->servers; serv; serv = serv->next)
542 if (serv->flags & flag)
543 serv->flags |= SERV_MARK;
544 else
545 serv->flags &= ~SERV_MARK;
546
547 for (serv = daemon->local_domains; serv; serv = serv->next)
548 if (serv->flags & flag)
549 serv->flags |= SERV_MARK;
550 else
551 serv->flags &= ~SERV_MARK;
552}
553
554void cleanup_servers(void)
555{
556 struct server *serv, *tmp, **up;
557
558 /* unlink and free anything still marked. */
559 for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
560 {
561 tmp = serv->next;
562 if (serv->flags & SERV_MARK)
563 {
564 server_gone(serv);
565 *up = serv->next;
566 free(serv->domain);
567 free(serv);
568 }
569 else
570 up = &serv->next;
571 }
572
573 for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
574 {
575 tmp = serv->next;
576 if (serv->flags & SERV_MARK)
577 {
578 *up = serv->next;
579 free(serv->domain);
580 free(serv);
581 }
582 else
583 up = &serv->next;
584 }
585}
586
587int add_update_server(int flags,
588 union mysockaddr *addr,
589 union mysockaddr *source_addr,
590 const char *interface,
591 const char *domain,
592 union all_addr *local_addr)
593{
594 struct server *serv = NULL;
595 char *alloc_domain;
596
597 if (!domain)
598 domain = "";
599
600 /* .domain == domain, for historical reasons. */
601 if (*domain == '.')
602 while (*domain == '.') domain++;
603 else if (*domain == '*')
604 {
605 domain++;
606 if (*domain != 0)
607 flags |= SERV_WILDCARD;
608 }
609
610 if (*domain == 0)
611 alloc_domain = whine_malloc(1);
612 else if (!(alloc_domain = canonicalise((char *)domain, NULL)))
613 return 0;
614
615 /* See if there is a suitable candidate, and unmark
616 only do this for forwarding servers, not
617 address or local, to avoid delays on large numbers. */
618 if (flags & SERV_IS_LOCAL)
619 for (serv = daemon->servers; serv; serv = serv->next)
620 if ((serv->flags & SERV_MARK) &&
621 hostname_isequal(alloc_domain, serv->domain))
622 break;
623
624 if (serv)
625 {
626 free(alloc_domain);
627 alloc_domain = serv->domain;
628 }
629 else
630 {
631 size_t size;
632
633 if (flags & SERV_LITERAL_ADDRESS)
634 {
635 if (flags & SERV_6ADDR)
636 size = sizeof(struct serv_addr6);
637 else if (flags & SERV_4ADDR)
638 size = sizeof(struct serv_addr4);
639 else
640 size = sizeof(struct serv_local);
641 }
642 else
643 size = sizeof(struct server);
644
645 if (!(serv = whine_malloc(size)))
646 return 0;
647
648 if (flags & SERV_IS_LOCAL)
649 {
650 serv->next = daemon->local_domains;
651 daemon->local_domains = serv;
652 }
653 else
654 {
655 struct server *s;
656 /* Add to the end of the chain, for order */
657 if (!daemon->servers)
658 daemon->servers = serv;
659 else
660 {
661 for (s = daemon->servers; s->next; s = s->next);
662 s->next = serv;
663 }
664
665 serv->next = NULL;
666 }
667 }
668
669 if (!(flags & SERV_IS_LOCAL))
670 memset(serv, 0, sizeof(struct server));
671
672 serv->flags = flags;
673 serv->domain = alloc_domain;
674 serv->domain_len = strlen(alloc_domain);
675
676 if (flags & SERV_4ADDR)
677 ((struct serv_addr4*)serv)->addr = local_addr->addr4;
678
679 if (flags & SERV_6ADDR)
680 ((struct serv_addr6*)serv)->addr = local_addr->addr6;
681
682 if (!(flags & SERV_IS_LOCAL))
683 {
684#ifdef HAVE_LOOP
685 serv->uid = rand32();
686#endif
687
688 if (interface)
689 safe_strncpy(serv->interface, interface, sizeof(serv->interface));
690 if (addr)
691 serv->addr = *addr;
692 if (source_addr)
693 serv->source_addr = *source_addr;
694 }
695
696 return 1;
697}
698