blob: fc6d09ca7cedaea4f17111931f69234c815e8dc7 [file] [log] [blame]
Simon Kelley61744352013-01-31 14:34:40 +00001/* dnsmasq is Copyright (c) 2000-2013 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 Kelleyf6b7dc42005-01-23 12:06:08 +000019
Simon Kelley9009d742008-11-14 20:04:27 +000020#define CHECK_LEN(header, pp, plen, len) \
21 ((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
22
23#define ADD_RDLEN(header, pp, plen, len) \
Simon Kelley22b135a2012-03-01 19:54:50 +000024 (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
Simon Kelley9009d742008-11-14 20:04:27 +000025
Simon Kelley4f7b3042012-11-28 21:27:02 +000026int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
27 char *name, int isExtract, int extrabytes)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000028{
Simon Kelley3d8df262005-08-29 12:19:27 +010029 unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000030 unsigned int j, l, hops = 0;
31 int retvalue = 1;
32
Simon Kelleyf6b7dc42005-01-23 12:06:08 +000033 if (isExtract)
34 *cp = 0;
35
Simon Kelley9009d742008-11-14 20:04:27 +000036 while (1)
37 {
38 unsigned int label_type;
39
40 if (!CHECK_LEN(header, p, plen, 1))
41 return 0;
42
43 if ((l = *p++) == 0)
44 /* end marker */
45 {
46 /* check that there are the correct no of bytes after the name */
47 if (!CHECK_LEN(header, p, plen, extrabytes))
48 return 0;
49
50 if (isExtract)
51 {
52 if (cp != (unsigned char *)name)
53 cp--;
54 *cp = 0; /* terminate: lose final period */
55 }
56 else if (*cp != 0)
57 retvalue = 2;
58
59 if (p1) /* we jumped via compression */
60 *pp = p1;
61 else
62 *pp = p;
63
64 return retvalue;
65 }
66
67 label_type = l & 0xc0;
68
Simon Kelley9e4abcb2004-01-22 19:47:41 +000069 if (label_type == 0xc0) /* pointer */
70 {
Simon Kelley9009d742008-11-14 20:04:27 +000071 if (!CHECK_LEN(header, p, plen, 1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000072 return 0;
73
74 /* get offset */
75 l = (l&0x3f) << 8;
76 l |= *p++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000077
78 if (!p1) /* first jump, save location to go back to */
79 p1 = p;
80
81 hops++; /* break malicious infinite loops */
82 if (hops > 255)
83 return 0;
84
85 p = l + (unsigned char *)header;
86 }
87 else if (label_type == 0x80)
88 return 0; /* reserved */
89 else if (label_type == 0x40)
90 { /* ELT */
91 unsigned int count, digs;
92
93 if ((l & 0x3f) != 1)
94 return 0; /* we only understand bitstrings */
95
96 if (!isExtract)
97 return 0; /* Cannot compare bitsrings */
98
99 count = *p++;
100 if (count == 0)
101 count = 256;
102 digs = ((count-1)>>2)+1;
103
104 /* output is \[x<hex>/siz]. which is digs+9 chars */
Simon Kelley3d8df262005-08-29 12:19:27 +0100105 if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000106 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000107 if (!CHECK_LEN(header, p, plen, (count-1)>>3))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000108 return 0;
109
110 *cp++ = '\\';
111 *cp++ = '[';
112 *cp++ = 'x';
113 for (j=0; j<digs; j++)
114 {
115 unsigned int dig;
116 if (j%2 == 0)
117 dig = *p >> 4;
118 else
119 dig = *p++ & 0x0f;
120
121 *cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
122 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100123 cp += sprintf((char *)cp, "/%d]", count);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000124 /* do this here to overwrite the zero char from sprintf */
125 *cp++ = '.';
126 }
127 else
128 { /* label_type = 0 -> label. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100129 if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000130 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000131 if (!CHECK_LEN(header, p, plen, l))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000132 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000133
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000134 for(j=0; j<l; j++, p++)
135 if (isExtract)
136 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100137 unsigned char c = *p;
138 if (isascii(c) && !iscntrl(c) && c != '.')
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000139 *cp++ = *p;
140 else
141 return 0;
142 }
143 else
144 {
145 unsigned char c1 = *cp, c2 = *p;
146
147 if (c1 == 0)
148 retvalue = 2;
149 else
150 {
151 cp++;
152 if (c1 >= 'A' && c1 <= 'Z')
153 c1 += 'a' - 'A';
154 if (c2 >= 'A' && c2 <= 'Z')
155 c2 += 'a' - 'A';
156
157 if (c1 != c2)
158 retvalue = 2;
159 }
160 }
161
162 if (isExtract)
163 *cp++ = '.';
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000164 else if (*cp != 0 && *cp++ != '.')
165 retvalue = 2;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000166 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000167 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000168}
169
170/* Max size of input string (for IPv6) is 75 chars.) */
171#define MAXARPANAME 75
Simon Kelley4f7b3042012-11-28 21:27:02 +0000172int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000173{
174 int j;
175 char name[MAXARPANAME+1], *cp1;
176 unsigned char *addr = (unsigned char *)addrp;
177 char *lastchunk = NULL, *penchunk = NULL;
178
179 if (strlen(namein) > MAXARPANAME)
180 return 0;
181
182 memset(addrp, 0, sizeof(struct all_addr));
183
184 /* turn name into a series of asciiz strings */
185 /* j counts no of labels */
186 for(j = 1,cp1 = name; *namein; cp1++, namein++)
187 if (*namein == '.')
188 {
189 penchunk = lastchunk;
190 lastchunk = cp1 + 1;
191 *cp1 = 0;
192 j++;
193 }
194 else
195 *cp1 = *namein;
196
197 *cp1 = 0;
198
199 if (j<3)
200 return 0;
201
202 if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
203 {
204 /* IP v4 */
205 /* address arives as a name of the form
206 www.xxx.yyy.zzz.in-addr.arpa
207 some of the low order address octets might be missing
208 and should be set to zero. */
209 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
210 {
211 /* check for digits only (weeds out things like
212 50.0/24.67.28.64.in-addr.arpa which are used
213 as CNAME targets according to RFC 2317 */
214 char *cp;
215 for (cp = cp1; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000216 if (!isdigit((unsigned char)*cp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000217 return 0;
218
219 addr[3] = addr[2];
220 addr[2] = addr[1];
221 addr[1] = addr[0];
222 addr[0] = atoi(cp1);
223 }
224
225 return F_IPV4;
226 }
227#ifdef HAVE_IPV6
228 else if (hostname_isequal(penchunk, "ip6") &&
229 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
230 {
231 /* IP v6:
232 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
233 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
234
235 Note that most of these the various reprentations are obsolete and
236 left-over from the many DNS-for-IPv6 wars. We support all the formats
237 that we can since there is no reason not to.
238 */
239
240 if (*name == '\\' && *(name+1) == '[' &&
241 (*(name+2) == 'x' || *(name+2) == 'X'))
242 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000243 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000244 {
245 char xdig[2];
246 xdig[0] = *cp1;
247 xdig[1] = 0;
248 if (j%2)
249 addr[j/2] |= strtol(xdig, NULL, 16);
250 else
251 addr[j/2] = strtol(xdig, NULL, 16) << 4;
252 }
253
254 if (*cp1 == '/' && j == 32)
255 return F_IPV6;
256 }
257 else
258 {
259 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
260 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000261 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000262 return 0;
263
264 for (j = sizeof(struct all_addr)-1; j>0; j--)
265 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
266 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
267 }
268
269 return F_IPV6;
270 }
271 }
272#endif
273
274 return 0;
275}
276
Simon Kelley572b41e2011-02-18 18:11:18 +0000277static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100278{
279 while(1)
280 {
Simon Kelley9009d742008-11-14 20:04:27 +0000281 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100282
Simon Kelley9009d742008-11-14 20:04:27 +0000283 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100284 return NULL;
285
Simon Kelley9009d742008-11-14 20:04:27 +0000286 label_type = (*ansp) & 0xc0;
287
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100288 if (label_type == 0xc0)
289 {
290 /* pointer for compression. */
291 ansp += 2;
292 break;
293 }
294 else if (label_type == 0x80)
295 return NULL; /* reserved */
296 else if (label_type == 0x40)
297 {
298 /* Extended label type */
299 unsigned int count;
300
Simon Kelley9009d742008-11-14 20:04:27 +0000301 if (!CHECK_LEN(header, ansp, plen, 2))
302 return NULL;
303
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100304 if (((*ansp++) & 0x3f) != 1)
305 return NULL; /* we only understand bitstrings */
306
307 count = *(ansp++); /* Bits in bitstring */
308
309 if (count == 0) /* count == 0 means 256 bits */
310 ansp += 32;
311 else
312 ansp += ((count-1)>>3)+1;
313 }
314 else
315 { /* label type == 0 Bottom six bits is length */
316 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000317
318 if (!ADD_RDLEN(header, ansp, plen, len))
319 return NULL;
320
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100321 if (len == 0)
322 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100323 }
324 }
Simon Kelley9009d742008-11-14 20:04:27 +0000325
326 if (!CHECK_LEN(header, ansp, plen, extrabytes))
327 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100328
329 return ansp;
330}
331
Simon Kelley4f7b3042012-11-28 21:27:02 +0000332unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000333{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100334 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000335 unsigned char *ansp = (unsigned char *)(header+1);
336
Simon Kelley5aabfc72007-08-29 11:24:47 +0100337 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000338 {
Simon Kelley9009d742008-11-14 20:04:27 +0000339 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100340 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000341 ansp += 4; /* class and type */
342 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000343
344 return ansp;
345}
346
Simon Kelley572b41e2011-02-18 18:11:18 +0000347static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100348{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100349 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100350
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100351 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100352 {
Simon Kelley9009d742008-11-14 20:04:27 +0000353 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100354 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100355 ansp += 8; /* type, class, TTL */
356 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000357 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100358 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100359 }
360
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100361 return ansp;
362}
363
Simon Kelley0a852542005-03-23 20:28:59 +0000364/* CRC the question section. This is used to safely detect query
365 retransmision and to detect answers to questions we didn't ask, which
366 might be poisoning attacks. Note that we decode the name rather
367 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000368 We ignore case in the names for the same reason. Return all-ones
369 if there is not question section. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000370unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100371{
Simon Kelley91dccd02005-03-31 17:48:32 +0100372 int q;
373 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000374 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100375
Simon Kelley5aabfc72007-08-29 11:24:47 +0100376 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000377 {
Simon Kelley9009d742008-11-14 20:04:27 +0000378 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000379 return crc; /* bad packet */
380
Simon Kelley3d8df262005-08-29 12:19:27 +0100381 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000382 {
383 int i = 8;
384 char c = *p1;
385
386 if (c >= 'A' && c <= 'Z')
387 c += 'a' - 'A';
388
389 crc ^= c << 24;
390 while (i--)
391 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
392 }
393
394 /* CRC the class and type as well */
395 for (p1 = p; p1 < p+4; p1++)
396 {
397 int i = 8;
398 crc ^= *p1 << 24;
399 while (i--)
400 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
401 }
402
403 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000404 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000405 return crc; /* bad packet */
406 }
407
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100408 return crc;
409}
410
411
Simon Kelley572b41e2011-02-18 18:11:18 +0000412size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100413{
414 unsigned char *ansp = skip_questions(header, plen);
415
Simon Kelley9009d742008-11-14 20:04:27 +0000416 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100417 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000418 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100419
420 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
421 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000422 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100423
Simon Kelley36717ee2004-09-20 19:20:58 +0100424 /* restore pseudoheader */
425 if (pheader && ntohs(header->arcount) == 0)
426 {
427 /* must use memmove, may overlap */
428 memmove(ansp, pheader, hlen);
429 header->arcount = htons(1);
430 ansp += hlen;
431 }
432
433 return ansp - (unsigned char *)header;
434}
435
Simon Kelley572b41e2011-02-18 18:11:18 +0000436unsigned 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 +0100437{
438 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
Simon Kelley832af0b2007-01-21 20:01:28 +0000439 also return length of pseudoheader in *len and pointer to the UDP size in *p
440 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
441 forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100442
443 int i, arcount = ntohs(header->arcount);
Simon Kelley832af0b2007-01-21 20:01:28 +0000444 unsigned char *ansp = (unsigned char *)(header+1);
445 unsigned short rdlen, type, class;
446 unsigned char *ret = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000447
448 if (is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000449 {
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000450 *is_sign = 0;
451
Simon Kelley572b41e2011-02-18 18:11:18 +0000452 if (OPCODE(header) == QUERY)
Simon Kelley832af0b2007-01-21 20:01:28 +0000453 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100454 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000455 {
Simon Kelley9009d742008-11-14 20:04:27 +0000456 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000457 return NULL;
458
459 GETSHORT(type, ansp);
460 GETSHORT(class, ansp);
461
462 if (class == C_IN && type == T_TKEY)
463 *is_sign = 1;
464 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000465 }
466 }
467 else
468 {
469 if (!(ansp = skip_questions(header, plen)))
470 return NULL;
471 }
472
473 if (arcount == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100474 return NULL;
475
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100476 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
477 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000478
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100479 for (i = 0; i < arcount; i++)
480 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100481 unsigned char *save, *start = ansp;
Simon Kelley9009d742008-11-14 20:04:27 +0000482 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100483 return NULL;
484
485 GETSHORT(type, ansp);
486 save = ansp;
Simon Kelley832af0b2007-01-21 20:01:28 +0000487 GETSHORT(class, ansp);
488 ansp += 4; /* TTL */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100489 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000490 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100491 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000492 if (type == T_OPT)
Simon Kelley36717ee2004-09-20 19:20:58 +0100493 {
494 if (len)
495 *len = ansp - start;
496 if (p)
497 *p = save;
Simon Kelley832af0b2007-01-21 20:01:28 +0000498 ret = start;
Simon Kelley36717ee2004-09-20 19:20:58 +0100499 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000500 else if (is_sign &&
501 i == arcount - 1 &&
502 class == C_ANY &&
503 (type == T_SIG || type == T_TSIG))
504 *is_sign = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100505 }
506
Simon Kelley832af0b2007-01-21 20:01:28 +0000507 return ret;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100508}
Simon Kelley28866e92011-02-14 20:19:14 +0000509
510struct macparm {
511 unsigned char *limit;
Simon Kelley572b41e2011-02-18 18:11:18 +0000512 struct dns_header *header;
Simon Kelley28866e92011-02-14 20:19:14 +0000513 size_t plen;
514 union mysockaddr *l3;
515};
Simon Kelleyed4c0762013-10-08 20:46:34 +0100516
517static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
518 int optno, unsigned char *opt, size_t optlen)
519{
520 unsigned char *lenp, *datap, *p;
521 int rdlen;
522
523 if (ntohs(header->arcount) == 0)
524 {
525 /* We are adding the pseudoheader */
526 if (!(p = skip_questions(header, plen)) ||
527 !(p = skip_section(p,
528 ntohs(header->ancount) + ntohs(header->nscount),
529 header, plen)))
530 return plen;
531 *p++ = 0; /* empty name */
532 PUTSHORT(T_OPT, p);
533 PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
534 PUTLONG(0, p); /* extended RCODE */
535 lenp = p;
536 PUTSHORT(0, p); /* RDLEN */
537 rdlen = 0;
538 if (((ssize_t)optlen) > (limit - (p + 4)))
539 return plen; /* Too big */
540 header->arcount = htons(1);
541 datap = p;
542 }
543 else
544 {
545 int i, is_sign;
546 unsigned short code, len;
547
548 if (ntohs(header->arcount) != 1 ||
549 !(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)) ||
550 is_sign ||
551 (!(p = skip_name(p, header, plen, 10))))
552 return plen;
553
554 p += 8; /* skip UDP length and RCODE */
555
556 lenp = p;
557 GETSHORT(rdlen, p);
558 if (!CHECK_LEN(header, p, plen, rdlen))
559 return plen; /* bad packet */
560 datap = p;
561
562 /* check if option already there */
563 for (i = 0; i + 4 < rdlen; i += len + 4)
564 {
565 GETSHORT(code, p);
566 GETSHORT(len, p);
567 if (code == optno)
568 return plen;
569 p += len;
570 }
571
572 if (((ssize_t)optlen) > (limit - (p + 4)))
573 return plen; /* Too big */
574 }
575
576 PUTSHORT(optno, p);
577 PUTSHORT(optlen, p);
578 memcpy(p, opt, optlen);
579 p += optlen;
580
581 PUTSHORT(p - datap, lenp);
582 return p - (unsigned char *)header;
583
584}
Simon Kelley28866e92011-02-14 20:19:14 +0000585
586static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
587{
588 struct macparm *parm = parmv;
589 int match = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100590
Simon Kelley28866e92011-02-14 20:19:14 +0000591 if (family == parm->l3->sa.sa_family)
592 {
593 if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
594 match = 1;
595#ifdef HAVE_IPV6
596 else
597 if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
598 match = 1;
599#endif
600 }
601
602 if (!match)
603 return 1; /* continue */
Simon Kelley28866e92011-02-14 20:19:14 +0000604
Simon Kelleyed4c0762013-10-08 20:46:34 +0100605 parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen);
Simon Kelley28866e92011-02-14 20:19:14 +0000606
607 return 0; /* done */
608}
609
Simon Kelley572b41e2011-02-18 18:11:18 +0000610size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
Simon Kelley28866e92011-02-14 20:19:14 +0000611{
612 struct macparm parm;
613
614/* Must have an existing pseudoheader as the only ar-record,
615 or have no ar-records. Must also not be signed */
616
617 if (ntohs(header->arcount) > 1)
618 return plen;
619
620 parm.header = header;
621 parm.limit = (unsigned char *)limit;
622 parm.plen = plen;
623 parm.l3 = l3;
624
625 iface_enumerate(AF_UNSPEC, &parm, filter_mac);
626
627 return parm.plen;
628}
629
Simon Kelleyed4c0762013-10-08 20:46:34 +0100630struct subnet_opt {
631 u16 family;
632 u8 source_netmask, scope_netmask;
633#ifdef HAVE_IPV6
634 u8 addr[IN6ADDRSZ];
635#else
636 u8 addr[INADDRSZ];
637#endif
638};
639
640size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
641{
642 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
643
644 int len;
645 void *addrp;
646
Simon Kelleyed4c0762013-10-08 20:46:34 +0100647#ifdef HAVE_IPV6
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100648 if (source->sa.sa_family == AF_INET6)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100649 {
650 opt->family = htons(2);
651 opt->source_netmask = daemon->addr6_netmask;
652 addrp = &source->in6.sin6_addr;
653 }
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100654 else
Simon Kelleyed4c0762013-10-08 20:46:34 +0100655#endif
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100656 {
657 opt->family = htons(1);
658 opt->source_netmask = daemon->addr4_netmask;
659 addrp = &source->in.sin_addr;
660 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100661
662 opt->scope_netmask = 0;
663 len = 0;
664
665 if (opt->source_netmask != 0)
666 {
667 len = ((opt->source_netmask - 1) >> 3) + 1;
668 memcpy(opt->addr, addrp, len);
669 if (opt->source_netmask & 7)
670 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
671 }
672
673 return len + 4;
674}
675
676size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
677{
678 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
679
680 int len;
681 struct subnet_opt opt;
682
683 len = calc_subnet_opt(&opt, source);
684 return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len);
685}
686
687int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
688{
689 /* Section 9.2, Check that subnet option in reply matches. */
690
691
692 int len, calc_len;
693 struct subnet_opt opt;
694 unsigned char *p;
695 int code, i, rdlen;
696
697 calc_len = calc_subnet_opt(&opt, peer);
698
699 if (!(p = skip_name(pseudoheader, header, plen, 10)))
700 return 1;
701
702 p += 8; /* skip UDP length and RCODE */
703
704 GETSHORT(rdlen, p);
705 if (!CHECK_LEN(header, p, plen, rdlen))
706 return 1; /* bad packet */
707
708 /* check if option there */
709 for (i = 0; i + 4 < rdlen; i += len + 4)
710 {
711 GETSHORT(code, p);
712 GETSHORT(len, p);
713 if (code == EDNS0_OPTION_CLIENT_SUBNET)
714 {
715 /* make sure this doesn't mismatch. */
716 opt.scope_netmask = p[3];
717 if (len != calc_len || memcmp(p, &opt, len) != 0)
718 return 0;
719 }
720 p += len;
721 }
722
723 return 1;
724}
725
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000726/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100727int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000728{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100729 in_addr_t ip_addr = ntohl(addr.s_addr);
730
731 return
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100732 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100733 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
734 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
735 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
736 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000737}
Simon Kelley1cff1662004-03-12 08:12:58 +0000738
Simon Kelley572b41e2011-02-18 18:11:18 +0000739static 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 +0000740{
741 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000742
743 for (i = count; i != 0; i--)
744 {
Simon Kelley28866e92011-02-14 20:19:14 +0000745 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100746 {
747 if (!extract_name(header, qlen, &p, name, 1, 10))
748 return 0;
749 }
750 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000751 return 0; /* bad packet */
752
753 GETSHORT(qtype, p);
754 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100755 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000756 GETSHORT(rdlen, p);
757
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100758 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000759 {
760 struct doctor *doctor;
761 struct in_addr addr;
762
Simon Kelley9009d742008-11-14 20:04:27 +0000763 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
764 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100765
766 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000767 memcpy(&addr, p, INADDRSZ);
768
769 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000770 {
771 if (doctor->end.s_addr == 0)
772 {
773 if (!is_same_net(doctor->in, addr, doctor->mask))
774 continue;
775 }
776 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
777 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
778 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100779
Simon Kelley73a08a22009-02-05 20:28:08 +0000780 addr.s_addr &= ~doctor->mask.s_addr;
781 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
782 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000783 header->hb3 &= ~HB3_AA;
Simon Kelley73a08a22009-02-05 20:28:08 +0000784 memcpy(p, &addr, INADDRSZ);
785 break;
786 }
Simon Kelley824af852008-02-12 20:43:05 +0000787 }
Simon Kelley28866e92011-02-14 20:19:14 +0000788 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100789 {
790 unsigned char *p1 = p;
791 if (!CHECK_LEN(header, p1, qlen, rdlen))
792 return 0;
793 while ((p1 - p) < rdlen)
794 {
795 unsigned int i, len = *p1;
796 unsigned char *p2 = p1;
797 /* make counted string zero-term and sanitise */
798 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100799 {
800 if (!isprint((int)*(p2+1)))
801 break;
802
803 *p2 = *(p2+1);
804 p2++;
805 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100806 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000807 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100808 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100809 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100810 *p1 = len;
811 p1 += len+1;
812 }
813 }
Simon Kelley824af852008-02-12 20:43:05 +0000814
Simon Kelley9009d742008-11-14 20:04:27 +0000815 if (!ADD_RDLEN(header, p, qlen, rdlen))
816 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000817 }
818
819 return p;
820}
821
Simon Kelley572b41e2011-02-18 18:11:18 +0000822static int find_soa(struct dns_header *header, size_t qlen, char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000823{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100824 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000825 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100826 unsigned long ttl, minttl = ULONG_MAX;
827 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000828
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100829 /* first move to NS section and find TTL from any SOA section */
830 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100831 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name)))
Simon Kelley824af852008-02-12 20:43:05 +0000832 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000833
Simon Kelley5aabfc72007-08-29 11:24:47 +0100834 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000835 {
Simon Kelley9009d742008-11-14 20:04:27 +0000836 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100837 return 0; /* bad packet */
838
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000839 GETSHORT(qtype, p);
840 GETSHORT(qclass, p);
841 GETLONG(ttl, p);
842 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843
844 if ((qclass == C_IN) && (qtype == T_SOA))
845 {
846 found_soa = 1;
847 if (ttl < minttl)
848 minttl = ttl;
849
850 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000851 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100852 return 0;
853 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000854 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100855 return 0;
856 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
857
858 GETLONG(ttl, p); /* minTTL */
859 if (ttl < minttl)
860 minttl = ttl;
861 }
Simon Kelley9009d742008-11-14 20:04:27 +0000862 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100863 return 0; /* bad packet */
864 }
Simon Kelley9009d742008-11-14 20:04:27 +0000865
Simon Kelley824af852008-02-12 20:43:05 +0000866 /* rewrite addresses in additioal section too */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100867 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL))
Simon Kelley824af852008-02-12 20:43:05 +0000868 return 0;
869
870 if (!found_soa)
871 minttl = daemon->neg_ttl;
872
873 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100874}
875
876/* Note that the following code can create CNAME chains that don't point to a real record,
877 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 +0000878 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100879 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000880int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000881 char **ipsets, int is_sign, int check_rebind, int checking_disabled)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882{
Simon Kelley824af852008-02-12 20:43:05 +0000883 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100884 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000885 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100886 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000887#ifdef HAVE_IPSET
888 char **ipsets_cur;
889#else
890 (void)ipsets; /* unused */
891#endif
892
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100893 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000894
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100895 /* 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 +0000896 if (daemon->doctors || option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000897 {
898 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100899 ttl = find_soa(header, qlen, name);
Simon Kelley0a852542005-03-23 20:28:59 +0000900 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100901
902 /* go through the questions. */
903 p = (unsigned char *)(header+1);
904
Simon Kelley5aabfc72007-08-29 11:24:47 +0100905 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100906 {
907 int found = 0, cname_count = 5;
908 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000909 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000910 unsigned long cttl = ULONG_MAX, attl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100911
Simon Kelley824af852008-02-12 20:43:05 +0000912 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000913 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000914 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100915
916 GETSHORT(qtype, p);
917 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000918
919 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100920 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000921
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100922 /* PTRs: we chase CNAMEs here, since we have no way to
923 represent them in the cache. */
924 if (qtype == T_PTR)
925 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000926 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100927
928 if (!name_encoding)
929 continue;
930
931 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000932 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100933 cname_loop:
934 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000935 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100936
Simon Kelley5aabfc72007-08-29 11:24:47 +0100937 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100938 {
Simon Kelley824af852008-02-12 20:43:05 +0000939 unsigned char *tmp = namep;
940 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000941 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
942 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000943 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100944
945 GETSHORT(aqtype, p1);
946 GETSHORT(aqclass, p1);
947 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100948 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
949 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000950 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100951 PUTLONG(daemon->max_ttl, p1);
952 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100953 GETSHORT(ardlen, p1);
954 endrr = p1+ardlen;
955
956 /* TTL of record is minimum of CNAMES and PTR */
957 if (attl < cttl)
958 cttl = attl;
959
960 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
961 {
Simon Kelley9009d742008-11-14 20:04:27 +0000962 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000963 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100964
965 if (aqtype == T_CNAME)
966 {
967 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000968 return 0; /* looped CNAMES */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100969 goto cname_loop;
970 }
971
972 cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);
973 found = 1;
974 }
975
976 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000977 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000978 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100979 }
980 }
981
Simon Kelley28866e92011-02-14 20:19:14 +0000982 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100983 {
984 if (!searched_soa)
985 {
986 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100987 ttl = find_soa(header, qlen, NULL);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100988 }
989 if (ttl)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100990 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000991 }
992 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100993 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000994 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100995 /* everything other than PTR */
996 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100997 int addrlen;
998
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100999 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001000 {
1001 addrlen = INADDRSZ;
1002 flags |= F_IPV4;
1003 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001004#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001005 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001006 {
1007 addrlen = IN6ADDRSZ;
1008 flags |= F_IPV6;
1009 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001010#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001011 else
1012 continue;
1013
Simon Kelley45cca582013-10-15 10:20:13 +01001014 cname_loop1:
1015 if (!(p1 = skip_questions(header, qlen)))
1016 return 0;
1017
1018 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001019 {
Simon Kelley45cca582013-10-15 10:20:13 +01001020 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
1021 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001022
Simon Kelley45cca582013-10-15 10:20:13 +01001023 GETSHORT(aqtype, p1);
1024 GETSHORT(aqclass, p1);
1025 GETLONG(attl, p1);
1026 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001027 {
Simon Kelley45cca582013-10-15 10:20:13 +01001028 (p1) -= 4;
1029 PUTLONG(daemon->max_ttl, p1);
1030 }
1031 GETSHORT(ardlen, p1);
1032 endrr = p1+ardlen;
1033
1034 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
1035 {
1036 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001037 {
Simon Kelley45cca582013-10-15 10:20:13 +01001038 if (!cname_count--)
1039 return 0; /* looped CNAMES */
1040 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
1041 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001042 {
Simon Kelley45cca582013-10-15 10:20:13 +01001043 newc->addr.cname.target.cache = NULL;
1044 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001045 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001046 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001047 cpp->addr.cname.uid = newc->uid;
1048 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001049 }
Simon Kelley45cca582013-10-15 10:20:13 +01001050
1051 cpp = newc;
1052 if (attl < cttl)
1053 cttl = attl;
1054
1055 if (!extract_name(header, qlen, &p1, name, 1, 0))
1056 return 0;
1057 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001058 }
Simon Kelley45cca582013-10-15 10:20:13 +01001059 else if (!(flags & F_NXDOMAIN))
1060 {
1061 found = 1;
1062
1063 /* copy address into aligned storage */
1064 if (!CHECK_LEN(header, p1, qlen, addrlen))
1065 return 0; /* bad packet */
1066 memcpy(&addr, p1, addrlen);
1067
1068 /* check for returned address in private space */
1069 if (check_rebind &&
1070 (flags & F_IPV4) &&
1071 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
1072 return 1;
1073
1074#ifdef HAVE_IPSET
1075 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
1076 {
1077 ipsets_cur = ipsets;
1078 while (*ipsets_cur)
1079 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
1080 }
1081#endif
1082
1083 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
1084 if (newc && cpp)
1085 {
1086 cpp->addr.cname.target.cache = newc;
1087 cpp->addr.cname.uid = newc->uid;
1088 }
1089 cpp = NULL;
1090 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001091 }
Simon Kelley45cca582013-10-15 10:20:13 +01001092
1093 p1 = endrr;
1094 if (!CHECK_LEN(header, p1, qlen, 0))
1095 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001096 }
1097
Simon Kelley28866e92011-02-14 20:19:14 +00001098 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001099 {
1100 if (!searched_soa)
1101 {
1102 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001103 ttl = find_soa(header, qlen, NULL);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001104 }
1105 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001106 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001107 if (ttl || cpp)
1108 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001109 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
Simon Kelley26128d22004-11-14 16:43:54 +00001110 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001111 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001112 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001113 cpp->addr.cname.uid = newc->uid;
1114 }
1115 }
1116 }
1117 }
1118 }
1119
Simon Kelley1023dcb2012-04-09 18:00:08 +01001120 /* Don't put stuff from a truncated packet into the cache.
1121 Don't cache replies where DNSSEC validation was turned off, either
1122 the upstream server told us so, or the original query specified it.
1123 Don't cache replies from non-recursive nameservers, since we may get a
1124 reply containing a CNAME but not its target, even though the target
1125 does exist. */
1126 if (!(header->hb3 & HB3_TC) &&
1127 !(header->hb4 & HB4_CD) &&
1128 (header->hb4 & HB4_RA) &&
1129 !checking_disabled)
Simon Kelley824af852008-02-12 20:43:05 +00001130 cache_end_insert();
1131
1132 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001133}
1134
1135/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001136 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001137
Simon Kelley572b41e2011-02-18 18:11:18 +00001138unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001139{
1140 unsigned char *p = (unsigned char *)(header+1);
1141 int qtype, qclass;
1142
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001143 if (typep)
1144 *typep = 0;
1145
Simon Kelley572b41e2011-02-18 18:11:18 +00001146 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001147 return 0; /* must be exactly one query. */
1148
Simon Kelley9009d742008-11-14 20:04:27 +00001149 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001150 return 0; /* bad packet */
1151
1152 GETSHORT(qtype, p);
1153 GETSHORT(qclass, p);
1154
Simon Kelley0a852542005-03-23 20:28:59 +00001155 if (typep)
1156 *typep = qtype;
1157
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001158 if (qclass == C_IN)
1159 {
1160 if (qtype == T_A)
1161 return F_IPV4;
1162 if (qtype == T_AAAA)
1163 return F_IPV6;
1164 if (qtype == T_ANY)
1165 return F_IPV4 | F_IPV6;
1166 }
1167
1168 return F_QUERY;
1169}
1170
1171
Simon Kelley572b41e2011-02-18 18:11:18 +00001172size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001173 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001174{
1175 unsigned char *p = skip_questions(header, qlen);
1176
Simon Kelley572b41e2011-02-18 18:11:18 +00001177 /* clear authoritative and truncated flags, set QR flag */
1178 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1179 /* set RA flag */
1180 header->hb4 |= HB4_RA;
1181
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001182 header->nscount = htons(0);
1183 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001184 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001185 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001186 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001187 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001188 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001189 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001190 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001191 else if (p && flags == F_IPV4)
1192 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001193 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001194 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001195 header->hb3 |= HB3_AA;
1196 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 +00001197 }
1198#ifdef HAVE_IPV6
1199 else if (p && flags == F_IPV6)
1200 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001201 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001202 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001203 header->hb3 |= HB3_AA;
1204 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 +00001205 }
1206#endif
1207 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001208 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001209
1210 return p - (unsigned char *)header;
1211}
Simon Kelley36717ee2004-09-20 19:20:58 +01001212
1213/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001214int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001215{
1216 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001217 struct mx_srv_record *mx;
1218 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001219 struct interface_name *intr;
1220 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001221 struct naptr *naptr;
1222
1223 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
Simon Kelley36717ee2004-09-20 19:20:58 +01001224 (crecp->flags & (F_HOSTS | F_DHCP)))
1225 return 1;
1226
Simon Kelley7de060b2011-08-26 17:24:52 +01001227 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1228 if (hostname_isequal(name, naptr->name))
1229 return 1;
1230
1231 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001232 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001233 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001234
Simon Kelley0a852542005-03-23 20:28:59 +00001235 for (txt = daemon->txt; txt; txt = txt->next)
1236 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001237 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001238
1239 for (intr = daemon->int_names; intr; intr = intr->next)
1240 if (hostname_isequal(name, intr->name))
1241 return 1;
1242
1243 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1244 if (hostname_isequal(name, ptr->name))
1245 return 1;
1246
Simon Kelley36717ee2004-09-20 19:20:58 +01001247 return 0;
1248}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001249
1250/* Is the packet a reply with the answer address equal to addr?
1251 If so mung is into an NXDOMAIN reply and also put that information
1252 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001253int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001254 struct bogus_addr *baddr, time_t now)
1255{
1256 unsigned char *p;
1257 int i, qtype, qclass, rdlen;
1258 unsigned long ttl;
1259 struct bogus_addr *baddrp;
1260
1261 /* skip over questions */
1262 if (!(p = skip_questions(header, qlen)))
1263 return 0; /* bad packet */
1264
Simon Kelley5aabfc72007-08-29 11:24:47 +01001265 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001266 {
Simon Kelley9009d742008-11-14 20:04:27 +00001267 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001268 return 0; /* bad packet */
1269
1270 GETSHORT(qtype, p);
1271 GETSHORT(qclass, p);
1272 GETLONG(ttl, p);
1273 GETSHORT(rdlen, p);
1274
1275 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001276 {
1277 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1278 return 0;
1279
1280 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1281 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1282 {
1283 /* Found a bogus address. Insert that info here, since there no SOA record
1284 to get the ttl from in the normal processing */
1285 cache_start_insert();
1286 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
1287 cache_end_insert();
1288
1289 return 1;
1290 }
1291 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001292
Simon Kelley9009d742008-11-14 20:04:27 +00001293 if (!ADD_RDLEN(header, p, qlen, rdlen))
1294 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001295 }
1296
1297 return 0;
1298}
1299
Simon Kelleyb75e9362012-12-07 11:50:41 +00001300int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001301 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001302{
1303 va_list ap;
1304 unsigned char *sav, *p = *pp;
1305 int j;
1306 unsigned short usval;
1307 long lval;
1308 char *sval;
1309
1310 if (truncp && *truncp)
1311 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001312
1313 va_start(ap, format); /* make ap point to 1st unamed argument */
1314
Simon Kelleyb75e9362012-12-07 11:50:41 +00001315 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001316 {
1317 PUTSHORT(nameoffset | 0xc000, p);
1318 }
1319 else
1320 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001321 char *name = va_arg(ap, char *);
1322 if (name)
1323 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001324 if (nameoffset < 0)
1325 {
1326 PUTSHORT(-nameoffset | 0xc000, p);
1327 }
1328 else
1329 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001330 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001331
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001332 PUTSHORT(type, p);
1333 PUTSHORT(class, p);
1334 PUTLONG(ttl, p); /* TTL */
1335
1336 sav = p; /* Save pointer to RDLength field */
1337 PUTSHORT(0, p); /* Placeholder RDLength */
1338
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001339 for (; *format; format++)
1340 switch (*format)
1341 {
1342#ifdef HAVE_IPV6
1343 case '6':
1344 sval = va_arg(ap, char *);
1345 memcpy(p, sval, IN6ADDRSZ);
1346 p += IN6ADDRSZ;
1347 break;
1348#endif
1349
1350 case '4':
1351 sval = va_arg(ap, char *);
1352 memcpy(p, sval, INADDRSZ);
1353 p += INADDRSZ;
1354 break;
1355
1356 case 's':
1357 usval = va_arg(ap, int);
1358 PUTSHORT(usval, p);
1359 break;
1360
1361 case 'l':
1362 lval = va_arg(ap, long);
1363 PUTLONG(lval, p);
1364 break;
1365
1366 case 'd':
1367 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001368 if (offset)
1369 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001370 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001371 *p++ = 0;
1372 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001373
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001374 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001375 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001376 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001377 if (usval != 0)
1378 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001379 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001380 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001381
1382 case 'z':
1383 sval = va_arg(ap, char *);
1384 usval = sval ? strlen(sval) : 0;
1385 if (usval > 255)
1386 usval = 255;
1387 *p++ = (unsigned char)usval;
1388 memcpy(p, sval, usval);
1389 p += usval;
1390 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001391 }
1392
1393 va_end(ap); /* clean up variable argument pointer */
1394
1395 j = p - sav - 2;
1396 PUTSHORT(j, sav); /* Now, store real RDLength */
1397
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001398 /* check for overflow of buffer */
1399 if (limit && ((unsigned char *)limit - p) < 0)
1400 {
1401 if (truncp)
1402 *truncp = 1;
1403 return 0;
1404 }
1405
1406 *pp = p;
1407 return 1;
1408}
1409
Simon Kelley9009d742008-11-14 20:04:27 +00001410static unsigned long crec_ttl(struct crec *crecp, time_t now)
1411{
1412 /* Return 0 ttl for DHCP entries, which might change
1413 before the lease expires. */
1414
1415 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1416 return daemon->local_ttl;
1417
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001418 /* Return the Max TTL value if it is lower then the actual TTL */
1419 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1420 return crecp->ttd - now;
1421 else
1422 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001423}
1424
1425
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001426/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001427size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelleycdeda282006-03-16 20:16:06 +00001428 struct in_addr local_addr, struct in_addr local_netmask, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001429{
Simon Kelley3be34542004-09-11 19:12:13 +01001430 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001431 unsigned char *p, *ansp, *pheader;
Simon Kelley832af0b2007-01-21 20:01:28 +00001432 int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001433 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001434 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001435 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001436 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001437 int dryrun = 0, sec_reqd = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001438 int is_sign;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001439 struct crec *crecp;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001440 int nxdomain = 0, auth = 1, trunc = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001441 struct mx_srv_record *rec;
1442
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001443 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1444 partial replies, so we have to do a dry run to see if we can answer
1445 the query. We check to see if the do bit is set, if so we always
1446 forward rather than answering from the cache, which doesn't include
1447 security information. */
1448
Simon Kelley832af0b2007-01-21 20:01:28 +00001449 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001450 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001451 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001452 unsigned char *psave = pheader;
1453
1454 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001455 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001456 GETSHORT(flags, pheader);
1457
1458 sec_reqd = flags & 0x8000; /* do bit */
1459
1460 /* If our client is advertising a larger UDP packet size
1461 than we allow, trim it so that we don't get an overlarge
1462 response from upstream */
1463
Simon Kelley832af0b2007-01-21 20:01:28 +00001464 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001465 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001466
1467 dryrun = 1;
1468 }
1469
Simon Kelley572b41e2011-02-18 18:11:18 +00001470 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001471 return 0;
1472
Simon Kelley0a852542005-03-23 20:28:59 +00001473 for (rec = daemon->mxnames; rec; rec = rec->next)
1474 rec->offset = 0;
1475
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001476 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001477 /* determine end of question section (we put answers there) */
1478 if (!(ansp = skip_questions(header, qlen)))
1479 return 0; /* bad packet */
1480
1481 /* now process each question, answers go in RRs after the question */
1482 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001483
Simon Kelley5aabfc72007-08-29 11:24:47 +01001484 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001485 {
1486 /* save pointer to name for copying into answers */
1487 nameoffset = p - (unsigned char *)header;
1488
1489 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001490 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001491 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001492
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001493 GETSHORT(qtype, p);
1494 GETSHORT(qclass, p);
1495
1496 ans = 0; /* have we answered this question */
1497
Simon Kelley0a852542005-03-23 20:28:59 +00001498 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001499 {
Simon Kelley0a852542005-03-23 20:28:59 +00001500 struct txt_record *t;
1501 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001502 {
Simon Kelley0a852542005-03-23 20:28:59 +00001503 if (t->class == qclass && hostname_isequal(name, t->name))
1504 {
1505 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001506 if (!dryrun)
1507 {
Simon Kelley28866e92011-02-14 20:19:14 +00001508 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001509 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1510 daemon->local_ttl, NULL,
1511 T_TXT, t->class, "t", t->len, t->txt))
1512 anscount++;
1513
1514 }
Simon Kelley0a852542005-03-23 20:28:59 +00001515 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001516 }
Simon Kelley0a852542005-03-23 20:28:59 +00001517 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001518
Simon Kelley0a852542005-03-23 20:28:59 +00001519 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001520 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001521 struct txt_record *t;
1522
1523 for (t = daemon->rr; t; t = t->next)
1524 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1525 {
1526 ans = 1;
1527 if (!dryrun)
1528 {
1529 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1530 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1531 daemon->local_ttl, NULL,
1532 t->class, C_IN, "t", t->len, t->txt))
1533 anscount ++;
1534 }
1535 }
1536
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001537 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001538 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001539 /* see if it's w.z.y.z.in-addr.arpa format */
1540 int is_arpa = in_arpa_name_2_addr(name, &addr);
1541 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001542 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001543
1544 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1545 if (hostname_isequal(name, ptr->name))
1546 break;
1547
Simon Kelleyf2621c72007-04-29 19:47:21 +01001548 if (is_arpa == F_IPV4)
1549 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001550 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001551 struct addrlist *addrlist;
1552
1553 for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
1554 if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
1555 break;
1556
1557 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001558 break;
1559 else
1560 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1561 intr = intr->next;
1562 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001563#ifdef HAVE_IPV6
1564 else if (is_arpa == F_IPV6)
1565 for (intr = daemon->int_names; intr; intr = intr->next)
1566 {
1567 struct addrlist *addrlist;
1568
1569 for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
1570 if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
1571 break;
1572
1573 if (addrlist)
1574 break;
1575 else
1576 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1577 intr = intr->next;
1578 }
1579#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001580
1581 if (intr)
1582 {
1583 ans = 1;
1584 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001585 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001586 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001587 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1588 daemon->local_ttl, NULL,
1589 T_PTR, C_IN, "d", intr->name))
1590 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001591 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001592 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001593 else if (ptr)
1594 {
1595 ans = 1;
1596 if (!dryrun)
1597 {
Simon Kelley28866e92011-02-14 20:19:14 +00001598 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001599 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001600 if (hostname_isequal(name, ptr->name) &&
1601 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1602 daemon->local_ttl, NULL,
1603 T_PTR, C_IN, "d", ptr->ptr))
1604 anscount++;
1605
Simon Kelley832af0b2007-01-21 20:01:28 +00001606 }
1607 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001608 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
1609 do
1610 {
1611 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1612 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1613 continue;
1614
1615 if (crecp->flags & F_NEG)
1616 {
1617 ans = 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001618 auth = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001619 if (crecp->flags & F_NXDOMAIN)
1620 nxdomain = 1;
1621 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001622 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001623 }
1624 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
1625 {
1626 ans = 1;
1627 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1628 auth = 0;
1629 if (!dryrun)
1630 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001631 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
Simon Kelley7622fc02009-06-04 20:32:05 +01001632 record_source(crecp->uid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001633
Simon Kelley9009d742008-11-14 20:04:27 +00001634 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1635 crec_ttl(crecp, now), NULL,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001636 T_PTR, C_IN, "d", cache_get_name(crecp)))
1637 anscount++;
1638 }
1639 }
1640 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
Simon Kelley2bb73af2013-04-24 17:38:19 +01001641 else if (is_rev_synth(is_arpa, &addr, name))
1642 {
1643 ans = 1;
1644 if (!dryrun)
1645 {
1646 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1647
1648 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1649 daemon->local_ttl, NULL,
1650 T_PTR, C_IN, "d", name))
1651 anscount++;
1652 }
1653 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001654 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001655 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001656 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001657 {
1658 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1659 ans = 1;
1660 nxdomain = 1;
1661 if (!dryrun)
1662 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001663 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001664 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001665 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001666
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001667 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1668 {
1669 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001670 struct interface_name *intr;
1671
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001672 if (flag == F_IPV6)
1673#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001674 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001675#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001676 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001677#endif
1678
1679 if (qtype != type && qtype != T_ANY)
1680 continue;
1681
Simon Kelley316e2732010-01-22 20:16:09 +00001682 /* Check for "A for A" queries; be rather conservative
1683 about what looks like dotted-quad. */
1684 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001685 {
Simon Kelley316e2732010-01-22 20:16:09 +00001686 char *cp;
1687 unsigned int i, a;
1688 int x;
1689
1690 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001691 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001692 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001693 {
1694 i = 5;
1695 break;
1696 }
1697
1698 a = (a << 8) + x;
1699
1700 if (*cp == '.')
1701 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001702 }
Simon Kelley316e2732010-01-22 20:16:09 +00001703
1704 if (i == 4)
1705 {
1706 ans = 1;
1707 if (!dryrun)
1708 {
1709 addr.addr.addr4.s_addr = htonl(a);
1710 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1711 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1712 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1713 anscount++;
1714 }
1715 continue;
1716 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001717 }
1718
Simon Kelleyf2621c72007-04-29 19:47:21 +01001719 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001720 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001721 for (intr = daemon->int_names; intr; intr = intr->next)
1722 if (hostname_isequal(name, intr->name))
1723 break;
1724
1725 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001726 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001727 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001728 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001729
Simon Kelley115ac3e2013-05-20 11:28:32 +01001730 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001731
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001732 for (intr = daemon->int_names; intr; intr = intr->next)
1733 if (hostname_isequal(name, intr->name))
1734 {
1735 addrlist = intr->addr4;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001736#ifdef HAVE_IPV6
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001737 if (type == T_AAAA)
1738 addrlist = intr->addr6;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001739#endif
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001740 ans = 1;
1741 if (!dryrun)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001742 {
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001743 if (addrlist)
1744 {
1745 gotit = 1;
1746 for (; addrlist; addrlist = addrlist->next)
1747 {
1748 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1749 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1750 daemon->local_ttl, NULL, type, C_IN,
1751 type == T_A ? "4" : "6", &addrlist->addr))
1752 anscount++;
1753 }
1754 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001755 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001756 }
1757
1758 if (!dryrun && !gotit)
1759 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1760
Simon Kelley115ac3e2013-05-20 11:28:32 +01001761 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001762 }
1763
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001764 cname_restart:
1765 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
1766 {
1767 int localise = 0;
1768
1769 /* See if a putative address is on the network from which we recieved
1770 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001771 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001772 {
1773 struct crec *save = crecp;
1774 do {
1775 if ((crecp->flags & F_HOSTS) &&
1776 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1777 {
1778 localise = 1;
1779 break;
1780 }
1781 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1782 crecp = save;
1783 }
1784
1785 do
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001786 {
Simon Kelley26128d22004-11-14 16:43:54 +00001787 /* don't answer wildcard queries with data not from /etc/hosts
1788 or DHCP leases */
Simon Kelley3bb51da2013-10-14 14:20:34 +01001789 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley26128d22004-11-14 16:43:54 +00001790 break;
1791
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001792 if (crecp->flags & F_CNAME)
1793 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001794 char *cname_target = cache_get_cname_target(crecp);
1795
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001796 if (!dryrun)
1797 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001798 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
Simon Kelley9009d742008-11-14 20:04:27 +00001799 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1800 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01001801 T_CNAME, C_IN, "d", cname_target))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001802 anscount++;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001803 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001804
Simon Kelleyd56a6042013-10-11 14:39:03 +01001805 strcpy(name, cname_target);
1806 /* check if target interface_name */
1807 if (crecp->addr.cname.uid == -1)
1808 goto intname_restart;
1809 else
1810 goto cname_restart;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001811 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001812
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001813 if (crecp->flags & F_NEG)
1814 {
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001815 ans = 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001816 auth = 0;
1817 if (crecp->flags & F_NXDOMAIN)
1818 nxdomain = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001819 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001820 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001821 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001822 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001823 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001824 /* If we are returning local answers depending on network,
1825 filter here. */
1826 if (localise &&
1827 (crecp->flags & F_HOSTS) &&
1828 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1829 continue;
1830
1831 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1832 auth = 0;
1833
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001834 ans = 1;
1835 if (!dryrun)
1836 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001837 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
Simon Kelley7622fc02009-06-04 20:32:05 +01001838 record_source(crecp->uid));
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001839
Simon Kelley9009d742008-11-14 20:04:27 +00001840 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1841 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001842 type == T_A ? "4" : "6", &crecp->addr))
1843 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001844 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001845 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001846 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001847 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001848 else if (is_name_synthetic(flag, name, &addr))
1849 {
1850 ans = 1;
1851 if (!dryrun)
1852 {
1853 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
1854 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1855 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
1856 anscount++;
1857 }
1858 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001859 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001860
1861 if (qtype == T_CNAME || qtype == T_ANY)
1862 {
1863 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
1864 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP))))
1865 {
1866 ans = 1;
1867 if (!dryrun)
1868 {
1869 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1870 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1871 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01001872 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001873 anscount++;
1874 }
1875 }
1876 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001877
1878 if (qtype == T_MX || qtype == T_ANY)
1879 {
1880 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001881 for (rec = daemon->mxnames; rec; rec = rec->next)
1882 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001883 {
1884 ans = found = 1;
1885 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001886 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001887 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001888 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00001889 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1890 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1891 {
1892 anscount++;
1893 if (rec->target)
1894 rec->offset = offset;
1895 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001896 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001897 }
1898
Simon Kelley28866e92011-02-14 20:19:14 +00001899 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001900 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
1901 {
1902 ans = 1;
1903 if (!dryrun)
1904 {
Simon Kelley28866e92011-02-14 20:19:14 +00001905 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001906 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1907 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00001908 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001909 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001910 }
1911 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001912 }
1913
1914 if (qtype == T_SRV || qtype == T_ANY)
1915 {
1916 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001917 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
1918
Simon Kelley0a852542005-03-23 20:28:59 +00001919 for (rec = daemon->mxnames; rec; rec = rec->next)
1920 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001921 {
1922 found = ans = 1;
1923 if (!dryrun)
1924 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001925 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001926 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001927 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001928 &offset, T_SRV, C_IN, "sssd",
1929 rec->priority, rec->weight, rec->srvport, rec->target))
1930 {
1931 anscount++;
1932 if (rec->target)
1933 rec->offset = offset;
1934 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001935 }
Simon Kelley28866e92011-02-14 20:19:14 +00001936
1937 /* unlink first SRV record found */
1938 if (!move)
1939 {
1940 move = rec;
1941 *up = rec->next;
1942 }
1943 else
1944 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001945 }
Simon Kelley28866e92011-02-14 20:19:14 +00001946 else
1947 up = &rec->next;
1948
1949 /* put first SRV record back at the end. */
1950 if (move)
1951 {
1952 *up = move;
1953 move->next = NULL;
1954 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001955
Simon Kelley28866e92011-02-14 20:19:14 +00001956 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001957 {
1958 ans = 1;
1959 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001960 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001961 }
1962 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001963
1964 if (qtype == T_NAPTR || qtype == T_ANY)
1965 {
1966 struct naptr *na;
1967 for (na = daemon->naptr; na; na = na->next)
1968 if (hostname_isequal(name, na->name))
1969 {
1970 ans = 1;
1971 if (!dryrun)
1972 {
Simon Kelley28866e92011-02-14 20:19:14 +00001973 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001974 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1975 NULL, T_NAPTR, C_IN, "sszzzd",
1976 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1977 anscount++;
1978 }
1979 }
1980 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001981
1982 if (qtype == T_MAILB)
1983 ans = 1, nxdomain = 1;
1984
Simon Kelley28866e92011-02-14 20:19:14 +00001985 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001986 {
1987 ans = 1;
1988 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001989 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001990 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001991 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001992
1993 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001994 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001995 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001996
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001997 if (dryrun)
1998 {
1999 dryrun = 0;
2000 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002001 }
2002
Simon Kelley0a852542005-03-23 20:28:59 +00002003 /* create an additional data section, for stuff in SRV and MX record replies. */
2004 for (rec = daemon->mxnames; rec; rec = rec->next)
2005 if (rec->offset != 0)
2006 {
2007 /* squash dupes */
2008 struct mx_srv_record *tmp;
2009 for (tmp = rec->next; tmp; tmp = tmp->next)
2010 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2011 tmp->offset = 0;
2012
2013 crecp = NULL;
2014 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2015 {
Simon Kelley0a852542005-03-23 20:28:59 +00002016#ifdef HAVE_IPV6
2017 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2018#else
2019 int type = T_A;
2020#endif
2021 if (crecp->flags & F_NEG)
2022 continue;
2023
Simon Kelley9009d742008-11-14 20:04:27 +00002024 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2025 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002026 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2027 addncount++;
2028 }
2029 }
2030
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002031 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002032 /* clear authoritative and truncated flags, set QR flag */
2033 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2034 /* set RA flag */
2035 header->hb4 |= HB4_RA;
2036
2037 /* authoritive - only hosts and DHCP derived names. */
2038 if (auth)
2039 header->hb3 |= HB3_AA;
2040
2041 /* truncation */
2042 if (trunc)
2043 header->hb3 |= HB3_TC;
2044
Simon Kelley45cca582013-10-15 10:20:13 +01002045 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002046 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002047 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002048 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002049 header->ancount = htons(anscount);
2050 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002051 header->arcount = htons(addncount);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002052 return ansp - (unsigned char *)header;
2053}
2054