blob: 60ed068fa6cf3b7f63d043f039ddddd27a7cb57e [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};
516
517static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
518{
519 struct macparm *parm = parmv;
520 int match = 0;
521 unsigned short rdlen;
Simon Kelley572b41e2011-02-18 18:11:18 +0000522 struct dns_header *header = parm->header;
Simon Kelley28866e92011-02-14 20:19:14 +0000523 unsigned char *lenp, *datap, *p;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100524
Simon Kelley28866e92011-02-14 20:19:14 +0000525 if (family == parm->l3->sa.sa_family)
526 {
527 if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
528 match = 1;
529#ifdef HAVE_IPV6
530 else
531 if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
532 match = 1;
533#endif
534 }
535
536 if (!match)
537 return 1; /* continue */
538
539 if (ntohs(header->arcount) == 0)
540 {
541 /* We are adding the pseudoheader */
542 if (!(p = skip_questions(header, parm->plen)) ||
543 !(p = skip_section(p,
544 ntohs(header->ancount) + ntohs(header->nscount),
545 header, parm->plen)))
546 return 0;
547 *p++ = 0; /* empty name */
548 PUTSHORT(T_OPT, p);
549 PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */
550 PUTLONG(0, p); /* extended RCODE */
551 lenp = p;
552 PUTSHORT(0, p); /* RDLEN */
553 rdlen = 0;
554 if (((ssize_t)maclen) > (parm->limit - (p + 4)))
555 return 0; /* Too big */
556 header->arcount = htons(1);
557 datap = p;
558 }
559 else
560 {
561 int i, is_sign;
562 unsigned short code, len;
563
564 if (ntohs(header->arcount) != 1 ||
565 !(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) ||
566 is_sign ||
567 (!(p = skip_name(p, header, parm->plen, 10))))
568 return 0;
569
570 p += 8; /* skip UDP length and RCODE */
571
572 lenp = p;
573 GETSHORT(rdlen, p);
574 if (!CHECK_LEN(header, p, parm->plen, rdlen))
575 return 0; /* bad packet */
576 datap = p;
577
578 /* check if option already there */
579 for (i = 0; i + 4 < rdlen; i += len + 4)
580 {
581 GETSHORT(code, p);
582 GETSHORT(len, p);
583 if (code == EDNS0_OPTION_MAC)
584 return 0;
585 p += len;
586 }
587
588 if (((ssize_t)maclen) > (parm->limit - (p + 4)))
589 return 0; /* Too big */
590 }
591
592 PUTSHORT(EDNS0_OPTION_MAC, p);
593 PUTSHORT(maclen, p);
594 memcpy(p, mac, maclen);
595 p += maclen;
596
597 PUTSHORT(p - datap, lenp);
598 parm->plen = p - (unsigned char *)header;
599
600 return 0; /* done */
601}
602
603
Simon Kelley572b41e2011-02-18 18:11:18 +0000604size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
Simon Kelley28866e92011-02-14 20:19:14 +0000605{
606 struct macparm parm;
607
608/* Must have an existing pseudoheader as the only ar-record,
609 or have no ar-records. Must also not be signed */
610
611 if (ntohs(header->arcount) > 1)
612 return plen;
613
614 parm.header = header;
615 parm.limit = (unsigned char *)limit;
616 parm.plen = plen;
617 parm.l3 = l3;
618
619 iface_enumerate(AF_UNSPEC, &parm, filter_mac);
620
621 return parm.plen;
622}
623
624
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000625/* is addr in the non-globally-routed IP space? */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100626static int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000627{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100628 in_addr_t ip_addr = ntohl(addr.s_addr);
629
630 return
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100631 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100632 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
633 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
634 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
635 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000636}
Simon Kelley1cff1662004-03-12 08:12:58 +0000637
Simon Kelley572b41e2011-02-18 18:11:18 +0000638static 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 +0000639{
640 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000641
642 for (i = count; i != 0; i--)
643 {
Simon Kelley28866e92011-02-14 20:19:14 +0000644 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100645 {
646 if (!extract_name(header, qlen, &p, name, 1, 10))
647 return 0;
648 }
649 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000650 return 0; /* bad packet */
651
652 GETSHORT(qtype, p);
653 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100654 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000655 GETSHORT(rdlen, p);
656
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100657 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000658 {
659 struct doctor *doctor;
660 struct in_addr addr;
661
Simon Kelley9009d742008-11-14 20:04:27 +0000662 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
663 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100664
665 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000666 memcpy(&addr, p, INADDRSZ);
667
668 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000669 {
670 if (doctor->end.s_addr == 0)
671 {
672 if (!is_same_net(doctor->in, addr, doctor->mask))
673 continue;
674 }
675 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
676 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
677 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100678
Simon Kelley73a08a22009-02-05 20:28:08 +0000679 addr.s_addr &= ~doctor->mask.s_addr;
680 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
681 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000682 header->hb3 &= ~HB3_AA;
Simon Kelley73a08a22009-02-05 20:28:08 +0000683 memcpy(p, &addr, INADDRSZ);
684 break;
685 }
Simon Kelley824af852008-02-12 20:43:05 +0000686 }
Simon Kelley28866e92011-02-14 20:19:14 +0000687 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100688 {
689 unsigned char *p1 = p;
690 if (!CHECK_LEN(header, p1, qlen, rdlen))
691 return 0;
692 while ((p1 - p) < rdlen)
693 {
694 unsigned int i, len = *p1;
695 unsigned char *p2 = p1;
696 /* make counted string zero-term and sanitise */
697 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100698 {
699 if (!isprint((int)*(p2+1)))
700 break;
701
702 *p2 = *(p2+1);
703 p2++;
704 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100705 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000706 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100707 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100708 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100709 *p1 = len;
710 p1 += len+1;
711 }
712 }
Simon Kelley824af852008-02-12 20:43:05 +0000713
Simon Kelley9009d742008-11-14 20:04:27 +0000714 if (!ADD_RDLEN(header, p, qlen, rdlen))
715 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000716 }
717
718 return p;
719}
720
Simon Kelley572b41e2011-02-18 18:11:18 +0000721static int find_soa(struct dns_header *header, size_t qlen, char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000722{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100723 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000724 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100725 unsigned long ttl, minttl = ULONG_MAX;
726 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000727
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100728 /* first move to NS section and find TTL from any SOA section */
729 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100730 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name)))
Simon Kelley824af852008-02-12 20:43:05 +0000731 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000732
Simon Kelley5aabfc72007-08-29 11:24:47 +0100733 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000734 {
Simon Kelley9009d742008-11-14 20:04:27 +0000735 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100736 return 0; /* bad packet */
737
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000738 GETSHORT(qtype, p);
739 GETSHORT(qclass, p);
740 GETLONG(ttl, p);
741 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100742
743 if ((qclass == C_IN) && (qtype == T_SOA))
744 {
745 found_soa = 1;
746 if (ttl < minttl)
747 minttl = ttl;
748
749 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000750 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100751 return 0;
752 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000753 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100754 return 0;
755 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
756
757 GETLONG(ttl, p); /* minTTL */
758 if (ttl < minttl)
759 minttl = ttl;
760 }
Simon Kelley9009d742008-11-14 20:04:27 +0000761 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100762 return 0; /* bad packet */
763 }
Simon Kelley9009d742008-11-14 20:04:27 +0000764
Simon Kelley824af852008-02-12 20:43:05 +0000765 /* rewrite addresses in additioal section too */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100766 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL))
Simon Kelley824af852008-02-12 20:43:05 +0000767 return 0;
768
769 if (!found_soa)
770 minttl = daemon->neg_ttl;
771
772 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100773}
774
775/* Note that the following code can create CNAME chains that don't point to a real record,
776 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 +0000777 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100778 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000779int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000780 char **ipsets, int is_sign, int check_rebind, int checking_disabled)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100781{
Simon Kelley824af852008-02-12 20:43:05 +0000782 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100783 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000784 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100785 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000786#ifdef HAVE_IPSET
787 char **ipsets_cur;
788#else
789 (void)ipsets; /* unused */
790#endif
791
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100792 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000793
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100794 /* 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 +0000795 if (daemon->doctors || option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000796 {
797 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100798 ttl = find_soa(header, qlen, name);
Simon Kelley0a852542005-03-23 20:28:59 +0000799 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100800
801 /* go through the questions. */
802 p = (unsigned char *)(header+1);
803
Simon Kelley5aabfc72007-08-29 11:24:47 +0100804 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100805 {
806 int found = 0, cname_count = 5;
807 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000808 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000809 unsigned long cttl = ULONG_MAX, attl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100810
Simon Kelley824af852008-02-12 20:43:05 +0000811 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000812 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000813 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100814
815 GETSHORT(qtype, p);
816 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000817
818 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100819 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000820
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100821 /* PTRs: we chase CNAMEs here, since we have no way to
822 represent them in the cache. */
823 if (qtype == T_PTR)
824 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000825 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100826
827 if (!name_encoding)
828 continue;
829
830 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000831 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100832 cname_loop:
833 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000834 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100835
Simon Kelley5aabfc72007-08-29 11:24:47 +0100836 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100837 {
Simon Kelley824af852008-02-12 20:43:05 +0000838 unsigned char *tmp = namep;
839 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000840 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
841 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000842 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843
844 GETSHORT(aqtype, p1);
845 GETSHORT(aqclass, p1);
846 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100847 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
848 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000849 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100850 PUTLONG(daemon->max_ttl, p1);
851 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100852 GETSHORT(ardlen, p1);
853 endrr = p1+ardlen;
854
855 /* TTL of record is minimum of CNAMES and PTR */
856 if (attl < cttl)
857 cttl = attl;
858
859 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
860 {
Simon Kelley9009d742008-11-14 20:04:27 +0000861 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000862 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100863
864 if (aqtype == T_CNAME)
865 {
866 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000867 return 0; /* looped CNAMES */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100868 goto cname_loop;
869 }
870
871 cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);
872 found = 1;
873 }
874
875 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000876 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000877 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100878 }
879 }
880
Simon Kelley28866e92011-02-14 20:19:14 +0000881 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882 {
883 if (!searched_soa)
884 {
885 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100886 ttl = find_soa(header, qlen, NULL);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100887 }
888 if (ttl)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100889 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000890 }
891 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100892 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000893 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100894 /* everything other than PTR */
895 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100896 int addrlen;
897
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100898 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100899 {
900 addrlen = INADDRSZ;
901 flags |= F_IPV4;
902 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000903#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100904 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100905 {
906 addrlen = IN6ADDRSZ;
907 flags |= F_IPV6;
908 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000909#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100910 else
911 continue;
912
913 if (!(flags & F_NXDOMAIN))
914 {
915 cname_loop1:
916 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000917 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100918
Simon Kelley5aabfc72007-08-29 11:24:47 +0100919 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000920 {
Simon Kelley9009d742008-11-14 20:04:27 +0000921 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000922 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100923
924 GETSHORT(aqtype, p1);
925 GETSHORT(aqclass, p1);
926 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100927 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
928 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000929 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100930 PUTLONG(daemon->max_ttl, p1);
931 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100932 GETSHORT(ardlen, p1);
933 endrr = p1+ardlen;
934
935 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100937 if (aqtype == T_CNAME)
938 {
939 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000940 return 0; /* looped CNAMES */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100941 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100942 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100943 {
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100944 newc->addr.cname.cache = NULL;
945 if (cpp)
946 {
947 cpp->addr.cname.cache = newc;
948 cpp->addr.cname.uid = newc->uid;
949 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100950 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000951
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100952 cpp = newc;
953 if (attl < cttl)
954 cttl = attl;
955
Simon Kelley9009d742008-11-14 20:04:27 +0000956 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000957 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100958 goto cname_loop1;
959 }
960 else
961 {
962 found = 1;
Simon Kelley9009d742008-11-14 20:04:27 +0000963
Simon Kelley5aabfc72007-08-29 11:24:47 +0100964 /* copy address into aligned storage */
Simon Kelley9009d742008-11-14 20:04:27 +0000965 if (!CHECK_LEN(header, p1, qlen, addrlen))
966 return 0; /* bad packet */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100967 memcpy(&addr, p1, addrlen);
Simon Kelley824af852008-02-12 20:43:05 +0000968
969 /* check for returned address in private space */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100970 if (check_rebind &&
Simon Kelley824af852008-02-12 20:43:05 +0000971 (flags & F_IPV4) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000972 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +0000973 return 1;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000974
975#ifdef HAVE_IPSET
976 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
977 {
978 ipsets_cur = ipsets;
979 while (*ipsets_cur)
980 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
981 }
982#endif
Simon Kelley824af852008-02-12 20:43:05 +0000983
Simon Kelley5aabfc72007-08-29 11:24:47 +0100984 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
Simon Kelley26128d22004-11-14 16:43:54 +0000985 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100986 {
987 cpp->addr.cname.cache = newc;
988 cpp->addr.cname.uid = newc->uid;
989 }
990 cpp = NULL;
991 }
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 there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001008 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001009 if (ttl || cpp)
1010 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001011 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
Simon Kelley26128d22004-11-14 16:43:54 +00001012 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001013 {
1014 cpp->addr.cname.cache = newc;
1015 cpp->addr.cname.uid = newc->uid;
1016 }
1017 }
1018 }
1019 }
1020 }
1021
Simon Kelley1023dcb2012-04-09 18:00:08 +01001022 /* Don't put stuff from a truncated packet into the cache.
1023 Don't cache replies where DNSSEC validation was turned off, either
1024 the upstream server told us so, or the original query specified it.
1025 Don't cache replies from non-recursive nameservers, since we may get a
1026 reply containing a CNAME but not its target, even though the target
1027 does exist. */
1028 if (!(header->hb3 & HB3_TC) &&
1029 !(header->hb4 & HB4_CD) &&
1030 (header->hb4 & HB4_RA) &&
1031 !checking_disabled)
Simon Kelley824af852008-02-12 20:43:05 +00001032 cache_end_insert();
1033
1034 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001035}
1036
1037/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001038 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001039
Simon Kelley572b41e2011-02-18 18:11:18 +00001040unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001041{
1042 unsigned char *p = (unsigned char *)(header+1);
1043 int qtype, qclass;
1044
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001045 if (typep)
1046 *typep = 0;
1047
Simon Kelley572b41e2011-02-18 18:11:18 +00001048 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001049 return 0; /* must be exactly one query. */
1050
Simon Kelley9009d742008-11-14 20:04:27 +00001051 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001052 return 0; /* bad packet */
1053
1054 GETSHORT(qtype, p);
1055 GETSHORT(qclass, p);
1056
Simon Kelley0a852542005-03-23 20:28:59 +00001057 if (typep)
1058 *typep = qtype;
1059
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001060 if (qclass == C_IN)
1061 {
1062 if (qtype == T_A)
1063 return F_IPV4;
1064 if (qtype == T_AAAA)
1065 return F_IPV6;
1066 if (qtype == T_ANY)
1067 return F_IPV4 | F_IPV6;
1068 }
1069
1070 return F_QUERY;
1071}
1072
1073
Simon Kelley572b41e2011-02-18 18:11:18 +00001074size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001075 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001076{
1077 unsigned char *p = skip_questions(header, qlen);
1078
Simon Kelley572b41e2011-02-18 18:11:18 +00001079 /* clear authoritative and truncated flags, set QR flag */
1080 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1081 /* set RA flag */
1082 header->hb4 |= HB4_RA;
1083
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001084 header->nscount = htons(0);
1085 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001086 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001087 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001088 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001089 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001090 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001091 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001092 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001093 else if (p && flags == F_IPV4)
1094 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001095 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001096 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001097 header->hb3 |= HB3_AA;
1098 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 +00001099 }
1100#ifdef HAVE_IPV6
1101 else if (p && flags == F_IPV6)
1102 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001103 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001104 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001105 header->hb3 |= HB3_AA;
1106 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 +00001107 }
1108#endif
1109 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001110 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001111
1112 return p - (unsigned char *)header;
1113}
Simon Kelley36717ee2004-09-20 19:20:58 +01001114
1115/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001116int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001117{
1118 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001119 struct mx_srv_record *mx;
1120 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001121 struct interface_name *intr;
1122 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001123 struct naptr *naptr;
1124
1125 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
Simon Kelley36717ee2004-09-20 19:20:58 +01001126 (crecp->flags & (F_HOSTS | F_DHCP)))
1127 return 1;
1128
Simon Kelley7de060b2011-08-26 17:24:52 +01001129 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1130 if (hostname_isequal(name, naptr->name))
1131 return 1;
1132
1133 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001134 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001135 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001136
Simon Kelley0a852542005-03-23 20:28:59 +00001137 for (txt = daemon->txt; txt; txt = txt->next)
1138 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001139 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001140
1141 for (intr = daemon->int_names; intr; intr = intr->next)
1142 if (hostname_isequal(name, intr->name))
1143 return 1;
1144
1145 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1146 if (hostname_isequal(name, ptr->name))
1147 return 1;
1148
Simon Kelley36717ee2004-09-20 19:20:58 +01001149 return 0;
1150}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001151
1152/* Is the packet a reply with the answer address equal to addr?
1153 If so mung is into an NXDOMAIN reply and also put that information
1154 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001155int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001156 struct bogus_addr *baddr, time_t now)
1157{
1158 unsigned char *p;
1159 int i, qtype, qclass, rdlen;
1160 unsigned long ttl;
1161 struct bogus_addr *baddrp;
1162
1163 /* skip over questions */
1164 if (!(p = skip_questions(header, qlen)))
1165 return 0; /* bad packet */
1166
Simon Kelley5aabfc72007-08-29 11:24:47 +01001167 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001168 {
Simon Kelley9009d742008-11-14 20:04:27 +00001169 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001170 return 0; /* bad packet */
1171
1172 GETSHORT(qtype, p);
1173 GETSHORT(qclass, p);
1174 GETLONG(ttl, p);
1175 GETSHORT(rdlen, p);
1176
1177 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001178 {
1179 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1180 return 0;
1181
1182 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1183 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1184 {
1185 /* Found a bogus address. Insert that info here, since there no SOA record
1186 to get the ttl from in the normal processing */
1187 cache_start_insert();
1188 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
1189 cache_end_insert();
1190
1191 return 1;
1192 }
1193 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001194
Simon Kelley9009d742008-11-14 20:04:27 +00001195 if (!ADD_RDLEN(header, p, qlen, rdlen))
1196 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001197 }
1198
1199 return 0;
1200}
1201
Simon Kelleyb75e9362012-12-07 11:50:41 +00001202int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001203 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001204{
1205 va_list ap;
1206 unsigned char *sav, *p = *pp;
1207 int j;
1208 unsigned short usval;
1209 long lval;
1210 char *sval;
1211
1212 if (truncp && *truncp)
1213 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001214
1215 va_start(ap, format); /* make ap point to 1st unamed argument */
1216
Simon Kelleyb75e9362012-12-07 11:50:41 +00001217 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001218 {
1219 PUTSHORT(nameoffset | 0xc000, p);
1220 }
1221 else
1222 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001223 char *name = va_arg(ap, char *);
1224 if (name)
1225 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001226 if (nameoffset < 0)
1227 {
1228 PUTSHORT(-nameoffset | 0xc000, p);
1229 }
1230 else
1231 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001232 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001233
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001234 PUTSHORT(type, p);
1235 PUTSHORT(class, p);
1236 PUTLONG(ttl, p); /* TTL */
1237
1238 sav = p; /* Save pointer to RDLength field */
1239 PUTSHORT(0, p); /* Placeholder RDLength */
1240
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001241 for (; *format; format++)
1242 switch (*format)
1243 {
1244#ifdef HAVE_IPV6
1245 case '6':
1246 sval = va_arg(ap, char *);
1247 memcpy(p, sval, IN6ADDRSZ);
1248 p += IN6ADDRSZ;
1249 break;
1250#endif
1251
1252 case '4':
1253 sval = va_arg(ap, char *);
1254 memcpy(p, sval, INADDRSZ);
1255 p += INADDRSZ;
1256 break;
1257
1258 case 's':
1259 usval = va_arg(ap, int);
1260 PUTSHORT(usval, p);
1261 break;
1262
1263 case 'l':
1264 lval = va_arg(ap, long);
1265 PUTLONG(lval, p);
1266 break;
1267
1268 case 'd':
1269 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001270 if (offset)
1271 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001272 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001273 *p++ = 0;
1274 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001275
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001276 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001277 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001278 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001279 if (usval != 0)
1280 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001281 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001282 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001283
1284 case 'z':
1285 sval = va_arg(ap, char *);
1286 usval = sval ? strlen(sval) : 0;
1287 if (usval > 255)
1288 usval = 255;
1289 *p++ = (unsigned char)usval;
1290 memcpy(p, sval, usval);
1291 p += usval;
1292 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001293 }
1294
1295 va_end(ap); /* clean up variable argument pointer */
1296
1297 j = p - sav - 2;
1298 PUTSHORT(j, sav); /* Now, store real RDLength */
1299
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001300 /* check for overflow of buffer */
1301 if (limit && ((unsigned char *)limit - p) < 0)
1302 {
1303 if (truncp)
1304 *truncp = 1;
1305 return 0;
1306 }
1307
1308 *pp = p;
1309 return 1;
1310}
1311
Simon Kelley9009d742008-11-14 20:04:27 +00001312static unsigned long crec_ttl(struct crec *crecp, time_t now)
1313{
1314 /* Return 0 ttl for DHCP entries, which might change
1315 before the lease expires. */
1316
1317 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1318 return daemon->local_ttl;
1319
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001320 /* Return the Max TTL value if it is lower then the actual TTL */
1321 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1322 return crecp->ttd - now;
1323 else
1324 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001325}
1326
1327
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001328/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001329size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelleycdeda282006-03-16 20:16:06 +00001330 struct in_addr local_addr, struct in_addr local_netmask, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001331{
Simon Kelley3be34542004-09-11 19:12:13 +01001332 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001333 unsigned char *p, *ansp, *pheader;
Simon Kelley832af0b2007-01-21 20:01:28 +00001334 int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001335 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001336 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001337 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001338 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001339 int dryrun = 0, sec_reqd = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001340 int is_sign;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001341 struct crec *crecp;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001342 int nxdomain = 0, auth = 1, trunc = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001343 struct mx_srv_record *rec;
1344
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001345 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1346 partial replies, so we have to do a dry run to see if we can answer
1347 the query. We check to see if the do bit is set, if so we always
1348 forward rather than answering from the cache, which doesn't include
1349 security information. */
1350
Simon Kelley832af0b2007-01-21 20:01:28 +00001351 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001352 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001353 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001354 unsigned char *psave = pheader;
1355
1356 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001357 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001358 GETSHORT(flags, pheader);
1359
1360 sec_reqd = flags & 0x8000; /* do bit */
1361
1362 /* If our client is advertising a larger UDP packet size
1363 than we allow, trim it so that we don't get an overlarge
1364 response from upstream */
1365
Simon Kelley832af0b2007-01-21 20:01:28 +00001366 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001367 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001368
1369 dryrun = 1;
1370 }
1371
Simon Kelley572b41e2011-02-18 18:11:18 +00001372 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001373 return 0;
1374
Simon Kelley0a852542005-03-23 20:28:59 +00001375 for (rec = daemon->mxnames; rec; rec = rec->next)
1376 rec->offset = 0;
1377
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001378 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001379 /* determine end of question section (we put answers there) */
1380 if (!(ansp = skip_questions(header, qlen)))
1381 return 0; /* bad packet */
1382
1383 /* now process each question, answers go in RRs after the question */
1384 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001385
Simon Kelley5aabfc72007-08-29 11:24:47 +01001386 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001387 {
1388 /* save pointer to name for copying into answers */
1389 nameoffset = p - (unsigned char *)header;
1390
1391 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001392 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001393 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001394
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001395 GETSHORT(qtype, p);
1396 GETSHORT(qclass, p);
1397
1398 ans = 0; /* have we answered this question */
1399
Simon Kelley0a852542005-03-23 20:28:59 +00001400 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001401 {
Simon Kelley0a852542005-03-23 20:28:59 +00001402 struct txt_record *t;
1403 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001404 {
Simon Kelley0a852542005-03-23 20:28:59 +00001405 if (t->class == qclass && hostname_isequal(name, t->name))
1406 {
1407 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001408 if (!dryrun)
1409 {
Simon Kelley28866e92011-02-14 20:19:14 +00001410 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001411 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1412 daemon->local_ttl, NULL,
1413 T_TXT, t->class, "t", t->len, t->txt))
1414 anscount++;
1415
1416 }
Simon Kelley0a852542005-03-23 20:28:59 +00001417 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001418 }
Simon Kelley0a852542005-03-23 20:28:59 +00001419 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001420
Simon Kelley0a852542005-03-23 20:28:59 +00001421 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001422 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001423 struct txt_record *t;
1424
1425 for (t = daemon->rr; t; t = t->next)
1426 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1427 {
1428 ans = 1;
1429 if (!dryrun)
1430 {
1431 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1432 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1433 daemon->local_ttl, NULL,
1434 t->class, C_IN, "t", t->len, t->txt))
1435 anscount ++;
1436 }
1437 }
1438
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001439 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001440 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001441 /* see if it's w.z.y.z.in-addr.arpa format */
1442 int is_arpa = in_arpa_name_2_addr(name, &addr);
1443 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001444 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001445
1446 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1447 if (hostname_isequal(name, ptr->name))
1448 break;
1449
Simon Kelleyf2621c72007-04-29 19:47:21 +01001450 if (is_arpa == F_IPV4)
1451 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001452 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001453 struct addrlist *addrlist;
1454
1455 for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
1456 if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
1457 break;
1458
1459 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001460 break;
1461 else
1462 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1463 intr = intr->next;
1464 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001465#ifdef HAVE_IPV6
1466 else if (is_arpa == F_IPV6)
1467 for (intr = daemon->int_names; intr; intr = intr->next)
1468 {
1469 struct addrlist *addrlist;
1470
1471 for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
1472 if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
1473 break;
1474
1475 if (addrlist)
1476 break;
1477 else
1478 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1479 intr = intr->next;
1480 }
1481#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001482
1483 if (intr)
1484 {
1485 ans = 1;
1486 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001487 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001488 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001489 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1490 daemon->local_ttl, NULL,
1491 T_PTR, C_IN, "d", intr->name))
1492 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001493 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001494 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001495 else if (ptr)
1496 {
1497 ans = 1;
1498 if (!dryrun)
1499 {
Simon Kelley28866e92011-02-14 20:19:14 +00001500 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001501 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001502 if (hostname_isequal(name, ptr->name) &&
1503 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1504 daemon->local_ttl, NULL,
1505 T_PTR, C_IN, "d", ptr->ptr))
1506 anscount++;
1507
Simon Kelley832af0b2007-01-21 20:01:28 +00001508 }
1509 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001510 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
1511 do
1512 {
1513 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1514 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1515 continue;
1516
1517 if (crecp->flags & F_NEG)
1518 {
1519 ans = 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001520 auth = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001521 if (crecp->flags & F_NXDOMAIN)
1522 nxdomain = 1;
1523 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001524 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001525 }
1526 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
1527 {
1528 ans = 1;
1529 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1530 auth = 0;
1531 if (!dryrun)
1532 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001533 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
Simon Kelley7622fc02009-06-04 20:32:05 +01001534 record_source(crecp->uid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001535
Simon Kelley9009d742008-11-14 20:04:27 +00001536 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1537 crec_ttl(crecp, now), NULL,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001538 T_PTR, C_IN, "d", cache_get_name(crecp)))
1539 anscount++;
1540 }
1541 }
1542 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
Simon Kelley2bb73af2013-04-24 17:38:19 +01001543 else if (is_rev_synth(is_arpa, &addr, name))
1544 {
1545 ans = 1;
1546 if (!dryrun)
1547 {
1548 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1549
1550 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1551 daemon->local_ttl, NULL,
1552 T_PTR, C_IN, "d", name))
1553 anscount++;
1554 }
1555 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001556 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001557 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001558 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001559 {
1560 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1561 ans = 1;
1562 nxdomain = 1;
1563 if (!dryrun)
1564 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001565 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001566 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001567 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001568
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001569 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1570 {
1571 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001572 struct interface_name *intr;
1573
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001574 if (flag == F_IPV6)
1575#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001576 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001577#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001578 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001579#endif
1580
1581 if (qtype != type && qtype != T_ANY)
1582 continue;
1583
Simon Kelley316e2732010-01-22 20:16:09 +00001584 /* Check for "A for A" queries; be rather conservative
1585 about what looks like dotted-quad. */
1586 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001587 {
Simon Kelley316e2732010-01-22 20:16:09 +00001588 char *cp;
1589 unsigned int i, a;
1590 int x;
1591
1592 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001593 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001594 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001595 {
1596 i = 5;
1597 break;
1598 }
1599
1600 a = (a << 8) + x;
1601
1602 if (*cp == '.')
1603 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001604 }
Simon Kelley316e2732010-01-22 20:16:09 +00001605
1606 if (i == 4)
1607 {
1608 ans = 1;
1609 if (!dryrun)
1610 {
1611 addr.addr.addr4.s_addr = htonl(a);
1612 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1613 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1614 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1615 anscount++;
1616 }
1617 continue;
1618 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001619 }
1620
Simon Kelleyf2621c72007-04-29 19:47:21 +01001621 /* interface name stuff */
Simon Kelley115ac3e2013-05-20 11:28:32 +01001622
1623 for (intr = daemon->int_names; intr; intr = intr->next)
1624 if (hostname_isequal(name, intr->name))
1625 break;
1626
1627 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001628 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001629 struct addrlist *addrlist;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001630
Simon Kelley115ac3e2013-05-20 11:28:32 +01001631 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001632
Simon Kelley115ac3e2013-05-20 11:28:32 +01001633 addrlist = intr->addr4;
1634#ifdef HAVE_IPV6
1635 if (type == T_AAAA)
1636 addrlist = intr->addr6;
1637#endif
1638 ans = 1;
1639 if (!dryrun)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001640 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001641 if (!addrlist)
1642 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1643 else
1644 for (; addrlist; addrlist = addrlist->next)
1645 {
1646 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1647 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1648 daemon->local_ttl, NULL, type, C_IN,
1649 type == T_A ? "4" : "6", &addrlist->addr))
1650 anscount++;
1651 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001652 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001653 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001654 }
1655
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001656 cname_restart:
1657 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
1658 {
1659 int localise = 0;
1660
1661 /* See if a putative address is on the network from which we recieved
1662 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001663 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001664 {
1665 struct crec *save = crecp;
1666 do {
1667 if ((crecp->flags & F_HOSTS) &&
1668 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1669 {
1670 localise = 1;
1671 break;
1672 }
1673 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1674 crecp = save;
1675 }
1676
1677 do
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001678 {
Simon Kelley26128d22004-11-14 16:43:54 +00001679 /* don't answer wildcard queries with data not from /etc/hosts
1680 or DHCP leases */
1681 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1682 break;
1683
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001684 if (crecp->flags & F_CNAME)
1685 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001686 if (!dryrun)
1687 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001688 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
Simon Kelley9009d742008-11-14 20:04:27 +00001689 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1690 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001691 T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
1692 anscount++;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001693 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001694
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001695 strcpy(name, cache_get_name(crecp->addr.cname.cache));
1696 goto cname_restart;
1697 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001698
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001699 if (crecp->flags & F_NEG)
1700 {
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001701 ans = 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001702 auth = 0;
1703 if (crecp->flags & F_NXDOMAIN)
1704 nxdomain = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001705 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001706 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001707 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001708 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001709 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001710 /* If we are returning local answers depending on network,
1711 filter here. */
1712 if (localise &&
1713 (crecp->flags & F_HOSTS) &&
1714 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1715 continue;
1716
1717 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1718 auth = 0;
1719
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001720 ans = 1;
1721 if (!dryrun)
1722 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001723 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
Simon Kelley7622fc02009-06-04 20:32:05 +01001724 record_source(crecp->uid));
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001725
Simon Kelley9009d742008-11-14 20:04:27 +00001726 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1727 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001728 type == T_A ? "4" : "6", &crecp->addr))
1729 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001730 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001731 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001732 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001733 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001734 else if (is_name_synthetic(flag, name, &addr))
1735 {
1736 ans = 1;
1737 if (!dryrun)
1738 {
1739 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
1740 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1741 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
1742 anscount++;
1743 }
1744 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001745 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001746
1747 if (qtype == T_CNAME || qtype == T_ANY)
1748 {
1749 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
1750 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP))))
1751 {
1752 ans = 1;
1753 if (!dryrun)
1754 {
1755 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1756 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1757 crec_ttl(crecp, now), &nameoffset,
1758 T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
1759 anscount++;
1760 }
1761 }
1762 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001763
1764 if (qtype == T_MX || qtype == T_ANY)
1765 {
1766 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001767 for (rec = daemon->mxnames; rec; rec = rec->next)
1768 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001769 {
1770 ans = found = 1;
1771 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001772 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001773 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001774 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00001775 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1776 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1777 {
1778 anscount++;
1779 if (rec->target)
1780 rec->offset = offset;
1781 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001782 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001783 }
1784
Simon Kelley28866e92011-02-14 20:19:14 +00001785 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001786 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
1787 {
1788 ans = 1;
1789 if (!dryrun)
1790 {
Simon Kelley28866e92011-02-14 20:19:14 +00001791 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001792 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1793 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00001794 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001795 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001796 }
1797 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001798 }
1799
1800 if (qtype == T_SRV || qtype == T_ANY)
1801 {
1802 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001803 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
1804
Simon Kelley0a852542005-03-23 20:28:59 +00001805 for (rec = daemon->mxnames; rec; rec = rec->next)
1806 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001807 {
1808 found = ans = 1;
1809 if (!dryrun)
1810 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001811 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001812 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001813 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001814 &offset, T_SRV, C_IN, "sssd",
1815 rec->priority, rec->weight, rec->srvport, rec->target))
1816 {
1817 anscount++;
1818 if (rec->target)
1819 rec->offset = offset;
1820 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001821 }
Simon Kelley28866e92011-02-14 20:19:14 +00001822
1823 /* unlink first SRV record found */
1824 if (!move)
1825 {
1826 move = rec;
1827 *up = rec->next;
1828 }
1829 else
1830 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001831 }
Simon Kelley28866e92011-02-14 20:19:14 +00001832 else
1833 up = &rec->next;
1834
1835 /* put first SRV record back at the end. */
1836 if (move)
1837 {
1838 *up = move;
1839 move->next = NULL;
1840 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001841
Simon Kelley28866e92011-02-14 20:19:14 +00001842 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001843 {
1844 ans = 1;
1845 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001846 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001847 }
1848 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001849
1850 if (qtype == T_NAPTR || qtype == T_ANY)
1851 {
1852 struct naptr *na;
1853 for (na = daemon->naptr; na; na = na->next)
1854 if (hostname_isequal(name, na->name))
1855 {
1856 ans = 1;
1857 if (!dryrun)
1858 {
Simon Kelley28866e92011-02-14 20:19:14 +00001859 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001860 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1861 NULL, T_NAPTR, C_IN, "sszzzd",
1862 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1863 anscount++;
1864 }
1865 }
1866 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001867
1868 if (qtype == T_MAILB)
1869 ans = 1, nxdomain = 1;
1870
Simon Kelley28866e92011-02-14 20:19:14 +00001871 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001872 {
1873 ans = 1;
1874 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001875 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001876 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001877 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001878
1879 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001880 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001881 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001882
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001883 if (dryrun)
1884 {
1885 dryrun = 0;
1886 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001887 }
1888
Simon Kelley0a852542005-03-23 20:28:59 +00001889 /* create an additional data section, for stuff in SRV and MX record replies. */
1890 for (rec = daemon->mxnames; rec; rec = rec->next)
1891 if (rec->offset != 0)
1892 {
1893 /* squash dupes */
1894 struct mx_srv_record *tmp;
1895 for (tmp = rec->next; tmp; tmp = tmp->next)
1896 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1897 tmp->offset = 0;
1898
1899 crecp = NULL;
1900 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1901 {
Simon Kelley0a852542005-03-23 20:28:59 +00001902#ifdef HAVE_IPV6
1903 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
1904#else
1905 int type = T_A;
1906#endif
1907 if (crecp->flags & F_NEG)
1908 continue;
1909
Simon Kelley9009d742008-11-14 20:04:27 +00001910 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
1911 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00001912 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1913 addncount++;
1914 }
1915 }
1916
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001917 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00001918 /* clear authoritative and truncated flags, set QR flag */
1919 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1920 /* set RA flag */
1921 header->hb4 |= HB4_RA;
1922
1923 /* authoritive - only hosts and DHCP derived names. */
1924 if (auth)
1925 header->hb3 |= HB3_AA;
1926
1927 /* truncation */
1928 if (trunc)
1929 header->hb3 |= HB3_TC;
1930
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001931 if (anscount == 0 && nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00001932 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001933 else
Simon Kelley572b41e2011-02-18 18:11:18 +00001934 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001935 header->ancount = htons(anscount);
1936 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00001937 header->arcount = htons(addncount);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001938 return ansp - (unsigned char *)header;
1939}
1940