]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/rfc1035.c
import of dnsmasq-2.22.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{
91dccd09
SK
343 int q;
344 unsigned int crc = 0xffffffff;
0a852541
SK
345 unsigned char *p1, *p = (unsigned char *)(header+1);
346
347 for (q = 0; q < ntohs(header->qdcount); q++)
348 {
349 if (!extract_name(header, plen, &p, name, 1))
350 return crc; /* bad packet */
351
352 for (p1 = name; *p1; p1++)
353 {
354 int i = 8;
355 char c = *p1;
356
357 if (c >= 'A' && c <= 'Z')
358 c += 'a' - 'A';
359
360 crc ^= c << 24;
361 while (i--)
362 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
363 }
364
365 /* CRC the class and type as well */
366 for (p1 = p; p1 < p+4; p1++)
367 {
368 int i = 8;
369 crc ^= *p1 << 24;
370 while (i--)
371 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
372 }
373
374 p += 4;
375 if ((unsigned int)(p - (unsigned char *)header) > plen)
376 return crc; /* bad packet */
377 }
fd9fa481 378
fd9fa481
SK
379 return crc;
380}
381
382
383int resize_packet(HEADER *header, unsigned int plen, unsigned char *pheader, unsigned int hlen)
384{
385 unsigned char *ansp = skip_questions(header, plen);
386
387 if (!ansp)
388 return 0;
389
390 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
391 header, plen)))
392 return 0;
393
36717eee
SK
394 /* restore pseudoheader */
395 if (pheader && ntohs(header->arcount) == 0)
396 {
397 /* must use memmove, may overlap */
398 memmove(ansp, pheader, hlen);
399 header->arcount = htons(1);
400 ansp += hlen;
401 }
402
403 return ansp - (unsigned char *)header;
404}
405
406unsigned char *find_pseudoheader(HEADER *header, unsigned int plen, unsigned int *len, unsigned char **p)
407{
408 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
409 also return length of pseudoheader in *len and pointer to the UDP size in *p */
feba5c1d
SK
410
411 int i, arcount = ntohs(header->arcount);
412 unsigned char *ansp;
413 unsigned short rdlen, type;
414
415 if (arcount == 0 || !(ansp = skip_questions(header, plen)))
416 return NULL;
417
fd9fa481
SK
418 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
419 return NULL;
420
feba5c1d
SK
421 for (i = 0; i < arcount; i++)
422 {
36717eee 423 unsigned char *save, *start = ansp;
feba5c1d
SK
424 if (!(ansp = skip_name(ansp, header, plen)))
425 return NULL;
426
427 GETSHORT(type, ansp);
428 save = ansp;
429 ansp += 6; /* class, TTL */
430 GETSHORT(rdlen, ansp);
431 if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
432 return NULL;
36717eee
SK
433 ansp += rdlen;
434 if (type == T_OPT)
435 {
436 if (len)
437 *len = ansp - start;
438 if (p)
439 *p = save;
440 return start;
441 }
feba5c1d
SK
442 }
443
444 return NULL;
445}
446
447
9e4abcb5
SK
448/* is addr in the non-globally-routed IP space? */
449static int private_net(struct all_addr *addrp)
450{
451 struct in_addr addr = *(struct in_addr *)addrp;
452 if (inet_netof(addr) == 0xA ||
453 (inet_netof(addr) >= 0xAC10 && inet_netof(addr) < 0xAC20) ||
454 (inet_netof(addr) >> 8) == 0xC0A8)
455 return 1;
456 else
457 return 0;
458}
459
fd9fa481
SK
460static void dns_doctor(HEADER *header, struct doctor *doctor, struct in_addr *addr)
461{
462 for (; doctor; doctor = doctor->next)
463 if (is_same_net(doctor->in, *addr, doctor->mask))
464 {
465 addr->s_addr &= ~doctor->mask.s_addr;
466 addr->s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
467 /* Since we munged the data, the server it came from is no longer authoritative */
fd9fa481
SK
468 header->aa = 0;
469 break;
470 }
471}
472
0a852541 473static int find_soa(HEADER *header, struct doctor *doctor, unsigned int qlen)
9e4abcb5
SK
474{
475 unsigned char *p;
9e4abcb5 476 int qtype, qclass, rdlen;
fd9fa481
SK
477 unsigned long ttl, minttl = ULONG_MAX;
478 int i, found_soa = 0;
9e4abcb5 479
fd9fa481
SK
480 /* first move to NS section and find TTL from any SOA section */
481 if (!(p = skip_questions(header, qlen)) ||
482 !(p = skip_section(p, ntohs(header->ancount), header, qlen)))
483 return 0; /* bad packet */
9e4abcb5 484
9e4abcb5
SK
485 for (i=0; i<ntohs(header->nscount); i++)
486 {
fd9fa481
SK
487 if (!(p = skip_name(p, header, qlen)))
488 return 0; /* bad packet */
489
9e4abcb5
SK
490 GETSHORT(qtype, p);
491 GETSHORT(qclass, p);
492 GETLONG(ttl, p);
493 GETSHORT(rdlen, p);
fd9fa481 494
9e4abcb5
SK
495 if ((qclass == C_IN) && (qtype == T_SOA))
496 {
fd9fa481
SK
497 found_soa = 1;
498 if (ttl < minttl)
499 minttl = ttl;
500
9e4abcb5 501 /* MNAME */
fd9fa481
SK
502 if (!(p = skip_name(p, header, qlen)))
503 return 0;
9e4abcb5 504 /* RNAME */
fd9fa481
SK
505 if (!(p = skip_name(p, header, qlen)))
506 return 0;
507 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
508
9e4abcb5
SK
509 GETLONG(ttl, p); /* minTTL */
510 if (ttl < minttl)
511 minttl = ttl;
512 }
513 else
514 p += rdlen;
9e4abcb5 515
fd9fa481
SK
516 if ((unsigned int)(p - (unsigned char *)header) > qlen)
517 return 0; /* bad packet */
9e4abcb5 518 }
fd9fa481 519
0a852541
SK
520 if (doctor)
521 for (i=0; i<ntohs(header->arcount); i++)
522 {
523 if (!(p = skip_name(p, header, qlen)))
524 return 0; /* bad packet */
525
526 GETSHORT(qtype, p);
527 GETSHORT(qclass, p);
528 GETLONG(ttl, p);
529 GETSHORT(rdlen, p);
530
531 if ((qclass == C_IN) && (qtype == T_A))
532 dns_doctor(header, doctor, (struct in_addr *)p);
533
534 p += rdlen;
535
536 if ((unsigned int)(p - (unsigned char *)header) > qlen)
537 return 0; /* bad packet */
538 }
539
fd9fa481 540 return found_soa ? minttl : 0;
1cff166d
SK
541}
542
fd9fa481
SK
543/* Note that the following code can create CNAME chains that don't point to a real record,
544 either because of lack of memory, or lack of SOA records. These are treated by the cache code as
545 expired and cleaned out that way. */
546void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now, struct daemon *daemon)
9e4abcb5 547{
fd9fa481
SK
548 unsigned char *p, *p1, *endrr;
549 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
0a852541
SK
550 unsigned long ttl = 0;
551
9e4abcb5 552 cache_start_insert();
0a852541
SK
553
554 /* find_soa is needed for dns_doctor side-effects, so don't call it lazily if there are any. */
555 if (daemon->doctors)
556 {
557 searched_soa = 1;
558 ttl = find_soa(header, daemon->doctors, qlen);
559 }
9e4abcb5 560
fd9fa481
SK
561 /* go through the questions. */
562 p = (unsigned char *)(header+1);
9e4abcb5 563
fd9fa481 564 for (i = 0; i<ntohs(header->qdcount); i++)
9e4abcb5 565 {
fd9fa481
SK
566 int found = 0, cname_count = 5;
567 struct crec *cpp = NULL;
568 int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
0a852541 569 unsigned long cttl = ULONG_MAX, attl;
fd9fa481 570
9e4abcb5
SK
571 if (!extract_name(header, qlen, &p, name, 1))
572 return; /* bad packet */
fd9fa481 573
9e4abcb5
SK
574 GETSHORT(qtype, p);
575 GETSHORT(qclass, p);
9e4abcb5
SK
576
577 if (qclass != C_IN)
fd9fa481 578 continue;
9e4abcb5 579
fd9fa481
SK
580 /* PTRs: we chase CNAMEs here, since we have no way to
581 represent them in the cache. */
582 if (qtype == T_PTR)
583 {
9e4abcb5
SK
584 struct all_addr addr;
585 int name_encoding = in_arpa_name_2_addr(name, &addr);
fd9fa481
SK
586
587 if (!name_encoding)
588 continue;
589
590 if (!(flags & F_NXDOMAIN))
9e4abcb5 591 {
fd9fa481
SK
592 cname_loop:
593 if (!(p1 = skip_questions(header, qlen)))
594 return;
595
596 for (j = 0; j<ntohs(header->ancount); j++)
597 {
598 if (!(res = extract_name(header, qlen, &p1, name, 0)))
599 return; /* bad packet */
600
601 GETSHORT(aqtype, p1);
602 GETSHORT(aqclass, p1);
603 GETLONG(attl, p1);
604 GETSHORT(ardlen, p1);
605 endrr = p1+ardlen;
606
607 /* TTL of record is minimum of CNAMES and PTR */
608 if (attl < cttl)
609 cttl = attl;
610
611 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
612 {
613 if (!extract_name(header, qlen, &p1, name, 1))
614 return;
615
616 if (aqtype == T_CNAME)
617 {
618 if (!cname_count--)
619 return; /* looped CNAMES */
620 goto cname_loop;
621 }
622
623 cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);
624 found = 1;
625 }
626
627 p1 = endrr;
628 if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
629 return; /* bad packet */
630 }
631 }
632
633 if (!found && !(daemon->options & OPT_NO_NEG))
634 {
635 if (!searched_soa)
636 {
637 searched_soa = 1;
0a852541 638 ttl = find_soa(header, NULL, qlen);
fd9fa481
SK
639 }
640 if (ttl)
641 cache_insert(name, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
9e4abcb5
SK
642 }
643 }
fd9fa481 644 else
9e4abcb5 645 {
fd9fa481
SK
646 /* everything other than PTR */
647 struct crec *newc;
648
649 if (qtype == T_A)
650 flags |= F_IPV4;
651#ifdef HAVE_IPV6
652 else if (qtype == T_AAAA)
653 flags |= F_IPV6;
654#endif
655 else
656 continue;
657
658 if (!(flags & F_NXDOMAIN))
9e4abcb5 659 {
fd9fa481
SK
660 cname_loop1:
661 if (!(p1 = skip_questions(header, qlen)))
662 return;
9e4abcb5 663
fd9fa481 664 for (j = 0; j<ntohs(header->ancount); j++)
9e4abcb5 665 {
fd9fa481
SK
666 if (!(res = extract_name(header, qlen, &p1, name, 0)))
667 return; /* bad packet */
668
669 GETSHORT(aqtype, p1);
670 GETSHORT(aqclass, p1);
671 GETLONG(attl, p1);
672 GETSHORT(ardlen, p1);
673 endrr = p1+ardlen;
674
675 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
676 {
677 if (aqtype == T_CNAME)
678 {
679 if (!cname_count--)
680 return; /* looped CNAMES */
681 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
26128d27 682 if (newc && cpp)
fd9fa481
SK
683 {
684 cpp->addr.cname.cache = newc;
685 cpp->addr.cname.uid = newc->uid;
686 }
9e4abcb5 687
fd9fa481
SK
688 cpp = newc;
689 if (attl < cttl)
690 cttl = attl;
691
692 if (!extract_name(header, qlen, &p1, name, 1))
693 return;
694 goto cname_loop1;
695 }
696 else
697 {
698 found = 1;
699 if (aqtype == T_A)
700 dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
701 newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
26128d27 702 if (newc && cpp)
fd9fa481
SK
703 {
704 cpp->addr.cname.cache = newc;
705 cpp->addr.cname.uid = newc->uid;
706 }
707 cpp = NULL;
708 }
709 }
710
711 p1 = endrr;
712 if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
713 return; /* bad packet */
714 }
715 }
716
717 if (!found && !(daemon->options & OPT_NO_NEG))
718 {
719 if (!searched_soa)
1cff166d 720 {
fd9fa481 721 searched_soa = 1;
0a852541 722 ttl = find_soa(header, NULL, qlen);
1cff166d 723 }
fd9fa481
SK
724 /* If there's no SOA to get the TTL from, but there is a CNAME
725 pointing at this, inherit it's TTL */
726 if (ttl || cpp)
9e4abcb5 727 {
fd9fa481 728 newc = cache_insert(name, (struct all_addr *)p, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
26128d27 729 if (newc && cpp)
9e4abcb5 730 {
fd9fa481
SK
731 cpp->addr.cname.cache = newc;
732 cpp->addr.cname.uid = newc->uid;
733 }
9e4abcb5 734 }
9e4abcb5 735 }
fd9fa481 736 }
9e4abcb5 737 }
fd9fa481 738
9e4abcb5
SK
739 cache_end_insert();
740}
741
742/* If the packet holds exactly one query
743 return 1 and leave the name from the query in name. */
744
c1bb8504 745unsigned short extract_request(HEADER *header,unsigned int qlen, char *name, unsigned short *typep)
9e4abcb5
SK
746{
747 unsigned char *p = (unsigned char *)(header+1);
748 int qtype, qclass;
749
c1bb8504
SK
750 if (typep)
751 *typep = 0;
752
9e4abcb5
SK
753 if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
754 return 0; /* must be exactly one query. */
755
756 if (!extract_name(header, qlen, &p, name, 1))
757 return 0; /* bad packet */
758
759 GETSHORT(qtype, p);
760 GETSHORT(qclass, p);
761
0a852541
SK
762 if (typep)
763 *typep = qtype;
764
9e4abcb5
SK
765 if (qclass == C_IN)
766 {
767 if (qtype == T_A)
768 return F_IPV4;
769 if (qtype == T_AAAA)
770 return F_IPV6;
771 if (qtype == T_ANY)
772 return F_IPV4 | F_IPV6;
773 }
774
775 return F_QUERY;
776}
777
778
779int setup_reply(HEADER *header, unsigned int qlen,
780 struct all_addr *addrp, unsigned short flags, unsigned long ttl)
781{
782 unsigned char *p = skip_questions(header, qlen);
783
784 header->qr = 1; /* response */
785 header->aa = 0; /* authoritive */
786 header->ra = 1; /* recursion if available */
787 header->tc = 0; /* not truncated */
788 header->nscount = htons(0);
789 header->arcount = htons(0);
feba5c1d 790 header->ancount = htons(0); /* no answers unless changed below */
9e4abcb5
SK
791 if (flags == F_NEG)
792 header->rcode = SERVFAIL; /* couldn't get memory */
44a2a316 793 else if (flags == F_NOERR || flags == F_QUERY)
9e4abcb5
SK
794 header->rcode = NOERROR; /* empty domain */
795 else if (flags == F_NXDOMAIN)
796 header->rcode = NXDOMAIN;
797 else if (p && flags == F_IPV4)
798 { /* we know the address */
799 header->rcode = NOERROR;
800 header->ancount = htons(1);
801 header->aa = 1;
f6b7dc47 802 add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_A, C_IN, "4", addrp);
9e4abcb5
SK
803 }
804#ifdef HAVE_IPV6
805 else if (p && flags == F_IPV6)
806 {
807 header->rcode = NOERROR;
808 header->ancount = htons(1);
809 header->aa = 1;
f6b7dc47 810 add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
9e4abcb5
SK
811 }
812#endif
813 else /* nowhere to forward to */
814 header->rcode = REFUSED;
815
816 return p - (unsigned char *)header;
817}
36717eee
SK
818
819/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
f6b7dc47 820int check_for_local_domain(char *name, time_t now, struct daemon *daemon)
36717eee
SK
821{
822 struct crec *crecp;
0a852541
SK
823 struct mx_srv_record *mx;
824 struct txt_record *txt;
825
26128d27 826 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
36717eee
SK
827 (crecp->flags & (F_HOSTS | F_DHCP)))
828 return 1;
829
f6b7dc47 830 for (mx = daemon->mxnames; mx; mx = mx->next)
0a852541 831 if (hostname_isequal(name, mx->name))
36717eee 832 return 1;
f6b7dc47 833
0a852541
SK
834 for (txt = daemon->txt; txt; txt = txt->next)
835 if (hostname_isequal(name, txt->name))
f6b7dc47 836 return 1;
0a852541 837
36717eee
SK
838 return 0;
839}
9e4abcb5
SK
840
841/* Is the packet a reply with the answer address equal to addr?
842 If so mung is into an NXDOMAIN reply and also put that information
843 in the cache. */
844int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
845 struct bogus_addr *baddr, time_t now)
846{
847 unsigned char *p;
848 int i, qtype, qclass, rdlen;
849 unsigned long ttl;
850 struct bogus_addr *baddrp;
851
852 /* skip over questions */
853 if (!(p = skip_questions(header, qlen)))
854 return 0; /* bad packet */
855
856 for (i=0; i<ntohs(header->ancount); i++)
857 {
858 if (!extract_name(header, qlen, &p, name, 1))
859 return 0; /* bad packet */
860
861 GETSHORT(qtype, p);
862 GETSHORT(qclass, p);
863 GETLONG(ttl, p);
864 GETSHORT(rdlen, p);
865
866 if (qclass == C_IN && qtype == T_A)
867 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
868 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
869 {
fd9fa481
SK
870 /* Found a bogus address. Insert that info here, since there no SOA record
871 to get the ttl from in the normal processing */
9e4abcb5
SK
872 cache_start_insert();
873 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
874 cache_end_insert();
875
876 return 1;
877 }
878
879 p += rdlen;
880 }
881
882 return 0;
883}
884
f6b7dc47
SK
885static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
886 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
887{
888 va_list ap;
889 unsigned char *sav, *p = *pp;
890 int j;
891 unsigned short usval;
892 long lval;
893 char *sval;
894
895 if (truncp && *truncp)
896 return 0;
897
898 PUTSHORT(nameoffset | 0xc000, p);
899 PUTSHORT(type, p);
900 PUTSHORT(class, p);
901 PUTLONG(ttl, p); /* TTL */
902
903 sav = p; /* Save pointer to RDLength field */
904 PUTSHORT(0, p); /* Placeholder RDLength */
905
906 va_start(ap, format); /* make ap point to 1st unamed argument */
907
908 for (; *format; format++)
909 switch (*format)
910 {
911#ifdef HAVE_IPV6
912 case '6':
913 sval = va_arg(ap, char *);
914 memcpy(p, sval, IN6ADDRSZ);
915 p += IN6ADDRSZ;
916 break;
917#endif
918
919 case '4':
920 sval = va_arg(ap, char *);
921 memcpy(p, sval, INADDRSZ);
922 p += INADDRSZ;
923 break;
924
925 case 's':
926 usval = va_arg(ap, int);
927 PUTSHORT(usval, p);
928 break;
929
930 case 'l':
931 lval = va_arg(ap, long);
932 PUTLONG(lval, p);
933 break;
934
935 case 'd':
936 /* get domain-name answer arg and store it in RDATA field */
0a852541
SK
937 if (offset)
938 *offset = p - (unsigned char *)header;
f6b7dc47
SK
939 sval = va_arg(ap, char *);
940 while (sval && *sval)
941 {
942 unsigned char *cp = p++;
943 for (j = 0; *sval && (*sval != '.'); sval++, j++)
944 *p++ = *sval;
945 *cp = j;
946 if (*sval)
947 sval++;
948 }
949 *p++ = 0;
950 break;
951
952 case 't':
0a852541 953 usval = va_arg(ap, int);
f6b7dc47 954 sval = va_arg(ap, char *);
0a852541
SK
955 memcpy(p, sval, usval);
956 p += usval;
f6b7dc47
SK
957 break;
958 }
959
960 va_end(ap); /* clean up variable argument pointer */
961
962 j = p - sav - 2;
963 PUTSHORT(j, sav); /* Now, store real RDLength */
964
f6b7dc47
SK
965 /* check for overflow of buffer */
966 if (limit && ((unsigned char *)limit - p) < 0)
967 {
968 if (truncp)
969 *truncp = 1;
970 return 0;
971 }
972
973 *pp = p;
974 return 1;
975}
976
9e4abcb5 977/* return zero if we can't answer from cache, or packet size if we can */
f6b7dc47
SK
978int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon,
979 struct in_addr local_addr, struct in_addr local_netmask, time_t now)
9e4abcb5 980{
3be34541 981 char *name = daemon->namebuff;
feba5c1d 982 unsigned char *p, *ansp, *pheader;
9e4abcb5
SK
983 int qtype, qclass, is_arpa;
984 struct all_addr addr;
985 unsigned int nameoffset;
feba5c1d
SK
986 unsigned short flag;
987 int qdcount = ntohs(header->qdcount);
0a852541 988 int q, ans, anscount = 0, addncount = 0;
feba5c1d 989 int dryrun = 0, sec_reqd = 0;
9e4abcb5 990 struct crec *crecp;
f6b7dc47 991 int nxdomain = 0, auth = 1, trunc = 0;
0a852541
SK
992 struct mx_srv_record *rec;
993
9e4abcb5
SK
994 if (!qdcount || header->opcode != QUERY )
995 return 0;
996
feba5c1d
SK
997 /* If there is an RFC2671 pseudoheader then it will be overwritten by
998 partial replies, so we have to do a dry run to see if we can answer
999 the query. We check to see if the do bit is set, if so we always
1000 forward rather than answering from the cache, which doesn't include
1001 security information. */
1002
36717eee 1003 if (find_pseudoheader(header, qlen, NULL, &pheader))
feba5c1d
SK
1004 {
1005 unsigned short udpsz, ext_rcode, flags;
1006 unsigned char *psave = pheader;
1007
1008 GETSHORT(udpsz, pheader);
1009 GETSHORT(ext_rcode, pheader);
1010 GETSHORT(flags, pheader);
1011
1012 sec_reqd = flags & 0x8000; /* do bit */
1013
1014 /* If our client is advertising a larger UDP packet size
1015 than we allow, trim it so that we don't get an overlarge
1016 response from upstream */
1017
3be34541
SK
1018 if (udpsz > daemon->edns_pktsz)
1019 PUTSHORT(daemon->edns_pktsz, psave);
feba5c1d
SK
1020
1021 dryrun = 1;
1022 }
1023
0a852541
SK
1024 for (rec = daemon->mxnames; rec; rec = rec->next)
1025 rec->offset = 0;
1026
feba5c1d 1027 rerun:
9e4abcb5
SK
1028 /* determine end of question section (we put answers there) */
1029 if (!(ansp = skip_questions(header, qlen)))
1030 return 0; /* bad packet */
1031
1032 /* now process each question, answers go in RRs after the question */
1033 p = (unsigned char *)(header+1);
feba5c1d 1034
9e4abcb5
SK
1035 for (q=0; q<qdcount; q++)
1036 {
1037 /* save pointer to name for copying into answers */
1038 nameoffset = p - (unsigned char *)header;
1039
1040 /* now extract name as .-concatenated string into name */
1041 if (!extract_name(header, qlen, &p, name, 1))
1042 return 0; /* bad packet */
1043
1044 /* see if it's w.z.y.z.in-addr.arpa format */
1045
1046 is_arpa = in_arpa_name_2_addr(name, &addr);
1047
1048 GETSHORT(qtype, p);
1049 GETSHORT(qclass, p);
1050
1051 ans = 0; /* have we answered this question */
1052
0a852541 1053 if (qtype == T_TXT || qtype == T_ANY)
9e4abcb5 1054 {
0a852541
SK
1055 struct txt_record *t;
1056 for(t = daemon->txt; t ; t = t->next)
9e4abcb5 1057 {
0a852541
SK
1058 if (t->class == qclass && hostname_isequal(name, t->name))
1059 {
1060 ans = 1;
1061 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
1062 if (!dryrun &&
1063 add_resource_record(header, limit, &trunc, nameoffset, &ansp, 0, NULL,
1064 T_TXT, t->class, "t", t->len, t->txt))
1065 anscount++;
1066 }
9e4abcb5 1067 }
0a852541 1068 }
f6b7dc47 1069
0a852541 1070 if (qclass == C_IN)
9e4abcb5 1071 {
f6b7dc47 1072 if (qtype == T_PTR || qtype == T_ANY)
c1bb8504 1073 {
f6b7dc47
SK
1074 if (!(crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
1075 {
1076 if (is_arpa == F_IPV4 && (daemon->options & OPT_BOGUSPRIV) && private_net(&addr))
1077 {
1078 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1079 ans = 1;
1080 nxdomain = 1;
1081 if (!dryrun)
1082 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0, NULL, 0);
9e4abcb5 1083 }
9e4abcb5 1084 }
f6b7dc47
SK
1085 else do
1086 {
1087 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1088 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1089 continue;
1090
1091 if (crecp->flags & F_NEG)
feba5c1d 1092 {
f6b7dc47
SK
1093 ans = 1;
1094 auth = 0;
1095 if (crecp->flags & F_NXDOMAIN)
1096 nxdomain = 1;
1097 if (!dryrun)
1098 log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
1099 }
1100 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
1101 {
1102 ans = 1;
1103 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1104 auth = 0;
1105 if (!dryrun)
1106 {
1107 unsigned long ttl;
1108 /* Return 0 ttl for DHCP entries, which might change
1109 before the lease expires. */
1110 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1111 ttl = daemon->local_ttl;
1112 else
1113 ttl = crecp->ttd - now;
1114
1115 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1116 0, daemon->addn_hosts, crecp->uid);
1117
1118 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL,
1119 T_PTR, C_IN, "d", cache_get_name(crecp)))
1120 anscount++;
1121 }
1122 }
1123 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1124 }
1125
1126 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1127 {
1128 unsigned short type = T_A;
1129
1130 if (flag == F_IPV6)
feba5c1d 1131#ifdef HAVE_IPV6
f6b7dc47 1132 type = T_AAAA;
feba5c1d 1133#else
f6b7dc47 1134 break;
feba5c1d 1135#endif
f6b7dc47
SK
1136
1137 if (qtype != type && qtype != T_ANY)
1138 continue;
1139
1140 cname_restart:
1141 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
1142 {
1143 int localise = 0;
feba5c1d 1144
f6b7dc47
SK
1145 /* See if a putative address is on the network from which we recieved
1146 the query, is so we'll filter other answers. */
1147 if (local_addr.s_addr != 0 && (daemon->options & OPT_LOCALISE) && flag == F_IPV4)
1148 {
1149 struct crec *save = crecp;
1150 do {
1151 if ((crecp->flags & F_HOSTS) &&
1152 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1153 {
1154 localise = 1;
1155 break;
1156 }
1157 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1158 crecp = save;
1159 }
1160
1161 do
9e4abcb5 1162 {
26128d27
SK
1163 /* don't answer wildcard queries with data not from /etc/hosts
1164 or DHCP leases */
1165 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1166 break;
1167
fd9fa481
SK
1168 if (crecp->flags & F_CNAME)
1169 {
fd9fa481
SK
1170 if (!dryrun)
1171 {
fd9fa481 1172 log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
f6b7dc47
SK
1173 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset,
1174 T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
1175 anscount++;
fd9fa481 1176 }
f6b7dc47 1177
fd9fa481
SK
1178 strcpy(name, cache_get_name(crecp->addr.cname.cache));
1179 goto cname_restart;
1180 }
f6b7dc47 1181
9e4abcb5
SK
1182 if (crecp->flags & F_NEG)
1183 {
feba5c1d 1184 ans = 1;
f6b7dc47
SK
1185 auth = 0;
1186 if (crecp->flags & F_NXDOMAIN)
1187 nxdomain = 1;
feba5c1d 1188 if (!dryrun)
f6b7dc47 1189 log_query(crecp->flags, name, NULL, 0, NULL, 0);
9e4abcb5 1190 }
feba5c1d 1191 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
9e4abcb5 1192 {
f6b7dc47
SK
1193 /* If we are returning local answers depending on network,
1194 filter here. */
1195 if (localise &&
1196 (crecp->flags & F_HOSTS) &&
1197 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1198 continue;
1199
1200 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1201 auth = 0;
1202
feba5c1d
SK
1203 ans = 1;
1204 if (!dryrun)
1205 {
1206 unsigned long ttl;
1207
1208 if (crecp->flags & (F_IMMORTAL | F_DHCP))
3be34541 1209 ttl = daemon->local_ttl;
feba5c1d
SK
1210 else
1211 ttl = crecp->ttd - now;
1212
fd9fa481
SK
1213 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
1214 0, daemon->addn_hosts, crecp->uid);
feba5c1d 1215
f6b7dc47
SK
1216 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN,
1217 type == T_A ? "4" : "6", &crecp->addr))
1218 anscount++;
feba5c1d 1219 }
9e4abcb5 1220 }
f6b7dc47 1221 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
9e4abcb5 1222 }
f6b7dc47
SK
1223 }
1224
1225 if (qtype == T_MX || qtype == T_ANY)
1226 {
1227 int found = 0;
0a852541
SK
1228 for (rec = daemon->mxnames; rec; rec = rec->next)
1229 if (!rec->issrv && hostname_isequal(name, rec->name))
f6b7dc47
SK
1230 {
1231 ans = found = 1;
1232 if (!dryrun)
feba5c1d 1233 {
0a852541 1234 int offset;
f6b7dc47 1235 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
0a852541
SK
1236 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1237 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1238 {
1239 anscount++;
1240 if (rec->target)
1241 rec->offset = offset;
1242 }
feba5c1d 1243 }
f6b7dc47
SK
1244 }
1245
1246 if (!found && (daemon->options & (OPT_SELFMX | OPT_LOCALMX)) &&
1247 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
1248 {
1249 ans = 1;
1250 if (!dryrun)
1251 {
1252 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
1253 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1254 T_MX, C_IN, "sd", 1,
1255 (daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
1256 anscount++;
9e4abcb5
SK
1257 }
1258 }
f6b7dc47
SK
1259 }
1260
1261 if (qtype == T_SRV || qtype == T_ANY)
1262 {
1263 int found = 0;
9e4abcb5 1264
0a852541
SK
1265 for (rec = daemon->mxnames; rec; rec = rec->next)
1266 if (rec->issrv && hostname_isequal(name, rec->name))
f6b7dc47
SK
1267 {
1268 found = ans = 1;
1269 if (!dryrun)
1270 {
0a852541 1271 int offset;
f6b7dc47
SK
1272 log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
1273 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
0a852541
SK
1274 &offset, T_SRV, C_IN, "sssd",
1275 rec->priority, rec->weight, rec->srvport, rec->target))
1276 {
1277 anscount++;
1278 if (rec->target)
1279 rec->offset = offset;
1280 }
f6b7dc47
SK
1281 }
1282 }
feba5c1d 1283
f6b7dc47
SK
1284 if (!found && (daemon->options & OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
1285 {
1286 ans = 1;
1287 if (!dryrun)
1288 log_query(F_CONFIG | F_NEG, name, NULL, 0, NULL, 0);
1289 }
1290 }
1291
1292 if (qtype == T_MAILB)
1293 ans = 1, nxdomain = 1;
1294
1295 if (qtype == T_SOA && (daemon->options & OPT_FILTER))
1296 {
1297 ans = 1;
1298 if (!dryrun)
1299 log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
feba5c1d 1300 }
9e4abcb5 1301 }
f6b7dc47
SK
1302
1303 if (!ans)
9e4abcb5 1304 return 0; /* failed to answer a question */
feba5c1d 1305 }
f6b7dc47 1306
feba5c1d
SK
1307 if (dryrun)
1308 {
1309 dryrun = 0;
1310 goto rerun;
9e4abcb5
SK
1311 }
1312
0a852541
SK
1313 /* create an additional data section, for stuff in SRV and MX record replies. */
1314 for (rec = daemon->mxnames; rec; rec = rec->next)
1315 if (rec->offset != 0)
1316 {
1317 /* squash dupes */
1318 struct mx_srv_record *tmp;
1319 for (tmp = rec->next; tmp; tmp = tmp->next)
1320 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1321 tmp->offset = 0;
1322
1323 crecp = NULL;
1324 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1325 {
1326 unsigned long ttl;
1327#ifdef HAVE_IPV6
1328 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
1329#else
1330 int type = T_A;
1331#endif
1332 if (crecp->flags & F_NEG)
1333 continue;
1334
1335 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1336 ttl = daemon->local_ttl;
1337 else
1338 ttl = crecp->ttd - now;
1339
1340 if (add_resource_record(header, limit, NULL, rec->offset, &ansp, ttl, NULL, type, C_IN,
1341 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1342 addncount++;
1343 }
1344 }
1345
9e4abcb5
SK
1346 /* done all questions, set up header and return length of result */
1347 header->qr = 1; /* response */
1348 header->aa = auth; /* authoritive - only hosts and DHCP derived names. */
1349 header->ra = 1; /* recursion if available */
f6b7dc47 1350 header->tc = trunc; /* truncation */
9e4abcb5
SK
1351 if (anscount == 0 && nxdomain)
1352 header->rcode = NXDOMAIN;
1353 else
1354 header->rcode = NOERROR; /* no error */
1355 header->ancount = htons(anscount);
1356 header->nscount = htons(0);
0a852541 1357 header->arcount = htons(addncount);
9e4abcb5
SK
1358 return ansp - (unsigned char *)header;
1359}
1360
1361
1362
1363
1364