blob: 77156e49361561698fce841c8a4a3b2bce2389c3 [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
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
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 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.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 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/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
17#include "dnsmasq.h"
18
Simon Kelley4f7b3042012-11-28 21:27:02 +000019int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
20 char *name, int isExtract, int extrabytes)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000021{
Simon Kelley3d8df262005-08-29 12:19:27 +010022 unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000023 unsigned int j, l, hops = 0;
24 int retvalue = 1;
25
Simon Kelleyf6b7dc42005-01-23 12:06:08 +000026 if (isExtract)
27 *cp = 0;
28
Simon Kelley9009d742008-11-14 20:04:27 +000029 while (1)
30 {
31 unsigned int label_type;
32
33 if (!CHECK_LEN(header, p, plen, 1))
34 return 0;
35
36 if ((l = *p++) == 0)
37 /* end marker */
38 {
39 /* check that there are the correct no of bytes after the name */
40 if (!CHECK_LEN(header, p, plen, extrabytes))
41 return 0;
42
43 if (isExtract)
44 {
45 if (cp != (unsigned char *)name)
46 cp--;
47 *cp = 0; /* terminate: lose final period */
48 }
49 else if (*cp != 0)
50 retvalue = 2;
51
52 if (p1) /* we jumped via compression */
53 *pp = p1;
54 else
55 *pp = p;
56
57 return retvalue;
58 }
59
60 label_type = l & 0xc0;
61
Simon Kelley9e4abcb2004-01-22 19:47:41 +000062 if (label_type == 0xc0) /* pointer */
63 {
Simon Kelley9009d742008-11-14 20:04:27 +000064 if (!CHECK_LEN(header, p, plen, 1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065 return 0;
66
67 /* get offset */
68 l = (l&0x3f) << 8;
69 l |= *p++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000070
71 if (!p1) /* first jump, save location to go back to */
72 p1 = p;
73
74 hops++; /* break malicious infinite loops */
75 if (hops > 255)
76 return 0;
77
78 p = l + (unsigned char *)header;
79 }
80 else if (label_type == 0x80)
81 return 0; /* reserved */
82 else if (label_type == 0x40)
83 { /* ELT */
84 unsigned int count, digs;
85
86 if ((l & 0x3f) != 1)
87 return 0; /* we only understand bitstrings */
88
89 if (!isExtract)
90 return 0; /* Cannot compare bitsrings */
91
92 count = *p++;
93 if (count == 0)
94 count = 256;
95 digs = ((count-1)>>2)+1;
96
97 /* output is \[x<hex>/siz]. which is digs+9 chars */
Simon Kelley3d8df262005-08-29 12:19:27 +010098 if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000099 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000100 if (!CHECK_LEN(header, p, plen, (count-1)>>3))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000101 return 0;
102
103 *cp++ = '\\';
104 *cp++ = '[';
105 *cp++ = 'x';
106 for (j=0; j<digs; j++)
107 {
108 unsigned int dig;
109 if (j%2 == 0)
110 dig = *p >> 4;
111 else
112 dig = *p++ & 0x0f;
113
114 *cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
115 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100116 cp += sprintf((char *)cp, "/%d]", count);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000117 /* do this here to overwrite the zero char from sprintf */
118 *cp++ = '.';
119 }
120 else
121 { /* label_type = 0 -> label. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100122 if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000123 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000124 if (!CHECK_LEN(header, p, plen, l))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000125 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000126
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000127 for(j=0; j<l; j++, p++)
128 if (isExtract)
129 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100130 unsigned char c = *p;
131 if (isascii(c) && !iscntrl(c) && c != '.')
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000132 *cp++ = *p;
133 else
134 return 0;
135 }
136 else
137 {
138 unsigned char c1 = *cp, c2 = *p;
139
140 if (c1 == 0)
141 retvalue = 2;
142 else
143 {
144 cp++;
145 if (c1 >= 'A' && c1 <= 'Z')
146 c1 += 'a' - 'A';
147 if (c2 >= 'A' && c2 <= 'Z')
148 c2 += 'a' - 'A';
149
150 if (c1 != c2)
151 retvalue = 2;
152 }
153 }
154
155 if (isExtract)
156 *cp++ = '.';
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000157 else if (*cp != 0 && *cp++ != '.')
158 retvalue = 2;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000159 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000160 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000161}
162
163/* Max size of input string (for IPv6) is 75 chars.) */
164#define MAXARPANAME 75
Simon Kelley4f7b3042012-11-28 21:27:02 +0000165int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000166{
167 int j;
168 char name[MAXARPANAME+1], *cp1;
169 unsigned char *addr = (unsigned char *)addrp;
170 char *lastchunk = NULL, *penchunk = NULL;
171
172 if (strlen(namein) > MAXARPANAME)
173 return 0;
174
175 memset(addrp, 0, sizeof(struct all_addr));
176
177 /* turn name into a series of asciiz strings */
178 /* j counts no of labels */
179 for(j = 1,cp1 = name; *namein; cp1++, namein++)
180 if (*namein == '.')
181 {
182 penchunk = lastchunk;
183 lastchunk = cp1 + 1;
184 *cp1 = 0;
185 j++;
186 }
187 else
188 *cp1 = *namein;
189
190 *cp1 = 0;
191
192 if (j<3)
193 return 0;
194
195 if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
196 {
197 /* IP v4 */
198 /* address arives as a name of the form
199 www.xxx.yyy.zzz.in-addr.arpa
200 some of the low order address octets might be missing
201 and should be set to zero. */
202 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
203 {
204 /* check for digits only (weeds out things like
205 50.0/24.67.28.64.in-addr.arpa which are used
206 as CNAME targets according to RFC 2317 */
207 char *cp;
208 for (cp = cp1; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000209 if (!isdigit((unsigned char)*cp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000210 return 0;
211
212 addr[3] = addr[2];
213 addr[2] = addr[1];
214 addr[1] = addr[0];
215 addr[0] = atoi(cp1);
216 }
217
218 return F_IPV4;
219 }
220#ifdef HAVE_IPV6
221 else if (hostname_isequal(penchunk, "ip6") &&
222 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
223 {
224 /* IP v6:
225 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
226 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
227
228 Note that most of these the various reprentations are obsolete and
229 left-over from the many DNS-for-IPv6 wars. We support all the formats
230 that we can since there is no reason not to.
231 */
232
233 if (*name == '\\' && *(name+1) == '[' &&
234 (*(name+2) == 'x' || *(name+2) == 'X'))
235 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000236 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000237 {
238 char xdig[2];
239 xdig[0] = *cp1;
240 xdig[1] = 0;
241 if (j%2)
242 addr[j/2] |= strtol(xdig, NULL, 16);
243 else
244 addr[j/2] = strtol(xdig, NULL, 16) << 4;
245 }
246
247 if (*cp1 == '/' && j == 32)
248 return F_IPV6;
249 }
250 else
251 {
252 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
253 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000254 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000255 return 0;
256
257 for (j = sizeof(struct all_addr)-1; j>0; j--)
258 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
259 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
260 }
261
262 return F_IPV6;
263 }
264 }
265#endif
266
267 return 0;
268}
269
Giovanni Bajo32f82c62012-04-28 01:01:16 +0200270unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100271{
272 while(1)
273 {
Simon Kelley9009d742008-11-14 20:04:27 +0000274 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100275
Simon Kelley9009d742008-11-14 20:04:27 +0000276 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100277 return NULL;
278
Simon Kelley9009d742008-11-14 20:04:27 +0000279 label_type = (*ansp) & 0xc0;
280
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100281 if (label_type == 0xc0)
282 {
283 /* pointer for compression. */
284 ansp += 2;
285 break;
286 }
287 else if (label_type == 0x80)
288 return NULL; /* reserved */
289 else if (label_type == 0x40)
290 {
291 /* Extended label type */
292 unsigned int count;
293
Simon Kelley9009d742008-11-14 20:04:27 +0000294 if (!CHECK_LEN(header, ansp, plen, 2))
295 return NULL;
296
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100297 if (((*ansp++) & 0x3f) != 1)
298 return NULL; /* we only understand bitstrings */
299
300 count = *(ansp++); /* Bits in bitstring */
301
302 if (count == 0) /* count == 0 means 256 bits */
303 ansp += 32;
304 else
305 ansp += ((count-1)>>3)+1;
306 }
307 else
308 { /* label type == 0 Bottom six bits is length */
309 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000310
311 if (!ADD_RDLEN(header, ansp, plen, len))
312 return NULL;
313
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100314 if (len == 0)
315 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100316 }
317 }
Simon Kelley9009d742008-11-14 20:04:27 +0000318
319 if (!CHECK_LEN(header, ansp, plen, extrabytes))
320 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100321
322 return ansp;
323}
324
Simon Kelley4f7b3042012-11-28 21:27:02 +0000325unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000326{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100327 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000328 unsigned char *ansp = (unsigned char *)(header+1);
329
Simon Kelley5aabfc72007-08-29 11:24:47 +0100330 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000331 {
Simon Kelley9009d742008-11-14 20:04:27 +0000332 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100333 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000334 ansp += 4; /* class and type */
335 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000336
337 return ansp;
338}
339
Simon Kelley5107ace2014-02-23 10:48:32 +0000340unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100341{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100342 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100343
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100344 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100345 {
Simon Kelley9009d742008-11-14 20:04:27 +0000346 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100347 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100348 ansp += 8; /* type, class, TTL */
349 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000350 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100351 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100352 }
353
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100354 return ansp;
355}
356
Simon Kelley0a852542005-03-23 20:28:59 +0000357/* CRC the question section. This is used to safely detect query
358 retransmision and to detect answers to questions we didn't ask, which
359 might be poisoning attacks. Note that we decode the name rather
360 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000361 We ignore case in the names for the same reason. Return all-ones
362 if there is not question section. */
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000363#ifndef HAVE_DNSSEC
Simon Kelley572b41e2011-02-18 18:11:18 +0000364unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100365{
Simon Kelley91dccd02005-03-31 17:48:32 +0100366 int q;
367 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000368 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100369
Simon Kelley5aabfc72007-08-29 11:24:47 +0100370 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000371 {
Simon Kelley9009d742008-11-14 20:04:27 +0000372 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000373 return crc; /* bad packet */
374
Simon Kelley3d8df262005-08-29 12:19:27 +0100375 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000376 {
377 int i = 8;
378 char c = *p1;
379
380 if (c >= 'A' && c <= 'Z')
381 c += 'a' - 'A';
382
383 crc ^= c << 24;
384 while (i--)
385 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
386 }
387
388 /* CRC the class and type as well */
389 for (p1 = p; p1 < p+4; p1++)
390 {
391 int i = 8;
392 crc ^= *p1 << 24;
393 while (i--)
394 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
395 }
396
397 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000398 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000399 return crc; /* bad packet */
400 }
401
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100402 return crc;
403}
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000404#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100405
Simon Kelley572b41e2011-02-18 18:11:18 +0000406size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100407{
408 unsigned char *ansp = skip_questions(header, plen);
409
Simon Kelley9009d742008-11-14 20:04:27 +0000410 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100411 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000412 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100413
414 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
415 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000416 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100417
Simon Kelley36717ee2004-09-20 19:20:58 +0100418 /* restore pseudoheader */
419 if (pheader && ntohs(header->arcount) == 0)
420 {
421 /* must use memmove, may overlap */
422 memmove(ansp, pheader, hlen);
423 header->arcount = htons(1);
424 ansp += hlen;
425 }
426
427 return ansp - (unsigned char *)header;
428}
429
Simon Kelley572b41e2011-02-18 18:11:18 +0000430unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
Simon Kelley36717ee2004-09-20 19:20:58 +0100431{
432 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
Simon Kelley832af0b2007-01-21 20:01:28 +0000433 also return length of pseudoheader in *len and pointer to the UDP size in *p
434 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
435 forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100436
437 int i, arcount = ntohs(header->arcount);
Simon Kelley832af0b2007-01-21 20:01:28 +0000438 unsigned char *ansp = (unsigned char *)(header+1);
439 unsigned short rdlen, type, class;
440 unsigned char *ret = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000441
442 if (is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000443 {
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000444 *is_sign = 0;
445
Simon Kelley572b41e2011-02-18 18:11:18 +0000446 if (OPCODE(header) == QUERY)
Simon Kelley832af0b2007-01-21 20:01:28 +0000447 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100448 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000449 {
Simon Kelley9009d742008-11-14 20:04:27 +0000450 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000451 return NULL;
452
453 GETSHORT(type, ansp);
454 GETSHORT(class, ansp);
455
456 if (class == C_IN && type == T_TKEY)
457 *is_sign = 1;
458 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000459 }
460 }
461 else
462 {
463 if (!(ansp = skip_questions(header, plen)))
464 return NULL;
465 }
466
467 if (arcount == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100468 return NULL;
469
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100470 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
471 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000472
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100473 for (i = 0; i < arcount; i++)
474 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100475 unsigned char *save, *start = ansp;
Simon Kelley9009d742008-11-14 20:04:27 +0000476 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100477 return NULL;
478
479 GETSHORT(type, ansp);
480 save = ansp;
Simon Kelley832af0b2007-01-21 20:01:28 +0000481 GETSHORT(class, ansp);
482 ansp += 4; /* TTL */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100483 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000484 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100485 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000486 if (type == T_OPT)
Simon Kelley36717ee2004-09-20 19:20:58 +0100487 {
488 if (len)
489 *len = ansp - start;
490 if (p)
491 *p = save;
Simon Kelley832af0b2007-01-21 20:01:28 +0000492 ret = start;
Simon Kelley36717ee2004-09-20 19:20:58 +0100493 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000494 else if (is_sign &&
495 i == arcount - 1 &&
496 class == C_ANY &&
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000497 type == T_TSIG)
Simon Kelley832af0b2007-01-21 20:01:28 +0000498 *is_sign = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100499 }
500
Simon Kelley832af0b2007-01-21 20:01:28 +0000501 return ret;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100502}
Simon Kelley28866e92011-02-14 20:19:14 +0000503
504struct macparm {
505 unsigned char *limit;
Simon Kelley572b41e2011-02-18 18:11:18 +0000506 struct dns_header *header;
Simon Kelley28866e92011-02-14 20:19:14 +0000507 size_t plen;
508 union mysockaddr *l3;
509};
Simon Kelleyed4c0762013-10-08 20:46:34 +0100510
511static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
Simon Kelley3a237152013-12-12 12:15:50 +0000512 int optno, unsigned char *opt, size_t optlen, int set_do)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100513{
514 unsigned char *lenp, *datap, *p;
Simon Kelleya25720a2014-01-14 23:13:55 +0000515 int rdlen, is_sign;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100516
Simon Kelleya25720a2014-01-14 23:13:55 +0000517 if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
Simon Kelleyed4c0762013-10-08 20:46:34 +0100518 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000519 if (is_sign)
520 return plen;
521
Simon Kelleyed4c0762013-10-08 20:46:34 +0100522 /* We are adding the pseudoheader */
523 if (!(p = skip_questions(header, plen)) ||
524 !(p = skip_section(p,
Simon Kelleya25720a2014-01-14 23:13:55 +0000525 ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
Simon Kelleyed4c0762013-10-08 20:46:34 +0100526 header, plen)))
527 return plen;
528 *p++ = 0; /* empty name */
529 PUTSHORT(T_OPT, p);
530 PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
Simon Kelley3a237152013-12-12 12:15:50 +0000531 PUTSHORT(0, p); /* extended RCODE and version */
532 PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100533 lenp = p;
534 PUTSHORT(0, p); /* RDLEN */
535 rdlen = 0;
536 if (((ssize_t)optlen) > (limit - (p + 4)))
537 return plen; /* Too big */
Simon Kelleya25720a2014-01-14 23:13:55 +0000538 header->arcount = htons(ntohs(header->arcount) + 1);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100539 datap = p;
540 }
541 else
542 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000543 int i;
Simon Kelley3a237152013-12-12 12:15:50 +0000544 unsigned short code, len, flags;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100545
Simon Kelleya25720a2014-01-14 23:13:55 +0000546 /* Must be at the end, if exists */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100547 if (ntohs(header->arcount) != 1 ||
Simon Kelleyed4c0762013-10-08 20:46:34 +0100548 is_sign ||
549 (!(p = skip_name(p, header, plen, 10))))
550 return plen;
551
Simon Kelley3a237152013-12-12 12:15:50 +0000552 p += 6; /* skip UDP length and RCODE */
553 GETSHORT(flags, p);
554 if (set_do)
555 {
556 p -=2;
557 PUTSHORT(flags | 0x8000, p);
558 }
559
Simon Kelleyed4c0762013-10-08 20:46:34 +0100560 lenp = p;
561 GETSHORT(rdlen, p);
562 if (!CHECK_LEN(header, p, plen, rdlen))
563 return plen; /* bad packet */
564 datap = p;
565
Simon Kelley3a237152013-12-12 12:15:50 +0000566 /* no option to add */
567 if (optno == 0)
568 return plen;
569
Simon Kelleyed4c0762013-10-08 20:46:34 +0100570 /* check if option already there */
571 for (i = 0; i + 4 < rdlen; i += len + 4)
572 {
573 GETSHORT(code, p);
574 GETSHORT(len, p);
575 if (code == optno)
576 return plen;
577 p += len;
578 }
579
580 if (((ssize_t)optlen) > (limit - (p + 4)))
581 return plen; /* Too big */
582 }
583
Simon Kelley0fc2f312014-01-08 10:26:58 +0000584 if (optno != 0)
585 {
586 PUTSHORT(optno, p);
587 PUTSHORT(optlen, p);
588 memcpy(p, opt, optlen);
589 p += optlen;
590 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100591
592 PUTSHORT(p - datap, lenp);
593 return p - (unsigned char *)header;
594
595}
Simon Kelley28866e92011-02-14 20:19:14 +0000596
597static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
598{
599 struct macparm *parm = parmv;
600 int match = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100601
Simon Kelley28866e92011-02-14 20:19:14 +0000602 if (family == parm->l3->sa.sa_family)
603 {
Simon Kelley613ad152014-02-25 23:02:28 +0000604 if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000605 match = 1;
606#ifdef HAVE_IPV6
607 else
Simon Kelley613ad152014-02-25 23:02:28 +0000608 if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000609 match = 1;
610#endif
611 }
612
613 if (!match)
614 return 1; /* continue */
Simon Kelley28866e92011-02-14 20:19:14 +0000615
Simon Kelley3a237152013-12-12 12:15:50 +0000616 parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
Simon Kelley28866e92011-02-14 20:19:14 +0000617
618 return 0; /* done */
619}
620
Simon Kelley572b41e2011-02-18 18:11:18 +0000621size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
Simon Kelley28866e92011-02-14 20:19:14 +0000622{
623 struct macparm parm;
624
625/* Must have an existing pseudoheader as the only ar-record,
626 or have no ar-records. Must also not be signed */
627
628 if (ntohs(header->arcount) > 1)
629 return plen;
630
631 parm.header = header;
632 parm.limit = (unsigned char *)limit;
633 parm.plen = plen;
634 parm.l3 = l3;
635
636 iface_enumerate(AF_UNSPEC, &parm, filter_mac);
637
638 return parm.plen;
639}
640
Simon Kelleyed4c0762013-10-08 20:46:34 +0100641struct subnet_opt {
642 u16 family;
643 u8 source_netmask, scope_netmask;
644#ifdef HAVE_IPV6
645 u8 addr[IN6ADDRSZ];
646#else
647 u8 addr[INADDRSZ];
648#endif
649};
650
Simon Kelley44de6492013-11-06 11:36:57 +0000651static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100652{
653 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
654
655 int len;
656 void *addrp;
657
Simon Kelleyed4c0762013-10-08 20:46:34 +0100658#ifdef HAVE_IPV6
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100659 if (source->sa.sa_family == AF_INET6)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100660 {
661 opt->family = htons(2);
662 opt->source_netmask = daemon->addr6_netmask;
663 addrp = &source->in6.sin6_addr;
664 }
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100665 else
Simon Kelleyed4c0762013-10-08 20:46:34 +0100666#endif
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100667 {
668 opt->family = htons(1);
669 opt->source_netmask = daemon->addr4_netmask;
670 addrp = &source->in.sin_addr;
671 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100672
673 opt->scope_netmask = 0;
674 len = 0;
675
676 if (opt->source_netmask != 0)
677 {
678 len = ((opt->source_netmask - 1) >> 3) + 1;
679 memcpy(opt->addr, addrp, len);
680 if (opt->source_netmask & 7)
681 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
682 }
683
684 return len + 4;
685}
686
687size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
688{
689 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
690
691 int len;
692 struct subnet_opt opt;
693
694 len = calc_subnet_opt(&opt, source);
Simon Kelley3a237152013-12-12 12:15:50 +0000695 return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100696}
Simon Kelley3a237152013-12-12 12:15:50 +0000697
698#ifdef HAVE_DNSSEC
699size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
700{
701 return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
702}
703#endif
704
Simon Kelleyed4c0762013-10-08 20:46:34 +0100705int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
706{
707 /* Section 9.2, Check that subnet option in reply matches. */
708
709
710 int len, calc_len;
711 struct subnet_opt opt;
712 unsigned char *p;
713 int code, i, rdlen;
714
715 calc_len = calc_subnet_opt(&opt, peer);
716
717 if (!(p = skip_name(pseudoheader, header, plen, 10)))
718 return 1;
719
720 p += 8; /* skip UDP length and RCODE */
721
722 GETSHORT(rdlen, p);
723 if (!CHECK_LEN(header, p, plen, rdlen))
724 return 1; /* bad packet */
725
726 /* check if option there */
727 for (i = 0; i + 4 < rdlen; i += len + 4)
728 {
729 GETSHORT(code, p);
730 GETSHORT(len, p);
731 if (code == EDNS0_OPTION_CLIENT_SUBNET)
732 {
733 /* make sure this doesn't mismatch. */
734 opt.scope_netmask = p[3];
735 if (len != calc_len || memcmp(p, &opt, len) != 0)
736 return 0;
737 }
738 p += len;
739 }
740
741 return 1;
742}
743
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000744/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100745int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000746{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100747 in_addr_t ip_addr = ntohl(addr.s_addr);
748
749 return
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100750 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100751 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
752 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
753 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
754 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000755}
Simon Kelley1cff1662004-03-12 08:12:58 +0000756
Simon Kelley6938f342014-01-26 22:47:39 +0000757static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley824af852008-02-12 20:43:05 +0000758{
759 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000760
761 for (i = count; i != 0; i--)
762 {
Simon Kelley28866e92011-02-14 20:19:14 +0000763 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100764 {
765 if (!extract_name(header, qlen, &p, name, 1, 10))
766 return 0;
767 }
768 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000769 return 0; /* bad packet */
770
771 GETSHORT(qtype, p);
772 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100773 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000774 GETSHORT(rdlen, p);
775
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100776 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000777 {
778 struct doctor *doctor;
779 struct in_addr addr;
780
Simon Kelley9009d742008-11-14 20:04:27 +0000781 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
782 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100783
784 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000785 memcpy(&addr, p, INADDRSZ);
786
787 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000788 {
789 if (doctor->end.s_addr == 0)
790 {
791 if (!is_same_net(doctor->in, addr, doctor->mask))
792 continue;
793 }
794 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
795 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
796 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100797
Simon Kelley73a08a22009-02-05 20:28:08 +0000798 addr.s_addr &= ~doctor->mask.s_addr;
799 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
800 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000801 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000802 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000803 memcpy(p, &addr, INADDRSZ);
804 break;
805 }
Simon Kelley824af852008-02-12 20:43:05 +0000806 }
Simon Kelley28866e92011-02-14 20:19:14 +0000807 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100808 {
809 unsigned char *p1 = p;
810 if (!CHECK_LEN(header, p1, qlen, rdlen))
811 return 0;
812 while ((p1 - p) < rdlen)
813 {
814 unsigned int i, len = *p1;
815 unsigned char *p2 = p1;
816 /* make counted string zero-term and sanitise */
817 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100818 {
819 if (!isprint((int)*(p2+1)))
820 break;
821
822 *p2 = *(p2+1);
823 p2++;
824 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100825 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000826 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100827 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100828 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100829 *p1 = len;
830 p1 += len+1;
831 }
832 }
Simon Kelley824af852008-02-12 20:43:05 +0000833
Simon Kelley9009d742008-11-14 20:04:27 +0000834 if (!ADD_RDLEN(header, p, qlen, rdlen))
835 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000836 }
837
838 return p;
839}
840
Simon Kelley6938f342014-01-26 22:47:39 +0000841static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000844 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100845 unsigned long ttl, minttl = ULONG_MAX;
846 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000847
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100848 /* first move to NS section and find TTL from any SOA section */
849 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000850 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000851 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000852
Simon Kelley5aabfc72007-08-29 11:24:47 +0100853 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000854 {
Simon Kelley9009d742008-11-14 20:04:27 +0000855 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100856 return 0; /* bad packet */
857
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000858 GETSHORT(qtype, p);
859 GETSHORT(qclass, p);
860 GETLONG(ttl, p);
861 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100862
863 if ((qclass == C_IN) && (qtype == T_SOA))
864 {
865 found_soa = 1;
866 if (ttl < minttl)
867 minttl = ttl;
868
869 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000870 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100871 return 0;
872 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000873 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100874 return 0;
875 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
876
877 GETLONG(ttl, p); /* minTTL */
878 if (ttl < minttl)
879 minttl = ttl;
880 }
Simon Kelley9009d742008-11-14 20:04:27 +0000881 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882 return 0; /* bad packet */
883 }
Simon Kelley9009d742008-11-14 20:04:27 +0000884
Simon Kelley6938f342014-01-26 22:47:39 +0000885 /* rewrite addresses in additional section too */
886 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000887 return 0;
888
889 if (!found_soa)
890 minttl = daemon->neg_ttl;
891
892 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100893}
894
895/* Note that the following code can create CNAME chains that don't point to a real record,
896 either because of lack of memory, or lack of SOA records. These are treated by the cache code as
Simon Kelley824af852008-02-12 20:43:05 +0000897 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100898 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000899int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelley6938f342014-01-26 22:47:39 +0000900 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100901{
Simon Kelley824af852008-02-12 20:43:05 +0000902 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100903 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000904 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100905 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000906#ifdef HAVE_IPSET
907 char **ipsets_cur;
908#else
909 (void)ipsets; /* unused */
910#endif
911
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100912 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000913
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100914 /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
Simon Kelley6938f342014-01-26 22:47:39 +0000915 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000916 {
917 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000918 ttl = find_soa(header, qlen, name, doctored);
919#ifdef HAVE_DNSSEC
920 if (*doctored)
921 secure = 0;
922#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000923 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100924
925 /* go through the questions. */
926 p = (unsigned char *)(header+1);
927
Simon Kelley5aabfc72007-08-29 11:24:47 +0100928 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100929 {
930 int found = 0, cname_count = 5;
931 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000932 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0435d042014-01-08 18:22:37 +0000933 int secflag = secure ? F_DNSSECOK : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000934 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000935
Simon Kelley824af852008-02-12 20:43:05 +0000936 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000937 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000938 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100939
940 GETSHORT(qtype, p);
941 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000942
943 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100944 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000945
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100946 /* PTRs: we chase CNAMEs here, since we have no way to
947 represent them in the cache. */
948 if (qtype == T_PTR)
949 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000950 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100951
952 if (!name_encoding)
953 continue;
954
955 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000956 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100957 cname_loop:
958 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000959 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100960
Simon Kelley5aabfc72007-08-29 11:24:47 +0100961 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100962 {
Simon Kelley824af852008-02-12 20:43:05 +0000963 unsigned char *tmp = namep;
964 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000965 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
966 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000967 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100968
969 GETSHORT(aqtype, p1);
970 GETSHORT(aqclass, p1);
971 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100972 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
973 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000974 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100975 PUTLONG(daemon->max_ttl, p1);
976 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100977 GETSHORT(ardlen, p1);
978 endrr = p1+ardlen;
979
980 /* TTL of record is minimum of CNAMES and PTR */
981 if (attl < cttl)
982 cttl = attl;
983
984 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
985 {
Simon Kelley9009d742008-11-14 20:04:27 +0000986 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000987 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100988
989 if (aqtype == T_CNAME)
990 {
991 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000992 return 0; /* looped CNAMES */
Simon Kelley2d33bda2014-01-24 22:37:25 +0000993 secflag = 0; /* no longer DNSSEC */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100994 goto cname_loop;
995 }
996
Simon Kelley0435d042014-01-08 18:22:37 +0000997 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100998 found = 1;
999 }
1000
1001 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +00001002 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +00001003 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001004 }
1005 }
1006
Simon Kelley28866e92011-02-14 20:19:14 +00001007 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001008 {
1009 if (!searched_soa)
1010 {
1011 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001012 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001013 }
1014 if (ttl)
Simon Kelley0435d042014-01-08 18:22:37 +00001015 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001016 }
1017 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001018 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001019 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001020 /* everything other than PTR */
1021 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001022 int addrlen;
1023
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001024 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001025 {
1026 addrlen = INADDRSZ;
1027 flags |= F_IPV4;
1028 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001029#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001030 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001031 {
1032 addrlen = IN6ADDRSZ;
1033 flags |= F_IPV6;
1034 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001035#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001036 else
1037 continue;
1038
Simon Kelley45cca582013-10-15 10:20:13 +01001039 cname_loop1:
1040 if (!(p1 = skip_questions(header, qlen)))
1041 return 0;
1042
1043 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001044 {
Simon Kelley45cca582013-10-15 10:20:13 +01001045 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
1046 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001047
Simon Kelley45cca582013-10-15 10:20:13 +01001048 GETSHORT(aqtype, p1);
1049 GETSHORT(aqclass, p1);
1050 GETLONG(attl, p1);
1051 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001052 {
Simon Kelley45cca582013-10-15 10:20:13 +01001053 (p1) -= 4;
1054 PUTLONG(daemon->max_ttl, p1);
1055 }
1056 GETSHORT(ardlen, p1);
1057 endrr = p1+ardlen;
1058
1059 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
1060 {
1061 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001062 {
Simon Kelley45cca582013-10-15 10:20:13 +01001063 if (!cname_count--)
1064 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +00001065 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001066 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001067 {
Simon Kelley45cca582013-10-15 10:20:13 +01001068 newc->addr.cname.target.cache = NULL;
1069 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001070 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001071 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001072 cpp->addr.cname.uid = newc->uid;
1073 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001074 }
Simon Kelley45cca582013-10-15 10:20:13 +01001075
1076 cpp = newc;
1077 if (attl < cttl)
1078 cttl = attl;
1079
1080 if (!extract_name(header, qlen, &p1, name, 1, 0))
1081 return 0;
1082 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001083 }
Simon Kelley45cca582013-10-15 10:20:13 +01001084 else if (!(flags & F_NXDOMAIN))
1085 {
1086 found = 1;
1087
1088 /* copy address into aligned storage */
1089 if (!CHECK_LEN(header, p1, qlen, addrlen))
1090 return 0; /* bad packet */
1091 memcpy(&addr, p1, addrlen);
1092
1093 /* check for returned address in private space */
1094 if (check_rebind &&
1095 (flags & F_IPV4) &&
1096 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
1097 return 1;
1098
1099#ifdef HAVE_IPSET
1100 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
1101 {
1102 ipsets_cur = ipsets;
1103 while (*ipsets_cur)
1104 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
1105 }
1106#endif
1107
Simon Kelley0435d042014-01-08 18:22:37 +00001108 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001109 if (newc && cpp)
1110 {
1111 cpp->addr.cname.target.cache = newc;
1112 cpp->addr.cname.uid = newc->uid;
1113 }
1114 cpp = NULL;
1115 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001116 }
Simon Kelley45cca582013-10-15 10:20:13 +01001117
1118 p1 = endrr;
1119 if (!CHECK_LEN(header, p1, qlen, 0))
1120 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001121 }
1122
Simon Kelley28866e92011-02-14 20:19:14 +00001123 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001124 {
1125 if (!searched_soa)
1126 {
1127 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001128 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001129 }
1130 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001131 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001132 if (ttl || cpp)
1133 {
Simon Kelley0435d042014-01-08 18:22:37 +00001134 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
Simon Kelley26128d22004-11-14 16:43:54 +00001135 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001136 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001137 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001138 cpp->addr.cname.uid = newc->uid;
1139 }
1140 }
1141 }
1142 }
1143 }
1144
Simon Kelley1023dcb2012-04-09 18:00:08 +01001145 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +01001146 Don't cache replies from non-recursive nameservers, since we may get a
1147 reply containing a CNAME but not its target, even though the target
1148 does exist. */
1149 if (!(header->hb3 & HB3_TC) &&
1150 !(header->hb4 & HB4_CD) &&
1151 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +00001152 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +00001153 cache_end_insert();
1154
1155 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001156}
1157
1158/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001159 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +00001160unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001161{
1162 unsigned char *p = (unsigned char *)(header+1);
1163 int qtype, qclass;
1164
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001165 if (typep)
1166 *typep = 0;
1167
Simon Kelley572b41e2011-02-18 18:11:18 +00001168 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001169 return 0; /* must be exactly one query. */
1170
Simon Kelley9009d742008-11-14 20:04:27 +00001171 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001172 return 0; /* bad packet */
1173
1174 GETSHORT(qtype, p);
1175 GETSHORT(qclass, p);
1176
Simon Kelley0a852542005-03-23 20:28:59 +00001177 if (typep)
1178 *typep = qtype;
1179
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001180 if (qclass == C_IN)
1181 {
1182 if (qtype == T_A)
1183 return F_IPV4;
1184 if (qtype == T_AAAA)
1185 return F_IPV6;
1186 if (qtype == T_ANY)
1187 return F_IPV4 | F_IPV6;
1188 }
1189
1190 return F_QUERY;
1191}
1192
1193
Simon Kelley572b41e2011-02-18 18:11:18 +00001194size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001195 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001196{
1197 unsigned char *p = skip_questions(header, qlen);
1198
Simon Kelley572b41e2011-02-18 18:11:18 +00001199 /* clear authoritative and truncated flags, set QR flag */
1200 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1201 /* set RA flag */
1202 header->hb4 |= HB4_RA;
1203
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001204 header->nscount = htons(0);
1205 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001206 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001207 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001208 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001209 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001210 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001211 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001212 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001213 else if (p && flags == F_IPV4)
1214 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001215 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001216 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001217 header->hb3 |= HB3_AA;
1218 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001219 }
1220#ifdef HAVE_IPV6
1221 else if (p && flags == F_IPV6)
1222 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001223 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001224 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001225 header->hb3 |= HB3_AA;
1226 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001227 }
1228#endif
1229 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001230 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001231
1232 return p - (unsigned char *)header;
1233}
Simon Kelley36717ee2004-09-20 19:20:58 +01001234
1235/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001236int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001237{
1238 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001239 struct mx_srv_record *mx;
1240 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001241 struct interface_name *intr;
1242 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001243 struct naptr *naptr;
1244
Simon Kelley12fae492014-02-04 22:03:06 +00001245 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +00001246 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +01001247 return 1;
1248
Simon Kelley7de060b2011-08-26 17:24:52 +01001249 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1250 if (hostname_isequal(name, naptr->name))
1251 return 1;
1252
1253 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001254 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001255 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001256
Simon Kelley0a852542005-03-23 20:28:59 +00001257 for (txt = daemon->txt; txt; txt = txt->next)
1258 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001259 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001260
1261 for (intr = daemon->int_names; intr; intr = intr->next)
1262 if (hostname_isequal(name, intr->name))
1263 return 1;
1264
1265 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1266 if (hostname_isequal(name, ptr->name))
1267 return 1;
1268
Simon Kelley36717ee2004-09-20 19:20:58 +01001269 return 0;
1270}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001271
1272/* Is the packet a reply with the answer address equal to addr?
1273 If so mung is into an NXDOMAIN reply and also put that information
1274 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001275int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001276 struct bogus_addr *baddr, time_t now)
1277{
1278 unsigned char *p;
1279 int i, qtype, qclass, rdlen;
1280 unsigned long ttl;
1281 struct bogus_addr *baddrp;
1282
1283 /* skip over questions */
1284 if (!(p = skip_questions(header, qlen)))
1285 return 0; /* bad packet */
1286
Simon Kelley5aabfc72007-08-29 11:24:47 +01001287 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001288 {
Simon Kelley9009d742008-11-14 20:04:27 +00001289 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001290 return 0; /* bad packet */
1291
1292 GETSHORT(qtype, p);
1293 GETSHORT(qclass, p);
1294 GETLONG(ttl, p);
1295 GETSHORT(rdlen, p);
1296
1297 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001298 {
1299 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1300 return 0;
1301
1302 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1303 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1304 {
1305 /* Found a bogus address. Insert that info here, since there no SOA record
1306 to get the ttl from in the normal processing */
1307 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001308 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001309 cache_end_insert();
1310
1311 return 1;
1312 }
1313 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001314
Simon Kelley9009d742008-11-14 20:04:27 +00001315 if (!ADD_RDLEN(header, p, qlen, rdlen))
1316 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001317 }
1318
1319 return 0;
1320}
1321
Simon Kelleyb75e9362012-12-07 11:50:41 +00001322int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001323 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001324{
1325 va_list ap;
1326 unsigned char *sav, *p = *pp;
1327 int j;
1328 unsigned short usval;
1329 long lval;
1330 char *sval;
1331
1332 if (truncp && *truncp)
1333 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001334
1335 va_start(ap, format); /* make ap point to 1st unamed argument */
1336
Simon Kelleyb75e9362012-12-07 11:50:41 +00001337 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001338 {
1339 PUTSHORT(nameoffset | 0xc000, p);
1340 }
1341 else
1342 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001343 char *name = va_arg(ap, char *);
1344 if (name)
1345 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001346 if (nameoffset < 0)
1347 {
1348 PUTSHORT(-nameoffset | 0xc000, p);
1349 }
1350 else
1351 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001352 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001353
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001354 PUTSHORT(type, p);
1355 PUTSHORT(class, p);
1356 PUTLONG(ttl, p); /* TTL */
1357
1358 sav = p; /* Save pointer to RDLength field */
1359 PUTSHORT(0, p); /* Placeholder RDLength */
1360
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001361 for (; *format; format++)
1362 switch (*format)
1363 {
1364#ifdef HAVE_IPV6
1365 case '6':
1366 sval = va_arg(ap, char *);
1367 memcpy(p, sval, IN6ADDRSZ);
1368 p += IN6ADDRSZ;
1369 break;
1370#endif
1371
1372 case '4':
1373 sval = va_arg(ap, char *);
1374 memcpy(p, sval, INADDRSZ);
1375 p += INADDRSZ;
1376 break;
1377
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001378 case 'b':
1379 usval = va_arg(ap, int);
1380 *p++ = usval;
1381 break;
1382
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001383 case 's':
1384 usval = va_arg(ap, int);
1385 PUTSHORT(usval, p);
1386 break;
1387
1388 case 'l':
1389 lval = va_arg(ap, long);
1390 PUTLONG(lval, p);
1391 break;
1392
1393 case 'd':
1394 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001395 if (offset)
1396 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001397 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001398 *p++ = 0;
1399 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001400
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001401 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001402 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001403 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001404 if (usval != 0)
1405 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001406 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001407 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001408
1409 case 'z':
1410 sval = va_arg(ap, char *);
1411 usval = sval ? strlen(sval) : 0;
1412 if (usval > 255)
1413 usval = 255;
1414 *p++ = (unsigned char)usval;
1415 memcpy(p, sval, usval);
1416 p += usval;
1417 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001418 }
1419
1420 va_end(ap); /* clean up variable argument pointer */
1421
1422 j = p - sav - 2;
1423 PUTSHORT(j, sav); /* Now, store real RDLength */
1424
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001425 /* check for overflow of buffer */
1426 if (limit && ((unsigned char *)limit - p) < 0)
1427 {
1428 if (truncp)
1429 *truncp = 1;
1430 return 0;
1431 }
1432
1433 *pp = p;
1434 return 1;
1435}
1436
Simon Kelley9009d742008-11-14 20:04:27 +00001437static unsigned long crec_ttl(struct crec *crecp, time_t now)
1438{
1439 /* Return 0 ttl for DHCP entries, which might change
1440 before the lease expires. */
1441
1442 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1443 return daemon->local_ttl;
1444
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001445 /* Return the Max TTL value if it is lower then the actual TTL */
1446 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1447 return crecp->ttd - now;
1448 else
1449 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001450}
1451
1452
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001453/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001454size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001455 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelley613ad152014-02-25 23:02:28 +00001456 time_t now, int *ad_reqd, int *do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001457{
Simon Kelley3be34542004-09-11 19:12:13 +01001458 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001459 unsigned char *p, *ansp, *pheader;
Simon Kelley832af0b2007-01-21 20:01:28 +00001460 int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001461 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001462 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001463 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001464 int q, ans, anscount = 0, addncount = 0;
Simon Kelleya25720a2014-01-14 23:13:55 +00001465 int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001466 int is_sign;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001467 struct crec *crecp;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001468 int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001469 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001470 size_t len;
Simon Kelley0a852542005-03-23 20:28:59 +00001471
Simon Kelleye243c072014-02-06 18:14:09 +00001472 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001473 if (header->hb4 & HB4_CD)
1474 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001475
1476 /* RFC 6840 5.7 */
1477 *ad_reqd = header->hb4 & HB4_AD;
Simon Kelley613ad152014-02-25 23:02:28 +00001478 *do_bit = 0;
1479
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001480 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1481 partial replies, so we have to do a dry run to see if we can answer
1482 the query. We check to see if the do bit is set, if so we always
1483 forward rather than answering from the cache, which doesn't include
Simon Kelleya25720a2014-01-14 23:13:55 +00001484 security information, unless we're in DNSSEC validation mode. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001485
Simon Kelley832af0b2007-01-21 20:01:28 +00001486 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001487 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001488 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001489 unsigned char *psave = pheader;
1490
Simon Kelleya25720a2014-01-14 23:13:55 +00001491 have_pseudoheader = 1;
1492
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001493 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001494 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001495 GETSHORT(flags, pheader);
1496
Simon Kelley613ad152014-02-25 23:02:28 +00001497 if ((sec_reqd = flags & 0x8000))
1498 *do_bit = 1;/* do bit */
Simon Kelley83349b82014-02-10 21:02:01 +00001499 *ad_reqd = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001500
1501 /* If our client is advertising a larger UDP packet size
1502 than we allow, trim it so that we don't get an overlarge
1503 response from upstream */
1504
Simon Kelley832af0b2007-01-21 20:01:28 +00001505 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001506 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001507
1508 dryrun = 1;
1509 }
1510
Simon Kelley572b41e2011-02-18 18:11:18 +00001511 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001512 return 0;
1513
Simon Kelley0a852542005-03-23 20:28:59 +00001514 for (rec = daemon->mxnames; rec; rec = rec->next)
1515 rec->offset = 0;
1516
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001517 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001518 /* determine end of question section (we put answers there) */
1519 if (!(ansp = skip_questions(header, qlen)))
1520 return 0; /* bad packet */
1521
1522 /* now process each question, answers go in RRs after the question */
1523 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001524
Simon Kelley5aabfc72007-08-29 11:24:47 +01001525 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001526 {
1527 /* save pointer to name for copying into answers */
1528 nameoffset = p - (unsigned char *)header;
1529
1530 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001531 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001532 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001533
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001534 GETSHORT(qtype, p);
1535 GETSHORT(qclass, p);
1536
1537 ans = 0; /* have we answered this question */
1538
Simon Kelley0a852542005-03-23 20:28:59 +00001539 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001540 {
Simon Kelley0a852542005-03-23 20:28:59 +00001541 struct txt_record *t;
1542 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001543 {
Simon Kelley0a852542005-03-23 20:28:59 +00001544 if (t->class == qclass && hostname_isequal(name, t->name))
1545 {
1546 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001547 if (!dryrun)
1548 {
Simon Kelley28866e92011-02-14 20:19:14 +00001549 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001550 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1551 daemon->local_ttl, NULL,
1552 T_TXT, t->class, "t", t->len, t->txt))
1553 anscount++;
1554
1555 }
Simon Kelley0a852542005-03-23 20:28:59 +00001556 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001557 }
Simon Kelley0a852542005-03-23 20:28:59 +00001558 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001559
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001560#ifdef HAVE_DNSSEC
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001561 if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001562 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001563 int gotone = 0;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001564 struct blockdata *keydata;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001565
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001566 /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001567 if (sec_reqd)
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001568 {
Simon Kelley5f938532014-02-03 16:44:32 +00001569 crecp = NULL;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001570 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1571 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
1572 break;
1573 }
1574
1575 if (!sec_reqd || crecp)
1576 {
1577 if (qtype == T_DS)
1578 {
1579 crecp = NULL;
1580 while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
1581 if (crecp->uid == qclass)
1582 {
Simon Kelleyb8eac192014-02-27 14:30:03 +00001583 gotone = 1;
1584 if (!dryrun)
1585 {
1586 if (crecp->flags & F_NEG)
1587 {
1588 if (crecp->flags & F_NXDOMAIN)
1589 nxdomain = 1;
1590 log_query(F_UPSTREAM, name, NULL, "secure no DS");
1591 }
1592 else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
1593 {
1594 struct all_addr a;
1595 a.addr.keytag = crecp->addr.ds.keytag;
1596 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
1597 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1598 crec_ttl(crecp, now), &nameoffset,
1599 T_DS, qclass, "sbbt",
1600 crecp->addr.ds.keytag, crecp->addr.ds.algo,
1601 crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
1602 anscount++;
1603
1604 }
1605 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001606 }
1607 }
1608 else /* DNSKEY */
1609 {
1610 crecp = NULL;
1611 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
1612 if (crecp->uid == qclass)
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001613 {
Simon Kelleyee415862014-02-11 11:07:22 +00001614 gotone = 1;
1615 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
1616 {
1617 struct all_addr a;
1618 a.addr.keytag = crecp->addr.key.keytag;
1619 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
1620 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1621 crec_ttl(crecp, now), &nameoffset,
1622 T_DNSKEY, qclass, "sbbt",
1623 crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
1624 anscount++;
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001625 }
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001626 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001627 }
Simon Kelley5f938532014-02-03 16:44:32 +00001628 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001629
Simon Kelley5f938532014-02-03 16:44:32 +00001630 /* Now do RRSIGs */
1631 if (gotone)
1632 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001633 ans = 1;
1634 auth = 0;
1635 if (!dryrun && sec_reqd)
1636 {
1637 crecp = NULL;
1638 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1639 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
1640 (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
1641 {
Simon Kelley5f938532014-02-03 16:44:32 +00001642 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1643 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001644 T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
1645 anscount++;
1646 }
1647 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001648 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001649 }
1650#endif
1651
Simon Kelley0a852542005-03-23 20:28:59 +00001652 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001653 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001654 struct txt_record *t;
1655
1656 for (t = daemon->rr; t; t = t->next)
1657 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1658 {
1659 ans = 1;
1660 if (!dryrun)
1661 {
1662 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1663 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1664 daemon->local_ttl, NULL,
1665 t->class, C_IN, "t", t->len, t->txt))
1666 anscount ++;
1667 }
1668 }
1669
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001670 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001671 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001672 /* see if it's w.z.y.z.in-addr.arpa format */
1673 int is_arpa = in_arpa_name_2_addr(name, &addr);
1674 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001675 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001676
1677 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1678 if (hostname_isequal(name, ptr->name))
1679 break;
1680
Simon Kelleyf2621c72007-04-29 19:47:21 +01001681 if (is_arpa == F_IPV4)
1682 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001683 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001684 struct addrlist *addrlist;
1685
Simon Kelley376d48c2013-11-13 13:04:30 +00001686 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1687 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001688 break;
1689
1690 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001691 break;
1692 else
1693 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1694 intr = intr->next;
1695 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001696#ifdef HAVE_IPV6
1697 else if (is_arpa == F_IPV6)
1698 for (intr = daemon->int_names; intr; intr = intr->next)
1699 {
1700 struct addrlist *addrlist;
1701
Simon Kelley376d48c2013-11-13 13:04:30 +00001702 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1703 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001704 break;
1705
1706 if (addrlist)
1707 break;
1708 else
1709 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1710 intr = intr->next;
1711 }
1712#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001713
1714 if (intr)
1715 {
1716 ans = 1;
1717 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001718 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001719 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001720 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1721 daemon->local_ttl, NULL,
1722 T_PTR, C_IN, "d", intr->name))
1723 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001724 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001725 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001726 else if (ptr)
1727 {
1728 ans = 1;
1729 if (!dryrun)
1730 {
Simon Kelley28866e92011-02-14 20:19:14 +00001731 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001732 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001733 if (hostname_isequal(name, ptr->name) &&
1734 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1735 daemon->local_ttl, NULL,
1736 T_PTR, C_IN, "d", ptr->ptr))
1737 anscount++;
1738
Simon Kelley832af0b2007-01-21 20:01:28 +00001739 }
1740 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001741 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001742 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001743 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001744 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001745 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1746 crecp = NULL;
1747#ifdef HAVE_DNSSEC
1748 else if (crecp->flags & F_DNSSECOK)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001749 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001750 int gotsig = 0;
Simon Kelley12fae492014-02-04 22:03:06 +00001751 struct crec *rr_crec = NULL;
1752
1753 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001754 {
Simon Kelley12fae492014-02-04 22:03:06 +00001755 if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001756 {
Simon Kelley12fae492014-02-04 22:03:06 +00001757 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001758 gotsig = 1;
1759
1760 if (!dryrun &&
1761 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001762 rr_crec->ttd - now, &nameoffset,
Simon Kelley0744ca62014-01-25 16:40:15 +00001763 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
1764 anscount++;
1765 }
1766 }
Simon Kelley12fae492014-02-04 22:03:06 +00001767
1768 if (!gotsig)
1769 crecp = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001770 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001771#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001772 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001773
1774 if (crecp)
1775 {
1776 do
1777 {
1778 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1779 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1780 continue;
1781
1782 if (!(crecp->flags & F_DNSSECOK))
1783 sec_data = 0;
1784
1785 if (crecp->flags & F_NEG)
1786 {
1787 ans = 1;
1788 auth = 0;
1789 if (crecp->flags & F_NXDOMAIN)
1790 nxdomain = 1;
1791 if (!dryrun)
1792 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1793 }
1794 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
1795 {
1796 ans = 1;
1797 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1798 auth = 0;
1799 if (!dryrun)
1800 {
1801 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1802 record_source(crecp->uid));
1803
1804 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1805 crec_ttl(crecp, now), NULL,
1806 T_PTR, C_IN, "d", cache_get_name(crecp)))
1807 anscount++;
1808 }
1809 }
1810 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1811 }
1812 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001813 else if (is_rev_synth(is_arpa, &addr, name))
1814 {
1815 ans = 1;
1816 if (!dryrun)
1817 {
1818 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1819
1820 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1821 daemon->local_ttl, NULL,
1822 T_PTR, C_IN, "d", name))
1823 anscount++;
1824 }
1825 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001826 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001827 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001828 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001829 {
1830 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1831 ans = 1;
1832 nxdomain = 1;
1833 if (!dryrun)
1834 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001835 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001836 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001837 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001838
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001839 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1840 {
1841 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001842 struct interface_name *intr;
1843
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001844 if (flag == F_IPV6)
1845#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001846 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001847#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001848 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001849#endif
1850
1851 if (qtype != type && qtype != T_ANY)
1852 continue;
1853
Simon Kelley316e2732010-01-22 20:16:09 +00001854 /* Check for "A for A" queries; be rather conservative
1855 about what looks like dotted-quad. */
1856 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001857 {
Simon Kelley316e2732010-01-22 20:16:09 +00001858 char *cp;
1859 unsigned int i, a;
1860 int x;
1861
1862 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001863 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001864 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001865 {
1866 i = 5;
1867 break;
1868 }
1869
1870 a = (a << 8) + x;
1871
1872 if (*cp == '.')
1873 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001874 }
Simon Kelley316e2732010-01-22 20:16:09 +00001875
1876 if (i == 4)
1877 {
1878 ans = 1;
1879 if (!dryrun)
1880 {
1881 addr.addr.addr4.s_addr = htonl(a);
1882 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1883 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1884 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1885 anscount++;
1886 }
1887 continue;
1888 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001889 }
1890
Simon Kelleyf2621c72007-04-29 19:47:21 +01001891 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001892 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001893 for (intr = daemon->int_names; intr; intr = intr->next)
1894 if (hostname_isequal(name, intr->name))
1895 break;
1896
1897 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001898 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001899 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001900 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001901
Simon Kelley115ac3e2013-05-20 11:28:32 +01001902 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001903
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001904 for (intr = daemon->int_names; intr; intr = intr->next)
1905 if (hostname_isequal(name, intr->name))
1906 {
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001907 ans = 1;
1908 if (!dryrun)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001909 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001910
1911 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1912#ifdef HAVE_IPV6
1913 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
1914#endif
1915 {
1916 gotit = 1;
1917 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1918 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1919 daemon->local_ttl, NULL, type, C_IN,
1920 type == T_A ? "4" : "6", &addrlist->addr))
1921 anscount++;
1922 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001923 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001924 }
1925
1926 if (!dryrun && !gotit)
1927 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1928
Simon Kelley115ac3e2013-05-20 11:28:32 +01001929 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001930 }
1931
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001932 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00001933 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001934 {
1935 int localise = 0;
1936
1937 /* See if a putative address is on the network from which we recieved
1938 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001939 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001940 {
1941 struct crec *save = crecp;
1942 do {
1943 if ((crecp->flags & F_HOSTS) &&
1944 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1945 {
1946 localise = 1;
1947 break;
1948 }
1949 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1950 crecp = save;
1951 }
Simon Kelley824202e2014-01-23 20:59:46 +00001952
Simon Kelley0744ca62014-01-25 16:40:15 +00001953 /* If the client asked for DNSSEC and we can't provide RRSIGs, either
1954 because we've not doing DNSSEC or the cached answer is signed by negative,
1955 don't answer from the cache, forward instead. */
1956 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley824202e2014-01-23 20:59:46 +00001957 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001958 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1959 crecp = NULL;
1960#ifdef HAVE_DNSSEC
1961 else if (crecp->flags & F_DNSSECOK)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001962 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001963 /* We're returning validated data, need to return the RRSIG too. */
Simon Kelley12fae492014-02-04 22:03:06 +00001964 struct crec *rr_crec = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001965 int sigtype = type;
1966 /* The signature may have expired even though the data is still in cache,
1967 forward instead of answering from cache if so. */
1968 int gotsig = 0;
1969
1970 if (crecp->flags & F_CNAME)
1971 sigtype = T_CNAME;
1972
Simon Kelley12fae492014-02-04 22:03:06 +00001973 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001974 {
Simon Kelley12fae492014-02-04 22:03:06 +00001975 if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001976 {
Simon Kelley12fae492014-02-04 22:03:06 +00001977 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001978 gotsig = 1;
1979
1980 if (!dryrun &&
1981 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001982 rr_crec->ttd - now, &nameoffset,
1983 T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
Simon Kelley0744ca62014-01-25 16:40:15 +00001984 anscount++;
1985 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001986 }
Simon Kelley12fae492014-02-04 22:03:06 +00001987
1988 if (!gotsig)
1989 crecp = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001990 }
Simon Kelley824202e2014-01-23 20:59:46 +00001991#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001992 }
1993
Simon Kelley824202e2014-01-23 20:59:46 +00001994 if (crecp)
1995 do
1996 {
1997 /* don't answer wildcard queries with data not from /etc/hosts
1998 or DHCP leases */
1999 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
2000 break;
2001
2002 if (!(crecp->flags & F_DNSSECOK))
2003 sec_data = 0;
2004
2005 if (crecp->flags & F_CNAME)
2006 {
2007 char *cname_target = cache_get_cname_target(crecp);
2008
2009 if (!dryrun)
2010 {
2011 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2012 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2013 crec_ttl(crecp, now), &nameoffset,
2014 T_CNAME, C_IN, "d", cname_target))
2015 anscount++;
2016 }
2017
2018 strcpy(name, cname_target);
2019 /* check if target interface_name */
2020 if (crecp->addr.cname.uid == -1)
2021 goto intname_restart;
2022 else
2023 goto cname_restart;
2024 }
2025
2026 if (crecp->flags & F_NEG)
2027 {
2028 /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
2029 is cached and the client wants DNSSEC, forward rather than answering from the cache */
2030 if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
2031 {
2032 ans = 1;
2033 auth = 0;
2034 if (crecp->flags & F_NXDOMAIN)
2035 nxdomain = 1;
2036 if (!dryrun)
2037 log_query(crecp->flags, name, NULL, NULL);
2038 }
2039 }
2040 else
2041 {
2042 /* If we are returning local answers depending on network,
2043 filter here. */
2044 if (localise &&
2045 (crecp->flags & F_HOSTS) &&
2046 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
2047 continue;
2048
2049 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
2050 auth = 0;
2051
2052 ans = 1;
2053 if (!dryrun)
2054 {
2055 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
2056 record_source(crecp->uid));
2057
2058 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2059 crec_ttl(crecp, now), NULL, type, C_IN,
2060 type == T_A ? "4" : "6", &crecp->addr))
2061 anscount++;
2062 }
2063 }
2064 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002065 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002066 else if (is_name_synthetic(flag, name, &addr))
2067 {
2068 ans = 1;
2069 if (!dryrun)
2070 {
2071 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
2072 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2073 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
2074 anscount++;
2075 }
2076 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002077 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002078
2079 if (qtype == T_CNAME || qtype == T_ANY)
2080 {
2081 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002082 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002083 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00002084 if (!(crecp->flags & F_DNSSECOK))
2085 sec_data = 0;
2086
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002087 ans = 1;
2088 if (!dryrun)
2089 {
2090 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2091 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2092 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01002093 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002094 anscount++;
2095 }
2096 }
2097 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002098
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002099 if (qtype == T_MX || qtype == T_ANY)
2100 {
2101 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00002102 for (rec = daemon->mxnames; rec; rec = rec->next)
2103 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002104 {
2105 ans = found = 1;
2106 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002107 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002108 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002109 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00002110 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2111 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
2112 {
2113 anscount++;
2114 if (rec->target)
2115 rec->offset = offset;
2116 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002117 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002118 }
2119
Simon Kelley28866e92011-02-14 20:19:14 +00002120 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002121 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002122 {
2123 ans = 1;
2124 if (!dryrun)
2125 {
Simon Kelley28866e92011-02-14 20:19:14 +00002126 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002127 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
2128 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00002129 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002130 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002131 }
2132 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002133 }
2134
2135 if (qtype == T_SRV || qtype == T_ANY)
2136 {
2137 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00002138 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
2139
Simon Kelley0a852542005-03-23 20:28:59 +00002140 for (rec = daemon->mxnames; rec; rec = rec->next)
2141 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002142 {
2143 found = ans = 1;
2144 if (!dryrun)
2145 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002146 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002147 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002148 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00002149 &offset, T_SRV, C_IN, "sssd",
2150 rec->priority, rec->weight, rec->srvport, rec->target))
2151 {
2152 anscount++;
2153 if (rec->target)
2154 rec->offset = offset;
2155 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002156 }
Simon Kelley28866e92011-02-14 20:19:14 +00002157
2158 /* unlink first SRV record found */
2159 if (!move)
2160 {
2161 move = rec;
2162 *up = rec->next;
2163 }
2164 else
2165 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002166 }
Simon Kelley28866e92011-02-14 20:19:14 +00002167 else
2168 up = &rec->next;
2169
2170 /* put first SRV record back at the end. */
2171 if (move)
2172 {
2173 *up = move;
2174 move->next = NULL;
2175 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002176
Simon Kelley28866e92011-02-14 20:19:14 +00002177 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002178 {
2179 ans = 1;
2180 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002181 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002182 }
2183 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002184
2185 if (qtype == T_NAPTR || qtype == T_ANY)
2186 {
2187 struct naptr *na;
2188 for (na = daemon->naptr; na; na = na->next)
2189 if (hostname_isequal(name, na->name))
2190 {
2191 ans = 1;
2192 if (!dryrun)
2193 {
Simon Kelley28866e92011-02-14 20:19:14 +00002194 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01002195 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2196 NULL, T_NAPTR, C_IN, "sszzzd",
2197 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
2198 anscount++;
2199 }
2200 }
2201 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002202
2203 if (qtype == T_MAILB)
2204 ans = 1, nxdomain = 1;
2205
Simon Kelley28866e92011-02-14 20:19:14 +00002206 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002207 {
2208 ans = 1;
2209 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002210 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002211 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002212 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002213
2214 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002215 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002216 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002217
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002218 if (dryrun)
2219 {
2220 dryrun = 0;
2221 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002222 }
2223
Simon Kelley0a852542005-03-23 20:28:59 +00002224 /* create an additional data section, for stuff in SRV and MX record replies. */
2225 for (rec = daemon->mxnames; rec; rec = rec->next)
2226 if (rec->offset != 0)
2227 {
2228 /* squash dupes */
2229 struct mx_srv_record *tmp;
2230 for (tmp = rec->next; tmp; tmp = tmp->next)
2231 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2232 tmp->offset = 0;
2233
2234 crecp = NULL;
2235 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2236 {
Simon Kelley0a852542005-03-23 20:28:59 +00002237#ifdef HAVE_IPV6
2238 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2239#else
2240 int type = T_A;
2241#endif
2242 if (crecp->flags & F_NEG)
2243 continue;
2244
Simon Kelley9009d742008-11-14 20:04:27 +00002245 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2246 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002247 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2248 addncount++;
2249 }
2250 }
2251
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002252 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002253 /* clear authoritative and truncated flags, set QR flag */
2254 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2255 /* set RA flag */
2256 header->hb4 |= HB4_RA;
2257
2258 /* authoritive - only hosts and DHCP derived names. */
2259 if (auth)
2260 header->hb3 |= HB3_AA;
2261
2262 /* truncation */
2263 if (trunc)
2264 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002265
Simon Kelley45cca582013-10-15 10:20:13 +01002266 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002267 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002268 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002269 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002270 header->ancount = htons(anscount);
2271 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002272 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00002273
Simon Kelleya25720a2014-01-14 23:13:55 +00002274 len = ansp - (unsigned char *)header;
2275
2276 if (have_pseudoheader)
Simon Kelleye243c072014-02-06 18:14:09 +00002277 len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
2278
Simon Kelley83349b82014-02-10 21:02:01 +00002279 if (*ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00002280 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00002281 else
2282 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00002283
Simon Kelley7c286122014-01-27 21:38:11 +00002284 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002285}
2286