blob: a50b7d9fa7cf0e744bed35ac23f7485e016f9d76 [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
17#include "dnsmasq.h"
18
Simon Kelley4f7b3042012-11-28 21:27:02 +000019int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
20 char *name, int isExtract, int extrabytes)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000021{
Simon Kelley3d8df262005-08-29 12:19:27 +010022 unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000023 unsigned int j, l, hops = 0;
24 int retvalue = 1;
25
Simon Kelleyf6b7dc42005-01-23 12:06:08 +000026 if (isExtract)
27 *cp = 0;
28
Simon Kelley9009d742008-11-14 20:04:27 +000029 while (1)
30 {
31 unsigned int label_type;
32
33 if (!CHECK_LEN(header, p, plen, 1))
34 return 0;
35
36 if ((l = *p++) == 0)
37 /* end marker */
38 {
39 /* check that there are the correct no of bytes after the name */
40 if (!CHECK_LEN(header, p, plen, extrabytes))
41 return 0;
42
43 if (isExtract)
44 {
45 if (cp != (unsigned char *)name)
46 cp--;
47 *cp = 0; /* terminate: lose final period */
48 }
49 else if (*cp != 0)
50 retvalue = 2;
51
52 if (p1) /* we jumped via compression */
53 *pp = p1;
54 else
55 *pp = p;
56
57 return retvalue;
58 }
59
60 label_type = l & 0xc0;
61
Simon Kelley9e4abcb2004-01-22 19:47:41 +000062 if (label_type == 0xc0) /* pointer */
63 {
Simon Kelley9009d742008-11-14 20:04:27 +000064 if (!CHECK_LEN(header, p, plen, 1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065 return 0;
66
67 /* get offset */
68 l = (l&0x3f) << 8;
69 l |= *p++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000070
71 if (!p1) /* first jump, save location to go back to */
72 p1 = p;
73
74 hops++; /* break malicious infinite loops */
75 if (hops > 255)
76 return 0;
77
78 p = l + (unsigned char *)header;
79 }
80 else if (label_type == 0x80)
81 return 0; /* reserved */
82 else if (label_type == 0x40)
83 { /* ELT */
84 unsigned int count, digs;
85
86 if ((l & 0x3f) != 1)
87 return 0; /* we only understand bitstrings */
88
89 if (!isExtract)
90 return 0; /* Cannot compare bitsrings */
91
92 count = *p++;
93 if (count == 0)
94 count = 256;
95 digs = ((count-1)>>2)+1;
96
97 /* output is \[x<hex>/siz]. which is digs+9 chars */
Simon Kelley3d8df262005-08-29 12:19:27 +010098 if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000099 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000100 if (!CHECK_LEN(header, p, plen, (count-1)>>3))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000101 return 0;
102
103 *cp++ = '\\';
104 *cp++ = '[';
105 *cp++ = 'x';
106 for (j=0; j<digs; j++)
107 {
108 unsigned int dig;
109 if (j%2 == 0)
110 dig = *p >> 4;
111 else
112 dig = *p++ & 0x0f;
113
114 *cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
115 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100116 cp += sprintf((char *)cp, "/%d]", count);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000117 /* do this here to overwrite the zero char from sprintf */
118 *cp++ = '.';
119 }
120 else
121 { /* label_type = 0 -> label. */
Simon Kelley3d8df262005-08-29 12:19:27 +0100122 if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000123 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000124 if (!CHECK_LEN(header, p, plen, l))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000125 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000126
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000127 for(j=0; j<l; j++, p++)
128 if (isExtract)
129 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100130 unsigned char c = *p;
131 if (isascii(c) && !iscntrl(c) && c != '.')
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000132 *cp++ = *p;
133 else
134 return 0;
135 }
136 else
137 {
138 unsigned char c1 = *cp, c2 = *p;
139
140 if (c1 == 0)
141 retvalue = 2;
142 else
143 {
144 cp++;
145 if (c1 >= 'A' && c1 <= 'Z')
146 c1 += 'a' - 'A';
147 if (c2 >= 'A' && c2 <= 'Z')
148 c2 += 'a' - 'A';
149
150 if (c1 != c2)
151 retvalue = 2;
152 }
153 }
154
155 if (isExtract)
156 *cp++ = '.';
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000157 else if (*cp != 0 && *cp++ != '.')
158 retvalue = 2;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000159 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000160 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000161}
162
163/* Max size of input string (for IPv6) is 75 chars.) */
164#define MAXARPANAME 75
Simon Kelley4f7b3042012-11-28 21:27:02 +0000165int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000166{
167 int j;
168 char name[MAXARPANAME+1], *cp1;
169 unsigned char *addr = (unsigned char *)addrp;
170 char *lastchunk = NULL, *penchunk = NULL;
171
172 if (strlen(namein) > MAXARPANAME)
173 return 0;
174
175 memset(addrp, 0, sizeof(struct all_addr));
176
177 /* turn name into a series of asciiz strings */
178 /* j counts no of labels */
179 for(j = 1,cp1 = name; *namein; cp1++, namein++)
180 if (*namein == '.')
181 {
182 penchunk = lastchunk;
183 lastchunk = cp1 + 1;
184 *cp1 = 0;
185 j++;
186 }
187 else
188 *cp1 = *namein;
189
190 *cp1 = 0;
191
192 if (j<3)
193 return 0;
194
195 if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
196 {
197 /* IP v4 */
198 /* address arives as a name of the form
199 www.xxx.yyy.zzz.in-addr.arpa
200 some of the low order address octets might be missing
201 and should be set to zero. */
202 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
203 {
204 /* check for digits only (weeds out things like
205 50.0/24.67.28.64.in-addr.arpa which are used
206 as CNAME targets according to RFC 2317 */
207 char *cp;
208 for (cp = cp1; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000209 if (!isdigit((unsigned char)*cp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000210 return 0;
211
212 addr[3] = addr[2];
213 addr[2] = addr[1];
214 addr[1] = addr[0];
215 addr[0] = atoi(cp1);
216 }
217
218 return F_IPV4;
219 }
220#ifdef HAVE_IPV6
221 else if (hostname_isequal(penchunk, "ip6") &&
222 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
223 {
224 /* IP v6:
225 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
226 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
227
228 Note that most of these the various reprentations are obsolete and
229 left-over from the many DNS-for-IPv6 wars. We support all the formats
230 that we can since there is no reason not to.
231 */
232
233 if (*name == '\\' && *(name+1) == '[' &&
234 (*(name+2) == 'x' || *(name+2) == 'X'))
235 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000236 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000237 {
238 char xdig[2];
239 xdig[0] = *cp1;
240 xdig[1] = 0;
241 if (j%2)
242 addr[j/2] |= strtol(xdig, NULL, 16);
243 else
244 addr[j/2] = strtol(xdig, NULL, 16) << 4;
245 }
246
247 if (*cp1 == '/' && j == 32)
248 return F_IPV6;
249 }
250 else
251 {
252 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
253 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000254 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000255 return 0;
256
257 for (j = sizeof(struct all_addr)-1; j>0; j--)
258 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
259 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
260 }
261
262 return F_IPV6;
263 }
264 }
265#endif
266
267 return 0;
268}
269
Giovanni Bajo32f82c62012-04-28 01:01:16 +0200270unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100271{
272 while(1)
273 {
Simon Kelley9009d742008-11-14 20:04:27 +0000274 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100275
Simon Kelley9009d742008-11-14 20:04:27 +0000276 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100277 return NULL;
278
Simon Kelley9009d742008-11-14 20:04:27 +0000279 label_type = (*ansp) & 0xc0;
280
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100281 if (label_type == 0xc0)
282 {
283 /* pointer for compression. */
284 ansp += 2;
285 break;
286 }
287 else if (label_type == 0x80)
288 return NULL; /* reserved */
289 else if (label_type == 0x40)
290 {
291 /* Extended label type */
292 unsigned int count;
293
Simon Kelley9009d742008-11-14 20:04:27 +0000294 if (!CHECK_LEN(header, ansp, plen, 2))
295 return NULL;
296
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100297 if (((*ansp++) & 0x3f) != 1)
298 return NULL; /* we only understand bitstrings */
299
300 count = *(ansp++); /* Bits in bitstring */
301
302 if (count == 0) /* count == 0 means 256 bits */
303 ansp += 32;
304 else
305 ansp += ((count-1)>>3)+1;
306 }
307 else
308 { /* label type == 0 Bottom six bits is length */
309 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000310
311 if (!ADD_RDLEN(header, ansp, plen, len))
312 return NULL;
313
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100314 if (len == 0)
315 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100316 }
317 }
Simon Kelley9009d742008-11-14 20:04:27 +0000318
319 if (!CHECK_LEN(header, ansp, plen, extrabytes))
320 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100321
322 return ansp;
323}
324
Simon Kelley4f7b3042012-11-28 21:27:02 +0000325unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000326{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100327 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000328 unsigned char *ansp = (unsigned char *)(header+1);
329
Simon Kelley5aabfc72007-08-29 11:24:47 +0100330 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000331 {
Simon Kelley9009d742008-11-14 20:04:27 +0000332 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100333 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000334 ansp += 4; /* class and type */
335 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000336
337 return ansp;
338}
339
Simon Kelley572b41e2011-02-18 18:11:18 +0000340static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100341{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100342 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100343
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100344 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100345 {
Simon Kelley9009d742008-11-14 20:04:27 +0000346 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100347 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100348 ansp += 8; /* type, class, TTL */
349 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000350 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100351 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100352 }
353
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100354 return ansp;
355}
356
Simon Kelley0a852542005-03-23 20:28:59 +0000357/* CRC the question section. This is used to safely detect query
358 retransmision and to detect answers to questions we didn't ask, which
359 might be poisoning attacks. Note that we decode the name rather
360 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000361 We ignore case in the names for the same reason. Return all-ones
362 if there is not question section. */
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000363#ifndef HAVE_DNSSEC
Simon Kelley572b41e2011-02-18 18:11:18 +0000364unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100365{
Simon Kelley91dccd02005-03-31 17:48:32 +0100366 int q;
367 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000368 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100369
Simon Kelley5aabfc72007-08-29 11:24:47 +0100370 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000371 {
Simon Kelley9009d742008-11-14 20:04:27 +0000372 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000373 return crc; /* bad packet */
374
Simon Kelley3d8df262005-08-29 12:19:27 +0100375 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000376 {
377 int i = 8;
378 char c = *p1;
379
380 if (c >= 'A' && c <= 'Z')
381 c += 'a' - 'A';
382
383 crc ^= c << 24;
384 while (i--)
385 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
386 }
387
388 /* CRC the class and type as well */
389 for (p1 = p; p1 < p+4; p1++)
390 {
391 int i = 8;
392 crc ^= *p1 << 24;
393 while (i--)
394 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
395 }
396
397 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000398 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000399 return crc; /* bad packet */
400 }
401
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100402 return crc;
403}
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000404#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100405
Simon Kelley572b41e2011-02-18 18:11:18 +0000406size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100407{
408 unsigned char *ansp = skip_questions(header, plen);
409
Simon Kelley9009d742008-11-14 20:04:27 +0000410 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100411 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000412 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100413
414 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
415 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000416 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100417
Simon Kelley36717ee2004-09-20 19:20:58 +0100418 /* restore pseudoheader */
419 if (pheader && ntohs(header->arcount) == 0)
420 {
421 /* must use memmove, may overlap */
422 memmove(ansp, pheader, hlen);
423 header->arcount = htons(1);
424 ansp += hlen;
425 }
426
427 return ansp - (unsigned char *)header;
428}
429
Simon Kelley572b41e2011-02-18 18:11:18 +0000430unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
Simon Kelley36717ee2004-09-20 19:20:58 +0100431{
432 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
Simon Kelley832af0b2007-01-21 20:01:28 +0000433 also return length of pseudoheader in *len and pointer to the UDP size in *p
434 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
435 forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100436
437 int i, arcount = ntohs(header->arcount);
Simon Kelley832af0b2007-01-21 20:01:28 +0000438 unsigned char *ansp = (unsigned char *)(header+1);
439 unsigned short rdlen, type, class;
440 unsigned char *ret = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000441
442 if (is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000443 {
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000444 *is_sign = 0;
445
Simon Kelley572b41e2011-02-18 18:11:18 +0000446 if (OPCODE(header) == QUERY)
Simon Kelley832af0b2007-01-21 20:01:28 +0000447 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100448 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000449 {
Simon Kelley9009d742008-11-14 20:04:27 +0000450 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000451 return NULL;
452
453 GETSHORT(type, ansp);
454 GETSHORT(class, ansp);
455
456 if (class == C_IN && type == T_TKEY)
457 *is_sign = 1;
458 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000459 }
460 }
461 else
462 {
463 if (!(ansp = skip_questions(header, plen)))
464 return NULL;
465 }
466
467 if (arcount == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100468 return NULL;
469
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100470 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
471 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000472
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100473 for (i = 0; i < arcount; i++)
474 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100475 unsigned char *save, *start = ansp;
Simon Kelley9009d742008-11-14 20:04:27 +0000476 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100477 return NULL;
478
479 GETSHORT(type, ansp);
480 save = ansp;
Simon Kelley832af0b2007-01-21 20:01:28 +0000481 GETSHORT(class, ansp);
482 ansp += 4; /* TTL */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100483 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000484 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100485 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000486 if (type == T_OPT)
Simon Kelley36717ee2004-09-20 19:20:58 +0100487 {
488 if (len)
489 *len = ansp - start;
490 if (p)
491 *p = save;
Simon Kelley832af0b2007-01-21 20:01:28 +0000492 ret = start;
Simon Kelley36717ee2004-09-20 19:20:58 +0100493 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000494 else if (is_sign &&
495 i == arcount - 1 &&
496 class == C_ANY &&
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000497 type == T_TSIG)
Simon Kelley832af0b2007-01-21 20:01:28 +0000498 *is_sign = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100499 }
500
Simon Kelley832af0b2007-01-21 20:01:28 +0000501 return ret;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100502}
Simon Kelley28866e92011-02-14 20:19:14 +0000503
504struct macparm {
505 unsigned char *limit;
Simon Kelley572b41e2011-02-18 18:11:18 +0000506 struct dns_header *header;
Simon Kelley28866e92011-02-14 20:19:14 +0000507 size_t plen;
508 union mysockaddr *l3;
509};
Simon Kelleyed4c0762013-10-08 20:46:34 +0100510
511static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
Simon Kelley3a237152013-12-12 12:15:50 +0000512 int optno, unsigned char *opt, size_t optlen, int set_do)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100513{
514 unsigned char *lenp, *datap, *p;
Simon Kelleya25720a2014-01-14 23:13:55 +0000515 int rdlen, is_sign;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100516
Simon Kelleya25720a2014-01-14 23:13:55 +0000517 if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
Simon Kelleyed4c0762013-10-08 20:46:34 +0100518 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000519 if (is_sign)
520 return plen;
521
Simon Kelleyed4c0762013-10-08 20:46:34 +0100522 /* We are adding the pseudoheader */
523 if (!(p = skip_questions(header, plen)) ||
524 !(p = skip_section(p,
Simon Kelleya25720a2014-01-14 23:13:55 +0000525 ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
Simon Kelleyed4c0762013-10-08 20:46:34 +0100526 header, plen)))
527 return plen;
528 *p++ = 0; /* empty name */
529 PUTSHORT(T_OPT, p);
530 PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
Simon Kelley3a237152013-12-12 12:15:50 +0000531 PUTSHORT(0, p); /* extended RCODE and version */
532 PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100533 lenp = p;
534 PUTSHORT(0, p); /* RDLEN */
535 rdlen = 0;
536 if (((ssize_t)optlen) > (limit - (p + 4)))
537 return plen; /* Too big */
Simon Kelleya25720a2014-01-14 23:13:55 +0000538 header->arcount = htons(ntohs(header->arcount) + 1);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100539 datap = p;
540 }
541 else
542 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000543 int i;
Simon Kelley3a237152013-12-12 12:15:50 +0000544 unsigned short code, len, flags;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100545
Simon Kelleya25720a2014-01-14 23:13:55 +0000546 /* Must be at the end, if exists */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100547 if (ntohs(header->arcount) != 1 ||
Simon Kelleyed4c0762013-10-08 20:46:34 +0100548 is_sign ||
549 (!(p = skip_name(p, header, plen, 10))))
550 return plen;
551
Simon Kelley3a237152013-12-12 12:15:50 +0000552 p += 6; /* skip UDP length and RCODE */
553 GETSHORT(flags, p);
554 if (set_do)
555 {
556 p -=2;
557 PUTSHORT(flags | 0x8000, p);
558 }
559
Simon Kelleyed4c0762013-10-08 20:46:34 +0100560 lenp = p;
561 GETSHORT(rdlen, p);
562 if (!CHECK_LEN(header, p, plen, rdlen))
563 return plen; /* bad packet */
564 datap = p;
565
Simon Kelley3a237152013-12-12 12:15:50 +0000566 /* no option to add */
567 if (optno == 0)
568 return plen;
569
Simon Kelleyed4c0762013-10-08 20:46:34 +0100570 /* check if option already there */
571 for (i = 0; i + 4 < rdlen; i += len + 4)
572 {
573 GETSHORT(code, p);
574 GETSHORT(len, p);
575 if (code == optno)
576 return plen;
577 p += len;
578 }
579
580 if (((ssize_t)optlen) > (limit - (p + 4)))
581 return plen; /* Too big */
582 }
583
Simon Kelley0fc2f312014-01-08 10:26:58 +0000584 if (optno != 0)
585 {
586 PUTSHORT(optno, p);
587 PUTSHORT(optlen, p);
588 memcpy(p, opt, optlen);
589 p += optlen;
590 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100591
592 PUTSHORT(p - datap, lenp);
593 return p - (unsigned char *)header;
594
595}
Simon Kelley28866e92011-02-14 20:19:14 +0000596
597static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
598{
599 struct macparm *parm = parmv;
600 int match = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100601
Simon Kelley28866e92011-02-14 20:19:14 +0000602 if (family == parm->l3->sa.sa_family)
603 {
604 if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
605 match = 1;
606#ifdef HAVE_IPV6
607 else
608 if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
609 match = 1;
610#endif
611 }
612
613 if (!match)
614 return 1; /* continue */
Simon Kelley28866e92011-02-14 20:19:14 +0000615
Simon Kelley3a237152013-12-12 12:15:50 +0000616 parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
Simon Kelley28866e92011-02-14 20:19:14 +0000617
618 return 0; /* done */
619}
620
Simon Kelley572b41e2011-02-18 18:11:18 +0000621size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
Simon Kelley28866e92011-02-14 20:19:14 +0000622{
623 struct macparm parm;
624
625/* Must have an existing pseudoheader as the only ar-record,
626 or have no ar-records. Must also not be signed */
627
628 if (ntohs(header->arcount) > 1)
629 return plen;
630
631 parm.header = header;
632 parm.limit = (unsigned char *)limit;
633 parm.plen = plen;
634 parm.l3 = l3;
635
636 iface_enumerate(AF_UNSPEC, &parm, filter_mac);
637
638 return parm.plen;
639}
640
Simon Kelleyed4c0762013-10-08 20:46:34 +0100641struct subnet_opt {
642 u16 family;
643 u8 source_netmask, scope_netmask;
644#ifdef HAVE_IPV6
645 u8 addr[IN6ADDRSZ];
646#else
647 u8 addr[INADDRSZ];
648#endif
649};
650
Simon Kelley44de6492013-11-06 11:36:57 +0000651static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100652{
653 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
654
655 int len;
656 void *addrp;
657
Simon Kelleyed4c0762013-10-08 20:46:34 +0100658#ifdef HAVE_IPV6
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100659 if (source->sa.sa_family == AF_INET6)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100660 {
661 opt->family = htons(2);
662 opt->source_netmask = daemon->addr6_netmask;
663 addrp = &source->in6.sin6_addr;
664 }
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100665 else
Simon Kelleyed4c0762013-10-08 20:46:34 +0100666#endif
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100667 {
668 opt->family = htons(1);
669 opt->source_netmask = daemon->addr4_netmask;
670 addrp = &source->in.sin_addr;
671 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100672
673 opt->scope_netmask = 0;
674 len = 0;
675
676 if (opt->source_netmask != 0)
677 {
678 len = ((opt->source_netmask - 1) >> 3) + 1;
679 memcpy(opt->addr, addrp, len);
680 if (opt->source_netmask & 7)
681 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
682 }
683
684 return len + 4;
685}
686
687size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
688{
689 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
690
691 int len;
692 struct subnet_opt opt;
693
694 len = calc_subnet_opt(&opt, source);
Simon Kelley3a237152013-12-12 12:15:50 +0000695 return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100696}
Simon Kelley3a237152013-12-12 12:15:50 +0000697
698#ifdef HAVE_DNSSEC
699size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
700{
701 return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
702}
703#endif
704
Simon Kelleyed4c0762013-10-08 20:46:34 +0100705int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
706{
707 /* Section 9.2, Check that subnet option in reply matches. */
708
709
710 int len, calc_len;
711 struct subnet_opt opt;
712 unsigned char *p;
713 int code, i, rdlen;
714
715 calc_len = calc_subnet_opt(&opt, peer);
716
717 if (!(p = skip_name(pseudoheader, header, plen, 10)))
718 return 1;
719
720 p += 8; /* skip UDP length and RCODE */
721
722 GETSHORT(rdlen, p);
723 if (!CHECK_LEN(header, p, plen, rdlen))
724 return 1; /* bad packet */
725
726 /* check if option there */
727 for (i = 0; i + 4 < rdlen; i += len + 4)
728 {
729 GETSHORT(code, p);
730 GETSHORT(len, p);
731 if (code == EDNS0_OPTION_CLIENT_SUBNET)
732 {
733 /* make sure this doesn't mismatch. */
734 opt.scope_netmask = p[3];
735 if (len != calc_len || memcmp(p, &opt, len) != 0)
736 return 0;
737 }
738 p += len;
739 }
740
741 return 1;
742}
743
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000744/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100745int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000746{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100747 in_addr_t ip_addr = ntohl(addr.s_addr);
748
749 return
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100750 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100751 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
752 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
753 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
754 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000755}
Simon Kelley1cff1662004-03-12 08:12:58 +0000756
Simon Kelley6938f342014-01-26 22:47:39 +0000757static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley824af852008-02-12 20:43:05 +0000758{
759 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000760
761 for (i = count; i != 0; i--)
762 {
Simon Kelley28866e92011-02-14 20:19:14 +0000763 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100764 {
765 if (!extract_name(header, qlen, &p, name, 1, 10))
766 return 0;
767 }
768 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000769 return 0; /* bad packet */
770
771 GETSHORT(qtype, p);
772 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100773 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000774 GETSHORT(rdlen, p);
775
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100776 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000777 {
778 struct doctor *doctor;
779 struct in_addr addr;
780
Simon Kelley9009d742008-11-14 20:04:27 +0000781 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
782 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100783
784 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000785 memcpy(&addr, p, INADDRSZ);
786
787 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000788 {
789 if (doctor->end.s_addr == 0)
790 {
791 if (!is_same_net(doctor->in, addr, doctor->mask))
792 continue;
793 }
794 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
795 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
796 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100797
Simon Kelley73a08a22009-02-05 20:28:08 +0000798 addr.s_addr &= ~doctor->mask.s_addr;
799 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
800 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000801 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000802 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000803 memcpy(p, &addr, INADDRSZ);
804 break;
805 }
Simon Kelley824af852008-02-12 20:43:05 +0000806 }
Simon Kelley28866e92011-02-14 20:19:14 +0000807 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100808 {
809 unsigned char *p1 = p;
810 if (!CHECK_LEN(header, p1, qlen, rdlen))
811 return 0;
812 while ((p1 - p) < rdlen)
813 {
814 unsigned int i, len = *p1;
815 unsigned char *p2 = p1;
816 /* make counted string zero-term and sanitise */
817 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100818 {
819 if (!isprint((int)*(p2+1)))
820 break;
821
822 *p2 = *(p2+1);
823 p2++;
824 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100825 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000826 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100827 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100828 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100829 *p1 = len;
830 p1 += len+1;
831 }
832 }
Simon Kelley824af852008-02-12 20:43:05 +0000833
Simon Kelley9009d742008-11-14 20:04:27 +0000834 if (!ADD_RDLEN(header, p, qlen, rdlen))
835 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000836 }
837
838 return p;
839}
840
Simon Kelley6938f342014-01-26 22:47:39 +0000841static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000842{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000844 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100845 unsigned long ttl, minttl = ULONG_MAX;
846 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000847
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100848 /* first move to NS section and find TTL from any SOA section */
849 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000850 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000851 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000852
Simon Kelley5aabfc72007-08-29 11:24:47 +0100853 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000854 {
Simon Kelley9009d742008-11-14 20:04:27 +0000855 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100856 return 0; /* bad packet */
857
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000858 GETSHORT(qtype, p);
859 GETSHORT(qclass, p);
860 GETLONG(ttl, p);
861 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100862
863 if ((qclass == C_IN) && (qtype == T_SOA))
864 {
865 found_soa = 1;
866 if (ttl < minttl)
867 minttl = ttl;
868
869 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000870 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100871 return 0;
872 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000873 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100874 return 0;
875 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
876
877 GETLONG(ttl, p); /* minTTL */
878 if (ttl < minttl)
879 minttl = ttl;
880 }
Simon Kelley9009d742008-11-14 20:04:27 +0000881 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882 return 0; /* bad packet */
883 }
Simon Kelley9009d742008-11-14 20:04:27 +0000884
Simon Kelley6938f342014-01-26 22:47:39 +0000885 /* rewrite addresses in additional section too */
886 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000887 return 0;
888
889 if (!found_soa)
890 minttl = daemon->neg_ttl;
891
892 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100893}
894
895/* Note that the following code can create CNAME chains that don't point to a real record,
896 either because of lack of memory, or lack of SOA records. These are treated by the cache code as
Simon Kelley824af852008-02-12 20:43:05 +0000897 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100898 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000899int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelley6938f342014-01-26 22:47:39 +0000900 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100901{
Simon Kelley824af852008-02-12 20:43:05 +0000902 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100903 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000904 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100905 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000906#ifdef HAVE_IPSET
907 char **ipsets_cur;
908#else
909 (void)ipsets; /* unused */
910#endif
911
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100912 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000913
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100914 /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
Simon Kelley6938f342014-01-26 22:47:39 +0000915 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000916 {
917 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000918 ttl = find_soa(header, qlen, name, doctored);
919#ifdef HAVE_DNSSEC
920 if (*doctored)
921 secure = 0;
922#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000923 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100924
925 /* go through the questions. */
926 p = (unsigned char *)(header+1);
927
Simon Kelley5aabfc72007-08-29 11:24:47 +0100928 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100929 {
930 int found = 0, cname_count = 5;
931 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000932 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0435d042014-01-08 18:22:37 +0000933 int secflag = secure ? F_DNSSECOK : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000934 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000935
Simon Kelley824af852008-02-12 20:43:05 +0000936 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000937 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000938 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100939
940 GETSHORT(qtype, p);
941 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000942
943 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100944 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000945
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100946 /* PTRs: we chase CNAMEs here, since we have no way to
947 represent them in the cache. */
948 if (qtype == T_PTR)
949 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000950 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100951
952 if (!name_encoding)
953 continue;
954
955 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000956 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100957 cname_loop:
958 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000959 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100960
Simon Kelley5aabfc72007-08-29 11:24:47 +0100961 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100962 {
Simon Kelley824af852008-02-12 20:43:05 +0000963 unsigned char *tmp = namep;
964 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000965 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
966 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000967 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100968
969 GETSHORT(aqtype, p1);
970 GETSHORT(aqclass, p1);
971 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100972 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
973 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000974 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100975 PUTLONG(daemon->max_ttl, p1);
976 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100977 GETSHORT(ardlen, p1);
978 endrr = p1+ardlen;
979
980 /* TTL of record is minimum of CNAMES and PTR */
981 if (attl < cttl)
982 cttl = attl;
983
984 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
985 {
Simon Kelley9009d742008-11-14 20:04:27 +0000986 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000987 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100988
989 if (aqtype == T_CNAME)
990 {
991 if (!cname_count--)
Simon Kelley824af852008-02-12 20:43:05 +0000992 return 0; /* looped CNAMES */
Simon Kelley2d33bda2014-01-24 22:37:25 +0000993 secflag = 0; /* no longer DNSSEC */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100994 goto cname_loop;
995 }
996
Simon Kelley0435d042014-01-08 18:22:37 +0000997 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100998 found = 1;
999 }
1000
1001 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +00001002 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +00001003 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001004 }
1005 }
1006
Simon Kelley28866e92011-02-14 20:19:14 +00001007 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001008 {
1009 if (!searched_soa)
1010 {
1011 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001012 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001013 }
1014 if (ttl)
Simon Kelley0435d042014-01-08 18:22:37 +00001015 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001016 }
1017 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001018 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001019 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001020 /* everything other than PTR */
1021 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001022 int addrlen;
1023
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001024 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001025 {
1026 addrlen = INADDRSZ;
1027 flags |= F_IPV4;
1028 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001029#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001030 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001031 {
1032 addrlen = IN6ADDRSZ;
1033 flags |= F_IPV6;
1034 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001035#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001036 else
1037 continue;
1038
Simon Kelley45cca582013-10-15 10:20:13 +01001039 cname_loop1:
1040 if (!(p1 = skip_questions(header, qlen)))
1041 return 0;
1042
1043 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001044 {
Simon Kelley45cca582013-10-15 10:20:13 +01001045 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
1046 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001047
Simon Kelley45cca582013-10-15 10:20:13 +01001048 GETSHORT(aqtype, p1);
1049 GETSHORT(aqclass, p1);
1050 GETLONG(attl, p1);
1051 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001052 {
Simon Kelley45cca582013-10-15 10:20:13 +01001053 (p1) -= 4;
1054 PUTLONG(daemon->max_ttl, p1);
1055 }
1056 GETSHORT(ardlen, p1);
1057 endrr = p1+ardlen;
1058
1059 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
1060 {
1061 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001062 {
Simon Kelley45cca582013-10-15 10:20:13 +01001063 if (!cname_count--)
1064 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +00001065 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001066 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001067 {
Simon Kelley45cca582013-10-15 10:20:13 +01001068 newc->addr.cname.target.cache = NULL;
1069 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001070 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001071 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001072 cpp->addr.cname.uid = newc->uid;
1073 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001074 }
Simon Kelley45cca582013-10-15 10:20:13 +01001075
1076 cpp = newc;
1077 if (attl < cttl)
1078 cttl = attl;
1079
1080 if (!extract_name(header, qlen, &p1, name, 1, 0))
1081 return 0;
1082 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001083 }
Simon Kelley45cca582013-10-15 10:20:13 +01001084 else if (!(flags & F_NXDOMAIN))
1085 {
1086 found = 1;
1087
1088 /* copy address into aligned storage */
1089 if (!CHECK_LEN(header, p1, qlen, addrlen))
1090 return 0; /* bad packet */
1091 memcpy(&addr, p1, addrlen);
1092
1093 /* check for returned address in private space */
1094 if (check_rebind &&
1095 (flags & F_IPV4) &&
1096 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
1097 return 1;
1098
1099#ifdef HAVE_IPSET
1100 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
1101 {
1102 ipsets_cur = ipsets;
1103 while (*ipsets_cur)
1104 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
1105 }
1106#endif
1107
Simon Kelley0435d042014-01-08 18:22:37 +00001108 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001109 if (newc && cpp)
1110 {
1111 cpp->addr.cname.target.cache = newc;
1112 cpp->addr.cname.uid = newc->uid;
1113 }
1114 cpp = NULL;
1115 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001116 }
Simon Kelley45cca582013-10-15 10:20:13 +01001117
1118 p1 = endrr;
1119 if (!CHECK_LEN(header, p1, qlen, 0))
1120 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001121 }
1122
Simon Kelley28866e92011-02-14 20:19:14 +00001123 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001124 {
1125 if (!searched_soa)
1126 {
1127 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001128 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001129 }
1130 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001131 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001132 if (ttl || cpp)
1133 {
Simon Kelley0435d042014-01-08 18:22:37 +00001134 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
Simon Kelley26128d22004-11-14 16:43:54 +00001135 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001136 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001137 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001138 cpp->addr.cname.uid = newc->uid;
1139 }
1140 }
1141 }
1142 }
1143 }
1144
Simon Kelley1023dcb2012-04-09 18:00:08 +01001145 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +01001146 Don't cache replies from non-recursive nameservers, since we may get a
1147 reply containing a CNAME but not its target, even though the target
1148 does exist. */
1149 if (!(header->hb3 & HB3_TC) &&
1150 !(header->hb4 & HB4_CD) &&
1151 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +00001152 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +00001153 cache_end_insert();
1154
1155 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001156}
1157
1158/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001159 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +00001160unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001161{
1162 unsigned char *p = (unsigned char *)(header+1);
1163 int qtype, qclass;
1164
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001165 if (typep)
1166 *typep = 0;
1167
Simon Kelley572b41e2011-02-18 18:11:18 +00001168 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001169 return 0; /* must be exactly one query. */
1170
Simon Kelley9009d742008-11-14 20:04:27 +00001171 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001172 return 0; /* bad packet */
1173
1174 GETSHORT(qtype, p);
1175 GETSHORT(qclass, p);
1176
Simon Kelley0a852542005-03-23 20:28:59 +00001177 if (typep)
1178 *typep = qtype;
1179
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001180 if (qclass == C_IN)
1181 {
1182 if (qtype == T_A)
1183 return F_IPV4;
1184 if (qtype == T_AAAA)
1185 return F_IPV6;
1186 if (qtype == T_ANY)
1187 return F_IPV4 | F_IPV6;
1188 }
1189
1190 return F_QUERY;
1191}
1192
1193
Simon Kelley572b41e2011-02-18 18:11:18 +00001194size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001195 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001196{
1197 unsigned char *p = skip_questions(header, qlen);
1198
Simon Kelley572b41e2011-02-18 18:11:18 +00001199 /* clear authoritative and truncated flags, set QR flag */
1200 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1201 /* set RA flag */
1202 header->hb4 |= HB4_RA;
1203
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001204 header->nscount = htons(0);
1205 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001206 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001207 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001208 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001209 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001210 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001211 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001212 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001213 else if (p && flags == F_IPV4)
1214 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001215 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001216 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001217 header->hb3 |= HB3_AA;
1218 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001219 }
1220#ifdef HAVE_IPV6
1221 else if (p && flags == F_IPV6)
1222 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001223 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001224 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001225 header->hb3 |= HB3_AA;
1226 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001227 }
1228#endif
1229 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001230 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001231
1232 return p - (unsigned char *)header;
1233}
Simon Kelley36717ee2004-09-20 19:20:58 +01001234
1235/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001236int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001237{
1238 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001239 struct mx_srv_record *mx;
1240 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001241 struct interface_name *intr;
1242 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001243 struct naptr *naptr;
1244
1245 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +00001246 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +01001247 return 1;
1248
Simon Kelley7de060b2011-08-26 17:24:52 +01001249 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1250 if (hostname_isequal(name, naptr->name))
1251 return 1;
1252
1253 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001254 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001255 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001256
Simon Kelley0a852542005-03-23 20:28:59 +00001257 for (txt = daemon->txt; txt; txt = txt->next)
1258 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001259 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001260
1261 for (intr = daemon->int_names; intr; intr = intr->next)
1262 if (hostname_isequal(name, intr->name))
1263 return 1;
1264
1265 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1266 if (hostname_isequal(name, ptr->name))
1267 return 1;
1268
Simon Kelley36717ee2004-09-20 19:20:58 +01001269 return 0;
1270}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001271
1272/* Is the packet a reply with the answer address equal to addr?
1273 If so mung is into an NXDOMAIN reply and also put that information
1274 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001275int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001276 struct bogus_addr *baddr, time_t now)
1277{
1278 unsigned char *p;
1279 int i, qtype, qclass, rdlen;
1280 unsigned long ttl;
1281 struct bogus_addr *baddrp;
1282
1283 /* skip over questions */
1284 if (!(p = skip_questions(header, qlen)))
1285 return 0; /* bad packet */
1286
Simon Kelley5aabfc72007-08-29 11:24:47 +01001287 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001288 {
Simon Kelley9009d742008-11-14 20:04:27 +00001289 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001290 return 0; /* bad packet */
1291
1292 GETSHORT(qtype, p);
1293 GETSHORT(qclass, p);
1294 GETLONG(ttl, p);
1295 GETSHORT(rdlen, p);
1296
1297 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001298 {
1299 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1300 return 0;
1301
1302 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1303 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1304 {
1305 /* Found a bogus address. Insert that info here, since there no SOA record
1306 to get the ttl from in the normal processing */
1307 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001308 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001309 cache_end_insert();
1310
1311 return 1;
1312 }
1313 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001314
Simon Kelley9009d742008-11-14 20:04:27 +00001315 if (!ADD_RDLEN(header, p, qlen, rdlen))
1316 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001317 }
1318
1319 return 0;
1320}
1321
Simon Kelleyb75e9362012-12-07 11:50:41 +00001322int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001323 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001324{
1325 va_list ap;
1326 unsigned char *sav, *p = *pp;
1327 int j;
1328 unsigned short usval;
1329 long lval;
1330 char *sval;
1331
1332 if (truncp && *truncp)
1333 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001334
1335 va_start(ap, format); /* make ap point to 1st unamed argument */
1336
Simon Kelleyb75e9362012-12-07 11:50:41 +00001337 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001338 {
1339 PUTSHORT(nameoffset | 0xc000, p);
1340 }
1341 else
1342 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001343 char *name = va_arg(ap, char *);
1344 if (name)
1345 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001346 if (nameoffset < 0)
1347 {
1348 PUTSHORT(-nameoffset | 0xc000, p);
1349 }
1350 else
1351 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001352 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001353
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001354 PUTSHORT(type, p);
1355 PUTSHORT(class, p);
1356 PUTLONG(ttl, p); /* TTL */
1357
1358 sav = p; /* Save pointer to RDLength field */
1359 PUTSHORT(0, p); /* Placeholder RDLength */
1360
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001361 for (; *format; format++)
1362 switch (*format)
1363 {
1364#ifdef HAVE_IPV6
1365 case '6':
1366 sval = va_arg(ap, char *);
1367 memcpy(p, sval, IN6ADDRSZ);
1368 p += IN6ADDRSZ;
1369 break;
1370#endif
1371
1372 case '4':
1373 sval = va_arg(ap, char *);
1374 memcpy(p, sval, INADDRSZ);
1375 p += INADDRSZ;
1376 break;
1377
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001378 case 'b':
1379 usval = va_arg(ap, int);
1380 *p++ = usval;
1381 break;
1382
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001383 case 's':
1384 usval = va_arg(ap, int);
1385 PUTSHORT(usval, p);
1386 break;
1387
1388 case 'l':
1389 lval = va_arg(ap, long);
1390 PUTLONG(lval, p);
1391 break;
1392
1393 case 'd':
1394 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001395 if (offset)
1396 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001397 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001398 *p++ = 0;
1399 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001400
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001401 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001402 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001403 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001404 if (usval != 0)
1405 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001406 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001407 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001408
1409 case 'z':
1410 sval = va_arg(ap, char *);
1411 usval = sval ? strlen(sval) : 0;
1412 if (usval > 255)
1413 usval = 255;
1414 *p++ = (unsigned char)usval;
1415 memcpy(p, sval, usval);
1416 p += usval;
1417 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001418 }
1419
1420 va_end(ap); /* clean up variable argument pointer */
1421
1422 j = p - sav - 2;
1423 PUTSHORT(j, sav); /* Now, store real RDLength */
1424
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001425 /* check for overflow of buffer */
1426 if (limit && ((unsigned char *)limit - p) < 0)
1427 {
1428 if (truncp)
1429 *truncp = 1;
1430 return 0;
1431 }
1432
1433 *pp = p;
1434 return 1;
1435}
1436
Simon Kelley9009d742008-11-14 20:04:27 +00001437static unsigned long crec_ttl(struct crec *crecp, time_t now)
1438{
1439 /* Return 0 ttl for DHCP entries, which might change
1440 before the lease expires. */
1441
1442 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1443 return daemon->local_ttl;
1444
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001445 /* Return the Max TTL value if it is lower then the actual TTL */
1446 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1447 return crecp->ttd - now;
1448 else
1449 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001450}
1451
1452
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001453/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001454size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelleycdeda282006-03-16 20:16:06 +00001455 struct in_addr local_addr, struct in_addr local_netmask, time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001456{
Simon Kelley3be34542004-09-11 19:12:13 +01001457 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001458 unsigned char *p, *ansp, *pheader;
Simon Kelley832af0b2007-01-21 20:01:28 +00001459 int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001460 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001461 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001462 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001463 int q, ans, anscount = 0, addncount = 0;
Simon Kelleya25720a2014-01-14 23:13:55 +00001464 int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001465 int is_sign;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001466 struct crec *crecp;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001467 int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001468 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001469 size_t len;
Simon Kelley0a852542005-03-23 20:28:59 +00001470
Simon Kelleya25720a2014-01-14 23:13:55 +00001471 /* Don't return AD set even for local data if checking disabled. */
1472 if (header->hb4 & HB4_CD)
1473 sec_data = 0;
1474
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001475 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1476 partial replies, so we have to do a dry run to see if we can answer
1477 the query. We check to see if the do bit is set, if so we always
1478 forward rather than answering from the cache, which doesn't include
Simon Kelleya25720a2014-01-14 23:13:55 +00001479 security information, unless we're in DNSSEC validation mode. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001480
Simon Kelley832af0b2007-01-21 20:01:28 +00001481 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001482 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001483 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001484 unsigned char *psave = pheader;
1485
Simon Kelleya25720a2014-01-14 23:13:55 +00001486 have_pseudoheader = 1;
1487
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001488 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001489 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001490 GETSHORT(flags, pheader);
1491
1492 sec_reqd = flags & 0x8000; /* do bit */
1493
1494 /* If our client is advertising a larger UDP packet size
1495 than we allow, trim it so that we don't get an overlarge
1496 response from upstream */
1497
Simon Kelley832af0b2007-01-21 20:01:28 +00001498 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001499 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001500
1501 dryrun = 1;
1502 }
1503
Simon Kelley572b41e2011-02-18 18:11:18 +00001504 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001505 return 0;
1506
Simon Kelley0a852542005-03-23 20:28:59 +00001507 for (rec = daemon->mxnames; rec; rec = rec->next)
1508 rec->offset = 0;
1509
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001510 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001511 /* determine end of question section (we put answers there) */
1512 if (!(ansp = skip_questions(header, qlen)))
1513 return 0; /* bad packet */
1514
1515 /* now process each question, answers go in RRs after the question */
1516 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001517
Simon Kelley5aabfc72007-08-29 11:24:47 +01001518 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001519 {
1520 /* save pointer to name for copying into answers */
1521 nameoffset = p - (unsigned char *)header;
1522
1523 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001524 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001525 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001526
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001527 GETSHORT(qtype, p);
1528 GETSHORT(qclass, p);
1529
1530 ans = 0; /* have we answered this question */
1531
Simon Kelley0a852542005-03-23 20:28:59 +00001532 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001533 {
Simon Kelley0a852542005-03-23 20:28:59 +00001534 struct txt_record *t;
1535 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001536 {
Simon Kelley0a852542005-03-23 20:28:59 +00001537 if (t->class == qclass && hostname_isequal(name, t->name))
1538 {
1539 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001540 if (!dryrun)
1541 {
Simon Kelley28866e92011-02-14 20:19:14 +00001542 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001543 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1544 daemon->local_ttl, NULL,
1545 T_TXT, t->class, "t", t->len, t->txt))
1546 anscount++;
1547
1548 }
Simon Kelley0a852542005-03-23 20:28:59 +00001549 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001550 }
Simon Kelley0a852542005-03-23 20:28:59 +00001551 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001552
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001553#ifdef HAVE_DNSSEC
Simon Kelley32f90c02014-01-24 10:37:36 +00001554 if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS || qtype == T_RRSIG))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001555 {
Simon Kelley5f938532014-02-03 16:44:32 +00001556 int gotone = 0, have_rrsig = 0;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001557 struct blockdata *keydata;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001558
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001559 /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
1560 crecp = NULL;
1561 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1562 if (crecp->uid == qclass && (qtype == T_RRSIG || crecp->addr.sig.type_covered == qtype))
Simon Kelley5f938532014-02-03 16:44:32 +00001563 {
1564 have_rrsig = 1;
1565 break;
1566 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001567
Simon Kelley5f938532014-02-03 16:44:32 +00001568 if (qtype == T_RRSIG && have_rrsig)
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001569 {
Simon Kelley5f938532014-02-03 16:44:32 +00001570 ans = gotone = 1;
1571 auth = 0;
1572 }
1573 else if (qtype == T_DS && have_rrsig)
1574 {
1575 auth = 0;
1576 crecp = NULL;
1577 while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
1578 if (crecp->uid == qclass)
1579 {
1580 ans = gotone = 1;
1581 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
1582 {
1583 struct all_addr a;
1584 a.addr.keytag = crecp->addr.ds.keytag;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001585 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
1586 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1587 crec_ttl(crecp, now), &nameoffset,
1588 T_DS, qclass, "sbbt",
1589 crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
1590 anscount++;
1591
Simon Kelley5f938532014-02-03 16:44:32 +00001592 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001593 }
Simon Kelley5f938532014-02-03 16:44:32 +00001594 }
1595 else if (qtype == T_DNSKEY)
1596 {
1597 crecp = NULL;
1598 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
1599 if (crecp->uid == qclass)
1600 {
1601 if ((crecp->flags & F_CONFIG) || have_rrsig) /* Return configured keys without an RRISG */
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001602 {
Simon Kelley5f938532014-02-03 16:44:32 +00001603 if (!(crecp->flags & F_CONFIG))
1604 auth = 0, gotone = 1;
1605 ans = 1;
1606 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
1607 {
1608 struct all_addr a;
1609 a.addr.keytag = crecp->addr.key.keytag;
1610 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
1611 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1612 crec_ttl(crecp, now), &nameoffset,
1613 T_DNSKEY, qclass, "sbbt",
1614 crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
1615 anscount++;
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001616 }
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001617 }
Simon Kelley5f938532014-02-03 16:44:32 +00001618 }
1619 }
1620
1621 /* Now do RRSIGs */
1622 if (gotone)
1623 {
1624 crecp = NULL;
1625 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1626 if (crecp->uid == qclass && (qtype == T_RRSIG || (sec_reqd && crecp->addr.sig.type_covered == qtype)) &&
1627 !dryrun &&
1628 (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
1629 {
1630 if (qtype == T_RRSIG)
1631 {
1632 char types[20];
1633 querystr("rrsig", types, crecp->addr.sig.type_covered);
1634 log_query(F_RRNAME, name, NULL, types);
1635 }
1636 if ((keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)) &&
1637 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1638 crec_ttl(crecp, now), &nameoffset,
1639 T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata))
1640 anscount++;
1641 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001642 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001643 }
1644#endif
1645
Simon Kelley0a852542005-03-23 20:28:59 +00001646 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001647 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001648 struct txt_record *t;
1649
1650 for (t = daemon->rr; t; t = t->next)
1651 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1652 {
1653 ans = 1;
1654 if (!dryrun)
1655 {
1656 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1657 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1658 daemon->local_ttl, NULL,
1659 t->class, C_IN, "t", t->len, t->txt))
1660 anscount ++;
1661 }
1662 }
1663
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001664 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001665 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001666 /* see if it's w.z.y.z.in-addr.arpa format */
1667 int is_arpa = in_arpa_name_2_addr(name, &addr);
1668 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001669 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001670
1671 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1672 if (hostname_isequal(name, ptr->name))
1673 break;
1674
Simon Kelleyf2621c72007-04-29 19:47:21 +01001675 if (is_arpa == F_IPV4)
1676 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001677 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001678 struct addrlist *addrlist;
1679
Simon Kelley376d48c2013-11-13 13:04:30 +00001680 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1681 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001682 break;
1683
1684 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001685 break;
1686 else
1687 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1688 intr = intr->next;
1689 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001690#ifdef HAVE_IPV6
1691 else if (is_arpa == F_IPV6)
1692 for (intr = daemon->int_names; intr; intr = intr->next)
1693 {
1694 struct addrlist *addrlist;
1695
Simon Kelley376d48c2013-11-13 13:04:30 +00001696 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1697 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001698 break;
1699
1700 if (addrlist)
1701 break;
1702 else
1703 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1704 intr = intr->next;
1705 }
1706#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001707
1708 if (intr)
1709 {
1710 ans = 1;
1711 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001712 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001713 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001714 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1715 daemon->local_ttl, NULL,
1716 T_PTR, C_IN, "d", intr->name))
1717 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001718 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001719 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001720 else if (ptr)
1721 {
1722 ans = 1;
1723 if (!dryrun)
1724 {
Simon Kelley28866e92011-02-14 20:19:14 +00001725 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001726 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001727 if (hostname_isequal(name, ptr->name) &&
1728 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1729 daemon->local_ttl, NULL,
1730 T_PTR, C_IN, "d", ptr->ptr))
1731 anscount++;
1732
Simon Kelley832af0b2007-01-21 20:01:28 +00001733 }
1734 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001735 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001736 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001737 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001738 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001739 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1740 crecp = NULL;
1741#ifdef HAVE_DNSSEC
1742 else if (crecp->flags & F_DNSSECOK)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001743 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001744 int gotsig = 0;
1745
1746 crecp = NULL;
1747 while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001748 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001749 if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN)
1750 {
1751 char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
1752 gotsig = 1;
1753
1754 if (!dryrun &&
1755 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1756 crecp->ttd - now, &nameoffset,
1757 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
1758 anscount++;
1759 }
1760 }
1761 /* Need to re-run original cache search */
1762 crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL;
1763 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001764#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001765 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001766
1767 if (crecp)
1768 {
1769 do
1770 {
1771 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1772 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1773 continue;
1774
1775 if (!(crecp->flags & F_DNSSECOK))
1776 sec_data = 0;
1777
1778 if (crecp->flags & F_NEG)
1779 {
1780 ans = 1;
1781 auth = 0;
1782 if (crecp->flags & F_NXDOMAIN)
1783 nxdomain = 1;
1784 if (!dryrun)
1785 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1786 }
1787 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
1788 {
1789 ans = 1;
1790 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1791 auth = 0;
1792 if (!dryrun)
1793 {
1794 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1795 record_source(crecp->uid));
1796
1797 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1798 crec_ttl(crecp, now), NULL,
1799 T_PTR, C_IN, "d", cache_get_name(crecp)))
1800 anscount++;
1801 }
1802 }
1803 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1804 }
1805 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001806 else if (is_rev_synth(is_arpa, &addr, name))
1807 {
1808 ans = 1;
1809 if (!dryrun)
1810 {
1811 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1812
1813 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1814 daemon->local_ttl, NULL,
1815 T_PTR, C_IN, "d", name))
1816 anscount++;
1817 }
1818 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001819 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001820 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001821 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001822 {
1823 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1824 ans = 1;
1825 nxdomain = 1;
1826 if (!dryrun)
1827 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001828 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001829 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001830 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001831
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001832 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1833 {
1834 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001835 struct interface_name *intr;
1836
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001837 if (flag == F_IPV6)
1838#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001839 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001840#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001841 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001842#endif
1843
1844 if (qtype != type && qtype != T_ANY)
1845 continue;
1846
Simon Kelley316e2732010-01-22 20:16:09 +00001847 /* Check for "A for A" queries; be rather conservative
1848 about what looks like dotted-quad. */
1849 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001850 {
Simon Kelley316e2732010-01-22 20:16:09 +00001851 char *cp;
1852 unsigned int i, a;
1853 int x;
1854
1855 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001856 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001857 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001858 {
1859 i = 5;
1860 break;
1861 }
1862
1863 a = (a << 8) + x;
1864
1865 if (*cp == '.')
1866 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001867 }
Simon Kelley316e2732010-01-22 20:16:09 +00001868
1869 if (i == 4)
1870 {
1871 ans = 1;
1872 if (!dryrun)
1873 {
1874 addr.addr.addr4.s_addr = htonl(a);
1875 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1876 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1877 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1878 anscount++;
1879 }
1880 continue;
1881 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001882 }
1883
Simon Kelleyf2621c72007-04-29 19:47:21 +01001884 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001885 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001886 for (intr = daemon->int_names; intr; intr = intr->next)
1887 if (hostname_isequal(name, intr->name))
1888 break;
1889
1890 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001891 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001892 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001893 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001894
Simon Kelley115ac3e2013-05-20 11:28:32 +01001895 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001896
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001897 for (intr = daemon->int_names; intr; intr = intr->next)
1898 if (hostname_isequal(name, intr->name))
1899 {
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001900 ans = 1;
1901 if (!dryrun)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001902 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001903
1904 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1905#ifdef HAVE_IPV6
1906 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
1907#endif
1908 {
1909 gotit = 1;
1910 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1911 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1912 daemon->local_ttl, NULL, type, C_IN,
1913 type == T_A ? "4" : "6", &addrlist->addr))
1914 anscount++;
1915 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001916 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001917 }
1918
1919 if (!dryrun && !gotit)
1920 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1921
Simon Kelley115ac3e2013-05-20 11:28:32 +01001922 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001923 }
1924
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001925 cname_restart:
1926 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
1927 {
1928 int localise = 0;
1929
1930 /* See if a putative address is on the network from which we recieved
1931 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001932 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001933 {
1934 struct crec *save = crecp;
1935 do {
1936 if ((crecp->flags & F_HOSTS) &&
1937 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1938 {
1939 localise = 1;
1940 break;
1941 }
1942 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1943 crecp = save;
1944 }
Simon Kelley824202e2014-01-23 20:59:46 +00001945
Simon Kelley0744ca62014-01-25 16:40:15 +00001946 /* If the client asked for DNSSEC and we can't provide RRSIGs, either
1947 because we've not doing DNSSEC or the cached answer is signed by negative,
1948 don't answer from the cache, forward instead. */
1949 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley824202e2014-01-23 20:59:46 +00001950 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001951 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1952 crecp = NULL;
1953#ifdef HAVE_DNSSEC
1954 else if (crecp->flags & F_DNSSECOK)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001955 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001956 /* We're returning validated data, need to return the RRSIG too. */
1957
1958 int sigtype = type;
1959 /* The signature may have expired even though the data is still in cache,
1960 forward instead of answering from cache if so. */
1961 int gotsig = 0;
1962
1963 if (crecp->flags & F_CNAME)
1964 sigtype = T_CNAME;
1965
1966 crecp = NULL;
1967 while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001968 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001969 if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
1970 {
1971 char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
1972 gotsig = 1;
1973
1974 if (!dryrun &&
1975 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1976 crecp->ttd - now, &nameoffset,
1977 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
1978 anscount++;
1979 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001980 }
Simon Kelley0744ca62014-01-25 16:40:15 +00001981 /* Need to re-run original cache search */
1982 crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001983 }
Simon Kelley824202e2014-01-23 20:59:46 +00001984#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001985 }
1986
Simon Kelley824202e2014-01-23 20:59:46 +00001987 if (crecp)
1988 do
1989 {
1990 /* don't answer wildcard queries with data not from /etc/hosts
1991 or DHCP leases */
1992 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1993 break;
1994
1995 if (!(crecp->flags & F_DNSSECOK))
1996 sec_data = 0;
1997
1998 if (crecp->flags & F_CNAME)
1999 {
2000 char *cname_target = cache_get_cname_target(crecp);
2001
2002 if (!dryrun)
2003 {
2004 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2005 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2006 crec_ttl(crecp, now), &nameoffset,
2007 T_CNAME, C_IN, "d", cname_target))
2008 anscount++;
2009 }
2010
2011 strcpy(name, cname_target);
2012 /* check if target interface_name */
2013 if (crecp->addr.cname.uid == -1)
2014 goto intname_restart;
2015 else
2016 goto cname_restart;
2017 }
2018
2019 if (crecp->flags & F_NEG)
2020 {
2021 /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
2022 is cached and the client wants DNSSEC, forward rather than answering from the cache */
2023 if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
2024 {
2025 ans = 1;
2026 auth = 0;
2027 if (crecp->flags & F_NXDOMAIN)
2028 nxdomain = 1;
2029 if (!dryrun)
2030 log_query(crecp->flags, name, NULL, NULL);
2031 }
2032 }
2033 else
2034 {
2035 /* If we are returning local answers depending on network,
2036 filter here. */
2037 if (localise &&
2038 (crecp->flags & F_HOSTS) &&
2039 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
2040 continue;
2041
2042 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
2043 auth = 0;
2044
2045 ans = 1;
2046 if (!dryrun)
2047 {
2048 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
2049 record_source(crecp->uid));
2050
2051 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2052 crec_ttl(crecp, now), NULL, type, C_IN,
2053 type == T_A ? "4" : "6", &crecp->addr))
2054 anscount++;
2055 }
2056 }
2057 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002058 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002059 else if (is_name_synthetic(flag, name, &addr))
2060 {
2061 ans = 1;
2062 if (!dryrun)
2063 {
2064 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
2065 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2066 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
2067 anscount++;
2068 }
2069 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002070 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002071
2072 if (qtype == T_CNAME || qtype == T_ANY)
2073 {
2074 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +00002075 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002076 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00002077 if (!(crecp->flags & F_DNSSECOK))
2078 sec_data = 0;
2079
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002080 ans = 1;
2081 if (!dryrun)
2082 {
2083 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2084 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2085 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01002086 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002087 anscount++;
2088 }
2089 }
2090 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002091
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002092 if (qtype == T_MX || qtype == T_ANY)
2093 {
2094 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00002095 for (rec = daemon->mxnames; rec; rec = rec->next)
2096 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002097 {
2098 ans = found = 1;
2099 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002100 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002101 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002102 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00002103 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2104 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
2105 {
2106 anscount++;
2107 if (rec->target)
2108 rec->offset = offset;
2109 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002110 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002111 }
2112
Simon Kelley28866e92011-02-14 20:19:14 +00002113 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002114 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
2115 {
2116 ans = 1;
2117 if (!dryrun)
2118 {
Simon Kelley28866e92011-02-14 20:19:14 +00002119 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002120 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
2121 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00002122 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002123 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002124 }
2125 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002126 }
2127
2128 if (qtype == T_SRV || qtype == T_ANY)
2129 {
2130 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00002131 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
2132
Simon Kelley0a852542005-03-23 20:28:59 +00002133 for (rec = daemon->mxnames; rec; rec = rec->next)
2134 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002135 {
2136 found = ans = 1;
2137 if (!dryrun)
2138 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002139 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002140 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002141 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00002142 &offset, T_SRV, C_IN, "sssd",
2143 rec->priority, rec->weight, rec->srvport, rec->target))
2144 {
2145 anscount++;
2146 if (rec->target)
2147 rec->offset = offset;
2148 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002149 }
Simon Kelley28866e92011-02-14 20:19:14 +00002150
2151 /* unlink first SRV record found */
2152 if (!move)
2153 {
2154 move = rec;
2155 *up = rec->next;
2156 }
2157 else
2158 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002159 }
Simon Kelley28866e92011-02-14 20:19:14 +00002160 else
2161 up = &rec->next;
2162
2163 /* put first SRV record back at the end. */
2164 if (move)
2165 {
2166 *up = move;
2167 move->next = NULL;
2168 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002169
Simon Kelley28866e92011-02-14 20:19:14 +00002170 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002171 {
2172 ans = 1;
2173 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002174 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002175 }
2176 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002177
2178 if (qtype == T_NAPTR || qtype == T_ANY)
2179 {
2180 struct naptr *na;
2181 for (na = daemon->naptr; na; na = na->next)
2182 if (hostname_isequal(name, na->name))
2183 {
2184 ans = 1;
2185 if (!dryrun)
2186 {
Simon Kelley28866e92011-02-14 20:19:14 +00002187 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01002188 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2189 NULL, T_NAPTR, C_IN, "sszzzd",
2190 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
2191 anscount++;
2192 }
2193 }
2194 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002195
2196 if (qtype == T_MAILB)
2197 ans = 1, nxdomain = 1;
2198
Simon Kelley28866e92011-02-14 20:19:14 +00002199 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002200 {
2201 ans = 1;
2202 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002203 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002204 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002205 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002206
2207 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002208 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002209 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002210
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002211 if (dryrun)
2212 {
2213 dryrun = 0;
2214 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002215 }
2216
Simon Kelley0a852542005-03-23 20:28:59 +00002217 /* create an additional data section, for stuff in SRV and MX record replies. */
2218 for (rec = daemon->mxnames; rec; rec = rec->next)
2219 if (rec->offset != 0)
2220 {
2221 /* squash dupes */
2222 struct mx_srv_record *tmp;
2223 for (tmp = rec->next; tmp; tmp = tmp->next)
2224 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2225 tmp->offset = 0;
2226
2227 crecp = NULL;
2228 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2229 {
Simon Kelley0a852542005-03-23 20:28:59 +00002230#ifdef HAVE_IPV6
2231 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2232#else
2233 int type = T_A;
2234#endif
2235 if (crecp->flags & F_NEG)
2236 continue;
2237
Simon Kelley9009d742008-11-14 20:04:27 +00002238 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2239 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002240 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2241 addncount++;
2242 }
2243 }
2244
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002245 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002246 /* clear authoritative and truncated flags, set QR flag */
2247 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2248 /* set RA flag */
2249 header->hb4 |= HB4_RA;
2250
2251 /* authoritive - only hosts and DHCP derived names. */
2252 if (auth)
2253 header->hb3 |= HB3_AA;
2254
2255 /* truncation */
2256 if (trunc)
2257 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002258
Simon Kelley45cca582013-10-15 10:20:13 +01002259 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002260 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002261 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002262 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002263 header->ancount = htons(anscount);
2264 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002265 header->arcount = htons(addncount);
Simon Kelleya25720a2014-01-14 23:13:55 +00002266
2267 header->hb4 &= ~HB4_AD;
2268 len = ansp - (unsigned char *)header;
2269
2270 if (have_pseudoheader)
2271 {
2272 len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
2273 if (sec_reqd && sec_data)
2274 header->hb4 |= HB4_AD;
2275
2276 }
2277
Simon Kelley7c286122014-01-27 21:38:11 +00002278 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002279}
2280