blob: 172a4b2d3e3bc20a7d3cd42d4efb53ac5c37b257 [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
19#ifdef HAVE_AUTH
20
21static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u)
22{
23 do {
24 if (!(list->flags & ADDRLIST_IPV6))
25 {
26 struct in_addr netmask, addr = addr_u->addr4;
27
28 if (!(flag & F_IPV4))
29 continue;
30
31 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
32
33 if (is_same_net(addr, list->addr.addr4, netmask))
34 return list;
35 }
36 else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen))
37 return list;
38
39 } while ((list = list->next));
40
41 return NULL;
42}
43
44static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union all_addr *addr_u)
45{
46 if (!zone->subnet)
47 return NULL;
48
49 return find_addrlist(zone->subnet, flag, addr_u);
50}
51
52static struct addrlist *find_exclude(struct auth_zone *zone, int flag, union all_addr *addr_u)
53{
54 if (!zone->exclude)
55 return NULL;
56
57 return find_addrlist(zone->exclude, flag, addr_u);
58}
59
60static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u)
61{
62 if (find_exclude(zone, flag, addr_u))
63 return 0;
64
65 /* No subnets specified, no filter */
66 if (!zone->subnet)
67 return 1;
68
69 return find_subnet(zone, flag, addr_u) != NULL;
70}
71
72int in_zone(struct auth_zone *zone, char *name, char **cut)
73{
74 size_t namelen = strlen(name);
75 size_t domainlen = strlen(zone->domain);
76
77 if (cut)
78 *cut = NULL;
79
80 if (namelen >= domainlen &&
81 hostname_isequal(zone->domain, &name[namelen - domainlen]))
82 {
83
84 if (namelen == domainlen)
85 return 1;
86
87 if (name[namelen - domainlen - 1] == '.')
88 {
89 if (cut)
90 *cut = &name[namelen - domainlen - 1];
91 return 1;
92 }
93 }
94
95 return 0;
96}
97
98
99size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr,
100 int local_query, int do_bit, int have_pseudoheader)
101{
102 char *name = daemon->namebuff;
103 unsigned char *p, *ansp;
104 int qtype, qclass, rc;
105 int nameoffset, axfroffset = 0;
106 int q, anscount = 0, authcount = 0;
107 struct crec *crecp;
108 int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0;
109 struct auth_zone *zone = NULL;
110 struct addrlist *subnet = NULL;
111 char *cut;
112 struct mx_srv_record *rec, *move, **up;
113 struct txt_record *txt;
114 struct interface_name *intr;
115 struct naptr *na;
116 union all_addr addr;
117 struct cname *a, *candidate;
118 unsigned int wclen;
119
120 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
121 return 0;
122
123 /* determine end of question section (we put answers there) */
124 if (!(ansp = skip_questions(header, qlen)))
125 return 0; /* bad packet */
126
127 /* now process each question, answers go in RRs after the question */
128 p = (unsigned char *)(header+1);
129
130 for (q = ntohs(header->qdcount); q != 0; q--)
131 {
132 unsigned int flag = 0;
133 int found = 0;
134 int cname_wildcard = 0;
135
136 /* save pointer to name for copying into answers */
137 nameoffset = p - (unsigned char *)header;
138
139 /* now extract name as .-concatenated string into name */
140 if (!extract_name(header, qlen, &p, name, 1, 4))
141 return 0; /* bad packet */
142
143 GETSHORT(qtype, p);
144 GETSHORT(qclass, p);
145
146 if (qclass != C_IN)
147 {
148 auth = 0;
149 out_of_zone = 1;
150 continue;
151 }
152
153 if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
154 (flag = in_arpa_name_2_addr(name, &addr)) &&
155 !local_query)
156 {
157 for (zone = daemon->auth_zones; zone; zone = zone->next)
158 if ((subnet = find_subnet(zone, flag, &addr)))
159 break;
160
161 if (!zone)
162 {
163 out_of_zone = 1;
164 auth = 0;
165 continue;
166 }
167 else if (qtype == T_SOA)
168 soa = 1, found = 1;
169 else if (qtype == T_NS)
170 ns = 1, found = 1;
171 }
172
173 if (qtype == T_PTR && flag)
174 {
175 intr = NULL;
176
177 if (flag == F_IPV4)
178 for (intr = daemon->int_names; intr; intr = intr->next)
179 {
180 struct addrlist *addrlist;
181
182 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
183 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
184 break;
185
186 if (addrlist)
187 break;
188 else
189 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
190 intr = intr->next;
191 }
192 else if (flag == F_IPV6)
193 for (intr = daemon->int_names; intr; intr = intr->next)
194 {
195 struct addrlist *addrlist;
196
197 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
198 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
199 break;
200
201 if (addrlist)
202 break;
203 else
204 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
205 intr = intr->next;
206 }
207
208 if (intr)
209 {
210 if (local_query || in_zone(zone, intr->name, NULL))
211 {
212 found = 1;
213 log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
214 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
215 daemon->auth_ttl, NULL,
216 T_PTR, C_IN, "d", intr->name))
217 anscount++;
218 }
219 }
220
221 if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
222 do {
223 strcpy(name, cache_get_name(crecp));
224
225 if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
226 {
227 char *p = strchr(name, '.');
228 if (p)
229 *p = 0; /* must be bare name */
230
231 /* add external domain */
232 if (zone)
233 {
234 strcat(name, ".");
235 strcat(name, zone->domain);
236 }
237 log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
238 found = 1;
239 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
240 daemon->auth_ttl, NULL,
241 T_PTR, C_IN, "d", name))
242 anscount++;
243 }
244 else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
245 {
246 log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
247 found = 1;
248 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
249 daemon->auth_ttl, NULL,
250 T_PTR, C_IN, "d", name))
251 anscount++;
252 }
253 else
254 continue;
255
256 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
257
258 if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
259 {
260 log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL);
261 found = 1;
262
263 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
264 daemon->auth_ttl, NULL,
265 T_PTR, C_IN, "d", name))
266 anscount++;
267 }
268
269 if (found)
270 nxdomain = 0;
271 else
272 log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
273
274 continue;
275 }
276
277 cname_restart:
278 if (found)
279 /* NS and SOA .arpa requests have set found above. */
280 cut = NULL;
281 else
282 {
283 for (zone = daemon->auth_zones; zone; zone = zone->next)
284 if (in_zone(zone, name, &cut))
285 break;
286
287 if (!zone)
288 {
289 out_of_zone = 1;
290 auth = 0;
291 continue;
292 }
293 }
294
295 for (rec = daemon->mxnames; rec; rec = rec->next)
296 if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
297 {
298 nxdomain = 0;
299
300 if (rc == 2 && qtype == T_MX)
301 {
302 found = 1;
303 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
304 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
305 NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
306 anscount++;
307 }
308 }
309
310 for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
311 if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
312 {
313 nxdomain = 0;
314
315 if (rc == 2 && qtype == T_SRV)
316 {
317 found = 1;
318 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
319 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
320 NULL, T_SRV, C_IN, "sssd",
321 rec->priority, rec->weight, rec->srvport, rec->target))
322
323 anscount++;
324 }
325
326 /* unlink first SRV record found */
327 if (!move)
328 {
329 move = rec;
330 *up = rec->next;
331 }
332 else
333 up = &rec->next;
334 }
335 else
336 up = &rec->next;
337
338 /* put first SRV record back at the end. */
339 if (move)
340 {
341 *up = move;
342 move->next = NULL;
343 }
344
345 for (txt = daemon->rr; txt; txt = txt->next)
346 if ((rc = hostname_issubdomain(name, txt->name)))
347 {
348 nxdomain = 0;
349 if (rc == 2 && txt->class == qtype)
350 {
351 found = 1;
352 log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
353 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
354 NULL, txt->class, C_IN, "t", txt->len, txt->txt))
355 anscount++;
356 }
357 }
358
359 for (txt = daemon->txt; txt; txt = txt->next)
360 if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
361 {
362 nxdomain = 0;
363 if (rc == 2 && qtype == T_TXT)
364 {
365 found = 1;
366 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
367 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
368 NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
369 anscount++;
370 }
371 }
372
373 for (na = daemon->naptr; na; na = na->next)
374 if ((rc = hostname_issubdomain(name, na->name)))
375 {
376 nxdomain = 0;
377 if (rc == 2 && qtype == T_NAPTR)
378 {
379 found = 1;
380 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
381 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
382 NULL, T_NAPTR, C_IN, "sszzzd",
383 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
384 anscount++;
385 }
386 }
387
388 if (qtype == T_A)
389 flag = F_IPV4;
390
391 if (qtype == T_AAAA)
392 flag = F_IPV6;
393
394 for (intr = daemon->int_names; intr; intr = intr->next)
395 if ((rc = hostname_issubdomain(name, intr->name)))
396 {
397 struct addrlist *addrlist;
398
399 nxdomain = 0;
400
401 if (rc == 2 && flag)
402 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
403 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
404 (local_query || filter_zone(zone, flag, &addrlist->addr)))
405 {
406 if (addrlist->flags & ADDRLIST_REVONLY)
407 continue;
408
409 found = 1;
410 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
411 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
412 daemon->auth_ttl, NULL, qtype, C_IN,
413 qtype == T_A ? "4" : "6", &addrlist->addr))
414 anscount++;
415 }
416 }
417
418 if (!found && is_name_synthetic(flag, name, &addr) )
419 {
420 found = 1;
421 nxdomain = 0;
422
423 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
424 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
425 daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
426 anscount++;
427 }
428
429 if (!cut)
430 {
431 nxdomain = 0;
432
433 if (qtype == T_SOA)
434 {
435 auth = soa = 1; /* inhibits auth section */
436 found = 1;
437 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
438 }
439 else if (qtype == T_AXFR)
440 {
441 struct iname *peers;
442
443 if (peer_addr->sa.sa_family == AF_INET)
444 peer_addr->in.sin_port = 0;
445 else
446 {
447 peer_addr->in6.sin6_port = 0;
448 peer_addr->in6.sin6_scope_id = 0;
449 }
450
451 for (peers = daemon->auth_peers; peers; peers = peers->next)
452 if (sockaddr_isequal(peer_addr, &peers->addr))
453 break;
454
455 /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
456 if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
457 (daemon->auth_peers && !peers))
458 {
459 if (peer_addr->sa.sa_family == AF_INET)
460 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
461 else
462 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
463
464 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
465 return 0;
466 }
467
468 auth = 1;
469 soa = 1; /* inhibits auth section */
470 ns = 1; /* ensure we include NS records! */
471 axfr = 1;
472 found = 1;
473 axfroffset = nameoffset;
474 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
475 }
476 else if (qtype == T_NS)
477 {
478 auth = 1;
479 ns = 1; /* inhibits auth section */
480 found = 1;
481 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
482 }
483 }
484
485 if (!option_bool(OPT_DHCP_FQDN) && cut)
486 {
487 *cut = 0; /* remove domain part */
488
489 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
490 {
491 if (crecp->flags & F_DHCP)
492 do
493 {
494 nxdomain = 0;
495 if ((crecp->flags & flag) &&
496 (local_query || filter_zone(zone, flag, &(crecp->addr))))
497 {
498 *cut = '.'; /* restore domain part */
499 log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
500 *cut = 0; /* remove domain part */
501 found = 1;
502 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
503 daemon->auth_ttl, NULL, qtype, C_IN,
504 qtype == T_A ? "4" : "6", &crecp->addr))
505 anscount++;
506 }
507 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
508 }
509
510 *cut = '.'; /* restore domain part */
511 }
512
513 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
514 {
515 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
516 do
517 {
518 nxdomain = 0;
519 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
520 {
521 log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
522 found = 1;
523 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
524 daemon->auth_ttl, NULL, qtype, C_IN,
525 qtype == T_A ? "4" : "6", &crecp->addr))
526 anscount++;
527 }
528 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
529 }
530
531 /* Only supply CNAME if no record for any type is known. */
532 if (nxdomain)
533 {
534 /* Check for possible wildcard match against *.domain
535 return length of match, to get longest.
536 Note that if return length of wildcard section, so
537 we match b.simon to _both_ *.simon and b.simon
538 but return a longer (better) match to b.simon.
539 */
540 for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
541 if (a->alias[0] == '*')
542 {
543 char *test = name;
544
545 while ((test = strchr(test+1, '.')))
546 {
547 if (hostname_isequal(test, &(a->alias[1])))
548 {
549 if (strlen(test) > wclen && !cname_wildcard)
550 {
551 wclen = strlen(test);
552 candidate = a;
553 cname_wildcard = 1;
554 }
555 break;
556 }
557 }
558
559 }
560 else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
561 {
562 /* Simple case, no wildcard */
563 wclen = strlen(a->alias);
564 candidate = a;
565 }
566
567 if (candidate)
568 {
569 log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
570 strcpy(name, candidate->target);
571 if (!strchr(name, '.'))
572 {
573 strcat(name, ".");
574 strcat(name, zone->domain);
575 }
576 found = 1;
577 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
578 daemon->auth_ttl, &nameoffset,
579 T_CNAME, C_IN, "d", name))
580 anscount++;
581
582 goto cname_restart;
583 }
584 else if (cache_find_non_terminal(name, now))
585 nxdomain = 0;
586
587 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
588 }
589
590 }
591
592 /* Add auth section */
593 if (auth && zone)
594 {
595 char *authname;
596 int newoffset, offset = 0;
597
598 if (!subnet)
599 authname = zone->domain;
600 else
601 {
602 /* handle NS and SOA for PTR records */
603
604 authname = name;
605
606 if (!(subnet->flags & ADDRLIST_IPV6))
607 {
608 in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
609 char *p = name;
610
611 if (subnet->prefixlen >= 24)
612 p += sprintf(p, "%u.", a & 0xff);
613 a = a >> 8;
614 if (subnet->prefixlen >= 16 )
615 p += sprintf(p, "%u.", a & 0xff);
616 a = a >> 8;
617 p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
618
619 }
620 else
621 {
622 char *p = name;
623 int i;
624
625 for (i = subnet->prefixlen-1; i >= 0; i -= 4)
626 {
627 int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
628 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
629 }
630 p += sprintf(p, "ip6.arpa");
631
632 }
633 }
634
635 /* handle NS and SOA in auth section or for explicit queries */
636 newoffset = ansp - (unsigned char *)header;
637 if (((anscount == 0 && !ns) || soa) &&
638 add_resource_record(header, limit, &trunc, 0, &ansp,
639 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
640 authname, daemon->authserver, daemon->hostmaster,
641 daemon->soa_sn, daemon->soa_refresh,
642 daemon->soa_retry, daemon->soa_expiry,
643 daemon->auth_ttl))
644 {
645 offset = newoffset;
646 if (soa)
647 anscount++;
648 else
649 authcount++;
650 }
651
652 if (anscount != 0 || ns)
653 {
654 struct name_list *secondary;
655
656 /* Only include the machine running dnsmasq if it's acting as an auth server */
657 if (daemon->authinterface)
658 {
659 newoffset = ansp - (unsigned char *)header;
660 if (add_resource_record(header, limit, &trunc, -offset, &ansp,
661 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
662 {
663 if (offset == 0)
664 offset = newoffset;
665 if (ns)
666 anscount++;
667 else
668 authcount++;
669 }
670 }
671
672 if (!subnet)
673 for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
674 if (add_resource_record(header, limit, &trunc, offset, &ansp,
675 daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
676 {
677 if (ns)
678 anscount++;
679 else
680 authcount++;
681 }
682 }
683
684 if (axfr)
685 {
686 for (rec = daemon->mxnames; rec; rec = rec->next)
687 if (in_zone(zone, rec->name, &cut))
688 {
689 if (cut)
690 *cut = 0;
691
692 if (rec->issrv)
693 {
694 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
695 NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
696 rec->priority, rec->weight, rec->srvport, rec->target))
697
698 anscount++;
699 }
700 else
701 {
702 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
703 NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
704 anscount++;
705 }
706
707 /* restore config data */
708 if (cut)
709 *cut = '.';
710 }
711
712 for (txt = daemon->rr; txt; txt = txt->next)
713 if (in_zone(zone, txt->name, &cut))
714 {
715 if (cut)
716 *cut = 0;
717
718 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
719 NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
720 anscount++;
721
722 /* restore config data */
723 if (cut)
724 *cut = '.';
725 }
726
727 for (txt = daemon->txt; txt; txt = txt->next)
728 if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
729 {
730 if (cut)
731 *cut = 0;
732
733 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
734 NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
735 anscount++;
736
737 /* restore config data */
738 if (cut)
739 *cut = '.';
740 }
741
742 for (na = daemon->naptr; na; na = na->next)
743 if (in_zone(zone, na->name, &cut))
744 {
745 if (cut)
746 *cut = 0;
747
748 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
749 NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
750 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
751 anscount++;
752
753 /* restore config data */
754 if (cut)
755 *cut = '.';
756 }
757
758 for (intr = daemon->int_names; intr; intr = intr->next)
759 if (in_zone(zone, intr->name, &cut))
760 {
761 struct addrlist *addrlist;
762
763 if (cut)
764 *cut = 0;
765
766 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
767 if (!(addrlist->flags & ADDRLIST_IPV6) &&
768 (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
769 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
770 daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
771 anscount++;
772
773 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
774 if ((addrlist->flags & ADDRLIST_IPV6) &&
775 (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
776 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
777 daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
778 anscount++;
779
780 /* restore config data */
781 if (cut)
782 *cut = '.';
783 }
784
785 for (a = daemon->cnames; a; a = a->next)
786 if (in_zone(zone, a->alias, &cut))
787 {
788 strcpy(name, a->target);
789 if (!strchr(name, '.'))
790 {
791 strcat(name, ".");
792 strcat(name, zone->domain);
793 }
794
795 if (cut)
796 *cut = 0;
797
798 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
799 daemon->auth_ttl, NULL,
800 T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
801 anscount++;
802 }
803
804 cache_enumerate(1);
805 while ((crecp = cache_enumerate(0)))
806 {
807 if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
808 !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
809 (crecp->flags & F_FORWARD))
810 {
811 if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
812 {
813 char *cache_name = cache_get_name(crecp);
814 if (!strchr(cache_name, '.') &&
815 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) &&
816 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
817 daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
818 (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
819 anscount++;
820 }
821
822 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
823 {
824 strcpy(name, cache_get_name(crecp));
825 if (in_zone(zone, name, &cut) &&
826 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
827 {
828 if (cut)
829 *cut = 0;
830
831 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
832 daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
833 (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
834 anscount++;
835 }
836 }
837 }
838 }
839
840 /* repeat SOA as last record */
841 if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
842 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
843 daemon->authserver, daemon->hostmaster,
844 daemon->soa_sn, daemon->soa_refresh,
845 daemon->soa_retry, daemon->soa_expiry,
846 daemon->auth_ttl))
847 anscount++;
848
849 }
850
851 }
852
853 /* done all questions, set up header and return length of result */
854 /* clear authoritative and truncated flags, set QR flag */
855 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
856
857 if (local_query)
858 {
859 /* set RA flag */
860 header->hb4 |= HB4_RA;
861 }
862 else
863 {
864 /* clear RA flag */
865 header->hb4 &= ~HB4_RA;
866 }
867
868 /* data is never DNSSEC signed. */
869 header->hb4 &= ~HB4_AD;
870
871 /* authoritative */
872 if (auth)
873 header->hb3 |= HB3_AA;
874
875 /* truncation */
876 if (trunc)
877 header->hb3 |= HB3_TC;
878
879 if ((auth || local_query) && nxdomain)
880 SET_RCODE(header, NXDOMAIN);
881 else
882 SET_RCODE(header, NOERROR); /* no error */
883
884 header->ancount = htons(anscount);
885 header->nscount = htons(authcount);
886 header->arcount = htons(0);
887
888 if (!local_query && out_of_zone)
889 {
890 SET_RCODE(header, REFUSED);
891 header->ancount = htons(0);
892 header->nscount = htons(0);
893 addr.log.rcode = REFUSED;
894 addr.log.ede = EDE_NOT_AUTH;
895 log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL);
896 return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
897 }
898
899 /* Advertise our packet size limit in our reply */
900 if (have_pseudoheader)
901 return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
902
903 return ansp - (unsigned char *)header;
904}
905
906#endif