1: /* dnsmasq is Copyright (c) 2000-2022 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:
21: static 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:
44: static 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:
52: static 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:
60: static 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:
72: int 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:
99: size_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, 0);
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), 0);
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), 0);
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, 0);
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, 0);
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>", 0);
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>", 0);
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, 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>", 0);
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>", 0);
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, 0);
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: nxdomain = 0;
421:
422: log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
423: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
424: daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
425: anscount++;
426: }
427:
428: if (!cut)
429: {
430: nxdomain = 0;
431:
432: if (qtype == T_SOA)
433: {
434: auth = soa = 1; /* inhibits auth section */
435: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
436: }
437: else if (qtype == T_AXFR)
438: {
439: struct iname *peers;
440:
441: if (peer_addr->sa.sa_family == AF_INET)
442: peer_addr->in.sin_port = 0;
443: else
444: {
445: peer_addr->in6.sin6_port = 0;
446: peer_addr->in6.sin6_scope_id = 0;
447: }
448:
449: for (peers = daemon->auth_peers; peers; peers = peers->next)
450: if (sockaddr_isequal(peer_addr, &peers->addr))
451: break;
452:
453: /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
454: if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
455: (daemon->auth_peers && !peers))
456: {
457: if (peer_addr->sa.sa_family == AF_INET)
458: inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
459: else
460: inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
461:
462: my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
463: return 0;
464: }
465:
466: auth = 1;
467: soa = 1; /* inhibits auth section */
468: ns = 1; /* ensure we include NS records! */
469: axfr = 1;
470: axfroffset = nameoffset;
471: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
472: }
473: else if (qtype == T_NS)
474: {
475: auth = 1;
476: ns = 1; /* inhibits auth section */
477: log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
478: }
479: }
480:
481: if (!option_bool(OPT_DHCP_FQDN) && cut)
482: {
483: *cut = 0; /* remove domain part */
484:
485: if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
486: {
487: if (crecp->flags & F_DHCP)
488: do
489: {
490: nxdomain = 0;
491: if ((crecp->flags & flag) &&
492: (local_query || filter_zone(zone, flag, &(crecp->addr))))
493: {
494: *cut = '.'; /* restore domain part */
495: log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
496: *cut = 0; /* remove domain part */
497: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
498: daemon->auth_ttl, NULL, qtype, C_IN,
499: qtype == T_A ? "4" : "6", &crecp->addr))
500: anscount++;
501: }
502: } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
503: }
504:
505: *cut = '.'; /* restore domain part */
506: }
507:
508: if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
509: {
510: if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
511: do
512: {
513: nxdomain = 0;
514: if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
515: {
516: log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
517: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
518: daemon->auth_ttl, NULL, qtype, C_IN,
519: qtype == T_A ? "4" : "6", &crecp->addr))
520: anscount++;
521: }
522: } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
523: }
524:
525: /* Only supply CNAME if no record for any type is known. */
526: if (nxdomain)
527: {
528: /* Check for possible wildcard match against *.domain
529: return length of match, to get longest.
530: Note that if return length of wildcard section, so
531: we match b.simon to _both_ *.simon and b.simon
532: but return a longer (better) match to b.simon.
533: */
534: for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
535: if (a->alias[0] == '*')
536: {
537: char *test = name;
538:
539: while ((test = strchr(test+1, '.')))
540: {
541: if (hostname_isequal(test, &(a->alias[1])))
542: {
543: if (strlen(test) > wclen && !cname_wildcard)
544: {
545: wclen = strlen(test);
546: candidate = a;
547: cname_wildcard = 1;
548: }
549: break;
550: }
551: }
552:
553: }
554: else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
555: {
556: /* Simple case, no wildcard */
557: wclen = strlen(a->alias);
558: candidate = a;
559: }
560:
561: if (candidate)
562: {
563: log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
564: strcpy(name, candidate->target);
565: if (!strchr(name, '.'))
566: {
567: strcat(name, ".");
568: strcat(name, zone->domain);
569: }
570: found = 1;
571: if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
572: daemon->auth_ttl, &nameoffset,
573: T_CNAME, C_IN, "d", name))
574: anscount++;
575:
576: goto cname_restart;
577: }
578: else if (cache_find_non_terminal(name, now))
579: nxdomain = 0;
580:
581: log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
582: }
583:
584: }
585:
586: /* Add auth section */
587: if (auth && zone)
588: {
589: char *authname;
590: int newoffset, offset = 0;
591:
592: if (!subnet)
593: authname = zone->domain;
594: else
595: {
596: /* handle NS and SOA for PTR records */
597:
598: authname = name;
599:
600: if (!(subnet->flags & ADDRLIST_IPV6))
601: {
602: in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
603: char *p = name;
604:
605: if (subnet->prefixlen >= 24)
606: p += sprintf(p, "%u.", a & 0xff);
607: a = a >> 8;
608: if (subnet->prefixlen >= 16 )
609: p += sprintf(p, "%u.", a & 0xff);
610: a = a >> 8;
611: sprintf(p, "%u.in-addr.arpa", a & 0xff);
612:
613: }
614: else
615: {
616: char *p = name;
617: int i;
618:
619: for (i = subnet->prefixlen-1; i >= 0; i -= 4)
620: {
621: int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
622: p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
623: }
624: sprintf(p, "ip6.arpa");
625:
626: }
627: }
628:
629: /* handle NS and SOA in auth section or for explicit queries */
630: newoffset = ansp - (unsigned char *)header;
631: if (((anscount == 0 && !ns) || soa) &&
632: add_resource_record(header, limit, &trunc, 0, &ansp,
633: daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
634: authname, daemon->authserver, daemon->hostmaster,
635: daemon->soa_sn, daemon->soa_refresh,
636: daemon->soa_retry, daemon->soa_expiry,
637: daemon->auth_ttl))
638: {
639: offset = newoffset;
640: if (soa)
641: anscount++;
642: else
643: authcount++;
644: }
645:
646: if (anscount != 0 || ns)
647: {
648: struct name_list *secondary;
649:
650: /* Only include the machine running dnsmasq if it's acting as an auth server */
651: if (daemon->authinterface)
652: {
653: newoffset = ansp - (unsigned char *)header;
654: if (add_resource_record(header, limit, &trunc, -offset, &ansp,
655: daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
656: {
657: if (offset == 0)
658: offset = newoffset;
659: if (ns)
660: anscount++;
661: else
662: authcount++;
663: }
664: }
665:
666: if (!subnet)
667: for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
668: if (add_resource_record(header, limit, &trunc, offset, &ansp,
669: daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
670: {
671: if (ns)
672: anscount++;
673: else
674: authcount++;
675: }
676: }
677:
678: if (axfr)
679: {
680: for (rec = daemon->mxnames; rec; rec = rec->next)
681: if (in_zone(zone, rec->name, &cut))
682: {
683: if (cut)
684: *cut = 0;
685:
686: if (rec->issrv)
687: {
688: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
689: NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
690: rec->priority, rec->weight, rec->srvport, rec->target))
691:
692: anscount++;
693: }
694: else
695: {
696: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
697: NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
698: anscount++;
699: }
700:
701: /* restore config data */
702: if (cut)
703: *cut = '.';
704: }
705:
706: for (txt = daemon->rr; txt; txt = txt->next)
707: if (in_zone(zone, txt->name, &cut))
708: {
709: if (cut)
710: *cut = 0;
711:
712: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
713: NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
714: anscount++;
715:
716: /* restore config data */
717: if (cut)
718: *cut = '.';
719: }
720:
721: for (txt = daemon->txt; txt; txt = txt->next)
722: if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
723: {
724: if (cut)
725: *cut = 0;
726:
727: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
728: NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
729: anscount++;
730:
731: /* restore config data */
732: if (cut)
733: *cut = '.';
734: }
735:
736: for (na = daemon->naptr; na; na = na->next)
737: if (in_zone(zone, na->name, &cut))
738: {
739: if (cut)
740: *cut = 0;
741:
742: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
743: NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
744: na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
745: anscount++;
746:
747: /* restore config data */
748: if (cut)
749: *cut = '.';
750: }
751:
752: for (intr = daemon->int_names; intr; intr = intr->next)
753: if (in_zone(zone, intr->name, &cut))
754: {
755: struct addrlist *addrlist;
756:
757: if (cut)
758: *cut = 0;
759:
760: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
761: if (!(addrlist->flags & ADDRLIST_IPV6) &&
762: (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
763: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
764: daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
765: anscount++;
766:
767: for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
768: if ((addrlist->flags & ADDRLIST_IPV6) &&
769: (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
770: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
771: daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
772: anscount++;
773:
774: /* restore config data */
775: if (cut)
776: *cut = '.';
777: }
778:
779: for (a = daemon->cnames; a; a = a->next)
780: if (in_zone(zone, a->alias, &cut))
781: {
782: strcpy(name, a->target);
783: if (!strchr(name, '.'))
784: {
785: strcat(name, ".");
786: strcat(name, zone->domain);
787: }
788:
789: if (cut)
790: *cut = 0;
791:
792: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
793: daemon->auth_ttl, NULL,
794: T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
795: anscount++;
796: }
797:
798: cache_enumerate(1);
799: while ((crecp = cache_enumerate(0)))
800: {
801: if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
802: !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
803: (crecp->flags & F_FORWARD))
804: {
805: if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
806: {
807: char *cache_name = cache_get_name(crecp);
808: if (!strchr(cache_name, '.') &&
809: (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) &&
810: add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
811: daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
812: (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
813: anscount++;
814: }
815:
816: if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
817: {
818: strcpy(name, cache_get_name(crecp));
819: if (in_zone(zone, name, &cut) &&
820: (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
821: {
822: if (cut)
823: *cut = 0;
824:
825: if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
826: daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
827: (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
828: anscount++;
829: }
830: }
831: }
832: }
833:
834: /* repeat SOA as last record */
835: if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
836: daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
837: daemon->authserver, daemon->hostmaster,
838: daemon->soa_sn, daemon->soa_refresh,
839: daemon->soa_retry, daemon->soa_expiry,
840: daemon->auth_ttl))
841: anscount++;
842:
843: }
844:
845: }
846:
847: /* done all questions, set up header and return length of result */
848: /* clear authoritative and truncated flags, set QR flag */
849: header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
850:
851: if (local_query)
852: {
853: /* set RA flag */
854: header->hb4 |= HB4_RA;
855: }
856: else
857: {
858: /* clear RA flag */
859: header->hb4 &= ~HB4_RA;
860: }
861:
862: /* data is never DNSSEC signed. */
863: header->hb4 &= ~HB4_AD;
864:
865: /* authoritative */
866: if (auth)
867: header->hb3 |= HB3_AA;
868:
869: /* truncation */
870: if (trunc)
871: header->hb3 |= HB3_TC;
872:
873: if ((auth || local_query) && nxdomain)
874: SET_RCODE(header, NXDOMAIN);
875: else
876: SET_RCODE(header, NOERROR); /* no error */
877:
878: header->ancount = htons(anscount);
879: header->nscount = htons(authcount);
880: header->arcount = htons(0);
881:
882: if (!local_query && out_of_zone)
883: {
884: SET_RCODE(header, REFUSED);
885: header->ancount = htons(0);
886: header->nscount = htons(0);
887: addr.log.rcode = REFUSED;
888: addr.log.ede = EDE_NOT_AUTH;
889: log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
890: return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
891: }
892:
893: /* Advertise our packet size limit in our reply */
894: if (have_pseudoheader)
895: return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
896:
897: return ansp - (unsigned char *)header;
898: }
899:
900: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>