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