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