Dnsmasq v2.68 rc4
[tomato.git] / release / src / router / dnsmasq / src / auth.c
blobd31ed60bffa265d43bbefd7885975258d5e39fb6
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 addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
23 struct addrlist *subnet;
25 for (subnet = zone->subnet; subnet; subnet = subnet->next)
27 if (!(subnet->flags & ADDRLIST_IPV6))
29 struct in_addr netmask, addr = addr_u->addr.addr4;
31 if (!(flag & F_IPV4))
32 continue;
34 netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
36 if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
37 return subnet;
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
45 return NULL;
48 static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
50 /* No zones specified, no filter */
51 if (!zone->subnet)
52 return 1;
54 return find_subnet(zone, flag, addr_u) != NULL;
57 int in_zone(struct auth_zone *zone, char *name, char **cut)
59 size_t namelen = strlen(name);
60 size_t domainlen = strlen(zone->domain);
62 if (cut)
63 *cut = NULL;
65 if (namelen >= domainlen &&
66 hostname_isequal(zone->domain, &name[namelen - domainlen]))
69 if (namelen == domainlen)
70 return 1;
72 if (name[namelen - domainlen - 1] == '.')
74 if (cut)
75 *cut = &name[namelen - domainlen - 1];
76 return 1;
80 return 0;
84 size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query)
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;
103 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
104 return 0;
106 /* determine end of question section (we put answers there) */
107 if (!(ansp = skip_questions(header, qlen)))
108 return 0; /* bad packet */
110 /* now process each question, answers go in RRs after the question */
111 p = (unsigned char *)(header+1);
113 for (q = ntohs(header->qdcount); q != 0; q--)
115 unsigned short flag = 0;
116 int found = 0;
118 /* save pointer to name for copying into answers */
119 nameoffset = p - (unsigned char *)header;
121 /* now extract name as .-concatenated string into name */
122 if (!extract_name(header, qlen, &p, name, 1, 4))
123 return 0; /* bad packet */
125 GETSHORT(qtype, p);
126 GETSHORT(qclass, p);
128 if (qclass != C_IN)
130 auth = 0;
131 continue;
134 if (qtype == T_PTR)
136 if (!(flag = in_arpa_name_2_addr(name, &addr)))
137 continue;
139 if (!local_query)
141 for (zone = daemon->auth_zones; zone; zone = zone->next)
142 if ((subnet = find_subnet(zone, flag, &addr)))
143 break;
145 if (!zone)
147 auth = 0;
148 continue;
152 intr = NULL;
154 if (flag == F_IPV4)
155 for (intr = daemon->int_names; intr; intr = intr->next)
157 struct addrlist *addrlist;
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;
163 if (addrlist)
164 break;
165 else
166 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
167 intr = intr->next;
169 #ifdef HAVE_IPV6
170 else if (flag == F_IPV6)
171 for (intr = daemon->int_names; intr; intr = intr->next)
173 struct addrlist *addrlist;
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;
179 if (addrlist)
180 break;
181 else
182 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
183 intr = intr->next;
185 #endif
187 if (intr)
189 if (in_zone(zone, intr->name, NULL))
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++;
200 if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
201 do {
202 strcpy(name, cache_get_name(crecp));
204 if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
206 char *p = strchr(name, '.');
207 if (p)
208 *p = 0; /* must be bare name */
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++;
220 else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
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++;
229 else
230 continue;
232 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
234 if (!found)
235 log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);
237 continue;
240 cname_restart:
241 for (zone = daemon->auth_zones; zone; zone = zone->next)
242 if (in_zone(zone, name, &cut))
243 break;
245 if (!zone)
247 auth = 0;
248 continue;
251 for (rec = daemon->mxnames; rec; rec = rec->next)
252 if (!rec->issrv && hostname_isequal(name, rec->name))
254 nxdomain = 0;
256 if (qtype == T_MX)
258 found = 1;
259 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
260 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
261 NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
262 anscount++;
266 for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
267 if (rec->issrv && hostname_isequal(name, rec->name))
269 nxdomain = 0;
271 if (qtype == T_SRV)
273 found = 1;
274 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
275 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
276 NULL, T_SRV, C_IN, "sssd",
277 rec->priority, rec->weight, rec->srvport, rec->target))
279 anscount++;
282 /* unlink first SRV record found */
283 if (!move)
285 move = rec;
286 *up = rec->next;
288 else
289 up = &rec->next;
291 else
292 up = &rec->next;
294 /* put first SRV record back at the end. */
295 if (move)
297 *up = move;
298 move->next = NULL;
301 for (txt = daemon->rr; txt; txt = txt->next)
302 if (hostname_isequal(name, txt->name))
304 nxdomain = 0;
305 if (txt->class == qtype)
307 found = 1;
308 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
309 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
310 NULL, txt->class, C_IN, "t", txt->len, txt->txt))
311 anscount++;
315 for (txt = daemon->txt; txt; txt = txt->next)
316 if (txt->class == C_IN && hostname_isequal(name, txt->name))
318 nxdomain = 0;
319 if (qtype == T_TXT)
321 found = 1;
322 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
323 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
324 NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
325 anscount++;
329 for (na = daemon->naptr; na; na = na->next)
330 if (hostname_isequal(name, na->name))
332 nxdomain = 0;
333 if (qtype == T_NAPTR)
335 found = 1;
336 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
337 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
338 NULL, T_NAPTR, C_IN, "sszzzd",
339 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
340 anscount++;
344 if (qtype == T_A)
345 flag = F_IPV4;
347 #ifdef HAVE_IPV6
348 if (qtype == T_AAAA)
349 flag = F_IPV6;
350 #endif
352 for (intr = daemon->int_names; intr; intr = intr->next)
353 if (hostname_isequal(name, intr->name))
355 struct addrlist *addrlist;
357 nxdomain = 0;
359 if (flag)
360 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
361 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
362 (local_query || filter_zone(zone, flag, &addrlist->addr)))
364 found = 1;
365 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
366 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
367 daemon->auth_ttl, NULL, qtype, C_IN,
368 qtype == T_A ? "4" : "6", &addrlist->addr))
369 anscount++;
373 for (a = daemon->cnames; a; a = a->next)
374 if (hostname_isequal(name, a->alias) )
376 log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
377 strcpy(name, a->target);
378 if (!strchr(name, '.'))
380 strcat(name, ".");
381 strcat(name, zone->domain);
383 found = 1;
384 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
385 daemon->auth_ttl, &nameoffset,
386 T_CNAME, C_IN, "d", name))
387 anscount++;
389 goto cname_restart;
392 if (!cut)
394 nxdomain = 0;
396 if (qtype == T_SOA)
398 auth = soa = 1; /* inhibits auth section */
399 found = 1;
400 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
402 else if (qtype == T_AXFR)
404 struct iname *peers;
406 if (peer_addr->sa.sa_family == AF_INET)
407 peer_addr->in.sin_port = 0;
408 #ifdef HAVE_IPV6
409 else
410 peer_addr->in6.sin6_port = 0;
411 #endif
413 for (peers = daemon->auth_peers; peers; peers = peers->next)
414 if (sockaddr_isequal(peer_addr, &peers->addr))
415 break;
417 /* Refuse all AXFR unless --auth-sec-servers is set */
418 if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
420 if (peer_addr->sa.sa_family == AF_INET)
421 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
422 #ifdef HAVE_IPV6
423 else
424 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
425 #endif
427 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
428 return 0;
431 auth = 1;
432 soa = 1; /* inhibits auth section */
433 ns = 1; /* ensure we include NS records! */
434 axfr = 1;
435 found = 1;
436 axfroffset = nameoffset;
437 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
439 else if (qtype == T_NS)
441 auth = 1;
442 ns = 1; /* inhibits auth section */
443 found = 1;
444 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
448 if (!option_bool(OPT_DHCP_FQDN) && cut)
450 *cut = 0; /* remove domain part */
452 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
454 if (crecp->flags & F_DHCP)
457 nxdomain = 0;
458 if ((crecp->flags & flag) &&
459 (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
461 *cut = '.'; /* restore domain part */
462 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
463 *cut = 0; /* remove domain part */
464 found = 1;
465 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
466 daemon->auth_ttl, NULL, qtype, C_IN,
467 qtype == T_A ? "4" : "6", &crecp->addr))
468 anscount++;
470 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
473 *cut = '.'; /* restore domain part */
476 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
478 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
481 nxdomain = 0;
482 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
484 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
485 found = 1;
486 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
487 daemon->auth_ttl, NULL, qtype, C_IN,
488 qtype == T_A ? "4" : "6", &crecp->addr))
489 anscount++;
491 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
494 if (!found)
495 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
499 /* Add auth section */
500 if (auth && zone)
502 char *authname;
503 int newoffset, offset = 0;
505 if (!subnet)
506 authname = zone->domain;
507 else
509 /* handle NS and SOA for PTR records */
511 authname = name;
513 if (!(subnet->flags & ADDRLIST_IPV6))
515 in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
516 char *p = name;
518 if (subnet->prefixlen >= 24)
519 p += sprintf(p, "%d.", a & 0xff);
520 a = a >> 8;
521 if (subnet->prefixlen >= 16 )
522 p += sprintf(p, "%d.", a & 0xff);
523 a = a >> 8;
524 p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
527 #ifdef HAVE_IPV6
528 else
530 char *p = name;
531 int i;
533 for (i = subnet->prefixlen-1; i >= 0; i -= 4)
535 int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3];
536 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
538 p += sprintf(p, "ip6.arpa");
541 #endif
544 /* handle NS and SOA in auth section or for explicit queries */
545 newoffset = ansp - (unsigned char *)header;
546 if (((anscount == 0 && !ns) || soa) &&
547 add_resource_record(header, limit, &trunc, 0, &ansp,
548 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
549 authname, daemon->authserver, daemon->hostmaster,
550 daemon->soa_sn, daemon->soa_refresh,
551 daemon->soa_retry, daemon->soa_expiry,
552 daemon->auth_ttl))
554 offset = newoffset;
555 if (soa)
556 anscount++;
557 else
558 authcount++;
561 if (anscount != 0 || ns)
563 struct name_list *secondary;
565 newoffset = ansp - (unsigned char *)header;
566 if (add_resource_record(header, limit, &trunc, -offset, &ansp,
567 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
569 if (offset == 0)
570 offset = newoffset;
571 if (ns)
572 anscount++;
573 else
574 authcount++;
577 if (!subnet)
578 for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
579 if (add_resource_record(header, limit, &trunc, offset, &ansp,
580 daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
582 if (ns)
583 anscount++;
584 else
585 authcount++;
589 if (axfr)
591 for (rec = daemon->mxnames; rec; rec = rec->next)
592 if (in_zone(zone, rec->name, &cut))
594 if (cut)
595 *cut = 0;
597 if (rec->issrv)
599 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
600 NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
601 rec->priority, rec->weight, rec->srvport, rec->target))
603 anscount++;
605 else
607 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
608 NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
609 anscount++;
612 /* restore config data */
613 if (cut)
614 *cut = '.';
617 for (txt = daemon->rr; txt; txt = txt->next)
618 if (in_zone(zone, txt->name, &cut))
620 if (cut)
621 *cut = 0;
623 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
624 NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
625 anscount++;
627 /* restore config data */
628 if (cut)
629 *cut = '.';
632 for (txt = daemon->txt; txt; txt = txt->next)
633 if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
635 if (cut)
636 *cut = 0;
638 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
639 NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
640 anscount++;
642 /* restore config data */
643 if (cut)
644 *cut = '.';
647 for (na = daemon->naptr; na; na = na->next)
648 if (in_zone(zone, na->name, &cut))
650 if (cut)
651 *cut = 0;
653 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
654 NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
655 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
656 anscount++;
658 /* restore config data */
659 if (cut)
660 *cut = '.';
663 for (intr = daemon->int_names; intr; intr = intr->next)
664 if (in_zone(zone, intr->name, &cut))
666 struct addrlist *addrlist;
668 if (cut)
669 *cut = 0;
671 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
672 if (!(addrlist->flags & ADDRLIST_IPV6) &&
673 (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
674 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
675 daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
676 anscount++;
678 #ifdef HAVE_IPV6
679 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
680 if ((addrlist->flags & ADDRLIST_IPV6) &&
681 (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
682 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
683 daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
684 anscount++;
685 #endif
687 /* restore config data */
688 if (cut)
689 *cut = '.';
692 for (a = daemon->cnames; a; a = a->next)
693 if (in_zone(zone, a->alias, &cut))
695 strcpy(name, a->target);
696 if (!strchr(name, '.'))
698 strcat(name, ".");
699 strcat(name, zone->domain);
702 if (cut)
703 *cut = 0;
705 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
706 daemon->auth_ttl, NULL,
707 T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
708 anscount++;
711 cache_enumerate(1);
712 while ((crecp = cache_enumerate(0)))
714 if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
715 !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
716 (crecp->flags & F_FORWARD))
718 if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
720 char *cache_name = cache_get_name(crecp);
721 if (!strchr(cache_name, '.') &&
722 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
724 qtype = T_A;
725 #ifdef HAVE_IPV6
726 if (crecp->flags & F_IPV6)
727 qtype = T_AAAA;
728 #endif
729 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
730 daemon->auth_ttl, NULL, qtype, C_IN,
731 (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
732 anscount++;
736 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
738 strcpy(name, cache_get_name(crecp));
739 if (in_zone(zone, name, &cut) &&
740 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
742 qtype = T_A;
743 #ifdef HAVE_IPV6
744 if (crecp->flags & F_IPV6)
745 qtype = T_AAAA;
746 #endif
747 if (cut)
748 *cut = 0;
750 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
751 daemon->auth_ttl, NULL, qtype, C_IN,
752 (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
753 anscount++;
759 /* repeat SOA as last record */
760 if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
761 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
762 daemon->authserver, daemon->hostmaster,
763 daemon->soa_sn, daemon->soa_refresh,
764 daemon->soa_retry, daemon->soa_expiry,
765 daemon->auth_ttl))
766 anscount++;
772 /* done all questions, set up header and return length of result */
773 /* clear authoritative and truncated flags, set QR flag */
774 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
776 if (local_query)
778 /* set RA flag */
779 header->hb4 |= HB4_RA;
781 else
783 /* clear RA flag */
784 header->hb4 &= ~HB4_RA;
787 /* authoritive */
788 if (auth)
789 header->hb3 |= HB3_AA;
791 /* truncation */
792 if (trunc)
793 header->hb3 |= HB3_TC;
795 if ((auth || local_query) && nxdomain)
796 SET_RCODE(header, NXDOMAIN);
797 else
798 SET_RCODE(header, NOERROR); /* no error */
799 header->ancount = htons(anscount);
800 header->nscount = htons(authcount);
801 header->arcount = htons(0);
802 return ansp - (unsigned char *)header;
805 #endif