]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/auth.c
Fix crash in auth code with odd configuration.
[people/ms/dnsmasq.git] / src / auth.c
CommitLineData
aff33962 1/* dnsmasq is Copyright (c) 2000-2015 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
10cfc0dd 34 netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen));
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 143 break;
38440b20 144
19b16891
SK
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 {
38440b20 189 if (local_query || in_zone(zone, intr->name, NULL))
115ac3e4
SK
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 */
38440b20
SK
211 if (zone)
212 {
213 strcat(name, ".");
214 strcat(name, zone->domain);
215 }
4f7b304f 216 log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
8273ea5a 217 found = 1;
4f7b304f
SK
218 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
219 daemon->auth_ttl, NULL,
220 T_PTR, C_IN, "d", name))
8273ea5a 221 anscount++;
4f7b304f 222 }
38440b20 223 else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
4f7b304f 224 {
4f7b304f 225 log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
8273ea5a 226 found = 1;
4f7b304f
SK
227 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
228 daemon->auth_ttl, NULL,
229 T_PTR, C_IN, "d", name))
8273ea5a 230 anscount++;
4f7b304f
SK
231 }
232 else
233 continue;
234
235 } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
86e3b9a0 236
10068600
SK
237 if (found)
238 nxdomain = 0;
239 else
240 log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
4f7b304f
SK
241
242 continue;
243 }
244
5c0bd5b1 245 cname_restart:
4f7b304f 246 for (zone = daemon->auth_zones; zone; zone = zone->next)
b75e9363
SK
247 if (in_zone(zone, name, &cut))
248 break;
86e3b9a0
SK
249
250 if (!zone)
4f7b304f
SK
251 {
252 auth = 0;
253 continue;
254 }
255
8273ea5a
SK
256 for (rec = daemon->mxnames; rec; rec = rec->next)
257 if (!rec->issrv && hostname_isequal(name, rec->name))
86e3b9a0
SK
258 {
259 nxdomain = 0;
260
261 if (qtype == T_MX)
262 {
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++;
268 }
269 }
270
271 for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
272 if (rec->issrv && hostname_isequal(name, rec->name))
273 {
274 nxdomain = 0;
275
276 if (qtype == T_SRV)
277 {
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))
4f7b304f 283
86e3b9a0
SK
284 anscount++;
285 }
286
287 /* unlink first SRV record found */
288 if (!move)
289 {
290 move = rec;
291 *up = rec->next;
292 }
293 else
294 up = &rec->next;
295 }
296 else
297 up = &rec->next;
298
299 /* put first SRV record back at the end. */
300 if (move)
4f7b304f 301 {
86e3b9a0
SK
302 *up = move;
303 move->next = NULL;
8273ea5a 304 }
86e3b9a0
SK
305
306 for (txt = daemon->rr; txt; txt = txt->next)
307 if (hostname_isequal(name, txt->name))
308 {
309 nxdomain = 0;
310 if (txt->class == qtype)
311 {
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++;
317 }
318 }
8273ea5a 319
86e3b9a0
SK
320 for (txt = daemon->txt; txt; txt = txt->next)
321 if (txt->class == C_IN && hostname_isequal(name, txt->name))
322 {
323 nxdomain = 0;
324 if (qtype == T_TXT)
325 {
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++;
331 }
332 }
333
334 for (na = daemon->naptr; na; na = na->next)
335 if (hostname_isequal(name, na->name))
336 {
337 nxdomain = 0;
338 if (qtype == T_NAPTR)
339 {
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++;
346 }
347 }
115ac3e4
SK
348
349 if (qtype == T_A)
350 flag = F_IPV4;
351
352#ifdef HAVE_IPV6
353 if (qtype == T_AAAA)
354 flag = F_IPV6;
355#endif
356
8ab91e9f
SK
357 for (intr = daemon->int_names; intr; intr = intr->next)
358 if (hostname_isequal(name, intr->name))
359 {
360 struct addrlist *addrlist;
361
8ab91e9f
SK
362 nxdomain = 0;
363
364 if (flag)
376d48c7
SK
365 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
366 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
367 (local_query || filter_zone(zone, flag, &addrlist->addr)))
fb63dd13 368 {
47669367
SK
369#ifdef HAVE_IPV6
370 if (addrlist->flags & ADDRLIST_REVONLY)
371 continue;
372#endif
fb63dd13
SK
373 found = 1;
374 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
375 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
376 daemon->auth_ttl, NULL, qtype, C_IN,
377 qtype == T_A ? "4" : "6", &addrlist->addr))
378 anscount++;
379 }
380 }
5c0bd5b1
SK
381
382 for (a = daemon->cnames; a; a = a->next)
383 if (hostname_isequal(name, a->alias) )
384 {
385 log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
386 strcpy(name, a->target);
387 if (!strchr(name, '.'))
388 {
389 strcat(name, ".");
390 strcat(name, zone->domain);
391 }
392 found = 1;
393 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
93bafe61 394 daemon->auth_ttl, &nameoffset,
5c0bd5b1
SK
395 T_CNAME, C_IN, "d", name))
396 anscount++;
397
398 goto cname_restart;
399 }
86e3b9a0 400
e1ff419c 401 if (!cut)
8273ea5a 402 {
e1ff419c
SK
403 nxdomain = 0;
404
405 if (qtype == T_SOA)
406 {
5f8002fc 407 auth = soa = 1; /* inhibits auth section */
e1ff419c
SK
408 found = 1;
409 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
410 }
411 else if (qtype == T_AXFR)
412 {
c6cb7407
SK
413 struct iname *peers;
414
415 if (peer_addr->sa.sa_family == AF_INET)
416 peer_addr->in.sin_port = 0;
417#ifdef HAVE_IPV6
418 else
39341559
SK
419 {
420 peer_addr->in6.sin6_port = 0;
421 peer_addr->in6.sin6_scope_id = 0;
422 }
c6cb7407
SK
423#endif
424
425 for (peers = daemon->auth_peers; peers; peers = peers->next)
426 if (sockaddr_isequal(peer_addr, &peers->addr))
427 break;
428
429 /* Refuse all AXFR unless --auth-sec-servers is set */
430 if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
49678767 431 {
49678767 432 if (peer_addr->sa.sa_family == AF_INET)
c6cb7407 433 inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
49678767
SK
434#ifdef HAVE_IPV6
435 else
c6cb7407 436 inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
49678767
SK
437#endif
438
c6cb7407
SK
439 my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
440 return 0;
49678767 441 }
c6cb7407 442
5f8002fc 443 auth = 1;
e1ff419c
SK
444 soa = 1; /* inhibits auth section */
445 ns = 1; /* ensure we include NS records! */
446 axfr = 1;
447 found = 1;
448 axfroffset = nameoffset;
449 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
450 }
451 else if (qtype == T_NS)
452 {
5f8002fc 453 auth = 1;
e1ff419c
SK
454 ns = 1; /* inhibits auth section */
455 found = 1;
456 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
457 }
4f7b304f 458 }
8273ea5a 459
b75e9363 460 if (!option_bool(OPT_DHCP_FQDN) && cut)
4f7b304f 461 {
b75e9363 462 *cut = 0; /* remove domain part */
4f7b304f 463
5c0bd5b1 464 if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
4f7b304f
SK
465 {
466 if (crecp->flags & F_DHCP)
467 do
468 {
469 nxdomain = 0;
60225f4e 470 if ((crecp->flags & flag) &&
376d48c7 471 (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
4f7b304f 472 {
b75e9363 473 *cut = '.'; /* restore domain part */
4f7b304f 474 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
b75e9363 475 *cut = 0; /* remove domain part */
8273ea5a 476 found = 1;
4f7b304f
SK
477 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
478 daemon->auth_ttl, NULL, qtype, C_IN,
479 qtype == T_A ? "4" : "6", &crecp->addr))
8273ea5a 480 anscount++;
4f7b304f
SK
481 }
482 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
483 }
484
b75e9363 485 *cut = '.'; /* restore domain part */
4f7b304f
SK
486 }
487
86e3b9a0 488 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
4f7b304f
SK
489 {
490 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
491 do
492 {
493 nxdomain = 0;
376d48c7 494 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
4f7b304f
SK
495 {
496 log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
8273ea5a 497 found = 1;
4f7b304f
SK
498 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
499 daemon->auth_ttl, NULL, qtype, C_IN,
500 qtype == T_A ? "4" : "6", &crecp->addr))
8273ea5a 501 anscount++;
4f7b304f
SK
502 }
503 } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
504 }
8273ea5a 505
4f7b304f
SK
506 if (!found)
507 log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
8273ea5a 508
4f7b304f 509 }
45dd1fec 510
4f7b304f 511 /* Add auth section */
aa67fe7a 512 if (auth && zone)
4f7b304f 513 {
b75e9363 514 char *authname;
e1ff419c
SK
515 int newoffset, offset = 0;
516
45dd1fec 517 if (!subnet)
b75e9363 518 authname = zone->domain;
45dd1fec
SK
519 else
520 {
521 /* handle NS and SOA for PTR records */
b75e9363
SK
522
523 authname = name;
524
376d48c7 525 if (!(subnet->flags & ADDRLIST_IPV6))
45dd1fec 526 {
376d48c7 527 in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
45dd1fec
SK
528 char *p = name;
529
baa80ae5 530 if (subnet->prefixlen >= 24)
45dd1fec
SK
531 p += sprintf(p, "%d.", a & 0xff);
532 a = a >> 8;
baa80ae5 533 if (subnet->prefixlen >= 16 )
45dd1fec
SK
534 p += sprintf(p, "%d.", a & 0xff);
535 a = a >> 8;
536 p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
537
538 }
539#ifdef HAVE_IPV6
540 else
541 {
542 char *p = name;
543 int i;
544
545 for (i = subnet->prefixlen-1; i >= 0; i -= 4)
546 {
376d48c7 547 int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3];
45dd1fec
SK
548 p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
549 }
550 p += sprintf(p, "ip6.arpa");
551
552 }
553#endif
554 }
555
556 /* handle NS and SOA in auth section or for explicit queries */
e1ff419c
SK
557 newoffset = ansp - (unsigned char *)header;
558 if (((anscount == 0 && !ns) || soa) &&
45dd1fec
SK
559 add_resource_record(header, limit, &trunc, 0, &ansp,
560 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
b75e9363 561 authname, daemon->authserver, daemon->hostmaster,
45dd1fec
SK
562 daemon->soa_sn, daemon->soa_refresh,
563 daemon->soa_retry, daemon->soa_expiry,
564 daemon->auth_ttl))
565 {
e1ff419c 566 offset = newoffset;
45dd1fec
SK
567 if (soa)
568 anscount++;
569 else
570 authcount++;
571 }
e1ff419c
SK
572
573 if (anscount != 0 || ns)
574 {
575 struct name_list *secondary;
576
577 newoffset = ansp - (unsigned char *)header;
578 if (add_resource_record(header, limit, &trunc, -offset, &ansp,
579 daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
580 {
581 if (offset == 0)
582 offset = newoffset;
583 if (ns)
584 anscount++;
585 else
586 authcount++;
587 }
b75e9363 588
e1ff419c
SK
589 if (!subnet)
590 for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
591 if (add_resource_record(header, limit, &trunc, offset, &ansp,
592 daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
593 {
594 if (ns)
595 anscount++;
596 else
597 authcount++;
598 }
599 }
600
b75e9363
SK
601 if (axfr)
602 {
e1ff419c
SK
603 for (rec = daemon->mxnames; rec; rec = rec->next)
604 if (in_zone(zone, rec->name, &cut))
605 {
606 if (cut)
607 *cut = 0;
608
609 if (rec->issrv)
610 {
611 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
612 NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
613 rec->priority, rec->weight, rec->srvport, rec->target))
614
615 anscount++;
616 }
617 else
618 {
619 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
620 NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
621 anscount++;
622 }
623
624 /* restore config data */
625 if (cut)
626 *cut = '.';
627 }
628
629 for (txt = daemon->rr; txt; txt = txt->next)
630 if (in_zone(zone, txt->name, &cut))
631 {
632 if (cut)
633 *cut = 0;
634
635 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
636 NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
637 anscount++;
638
639 /* restore config data */
640 if (cut)
641 *cut = '.';
642 }
643
644 for (txt = daemon->txt; txt; txt = txt->next)
645 if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
646 {
647 if (cut)
648 *cut = 0;
649
650 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
651 NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
652 anscount++;
653
654 /* restore config data */
655 if (cut)
656 *cut = '.';
657 }
658
659 for (na = daemon->naptr; na; na = na->next)
660 if (in_zone(zone, na->name, &cut))
661 {
662 if (cut)
663 *cut = 0;
664
665 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
666 NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
667 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
668 anscount++;
669
670 /* restore config data */
671 if (cut)
672 *cut = '.';
673 }
674
675 for (intr = daemon->int_names; intr; intr = intr->next)
115ac3e4 676 if (in_zone(zone, intr->name, &cut))
e1ff419c 677 {
115ac3e4
SK
678 struct addrlist *addrlist;
679
e1ff419c
SK
680 if (cut)
681 *cut = 0;
682
376d48c7 683 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
587ad4f2
SK
684 if (!(addrlist->flags & ADDRLIST_IPV6) &&
685 (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
115ac3e4
SK
686 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
687 daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
688 anscount++;
689
690#ifdef HAVE_IPV6
376d48c7 691 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
587ad4f2
SK
692 if ((addrlist->flags & ADDRLIST_IPV6) &&
693 (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
115ac3e4
SK
694 add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
695 daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
696 anscount++;
697#endif
e1ff419c
SK
698
699 /* restore config data */
700 if (cut)
701 *cut = '.';
702 }
115ac3e4 703
e1ff419c
SK
704 for (a = daemon->cnames; a; a = a->next)
705 if (in_zone(zone, a->alias, &cut))
706 {
707 strcpy(name, a->target);
708 if (!strchr(name, '.'))
709 {
710 strcat(name, ".");
711 strcat(name, zone->domain);
712 }
713
714 if (cut)
715 *cut = 0;
716
717 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
718 daemon->auth_ttl, NULL,
719 T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
720 anscount++;
721 }
722
b75e9363
SK
723 cache_enumerate(1);
724 while ((crecp = cache_enumerate(0)))
725 {
726 if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
727 !(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
728 (crecp->flags & F_FORWARD))
729 {
730 if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
731 {
732 char *cache_name = cache_get_name(crecp);
19b16891 733 if (!strchr(cache_name, '.') &&
376d48c7 734 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
b75e9363
SK
735 {
736 qtype = T_A;
737#ifdef HAVE_IPV6
738 if (crecp->flags & F_IPV6)
739 qtype = T_AAAA;
740#endif
741 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
742 daemon->auth_ttl, NULL, qtype, C_IN,
743 (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
744 anscount++;
745 }
746 }
747
748 if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
749 {
750 strcpy(name, cache_get_name(crecp));
19b16891 751 if (in_zone(zone, name, &cut) &&
376d48c7 752 (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
b75e9363
SK
753 {
754 qtype = T_A;
755#ifdef HAVE_IPV6
756 if (crecp->flags & F_IPV6)
757 qtype = T_AAAA;
758#endif
759 if (cut)
e1ff419c
SK
760 *cut = 0;
761
762 if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
763 daemon->auth_ttl, NULL, qtype, C_IN,
764 (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
765 anscount++;
b75e9363
SK
766 }
767 }
768 }
769 }
770
771 /* repeat SOA as last record */
772 if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
773 daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
774 daemon->authserver, daemon->hostmaster,
775 daemon->soa_sn, daemon->soa_refresh,
776 daemon->soa_retry, daemon->soa_expiry,
777 daemon->auth_ttl))
778 anscount++;
4c985dac 779
b75e9363 780 }
4c985dac
SK
781
782 }
45dd1fec 783
4f7b304f
SK
784 /* done all questions, set up header and return length of result */
785 /* clear authoritative and truncated flags, set QR flag */
786 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
93bafe61
SK
787
788 if (local_query)
789 {
790 /* set RA flag */
791 header->hb4 |= HB4_RA;
792 }
793 else
794 {
795 /* clear RA flag */
796 header->hb4 &= ~HB4_RA;
797 }
4f7b304f
SK
798
799 /* authoritive */
800 if (auth)
801 header->hb3 |= HB3_AA;
802
803 /* truncation */
804 if (trunc)
805 header->hb3 |= HB3_TC;
806
57310500 807 if ((auth || local_query) && nxdomain)
4f7b304f
SK
808 SET_RCODE(header, NXDOMAIN);
809 else
810 SET_RCODE(header, NOERROR); /* no error */
811 header->ancount = htons(anscount);
812 header->nscount = htons(authcount);
aa792351 813 header->arcount = htons(0);
4f7b304f
SK
814 return ansp - (unsigned char *)header;
815}
816
4820dce9 817#endif
b75e9363 818
4f7b304f
SK
819
820