blob: 5896a930e4135804c9d98ce278bcee7a01a0f869 [file] [log] [blame]
Simon Kelley59546082012-01-06 20:02:04 +00001/* dnsmasq is Copyright (c) 2000-2012 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,
Simon Kelley28866e92011-02-14 20:19:14 +0000780 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;
Simon Kelley0a852542005-03-23 20:28:59 +0000786
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100787 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000788
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100789 /* 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 +0000790 if (daemon->doctors || option_bool(OPT_LOG))
Simon Kelley0a852542005-03-23 20:28:59 +0000791 {
792 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100793 ttl = find_soa(header, qlen, name);
Simon Kelley0a852542005-03-23 20:28:59 +0000794 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100795
796 /* go through the questions. */
797 p = (unsigned char *)(header+1);
798
Simon Kelley5aabfc72007-08-29 11:24:47 +0100799 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100800 {
801 int found = 0, cname_count = 5;
802 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000803 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000804 unsigned long cttl = ULONG_MAX, attl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100805
Simon Kelley824af852008-02-12 20:43:05 +0000806 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000807 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000808 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100809
810 GETSHORT(qtype, p);
811 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000812
813 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100814 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000815
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100816 /* PTRs: we chase CNAMEs here, since we have no way to
817 represent them in the cache. */
818 if (qtype == T_PTR)
819 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000820 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100821
822 if (!name_encoding)
823 continue;
824
825 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000826 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100827 cname_loop:
828 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000829 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100830
Simon Kelley5aabfc72007-08-29 11:24:47 +0100831 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100832 {
Simon Kelley824af852008-02-12 20:43:05 +0000833 unsigned char *tmp = namep;
834 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000835 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
836 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000837 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100838
839 GETSHORT(aqtype, p1);
840 GETSHORT(aqclass, p1);
841 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100842 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
843 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000844 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100845 PUTLONG(daemon->max_ttl, p1);
846 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100847 GETSHORT(ardlen, p1);
848 endrr = p1+ardlen;
849
850 /* TTL of record is minimum of CNAMES and PTR */
851 if (attl < cttl)
852 cttl = attl;
853
854 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
855 {
Simon Kelley9009d742008-11-14 20:04:27 +0000856 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000857 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100858
859 if (aqtype == T_CNAME)
860 {
861 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000862 return 0; /* looped CNAMES */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100863 goto cname_loop;
864 }
865
866 cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);
867 found = 1;
868 }
869
870 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000871 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000872 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100873 }
874 }
875
Simon Kelley28866e92011-02-14 20:19:14 +0000876 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100877 {
878 if (!searched_soa)
879 {
880 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100881 ttl = find_soa(header, qlen, NULL);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882 }
883 if (ttl)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100884 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000885 }
886 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100887 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000888 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100889 /* everything other than PTR */
890 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100891 int addrlen;
892
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100893 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100894 {
895 addrlen = INADDRSZ;
896 flags |= F_IPV4;
897 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100899 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100900 {
901 addrlen = IN6ADDRSZ;
902 flags |= F_IPV6;
903 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000904#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100905 else
906 continue;
907
908 if (!(flags & F_NXDOMAIN))
909 {
910 cname_loop1:
911 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000912 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100913
Simon Kelley5aabfc72007-08-29 11:24:47 +0100914 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000915 {
Simon Kelley9009d742008-11-14 20:04:27 +0000916 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000917 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100918
919 GETSHORT(aqtype, p1);
920 GETSHORT(aqclass, p1);
921 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100922 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
923 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000924 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100925 PUTLONG(daemon->max_ttl, p1);
926 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100927 GETSHORT(ardlen, p1);
928 endrr = p1+ardlen;
929
930 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000931 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100932 if (aqtype == T_CNAME)
933 {
934 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000935 return 0; /* looped CNAMES */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100936 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100937 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100938 {
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100939 newc->addr.cname.cache = NULL;
940 if (cpp)
941 {
942 cpp->addr.cname.cache = newc;
943 cpp->addr.cname.uid = newc->uid;
944 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100945 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000946
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100947 cpp = newc;
948 if (attl < cttl)
949 cttl = attl;
950
Simon Kelley9009d742008-11-14 20:04:27 +0000951 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000952 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100953 goto cname_loop1;
954 }
955 else
956 {
957 found = 1;
Simon Kelley9009d742008-11-14 20:04:27 +0000958
Simon Kelley5aabfc72007-08-29 11:24:47 +0100959 /* copy address into aligned storage */
Simon Kelley9009d742008-11-14 20:04:27 +0000960 if (!CHECK_LEN(header, p1, qlen, addrlen))
961 return 0; /* bad packet */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100962 memcpy(&addr, p1, addrlen);
Simon Kelley824af852008-02-12 20:43:05 +0000963
964 /* check for returned address in private space */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100965 if (check_rebind &&
Simon Kelley824af852008-02-12 20:43:05 +0000966 (flags & F_IPV4) &&
Simon Kelley28866e92011-02-14 20:19:14 +0000967 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +0000968 return 1;
969
Simon Kelley5aabfc72007-08-29 11:24:47 +0100970 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
Simon Kelley26128d22004-11-14 16:43:54 +0000971 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100972 {
973 cpp->addr.cname.cache = newc;
974 cpp->addr.cname.uid = newc->uid;
975 }
976 cpp = NULL;
977 }
978 }
979
980 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000981 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000982 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100983 }
984 }
985
Simon Kelley28866e92011-02-14 20:19:14 +0000986 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100987 {
988 if (!searched_soa)
989 {
990 searched_soa = 1;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100991 ttl = find_soa(header, qlen, NULL);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100992 }
993 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +0000994 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100995 if (ttl || cpp)
996 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100997 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
Simon Kelley26128d22004-11-14 16:43:54 +0000998 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100999 {
1000 cpp->addr.cname.cache = newc;
1001 cpp->addr.cname.uid = newc->uid;
1002 }
1003 }
1004 }
1005 }
1006 }
1007
Simon Kelley1023dcb2012-04-09 18:00:08 +01001008 /* Don't put stuff from a truncated packet into the cache.
1009 Don't cache replies where DNSSEC validation was turned off, either
1010 the upstream server told us so, or the original query specified it.
1011 Don't cache replies from non-recursive nameservers, since we may get a
1012 reply containing a CNAME but not its target, even though the target
1013 does exist. */
1014 if (!(header->hb3 & HB3_TC) &&
1015 !(header->hb4 & HB4_CD) &&
1016 (header->hb4 & HB4_RA) &&
1017 !checking_disabled)
Simon Kelley824af852008-02-12 20:43:05 +00001018 cache_end_insert();
1019
1020 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001021}
1022
1023/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001024 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001025
Simon Kelley572b41e2011-02-18 18:11:18 +00001026unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001027{
1028 unsigned char *p = (unsigned char *)(header+1);
1029 int qtype, qclass;
1030
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001031 if (typep)
1032 *typep = 0;
1033
Simon Kelley572b41e2011-02-18 18:11:18 +00001034 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001035 return 0; /* must be exactly one query. */
1036
Simon Kelley9009d742008-11-14 20:04:27 +00001037 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001038 return 0; /* bad packet */
1039
1040 GETSHORT(qtype, p);
1041 GETSHORT(qclass, p);
1042
Simon Kelley0a852542005-03-23 20:28:59 +00001043 if (typep)
1044 *typep = qtype;
1045
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001046 if (qclass == C_IN)
1047 {
1048 if (qtype == T_A)
1049 return F_IPV4;
1050 if (qtype == T_AAAA)
1051 return F_IPV6;
1052 if (qtype == T_ANY)
1053 return F_IPV4 | F_IPV6;
1054 }
1055
1056 return F_QUERY;
1057}
1058
1059
Simon Kelley572b41e2011-02-18 18:11:18 +00001060size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001061 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001062{
1063 unsigned char *p = skip_questions(header, qlen);
1064
Simon Kelley572b41e2011-02-18 18:11:18 +00001065 /* clear authoritative and truncated flags, set QR flag */
1066 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1067 /* set RA flag */
1068 header->hb4 |= HB4_RA;
1069
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001070 header->nscount = htons(0);
1071 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001072 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001073 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001074 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001075 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001076 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001077 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001078 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001079 else if (p && flags == F_IPV4)
1080 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001081 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001082 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001083 header->hb3 |= HB3_AA;
1084 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 +00001085 }
1086#ifdef HAVE_IPV6
1087 else if (p && flags == F_IPV6)
1088 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001089 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001090 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001091 header->hb3 |= HB3_AA;
1092 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 +00001093 }
1094#endif
1095 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001096 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001097
1098 return p - (unsigned char *)header;
1099}
Simon Kelley36717ee2004-09-20 19:20:58 +01001100
1101/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001102int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001103{
1104 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001105 struct mx_srv_record *mx;
1106 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001107 struct interface_name *intr;
1108 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001109 struct naptr *naptr;
1110
1111 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
Simon Kelley36717ee2004-09-20 19:20:58 +01001112 (crecp->flags & (F_HOSTS | F_DHCP)))
1113 return 1;
1114
Simon Kelley7de060b2011-08-26 17:24:52 +01001115 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1116 if (hostname_isequal(name, naptr->name))
1117 return 1;
1118
1119 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001120 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001121 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001122
Simon Kelley0a852542005-03-23 20:28:59 +00001123 for (txt = daemon->txt; txt; txt = txt->next)
1124 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001125 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001126
1127 for (intr = daemon->int_names; intr; intr = intr->next)
1128 if (hostname_isequal(name, intr->name))
1129 return 1;
1130
1131 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1132 if (hostname_isequal(name, ptr->name))
1133 return 1;
1134
Simon Kelley36717ee2004-09-20 19:20:58 +01001135 return 0;
1136}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001137
1138/* Is the packet a reply with the answer address equal to addr?
1139 If so mung is into an NXDOMAIN reply and also put that information
1140 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001141int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001142 struct bogus_addr *baddr, time_t now)
1143{
1144 unsigned char *p;
1145 int i, qtype, qclass, rdlen;
1146 unsigned long ttl;
1147 struct bogus_addr *baddrp;
1148
1149 /* skip over questions */
1150 if (!(p = skip_questions(header, qlen)))
1151 return 0; /* bad packet */
1152
Simon Kelley5aabfc72007-08-29 11:24:47 +01001153 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001154 {
Simon Kelley9009d742008-11-14 20:04:27 +00001155 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001156 return 0; /* bad packet */
1157
1158 GETSHORT(qtype, p);
1159 GETSHORT(qclass, p);
1160 GETLONG(ttl, p);
1161 GETSHORT(rdlen, p);
1162
1163 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001164 {
1165 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1166 return 0;
1167
1168 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1169 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1170 {
1171 /* Found a bogus address. Insert that info here, since there no SOA record
1172 to get the ttl from in the normal processing */
1173 cache_start_insert();
1174 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
1175 cache_end_insert();
1176
1177 return 1;
1178 }
1179 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001180
Simon Kelley9009d742008-11-14 20:04:27 +00001181 if (!ADD_RDLEN(header, p, qlen, rdlen))
1182 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001183 }
1184
1185 return 0;
1186}
1187
Simon Kelley4f7b3042012-11-28 21:27:02 +00001188int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
1189 unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001190{
1191 va_list ap;
1192 unsigned char *sav, *p = *pp;
1193 int j;
1194 unsigned short usval;
1195 long lval;
1196 char *sval;
1197
1198 if (truncp && *truncp)
1199 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001200
1201 va_start(ap, format); /* make ap point to 1st unamed argument */
1202
1203 if (nameoffset != 0)
1204 {
1205 PUTSHORT(nameoffset | 0xc000, p);
1206 }
1207 else
1208 {
1209 p = do_rfc1035_name(p, va_arg(ap, char *));
1210 *p++ = 0;
1211 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001212
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001213 PUTSHORT(type, p);
1214 PUTSHORT(class, p);
1215 PUTLONG(ttl, p); /* TTL */
1216
1217 sav = p; /* Save pointer to RDLength field */
1218 PUTSHORT(0, p); /* Placeholder RDLength */
1219
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001220 for (; *format; format++)
1221 switch (*format)
1222 {
1223#ifdef HAVE_IPV6
1224 case '6':
1225 sval = va_arg(ap, char *);
1226 memcpy(p, sval, IN6ADDRSZ);
1227 p += IN6ADDRSZ;
1228 break;
1229#endif
1230
1231 case '4':
1232 sval = va_arg(ap, char *);
1233 memcpy(p, sval, INADDRSZ);
1234 p += INADDRSZ;
1235 break;
1236
1237 case 's':
1238 usval = va_arg(ap, int);
1239 PUTSHORT(usval, p);
1240 break;
1241
1242 case 'l':
1243 lval = va_arg(ap, long);
1244 PUTLONG(lval, p);
1245 break;
1246
1247 case 'd':
1248 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001249 if (offset)
1250 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001251 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001252 *p++ = 0;
1253 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001254
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001255 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001256 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001257 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001258 if (usval != 0)
1259 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001260 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001261 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001262
1263 case 'z':
1264 sval = va_arg(ap, char *);
1265 usval = sval ? strlen(sval) : 0;
1266 if (usval > 255)
1267 usval = 255;
1268 *p++ = (unsigned char)usval;
1269 memcpy(p, sval, usval);
1270 p += usval;
1271 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001272 }
1273
1274 va_end(ap); /* clean up variable argument pointer */
1275
1276 j = p - sav - 2;
1277 PUTSHORT(j, sav); /* Now, store real RDLength */
1278
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001279 /* check for overflow of buffer */
1280 if (limit && ((unsigned char *)limit - p) < 0)
1281 {
1282 if (truncp)
1283 *truncp = 1;
1284 return 0;
1285 }
1286
1287 *pp = p;
1288 return 1;
1289}
1290
Simon Kelley9009d742008-11-14 20:04:27 +00001291static unsigned long crec_ttl(struct crec *crecp, time_t now)
1292{
1293 /* Return 0 ttl for DHCP entries, which might change
1294 before the lease expires. */
1295
1296 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1297 return daemon->local_ttl;
1298
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001299 /* Return the Max TTL value if it is lower then the actual TTL */
1300 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1301 return crecp->ttd - now;
1302 else
1303 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001304}
1305
1306
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001307/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001308size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelleycdeda282006-03-16 20:16:06 +00001309 struct in_addr local_addr, struct in_addr local_netmask, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001310{
Simon Kelley3be34542004-09-11 19:12:13 +01001311 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001312 unsigned char *p, *ansp, *pheader;
Simon Kelley832af0b2007-01-21 20:01:28 +00001313 int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001314 struct all_addr addr;
1315 unsigned int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001316 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001317 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001318 int dryrun = 0, sec_reqd = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001319 int is_sign;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001320 struct crec *crecp;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001321 int nxdomain = 0, auth = 1, trunc = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001322 struct mx_srv_record *rec;
1323
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001324 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1325 partial replies, so we have to do a dry run to see if we can answer
1326 the query. We check to see if the do bit is set, if so we always
1327 forward rather than answering from the cache, which doesn't include
1328 security information. */
1329
Simon Kelley832af0b2007-01-21 20:01:28 +00001330 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001331 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001332 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001333 unsigned char *psave = pheader;
1334
1335 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001336 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001337 GETSHORT(flags, pheader);
1338
1339 sec_reqd = flags & 0x8000; /* do bit */
1340
1341 /* If our client is advertising a larger UDP packet size
1342 than we allow, trim it so that we don't get an overlarge
1343 response from upstream */
1344
Simon Kelley832af0b2007-01-21 20:01:28 +00001345 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001346 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001347
1348 dryrun = 1;
1349 }
1350
Simon Kelley572b41e2011-02-18 18:11:18 +00001351 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001352 return 0;
1353
Simon Kelley0a852542005-03-23 20:28:59 +00001354 for (rec = daemon->mxnames; rec; rec = rec->next)
1355 rec->offset = 0;
1356
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001357 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001358 /* determine end of question section (we put answers there) */
1359 if (!(ansp = skip_questions(header, qlen)))
1360 return 0; /* bad packet */
1361
1362 /* now process each question, answers go in RRs after the question */
1363 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001364
Simon Kelley5aabfc72007-08-29 11:24:47 +01001365 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001366 {
1367 /* save pointer to name for copying into answers */
1368 nameoffset = p - (unsigned char *)header;
1369
1370 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001371 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001372 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001373
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001374 GETSHORT(qtype, p);
1375 GETSHORT(qclass, p);
1376
1377 ans = 0; /* have we answered this question */
1378
Simon Kelley0a852542005-03-23 20:28:59 +00001379 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001380 {
Simon Kelley0a852542005-03-23 20:28:59 +00001381 struct txt_record *t;
1382 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001383 {
Simon Kelley0a852542005-03-23 20:28:59 +00001384 if (t->class == qclass && hostname_isequal(name, t->name))
1385 {
1386 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001387 if (!dryrun)
1388 {
Simon Kelley28866e92011-02-14 20:19:14 +00001389 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001390 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1391 daemon->local_ttl, NULL,
1392 T_TXT, t->class, "t", t->len, t->txt))
1393 anscount++;
1394
1395 }
Simon Kelley0a852542005-03-23 20:28:59 +00001396 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001397 }
Simon Kelley0a852542005-03-23 20:28:59 +00001398 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001399
Simon Kelley0a852542005-03-23 20:28:59 +00001400 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001401 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001402 struct txt_record *t;
1403
1404 for (t = daemon->rr; t; t = t->next)
1405 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1406 {
1407 ans = 1;
1408 if (!dryrun)
1409 {
1410 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1411 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1412 daemon->local_ttl, NULL,
1413 t->class, C_IN, "t", t->len, t->txt))
1414 anscount ++;
1415 }
1416 }
1417
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001418 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001419 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001420 /* see if it's w.z.y.z.in-addr.arpa format */
1421 int is_arpa = in_arpa_name_2_addr(name, &addr);
1422 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001423 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001424
1425 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1426 if (hostname_isequal(name, ptr->name))
1427 break;
1428
Simon Kelleyf2621c72007-04-29 19:47:21 +01001429 if (is_arpa == F_IPV4)
1430 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001431 {
1432 if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
1433 break;
1434 else
1435 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1436 intr = intr->next;
1437 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001438
1439 if (intr)
1440 {
1441 ans = 1;
1442 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001443 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001444 log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001445 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1446 daemon->local_ttl, NULL,
1447 T_PTR, C_IN, "d", intr->name))
1448 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001449 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001450 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001451 else if (ptr)
1452 {
1453 ans = 1;
1454 if (!dryrun)
1455 {
Simon Kelley28866e92011-02-14 20:19:14 +00001456 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001457 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001458 if (hostname_isequal(name, ptr->name) &&
1459 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1460 daemon->local_ttl, NULL,
1461 T_PTR, C_IN, "d", ptr->ptr))
1462 anscount++;
1463
Simon Kelley832af0b2007-01-21 20:01:28 +00001464 }
1465 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001466 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
1467 do
1468 {
1469 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1470 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1471 continue;
1472
1473 if (crecp->flags & F_NEG)
1474 {
1475 ans = 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001476 auth = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001477 if (crecp->flags & F_NXDOMAIN)
1478 nxdomain = 1;
1479 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001480 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001481 }
1482 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
1483 {
1484 ans = 1;
1485 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1486 auth = 0;
1487 if (!dryrun)
1488 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001489 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
Simon Kelley7622fc02009-06-04 20:32:05 +01001490 record_source(crecp->uid));
Simon Kelleyf2621c72007-04-29 19:47:21 +01001491
Simon Kelley9009d742008-11-14 20:04:27 +00001492 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1493 crec_ttl(crecp, now), NULL,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001494 T_PTR, C_IN, "d", cache_get_name(crecp)))
1495 anscount++;
1496 }
1497 }
1498 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1499 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001500 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001501 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001502 {
1503 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1504 ans = 1;
1505 nxdomain = 1;
1506 if (!dryrun)
1507 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001508 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001509 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001510 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001511
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001512 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1513 {
1514 unsigned short type = T_A;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001515
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001516 if (flag == F_IPV6)
1517#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001518 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001519#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001520 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001521#endif
1522
1523 if (qtype != type && qtype != T_ANY)
1524 continue;
1525
Simon Kelley316e2732010-01-22 20:16:09 +00001526 /* Check for "A for A" queries; be rather conservative
1527 about what looks like dotted-quad. */
1528 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001529 {
Simon Kelley316e2732010-01-22 20:16:09 +00001530 char *cp;
1531 unsigned int i, a;
1532 int x;
1533
1534 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001535 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001536 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001537 {
1538 i = 5;
1539 break;
1540 }
1541
1542 a = (a << 8) + x;
1543
1544 if (*cp == '.')
1545 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001546 }
Simon Kelley316e2732010-01-22 20:16:09 +00001547
1548 if (i == 4)
1549 {
1550 ans = 1;
1551 if (!dryrun)
1552 {
1553 addr.addr.addr4.s_addr = htonl(a);
1554 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1555 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1556 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1557 anscount++;
1558 }
1559 continue;
1560 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001561 }
1562
Simon Kelleyf2621c72007-04-29 19:47:21 +01001563 /* interface name stuff */
1564 if (qtype == T_A)
1565 {
1566 struct interface_name *intr;
1567
1568 for (intr = daemon->int_names; intr; intr = intr->next)
1569 if (hostname_isequal(name, intr->name))
1570 break;
1571
1572 if (intr)
1573 {
1574 ans = 1;
1575 if (!dryrun)
1576 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001577 if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001578 log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001579 else
1580 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001581 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001582 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1583 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1584 anscount++;
1585 }
1586 }
1587 continue;
1588 }
1589 }
1590
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001591 cname_restart:
1592 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
1593 {
1594 int localise = 0;
1595
1596 /* See if a putative address is on the network from which we recieved
1597 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001598 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001599 {
1600 struct crec *save = crecp;
1601 do {
1602 if ((crecp->flags & F_HOSTS) &&
1603 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1604 {
1605 localise = 1;
1606 break;
1607 }
1608 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1609 crecp = save;
1610 }
1611
1612 do
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001613 {
Simon Kelley26128d22004-11-14 16:43:54 +00001614 /* don't answer wildcard queries with data not from /etc/hosts
1615 or DHCP leases */
1616 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1617 break;
1618
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001619 if (crecp->flags & F_CNAME)
1620 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001621 if (!dryrun)
1622 {
Simon Kelley7622fc02009-06-04 20:32:05 +01001623 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
Simon Kelley9009d742008-11-14 20:04:27 +00001624 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1625 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001626 T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
1627 anscount++;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001628 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001629
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001630 strcpy(name, cache_get_name(crecp->addr.cname.cache));
1631 goto cname_restart;
1632 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001633
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001634 if (crecp->flags & F_NEG)
1635 {
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001636 ans = 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001637 auth = 0;
1638 if (crecp->flags & F_NXDOMAIN)
1639 nxdomain = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001640 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001641 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001642 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001643 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001644 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001645 /* If we are returning local answers depending on network,
1646 filter here. */
1647 if (localise &&
1648 (crecp->flags & F_HOSTS) &&
1649 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1650 continue;
1651
1652 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1653 auth = 0;
1654
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001655 ans = 1;
1656 if (!dryrun)
1657 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001658 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
Simon Kelley7622fc02009-06-04 20:32:05 +01001659 record_source(crecp->uid));
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001660
Simon Kelley9009d742008-11-14 20:04:27 +00001661 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1662 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001663 type == T_A ? "4" : "6", &crecp->addr))
1664 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001665 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001666 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001667 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001668 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001669 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001670
1671 if (qtype == T_CNAME || qtype == T_ANY)
1672 {
1673 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
1674 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP))))
1675 {
1676 ans = 1;
1677 if (!dryrun)
1678 {
1679 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1680 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1681 crec_ttl(crecp, now), &nameoffset,
1682 T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
1683 anscount++;
1684 }
1685 }
1686 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001687
1688 if (qtype == T_MX || qtype == T_ANY)
1689 {
1690 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001691 for (rec = daemon->mxnames; rec; rec = rec->next)
1692 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001693 {
1694 ans = found = 1;
1695 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001696 {
Simon Kelley3d8df262005-08-29 12:19:27 +01001697 unsigned int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001698 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00001699 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1700 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1701 {
1702 anscount++;
1703 if (rec->target)
1704 rec->offset = offset;
1705 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001706 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001707 }
1708
Simon Kelley28866e92011-02-14 20:19:14 +00001709 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001710 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
1711 {
1712 ans = 1;
1713 if (!dryrun)
1714 {
Simon Kelley28866e92011-02-14 20:19:14 +00001715 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001716 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1717 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00001718 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001719 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001720 }
1721 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001722 }
1723
1724 if (qtype == T_SRV || qtype == T_ANY)
1725 {
1726 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001727 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
1728
Simon Kelley0a852542005-03-23 20:28:59 +00001729 for (rec = daemon->mxnames; rec; rec = rec->next)
1730 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001731 {
1732 found = ans = 1;
1733 if (!dryrun)
1734 {
Simon Kelley3d8df262005-08-29 12:19:27 +01001735 unsigned int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001736 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001737 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001738 &offset, T_SRV, C_IN, "sssd",
1739 rec->priority, rec->weight, rec->srvport, rec->target))
1740 {
1741 anscount++;
1742 if (rec->target)
1743 rec->offset = offset;
1744 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001745 }
Simon Kelley28866e92011-02-14 20:19:14 +00001746
1747 /* unlink first SRV record found */
1748 if (!move)
1749 {
1750 move = rec;
1751 *up = rec->next;
1752 }
1753 else
1754 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001755 }
Simon Kelley28866e92011-02-14 20:19:14 +00001756 else
1757 up = &rec->next;
1758
1759 /* put first SRV record back at the end. */
1760 if (move)
1761 {
1762 *up = move;
1763 move->next = NULL;
1764 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001765
Simon Kelley28866e92011-02-14 20:19:14 +00001766 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001767 {
1768 ans = 1;
1769 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001770 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001771 }
1772 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001773
1774 if (qtype == T_NAPTR || qtype == T_ANY)
1775 {
1776 struct naptr *na;
1777 for (na = daemon->naptr; na; na = na->next)
1778 if (hostname_isequal(name, na->name))
1779 {
1780 ans = 1;
1781 if (!dryrun)
1782 {
Simon Kelley28866e92011-02-14 20:19:14 +00001783 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001784 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1785 NULL, T_NAPTR, C_IN, "sszzzd",
1786 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1787 anscount++;
1788 }
1789 }
1790 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001791
1792 if (qtype == T_MAILB)
1793 ans = 1, nxdomain = 1;
1794
Simon Kelley28866e92011-02-14 20:19:14 +00001795 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001796 {
1797 ans = 1;
1798 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001799 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001800 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001801 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001802
1803 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001804 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001805 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001806
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001807 if (dryrun)
1808 {
1809 dryrun = 0;
1810 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001811 }
1812
Simon Kelley0a852542005-03-23 20:28:59 +00001813 /* create an additional data section, for stuff in SRV and MX record replies. */
1814 for (rec = daemon->mxnames; rec; rec = rec->next)
1815 if (rec->offset != 0)
1816 {
1817 /* squash dupes */
1818 struct mx_srv_record *tmp;
1819 for (tmp = rec->next; tmp; tmp = tmp->next)
1820 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1821 tmp->offset = 0;
1822
1823 crecp = NULL;
1824 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1825 {
Simon Kelley0a852542005-03-23 20:28:59 +00001826#ifdef HAVE_IPV6
1827 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
1828#else
1829 int type = T_A;
1830#endif
1831 if (crecp->flags & F_NEG)
1832 continue;
1833
Simon Kelley9009d742008-11-14 20:04:27 +00001834 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
1835 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00001836 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1837 addncount++;
1838 }
1839 }
1840
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001841 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00001842 /* clear authoritative and truncated flags, set QR flag */
1843 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1844 /* set RA flag */
1845 header->hb4 |= HB4_RA;
1846
1847 /* authoritive - only hosts and DHCP derived names. */
1848 if (auth)
1849 header->hb3 |= HB3_AA;
1850
1851 /* truncation */
1852 if (trunc)
1853 header->hb3 |= HB3_TC;
1854
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001855 if (anscount == 0 && nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00001856 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001857 else
Simon Kelley572b41e2011-02-18 18:11:18 +00001858 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001859 header->ancount = htons(anscount);
1860 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00001861 header->arcount = htons(addncount);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001862 return ansp - (unsigned char *)header;
1863}
1864