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