blob: db98c629aa7dde7af025d5979c1c88c2181bffae [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 Kelley572b41e2011-02-18 18:11:18 +0000363unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100364{
Simon Kelley91dccd02005-03-31 17:48:32 +0100365 int q;
366 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000367 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100368
Simon Kelley5aabfc72007-08-29 11:24:47 +0100369 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000370 {
Simon Kelley9009d742008-11-14 20:04:27 +0000371 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000372 return crc; /* bad packet */
373
Simon Kelley3d8df262005-08-29 12:19:27 +0100374 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000375 {
376 int i = 8;
377 char c = *p1;
378
379 if (c >= 'A' && c <= 'Z')
380 c += 'a' - 'A';
381
382 crc ^= c << 24;
383 while (i--)
384 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
385 }
386
387 /* CRC the class and type as well */
388 for (p1 = p; p1 < p+4; p1++)
389 {
390 int i = 8;
391 crc ^= *p1 << 24;
392 while (i--)
393 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
394 }
395
396 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000397 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000398 return crc; /* bad packet */
399 }
400
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100401 return crc;
402}
403
404
Simon Kelley572b41e2011-02-18 18:11:18 +0000405size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100406{
407 unsigned char *ansp = skip_questions(header, plen);
408
Simon Kelley9009d742008-11-14 20:04:27 +0000409 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100410 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000411 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100412
413 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
414 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000415 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100416
Simon Kelley36717ee2004-09-20 19:20:58 +0100417 /* restore pseudoheader */
418 if (pheader && ntohs(header->arcount) == 0)
419 {
420 /* must use memmove, may overlap */
421 memmove(ansp, pheader, hlen);
422 header->arcount = htons(1);
423 ansp += hlen;
424 }
425
426 return ansp - (unsigned char *)header;
427}
428
Simon Kelley572b41e2011-02-18 18:11:18 +0000429unsigned 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 +0100430{
431 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
Simon Kelley832af0b2007-01-21 20:01:28 +0000432 also return length of pseudoheader in *len and pointer to the UDP size in *p
433 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
434 forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100435
436 int i, arcount = ntohs(header->arcount);
Simon Kelley832af0b2007-01-21 20:01:28 +0000437 unsigned char *ansp = (unsigned char *)(header+1);
438 unsigned short rdlen, type, class;
439 unsigned char *ret = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000440
441 if (is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000442 {
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000443 *is_sign = 0;
444
Simon Kelley572b41e2011-02-18 18:11:18 +0000445 if (OPCODE(header) == QUERY)
Simon Kelley832af0b2007-01-21 20:01:28 +0000446 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100447 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000448 {
Simon Kelley9009d742008-11-14 20:04:27 +0000449 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000450 return NULL;
451
452 GETSHORT(type, ansp);
453 GETSHORT(class, ansp);
454
455 if (class == C_IN && type == T_TKEY)
456 *is_sign = 1;
457 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000458 }
459 }
460 else
461 {
462 if (!(ansp = skip_questions(header, plen)))
463 return NULL;
464 }
465
466 if (arcount == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100467 return NULL;
468
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100469 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
470 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000471
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100472 for (i = 0; i < arcount; i++)
473 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100474 unsigned char *save, *start = ansp;
Simon Kelley9009d742008-11-14 20:04:27 +0000475 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100476 return NULL;
477
478 GETSHORT(type, ansp);
479 save = ansp;
Simon Kelley832af0b2007-01-21 20:01:28 +0000480 GETSHORT(class, ansp);
481 ansp += 4; /* TTL */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100482 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000483 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100484 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000485 if (type == T_OPT)
Simon Kelley36717ee2004-09-20 19:20:58 +0100486 {
487 if (len)
488 *len = ansp - start;
489 if (p)
490 *p = save;
Simon Kelley832af0b2007-01-21 20:01:28 +0000491 ret = start;
Simon Kelley36717ee2004-09-20 19:20:58 +0100492 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000493 else if (is_sign &&
494 i == arcount - 1 &&
495 class == C_ANY &&
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000496 type == T_TSIG)
Simon Kelley832af0b2007-01-21 20:01:28 +0000497 *is_sign = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100498 }
499
Simon Kelley832af0b2007-01-21 20:01:28 +0000500 return ret;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100501}
Simon Kelley28866e92011-02-14 20:19:14 +0000502
503struct macparm {
504 unsigned char *limit;
Simon Kelley572b41e2011-02-18 18:11:18 +0000505 struct dns_header *header;
Simon Kelley28866e92011-02-14 20:19:14 +0000506 size_t plen;
507 union mysockaddr *l3;
508};
Simon Kelleyed4c0762013-10-08 20:46:34 +0100509
510static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
Simon Kelley3a237152013-12-12 12:15:50 +0000511 int optno, unsigned char *opt, size_t optlen, int set_do)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100512{
513 unsigned char *lenp, *datap, *p;
Simon Kelleya25720a2014-01-14 23:13:55 +0000514 int rdlen, is_sign;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100515
Simon Kelleya25720a2014-01-14 23:13:55 +0000516 if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
Simon Kelleyed4c0762013-10-08 20:46:34 +0100517 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000518 if (is_sign)
519 return plen;
520
Simon Kelleyed4c0762013-10-08 20:46:34 +0100521 /* We are adding the pseudoheader */
522 if (!(p = skip_questions(header, plen)) ||
523 !(p = skip_section(p,
Simon Kelleya25720a2014-01-14 23:13:55 +0000524 ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
Simon Kelleyed4c0762013-10-08 20:46:34 +0100525 header, plen)))
526 return plen;
527 *p++ = 0; /* empty name */
528 PUTSHORT(T_OPT, p);
529 PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
Simon Kelley3a237152013-12-12 12:15:50 +0000530 PUTSHORT(0, p); /* extended RCODE and version */
531 PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100532 lenp = p;
533 PUTSHORT(0, p); /* RDLEN */
534 rdlen = 0;
535 if (((ssize_t)optlen) > (limit - (p + 4)))
536 return plen; /* Too big */
Simon Kelleya25720a2014-01-14 23:13:55 +0000537 header->arcount = htons(ntohs(header->arcount) + 1);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100538 datap = p;
539 }
540 else
541 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000542 int i;
Simon Kelley3a237152013-12-12 12:15:50 +0000543 unsigned short code, len, flags;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100544
Simon Kelleya25720a2014-01-14 23:13:55 +0000545 /* Must be at the end, if exists */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100546 if (ntohs(header->arcount) != 1 ||
Simon Kelleyed4c0762013-10-08 20:46:34 +0100547 is_sign ||
548 (!(p = skip_name(p, header, plen, 10))))
549 return plen;
550
Simon Kelley3a237152013-12-12 12:15:50 +0000551 p += 6; /* skip UDP length and RCODE */
552 GETSHORT(flags, p);
553 if (set_do)
554 {
555 p -=2;
556 PUTSHORT(flags | 0x8000, p);
557 }
558
Simon Kelleyed4c0762013-10-08 20:46:34 +0100559 lenp = p;
560 GETSHORT(rdlen, p);
561 if (!CHECK_LEN(header, p, plen, rdlen))
562 return plen; /* bad packet */
563 datap = p;
564
Simon Kelley3a237152013-12-12 12:15:50 +0000565 /* no option to add */
566 if (optno == 0)
567 return plen;
568
Simon Kelleyed4c0762013-10-08 20:46:34 +0100569 /* check if option already there */
570 for (i = 0; i + 4 < rdlen; i += len + 4)
571 {
572 GETSHORT(code, p);
573 GETSHORT(len, p);
574 if (code == optno)
575 return plen;
576 p += len;
577 }
578
579 if (((ssize_t)optlen) > (limit - (p + 4)))
580 return plen; /* Too big */
581 }
582
Simon Kelley0fc2f312014-01-08 10:26:58 +0000583 if (optno != 0)
584 {
585 PUTSHORT(optno, p);
586 PUTSHORT(optlen, p);
587 memcpy(p, opt, optlen);
588 p += optlen;
589 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100590
591 PUTSHORT(p - datap, lenp);
592 return p - (unsigned char *)header;
593
594}
Simon Kelley28866e92011-02-14 20:19:14 +0000595
596static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
597{
598 struct macparm *parm = parmv;
599 int match = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100600
Simon Kelley28866e92011-02-14 20:19:14 +0000601 if (family == parm->l3->sa.sa_family)
602 {
603 if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
604 match = 1;
605#ifdef HAVE_IPV6
606 else
607 if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
608 match = 1;
609#endif
610 }
611
612 if (!match)
613 return 1; /* continue */
Simon Kelley28866e92011-02-14 20:19:14 +0000614
Simon Kelley3a237152013-12-12 12:15:50 +0000615 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 +0000616
617 return 0; /* done */
618}
619
Simon Kelley572b41e2011-02-18 18:11:18 +0000620size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
Simon Kelley28866e92011-02-14 20:19:14 +0000621{
622 struct macparm parm;
623
624/* Must have an existing pseudoheader as the only ar-record,
625 or have no ar-records. Must also not be signed */
626
627 if (ntohs(header->arcount) > 1)
628 return plen;
629
630 parm.header = header;
631 parm.limit = (unsigned char *)limit;
632 parm.plen = plen;
633 parm.l3 = l3;
634
635 iface_enumerate(AF_UNSPEC, &parm, filter_mac);
636
637 return parm.plen;
638}
639
Simon Kelleyed4c0762013-10-08 20:46:34 +0100640struct subnet_opt {
641 u16 family;
642 u8 source_netmask, scope_netmask;
643#ifdef HAVE_IPV6
644 u8 addr[IN6ADDRSZ];
645#else
646 u8 addr[INADDRSZ];
647#endif
648};
649
Simon Kelley44de6492013-11-06 11:36:57 +0000650static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100651{
652 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
653
654 int len;
655 void *addrp;
656
Simon Kelleyed4c0762013-10-08 20:46:34 +0100657#ifdef HAVE_IPV6
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100658 if (source->sa.sa_family == AF_INET6)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100659 {
660 opt->family = htons(2);
661 opt->source_netmask = daemon->addr6_netmask;
662 addrp = &source->in6.sin6_addr;
663 }
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100664 else
Simon Kelleyed4c0762013-10-08 20:46:34 +0100665#endif
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100666 {
667 opt->family = htons(1);
668 opt->source_netmask = daemon->addr4_netmask;
669 addrp = &source->in.sin_addr;
670 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100671
672 opt->scope_netmask = 0;
673 len = 0;
674
675 if (opt->source_netmask != 0)
676 {
677 len = ((opt->source_netmask - 1) >> 3) + 1;
678 memcpy(opt->addr, addrp, len);
679 if (opt->source_netmask & 7)
680 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
681 }
682
683 return len + 4;
684}
685
686size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
687{
688 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
689
690 int len;
691 struct subnet_opt opt;
692
693 len = calc_subnet_opt(&opt, source);
Simon Kelley3a237152013-12-12 12:15:50 +0000694 return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100695}
Simon Kelley3a237152013-12-12 12:15:50 +0000696
697#ifdef HAVE_DNSSEC
698size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
699{
700 return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
701}
702#endif
703
Simon Kelleyed4c0762013-10-08 20:46:34 +0100704int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
705{
706 /* Section 9.2, Check that subnet option in reply matches. */
707
708
709 int len, calc_len;
710 struct subnet_opt opt;
711 unsigned char *p;
712 int code, i, rdlen;
713
714 calc_len = calc_subnet_opt(&opt, peer);
715
716 if (!(p = skip_name(pseudoheader, header, plen, 10)))
717 return 1;
718
719 p += 8; /* skip UDP length and RCODE */
720
721 GETSHORT(rdlen, p);
722 if (!CHECK_LEN(header, p, plen, rdlen))
723 return 1; /* bad packet */
724
725 /* check if option there */
726 for (i = 0; i + 4 < rdlen; i += len + 4)
727 {
728 GETSHORT(code, p);
729 GETSHORT(len, p);
730 if (code == EDNS0_OPTION_CLIENT_SUBNET)
731 {
732 /* make sure this doesn't mismatch. */
733 opt.scope_netmask = p[3];
734 if (len != calc_len || memcmp(p, &opt, len) != 0)
735 return 0;
736 }
737 p += len;
738 }
739
740 return 1;
741}
742
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000743/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100744int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000745{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100746 in_addr_t ip_addr = ntohl(addr.s_addr);
747
748 return
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100749 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100750 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
751 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
752 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
753 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000754}
Simon Kelley1cff1662004-03-12 08:12:58 +0000755
Simon Kelley572b41e2011-02-18 18:11:18 +0000756static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
Simon Kelley824af852008-02-12 20:43:05 +0000757{
758 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000759
760 for (i = count; i != 0; i--)
761 {
Simon Kelley28866e92011-02-14 20:19:14 +0000762 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100763 {
764 if (!extract_name(header, qlen, &p, name, 1, 10))
765 return 0;
766 }
767 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000768 return 0; /* bad packet */
769
770 GETSHORT(qtype, p);
771 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100772 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000773 GETSHORT(rdlen, p);
774
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100775 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000776 {
777 struct doctor *doctor;
778 struct in_addr addr;
779
Simon Kelley9009d742008-11-14 20:04:27 +0000780 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
781 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100782
783 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000784 memcpy(&addr, p, INADDRSZ);
785
786 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000787 {
788 if (doctor->end.s_addr == 0)
789 {
790 if (!is_same_net(doctor->in, addr, doctor->mask))
791 continue;
792 }
793 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
794 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
795 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100796
Simon Kelley73a08a22009-02-05 20:28:08 +0000797 addr.s_addr &= ~doctor->mask.s_addr;
798 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
799 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000800 header->hb3 &= ~HB3_AA;
Simon Kelley73a08a22009-02-05 20:28:08 +0000801 memcpy(p, &addr, INADDRSZ);
802 break;
803 }
Simon Kelley824af852008-02-12 20:43:05 +0000804 }
Simon Kelley28866e92011-02-14 20:19:14 +0000805 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100806 {
807 unsigned char *p1 = p;
808 if (!CHECK_LEN(header, p1, qlen, rdlen))
809 return 0;
810 while ((p1 - p) < rdlen)
811 {
812 unsigned int i, len = *p1;
813 unsigned char *p2 = p1;
814 /* make counted string zero-term and sanitise */
815 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100816 {
817 if (!isprint((int)*(p2+1)))
818 break;
819
820 *p2 = *(p2+1);
821 p2++;
822 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100823 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000824 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100825 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100826 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100827 *p1 = len;
828 p1 += len+1;
829 }
830 }
Simon Kelley824af852008-02-12 20:43:05 +0000831
Simon Kelley9009d742008-11-14 20:04:27 +0000832 if (!ADD_RDLEN(header, p, qlen, rdlen))
833 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000834 }
835
836 return p;
837}
838
Simon Kelley572b41e2011-02-18 18:11:18 +0000839static int find_soa(struct dns_header *header, size_t qlen, char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000840{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100841 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843 unsigned long ttl, minttl = ULONG_MAX;
844 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000845
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100846 /* first move to NS section and find TTL from any SOA section */
847 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100848 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name)))
Simon Kelley824af852008-02-12 20:43:05 +0000849 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000850
Simon Kelley5aabfc72007-08-29 11:24:47 +0100851 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000852 {
Simon Kelley9009d742008-11-14 20:04:27 +0000853 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100854 return 0; /* bad packet */
855
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000856 GETSHORT(qtype, p);
857 GETSHORT(qclass, p);
858 GETLONG(ttl, p);
859 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100860
861 if ((qclass == C_IN) && (qtype == T_SOA))
862 {
863 found_soa = 1;
864 if (ttl < minttl)
865 minttl = ttl;
866
867 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000868 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100869 return 0;
870 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000871 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100872 return 0;
873 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
874
875 GETLONG(ttl, p); /* minTTL */
876 if (ttl < minttl)
877 minttl = ttl;
878 }
Simon Kelley9009d742008-11-14 20:04:27 +0000879 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100880 return 0; /* bad packet */
881 }
Simon Kelley9009d742008-11-14 20:04:27 +0000882
Simon Kelley824af852008-02-12 20:43:05 +0000883 /* rewrite addresses in additioal section too */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100884 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL))
Simon Kelley824af852008-02-12 20:43:05 +0000885 return 0;
886
887 if (!found_soa)
888 minttl = daemon->neg_ttl;
889
890 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100891}
892
893/* Note that the following code can create CNAME chains that don't point to a real record,
894 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 +0000895 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100896 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000897int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelley0fc2f312014-01-08 10:26:58 +0000898 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100899{
Simon Kelley824af852008-02-12 20:43:05 +0000900 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100901 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000902 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100903 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000904#ifdef HAVE_IPSET
905 char **ipsets_cur;
906#else
907 (void)ipsets; /* unused */
908#endif
909
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100910 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000911
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100912 /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
Simon Kelley28866e92011-02-14 20:19:14 +0000913 if (daemon->doctors || option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000914 {
915 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100916 ttl = find_soa(header, qlen, name);
Simon Kelley0a852542005-03-23 20:28:59 +0000917 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100918
919 /* go through the questions. */
920 p = (unsigned char *)(header+1);
921
Simon Kelley5aabfc72007-08-29 11:24:47 +0100922 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100923 {
924 int found = 0, cname_count = 5;
925 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000926 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0435d042014-01-08 18:22:37 +0000927 int secflag = secure ? F_DNSSECOK : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000928 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000929
Simon Kelley824af852008-02-12 20:43:05 +0000930 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000931 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000932 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100933
934 GETSHORT(qtype, p);
935 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936
937 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100938 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000939
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100940 /* PTRs: we chase CNAMEs here, since we have no way to
941 represent them in the cache. */
942 if (qtype == T_PTR)
943 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000944 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100945
946 if (!name_encoding)
947 continue;
948
949 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000950 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100951 cname_loop:
952 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000953 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100954
Simon Kelley5aabfc72007-08-29 11:24:47 +0100955 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100956 {
Simon Kelley824af852008-02-12 20:43:05 +0000957 unsigned char *tmp = namep;
958 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000959 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
960 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000961 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100962
963 GETSHORT(aqtype, p1);
964 GETSHORT(aqclass, p1);
965 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100966 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
967 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000968 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100969 PUTLONG(daemon->max_ttl, p1);
970 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100971 GETSHORT(ardlen, p1);
972 endrr = p1+ardlen;
973
974 /* TTL of record is minimum of CNAMES and PTR */
975 if (attl < cttl)
976 cttl = attl;
977
978 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
979 {
Simon Kelley9009d742008-11-14 20:04:27 +0000980 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000981 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100982
983 if (aqtype == T_CNAME)
984 {
985 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000986 return 0; /* looped CNAMES */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100987 goto cname_loop;
988 }
989
Simon Kelley0435d042014-01-08 18:22:37 +0000990 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100991 found = 1;
992 }
993
994 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000995 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000996 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100997 }
998 }
999
Simon Kelley28866e92011-02-14 20:19:14 +00001000 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001001 {
1002 if (!searched_soa)
1003 {
1004 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001005 ttl = find_soa(header, qlen, NULL);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001006 }
1007 if (ttl)
Simon Kelley0435d042014-01-08 18:22:37 +00001008 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001009 }
1010 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001011 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001012 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001013 /* everything other than PTR */
1014 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001015 int addrlen;
1016
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001017 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001018 {
1019 addrlen = INADDRSZ;
1020 flags |= F_IPV4;
1021 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001022#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001023 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001024 {
1025 addrlen = IN6ADDRSZ;
1026 flags |= F_IPV6;
1027 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001028#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001029 else
1030 continue;
1031
Simon Kelley45cca582013-10-15 10:20:13 +01001032 cname_loop1:
1033 if (!(p1 = skip_questions(header, qlen)))
1034 return 0;
1035
1036 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001037 {
Simon Kelley45cca582013-10-15 10:20:13 +01001038 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
1039 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001040
Simon Kelley45cca582013-10-15 10:20:13 +01001041 GETSHORT(aqtype, p1);
1042 GETSHORT(aqclass, p1);
1043 GETLONG(attl, p1);
1044 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001045 {
Simon Kelley45cca582013-10-15 10:20:13 +01001046 (p1) -= 4;
1047 PUTLONG(daemon->max_ttl, p1);
1048 }
1049 GETSHORT(ardlen, p1);
1050 endrr = p1+ardlen;
1051
1052 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
1053 {
1054 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001055 {
Simon Kelley45cca582013-10-15 10:20:13 +01001056 if (!cname_count--)
1057 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +00001058 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001059 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001060 {
Simon Kelley45cca582013-10-15 10:20:13 +01001061 newc->addr.cname.target.cache = NULL;
1062 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001063 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001064 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001065 cpp->addr.cname.uid = newc->uid;
1066 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001067 }
Simon Kelley45cca582013-10-15 10:20:13 +01001068
1069 cpp = newc;
1070 if (attl < cttl)
1071 cttl = attl;
1072
1073 if (!extract_name(header, qlen, &p1, name, 1, 0))
1074 return 0;
1075 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001076 }
Simon Kelley45cca582013-10-15 10:20:13 +01001077 else if (!(flags & F_NXDOMAIN))
1078 {
1079 found = 1;
1080
1081 /* copy address into aligned storage */
1082 if (!CHECK_LEN(header, p1, qlen, addrlen))
1083 return 0; /* bad packet */
1084 memcpy(&addr, p1, addrlen);
1085
1086 /* check for returned address in private space */
1087 if (check_rebind &&
1088 (flags & F_IPV4) &&
1089 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
1090 return 1;
1091
1092#ifdef HAVE_IPSET
1093 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
1094 {
1095 ipsets_cur = ipsets;
1096 while (*ipsets_cur)
1097 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
1098 }
1099#endif
1100
Simon Kelley0435d042014-01-08 18:22:37 +00001101 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001102 if (newc && cpp)
1103 {
1104 cpp->addr.cname.target.cache = newc;
1105 cpp->addr.cname.uid = newc->uid;
1106 }
1107 cpp = NULL;
1108 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001109 }
Simon Kelley45cca582013-10-15 10:20:13 +01001110
1111 p1 = endrr;
1112 if (!CHECK_LEN(header, p1, qlen, 0))
1113 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001114 }
1115
Simon Kelley28866e92011-02-14 20:19:14 +00001116 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001117 {
1118 if (!searched_soa)
1119 {
1120 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001121 ttl = find_soa(header, qlen, NULL);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001122 }
1123 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001124 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001125 if (ttl || cpp)
1126 {
Simon Kelley0435d042014-01-08 18:22:37 +00001127 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
Simon Kelley26128d22004-11-14 16:43:54 +00001128 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001129 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001130 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001131 cpp->addr.cname.uid = newc->uid;
1132 }
1133 }
1134 }
1135 }
1136 }
1137
Simon Kelley1023dcb2012-04-09 18:00:08 +01001138 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +01001139 Don't cache replies from non-recursive nameservers, since we may get a
1140 reply containing a CNAME but not its target, even though the target
1141 does exist. */
1142 if (!(header->hb3 & HB3_TC) &&
1143 !(header->hb4 & HB4_CD) &&
1144 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +00001145 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +00001146 cache_end_insert();
1147
1148 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001149}
1150
1151/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001152 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +00001153unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001154{
1155 unsigned char *p = (unsigned char *)(header+1);
1156 int qtype, qclass;
1157
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001158 if (typep)
1159 *typep = 0;
1160
Simon Kelley572b41e2011-02-18 18:11:18 +00001161 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001162 return 0; /* must be exactly one query. */
1163
Simon Kelley9009d742008-11-14 20:04:27 +00001164 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001165 return 0; /* bad packet */
1166
1167 GETSHORT(qtype, p);
1168 GETSHORT(qclass, p);
1169
Simon Kelley0a852542005-03-23 20:28:59 +00001170 if (typep)
1171 *typep = qtype;
1172
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001173 if (qclass == C_IN)
1174 {
1175 if (qtype == T_A)
1176 return F_IPV4;
1177 if (qtype == T_AAAA)
1178 return F_IPV6;
1179 if (qtype == T_ANY)
1180 return F_IPV4 | F_IPV6;
1181 }
1182
1183 return F_QUERY;
1184}
1185
1186
Simon Kelley572b41e2011-02-18 18:11:18 +00001187size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001188 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001189{
1190 unsigned char *p = skip_questions(header, qlen);
1191
Simon Kelley572b41e2011-02-18 18:11:18 +00001192 /* clear authoritative and truncated flags, set QR flag */
1193 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1194 /* set RA flag */
1195 header->hb4 |= HB4_RA;
1196
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001197 header->nscount = htons(0);
1198 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001199 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001200 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001201 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001202 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001203 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001204 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001205 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001206 else if (p && flags == F_IPV4)
1207 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001208 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001209 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001210 header->hb3 |= HB3_AA;
1211 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 +00001212 }
1213#ifdef HAVE_IPV6
1214 else if (p && flags == F_IPV6)
1215 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001216 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001217 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001218 header->hb3 |= HB3_AA;
1219 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 +00001220 }
1221#endif
1222 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001223 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001224
1225 return p - (unsigned char *)header;
1226}
Simon Kelley36717ee2004-09-20 19:20:58 +01001227
1228/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001229int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001230{
1231 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001232 struct mx_srv_record *mx;
1233 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001234 struct interface_name *intr;
1235 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001236 struct naptr *naptr;
1237
1238 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +00001239 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +01001240 return 1;
1241
Simon Kelley7de060b2011-08-26 17:24:52 +01001242 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1243 if (hostname_isequal(name, naptr->name))
1244 return 1;
1245
1246 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001247 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001248 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001249
Simon Kelley0a852542005-03-23 20:28:59 +00001250 for (txt = daemon->txt; txt; txt = txt->next)
1251 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001252 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001253
1254 for (intr = daemon->int_names; intr; intr = intr->next)
1255 if (hostname_isequal(name, intr->name))
1256 return 1;
1257
1258 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1259 if (hostname_isequal(name, ptr->name))
1260 return 1;
1261
Simon Kelley36717ee2004-09-20 19:20:58 +01001262 return 0;
1263}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001264
1265/* Is the packet a reply with the answer address equal to addr?
1266 If so mung is into an NXDOMAIN reply and also put that information
1267 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001268int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001269 struct bogus_addr *baddr, time_t now)
1270{
1271 unsigned char *p;
1272 int i, qtype, qclass, rdlen;
1273 unsigned long ttl;
1274 struct bogus_addr *baddrp;
1275
1276 /* skip over questions */
1277 if (!(p = skip_questions(header, qlen)))
1278 return 0; /* bad packet */
1279
Simon Kelley5aabfc72007-08-29 11:24:47 +01001280 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001281 {
Simon Kelley9009d742008-11-14 20:04:27 +00001282 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001283 return 0; /* bad packet */
1284
1285 GETSHORT(qtype, p);
1286 GETSHORT(qclass, p);
1287 GETLONG(ttl, p);
1288 GETSHORT(rdlen, p);
1289
1290 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001291 {
1292 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1293 return 0;
1294
1295 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1296 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1297 {
1298 /* Found a bogus address. Insert that info here, since there no SOA record
1299 to get the ttl from in the normal processing */
1300 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001301 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001302 cache_end_insert();
1303
1304 return 1;
1305 }
1306 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001307
Simon Kelley9009d742008-11-14 20:04:27 +00001308 if (!ADD_RDLEN(header, p, qlen, rdlen))
1309 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001310 }
1311
1312 return 0;
1313}
1314
Simon Kelleyb75e9362012-12-07 11:50:41 +00001315int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001316 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001317{
1318 va_list ap;
1319 unsigned char *sav, *p = *pp;
1320 int j;
1321 unsigned short usval;
1322 long lval;
1323 char *sval;
1324
1325 if (truncp && *truncp)
1326 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001327
1328 va_start(ap, format); /* make ap point to 1st unamed argument */
1329
Simon Kelleyb75e9362012-12-07 11:50:41 +00001330 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001331 {
1332 PUTSHORT(nameoffset | 0xc000, p);
1333 }
1334 else
1335 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001336 char *name = va_arg(ap, char *);
1337 if (name)
1338 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001339 if (nameoffset < 0)
1340 {
1341 PUTSHORT(-nameoffset | 0xc000, p);
1342 }
1343 else
1344 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001345 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001346
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001347 PUTSHORT(type, p);
1348 PUTSHORT(class, p);
1349 PUTLONG(ttl, p); /* TTL */
1350
1351 sav = p; /* Save pointer to RDLength field */
1352 PUTSHORT(0, p); /* Placeholder RDLength */
1353
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001354 for (; *format; format++)
1355 switch (*format)
1356 {
1357#ifdef HAVE_IPV6
1358 case '6':
1359 sval = va_arg(ap, char *);
1360 memcpy(p, sval, IN6ADDRSZ);
1361 p += IN6ADDRSZ;
1362 break;
1363#endif
1364
1365 case '4':
1366 sval = va_arg(ap, char *);
1367 memcpy(p, sval, INADDRSZ);
1368 p += INADDRSZ;
1369 break;
1370
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001371 case 'b':
1372 usval = va_arg(ap, int);
1373 *p++ = usval;
1374 break;
1375
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001376 case 's':
1377 usval = va_arg(ap, int);
1378 PUTSHORT(usval, p);
1379 break;
1380
1381 case 'l':
1382 lval = va_arg(ap, long);
1383 PUTLONG(lval, p);
1384 break;
1385
1386 case 'd':
1387 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001388 if (offset)
1389 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001390 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001391 *p++ = 0;
1392 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001393
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001394 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001395 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001396 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001397 if (usval != 0)
1398 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001399 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001400 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001401
1402 case 'z':
1403 sval = va_arg(ap, char *);
1404 usval = sval ? strlen(sval) : 0;
1405 if (usval > 255)
1406 usval = 255;
1407 *p++ = (unsigned char)usval;
1408 memcpy(p, sval, usval);
1409 p += usval;
1410 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001411 }
1412
1413 va_end(ap); /* clean up variable argument pointer */
1414
1415 j = p - sav - 2;
1416 PUTSHORT(j, sav); /* Now, store real RDLength */
1417
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001418 /* check for overflow of buffer */
1419 if (limit && ((unsigned char *)limit - p) < 0)
1420 {
1421 if (truncp)
1422 *truncp = 1;
1423 return 0;
1424 }
1425
1426 *pp = p;
1427 return 1;
1428}
1429
Simon Kelley9009d742008-11-14 20:04:27 +00001430static unsigned long crec_ttl(struct crec *crecp, time_t now)
1431{
1432 /* Return 0 ttl for DHCP entries, which might change
1433 before the lease expires. */
1434
1435 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1436 return daemon->local_ttl;
1437
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001438 /* Return the Max TTL value if it is lower then the actual TTL */
1439 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1440 return crecp->ttd - now;
1441 else
1442 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001443}
1444
1445
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001446/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001447size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelleycdeda282006-03-16 20:16:06 +00001448 struct in_addr local_addr, struct in_addr local_netmask, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001449{
Simon Kelley3be34542004-09-11 19:12:13 +01001450 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001451 unsigned char *p, *ansp, *pheader;
Simon Kelley832af0b2007-01-21 20:01:28 +00001452 int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001453 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001454 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001455 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001456 int q, ans, anscount = 0, addncount = 0;
Simon Kelleya25720a2014-01-14 23:13:55 +00001457 int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001458 int is_sign;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001459 struct crec *crecp;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001460 int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001461 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001462 size_t len;
Simon Kelley0a852542005-03-23 20:28:59 +00001463
Simon Kelleya25720a2014-01-14 23:13:55 +00001464 /* Don't return AD set even for local data if checking disabled. */
1465 if (header->hb4 & HB4_CD)
1466 sec_data = 0;
1467
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001468 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1469 partial replies, so we have to do a dry run to see if we can answer
1470 the query. We check to see if the do bit is set, if so we always
1471 forward rather than answering from the cache, which doesn't include
Simon Kelleya25720a2014-01-14 23:13:55 +00001472 security information, unless we're in DNSSEC validation mode. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001473
Simon Kelley832af0b2007-01-21 20:01:28 +00001474 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001475 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001476 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001477 unsigned char *psave = pheader;
1478
Simon Kelleya25720a2014-01-14 23:13:55 +00001479 have_pseudoheader = 1;
1480
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001481 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001482 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001483 GETSHORT(flags, pheader);
1484
1485 sec_reqd = flags & 0x8000; /* do bit */
1486
1487 /* If our client is advertising a larger UDP packet size
1488 than we allow, trim it so that we don't get an overlarge
1489 response from upstream */
1490
Simon Kelley832af0b2007-01-21 20:01:28 +00001491 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001492 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001493
1494 dryrun = 1;
1495 }
1496
Simon Kelley572b41e2011-02-18 18:11:18 +00001497 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001498 return 0;
1499
Simon Kelley0a852542005-03-23 20:28:59 +00001500 for (rec = daemon->mxnames; rec; rec = rec->next)
1501 rec->offset = 0;
1502
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001503 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001504 /* determine end of question section (we put answers there) */
1505 if (!(ansp = skip_questions(header, qlen)))
1506 return 0; /* bad packet */
1507
1508 /* now process each question, answers go in RRs after the question */
1509 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001510
Simon Kelley5aabfc72007-08-29 11:24:47 +01001511 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001512 {
1513 /* save pointer to name for copying into answers */
1514 nameoffset = p - (unsigned char *)header;
1515
1516 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001517 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001518 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001519
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001520 GETSHORT(qtype, p);
1521 GETSHORT(qclass, p);
1522
1523 ans = 0; /* have we answered this question */
1524
Simon Kelley0a852542005-03-23 20:28:59 +00001525 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001526 {
Simon Kelley0a852542005-03-23 20:28:59 +00001527 struct txt_record *t;
1528 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001529 {
Simon Kelley0a852542005-03-23 20:28:59 +00001530 if (t->class == qclass && hostname_isequal(name, t->name))
1531 {
1532 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001533 if (!dryrun)
1534 {
Simon Kelley28866e92011-02-14 20:19:14 +00001535 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001536 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1537 daemon->local_ttl, NULL,
1538 T_TXT, t->class, "t", t->len, t->txt))
1539 anscount++;
1540
1541 }
Simon Kelley0a852542005-03-23 20:28:59 +00001542 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001543 }
Simon Kelley0a852542005-03-23 20:28:59 +00001544 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001545
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001546#ifdef HAVE_DNSSEC
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001547 if (qtype == T_DNSKEY || qtype == T_DS || qtype == T_RRSIG)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001548 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001549 int gotone = 0;
1550 struct blockdata *keydata;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001551
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001552 /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
1553 crecp = NULL;
1554 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1555 if (crecp->uid == qclass && (qtype == T_RRSIG || crecp->addr.sig.type_covered == qtype))
1556 break;
1557
1558 if (crecp)
1559 {
1560 if (qtype == T_RRSIG)
1561 ans = gotone = 1;
1562 else if (qtype == T_DS)
1563 {
1564 crecp = NULL;
1565 while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
1566 if (crecp->uid == qclass)
1567 {
1568 ans = gotone = 1;
1569 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
1570 {
1571 struct all_addr a;
1572 a.addr.keytag = crecp->addr.ds.keytag;
1573 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
1574 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1575 crec_ttl(crecp, now), &nameoffset,
1576 T_DS, qclass, "sbbt",
1577 crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
1578 anscount++;
1579
1580 }
1581 }
1582 }
1583 else if (qtype == T_DNSKEY)
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001584 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001585 crecp = NULL;
1586 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
1587 if (crecp->uid == qclass)
1588 {
1589 ans = gotone = 1;
1590 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
1591 {
1592 struct all_addr a;
1593 a.addr.keytag = crecp->addr.key.keytag;
1594 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
1595 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1596 crec_ttl(crecp, now), &nameoffset,
1597 T_DNSKEY, qclass, "sbbt",
1598 crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
1599 anscount++;
1600 }
1601 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001602 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001603
1604 /* Now do RRSIGs */
1605 if (gotone)
1606 {
1607 crecp = NULL;
1608 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1609 if (crecp->uid == qclass && (qtype == T_RRSIG || (sec_reqd && crecp->addr.sig.type_covered == qtype)) &&
1610 !dryrun &&
1611 (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)) &&
1612 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1613 crec_ttl(crecp, now), &nameoffset,
1614 T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata))
1615 anscount++;
1616 }
1617 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001618 }
1619#endif
1620
Simon Kelley0a852542005-03-23 20:28:59 +00001621 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001622 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001623 struct txt_record *t;
1624
1625 for (t = daemon->rr; t; t = t->next)
1626 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1627 {
1628 ans = 1;
1629 if (!dryrun)
1630 {
1631 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1632 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1633 daemon->local_ttl, NULL,
1634 t->class, C_IN, "t", t->len, t->txt))
1635 anscount ++;
1636 }
1637 }
1638
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001639 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001640 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001641 /* see if it's w.z.y.z.in-addr.arpa format */
1642 int is_arpa = in_arpa_name_2_addr(name, &addr);
1643 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001644 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001645
1646 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1647 if (hostname_isequal(name, ptr->name))
1648 break;
1649
Simon Kelleyf2621c72007-04-29 19:47:21 +01001650 if (is_arpa == F_IPV4)
1651 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001652 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001653 struct addrlist *addrlist;
1654
Simon Kelley376d48c2013-11-13 13:04:30 +00001655 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1656 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001657 break;
1658
1659 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001660 break;
1661 else
1662 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1663 intr = intr->next;
1664 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001665#ifdef HAVE_IPV6
1666 else if (is_arpa == F_IPV6)
1667 for (intr = daemon->int_names; intr; intr = intr->next)
1668 {
1669 struct addrlist *addrlist;
1670
Simon Kelley376d48c2013-11-13 13:04:30 +00001671 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1672 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001673 break;
1674
1675 if (addrlist)
1676 break;
1677 else
1678 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1679 intr = intr->next;
1680 }
1681#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001682
1683 if (intr)
1684 {
1685 ans = 1;
1686 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001687 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001688 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001689 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1690 daemon->local_ttl, NULL,
1691 T_PTR, C_IN, "d", intr->name))
1692 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001693 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001694 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001695 else if (ptr)
1696 {
1697 ans = 1;
1698 if (!dryrun)
1699 {
Simon Kelley28866e92011-02-14 20:19:14 +00001700 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001701 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001702 if (hostname_isequal(name, ptr->name) &&
1703 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1704 daemon->local_ttl, NULL,
1705 T_PTR, C_IN, "d", ptr->ptr))
1706 anscount++;
1707
Simon Kelley832af0b2007-01-21 20:01:28 +00001708 }
1709 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001710 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
1711 do
1712 {
1713 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1714 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1715 continue;
1716
Simon Kelley0fc2f312014-01-08 10:26:58 +00001717 if (!(crecp->flags & F_DNSSECOK))
1718 sec_data = 0;
1719
Simon Kelleyf2621c72007-04-29 19:47:21 +01001720 if (crecp->flags & F_NEG)
1721 {
1722 ans = 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001723 auth = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001724 if (crecp->flags & F_NXDOMAIN)
1725 nxdomain = 1;
1726 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001727 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001728 }
Simon Kelleya25720a2014-01-14 23:13:55 +00001729 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001730 {
1731 ans = 1;
1732 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1733 auth = 0;
1734 if (!dryrun)
1735 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001736 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
Simon Kelley7622fc02009-06-04 20:32:05 +01001737 record_source(crecp->uid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001738
Simon Kelley9009d742008-11-14 20:04:27 +00001739 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1740 crec_ttl(crecp, now), NULL,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001741 T_PTR, C_IN, "d", cache_get_name(crecp)))
1742 anscount++;
1743 }
1744 }
1745 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
Simon Kelley2bb73af2013-04-24 17:38:19 +01001746 else if (is_rev_synth(is_arpa, &addr, name))
1747 {
1748 ans = 1;
1749 if (!dryrun)
1750 {
1751 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1752
1753 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1754 daemon->local_ttl, NULL,
1755 T_PTR, C_IN, "d", name))
1756 anscount++;
1757 }
1758 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001759 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001760 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001761 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001762 {
1763 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1764 ans = 1;
1765 nxdomain = 1;
1766 if (!dryrun)
1767 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001768 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001769 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001770 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001771
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001772 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1773 {
1774 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001775 struct interface_name *intr;
1776
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001777 if (flag == F_IPV6)
1778#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001779 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001780#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001781 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001782#endif
1783
1784 if (qtype != type && qtype != T_ANY)
1785 continue;
1786
Simon Kelley316e2732010-01-22 20:16:09 +00001787 /* Check for "A for A" queries; be rather conservative
1788 about what looks like dotted-quad. */
1789 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001790 {
Simon Kelley316e2732010-01-22 20:16:09 +00001791 char *cp;
1792 unsigned int i, a;
1793 int x;
1794
1795 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001796 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001797 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001798 {
1799 i = 5;
1800 break;
1801 }
1802
1803 a = (a << 8) + x;
1804
1805 if (*cp == '.')
1806 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001807 }
Simon Kelley316e2732010-01-22 20:16:09 +00001808
1809 if (i == 4)
1810 {
1811 ans = 1;
1812 if (!dryrun)
1813 {
1814 addr.addr.addr4.s_addr = htonl(a);
1815 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1816 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1817 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1818 anscount++;
1819 }
1820 continue;
1821 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001822 }
1823
Simon Kelleyf2621c72007-04-29 19:47:21 +01001824 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001825 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001826 for (intr = daemon->int_names; intr; intr = intr->next)
1827 if (hostname_isequal(name, intr->name))
1828 break;
1829
1830 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001831 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001832 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001833 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001834
Simon Kelley115ac3e2013-05-20 11:28:32 +01001835 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001836
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001837 for (intr = daemon->int_names; intr; intr = intr->next)
1838 if (hostname_isequal(name, intr->name))
1839 {
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001840 ans = 1;
1841 if (!dryrun)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001842 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001843
1844 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1845#ifdef HAVE_IPV6
1846 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
1847#endif
1848 {
1849 gotit = 1;
1850 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1851 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1852 daemon->local_ttl, NULL, type, C_IN,
1853 type == T_A ? "4" : "6", &addrlist->addr))
1854 anscount++;
1855 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001856 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001857 }
1858
1859 if (!dryrun && !gotit)
1860 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1861
Simon Kelley115ac3e2013-05-20 11:28:32 +01001862 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001863 }
1864
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001865 cname_restart:
1866 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
1867 {
1868 int localise = 0;
1869
1870 /* See if a putative address is on the network from which we recieved
1871 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001872 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001873 {
1874 struct crec *save = crecp;
1875 do {
1876 if ((crecp->flags & F_HOSTS) &&
1877 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1878 {
1879 localise = 1;
1880 break;
1881 }
1882 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1883 crecp = save;
1884 }
Simon Kelley824202e2014-01-23 20:59:46 +00001885
1886#ifdef HAVE_DNSSEC
1887 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
1888 (crecp->flags & F_DNSSECOK) &&
1889 !(crecp->flags & F_NEG) &&
1890 sec_reqd &&
1891 option_bool(OPT_DNSSEC_VALID))
1892 {
1893 /* We're returning validated data, need to return the RRSIG too. */
1894
1895 int sigtype = type;
1896 /* The signature may have expired even though the data is still in cache,
1897 forward instead of answering from cache if so. */
1898 int gotsig = 0;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001899
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001900 if (crecp->flags & F_CNAME)
Simon Kelley824202e2014-01-23 20:59:46 +00001901 sigtype = T_CNAME;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001902
Simon Kelley824202e2014-01-23 20:59:46 +00001903 crecp = NULL;
1904 while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001905 {
Simon Kelley824202e2014-01-23 20:59:46 +00001906 if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001907 {
Simon Kelley824202e2014-01-23 20:59:46 +00001908 char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
1909 gotsig = 1;
1910
1911 if (!dryrun &&
1912 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1913 crecp->ttd - now, &nameoffset,
1914 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001915 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001916 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001917 }
Simon Kelley824202e2014-01-23 20:59:46 +00001918 /* Need to re-run original cache search */
1919 crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL;
1920 }
1921
1922#endif
1923 if (crecp)
1924 do
1925 {
1926 /* don't answer wildcard queries with data not from /etc/hosts
1927 or DHCP leases */
1928 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1929 break;
1930
1931 if (!(crecp->flags & F_DNSSECOK))
1932 sec_data = 0;
1933
1934 if (crecp->flags & F_CNAME)
1935 {
1936 char *cname_target = cache_get_cname_target(crecp);
1937
1938 if (!dryrun)
1939 {
1940 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1941 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1942 crec_ttl(crecp, now), &nameoffset,
1943 T_CNAME, C_IN, "d", cname_target))
1944 anscount++;
1945 }
1946
1947 strcpy(name, cname_target);
1948 /* check if target interface_name */
1949 if (crecp->addr.cname.uid == -1)
1950 goto intname_restart;
1951 else
1952 goto cname_restart;
1953 }
1954
1955 if (crecp->flags & F_NEG)
1956 {
1957 /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
1958 is cached and the client wants DNSSEC, forward rather than answering from the cache */
1959 if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
1960 {
1961 ans = 1;
1962 auth = 0;
1963 if (crecp->flags & F_NXDOMAIN)
1964 nxdomain = 1;
1965 if (!dryrun)
1966 log_query(crecp->flags, name, NULL, NULL);
1967 }
1968 }
1969 else
1970 {
1971 /* If we are returning local answers depending on network,
1972 filter here. */
1973 if (localise &&
1974 (crecp->flags & F_HOSTS) &&
1975 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1976 continue;
1977
1978 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1979 auth = 0;
1980
1981 ans = 1;
1982 if (!dryrun)
1983 {
1984 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
1985 record_source(crecp->uid));
1986
1987 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1988 crec_ttl(crecp, now), NULL, type, C_IN,
1989 type == T_A ? "4" : "6", &crecp->addr))
1990 anscount++;
1991 }
1992 }
1993 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001994 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001995 else if (is_name_synthetic(flag, name, &addr))
1996 {
1997 ans = 1;
1998 if (!dryrun)
1999 {
2000 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
2001 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2002 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
2003 anscount++;
2004 }
2005 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002006 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002007
2008 if (qtype == T_CNAME || qtype == T_ANY)
2009 {
2010 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +00002011 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002012 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00002013 if (!(crecp->flags & F_DNSSECOK))
2014 sec_data = 0;
2015
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002016 ans = 1;
2017 if (!dryrun)
2018 {
2019 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2020 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2021 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01002022 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002023 anscount++;
2024 }
2025 }
2026 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002027
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002028 if (qtype == T_MX || qtype == T_ANY)
2029 {
2030 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00002031 for (rec = daemon->mxnames; rec; rec = rec->next)
2032 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002033 {
2034 ans = found = 1;
2035 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002036 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002037 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002038 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00002039 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2040 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
2041 {
2042 anscount++;
2043 if (rec->target)
2044 rec->offset = offset;
2045 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002046 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002047 }
2048
Simon Kelley28866e92011-02-14 20:19:14 +00002049 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002050 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
2051 {
2052 ans = 1;
2053 if (!dryrun)
2054 {
Simon Kelley28866e92011-02-14 20:19:14 +00002055 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002056 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
2057 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00002058 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002059 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002060 }
2061 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002062 }
2063
2064 if (qtype == T_SRV || qtype == T_ANY)
2065 {
2066 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00002067 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
2068
Simon Kelley0a852542005-03-23 20:28:59 +00002069 for (rec = daemon->mxnames; rec; rec = rec->next)
2070 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002071 {
2072 found = ans = 1;
2073 if (!dryrun)
2074 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002075 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002076 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002077 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00002078 &offset, T_SRV, C_IN, "sssd",
2079 rec->priority, rec->weight, rec->srvport, rec->target))
2080 {
2081 anscount++;
2082 if (rec->target)
2083 rec->offset = offset;
2084 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002085 }
Simon Kelley28866e92011-02-14 20:19:14 +00002086
2087 /* unlink first SRV record found */
2088 if (!move)
2089 {
2090 move = rec;
2091 *up = rec->next;
2092 }
2093 else
2094 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002095 }
Simon Kelley28866e92011-02-14 20:19:14 +00002096 else
2097 up = &rec->next;
2098
2099 /* put first SRV record back at the end. */
2100 if (move)
2101 {
2102 *up = move;
2103 move->next = NULL;
2104 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002105
Simon Kelley28866e92011-02-14 20:19:14 +00002106 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002107 {
2108 ans = 1;
2109 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002110 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002111 }
2112 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002113
2114 if (qtype == T_NAPTR || qtype == T_ANY)
2115 {
2116 struct naptr *na;
2117 for (na = daemon->naptr; na; na = na->next)
2118 if (hostname_isequal(name, na->name))
2119 {
2120 ans = 1;
2121 if (!dryrun)
2122 {
Simon Kelley28866e92011-02-14 20:19:14 +00002123 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01002124 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2125 NULL, T_NAPTR, C_IN, "sszzzd",
2126 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
2127 anscount++;
2128 }
2129 }
2130 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002131
2132 if (qtype == T_MAILB)
2133 ans = 1, nxdomain = 1;
2134
Simon Kelley28866e92011-02-14 20:19:14 +00002135 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002136 {
2137 ans = 1;
2138 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002139 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002140 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002141 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002142
2143 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002144 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002145 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002146
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002147 if (dryrun)
2148 {
2149 dryrun = 0;
2150 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002151 }
2152
Simon Kelley0a852542005-03-23 20:28:59 +00002153 /* create an additional data section, for stuff in SRV and MX record replies. */
2154 for (rec = daemon->mxnames; rec; rec = rec->next)
2155 if (rec->offset != 0)
2156 {
2157 /* squash dupes */
2158 struct mx_srv_record *tmp;
2159 for (tmp = rec->next; tmp; tmp = tmp->next)
2160 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2161 tmp->offset = 0;
2162
2163 crecp = NULL;
2164 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2165 {
Simon Kelley0a852542005-03-23 20:28:59 +00002166#ifdef HAVE_IPV6
2167 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2168#else
2169 int type = T_A;
2170#endif
2171 if (crecp->flags & F_NEG)
2172 continue;
2173
Simon Kelley9009d742008-11-14 20:04:27 +00002174 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2175 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002176 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2177 addncount++;
2178 }
2179 }
2180
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002181 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002182 /* clear authoritative and truncated flags, set QR flag */
2183 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2184 /* set RA flag */
2185 header->hb4 |= HB4_RA;
2186
2187 /* authoritive - only hosts and DHCP derived names. */
2188 if (auth)
2189 header->hb3 |= HB3_AA;
2190
2191 /* truncation */
2192 if (trunc)
2193 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002194
Simon Kelley45cca582013-10-15 10:20:13 +01002195 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002196 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002197 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002198 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002199 header->ancount = htons(anscount);
2200 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002201 header->arcount = htons(addncount);
Simon Kelleya25720a2014-01-14 23:13:55 +00002202
2203 header->hb4 &= ~HB4_AD;
2204 len = ansp - (unsigned char *)header;
2205
2206 if (have_pseudoheader)
2207 {
2208 len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
2209 if (sec_reqd && sec_data)
2210 header->hb4 |= HB4_AD;
2211
2212 }
2213
2214 return len ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002215}
2216