blob: 3f13369d27b91afb5aa43830a77e68f83b7077b0 [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 Kelley5107ace2014-02-23 10:48:32 +0000340unsigned 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 {
Simon Kelley613ad152014-02-25 23:02:28 +0000604 if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000605 match = 1;
606#ifdef HAVE_IPV6
607 else
Simon Kelley613ad152014-02-25 23:02:28 +0000608 if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000609 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
Simon Kelleyd1fbb772014-03-01 20:08:58 +0000920 if (*doctored && secure)
921 return 0;
Simon Kelley6938f342014-01-26 22:47:39 +0000922#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 {
Simon Kelley1fbe4d22014-03-01 20:03:47 +0000930 int found = 0, cname_count = CNAME_CHAIN;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100931 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 {
Simon Kelleyd1fbb772014-03-01 20:08:58 +0000991 if (!cname_count-- || secure)
992 return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100993 goto cname_loop;
994 }
995
Simon Kelley0435d042014-01-08 18:22:37 +0000996 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100997 found = 1;
998 }
999
1000 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +00001001 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +00001002 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001003 }
1004 }
1005
Simon Kelley28866e92011-02-14 20:19:14 +00001006 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001007 {
1008 if (!searched_soa)
1009 {
1010 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001011 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001012 }
1013 if (ttl)
Simon Kelley0435d042014-01-08 18:22:37 +00001014 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001015 }
1016 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001017 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001018 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001019 /* everything other than PTR */
1020 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001021 int addrlen;
1022
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001023 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001024 {
1025 addrlen = INADDRSZ;
1026 flags |= F_IPV4;
1027 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001028#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001029 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001030 {
1031 addrlen = IN6ADDRSZ;
1032 flags |= F_IPV6;
1033 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001034#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001035 else
1036 continue;
1037
Simon Kelley45cca582013-10-15 10:20:13 +01001038 cname_loop1:
1039 if (!(p1 = skip_questions(header, qlen)))
1040 return 0;
1041
1042 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001043 {
Simon Kelley45cca582013-10-15 10:20:13 +01001044 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
1045 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001046
Simon Kelley45cca582013-10-15 10:20:13 +01001047 GETSHORT(aqtype, p1);
1048 GETSHORT(aqclass, p1);
1049 GETLONG(attl, p1);
1050 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001051 {
Simon Kelley45cca582013-10-15 10:20:13 +01001052 (p1) -= 4;
1053 PUTLONG(daemon->max_ttl, p1);
1054 }
1055 GETSHORT(ardlen, p1);
1056 endrr = p1+ardlen;
1057
1058 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
1059 {
1060 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001061 {
Simon Kelley45cca582013-10-15 10:20:13 +01001062 if (!cname_count--)
1063 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +00001064 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001065 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001066 {
Simon Kelley45cca582013-10-15 10:20:13 +01001067 newc->addr.cname.target.cache = NULL;
1068 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001069 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001070 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001071 cpp->addr.cname.uid = newc->uid;
1072 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001073 }
Simon Kelley45cca582013-10-15 10:20:13 +01001074
1075 cpp = newc;
1076 if (attl < cttl)
1077 cttl = attl;
1078
1079 if (!extract_name(header, qlen, &p1, name, 1, 0))
1080 return 0;
1081 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001082 }
Simon Kelley45cca582013-10-15 10:20:13 +01001083 else if (!(flags & F_NXDOMAIN))
1084 {
1085 found = 1;
1086
1087 /* copy address into aligned storage */
1088 if (!CHECK_LEN(header, p1, qlen, addrlen))
1089 return 0; /* bad packet */
1090 memcpy(&addr, p1, addrlen);
1091
1092 /* check for returned address in private space */
1093 if (check_rebind &&
1094 (flags & F_IPV4) &&
1095 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
1096 return 1;
1097
1098#ifdef HAVE_IPSET
1099 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
1100 {
1101 ipsets_cur = ipsets;
1102 while (*ipsets_cur)
1103 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
1104 }
1105#endif
1106
Simon Kelley0435d042014-01-08 18:22:37 +00001107 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001108 if (newc && cpp)
1109 {
1110 cpp->addr.cname.target.cache = newc;
1111 cpp->addr.cname.uid = newc->uid;
1112 }
1113 cpp = NULL;
1114 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001115 }
Simon Kelley45cca582013-10-15 10:20:13 +01001116
1117 p1 = endrr;
1118 if (!CHECK_LEN(header, p1, qlen, 0))
1119 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001120 }
1121
Simon Kelley28866e92011-02-14 20:19:14 +00001122 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001123 {
1124 if (!searched_soa)
1125 {
1126 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001127 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001128 }
1129 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001130 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001131 if (ttl || cpp)
1132 {
Simon Kelley0435d042014-01-08 18:22:37 +00001133 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
Simon Kelley26128d22004-11-14 16:43:54 +00001134 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001135 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001136 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001137 cpp->addr.cname.uid = newc->uid;
1138 }
1139 }
1140 }
1141 }
1142 }
1143
Simon Kelley1023dcb2012-04-09 18:00:08 +01001144 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +01001145 Don't cache replies from non-recursive nameservers, since we may get a
1146 reply containing a CNAME but not its target, even though the target
1147 does exist. */
1148 if (!(header->hb3 & HB3_TC) &&
1149 !(header->hb4 & HB4_CD) &&
1150 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +00001151 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +00001152 cache_end_insert();
1153
1154 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001155}
1156
1157/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001158 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +00001159unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001160{
1161 unsigned char *p = (unsigned char *)(header+1);
1162 int qtype, qclass;
1163
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001164 if (typep)
1165 *typep = 0;
1166
Simon Kelley572b41e2011-02-18 18:11:18 +00001167 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001168 return 0; /* must be exactly one query. */
1169
Simon Kelley9009d742008-11-14 20:04:27 +00001170 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001171 return 0; /* bad packet */
1172
1173 GETSHORT(qtype, p);
1174 GETSHORT(qclass, p);
1175
Simon Kelley0a852542005-03-23 20:28:59 +00001176 if (typep)
1177 *typep = qtype;
1178
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001179 if (qclass == C_IN)
1180 {
1181 if (qtype == T_A)
1182 return F_IPV4;
1183 if (qtype == T_AAAA)
1184 return F_IPV6;
1185 if (qtype == T_ANY)
1186 return F_IPV4 | F_IPV6;
1187 }
1188
1189 return F_QUERY;
1190}
1191
1192
Simon Kelley572b41e2011-02-18 18:11:18 +00001193size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001194 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001195{
1196 unsigned char *p = skip_questions(header, qlen);
1197
Simon Kelley572b41e2011-02-18 18:11:18 +00001198 /* clear authoritative and truncated flags, set QR flag */
1199 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1200 /* set RA flag */
1201 header->hb4 |= HB4_RA;
1202
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001203 header->nscount = htons(0);
1204 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001205 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001206 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001207 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001208 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001209 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001210 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001211 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001212 else if (p && flags == F_IPV4)
1213 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001214 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001215 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001216 header->hb3 |= HB3_AA;
1217 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 +00001218 }
1219#ifdef HAVE_IPV6
1220 else if (p && flags == F_IPV6)
1221 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001222 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001223 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001224 header->hb3 |= HB3_AA;
1225 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 +00001226 }
1227#endif
1228 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001229 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001230
1231 return p - (unsigned char *)header;
1232}
Simon Kelley36717ee2004-09-20 19:20:58 +01001233
1234/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001235int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001236{
1237 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001238 struct mx_srv_record *mx;
1239 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001240 struct interface_name *intr;
1241 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001242 struct naptr *naptr;
1243
Simon Kelley12fae492014-02-04 22:03:06 +00001244 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +00001245 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +01001246 return 1;
1247
Simon Kelley7de060b2011-08-26 17:24:52 +01001248 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1249 if (hostname_isequal(name, naptr->name))
1250 return 1;
1251
1252 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001253 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001254 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001255
Simon Kelley0a852542005-03-23 20:28:59 +00001256 for (txt = daemon->txt; txt; txt = txt->next)
1257 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001258 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001259
1260 for (intr = daemon->int_names; intr; intr = intr->next)
1261 if (hostname_isequal(name, intr->name))
1262 return 1;
1263
1264 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1265 if (hostname_isequal(name, ptr->name))
1266 return 1;
1267
Simon Kelley36717ee2004-09-20 19:20:58 +01001268 return 0;
1269}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001270
1271/* Is the packet a reply with the answer address equal to addr?
1272 If so mung is into an NXDOMAIN reply and also put that information
1273 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001274int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001275 struct bogus_addr *baddr, time_t now)
1276{
1277 unsigned char *p;
1278 int i, qtype, qclass, rdlen;
1279 unsigned long ttl;
1280 struct bogus_addr *baddrp;
1281
1282 /* skip over questions */
1283 if (!(p = skip_questions(header, qlen)))
1284 return 0; /* bad packet */
1285
Simon Kelley5aabfc72007-08-29 11:24:47 +01001286 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001287 {
Simon Kelley9009d742008-11-14 20:04:27 +00001288 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001289 return 0; /* bad packet */
1290
1291 GETSHORT(qtype, p);
1292 GETSHORT(qclass, p);
1293 GETLONG(ttl, p);
1294 GETSHORT(rdlen, p);
1295
1296 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001297 {
1298 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1299 return 0;
1300
1301 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1302 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1303 {
1304 /* Found a bogus address. Insert that info here, since there no SOA record
1305 to get the ttl from in the normal processing */
1306 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001307 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001308 cache_end_insert();
1309
1310 return 1;
1311 }
1312 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001313
Simon Kelley9009d742008-11-14 20:04:27 +00001314 if (!ADD_RDLEN(header, p, qlen, rdlen))
1315 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001316 }
1317
1318 return 0;
1319}
1320
Simon Kelleyb75e9362012-12-07 11:50:41 +00001321int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001322 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001323{
1324 va_list ap;
1325 unsigned char *sav, *p = *pp;
1326 int j;
1327 unsigned short usval;
1328 long lval;
1329 char *sval;
1330
1331 if (truncp && *truncp)
1332 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001333
1334 va_start(ap, format); /* make ap point to 1st unamed argument */
1335
Simon Kelleyb75e9362012-12-07 11:50:41 +00001336 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001337 {
1338 PUTSHORT(nameoffset | 0xc000, p);
1339 }
1340 else
1341 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001342 char *name = va_arg(ap, char *);
1343 if (name)
1344 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001345 if (nameoffset < 0)
1346 {
1347 PUTSHORT(-nameoffset | 0xc000, p);
1348 }
1349 else
1350 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001351 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001352
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001353 PUTSHORT(type, p);
1354 PUTSHORT(class, p);
1355 PUTLONG(ttl, p); /* TTL */
1356
1357 sav = p; /* Save pointer to RDLength field */
1358 PUTSHORT(0, p); /* Placeholder RDLength */
1359
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001360 for (; *format; format++)
1361 switch (*format)
1362 {
1363#ifdef HAVE_IPV6
1364 case '6':
1365 sval = va_arg(ap, char *);
1366 memcpy(p, sval, IN6ADDRSZ);
1367 p += IN6ADDRSZ;
1368 break;
1369#endif
1370
1371 case '4':
1372 sval = va_arg(ap, char *);
1373 memcpy(p, sval, INADDRSZ);
1374 p += INADDRSZ;
1375 break;
1376
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001377 case 'b':
1378 usval = va_arg(ap, int);
1379 *p++ = usval;
1380 break;
1381
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001382 case 's':
1383 usval = va_arg(ap, int);
1384 PUTSHORT(usval, p);
1385 break;
1386
1387 case 'l':
1388 lval = va_arg(ap, long);
1389 PUTLONG(lval, p);
1390 break;
1391
1392 case 'd':
1393 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001394 if (offset)
1395 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001396 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001397 *p++ = 0;
1398 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001399
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001400 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001401 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001402 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001403 if (usval != 0)
1404 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001405 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001406 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001407
1408 case 'z':
1409 sval = va_arg(ap, char *);
1410 usval = sval ? strlen(sval) : 0;
1411 if (usval > 255)
1412 usval = 255;
1413 *p++ = (unsigned char)usval;
1414 memcpy(p, sval, usval);
1415 p += usval;
1416 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001417 }
1418
1419 va_end(ap); /* clean up variable argument pointer */
1420
1421 j = p - sav - 2;
1422 PUTSHORT(j, sav); /* Now, store real RDLength */
1423
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001424 /* check for overflow of buffer */
1425 if (limit && ((unsigned char *)limit - p) < 0)
1426 {
1427 if (truncp)
1428 *truncp = 1;
1429 return 0;
1430 }
1431
1432 *pp = p;
1433 return 1;
1434}
1435
Simon Kelley9009d742008-11-14 20:04:27 +00001436static unsigned long crec_ttl(struct crec *crecp, time_t now)
1437{
1438 /* Return 0 ttl for DHCP entries, which might change
1439 before the lease expires. */
1440
1441 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1442 return daemon->local_ttl;
1443
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001444 /* Return the Max TTL value if it is lower then the actual TTL */
1445 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1446 return crecp->ttd - now;
1447 else
1448 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001449}
1450
1451
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001452/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001453size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001454 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelley613ad152014-02-25 23:02:28 +00001455 time_t now, int *ad_reqd, int *do_bit)
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 Kelleye243c072014-02-06 18:14:09 +00001471 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001472 if (header->hb4 & HB4_CD)
1473 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001474
1475 /* RFC 6840 5.7 */
1476 *ad_reqd = header->hb4 & HB4_AD;
Simon Kelley613ad152014-02-25 23:02:28 +00001477 *do_bit = 0;
1478
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001479 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1480 partial replies, so we have to do a dry run to see if we can answer
1481 the query. We check to see if the do bit is set, if so we always
1482 forward rather than answering from the cache, which doesn't include
Simon Kelleya25720a2014-01-14 23:13:55 +00001483 security information, unless we're in DNSSEC validation mode. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001484
Simon Kelley832af0b2007-01-21 20:01:28 +00001485 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001486 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001487 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001488 unsigned char *psave = pheader;
1489
Simon Kelleya25720a2014-01-14 23:13:55 +00001490 have_pseudoheader = 1;
1491
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001492 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001493 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001494 GETSHORT(flags, pheader);
1495
Simon Kelley613ad152014-02-25 23:02:28 +00001496 if ((sec_reqd = flags & 0x8000))
1497 *do_bit = 1;/* do bit */
Simon Kelley83349b82014-02-10 21:02:01 +00001498 *ad_reqd = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001499
1500 /* If our client is advertising a larger UDP packet size
1501 than we allow, trim it so that we don't get an overlarge
1502 response from upstream */
1503
Simon Kelley832af0b2007-01-21 20:01:28 +00001504 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001505 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001506
1507 dryrun = 1;
1508 }
1509
Simon Kelley572b41e2011-02-18 18:11:18 +00001510 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001511 return 0;
1512
Simon Kelley0a852542005-03-23 20:28:59 +00001513 for (rec = daemon->mxnames; rec; rec = rec->next)
1514 rec->offset = 0;
1515
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001516 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001517 /* determine end of question section (we put answers there) */
1518 if (!(ansp = skip_questions(header, qlen)))
1519 return 0; /* bad packet */
1520
1521 /* now process each question, answers go in RRs after the question */
1522 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001523
Simon Kelley5aabfc72007-08-29 11:24:47 +01001524 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001525 {
1526 /* save pointer to name for copying into answers */
1527 nameoffset = p - (unsigned char *)header;
1528
1529 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001530 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001531 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001532
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001533 GETSHORT(qtype, p);
1534 GETSHORT(qclass, p);
1535
1536 ans = 0; /* have we answered this question */
1537
Simon Kelley0a852542005-03-23 20:28:59 +00001538 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001539 {
Simon Kelley0a852542005-03-23 20:28:59 +00001540 struct txt_record *t;
1541 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001542 {
Simon Kelley0a852542005-03-23 20:28:59 +00001543 if (t->class == qclass && hostname_isequal(name, t->name))
1544 {
1545 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001546 if (!dryrun)
1547 {
Simon Kelley28866e92011-02-14 20:19:14 +00001548 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleye17fb622006-01-14 20:33:46 +00001549 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1550 daemon->local_ttl, NULL,
1551 T_TXT, t->class, "t", t->len, t->txt))
1552 anscount++;
1553
1554 }
Simon Kelley0a852542005-03-23 20:28:59 +00001555 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001556 }
Simon Kelley0a852542005-03-23 20:28:59 +00001557 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001558
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001559#ifdef HAVE_DNSSEC
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001560 if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001561 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001562 int gotone = 0;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001563 struct blockdata *keydata;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001564
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001565 /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001566 if (sec_reqd)
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001567 {
Simon Kelley5f938532014-02-03 16:44:32 +00001568 crecp = NULL;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001569 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1570 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
1571 break;
1572 }
1573
1574 if (!sec_reqd || crecp)
1575 {
1576 if (qtype == T_DS)
1577 {
1578 crecp = NULL;
1579 while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
1580 if (crecp->uid == qclass)
1581 {
Simon Kelleyb8eac192014-02-27 14:30:03 +00001582 gotone = 1;
1583 if (!dryrun)
1584 {
1585 if (crecp->flags & F_NEG)
1586 {
1587 if (crecp->flags & F_NXDOMAIN)
1588 nxdomain = 1;
1589 log_query(F_UPSTREAM, name, NULL, "secure no DS");
1590 }
1591 else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
1592 {
1593 struct all_addr a;
1594 a.addr.keytag = crecp->addr.ds.keytag;
1595 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
1596 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1597 crec_ttl(crecp, now), &nameoffset,
1598 T_DS, qclass, "sbbt",
1599 crecp->addr.ds.keytag, crecp->addr.ds.algo,
1600 crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
1601 anscount++;
1602
1603 }
1604 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001605 }
1606 }
1607 else /* DNSKEY */
1608 {
1609 crecp = NULL;
1610 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
1611 if (crecp->uid == qclass)
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001612 {
Simon Kelleyee415862014-02-11 11:07:22 +00001613 gotone = 1;
1614 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
1615 {
1616 struct all_addr a;
1617 a.addr.keytag = crecp->addr.key.keytag;
1618 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
1619 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1620 crec_ttl(crecp, now), &nameoffset,
1621 T_DNSKEY, qclass, "sbbt",
1622 crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
1623 anscount++;
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001624 }
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001625 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001626 }
Simon Kelley5f938532014-02-03 16:44:32 +00001627 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001628
Simon Kelley5f938532014-02-03 16:44:32 +00001629 /* Now do RRSIGs */
1630 if (gotone)
1631 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001632 ans = 1;
1633 auth = 0;
1634 if (!dryrun && sec_reqd)
1635 {
1636 crecp = NULL;
1637 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1638 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
1639 (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
1640 {
Simon Kelley5f938532014-02-03 16:44:32 +00001641 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1642 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001643 T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
1644 anscount++;
1645 }
1646 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001647 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001648 }
1649#endif
1650
Simon Kelley0a852542005-03-23 20:28:59 +00001651 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001652 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001653 struct txt_record *t;
1654
1655 for (t = daemon->rr; t; t = t->next)
1656 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1657 {
1658 ans = 1;
1659 if (!dryrun)
1660 {
1661 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1662 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1663 daemon->local_ttl, NULL,
1664 t->class, C_IN, "t", t->len, t->txt))
1665 anscount ++;
1666 }
1667 }
1668
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001669 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001670 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001671 /* see if it's w.z.y.z.in-addr.arpa format */
1672 int is_arpa = in_arpa_name_2_addr(name, &addr);
1673 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001674 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001675
1676 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1677 if (hostname_isequal(name, ptr->name))
1678 break;
1679
Simon Kelleyf2621c72007-04-29 19:47:21 +01001680 if (is_arpa == F_IPV4)
1681 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001682 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001683 struct addrlist *addrlist;
1684
Simon Kelley376d48c2013-11-13 13:04:30 +00001685 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1686 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001687 break;
1688
1689 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001690 break;
1691 else
1692 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1693 intr = intr->next;
1694 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001695#ifdef HAVE_IPV6
1696 else if (is_arpa == F_IPV6)
1697 for (intr = daemon->int_names; intr; intr = intr->next)
1698 {
1699 struct addrlist *addrlist;
1700
Simon Kelley376d48c2013-11-13 13:04:30 +00001701 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1702 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001703 break;
1704
1705 if (addrlist)
1706 break;
1707 else
1708 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1709 intr = intr->next;
1710 }
1711#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001712
1713 if (intr)
1714 {
1715 ans = 1;
1716 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001717 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001718 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001719 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1720 daemon->local_ttl, NULL,
1721 T_PTR, C_IN, "d", intr->name))
1722 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001723 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001724 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001725 else if (ptr)
1726 {
1727 ans = 1;
1728 if (!dryrun)
1729 {
Simon Kelley28866e92011-02-14 20:19:14 +00001730 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001731 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001732 if (hostname_isequal(name, ptr->name) &&
1733 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1734 daemon->local_ttl, NULL,
1735 T_PTR, C_IN, "d", ptr->ptr))
1736 anscount++;
1737
Simon Kelley832af0b2007-01-21 20:01:28 +00001738 }
1739 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001740 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001741 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001742 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001743 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001744 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1745 crecp = NULL;
1746#ifdef HAVE_DNSSEC
1747 else if (crecp->flags & F_DNSSECOK)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001748 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001749 int gotsig = 0;
Simon Kelley12fae492014-02-04 22:03:06 +00001750 struct crec *rr_crec = NULL;
1751
1752 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001753 {
Simon Kelley12fae492014-02-04 22:03:06 +00001754 if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001755 {
Simon Kelley12fae492014-02-04 22:03:06 +00001756 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001757 gotsig = 1;
1758
1759 if (!dryrun &&
1760 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001761 rr_crec->ttd - now, &nameoffset,
Simon Kelley0744ca62014-01-25 16:40:15 +00001762 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
1763 anscount++;
1764 }
1765 }
Simon Kelley12fae492014-02-04 22:03:06 +00001766
1767 if (!gotsig)
1768 crecp = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001769 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001770#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001771 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001772
1773 if (crecp)
1774 {
1775 do
1776 {
1777 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1778 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1779 continue;
1780
1781 if (!(crecp->flags & F_DNSSECOK))
1782 sec_data = 0;
1783
1784 if (crecp->flags & F_NEG)
1785 {
1786 ans = 1;
1787 auth = 0;
1788 if (crecp->flags & F_NXDOMAIN)
1789 nxdomain = 1;
1790 if (!dryrun)
1791 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1792 }
1793 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
1794 {
1795 ans = 1;
1796 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1797 auth = 0;
1798 if (!dryrun)
1799 {
1800 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1801 record_source(crecp->uid));
1802
1803 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1804 crec_ttl(crecp, now), NULL,
1805 T_PTR, C_IN, "d", cache_get_name(crecp)))
1806 anscount++;
1807 }
1808 }
1809 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1810 }
1811 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001812 else if (is_rev_synth(is_arpa, &addr, name))
1813 {
1814 ans = 1;
1815 if (!dryrun)
1816 {
1817 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1818
1819 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1820 daemon->local_ttl, NULL,
1821 T_PTR, C_IN, "d", name))
1822 anscount++;
1823 }
1824 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001825 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001826 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001827 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001828 {
1829 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1830 ans = 1;
1831 nxdomain = 1;
1832 if (!dryrun)
1833 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001834 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001835 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001836 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001837
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001838 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1839 {
1840 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001841 struct interface_name *intr;
1842
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001843 if (flag == F_IPV6)
1844#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001845 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001846#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001847 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001848#endif
1849
1850 if (qtype != type && qtype != T_ANY)
1851 continue;
1852
Simon Kelley316e2732010-01-22 20:16:09 +00001853 /* Check for "A for A" queries; be rather conservative
1854 about what looks like dotted-quad. */
1855 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001856 {
Simon Kelley316e2732010-01-22 20:16:09 +00001857 char *cp;
1858 unsigned int i, a;
1859 int x;
1860
1861 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001862 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001863 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001864 {
1865 i = 5;
1866 break;
1867 }
1868
1869 a = (a << 8) + x;
1870
1871 if (*cp == '.')
1872 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001873 }
Simon Kelley316e2732010-01-22 20:16:09 +00001874
1875 if (i == 4)
1876 {
1877 ans = 1;
1878 if (!dryrun)
1879 {
1880 addr.addr.addr4.s_addr = htonl(a);
1881 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1882 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1883 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1884 anscount++;
1885 }
1886 continue;
1887 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001888 }
1889
Simon Kelleyf2621c72007-04-29 19:47:21 +01001890 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001891 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001892 for (intr = daemon->int_names; intr; intr = intr->next)
1893 if (hostname_isequal(name, intr->name))
1894 break;
1895
1896 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001897 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001898 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001899 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001900
Simon Kelley115ac3e2013-05-20 11:28:32 +01001901 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001902
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001903 for (intr = daemon->int_names; intr; intr = intr->next)
1904 if (hostname_isequal(name, intr->name))
1905 {
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001906 ans = 1;
1907 if (!dryrun)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001908 {
Simon Kelley376d48c2013-11-13 13:04:30 +00001909
1910 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1911#ifdef HAVE_IPV6
1912 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
1913#endif
1914 {
1915 gotit = 1;
1916 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1917 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1918 daemon->local_ttl, NULL, type, C_IN,
1919 type == T_A ? "4" : "6", &addrlist->addr))
1920 anscount++;
1921 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001922 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001923 }
1924
1925 if (!dryrun && !gotit)
1926 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1927
Simon Kelley115ac3e2013-05-20 11:28:32 +01001928 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001929 }
1930
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001931 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00001932 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001933 {
1934 int localise = 0;
1935
1936 /* See if a putative address is on the network from which we recieved
1937 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001938 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001939 {
1940 struct crec *save = crecp;
1941 do {
1942 if ((crecp->flags & F_HOSTS) &&
1943 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1944 {
1945 localise = 1;
1946 break;
1947 }
1948 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1949 crecp = save;
1950 }
Simon Kelley824202e2014-01-23 20:59:46 +00001951
Simon Kelley0744ca62014-01-25 16:40:15 +00001952 /* If the client asked for DNSSEC and we can't provide RRSIGs, either
1953 because we've not doing DNSSEC or the cached answer is signed by negative,
1954 don't answer from the cache, forward instead. */
1955 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley824202e2014-01-23 20:59:46 +00001956 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001957 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1958 crecp = NULL;
1959#ifdef HAVE_DNSSEC
1960 else if (crecp->flags & F_DNSSECOK)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001961 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001962 /* We're returning validated data, need to return the RRSIG too. */
Simon Kelley12fae492014-02-04 22:03:06 +00001963 struct crec *rr_crec = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001964 int sigtype = type;
1965 /* The signature may have expired even though the data is still in cache,
1966 forward instead of answering from cache if so. */
1967 int gotsig = 0;
1968
1969 if (crecp->flags & F_CNAME)
1970 sigtype = T_CNAME;
1971
Simon Kelley12fae492014-02-04 22:03:06 +00001972 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001973 {
Simon Kelley12fae492014-02-04 22:03:06 +00001974 if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001975 {
Simon Kelley12fae492014-02-04 22:03:06 +00001976 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001977 gotsig = 1;
1978
1979 if (!dryrun &&
1980 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001981 rr_crec->ttd - now, &nameoffset,
1982 T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
Simon Kelley0744ca62014-01-25 16:40:15 +00001983 anscount++;
1984 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001985 }
Simon Kelley12fae492014-02-04 22:03:06 +00001986
1987 if (!gotsig)
1988 crecp = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001989 }
Simon Kelley824202e2014-01-23 20:59:46 +00001990#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001991 }
1992
Simon Kelley824202e2014-01-23 20:59:46 +00001993 if (crecp)
1994 do
1995 {
1996 /* don't answer wildcard queries with data not from /etc/hosts
1997 or DHCP leases */
1998 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1999 break;
2000
2001 if (!(crecp->flags & F_DNSSECOK))
2002 sec_data = 0;
2003
2004 if (crecp->flags & F_CNAME)
2005 {
2006 char *cname_target = cache_get_cname_target(crecp);
2007
2008 if (!dryrun)
2009 {
2010 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2011 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2012 crec_ttl(crecp, now), &nameoffset,
2013 T_CNAME, C_IN, "d", cname_target))
2014 anscount++;
2015 }
2016
2017 strcpy(name, cname_target);
2018 /* check if target interface_name */
2019 if (crecp->addr.cname.uid == -1)
2020 goto intname_restart;
2021 else
2022 goto cname_restart;
2023 }
2024
2025 if (crecp->flags & F_NEG)
2026 {
2027 /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
2028 is cached and the client wants DNSSEC, forward rather than answering from the cache */
2029 if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
2030 {
2031 ans = 1;
2032 auth = 0;
2033 if (crecp->flags & F_NXDOMAIN)
2034 nxdomain = 1;
2035 if (!dryrun)
2036 log_query(crecp->flags, name, NULL, NULL);
2037 }
2038 }
2039 else
2040 {
2041 /* If we are returning local answers depending on network,
2042 filter here. */
2043 if (localise &&
2044 (crecp->flags & F_HOSTS) &&
2045 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
2046 continue;
2047
2048 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
2049 auth = 0;
2050
2051 ans = 1;
2052 if (!dryrun)
2053 {
2054 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
2055 record_source(crecp->uid));
2056
2057 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2058 crec_ttl(crecp, now), NULL, type, C_IN,
2059 type == T_A ? "4" : "6", &crecp->addr))
2060 anscount++;
2061 }
2062 }
2063 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002064 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002065 else if (is_name_synthetic(flag, name, &addr))
2066 {
2067 ans = 1;
2068 if (!dryrun)
2069 {
2070 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
2071 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2072 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
2073 anscount++;
2074 }
2075 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002076 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002077
2078 if (qtype == T_CNAME || qtype == T_ANY)
2079 {
2080 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002081 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002082 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00002083 if (!(crecp->flags & F_DNSSECOK))
2084 sec_data = 0;
2085
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002086 ans = 1;
2087 if (!dryrun)
2088 {
2089 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2090 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2091 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01002092 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002093 anscount++;
2094 }
2095 }
2096 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002097
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002098 if (qtype == T_MX || qtype == T_ANY)
2099 {
2100 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00002101 for (rec = daemon->mxnames; rec; rec = rec->next)
2102 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002103 {
2104 ans = found = 1;
2105 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002106 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002107 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002108 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00002109 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2110 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
2111 {
2112 anscount++;
2113 if (rec->target)
2114 rec->offset = offset;
2115 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002116 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002117 }
2118
Simon Kelley28866e92011-02-14 20:19:14 +00002119 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002120 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002121 {
2122 ans = 1;
2123 if (!dryrun)
2124 {
Simon Kelley28866e92011-02-14 20:19:14 +00002125 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002126 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
2127 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00002128 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002129 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002130 }
2131 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002132 }
2133
2134 if (qtype == T_SRV || qtype == T_ANY)
2135 {
2136 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00002137 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
2138
Simon Kelley0a852542005-03-23 20:28:59 +00002139 for (rec = daemon->mxnames; rec; rec = rec->next)
2140 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002141 {
2142 found = ans = 1;
2143 if (!dryrun)
2144 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002145 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002146 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002147 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00002148 &offset, T_SRV, C_IN, "sssd",
2149 rec->priority, rec->weight, rec->srvport, rec->target))
2150 {
2151 anscount++;
2152 if (rec->target)
2153 rec->offset = offset;
2154 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002155 }
Simon Kelley28866e92011-02-14 20:19:14 +00002156
2157 /* unlink first SRV record found */
2158 if (!move)
2159 {
2160 move = rec;
2161 *up = rec->next;
2162 }
2163 else
2164 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002165 }
Simon Kelley28866e92011-02-14 20:19:14 +00002166 else
2167 up = &rec->next;
2168
2169 /* put first SRV record back at the end. */
2170 if (move)
2171 {
2172 *up = move;
2173 move->next = NULL;
2174 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002175
Simon Kelley28866e92011-02-14 20:19:14 +00002176 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002177 {
2178 ans = 1;
2179 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002180 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002181 }
2182 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002183
2184 if (qtype == T_NAPTR || qtype == T_ANY)
2185 {
2186 struct naptr *na;
2187 for (na = daemon->naptr; na; na = na->next)
2188 if (hostname_isequal(name, na->name))
2189 {
2190 ans = 1;
2191 if (!dryrun)
2192 {
Simon Kelley28866e92011-02-14 20:19:14 +00002193 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01002194 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2195 NULL, T_NAPTR, C_IN, "sszzzd",
2196 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
2197 anscount++;
2198 }
2199 }
2200 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002201
2202 if (qtype == T_MAILB)
2203 ans = 1, nxdomain = 1;
2204
Simon Kelley28866e92011-02-14 20:19:14 +00002205 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002206 {
2207 ans = 1;
2208 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002209 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002210 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002211 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002212
2213 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002214 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002215 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002216
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002217 if (dryrun)
2218 {
2219 dryrun = 0;
2220 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002221 }
2222
Simon Kelley0a852542005-03-23 20:28:59 +00002223 /* create an additional data section, for stuff in SRV and MX record replies. */
2224 for (rec = daemon->mxnames; rec; rec = rec->next)
2225 if (rec->offset != 0)
2226 {
2227 /* squash dupes */
2228 struct mx_srv_record *tmp;
2229 for (tmp = rec->next; tmp; tmp = tmp->next)
2230 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2231 tmp->offset = 0;
2232
2233 crecp = NULL;
2234 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2235 {
Simon Kelley0a852542005-03-23 20:28:59 +00002236#ifdef HAVE_IPV6
2237 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2238#else
2239 int type = T_A;
2240#endif
2241 if (crecp->flags & F_NEG)
2242 continue;
2243
Simon Kelley9009d742008-11-14 20:04:27 +00002244 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2245 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002246 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2247 addncount++;
2248 }
2249 }
2250
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002251 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002252 /* clear authoritative and truncated flags, set QR flag */
2253 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2254 /* set RA flag */
2255 header->hb4 |= HB4_RA;
2256
2257 /* authoritive - only hosts and DHCP derived names. */
2258 if (auth)
2259 header->hb3 |= HB3_AA;
2260
2261 /* truncation */
2262 if (trunc)
2263 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002264
Simon Kelley45cca582013-10-15 10:20:13 +01002265 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002266 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002267 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002268 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002269 header->ancount = htons(anscount);
2270 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002271 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00002272
Simon Kelleya25720a2014-01-14 23:13:55 +00002273 len = ansp - (unsigned char *)header;
2274
2275 if (have_pseudoheader)
Simon Kelleye243c072014-02-06 18:14:09 +00002276 len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
2277
Simon Kelley83349b82014-02-10 21:02:01 +00002278 if (*ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00002279 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00002280 else
2281 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00002282
Simon Kelley7c286122014-01-27 21:38:11 +00002283 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002284}
2285