Changes to update Tomato RAF.
[tomato.git] / release / src / router / dnsmasq / src / auth.c
blobaf2171cd4c573223a72e3b2ab03361915a70fc85
1 /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
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.
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.
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/>.
17 #include "dnsmasq.h"
19 #ifdef HAVE_AUTH
21 static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
23 struct subnet *subnet;
25 for (subnet = zone->subnet; subnet; subnet = subnet->next)
27 if (subnet->is6 && (flag & F_IPV4))
28 continue;
30 if (!subnet->is6)
32 struct in_addr addr = addr_u->addr.addr4;
33 struct in_addr mask;
35 mask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
37 if (is_same_net(addr, subnet->addr4, mask))
38 return subnet;
40 #ifdef HAVE_IPV6
41 else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr6, subnet->prefixlen))
42 return subnet;
43 #endif
46 return NULL;
49 static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_addr *addr_u)
51 #ifdef HAVE_DHCP6
52 struct dhcp_context *context;
54 if (flag & F_IPV6)
55 for (context = daemon->dhcp6; context; context = context->next)
56 if ((context->flags & CONTEXT_CONSTRUCTED) &&
57 !(context->flags & CONTEXT_NOAUTH) &&
58 is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
59 return 1;
60 #endif
62 return filter_zone(zone, flag, addr_u) != NULL;
65 static int in_zone(struct auth_zone *zone, char *name, char **cut)
67 size_t namelen = strlen(name);
68 size_t domainlen = strlen(zone->domain);
70 if (cut)
71 *cut = NULL;
73 if (namelen >= domainlen &&
74 hostname_isequal(zone->domain, &name[namelen - domainlen]))
77 if (namelen == domainlen)
78 return 1;
80 if (name[namelen - domainlen - 1] == '.')
82 if (cut)
83 *cut = &name[namelen - domainlen - 1];
84 return 1;
88 return 0;
92 size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr)
94 char *name = daemon->namebuff;
95 unsigned char *p, *ansp;
96 int qtype, qclass;
97 int nameoffset, axfroffset = 0;
98 int q, anscount = 0, authcount = 0;
99 struct crec *crecp;
100 int auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
101 struct auth_zone *zone = NULL;
102 struct subnet *subnet = NULL;
103 char *cut;
104 struct mx_srv_record *rec, *move, **up;
105 struct txt_record *txt;
106 struct interface_name *intr;
107 struct naptr *na;
108 struct all_addr addr;
109 struct cname *a;
111 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
112 return 0;
114 /* determine end of question section (we put answers there) */
115 if (!(ansp = skip_questions(header, qlen)))
116 return 0; /* bad packet */
118 /* now process each question, answers go in RRs after the question */
119 p = (unsigned char *)(header+1);
121 for (q = ntohs(header->qdcount); q != 0; q--)
123 unsigned short flag = 0;
124 int found = 0;
126 /* save pointer to name for copying into answers */
127 nameoffset = p - (unsigned char *)header;
129 /* now extract name as .-concatenated string into name */
130 if (!extract_name(header, qlen, &p, name, 1, 4))
131 return 0; /* bad packet */
133 GETSHORT(qtype, p);
134 GETSHORT(qclass, p);
136 if (qclass != C_IN)
138 auth = 0;
139 continue;
142 if (qtype == T_PTR)
144 if (!(flag = in_arpa_name_2_addr(name, &addr)))
145 continue;
147 for (zone = daemon->auth_zones; zone; zone = zone->next)
148 if ((subnet = filter_zone(zone, flag, &addr)))
149 break;
151 if (!zone)
153 auth = 0;
154 continue;
157 intr = NULL;
159 if (flag == F_IPV4)
160 for (intr = daemon->int_names; intr; intr = intr->next)
162 struct addrlist *addrlist;
164 for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
165 if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
166 break;
168 if (addrlist)
169 break;
170 else
171 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
172 intr = intr->next;
174 #ifdef HAVE_IPV6
175 else if (flag == F_IPV6)
176 for (intr = daemon->int_names; intr; intr = intr->next)
178 struct addrlist *addrlist;
180 for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
181 if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
182 break;
184 if (addrlist)
185 break;
186 else
187 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
188 intr = intr->next;
190 #endif
192 if (intr)
194 if (in_zone(zone, intr->name, NULL))
196 found = 1;
197 log_query(flag| F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
198 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
199 daemon->auth_ttl, NULL,
200 T_PTR, C_IN, "d", intr->name))
201 anscount++;
205 if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
206 do {
207 strcpy(name, cache_get_name(crecp));
209 if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
211 char *p = strchr(name, '.');
212 if (p)
213 *p = 0; /* must be bare name */
215 /* add external domain */
216 strcat(name, ".");
217 strcat(name, zone->domain);
218 log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
219 found = 1;
220 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
221 daemon->auth_ttl, NULL,
222 T_PTR, C_IN, "d", name))
223 anscount++;
225 else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
227 log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
228 found = 1;
229 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
230 daemon->auth_ttl, NULL,
231 T_PTR, C_IN, "d", name))
232 anscount++;
234 else
235 continue;
237 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
239 if (!found)
240 log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);
242 continue;
245 cname_restart:
246 for (zone = daemon->auth_zones; zone; zone = zone->next)
247 if (in_zone(zone, name, &cut))
248 break;
250 if (!zone)
252 auth = 0;
253 continue;
256 for (rec = daemon->mxnames; rec; rec = rec->next)
257 if (!rec->issrv && hostname_isequal(name, rec->name))
259 nxdomain = 0;
261 if (qtype == T_MX)
263 found = 1;
264 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
265 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
266 NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
267 anscount++;
271 for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
272 if (rec->issrv && hostname_isequal(name, rec->name))
274 nxdomain = 0;
276 if (qtype == T_SRV)
278 found = 1;
279 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
280 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
281 NULL, T_SRV, C_IN, "sssd",
282 rec->priority, rec->weight, rec->srvport, rec->target))
284 anscount++;
287 /* unlink first SRV record found */
288 if (!move)
290 move = rec;
291 *up = rec->next;
293 else
294 up = &rec->next;
296 else
297 up = &rec->next;
299 /* put first SRV record back at the end. */
300 if (move)
302 *up = move;
303 move->next = NULL;
306 for (txt = daemon->rr; txt; txt = txt->next)
307 if (hostname_isequal(name, txt->name))
309 nxdomain = 0;
310 if (txt->class == qtype)
312 found = 1;
313 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
314 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
315 NULL, txt->class, C_IN, "t", txt->len, txt->txt))
316 anscount++;
320 for (txt = daemon->txt; txt; txt = txt->next)
321 if (txt->class == C_IN && hostname_isequal(name, txt->name))
323 nxdomain = 0;
324 if (qtype == T_TXT)
326 found = 1;
327 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
328 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
329 NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
330 anscount++;
334 for (na = daemon->naptr; na; na = na->next)
335 if (hostname_isequal(name, na->name))
337 nxdomain = 0;
338 if (qtype == T_NAPTR)
340 found = 1;
341 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
342 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
343 NULL, T_NAPTR, C_IN, "sszzzd",
344 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
345 anscount++;
349 if (qtype == T_A)
350 flag = F_IPV4;
352 #ifdef HAVE_IPV6
353 if (qtype == T_AAAA)
354 flag = F_IPV6;
355 #endif
357 for (intr = daemon->int_names; intr; intr = intr->next)
358 if (hostname_isequal(name, intr->name))
360 struct addrlist *addrlist;
362 addrlist = intr->addr4;
363 #ifdef HAVE_IPV6
364 if (qtype == T_AAAA)
365 addrlist = intr->addr6;
366 #endif
367 nxdomain = 0;
369 for (; addrlist; addrlist = addrlist->next)
370 if (filter_constructed_dhcp(zone, flag, &addrlist->addr))
372 found = 1;
373 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
374 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
375 daemon->auth_ttl, NULL, qtype, C_IN,
376 qtype == T_A ? "4" : "6", &addrlist->addr))
377 anscount++;
381 for (a = daemon->cnames; a; a = a->next)
382 if (hostname_isequal(name, a->alias) )
384 log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
385 strcpy(name, a->target);
386 if (!strchr(name, '.'))
388 strcat(name, ".");
389 strcat(name, zone->domain);
391 found = 1;
392 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
393 daemon->auth_ttl, NULL,
394 T_CNAME, C_IN, "d", name))
395 anscount++;
397 goto cname_restart;
400 if (!cut)
402 nxdomain = 0;
404 if (qtype == T_SOA)
406 soa = 1; /* inhibits auth section */
407 found = 1;
408 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
410 else if (qtype == T_AXFR)
412 struct iname *peers;
414 if (peer_addr->sa.sa_family == AF_INET)
415 peer_addr->in.sin_port = 0;
416 #ifdef HAVE_IPV6
417 else
418 peer_addr->in6.sin6_port = 0;
419 #endif
421 for (peers = daemon->auth_peers; peers; peers = peers->next)
422 if (sockaddr_isequal(peer_addr, &peers->addr))
423 break;
425 /* Refuse all AXFR unless --auth-sec-servers is set */
426 if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
428 if (peer_addr->sa.sa_family == AF_INET)
429 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
430 #ifdef HAVE_IPV6
431 else
432 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
433 #endif
435 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
436 return 0;
439 soa = 1; /* inhibits auth section */
440 ns = 1; /* ensure we include NS records! */
441 axfr = 1;
442 found = 1;
443 axfroffset = nameoffset;
444 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
446 else if (qtype == T_NS)
448 ns = 1; /* inhibits auth section */
449 found = 1;
450 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
454 if (!option_bool(OPT_DHCP_FQDN) && cut)
456 *cut = 0; /* remove domain part */
458 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
460 if (crecp->flags & F_DHCP)
463 nxdomain = 0;
464 if ((crecp->flags & flag) &&
465 (filter_constructed_dhcp(zone, flag, &(crecp->addr.addr))))
467 *cut = '.'; /* restore domain part */
468 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
469 *cut = 0; /* remove domain part */
470 found = 1;
471 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
472 daemon->auth_ttl, NULL, qtype, C_IN,
473 qtype == T_A ? "4" : "6", &crecp->addr))
474 anscount++;
476 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
479 *cut = '.'; /* restore domain part */
482 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
484 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
487 nxdomain = 0;
488 if ((crecp->flags & flag) && filter_constructed_dhcp(zone, flag, &(crecp->addr.addr)))
490 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
491 found = 1;
492 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
493 daemon->auth_ttl, NULL, qtype, C_IN,
494 qtype == T_A ? "4" : "6", &crecp->addr))
495 anscount++;
497 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
500 if (!found)
501 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
505 /* Add auth section */
506 if (auth && zone)
508 char *authname;
509 int newoffset, offset = 0;
511 if (!subnet)
512 authname = zone->domain;
513 else
515 /* handle NS and SOA for PTR records */
517 authname = name;
519 if (!subnet->is6)
521 in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
522 char *p = name;
524 if (subnet->prefixlen >= 24)
525 p += sprintf(p, "%d.", a & 0xff);
526 a = a >> 8;
527 if (subnet->prefixlen >= 16 )
528 p += sprintf(p, "%d.", a & 0xff);
529 a = a >> 8;
530 p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
533 #ifdef HAVE_IPV6
534 else
536 char *p = name;
537 int i;
539 for (i = subnet->prefixlen-1; i >= 0; i -= 4)
541 int dig = ((unsigned char *)&subnet->addr6)[i>>3];
542 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
544 p += sprintf(p, "ip6.arpa");
547 #endif
550 /* handle NS and SOA in auth section or for explicit queries */
551 newoffset = ansp - (unsigned char *)header;
552 if (((anscount == 0 && !ns) || soa) &&
553 add_resource_record(header, limit, &trunc, 0, &ansp,
554 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
555 authname, daemon->authserver, daemon->hostmaster,
556 daemon->soa_sn, daemon->soa_refresh,
557 daemon->soa_retry, daemon->soa_expiry,
558 daemon->auth_ttl))
560 offset = newoffset;
561 if (soa)
562 anscount++;
563 else
564 authcount++;
567 if (anscount != 0 || ns)
569 struct name_list *secondary;
571 newoffset = ansp - (unsigned char *)header;
572 if (add_resource_record(header, limit, &trunc, -offset, &ansp,
573 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
575 if (offset == 0)
576 offset = newoffset;
577 if (ns)
578 anscount++;
579 else
580 authcount++;
583 if (!subnet)
584 for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
585 if (add_resource_record(header, limit, &trunc, offset, &ansp,
586 daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
588 if (ns)
589 anscount++;
590 else
591 authcount++;
595 if (axfr)
597 for (rec = daemon->mxnames; rec; rec = rec->next)
598 if (in_zone(zone, rec->name, &cut))
600 if (cut)
601 *cut = 0;
603 if (rec->issrv)
605 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
606 NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
607 rec->priority, rec->weight, rec->srvport, rec->target))
609 anscount++;
611 else
613 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
614 NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
615 anscount++;
618 /* restore config data */
619 if (cut)
620 *cut = '.';
623 for (txt = daemon->rr; txt; txt = txt->next)
624 if (in_zone(zone, txt->name, &cut))
626 if (cut)
627 *cut = 0;
629 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
630 NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
631 anscount++;
633 /* restore config data */
634 if (cut)
635 *cut = '.';
638 for (txt = daemon->txt; txt; txt = txt->next)
639 if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
641 if (cut)
642 *cut = 0;
644 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
645 NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
646 anscount++;
648 /* restore config data */
649 if (cut)
650 *cut = '.';
653 for (na = daemon->naptr; na; na = na->next)
654 if (in_zone(zone, na->name, &cut))
656 if (cut)
657 *cut = 0;
659 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
660 NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
661 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
662 anscount++;
664 /* restore config data */
665 if (cut)
666 *cut = '.';
669 for (intr = daemon->int_names; intr; intr = intr->next)
670 if (in_zone(zone, intr->name, &cut))
672 struct addrlist *addrlist;
674 if (cut)
675 *cut = 0;
677 for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
678 if (filter_constructed_dhcp(zone, F_IPV4, &addrlist->addr) &&
679 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
680 daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
681 anscount++;
683 #ifdef HAVE_IPV6
684 for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
685 if (filter_constructed_dhcp(zone, F_IPV6, &addrlist->addr) &&
686 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
687 daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
688 anscount++;
689 #endif
691 /* restore config data */
692 if (cut)
693 *cut = '.';
696 for (a = daemon->cnames; a; a = a->next)
697 if (in_zone(zone, a->alias, &cut))
699 strcpy(name, a->target);
700 if (!strchr(name, '.'))
702 strcat(name, ".");
703 strcat(name, zone->domain);
706 if (cut)
707 *cut = 0;
709 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
710 daemon->auth_ttl, NULL,
711 T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
712 anscount++;
715 cache_enumerate(1);
716 while ((crecp = cache_enumerate(0)))
718 if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
719 !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
720 (crecp->flags & F_FORWARD))
722 if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
724 char *cache_name = cache_get_name(crecp);
725 if (!strchr(cache_name, '.') && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
727 qtype = T_A;
728 #ifdef HAVE_IPV6
729 if (crecp->flags & F_IPV6)
730 qtype = T_AAAA;
731 #endif
732 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
733 daemon->auth_ttl, NULL, qtype, C_IN,
734 (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
735 anscount++;
739 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
741 strcpy(name, cache_get_name(crecp));
742 if (in_zone(zone, name, &cut) && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
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;
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++;
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++;
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 /* clear RA flag */
778 header->hb4 &= ~HB4_RA;
780 /* authoritive */
781 if (auth)
782 header->hb3 |= HB3_AA;
784 /* truncation */
785 if (trunc)
786 header->hb3 |= HB3_TC;
788 if (anscount == 0 && auth && nxdomain)
789 SET_RCODE(header, NXDOMAIN);
790 else
791 SET_RCODE(header, NOERROR); /* no error */
792 header->ancount = htons(anscount);
793 header->nscount = htons(authcount);
794 header->arcount = htons(0);
795 return ansp - (unsigned char *)header;
798 #endif