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