blob: b8e0f1866dd792e4ec4a3ac9749ade4cc86eba00 [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 Kelley572b41e2011-02-18 18:11:18 +0000340static unsigned 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 {
604 if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
605 match = 1;
606#ifdef HAVE_IPV6
607 else
608 if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
609 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,
1456 time_t now, int *ad_reqd)
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;
1478
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001479 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1480 partial replies, so we have to do a dry run to see if we can answer
1481 the query. We check to see if the do bit is set, if so we always
1482 forward rather than answering from the cache, which doesn't include
Simon Kelleya25720a2014-01-14 23:13:55 +00001483 security information, unless we're in DNSSEC validation mode. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001484
Simon Kelley832af0b2007-01-21 20:01:28 +00001485 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001486 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001487 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001488 unsigned char *psave = pheader;
1489
Simon Kelleya25720a2014-01-14 23:13:55 +00001490 have_pseudoheader = 1;
1491
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001492 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001493 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001494 GETSHORT(flags, pheader);
1495
1496 sec_reqd = flags & 0x8000; /* do bit */
Simon Kelley83349b82014-02-10 21:02:01 +00001497 *ad_reqd = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001498
1499 /* If our client is advertising a larger UDP packet size
1500 than we allow, trim it so that we don't get an overlarge
1501 response from upstream */
1502
Simon Kelley832af0b2007-01-21 20:01:28 +00001503 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001504 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001505
1506 dryrun = 1;
1507 }
1508
Simon Kelley572b41e2011-02-18 18:11:18 +00001509 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001510 return 0;
1511
Simon Kelley0a852542005-03-23 20:28:59 +00001512 for (rec = daemon->mxnames; rec; rec = rec->next)
1513 rec->offset = 0;
1514
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001515 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001516 /* determine end of question section (we put answers there) */
1517 if (!(ansp = skip_questions(header, qlen)))
1518 return 0; /* bad packet */
1519
1520 /* now process each question, answers go in RRs after the question */
1521 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001522
Simon Kelley5aabfc72007-08-29 11:24:47 +01001523 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001524 {
1525 /* save pointer to name for copying into answers */
1526 nameoffset = p - (unsigned char *)header;
1527
1528 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001529 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001530 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001531
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001532 GETSHORT(qtype, p);
1533 GETSHORT(qclass, p);
1534
1535 ans = 0; /* have we answered this question */
1536
Simon Kelley0a852542005-03-23 20:28:59 +00001537 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001538 {
Simon Kelley0a852542005-03-23 20:28:59 +00001539 struct txt_record *t;
1540 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001541 {
Simon Kelley0a852542005-03-23 20:28:59 +00001542 if (t->class == qclass && hostname_isequal(name, t->name))
1543 {
1544 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001545 if (!dryrun)
1546 {
Simon Kelley28866e92011-02-14 20:19:14 +00001547 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001548 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1549 daemon->local_ttl, NULL,
1550 T_TXT, t->class, "t", t->len, t->txt))
1551 anscount++;
1552
1553 }
Simon Kelley0a852542005-03-23 20:28:59 +00001554 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001555 }
Simon Kelley0a852542005-03-23 20:28:59 +00001556 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001557
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001558#ifdef HAVE_DNSSEC
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001559 if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001560 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001561 int gotone = 0;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001562 struct blockdata *keydata;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001563
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001564 /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001565 if (sec_reqd)
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001566 {
Simon Kelley5f938532014-02-03 16:44:32 +00001567 crecp = NULL;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001568 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1569 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
1570 break;
1571 }
1572
1573 if (!sec_reqd || crecp)
1574 {
1575 if (qtype == T_DS)
1576 {
1577 crecp = NULL;
1578 while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
1579 if (crecp->uid == qclass)
1580 {
1581 gotone = 1;
1582 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
1583 {
1584 struct all_addr a;
1585 a.addr.keytag = crecp->addr.ds.keytag;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001586 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
1587 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1588 crec_ttl(crecp, now), &nameoffset,
1589 T_DS, qclass, "sbbt",
1590 crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
1591 anscount++;
1592
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001593 }
1594 }
1595 }
1596 else /* DNSKEY */
1597 {
1598 crecp = NULL;
1599 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
1600 if (crecp->uid == qclass)
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001601 {
Simon Kelleyee415862014-02-11 11:07:22 +00001602 gotone = 1;
1603 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
1604 {
1605 struct all_addr a;
1606 a.addr.keytag = crecp->addr.key.keytag;
1607 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
1608 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1609 crec_ttl(crecp, now), &nameoffset,
1610 T_DNSKEY, qclass, "sbbt",
1611 crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
1612 anscount++;
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001613 }
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001614 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001615 }
Simon Kelley5f938532014-02-03 16:44:32 +00001616 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001617
Simon Kelley5f938532014-02-03 16:44:32 +00001618 /* Now do RRSIGs */
1619 if (gotone)
1620 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001621 ans = 1;
1622 auth = 0;
1623 if (!dryrun && sec_reqd)
1624 {
1625 crecp = NULL;
1626 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1627 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
1628 (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
1629 {
Simon Kelley5f938532014-02-03 16:44:32 +00001630 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1631 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001632 T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
1633 anscount++;
1634 }
1635 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001636 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001637 }
1638#endif
1639
Simon Kelley0a852542005-03-23 20:28:59 +00001640 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001641 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001642 struct txt_record *t;
1643
1644 for (t = daemon->rr; t; t = t->next)
1645 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1646 {
1647 ans = 1;
1648 if (!dryrun)
1649 {
1650 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1651 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1652 daemon->local_ttl, NULL,
1653 t->class, C_IN, "t", t->len, t->txt))
1654 anscount ++;
1655 }
1656 }
1657
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001658 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001659 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001660 /* see if it's w.z.y.z.in-addr.arpa format */
1661 int is_arpa = in_arpa_name_2_addr(name, &addr);
1662 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001663 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001664
1665 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1666 if (hostname_isequal(name, ptr->name))
1667 break;
1668
Simon Kelleyf2621c72007-04-29 19:47:21 +01001669 if (is_arpa == F_IPV4)
1670 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001671 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001672 struct addrlist *addrlist;
1673
Simon Kelley376d48c2013-11-13 13:04:30 +00001674 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1675 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001676 break;
1677
1678 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001679 break;
1680 else
1681 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1682 intr = intr->next;
1683 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001684#ifdef HAVE_IPV6
1685 else if (is_arpa == F_IPV6)
1686 for (intr = daemon->int_names; intr; intr = intr->next)
1687 {
1688 struct addrlist *addrlist;
1689
Simon Kelley376d48c2013-11-13 13:04:30 +00001690 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1691 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001692 break;
1693
1694 if (addrlist)
1695 break;
1696 else
1697 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1698 intr = intr->next;
1699 }
1700#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001701
1702 if (intr)
1703 {
1704 ans = 1;
1705 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001706 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001707 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001708 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1709 daemon->local_ttl, NULL,
1710 T_PTR, C_IN, "d", intr->name))
1711 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001712 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001713 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001714 else if (ptr)
1715 {
1716 ans = 1;
1717 if (!dryrun)
1718 {
Simon Kelley28866e92011-02-14 20:19:14 +00001719 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001720 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001721 if (hostname_isequal(name, ptr->name) &&
1722 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1723 daemon->local_ttl, NULL,
1724 T_PTR, C_IN, "d", ptr->ptr))
1725 anscount++;
1726
Simon Kelley832af0b2007-01-21 20:01:28 +00001727 }
1728 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001729 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001730 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001731 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001732 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001733 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1734 crecp = NULL;
1735#ifdef HAVE_DNSSEC
1736 else if (crecp->flags & F_DNSSECOK)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001737 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001738 int gotsig = 0;
Simon Kelley12fae492014-02-04 22:03:06 +00001739 struct crec *rr_crec = NULL;
1740
1741 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001742 {
Simon Kelley12fae492014-02-04 22:03:06 +00001743 if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001744 {
Simon Kelley12fae492014-02-04 22:03:06 +00001745 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001746 gotsig = 1;
1747
1748 if (!dryrun &&
1749 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001750 rr_crec->ttd - now, &nameoffset,
Simon Kelley0744ca62014-01-25 16:40:15 +00001751 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
1752 anscount++;
1753 }
1754 }
Simon Kelley12fae492014-02-04 22:03:06 +00001755
1756 if (!gotsig)
1757 crecp = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001758 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001759#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001760 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001761
1762 if (crecp)
1763 {
1764 do
1765 {
1766 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1767 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1768 continue;
1769
1770 if (!(crecp->flags & F_DNSSECOK))
1771 sec_data = 0;
1772
1773 if (crecp->flags & F_NEG)
1774 {
1775 ans = 1;
1776 auth = 0;
1777 if (crecp->flags & F_NXDOMAIN)
1778 nxdomain = 1;
1779 if (!dryrun)
1780 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1781 }
1782 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
1783 {
1784 ans = 1;
1785 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1786 auth = 0;
1787 if (!dryrun)
1788 {
1789 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1790 record_source(crecp->uid));
1791
1792 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1793 crec_ttl(crecp, now), NULL,
1794 T_PTR, C_IN, "d", cache_get_name(crecp)))
1795 anscount++;
1796 }
1797 }
1798 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1799 }
1800 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001801 else if (is_rev_synth(is_arpa, &addr, name))
1802 {
1803 ans = 1;
1804 if (!dryrun)
1805 {
1806 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1807
1808 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1809 daemon->local_ttl, NULL,
1810 T_PTR, C_IN, "d", name))
1811 anscount++;
1812 }
1813 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001814 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001815 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001816 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001817 {
1818 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1819 ans = 1;
1820 nxdomain = 1;
1821 if (!dryrun)
1822 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001823 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001824 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001825 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001826
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001827 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1828 {
1829 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001830 struct interface_name *intr;
1831
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001832 if (flag == F_IPV6)
1833#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001834 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001835#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001836 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001837#endif
1838
1839 if (qtype != type && qtype != T_ANY)
1840 continue;
1841
Simon Kelley316e2732010-01-22 20:16:09 +00001842 /* Check for "A for A" queries; be rather conservative
1843 about what looks like dotted-quad. */
1844 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001845 {
Simon Kelley316e2732010-01-22 20:16:09 +00001846 char *cp;
1847 unsigned int i, a;
1848 int x;
1849
1850 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001851 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001852 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001853 {
1854 i = 5;
1855 break;
1856 }
1857
1858 a = (a << 8) + x;
1859
1860 if (*cp == '.')
1861 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001862 }
Simon Kelley316e2732010-01-22 20:16:09 +00001863
1864 if (i == 4)
1865 {
1866 ans = 1;
1867 if (!dryrun)
1868 {
1869 addr.addr.addr4.s_addr = htonl(a);
1870 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1871 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1872 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1873 anscount++;
1874 }
1875 continue;
1876 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001877 }
1878
Simon Kelleyf2621c72007-04-29 19:47:21 +01001879 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001880 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001881 for (intr = daemon->int_names; intr; intr = intr->next)
1882 if (hostname_isequal(name, intr->name))
1883 break;
1884
1885 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001886 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001887 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001888 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001889
Simon Kelley115ac3e2013-05-20 11:28:32 +01001890 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001891
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001892 for (intr = daemon->int_names; intr; intr = intr->next)
1893 if (hostname_isequal(name, intr->name))
1894 {
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001895 ans = 1;
1896 if (!dryrun)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001897 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001898
1899 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1900#ifdef HAVE_IPV6
1901 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
1902#endif
1903 {
1904 gotit = 1;
1905 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1906 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1907 daemon->local_ttl, NULL, type, C_IN,
1908 type == T_A ? "4" : "6", &addrlist->addr))
1909 anscount++;
1910 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001911 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001912 }
1913
1914 if (!dryrun && !gotit)
1915 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1916
Simon Kelley115ac3e2013-05-20 11:28:32 +01001917 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001918 }
1919
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001920 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00001921 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001922 {
1923 int localise = 0;
1924
1925 /* See if a putative address is on the network from which we recieved
1926 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001927 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001928 {
1929 struct crec *save = crecp;
1930 do {
1931 if ((crecp->flags & F_HOSTS) &&
1932 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1933 {
1934 localise = 1;
1935 break;
1936 }
1937 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1938 crecp = save;
1939 }
Simon Kelley824202e2014-01-23 20:59:46 +00001940
Simon Kelley0744ca62014-01-25 16:40:15 +00001941 /* If the client asked for DNSSEC and we can't provide RRSIGs, either
1942 because we've not doing DNSSEC or the cached answer is signed by negative,
1943 don't answer from the cache, forward instead. */
1944 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley824202e2014-01-23 20:59:46 +00001945 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001946 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1947 crecp = NULL;
1948#ifdef HAVE_DNSSEC
1949 else if (crecp->flags & F_DNSSECOK)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001950 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001951 /* We're returning validated data, need to return the RRSIG too. */
Simon Kelley12fae492014-02-04 22:03:06 +00001952 struct crec *rr_crec = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001953 int sigtype = type;
1954 /* The signature may have expired even though the data is still in cache,
1955 forward instead of answering from cache if so. */
1956 int gotsig = 0;
1957
1958 if (crecp->flags & F_CNAME)
1959 sigtype = T_CNAME;
1960
Simon Kelley12fae492014-02-04 22:03:06 +00001961 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001962 {
Simon Kelley12fae492014-02-04 22:03:06 +00001963 if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001964 {
Simon Kelley12fae492014-02-04 22:03:06 +00001965 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001966 gotsig = 1;
1967
1968 if (!dryrun &&
1969 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001970 rr_crec->ttd - now, &nameoffset,
1971 T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
Simon Kelley0744ca62014-01-25 16:40:15 +00001972 anscount++;
1973 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001974 }
Simon Kelley12fae492014-02-04 22:03:06 +00001975
1976 if (!gotsig)
1977 crecp = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001978 }
Simon Kelley824202e2014-01-23 20:59:46 +00001979#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001980 }
1981
Simon Kelley824202e2014-01-23 20:59:46 +00001982 if (crecp)
1983 do
1984 {
1985 /* don't answer wildcard queries with data not from /etc/hosts
1986 or DHCP leases */
1987 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1988 break;
1989
1990 if (!(crecp->flags & F_DNSSECOK))
1991 sec_data = 0;
1992
1993 if (crecp->flags & F_CNAME)
1994 {
1995 char *cname_target = cache_get_cname_target(crecp);
1996
1997 if (!dryrun)
1998 {
1999 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2000 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2001 crec_ttl(crecp, now), &nameoffset,
2002 T_CNAME, C_IN, "d", cname_target))
2003 anscount++;
2004 }
2005
2006 strcpy(name, cname_target);
2007 /* check if target interface_name */
2008 if (crecp->addr.cname.uid == -1)
2009 goto intname_restart;
2010 else
2011 goto cname_restart;
2012 }
2013
2014 if (crecp->flags & F_NEG)
2015 {
2016 /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
2017 is cached and the client wants DNSSEC, forward rather than answering from the cache */
2018 if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
2019 {
2020 ans = 1;
2021 auth = 0;
2022 if (crecp->flags & F_NXDOMAIN)
2023 nxdomain = 1;
2024 if (!dryrun)
2025 log_query(crecp->flags, name, NULL, NULL);
2026 }
2027 }
2028 else
2029 {
2030 /* If we are returning local answers depending on network,
2031 filter here. */
2032 if (localise &&
2033 (crecp->flags & F_HOSTS) &&
2034 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
2035 continue;
2036
2037 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
2038 auth = 0;
2039
2040 ans = 1;
2041 if (!dryrun)
2042 {
2043 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
2044 record_source(crecp->uid));
2045
2046 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2047 crec_ttl(crecp, now), NULL, type, C_IN,
2048 type == T_A ? "4" : "6", &crecp->addr))
2049 anscount++;
2050 }
2051 }
2052 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002053 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002054 else if (is_name_synthetic(flag, name, &addr))
2055 {
2056 ans = 1;
2057 if (!dryrun)
2058 {
2059 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
2060 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2061 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
2062 anscount++;
2063 }
2064 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002065 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002066
2067 if (qtype == T_CNAME || qtype == T_ANY)
2068 {
2069 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002070 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002071 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00002072 if (!(crecp->flags & F_DNSSECOK))
2073 sec_data = 0;
2074
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002075 ans = 1;
2076 if (!dryrun)
2077 {
2078 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2079 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2080 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01002081 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002082 anscount++;
2083 }
2084 }
2085 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002086
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002087 if (qtype == T_MX || qtype == T_ANY)
2088 {
2089 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00002090 for (rec = daemon->mxnames; rec; rec = rec->next)
2091 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002092 {
2093 ans = found = 1;
2094 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002095 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002096 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002097 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00002098 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2099 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
2100 {
2101 anscount++;
2102 if (rec->target)
2103 rec->offset = offset;
2104 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002105 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002106 }
2107
Simon Kelley28866e92011-02-14 20:19:14 +00002108 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002109 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002110 {
2111 ans = 1;
2112 if (!dryrun)
2113 {
Simon Kelley28866e92011-02-14 20:19:14 +00002114 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002115 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
2116 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00002117 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002118 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002119 }
2120 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002121 }
2122
2123 if (qtype == T_SRV || qtype == T_ANY)
2124 {
2125 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00002126 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
2127
Simon Kelley0a852542005-03-23 20:28:59 +00002128 for (rec = daemon->mxnames; rec; rec = rec->next)
2129 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002130 {
2131 found = ans = 1;
2132 if (!dryrun)
2133 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002134 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002135 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002136 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00002137 &offset, T_SRV, C_IN, "sssd",
2138 rec->priority, rec->weight, rec->srvport, rec->target))
2139 {
2140 anscount++;
2141 if (rec->target)
2142 rec->offset = offset;
2143 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002144 }
Simon Kelley28866e92011-02-14 20:19:14 +00002145
2146 /* unlink first SRV record found */
2147 if (!move)
2148 {
2149 move = rec;
2150 *up = rec->next;
2151 }
2152 else
2153 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002154 }
Simon Kelley28866e92011-02-14 20:19:14 +00002155 else
2156 up = &rec->next;
2157
2158 /* put first SRV record back at the end. */
2159 if (move)
2160 {
2161 *up = move;
2162 move->next = NULL;
2163 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002164
Simon Kelley28866e92011-02-14 20:19:14 +00002165 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002166 {
2167 ans = 1;
2168 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002169 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002170 }
2171 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002172
2173 if (qtype == T_NAPTR || qtype == T_ANY)
2174 {
2175 struct naptr *na;
2176 for (na = daemon->naptr; na; na = na->next)
2177 if (hostname_isequal(name, na->name))
2178 {
2179 ans = 1;
2180 if (!dryrun)
2181 {
Simon Kelley28866e92011-02-14 20:19:14 +00002182 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01002183 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2184 NULL, T_NAPTR, C_IN, "sszzzd",
2185 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
2186 anscount++;
2187 }
2188 }
2189 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002190
2191 if (qtype == T_MAILB)
2192 ans = 1, nxdomain = 1;
2193
Simon Kelley28866e92011-02-14 20:19:14 +00002194 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002195 {
2196 ans = 1;
2197 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002198 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002199 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002200 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002201
2202 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002203 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002204 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002205
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002206 if (dryrun)
2207 {
2208 dryrun = 0;
2209 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002210 }
2211
Simon Kelley0a852542005-03-23 20:28:59 +00002212 /* create an additional data section, for stuff in SRV and MX record replies. */
2213 for (rec = daemon->mxnames; rec; rec = rec->next)
2214 if (rec->offset != 0)
2215 {
2216 /* squash dupes */
2217 struct mx_srv_record *tmp;
2218 for (tmp = rec->next; tmp; tmp = tmp->next)
2219 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2220 tmp->offset = 0;
2221
2222 crecp = NULL;
2223 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2224 {
Simon Kelley0a852542005-03-23 20:28:59 +00002225#ifdef HAVE_IPV6
2226 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2227#else
2228 int type = T_A;
2229#endif
2230 if (crecp->flags & F_NEG)
2231 continue;
2232
Simon Kelley9009d742008-11-14 20:04:27 +00002233 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2234 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002235 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2236 addncount++;
2237 }
2238 }
2239
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002240 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002241 /* clear authoritative and truncated flags, set QR flag */
2242 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2243 /* set RA flag */
2244 header->hb4 |= HB4_RA;
2245
2246 /* authoritive - only hosts and DHCP derived names. */
2247 if (auth)
2248 header->hb3 |= HB3_AA;
2249
2250 /* truncation */
2251 if (trunc)
2252 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002253
Simon Kelley45cca582013-10-15 10:20:13 +01002254 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002255 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002256 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002257 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002258 header->ancount = htons(anscount);
2259 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002260 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00002261
Simon Kelleya25720a2014-01-14 23:13:55 +00002262 len = ansp - (unsigned char *)header;
2263
2264 if (have_pseudoheader)
Simon Kelleye243c072014-02-06 18:14:09 +00002265 len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
2266
Simon Kelley83349b82014-02-10 21:02:01 +00002267 if (*ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00002268 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00002269 else
2270 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00002271
Simon Kelley7c286122014-01-27 21:38:11 +00002272 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002273}
2274