]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/rfc1035.c
import of dnsmasq-2.21.tar.gz
[people/ms/dnsmasq.git] / src / rfc1035.c
CommitLineData
0a852541 1/* dnsmasq is Copyright (c) 2000 - 2005 Simon Kelley
9e4abcb5
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.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13#include "dnsmasq.h"
14
f6b7dc47
SK
15static int add_resource_record(HEADER *header, char *limit, int *truncp,
16 unsigned int nameoffset, unsigned char **pp,
17 unsigned long ttl, int *offset, unsigned short type,
18 unsigned short class, char *format, ...);
19
9e4abcb5
SK
20static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
21 unsigned char *name, int isExtract)
22{
23 unsigned char *cp = name, *p = *pp, *p1 = NULL;
24 unsigned int j, l, hops = 0;
25 int retvalue = 1;
26
f6b7dc47
SK
27 if (isExtract)
28 *cp = 0;
29
9e4abcb5
SK
30 while ((l = *p++))
31 {
32 unsigned int label_type = l & 0xc0;
33 if (label_type == 0xc0) /* pointer */
34 {
35 if (p - (unsigned char *)header + 1u >= plen)
36 return 0;
37
38 /* get offset */
39 l = (l&0x3f) << 8;
40 l |= *p++;
41 if (l >= (unsigned int)plen)
42 return 0;
43
44 if (!p1) /* first jump, save location to go back to */
45 p1 = p;
46
47 hops++; /* break malicious infinite loops */
48 if (hops > 255)
49 return 0;
50
51 p = l + (unsigned char *)header;
52 }
53 else if (label_type == 0x80)
54 return 0; /* reserved */
55 else if (label_type == 0x40)
56 { /* ELT */
57 unsigned int count, digs;
58
59 if ((l & 0x3f) != 1)
60 return 0; /* we only understand bitstrings */
61
62 if (!isExtract)
63 return 0; /* Cannot compare bitsrings */
64
65 count = *p++;
66 if (count == 0)
67 count = 256;
68 digs = ((count-1)>>2)+1;
69
70 /* output is \[x<hex>/siz]. which is digs+9 chars */
71 if (cp - name + digs + 9 >= MAXDNAME)
72 return 0;
73 if (p - (unsigned char *)header + ((count-1)>>3) + 1u >= plen)
74 return 0;
75
76 *cp++ = '\\';
77 *cp++ = '[';
78 *cp++ = 'x';
79 for (j=0; j<digs; j++)
80 {
81 unsigned int dig;
82 if (j%2 == 0)
83 dig = *p >> 4;
84 else
85 dig = *p++ & 0x0f;
86
87 *cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
88 }
89 cp += sprintf(cp, "/%d]", count);
90 /* do this here to overwrite the zero char from sprintf */
91 *cp++ = '.';
92 }
93 else
94 { /* label_type = 0 -> label. */
95 if (cp - name + l + 1 >= MAXDNAME)
96 return 0;
97 if (p - (unsigned char *)header + 1u >= plen)
98 return 0;
99 for(j=0; j<l; j++, p++)
100 if (isExtract)
101 {
102 if (legal_char(*p))
103 *cp++ = *p;
104 else
105 return 0;
106 }
107 else
108 {
109 unsigned char c1 = *cp, c2 = *p;
110
111 if (c1 == 0)
112 retvalue = 2;
113 else
114 {
115 cp++;
116 if (c1 >= 'A' && c1 <= 'Z')
117 c1 += 'a' - 'A';
118 if (c2 >= 'A' && c2 <= 'Z')
119 c2 += 'a' - 'A';
120
121 if (c1 != c2)
122 retvalue = 2;
123 }
124 }
125
126 if (isExtract)
127 *cp++ = '.';
f6b7dc47
SK
128 else if (*cp != 0 && *cp++ != '.')
129 retvalue = 2;
9e4abcb5
SK
130 }
131
132 if ((unsigned int)(p - (unsigned char *)header) >= plen)
133 return 0;
134 }
135
136 if (isExtract)
137 *--cp = 0; /* terminate: lose final period */
f6b7dc47
SK
138 else if (*cp != 0)
139 retvalue = 2;
140
9e4abcb5
SK
141 if (p1) /* we jumped via compression */
142 *pp = p1;
143 else
144 *pp = p;
145
146 return retvalue;
147}
148
149/* Max size of input string (for IPv6) is 75 chars.) */
150#define MAXARPANAME 75
151static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
152{
153 int j;
154 char name[MAXARPANAME+1], *cp1;
155 unsigned char *addr = (unsigned char *)addrp;
156 char *lastchunk = NULL, *penchunk = NULL;
157
158 if (strlen(namein) > MAXARPANAME)
159 return 0;
160
161 memset(addrp, 0, sizeof(struct all_addr));
162
163 /* turn name into a series of asciiz strings */
164 /* j counts no of labels */
165 for(j = 1,cp1 = name; *namein; cp1++, namein++)
166 if (*namein == '.')
167 {
168 penchunk = lastchunk;
169 lastchunk = cp1 + 1;
170 *cp1 = 0;
171 j++;
172 }
173 else
174 *cp1 = *namein;
175
176 *cp1 = 0;
177
178 if (j<3)
179 return 0;
180
181 if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
182 {
183 /* IP v4 */
184 /* address arives as a name of the form
185 www.xxx.yyy.zzz.in-addr.arpa
186 some of the low order address octets might be missing
187 and should be set to zero. */
188 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
189 {
190 /* check for digits only (weeds out things like
191 50.0/24.67.28.64.in-addr.arpa which are used
192 as CNAME targets according to RFC 2317 */
193 char *cp;
194 for (cp = cp1; *cp; cp++)
195 if (!isdigit((int)*cp))
196 return 0;
197
198 addr[3] = addr[2];
199 addr[2] = addr[1];
200 addr[1] = addr[0];
201 addr[0] = atoi(cp1);
202 }
203
204 return F_IPV4;
205 }
206#ifdef HAVE_IPV6
207 else if (hostname_isequal(penchunk, "ip6") &&
208 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
209 {
210 /* IP v6:
211 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
212 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
213
214 Note that most of these the various reprentations are obsolete and
215 left-over from the many DNS-for-IPv6 wars. We support all the formats
216 that we can since there is no reason not to.
217 */
218
219 if (*name == '\\' && *(name+1) == '[' &&
220 (*(name+2) == 'x' || *(name+2) == 'X'))
221 {
222 for (j = 0, cp1 = name+3; *cp1 && isxdigit(*cp1) && j < 32; cp1++, j++)
223 {
224 char xdig[2];
225 xdig[0] = *cp1;
226 xdig[1] = 0;
227 if (j%2)
228 addr[j/2] |= strtol(xdig, NULL, 16);
229 else
230 addr[j/2] = strtol(xdig, NULL, 16) << 4;
231 }
232
233 if (*cp1 == '/' && j == 32)
234 return F_IPV6;
235 }
236 else
237 {
238 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
239 {
240 if (*(cp1+1) || !isxdigit((int)*cp1))
241 return 0;
242
243 for (j = sizeof(struct all_addr)-1; j>0; j--)
244 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
245 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
246 }
247
248 return F_IPV6;
249 }
250 }
251#endif
252
253 return 0;
254}
255
feba5c1d 256static unsigned char *skip_name(unsigned char *ansp, HEADER *header, unsigned int plen)
9e4abcb5 257{
feba5c1d 258 while(1)
9e4abcb5 259 {
feba5c1d
SK
260 unsigned int label_type = (*ansp) & 0xc0;
261
262 if ((unsigned int)(ansp - (unsigned char *)header) >= plen)
263 return NULL;
264
265 if (label_type == 0xc0)
9e4abcb5 266 {
feba5c1d
SK
267 /* pointer for compression. */
268 ansp += 2;
269 break;
270 }
271 else if (label_type == 0x80)
272 return NULL; /* reserved */
273 else if (label_type == 0x40)
274 {
275 /* Extended label type */
276 unsigned int count;
9e4abcb5 277
feba5c1d
SK
278 if (((*ansp++) & 0x3f) != 1)
279 return NULL; /* we only understand bitstrings */
9e4abcb5 280
feba5c1d
SK
281 count = *(ansp++); /* Bits in bitstring */
282
283 if (count == 0) /* count == 0 means 256 bits */
284 ansp += 32;
9e4abcb5 285 else
feba5c1d
SK
286 ansp += ((count-1)>>3)+1;
287 }
288 else
289 { /* label type == 0 Bottom six bits is length */
290 unsigned int len = (*ansp++) & 0x3f;
291 if (len == 0)
292 break; /* zero length label marks the end. */
293
294 ansp += len;
9e4abcb5 295 }
feba5c1d
SK
296 }
297
298 return ansp;
299}
300
301static unsigned char *skip_questions(HEADER *header, unsigned int plen)
302{
303 int q, qdcount = ntohs(header->qdcount);
304 unsigned char *ansp = (unsigned char *)(header+1);
305
306 for (q = 0; q<qdcount; q++)
307 {
308 if (!(ansp = skip_name(ansp, header, plen)))
309 return NULL;
9e4abcb5
SK
310 ansp += 4; /* class and type */
311 }
312 if ((unsigned int)(ansp - (unsigned char *)header) > plen)
313 return NULL;
314
315 return ansp;
316}
317
fd9fa481 318static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, unsigned int plen)
feba5c1d 319{
fd9fa481 320 int i, rdlen;
36717eee 321
fd9fa481 322 for (i = 0; i < count; i++)
36717eee
SK
323 {
324 if (!(ansp = skip_name(ansp, header, plen)))
fd9fa481 325 return NULL;
36717eee
SK
326 ansp += 8; /* type, class, TTL */
327 GETSHORT(rdlen, ansp);
328 if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
fd9fa481 329 return NULL;
36717eee
SK
330 ansp += rdlen;
331 }
332
fd9fa481
SK
333 return ansp;
334}
335
0a852541
SK
336/* CRC the question section. This is used to safely detect query
337 retransmision and to detect answers to questions we didn't ask, which
338 might be poisoning attacks. Note that we decode the name rather
339 than CRC the raw bytes, since replies might be compressed differently.
340 We ignore case in the names for the same reason. */
341unsigned int questions_crc(HEADER *header, unsigned int plen, char *name)
fd9fa481 342{
0a852541
SK
343 unsigned int q, crc = 0xffffffff;
344 unsigned char *p1, *p = (unsigned char *)(header+1);
345
346 for (q = 0; q < ntohs(header->qdcount); q++)
347 {
348 if (!extract_name(header, plen, &p, name, 1))
349 return crc; /* bad packet */
350
351 for (p1 = name; *p1; p1++)
352 {
353 int i = 8;
354 char c = *p1;
355
356 if (c >= 'A' && c <= 'Z')
357 c += 'a' - 'A';
358
359 crc ^= c << 24;
360 while (i--)
361 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
362 }
363
364 /* CRC the class and type as well */
365 for (p1 = p; p1 < p+4; p1++)
366 {
367 int i = 8;
368 crc ^= *p1 << 24;
369 while (i--)
370 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
371 }
372
373 p += 4;
374 if ((unsigned int)(p - (unsigned char *)header) > plen)
375 return crc; /* bad packet */
376 }
fd9fa481 377
fd9fa481
SK
378 return crc;
379}
380
381
382int resize_packet(HEADER *header, unsigned int plen, unsigned char *pheader, unsigned int hlen)
383{
384 unsigned char *ansp = skip_questions(header, plen);
385
386 if (!ansp)
387 return 0;
388
389 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
390 header, plen)))
391 return 0;
392
36717eee
SK
393 /* restore pseudoheader */
394 if (pheader && ntohs(header->arcount) == 0)
395 {
396 /* must use memmove, may overlap */
397 memmove(ansp, pheader, hlen);
398 header->arcount = htons(1);
399 ansp += hlen;
400 }
401
402 return ansp - (unsigned char *)header;
403}
404
405unsigned char *find_pseudoheader(HEADER *header, unsigned int plen, unsigned int *len, unsigned char **p)
406{
407 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
408 also return length of pseudoheader in *len and pointer to the UDP size in *p */
feba5c1d
SK
409
410 int i, arcount = ntohs(header->arcount);
411 unsigned char *ansp;
412 unsigned short rdlen, type;
413
414 if (arcount == 0 || !(ansp = skip_questions(header, plen)))
415 return NULL;
416
fd9fa481
SK
417 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
418 return NULL;
419
feba5c1d
SK
420 for (i = 0; i < arcount; i++)
421 {
36717eee 422 unsigned char *save, *start = ansp;
feba5c1d
SK
423 if (!(ansp = skip_name(ansp, header, plen)))
424 return NULL;
425
426 GETSHORT(type, ansp);
427 save = ansp;
428 ansp += 6; /* class, TTL */
429 GETSHORT(rdlen, ansp);
430 if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
431 return NULL;
36717eee
SK
432 ansp += rdlen;
433 if (type == T_OPT)
434 {
435 if (len)
436 *len = ansp - start;
437 if (p)
438 *p = save;
439 return start;
440 }
feba5c1d
SK
441 }
442
443 return NULL;
444}
445
446
9e4abcb5
SK
447/* is addr in the non-globally-routed IP space? */
448static int private_net(struct all_addr *addrp)
449{
450 struct in_addr addr = *(struct in_addr *)addrp;
451 if (inet_netof(addr) == 0xA ||
452 (inet_netof(addr) >= 0xAC10 && inet_netof(addr) < 0xAC20) ||
453 (inet_netof(addr) >> 8) == 0xC0A8)
454 return 1;
455 else
456 return 0;
457}
458
fd9fa481
SK
459static void dns_doctor(HEADER *header, struct doctor *doctor, struct in_addr *addr)
460{
461 for (; doctor; doctor = doctor->next)
462 if (is_same_net(doctor->in, *addr, doctor->mask))
463 {
464 addr->s_addr &= ~doctor->mask.s_addr;
465 addr->s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
466 /* Since we munged the data, the server it came from is no longer authoritative */
fd9fa481
SK
467 header->aa = 0;
468 break;
469 }
470}
471
0a852541 472static int find_soa(HEADER *header, struct doctor *doctor, unsigned int qlen)
9e4abcb5
SK
473{
474 unsigned char *p;
9e4abcb5 475 int qtype, qclass, rdlen;
fd9fa481
SK
476 unsigned long ttl, minttl = ULONG_MAX;
477 int i, found_soa = 0;
9e4abcb5 478
fd9fa481
SK
479 /* first move to NS section and find TTL from any SOA section */
480 if (!(p = skip_questions(header, qlen)) ||
481 !(p = skip_section(p, ntohs(header->ancount), header, qlen)))
482 return 0; /* bad packet */
9e4abcb5 483
9e4abcb5
SK
484 for (i=0; i<ntohs(header->nscount); i++)
485 {
fd9fa481
SK
486 if (!(p = skip_name(p, header, qlen)))
487 return 0; /* bad packet */
488
9e4abcb5
SK
489 GETSHORT(qtype, p);
490 GETSHORT(qclass, p);
491 GETLONG(ttl, p);
492 GETSHORT(rdlen, p);
fd9fa481 493
9e4abcb5
SK
494 if ((qclass == C_IN) && (qtype == T_SOA))
495 {
fd9fa481
SK
496 found_soa = 1;
497 if (ttl < minttl)
498 minttl = ttl;
499
9e4abcb5 500 /* MNAME */
fd9fa481
SK
501 if (!(p = skip_name(p, header, qlen)))
502 return 0;
9e4abcb5 503 /* RNAME */
fd9fa481
SK
504 if (!(p = skip_name(p, header, qlen)))
505 return 0;
506 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
507
9e4abcb5
SK
508 GETLONG(ttl, p); /* minTTL */
509 if (ttl < minttl)
510 minttl = ttl;
511 }
512 else
513 p += rdlen;
9e4abcb5 514
fd9fa481
SK
515 if ((unsigned int)(p - (unsigned char *)header) > qlen)
516 return 0; /* bad packet */
9e4abcb5 517 }
fd9fa481 518
0a852541
SK
519 if (doctor)
520 for (i=0; i<ntohs(header->arcount); i++)
521 {
522 if (!(p = skip_name(p, header, qlen)))
523 return 0; /* bad packet */
524
525 GETSHORT(qtype, p);
526 GETSHORT(qclass, p);
527 GETLONG(ttl, p);
528 GETSHORT(rdlen, p);
529
530 if ((qclass == C_IN) && (qtype == T_A))
531 dns_doctor(header, doctor, (struct in_addr *)p);
532
533 p += rdlen;
534
535 if ((unsigned int)(p - (unsigned char *)header) > qlen)
536 return 0; /* bad packet */
537 }
538
fd9fa481 539 return found_soa ? minttl : 0;
1cff166d
SK
540}
541
fd9fa481
SK
542/* Note that the following code can create CNAME chains that don't point to a real record,
543 either because of lack of memory, or lack of SOA records. These are treated by the cache code as
544 expired and cleaned out that way. */
545void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now, struct daemon *daemon)
9e4abcb5 546{
fd9fa481
SK
547 unsigned char *p, *p1, *endrr;
548 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
0a852541
SK
549 unsigned long ttl = 0;
550
9e4abcb5 551 cache_start_insert();
0a852541
SK
552
553 /* find_soa is needed for dns_doctor side-effects, so don't call it lazily if there are any. */
554 if (daemon->doctors)
555 {
556 searched_soa = 1;
557 ttl = find_soa(header, daemon->doctors, qlen);
558 }
9e4abcb5 559
fd9fa481
SK
560 /* go through the questions. */
561 p = (unsigned char *)(header+1);
9e4abcb5 562
fd9fa481 563 for (i = 0; i<ntohs(header->qdcount); i++)
9e4abcb5 564 {
fd9fa481
SK
565 int found = 0, cname_count = 5;
566 struct crec *cpp = NULL;
567 int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
0a852541 568 unsigned long cttl = ULONG_MAX, attl;
fd9fa481 569
9e4abcb5
SK
570 if (!extract_name(header, qlen, &p, name, 1))
571 return; /* bad packet */
fd9fa481 572
9e4abcb5
SK
573 GETSHORT(qtype, p);
574 GETSHORT(qclass, p);
9e4abcb5
SK
575
576 if (qclass != C_IN)
fd9fa481 577 continue;
9e4abcb5 578
fd9fa481
SK
579 /* PTRs: we chase CNAMEs here, since we have no way to
580 represent them in the cache. */
581 if (qtype == T_PTR)
582 {
9e4abcb5
SK
583 struct all_addr addr;
584 int name_encoding = in_arpa_name_2_addr(name, &addr);
fd9fa481
SK
585
586 if (!name_encoding)
587 continue;
588
589 if (!(flags & F_NXDOMAIN))
9e4abcb5 590 {
fd9fa481
SK
591 cname_loop:
592 if (!(p1 = skip_questions(header, qlen)))
593 return;
594
595 for (j = 0; j<ntohs(header->ancount); j++)
596 {
597 if (!(res = extract_name(header, qlen, &p1, name, 0)))
598 return; /* bad packet */
599
600 GETSHORT(aqtype, p1);
601 GETSHORT(aqclass, p1);
602 GETLONG(attl, p1);
603 GETSHORT(ardlen, p1);
604 endrr = p1+ardlen;
605
606 /* TTL of record is minimum of CNAMES and PTR */
607 if (attl < cttl)
608 cttl = attl;
609
610 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
611 {
612 if (!extract_name(header, qlen, &p1, name, 1))
613 return;
614
615 if (aqtype == T_CNAME)
616 {
617 if (!cname_count--)
618 return; /* looped CNAMES */
619 goto cname_loop;
620 }
621
622 cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);
623 found = 1;
624 }
625
626 p1 = endrr;
627 if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
628 return; /* bad packet */
629 }
630 }
631
632 if (!found && !(daemon->options & OPT_NO_NEG))
633 {
634 if (!searched_soa)
635 {
636 searched_soa = 1;
0a852541 637 ttl = find_soa(header, NULL, qlen);
fd9fa481
SK
638 }
639 if (ttl)
640 cache_insert(name, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
9e4abcb5
SK
641 }
642 }
fd9fa481 643 else
9e4abcb5 644 {
fd9fa481
SK
645 /* everything other than PTR */
646 struct crec *newc;
647
648 if (qtype == T_A)
649 flags |= F_IPV4;
650#ifdef HAVE_IPV6
651 else if (qtype == T_AAAA)
652 flags |= F_IPV6;
653#endif
654 else
655 continue;
656
657 if (!(flags & F_NXDOMAIN))
9e4abcb5 658 {
fd9fa481
SK
659 cname_loop1:
660 if (!(p1 = skip_questions(header, qlen)))
661 return;
9e4abcb5 662
fd9fa481 663 for (j = 0; j<ntohs(header->ancount); j++)
9e4abcb5 664 {
fd9fa481
SK
665 if (!(res = extract_name(header, qlen, &p1, name, 0)))
666 return; /* bad packet */
667
668 GETSHORT(aqtype, p1);
669 GETSHORT(aqclass, p1);
670 GETLONG(attl, p1);
671 GETSHORT(ardlen, p1);
672 endrr = p1+ardlen;
673
674 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
675 {
676 if (aqtype == T_CNAME)
677 {
678 if (!cname_count--)
679 return; /* looped CNAMES */
680 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
26128d27 681 if (newc && cpp)
fd9fa481
SK
682 {
683 cpp->addr.cname.cache = newc;
684 cpp->addr.cname.uid = newc->uid;
685 }
9e4abcb5 686
fd9fa481
SK
687 cpp = newc;
688 if (attl < cttl)
689 cttl = attl;
690
691 if (!extract_name(header, qlen, &p1, name, 1))
692 return;
693 goto cname_loop1;
694 }
695 else
696 {
697 found = 1;
698 if (aqtype == T_A)
699 dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
700 newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
26128d27 701 if (newc && cpp)
fd9fa481
SK
702 {
703 cpp->addr.cname.cache = newc;
704 cpp->addr.cname.uid = newc->uid;
705 }
706 cpp = NULL;
707 }
708 }
709
710 p1 = endrr;
711 if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
712 return; /* bad packet */
713 }
714 }
715
716 if (!found && !(daemon->options & OPT_NO_NEG))
717 {
718 if (!searched_soa)
1cff166d 719 {
fd9fa481 720 searched_soa = 1;
0a852541 721 ttl = find_soa(header, NULL, qlen);
1cff166d 722 }
fd9fa481
SK
723 /* If there's no SOA to get the TTL from, but there is a CNAME
724 pointing at this, inherit it's TTL */
725 if (ttl || cpp)
9e4abcb5 726 {
fd9fa481 727 newc = cache_insert(name, (struct all_addr *)p, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
26128d27 728 if (newc && cpp)
9e4abcb5 729 {
fd9fa481
SK
730 cpp->addr.cname.cache = newc;
731 cpp->addr.cname.uid = newc->uid;
732 }
9e4abcb5 733 }
9e4abcb5 734 }
fd9fa481 735 }
9e4abcb5 736 }
fd9fa481 737
9e4abcb5
SK
738 cache_end_insert();
739}
740
741/* If the packet holds exactly one query
742 return 1 and leave the name from the query in name. */
743
c1bb8504 744unsigned short extract_request(HEADER *header,unsigned int qlen, char *name, unsigned short *typep)
9e4abcb5
SK
745{
746 unsigned char *p = (unsigned char *)(header+1);
747 int qtype, qclass;
748
c1bb8504
SK
749 if (typep)
750 *typep = 0;
751
9e4abcb5
SK
752 if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
753 return 0; /* must be exactly one query. */
754
755 if (!extract_name(header, qlen, &p, name, 1))
756 return 0; /* bad packet */
757
758 GETSHORT(qtype, p);
759 GETSHORT(qclass, p);
760
0a852541
SK
761 if (typep)
762 *typep = qtype;
763
9e4abcb5
SK
764 if (qclass == C_IN)
765 {
766 if (qtype == T_A)
767 return F_IPV4;
768 if (qtype == T_AAAA)
769 return F_IPV6;
770 if (qtype == T_ANY)
771 return F_IPV4 | F_IPV6;
772 }
773
774 return F_QUERY;
775}
776
777
778int setup_reply(HEADER *header, unsigned int qlen,
779 struct all_addr *addrp, unsigned short flags, unsigned long ttl)
780{
781 unsigned char *p = skip_questions(header, qlen);
782
783 header->qr = 1; /* response */
784 header->aa = 0; /* authoritive */
785 header->ra = 1; /* recursion if available */
786 header->tc = 0; /* not truncated */
787 header->nscount = htons(0);
788 header->arcount = htons(0);
feba5c1d 789 header->ancount = htons(0); /* no answers unless changed below */
9e4abcb5
SK
790 if (flags == F_NEG)
791 header->rcode = SERVFAIL; /* couldn't get memory */
44a2a316 792 else if (flags == F_NOERR || flags == F_QUERY)
9e4abcb5
SK
793 header->rcode = NOERROR; /* empty domain */
794 else if (flags == F_NXDOMAIN)
795 header->rcode = NXDOMAIN;
796 else if (p && flags == F_IPV4)
797 { /* we know the address */
798 header->rcode = NOERROR;
799 header->ancount = htons(1);
800 header->aa = 1;
f6b7dc47 801 add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_A, C_IN, "4", addrp);
9e4abcb5
SK
802 }
803#ifdef HAVE_IPV6
804 else if (p && flags == F_IPV6)
805 {
806 header->rcode = NOERROR;
807 header->ancount = htons(1);
808 header->aa = 1;
f6b7dc47 809 add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
9e4abcb5
SK
810 }
811#endif
812 else /* nowhere to forward to */
813 header->rcode = REFUSED;
814
815 return p - (unsigned char *)header;
816}
36717eee
SK
817
818/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
f6b7dc47 819int check_for_local_domain(char *name, time_t now, struct daemon *daemon)
36717eee
SK
820{
821 struct crec *crecp;
0a852541
SK
822 struct mx_srv_record *mx;
823 struct txt_record *txt;
824
26128d27 825 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
36717eee
SK
826 (crecp->flags & (F_HOSTS | F_DHCP)))
827 return 1;
828
f6b7dc47 829 for (mx = daemon->mxnames; mx; mx = mx->next)
0a852541 830 if (hostname_isequal(name, mx->name))
36717eee 831 return 1;
f6b7dc47 832
0a852541
SK
833 for (txt = daemon->txt; txt; txt = txt->next)
834 if (hostname_isequal(name, txt->name))
f6b7dc47 835 return 1;
0a852541 836
36717eee
SK
837 return 0;
838}
9e4abcb5
SK
839
840/* Is the packet a reply with the answer address equal to addr?
841 If so mung is into an NXDOMAIN reply and also put that information
842 in the cache. */
843int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
844 struct bogus_addr *baddr, time_t now)
845{
846 unsigned char *p;
847 int i, qtype, qclass, rdlen;
848 unsigned long ttl;
849 struct bogus_addr *baddrp;
850
851 /* skip over questions */
852 if (!(p = skip_questions(header, qlen)))
853 return 0; /* bad packet */
854
855 for (i=0; i<ntohs(header->ancount); i++)
856 {
857 if (!extract_name(header, qlen, &p, name, 1))
858 return 0; /* bad packet */
859
860 GETSHORT(qtype, p);
861 GETSHORT(qclass, p);
862 GETLONG(ttl, p);
863 GETSHORT(rdlen, p);
864
865 if (qclass == C_IN && qtype == T_A)
866 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
867 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
868 {
fd9fa481
SK
869 /* Found a bogus address. Insert that info here, since there no SOA record
870 to get the ttl from in the normal processing */
9e4abcb5
SK
871 cache_start_insert();
872 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
873 cache_end_insert();
874
875 return 1;
876 }
877
878 p += rdlen;
879 }
880
881 return 0;
882}
883
f6b7dc47
SK
884static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
885 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
886{
887 va_list ap;
888 unsigned char *sav, *p = *pp;
889 int j;
890 unsigned short usval;
891 long lval;
892 char *sval;
893
894 if (truncp && *truncp)
895 return 0;
896
897 PUTSHORT(nameoffset | 0xc000, p);
898 PUTSHORT(type, p);
899 PUTSHORT(class, p);
900 PUTLONG(ttl, p); /* TTL */
901
902 sav = p; /* Save pointer to RDLength field */
903 PUTSHORT(0, p); /* Placeholder RDLength */
904
905 va_start(ap, format); /* make ap point to 1st unamed argument */
906
907 for (; *format; format++)
908 switch (*format)
909 {
910#ifdef HAVE_IPV6
911 case '6':
912 sval = va_arg(ap, char *);
913 memcpy(p, sval, IN6ADDRSZ);
914 p += IN6ADDRSZ;
915 break;
916#endif
917
918 case '4':
919 sval = va_arg(ap, char *);
920 memcpy(p, sval, INADDRSZ);
921 p += INADDRSZ;
922 break;
923
924 case 's':
925 usval = va_arg(ap, int);
926 PUTSHORT(usval, p);
927 break;
928
929 case 'l':
930 lval = va_arg(ap, long);
931 PUTLONG(lval, p);
932 break;
933
934 case 'd':
935 /* get domain-name answer arg and store it in RDATA field */
0a852541
SK
936 if (offset)
937 *offset = p - (unsigned char *)header;
f6b7dc47
SK
938 sval = va_arg(ap, char *);
939 while (sval && *sval)
940 {
941 unsigned char *cp = p++;
942 for (j = 0; *sval && (*sval != '.'); sval++, j++)
943 *p++ = *sval;
944 *cp = j;
945 if (*sval)
946 sval++;
947 }
948 *p++ = 0;
949 break;
950
951 case 't':
0a852541 952 usval = va_arg(ap, int);
f6b7dc47 953 sval = va_arg(ap, char *);
0a852541
SK
954 memcpy(p, sval, usval);
955 p += usval;
f6b7dc47
SK
956 break;
957 }
958
959 va_end(ap); /* clean up variable argument pointer */
960
961 j = p - sav - 2;
962 PUTSHORT(j, sav); /* Now, store real RDLength */
963
f6b7dc47
SK
964 /* check for overflow of buffer */
965 if (limit && ((unsigned char *)limit - p) < 0)
966 {
967 if (truncp)
968 *truncp = 1;
969 return 0;
970 }
971
972 *pp = p;
973 return 1;
974}
975
9e4abcb5 976/* return zero if we can't answer from cache, or packet size if we can */
f6b7dc47
SK
977int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon,
978 struct in_addr local_addr, struct in_addr local_netmask, time_t now)
9e4abcb5 979{
3be34541 980 char *name = daemon->namebuff;
feba5c1d 981 unsigned char *p, *ansp, *pheader;
9e4abcb5
SK
982 int qtype, qclass, is_arpa;
983 struct all_addr addr;
984 unsigned int nameoffset;
feba5c1d
SK
985 unsigned short flag;
986 int qdcount = ntohs(header->qdcount);
0a852541 987 int q, ans, anscount = 0, addncount = 0;
feba5c1d 988 int dryrun = 0, sec_reqd = 0;
9e4abcb5 989 struct crec *crecp;
f6b7dc47 990 int nxdomain = 0, auth = 1, trunc = 0;
0a852541
SK
991 struct mx_srv_record *rec;
992
9e4abcb5
SK
993 if (!qdcount || header->opcode != QUERY )
994 return 0;
995
feba5c1d
SK
996 /* If there is an RFC2671 pseudoheader then it will be overwritten by
997 partial replies, so we have to do a dry run to see if we can answer
998 the query. We check to see if the do bit is set, if so we always
999 forward rather than answering from the cache, which doesn't include
1000 security information. */
1001
36717eee 1002 if (find_pseudoheader(header, qlen, NULL, &pheader))
feba5c1d
SK
1003 {
1004 unsigned short udpsz, ext_rcode, flags;
1005 unsigned char *psave = pheader;
1006
1007 GETSHORT(udpsz, pheader);
1008 GETSHORT(ext_rcode, pheader);
1009 GETSHORT(flags, pheader);
1010
1011 sec_reqd = flags & 0x8000; /* do bit */
1012
1013 /* If our client is advertising a larger UDP packet size
1014 than we allow, trim it so that we don't get an overlarge
1015 response from upstream */
1016
3be34541
SK
1017 if (udpsz > daemon->edns_pktsz)
1018 PUTSHORT(daemon->edns_pktsz, psave);
feba5c1d
SK
1019
1020 dryrun = 1;
1021 }
1022
0a852541
SK
1023 for (rec = daemon->mxnames; rec; rec = rec->next)
1024 rec->offset = 0;
1025
feba5c1d 1026 rerun:
9e4abcb5
SK
1027 /* determine end of question section (we put answers there) */
1028 if (!(ansp = skip_questions(header, qlen)))
1029 return 0; /* bad packet */
1030
1031 /* now process each question, answers go in RRs after the question */
1032 p = (unsigned char *)(header+1);
feba5c1d 1033
9e4abcb5
SK
1034 for (q=0; q<qdcount; q++)
1035 {
1036 /* save pointer to name for copying into answers */
1037 nameoffset = p - (unsigned char *)header;
1038
1039 /* now extract name as .-concatenated string into name */
1040 if (!extract_name(header, qlen, &p, name, 1))
1041 return 0; /* bad packet */
1042
1043 /* see if it's w.z.y.z.in-addr.arpa format */
1044
1045 is_arpa = in_arpa_name_2_addr(name, &addr);
1046
1047 GETSHORT(qtype, p);
1048 GETSHORT(qclass, p);
1049
1050 ans = 0; /* have we answered this question */
1051
0a852541 1052 if (qtype == T_TXT || qtype == T_ANY)
9e4abcb5 1053 {
0a852541
SK
1054 struct txt_record *t;
1055 for(t = daemon->txt; t ; t = t->next)
9e4abcb5 1056 {
0a852541
SK
1057 if (t->class == qclass && hostname_isequal(name, t->name))
1058 {
1059 ans = 1;
1060 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
1061 if (!dryrun &&
1062 add_resource_record(header, limit, &trunc, nameoffset, &ansp, 0, NULL,
1063 T_TXT, t->class, "t", t->len, t->txt))
1064 anscount++;
1065 }
9e4abcb5 1066 }
0a852541 1067 }
f6b7dc47 1068
0a852541 1069 if (qclass == C_IN)
9e4abcb5 1070 {
f6b7dc47 1071 if (qtype == T_PTR || qtype == T_ANY)
c1bb8504 1072 {
f6b7dc47
SK
1073 if (!(crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
1074 {
1075 if (is_arpa == F_IPV4 && (daemon->options & OPT_BOGUSPRIV) && private_net(&addr))
1076 {
1077 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1078 ans = 1;
1079 nxdomain = 1;
1080 if (!dryrun)
1081 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0, NULL, 0);
9e4abcb5 1082 }
9e4abcb5 1083 }
f6b7dc47
SK
1084 else do
1085 {
1086 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1087 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1088 continue;
1089
1090 if (crecp->flags & F_NEG)
feba5c1d 1091 {
f6b7dc47
SK
1092 ans = 1;
1093 auth = 0;
1094 if (crecp->flags & F_NXDOMAIN)
1095 nxdomain = 1;
1096 if (!dryrun)
1097 log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
1098 }
1099 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
1100 {
1101 ans = 1;
1102 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1103 auth = 0;
1104 if (!dryrun)
1105 {
1106 unsigned long ttl;
1107 /* Return 0 ttl for DHCP entries, which might change
1108 before the lease expires. */
1109 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1110 ttl = daemon->local_ttl;
1111 else
1112 ttl = crecp->ttd - now;
1113
1114 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1115 0, daemon->addn_hosts, crecp->uid);
1116
1117 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
1118 T_PTR, C_IN, "d", cache_get_name(crecp)))
1119 anscount++;
1120 }
1121 }
1122 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1123 }
1124
1125 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1126 {
1127 unsigned short type = T_A;
1128
1129 if (flag == F_IPV6)
feba5c1d 1130#ifdef HAVE_IPV6
f6b7dc47 1131 type = T_AAAA;
feba5c1d 1132#else
f6b7dc47 1133 break;
feba5c1d 1134#endif
f6b7dc47
SK
1135
1136 if (qtype != type && qtype != T_ANY)
1137 continue;
1138
1139 cname_restart:
1140 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
1141 {
1142 int localise = 0;
feba5c1d 1143
f6b7dc47
SK
1144 /* See if a putative address is on the network from which we recieved
1145 the query, is so we'll filter other answers. */
1146 if (local_addr.s_addr != 0 && (daemon->options & OPT_LOCALISE) && flag == F_IPV4)
1147 {
1148 struct crec *save = crecp;
1149 do {
1150 if ((crecp->flags & F_HOSTS) &&
1151 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1152 {
1153 localise = 1;
1154 break;
1155 }
1156 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1157 crecp = save;
1158 }
1159
1160 do
9e4abcb5 1161 {
26128d27
SK
1162 /* don't answer wildcard queries with data not from /etc/hosts
1163 or DHCP leases */
1164 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1165 break;
1166
fd9fa481
SK
1167 if (crecp->flags & F_CNAME)
1168 {
fd9fa481
SK
1169 if (!dryrun)
1170 {
fd9fa481 1171 log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
f6b7dc47
SK
1172 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
1173 T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
1174 anscount++;
fd9fa481 1175 }
f6b7dc47 1176
fd9fa481
SK
1177 strcpy(name, cache_get_name(crecp->addr.cname.cache));
1178 goto cname_restart;
1179 }
f6b7dc47 1180
9e4abcb5
SK
1181 if (crecp->flags & F_NEG)
1182 {
feba5c1d 1183 ans = 1;
f6b7dc47
SK
1184 auth = 0;
1185 if (crecp->flags & F_NXDOMAIN)
1186 nxdomain = 1;
feba5c1d 1187 if (!dryrun)
f6b7dc47 1188 log_query(crecp->flags, name, NULL, 0, NULL, 0);
9e4abcb5 1189 }
feba5c1d 1190 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
9e4abcb5 1191 {
f6b7dc47
SK
1192 /* If we are returning local answers depending on network,
1193 filter here. */
1194 if (localise &&
1195 (crecp->flags & F_HOSTS) &&
1196 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1197 continue;
1198
1199 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1200 auth = 0;
1201
feba5c1d
SK
1202 ans = 1;
1203 if (!dryrun)
1204 {
1205 unsigned long ttl;
1206
1207 if (crecp->flags & (F_IMMORTAL | F_DHCP))
3be34541 1208 ttl = daemon->local_ttl;
feba5c1d
SK
1209 else
1210 ttl = crecp->ttd - now;
1211
fd9fa481
SK
1212 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
1213 0, daemon->addn_hosts, crecp->uid);
feba5c1d 1214
f6b7dc47
SK
1215 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN,
1216 type == T_A ? "4" : "6", &crecp->addr))
1217 anscount++;
feba5c1d 1218 }
9e4abcb5 1219 }
f6b7dc47 1220 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
9e4abcb5 1221 }
f6b7dc47
SK
1222 }
1223
1224 if (qtype == T_MX || qtype == T_ANY)
1225 {
1226 int found = 0;
0a852541
SK
1227 for (rec = daemon->mxnames; rec; rec = rec->next)
1228 if (!rec->issrv && hostname_isequal(name, rec->name))
f6b7dc47
SK
1229 {
1230 ans = found = 1;
1231 if (!dryrun)
feba5c1d 1232 {
0a852541 1233 int offset;
f6b7dc47 1234 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
0a852541
SK
1235 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1236 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1237 {
1238 anscount++;
1239 if (rec->target)
1240 rec->offset = offset;
1241 }
feba5c1d 1242 }
f6b7dc47
SK
1243 }
1244
1245 if (!found && (daemon->options & (OPT_SELFMX | OPT_LOCALMX)) &&
1246 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
1247 {
1248 ans = 1;
1249 if (!dryrun)
1250 {
1251 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
1252 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1253 T_MX, C_IN, "sd", 1,
1254 (daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
1255 anscount++;
9e4abcb5
SK
1256 }
1257 }
f6b7dc47
SK
1258 }
1259
1260 if (qtype == T_SRV || qtype == T_ANY)
1261 {
1262 int found = 0;
9e4abcb5 1263
0a852541
SK
1264 for (rec = daemon->mxnames; rec; rec = rec->next)
1265 if (rec->issrv && hostname_isequal(name, rec->name))
f6b7dc47
SK
1266 {
1267 found = ans = 1;
1268 if (!dryrun)
1269 {
0a852541 1270 int offset;
f6b7dc47
SK
1271 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
1272 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
0a852541
SK
1273 &offset, T_SRV, C_IN, "sssd",
1274 rec->priority, rec->weight, rec->srvport, rec->target))
1275 {
1276 anscount++;
1277 if (rec->target)
1278 rec->offset = offset;
1279 }
f6b7dc47
SK
1280 }
1281 }
feba5c1d 1282
f6b7dc47
SK
1283 if (!found && (daemon->options & OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
1284 {
1285 ans = 1;
1286 if (!dryrun)
1287 log_query(F_CONFIG | F_NEG, name, NULL, 0, NULL, 0);
1288 }
1289 }
1290
1291 if (qtype == T_MAILB)
1292 ans = 1, nxdomain = 1;
1293
1294 if (qtype == T_SOA && (daemon->options & OPT_FILTER))
1295 {
1296 ans = 1;
1297 if (!dryrun)
1298 log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
feba5c1d 1299 }
9e4abcb5 1300 }
f6b7dc47
SK
1301
1302 if (!ans)
9e4abcb5 1303 return 0; /* failed to answer a question */
feba5c1d 1304 }
f6b7dc47 1305
feba5c1d
SK
1306 if (dryrun)
1307 {
1308 dryrun = 0;
1309 goto rerun;
9e4abcb5
SK
1310 }
1311
0a852541
SK
1312 /* create an additional data section, for stuff in SRV and MX record replies. */
1313 for (rec = daemon->mxnames; rec; rec = rec->next)
1314 if (rec->offset != 0)
1315 {
1316 /* squash dupes */
1317 struct mx_srv_record *tmp;
1318 for (tmp = rec->next; tmp; tmp = tmp->next)
1319 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1320 tmp->offset = 0;
1321
1322 crecp = NULL;
1323 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1324 {
1325 unsigned long ttl;
1326#ifdef HAVE_IPV6
1327 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
1328#else
1329 int type = T_A;
1330#endif
1331 if (crecp->flags & F_NEG)
1332 continue;
1333
1334 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1335 ttl = daemon->local_ttl;
1336 else
1337 ttl = crecp->ttd - now;
1338
1339 if (add_resource_record(header, limit, NULL, rec->offset, &ansp, ttl, NULL, type, C_IN,
1340 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1341 addncount++;
1342 }
1343 }
1344
9e4abcb5
SK
1345 /* done all questions, set up header and return length of result */
1346 header->qr = 1; /* response */
1347 header->aa = auth; /* authoritive - only hosts and DHCP derived names. */
1348 header->ra = 1; /* recursion if available */
f6b7dc47 1349 header->tc = trunc; /* truncation */
9e4abcb5
SK
1350 if (anscount == 0 && nxdomain)
1351 header->rcode = NXDOMAIN;
1352 else
1353 header->rcode = NOERROR; /* no error */
1354 header->ancount = htons(anscount);
1355 header->nscount = htons(0);
0a852541 1356 header->arcount = htons(addncount);
9e4abcb5
SK
1357 return ansp - (unsigned char *)header;
1358}
1359
1360
1361
1362
1363