dnsmasq: re-apply original Tomato specific code
[tomato.git] / release / src / router / dnsmasq / src / auth.c
blob198572d84c874e571f24d48fa9289df102b7c59a
1 /* dnsmasq is Copyright (c) 2000-2016 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(~(in_addr_t)0 << (32 - subnet->prefixlen));
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,
85 int local_query, int do_bit, int have_pseudoheader)
87 char *name = daemon->namebuff;
88 unsigned char *p, *ansp;
89 int qtype, qclass;
90 int nameoffset, axfroffset = 0;
91 int q, anscount = 0, authcount = 0;
92 struct crec *crecp;
93 int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
94 struct auth_zone *zone = NULL;
95 struct addrlist *subnet = NULL;
96 char *cut;
97 struct mx_srv_record *rec, *move, **up;
98 struct txt_record *txt;
99 struct interface_name *intr;
100 struct naptr *na;
101 struct all_addr addr;
102 struct cname *a;
104 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
105 return 0;
107 /* determine end of question section (we put answers there) */
108 if (!(ansp = skip_questions(header, qlen)))
109 return 0; /* bad packet */
111 /* now process each question, answers go in RRs after the question */
112 p = (unsigned char *)(header+1);
114 for (q = ntohs(header->qdcount); q != 0; q--)
116 unsigned short flag = 0;
117 int found = 0;
119 /* save pointer to name for copying into answers */
120 nameoffset = p - (unsigned char *)header;
122 /* now extract name as .-concatenated string into name */
123 if (!extract_name(header, qlen, &p, name, 1, 4))
124 return 0; /* bad packet */
126 GETSHORT(qtype, p);
127 GETSHORT(qclass, p);
129 if (qclass != C_IN)
131 auth = 0;
132 continue;
135 if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
136 (flag = in_arpa_name_2_addr(name, &addr)) &&
137 !local_query)
139 for (zone = daemon->auth_zones; zone; zone = zone->next)
140 if ((subnet = find_subnet(zone, flag, &addr)))
141 break;
143 if (!zone)
145 auth = 0;
146 continue;
148 else if (qtype == T_SOA)
149 soa = 1, found = 1;
150 else if (qtype == T_NS)
151 ns = 1, found = 1;
154 if (qtype == T_PTR && flag)
156 intr = NULL;
158 if (flag == F_IPV4)
159 for (intr = daemon->int_names; intr; intr = intr->next)
161 struct addrlist *addrlist;
163 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
164 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
165 break;
167 if (addrlist)
168 break;
169 else
170 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
171 intr = intr->next;
173 #ifdef HAVE_IPV6
174 else if (flag == F_IPV6)
175 for (intr = daemon->int_names; intr; intr = intr->next)
177 struct addrlist *addrlist;
179 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
180 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
181 break;
183 if (addrlist)
184 break;
185 else
186 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
187 intr = intr->next;
189 #endif
191 if (intr)
193 if (local_query || in_zone(zone, intr->name, NULL))
195 found = 1;
196 log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
197 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
198 daemon->auth_ttl, NULL,
199 T_PTR, C_IN, "d", intr->name))
200 anscount++;
204 if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
205 do {
206 strcpy(name, cache_get_name(crecp));
208 if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
210 char *p = strchr(name, '.');
211 if (p)
212 *p = 0; /* must be bare name */
214 /* add external domain */
215 if (zone)
217 strcat(name, ".");
218 strcat(name, zone->domain);
220 log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
221 found = 1;
222 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
223 daemon->auth_ttl, NULL,
224 T_PTR, C_IN, "d", name))
225 anscount++;
227 else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
229 log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
230 found = 1;
231 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
232 daemon->auth_ttl, NULL,
233 T_PTR, C_IN, "d", name))
234 anscount++;
236 else
237 continue;
239 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
241 if (found)
242 nxdomain = 0;
243 else
244 log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
246 continue;
249 cname_restart:
250 if (found)
251 /* NS and SOA .arpa requests have set found above. */
252 cut = NULL;
253 else
255 for (zone = daemon->auth_zones; zone; zone = zone->next)
256 if (in_zone(zone, name, &cut))
257 break;
259 if (!zone)
261 auth = 0;
262 continue;
266 for (rec = daemon->mxnames; rec; rec = rec->next)
267 if (!rec->issrv && hostname_isequal(name, rec->name))
269 nxdomain = 0;
271 if (qtype == T_MX)
273 found = 1;
274 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
275 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
276 NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
277 anscount++;
281 for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
282 if (rec->issrv && hostname_isequal(name, rec->name))
284 nxdomain = 0;
286 if (qtype == T_SRV)
288 found = 1;
289 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
290 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
291 NULL, T_SRV, C_IN, "sssd",
292 rec->priority, rec->weight, rec->srvport, rec->target))
294 anscount++;
297 /* unlink first SRV record found */
298 if (!move)
300 move = rec;
301 *up = rec->next;
303 else
304 up = &rec->next;
306 else
307 up = &rec->next;
309 /* put first SRV record back at the end. */
310 if (move)
312 *up = move;
313 move->next = NULL;
316 for (txt = daemon->rr; txt; txt = txt->next)
317 if (hostname_isequal(name, txt->name))
319 nxdomain = 0;
320 if (txt->class == qtype)
322 found = 1;
323 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
324 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
325 NULL, txt->class, C_IN, "t", txt->len, txt->txt))
326 anscount++;
330 for (txt = daemon->txt; txt; txt = txt->next)
331 if (txt->class == C_IN && hostname_isequal(name, txt->name))
333 nxdomain = 0;
334 if (qtype == T_TXT)
336 found = 1;
337 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
338 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
339 NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
340 anscount++;
344 for (na = daemon->naptr; na; na = na->next)
345 if (hostname_isequal(name, na->name))
347 nxdomain = 0;
348 if (qtype == T_NAPTR)
350 found = 1;
351 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
352 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
353 NULL, T_NAPTR, C_IN, "sszzzd",
354 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
355 anscount++;
359 if (qtype == T_A)
360 flag = F_IPV4;
362 #ifdef HAVE_IPV6
363 if (qtype == T_AAAA)
364 flag = F_IPV6;
365 #endif
367 for (intr = daemon->int_names; intr; intr = intr->next)
368 if (hostname_isequal(name, intr->name))
370 struct addrlist *addrlist;
372 nxdomain = 0;
374 if (flag)
375 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
376 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
377 (local_query || filter_zone(zone, flag, &addrlist->addr)))
379 #ifdef HAVE_IPV6
380 if (addrlist->flags & ADDRLIST_REVONLY)
381 continue;
382 #endif
383 found = 1;
384 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
385 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
386 daemon->auth_ttl, NULL, qtype, C_IN,
387 qtype == T_A ? "4" : "6", &addrlist->addr))
388 anscount++;
392 for (a = daemon->cnames; a; a = a->next)
393 if (hostname_isequal(name, a->alias) )
395 log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
396 strcpy(name, a->target);
397 if (!strchr(name, '.'))
399 strcat(name, ".");
400 strcat(name, zone->domain);
402 found = 1;
403 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
404 daemon->auth_ttl, &nameoffset,
405 T_CNAME, C_IN, "d", name))
406 anscount++;
408 goto cname_restart;
411 if (!cut)
413 nxdomain = 0;
415 if (qtype == T_SOA)
417 auth = soa = 1; /* inhibits auth section */
418 found = 1;
419 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
421 else if (qtype == T_AXFR)
423 struct iname *peers;
425 if (peer_addr->sa.sa_family == AF_INET)
426 peer_addr->in.sin_port = 0;
427 #ifdef HAVE_IPV6
428 else
430 peer_addr->in6.sin6_port = 0;
431 peer_addr->in6.sin6_scope_id = 0;
433 #endif
435 for (peers = daemon->auth_peers; peers; peers = peers->next)
436 if (sockaddr_isequal(peer_addr, &peers->addr))
437 break;
439 /* Refuse all AXFR unless --auth-sec-servers is set */
440 if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
442 if (peer_addr->sa.sa_family == AF_INET)
443 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
444 #ifdef HAVE_IPV6
445 else
446 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
447 #endif
449 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
450 return 0;
453 auth = 1;
454 soa = 1; /* inhibits auth section */
455 ns = 1; /* ensure we include NS records! */
456 axfr = 1;
457 found = 1;
458 axfroffset = nameoffset;
459 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
461 else if (qtype == T_NS)
463 auth = 1;
464 ns = 1; /* inhibits auth section */
465 found = 1;
466 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
470 if (!option_bool(OPT_DHCP_FQDN) && cut)
472 *cut = 0; /* remove domain part */
474 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
476 if (crecp->flags & F_DHCP)
479 nxdomain = 0;
480 if ((crecp->flags & flag) &&
481 (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
483 *cut = '.'; /* restore domain part */
484 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
485 *cut = 0; /* remove domain part */
486 found = 1;
487 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
488 daemon->auth_ttl, NULL, qtype, C_IN,
489 qtype == T_A ? "4" : "6", &crecp->addr))
490 anscount++;
492 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
495 *cut = '.'; /* restore domain part */
498 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
500 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
503 nxdomain = 0;
504 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
506 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
507 found = 1;
508 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
509 daemon->auth_ttl, NULL, qtype, C_IN,
510 qtype == T_A ? "4" : "6", &crecp->addr))
511 anscount++;
513 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
516 if (!found)
517 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
521 /* Add auth section */
522 if (auth && zone)
524 char *authname;
525 int newoffset, offset = 0;
527 if (!subnet)
528 authname = zone->domain;
529 else
531 /* handle NS and SOA for PTR records */
533 authname = name;
535 if (!(subnet->flags & ADDRLIST_IPV6))
537 in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
538 char *p = name;
540 if (subnet->prefixlen >= 24)
541 p += sprintf(p, "%d.", a & 0xff);
542 a = a >> 8;
543 if (subnet->prefixlen >= 16 )
544 p += sprintf(p, "%d.", a & 0xff);
545 a = a >> 8;
546 p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
549 #ifdef HAVE_IPV6
550 else
552 char *p = name;
553 int i;
555 for (i = subnet->prefixlen-1; i >= 0; i -= 4)
557 int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3];
558 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
560 p += sprintf(p, "ip6.arpa");
563 #endif
566 /* handle NS and SOA in auth section or for explicit queries */
567 newoffset = ansp - (unsigned char *)header;
568 if (((anscount == 0 && !ns) || soa) &&
569 add_resource_record(header, limit, &trunc, 0, &ansp,
570 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
571 authname, daemon->authserver, daemon->hostmaster,
572 daemon->soa_sn, daemon->soa_refresh,
573 daemon->soa_retry, daemon->soa_expiry,
574 daemon->auth_ttl))
576 offset = newoffset;
577 if (soa)
578 anscount++;
579 else
580 authcount++;
583 if (anscount != 0 || ns)
585 struct name_list *secondary;
587 newoffset = ansp - (unsigned char *)header;
588 if (add_resource_record(header, limit, &trunc, -offset, &ansp,
589 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
591 if (offset == 0)
592 offset = newoffset;
593 if (ns)
594 anscount++;
595 else
596 authcount++;
599 if (!subnet)
600 for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
601 if (add_resource_record(header, limit, &trunc, offset, &ansp,
602 daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
604 if (ns)
605 anscount++;
606 else
607 authcount++;
611 if (axfr)
613 for (rec = daemon->mxnames; rec; rec = rec->next)
614 if (in_zone(zone, rec->name, &cut))
616 if (cut)
617 *cut = 0;
619 if (rec->issrv)
621 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
622 NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
623 rec->priority, rec->weight, rec->srvport, rec->target))
625 anscount++;
627 else
629 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
630 NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
631 anscount++;
634 /* restore config data */
635 if (cut)
636 *cut = '.';
639 for (txt = daemon->rr; txt; txt = txt->next)
640 if (in_zone(zone, txt->name, &cut))
642 if (cut)
643 *cut = 0;
645 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
646 NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
647 anscount++;
649 /* restore config data */
650 if (cut)
651 *cut = '.';
654 for (txt = daemon->txt; txt; txt = txt->next)
655 if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
657 if (cut)
658 *cut = 0;
660 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
661 NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
662 anscount++;
664 /* restore config data */
665 if (cut)
666 *cut = '.';
669 for (na = daemon->naptr; na; na = na->next)
670 if (in_zone(zone, na->name, &cut))
672 if (cut)
673 *cut = 0;
675 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
676 NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
677 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
678 anscount++;
680 /* restore config data */
681 if (cut)
682 *cut = '.';
685 for (intr = daemon->int_names; intr; intr = intr->next)
686 if (in_zone(zone, intr->name, &cut))
688 struct addrlist *addrlist;
690 if (cut)
691 *cut = 0;
693 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
694 if (!(addrlist->flags & ADDRLIST_IPV6) &&
695 (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
696 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
697 daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
698 anscount++;
700 #ifdef HAVE_IPV6
701 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
702 if ((addrlist->flags & ADDRLIST_IPV6) &&
703 (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
704 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
705 daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
706 anscount++;
707 #endif
709 /* restore config data */
710 if (cut)
711 *cut = '.';
714 for (a = daemon->cnames; a; a = a->next)
715 if (in_zone(zone, a->alias, &cut))
717 strcpy(name, a->target);
718 if (!strchr(name, '.'))
720 strcat(name, ".");
721 strcat(name, zone->domain);
724 if (cut)
725 *cut = 0;
727 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
728 daemon->auth_ttl, NULL,
729 T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
730 anscount++;
733 cache_enumerate(1);
734 while ((crecp = cache_enumerate(0)))
736 if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
737 !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
738 (crecp->flags & F_FORWARD))
740 if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
742 char *cache_name = cache_get_name(crecp);
743 if (!strchr(cache_name, '.') &&
744 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
746 qtype = T_A;
747 #ifdef HAVE_IPV6
748 if (crecp->flags & F_IPV6)
749 qtype = T_AAAA;
750 #endif
751 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
752 daemon->auth_ttl, NULL, qtype, C_IN,
753 (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
754 anscount++;
758 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
760 strcpy(name, cache_get_name(crecp));
761 if (in_zone(zone, name, &cut) &&
762 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
764 qtype = T_A;
765 #ifdef HAVE_IPV6
766 if (crecp->flags & F_IPV6)
767 qtype = T_AAAA;
768 #endif
769 if (cut)
770 *cut = 0;
772 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
773 daemon->auth_ttl, NULL, qtype, C_IN,
774 (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
775 anscount++;
781 /* repeat SOA as last record */
782 if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
783 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
784 daemon->authserver, daemon->hostmaster,
785 daemon->soa_sn, daemon->soa_refresh,
786 daemon->soa_retry, daemon->soa_expiry,
787 daemon->auth_ttl))
788 anscount++;
794 /* done all questions, set up header and return length of result */
795 /* clear authoritative and truncated flags, set QR flag */
796 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
798 if (local_query)
800 /* set RA flag */
801 header->hb4 |= HB4_RA;
803 else
805 /* clear RA flag */
806 header->hb4 &= ~HB4_RA;
809 /* authoritive */
810 if (auth)
811 header->hb3 |= HB3_AA;
813 /* truncation */
814 if (trunc)
815 header->hb3 |= HB3_TC;
817 if ((auth || local_query) && nxdomain)
818 SET_RCODE(header, NXDOMAIN);
819 else
820 SET_RCODE(header, NOERROR); /* no error */
821 header->ancount = htons(anscount);
822 header->nscount = htons(authcount);
823 header->arcount = htons(0);
825 /* Advertise our packet size limit in our reply */
826 if (have_pseudoheader)
827 return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
829 return ansp - (unsigned char *)header;
832 #endif