]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/auth.c
Add donate button to doc.html.
[people/ms/dnsmasq.git] / src / auth.c
CommitLineData
c47e3ba4 1/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
4f7b304f
SK
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
4820dce9 19#ifdef HAVE_AUTH
b75e9363 20
c50f25a3 21static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
4f7b304f 22{
376d48c7 23 struct addrlist *subnet;
4f7b304f
SK
24
25 for (subnet = zone->subnet; subnet; subnet = subnet->next)
26 {
376d48c7 27 if (!(subnet->flags & ADDRLIST_IPV6))
4f7b304f 28 {
376d48c7
SK
29 struct in_addr netmask, addr = addr_u->addr.addr4;
30
31 if (!(flag & F_IPV4))
32 continue;
4f7b304f 33
376d48c7 34 netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
4f7b304f 35
376d48c7 36 if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
45dd1fec 37 return subnet;
4f7b304f
SK
38 }
39#ifdef HAVE_IPV6
376d48c7 40 else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen))
45dd1fec 41 return subnet;
4f7b304f
SK
42#endif
43
44 }
45dd1fec 45 return NULL;
4f7b304f
SK
46}
47
c50f25a3
SK
48static 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
b485ed97 57int in_zone(struct auth_zone *zone, char *name, char **cut)
b75e9363
SK
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}
4f7b304f
SK
82
83
19b16891 84size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query)
4f7b304f
SK
85{
86 char *name = daemon->namebuff;
87 unsigned char *p, *ansp;
88 int qtype, qclass;
b75e9363 89 int nameoffset, axfroffset = 0;
4f7b304f
SK
90 int q, anscount = 0, authcount = 0;
91 struct crec *crecp;
19b16891 92 int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
4f7b304f 93 struct auth_zone *zone = NULL;
376d48c7 94 struct addrlist *subnet = NULL;
b75e9363 95 char *cut;
e1ff419c
SK
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
4f7b304f
SK
103 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
104 return 0;
6008bdbb 105
4f7b304f
SK
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 {
8273ea5a 115 unsigned short flag = 0;
4f7b304f 116 int found = 0;
e1ff419c 117
4f7b304f
SK
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)
f8abe0c5
SK
129 {
130 auth = 0;
131 continue;
132 }
b75e9363 133
4f7b304f
SK
134 if (qtype == T_PTR)
135 {
4f7b304f
SK
136 if (!(flag = in_arpa_name_2_addr(name, &addr)))
137 continue;
138
19b16891 139 if (!local_query)
4f7b304f 140 {
19b16891 141 for (zone = daemon->auth_zones; zone; zone = zone->next)
c50f25a3 142 if ((subnet = find_subnet(zone, flag, &addr)))
19b16891
SK
143 break;
144
145 if (!zone)
146 {
147 auth = 0;
148 continue;
149 }
4f7b304f 150 }
19b16891 151
115ac3e4
SK
152 intr = NULL;
153
86e3b9a0 154 if (flag == F_IPV4)
115ac3e4
SK
155 for (intr = daemon->int_names; intr; intr = intr->next)
156 {
157 struct addrlist *addrlist;
158
376d48c7
SK
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)
86e3b9a0 161 break;
115ac3e4
SK
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
376d48c7
SK
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))
115ac3e4
SK
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;
8ab91e9f 192 log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
115ac3e4
SK
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++;
86e3b9a0
SK
197 }
198 }
115ac3e4 199
4f7b304f
SK
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));
8273ea5a 214 found = 1;
4f7b304f
SK
215 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
216 daemon->auth_ttl, NULL,
217 T_PTR, C_IN, "d", name))
8273ea5a 218 anscount++;
4f7b304f 219 }
b75e9363 220 else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
4f7b304f 221 {
4f7b304f 222 log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
8273ea5a 223 found = 1;
4f7b304f
SK
224 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
225 daemon->auth_ttl, NULL,
226 T_PTR, C_IN, "d", name))
8273ea5a 227 anscount++;
4f7b304f
SK
228 }
229 else
230 continue;
231
232 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
86e3b9a0 233
10068600
SK
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);
4f7b304f
SK
238
239 continue;
240 }
241
5c0bd5b1 242 cname_restart:
4f7b304f 243 for (zone = daemon->auth_zones; zone; zone = zone->next)
b75e9363
SK
244 if (in_zone(zone, name, &cut))
245 break;
86e3b9a0
SK
246
247 if (!zone)
4f7b304f
SK
248 {
249 auth = 0;
250 continue;
251 }
252
8273ea5a
SK
253 for (rec = daemon->mxnames; rec; rec = rec->next)
254 if (!rec->issrv && hostname_isequal(name, rec->name))
86e3b9a0
SK
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))
4f7b304f 280
86e3b9a0
SK
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)
4f7b304f 298 {
86e3b9a0
SK
299 *up = move;
300 move->next = NULL;
8273ea5a 301 }
86e3b9a0
SK
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 }
8273ea5a 316
86e3b9a0
SK
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 }
115ac3e4
SK
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
8ab91e9f
SK
354 for (intr = daemon->int_names; intr; intr = intr->next)
355 if (hostname_isequal(name, intr->name))
356 {
357 struct addrlist *addrlist;
358
8ab91e9f
SK
359 nxdomain = 0;
360
361 if (flag)
376d48c7
SK
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)))
fb63dd13
SK
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 }
5c0bd5b1
SK
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,
93bafe61 387 daemon->auth_ttl, &nameoffset,
5c0bd5b1
SK
388 T_CNAME, C_IN, "d", name))
389 anscount++;
390
391 goto cname_restart;
392 }
86e3b9a0 393
e1ff419c 394 if (!cut)
8273ea5a 395 {
e1ff419c
SK
396 nxdomain = 0;
397
398 if (qtype == T_SOA)
399 {
5f8002fc 400 auth = soa = 1; /* inhibits auth section */
e1ff419c
SK
401 found = 1;
402 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
403 }
404 else if (qtype == T_AXFR)
405 {
c6cb7407
SK
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)
49678767 421 {
49678767 422 if (peer_addr->sa.sa_family == AF_INET)
c6cb7407 423 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
49678767
SK
424#ifdef HAVE_IPV6
425 else
c6cb7407 426 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
49678767
SK
427#endif
428
c6cb7407
SK
429 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
430 return 0;
49678767 431 }
c6cb7407 432
5f8002fc 433 auth = 1;
e1ff419c
SK
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 {
5f8002fc 443 auth = 1;
e1ff419c
SK
444 ns = 1; /* inhibits auth section */
445 found = 1;
446 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
447 }
4f7b304f 448 }
8273ea5a 449
b75e9363 450 if (!option_bool(OPT_DHCP_FQDN) && cut)
4f7b304f 451 {
b75e9363 452 *cut = 0; /* remove domain part */
4f7b304f 453
5c0bd5b1 454 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
4f7b304f
SK
455 {
456 if (crecp->flags & F_DHCP)
457 do
458 {
459 nxdomain = 0;
60225f4e 460 if ((crecp->flags & flag) &&
376d48c7 461 (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
4f7b304f 462 {
b75e9363 463 *cut = '.'; /* restore domain part */
4f7b304f 464 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
b75e9363 465 *cut = 0; /* remove domain part */
8273ea5a 466 found = 1;
4f7b304f
SK
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))
8273ea5a 470 anscount++;
4f7b304f
SK
471 }
472 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
473 }
474
b75e9363 475 *cut = '.'; /* restore domain part */
4f7b304f
SK
476 }
477
86e3b9a0 478 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
4f7b304f
SK
479 {
480 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
481 do
482 {
483 nxdomain = 0;
376d48c7 484 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
4f7b304f
SK
485 {
486 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
8273ea5a 487 found = 1;
4f7b304f
SK
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))
8273ea5a 491 anscount++;
4f7b304f
SK
492 }
493 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
494 }
8273ea5a 495
4f7b304f
SK
496 if (!found)
497 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
8273ea5a 498
4f7b304f 499 }
45dd1fec 500
4f7b304f 501 /* Add auth section */
aa67fe7a 502 if (auth && zone)
4f7b304f 503 {
b75e9363 504 char *authname;
e1ff419c
SK
505 int newoffset, offset = 0;
506
45dd1fec 507 if (!subnet)
b75e9363 508 authname = zone->domain;
45dd1fec
SK
509 else
510 {
511 /* handle NS and SOA for PTR records */
b75e9363
SK
512
513 authname = name;
514
376d48c7 515 if (!(subnet->flags & ADDRLIST_IPV6))
45dd1fec 516 {
376d48c7 517 in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
45dd1fec
SK
518 char *p = name;
519
baa80ae5 520 if (subnet->prefixlen >= 24)
45dd1fec
SK
521 p += sprintf(p, "%d.", a & 0xff);
522 a = a >> 8;
baa80ae5 523 if (subnet->prefixlen >= 16 )
45dd1fec
SK
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 {
376d48c7 537 int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3];
45dd1fec
SK
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 */
e1ff419c
SK
547 newoffset = ansp - (unsigned char *)header;
548 if (((anscount == 0 && !ns) || soa) &&
45dd1fec
SK
549 add_resource_record(header, limit, &trunc, 0, &ansp,
550 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
b75e9363 551 authname, daemon->authserver, daemon->hostmaster,
45dd1fec
SK
552 daemon->soa_sn, daemon->soa_refresh,
553 daemon->soa_retry, daemon->soa_expiry,
554 daemon->auth_ttl))
555 {
e1ff419c 556 offset = newoffset;
45dd1fec
SK
557 if (soa)
558 anscount++;
559 else
560 authcount++;
561 }
e1ff419c
SK
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 }
b75e9363 578
e1ff419c
SK
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
b75e9363
SK
591 if (axfr)
592 {
e1ff419c
SK
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)
115ac3e4 666 if (in_zone(zone, intr->name, &cut))
e1ff419c 667 {
115ac3e4
SK
668 struct addrlist *addrlist;
669
e1ff419c
SK
670 if (cut)
671 *cut = 0;
672
376d48c7 673 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
587ad4f2
SK
674 if (!(addrlist->flags & ADDRLIST_IPV6) &&
675 (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
115ac3e4
SK
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
376d48c7 681 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
587ad4f2
SK
682 if ((addrlist->flags & ADDRLIST_IPV6) &&
683 (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
115ac3e4
SK
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
e1ff419c
SK
688
689 /* restore config data */
690 if (cut)
691 *cut = '.';
692 }
115ac3e4 693
e1ff419c
SK
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
b75e9363
SK
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);
19b16891 723 if (!strchr(cache_name, '.') &&
376d48c7 724 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
b75e9363
SK
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));
19b16891 741 if (in_zone(zone, name, &cut) &&
376d48c7 742 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
b75e9363
SK
743 {
744 qtype = T_A;
745#ifdef HAVE_IPV6
746 if (crecp->flags & F_IPV6)
747 qtype = T_AAAA;
748#endif
749 if (cut)
e1ff419c
SK
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++;
b75e9363
SK
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++;
4c985dac 769
b75e9363 770 }
4c985dac
SK
771
772 }
45dd1fec 773
4f7b304f
SK
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;
93bafe61
SK
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 }
4f7b304f
SK
788
789 /* authoritive */
790 if (auth)
791 header->hb3 |= HB3_AA;
792
793 /* truncation */
794 if (trunc)
795 header->hb3 |= HB3_TC;
796
57310500 797 if ((auth || local_query) && nxdomain)
4f7b304f
SK
798 SET_RCODE(header, NXDOMAIN);
799 else
800 SET_RCODE(header, NOERROR); /* no error */
801 header->ancount = htons(anscount);
802 header->nscount = htons(authcount);
aa792351 803 header->arcount = htons(0);
4f7b304f
SK
804 return ansp - (unsigned char *)header;
805}
806
4820dce9 807#endif
b75e9363 808
4f7b304f
SK
809
810