blob: 56647b02ab4d7bcb3ac531ecd1db8bcf09be1747 [file] [log] [blame]
Simon Kelleyaff33962015-01-31 20:13:40 +00001/* dnsmasq is Copyright (c) 2000-2015 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 Kelleyb8f16552015-04-22 21:14:31 +010023 unsigned int j, l, namelen = 0, hops = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000024 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 }
Simon Kelley06568c62015-05-15 20:43:48 +010080 else if (label_type == 0x00)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000081 { /* label_type = 0 -> label. */
Simon Kelley5d07d772015-05-15 18:13:06 +010082 namelen += l + 1; /* include period */
83 if (namelen >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +000085 if (!CHECK_LEN(header, p, plen, l))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000086 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +000087
Simon Kelley9e4abcb2004-01-22 19:47:41 +000088 for(j=0; j<l; j++, p++)
89 if (isExtract)
90 {
Simon Kelley1f15b812009-10-13 17:49:32 +010091 unsigned char c = *p;
Simon Kelleycbe379a2015-04-21 22:57:06 +010092#ifdef HAVE_DNSSEC
93 if (option_bool(OPT_DNSSEC_VALID))
94 {
95 if (c == 0 || c == '.' || c == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +010096 {
97 *cp++ = NAME_ESCAPE;
98 *cp++ = c+1;
99 }
100 else
101 *cp++ = c;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100102 }
103 else
104#endif
Simon Kelley394ff492015-03-29 22:17:14 +0100105 if (c != 0 && c != '.')
106 *cp++ = c;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107 else
108 return 0;
109 }
110 else
111 {
112 unsigned char c1 = *cp, c2 = *p;
113
114 if (c1 == 0)
115 retvalue = 2;
116 else
117 {
118 cp++;
119 if (c1 >= 'A' && c1 <= 'Z')
120 c1 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100121#ifdef HAVE_DNSSEC
122 if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +0100123 c1 = (*cp++)-1;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100124#endif
125
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000126 if (c2 >= 'A' && c2 <= 'Z')
127 c2 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100128
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000129 if (c1 != c2)
130 retvalue = 2;
131 }
132 }
Simon Kelley06568c62015-05-15 20:43:48 +0100133
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000134 if (isExtract)
135 *cp++ = '.';
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000136 else if (*cp != 0 && *cp++ != '.')
137 retvalue = 2;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000138 }
Simon Kelley06568c62015-05-15 20:43:48 +0100139 else
140 return 0; /* label types 0x40 and 0x80 not supported */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000141 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000142}
143
144/* Max size of input string (for IPv6) is 75 chars.) */
145#define MAXARPANAME 75
Simon Kelley4f7b3042012-11-28 21:27:02 +0000146int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000147{
148 int j;
149 char name[MAXARPANAME+1], *cp1;
150 unsigned char *addr = (unsigned char *)addrp;
151 char *lastchunk = NULL, *penchunk = NULL;
152
153 if (strlen(namein) > MAXARPANAME)
154 return 0;
155
156 memset(addrp, 0, sizeof(struct all_addr));
157
158 /* turn name into a series of asciiz strings */
159 /* j counts no of labels */
160 for(j = 1,cp1 = name; *namein; cp1++, namein++)
161 if (*namein == '.')
162 {
163 penchunk = lastchunk;
164 lastchunk = cp1 + 1;
165 *cp1 = 0;
166 j++;
167 }
168 else
169 *cp1 = *namein;
170
171 *cp1 = 0;
172
173 if (j<3)
174 return 0;
175
176 if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
177 {
178 /* IP v4 */
179 /* address arives as a name of the form
180 www.xxx.yyy.zzz.in-addr.arpa
181 some of the low order address octets might be missing
182 and should be set to zero. */
183 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
184 {
185 /* check for digits only (weeds out things like
186 50.0/24.67.28.64.in-addr.arpa which are used
187 as CNAME targets according to RFC 2317 */
188 char *cp;
189 for (cp = cp1; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000190 if (!isdigit((unsigned char)*cp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000191 return 0;
192
193 addr[3] = addr[2];
194 addr[2] = addr[1];
195 addr[1] = addr[0];
196 addr[0] = atoi(cp1);
197 }
198
199 return F_IPV4;
200 }
201#ifdef HAVE_IPV6
202 else if (hostname_isequal(penchunk, "ip6") &&
203 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
204 {
205 /* IP v6:
206 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
207 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
208
209 Note that most of these the various reprentations are obsolete and
210 left-over from the many DNS-for-IPv6 wars. We support all the formats
211 that we can since there is no reason not to.
212 */
213
214 if (*name == '\\' && *(name+1) == '[' &&
215 (*(name+2) == 'x' || *(name+2) == 'X'))
216 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000217 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000218 {
219 char xdig[2];
220 xdig[0] = *cp1;
221 xdig[1] = 0;
222 if (j%2)
223 addr[j/2] |= strtol(xdig, NULL, 16);
224 else
225 addr[j/2] = strtol(xdig, NULL, 16) << 4;
226 }
227
228 if (*cp1 == '/' && j == 32)
229 return F_IPV6;
230 }
231 else
232 {
233 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
234 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000235 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000236 return 0;
237
238 for (j = sizeof(struct all_addr)-1; j>0; j--)
239 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
240 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
241 }
242
243 return F_IPV6;
244 }
245 }
246#endif
247
248 return 0;
249}
250
Giovanni Bajo32f82c62012-04-28 01:01:16 +0200251unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100252{
253 while(1)
254 {
Simon Kelley9009d742008-11-14 20:04:27 +0000255 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100256
Simon Kelley9009d742008-11-14 20:04:27 +0000257 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100258 return NULL;
259
Simon Kelley9009d742008-11-14 20:04:27 +0000260 label_type = (*ansp) & 0xc0;
261
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100262 if (label_type == 0xc0)
263 {
264 /* pointer for compression. */
265 ansp += 2;
266 break;
267 }
268 else if (label_type == 0x80)
269 return NULL; /* reserved */
270 else if (label_type == 0x40)
271 {
272 /* Extended label type */
273 unsigned int count;
274
Simon Kelley9009d742008-11-14 20:04:27 +0000275 if (!CHECK_LEN(header, ansp, plen, 2))
276 return NULL;
277
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100278 if (((*ansp++) & 0x3f) != 1)
279 return NULL; /* we only understand bitstrings */
280
281 count = *(ansp++); /* Bits in bitstring */
282
283 if (count == 0) /* count == 0 means 256 bits */
284 ansp += 32;
285 else
286 ansp += ((count-1)>>3)+1;
287 }
288 else
289 { /* label type == 0 Bottom six bits is length */
290 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000291
292 if (!ADD_RDLEN(header, ansp, plen, len))
293 return NULL;
294
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100295 if (len == 0)
296 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100297 }
298 }
Simon Kelley9009d742008-11-14 20:04:27 +0000299
300 if (!CHECK_LEN(header, ansp, plen, extrabytes))
301 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100302
303 return ansp;
304}
305
Simon Kelley4f7b3042012-11-28 21:27:02 +0000306unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000307{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100308 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000309 unsigned char *ansp = (unsigned char *)(header+1);
310
Simon Kelley5aabfc72007-08-29 11:24:47 +0100311 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000312 {
Simon Kelley9009d742008-11-14 20:04:27 +0000313 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100314 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000315 ansp += 4; /* class and type */
316 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000317
318 return ansp;
319}
320
Simon Kelley5107ace2014-02-23 10:48:32 +0000321unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100322{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100323 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100324
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100325 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100326 {
Simon Kelley9009d742008-11-14 20:04:27 +0000327 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100328 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100329 ansp += 8; /* type, class, TTL */
330 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000331 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100332 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100333 }
334
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100335 return ansp;
336}
337
Simon Kelley0a852542005-03-23 20:28:59 +0000338/* CRC the question section. This is used to safely detect query
339 retransmision and to detect answers to questions we didn't ask, which
340 might be poisoning attacks. Note that we decode the name rather
341 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000342 We ignore case in the names for the same reason. Return all-ones
343 if there is not question section. */
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000344#ifndef HAVE_DNSSEC
Simon Kelley572b41e2011-02-18 18:11:18 +0000345unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100346{
Simon Kelley91dccd02005-03-31 17:48:32 +0100347 int q;
348 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000349 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100350
Simon Kelley5aabfc72007-08-29 11:24:47 +0100351 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000352 {
Simon Kelley9009d742008-11-14 20:04:27 +0000353 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000354 return crc; /* bad packet */
355
Simon Kelley3d8df262005-08-29 12:19:27 +0100356 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000357 {
358 int i = 8;
359 char c = *p1;
360
361 if (c >= 'A' && c <= 'Z')
362 c += 'a' - 'A';
363
364 crc ^= c << 24;
365 while (i--)
366 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
367 }
368
369 /* CRC the class and type as well */
370 for (p1 = p; p1 < p+4; p1++)
371 {
372 int i = 8;
373 crc ^= *p1 << 24;
374 while (i--)
375 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
376 }
377
378 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000379 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000380 return crc; /* bad packet */
381 }
382
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100383 return crc;
384}
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000385#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100386
Simon Kelley572b41e2011-02-18 18:11:18 +0000387size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100388{
389 unsigned char *ansp = skip_questions(header, plen);
390
Simon Kelley9009d742008-11-14 20:04:27 +0000391 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100392 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000393 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100394
395 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
396 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000397 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100398
Simon Kelley36717ee2004-09-20 19:20:58 +0100399 /* restore pseudoheader */
400 if (pheader && ntohs(header->arcount) == 0)
401 {
402 /* must use memmove, may overlap */
403 memmove(ansp, pheader, hlen);
404 header->arcount = htons(1);
405 ansp += hlen;
406 }
407
408 return ansp - (unsigned char *)header;
409}
410
Simon Kelley572b41e2011-02-18 18:11:18 +0000411unsigned 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 +0100412{
413 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
Simon Kelley832af0b2007-01-21 20:01:28 +0000414 also return length of pseudoheader in *len and pointer to the UDP size in *p
415 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
416 forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100417
418 int i, arcount = ntohs(header->arcount);
Simon Kelley832af0b2007-01-21 20:01:28 +0000419 unsigned char *ansp = (unsigned char *)(header+1);
420 unsigned short rdlen, type, class;
421 unsigned char *ret = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000422
423 if (is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000424 {
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000425 *is_sign = 0;
426
Simon Kelley572b41e2011-02-18 18:11:18 +0000427 if (OPCODE(header) == QUERY)
Simon Kelley832af0b2007-01-21 20:01:28 +0000428 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100429 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000430 {
Simon Kelley9009d742008-11-14 20:04:27 +0000431 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000432 return NULL;
433
434 GETSHORT(type, ansp);
435 GETSHORT(class, ansp);
436
437 if (class == C_IN && type == T_TKEY)
438 *is_sign = 1;
439 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000440 }
441 }
442 else
443 {
444 if (!(ansp = skip_questions(header, plen)))
445 return NULL;
446 }
447
448 if (arcount == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100449 return NULL;
450
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100451 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
452 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000453
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100454 for (i = 0; i < arcount; i++)
455 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100456 unsigned char *save, *start = ansp;
Simon Kelley9009d742008-11-14 20:04:27 +0000457 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100458 return NULL;
459
460 GETSHORT(type, ansp);
461 save = ansp;
Simon Kelley832af0b2007-01-21 20:01:28 +0000462 GETSHORT(class, ansp);
463 ansp += 4; /* TTL */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100464 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000465 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100466 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000467 if (type == T_OPT)
Simon Kelley36717ee2004-09-20 19:20:58 +0100468 {
469 if (len)
470 *len = ansp - start;
471 if (p)
472 *p = save;
Simon Kelley832af0b2007-01-21 20:01:28 +0000473 ret = start;
Simon Kelley36717ee2004-09-20 19:20:58 +0100474 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000475 else if (is_sign &&
476 i == arcount - 1 &&
477 class == C_ANY &&
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000478 type == T_TSIG)
Simon Kelley832af0b2007-01-21 20:01:28 +0000479 *is_sign = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100480 }
481
Simon Kelley832af0b2007-01-21 20:01:28 +0000482 return ret;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100483}
Simon Kelley28866e92011-02-14 20:19:14 +0000484
485struct macparm {
486 unsigned char *limit;
Simon Kelley572b41e2011-02-18 18:11:18 +0000487 struct dns_header *header;
Simon Kelley28866e92011-02-14 20:19:14 +0000488 size_t plen;
489 union mysockaddr *l3;
490};
Simon Kelleyed4c0762013-10-08 20:46:34 +0100491
492static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
Simon Kelley3a237152013-12-12 12:15:50 +0000493 int optno, unsigned char *opt, size_t optlen, int set_do)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100494{
495 unsigned char *lenp, *datap, *p;
Simon Kelleya25720a2014-01-14 23:13:55 +0000496 int rdlen, is_sign;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100497
Simon Kelleya25720a2014-01-14 23:13:55 +0000498 if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
Simon Kelleyed4c0762013-10-08 20:46:34 +0100499 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000500 if (is_sign)
501 return plen;
502
Simon Kelleyed4c0762013-10-08 20:46:34 +0100503 /* We are adding the pseudoheader */
504 if (!(p = skip_questions(header, plen)) ||
505 !(p = skip_section(p,
Simon Kelleya25720a2014-01-14 23:13:55 +0000506 ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
Simon Kelleyed4c0762013-10-08 20:46:34 +0100507 header, plen)))
508 return plen;
509 *p++ = 0; /* empty name */
510 PUTSHORT(T_OPT, p);
Simon Kelleya77cec82015-05-08 16:25:38 +0100511 PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */
Simon Kelley3a237152013-12-12 12:15:50 +0000512 PUTSHORT(0, p); /* extended RCODE and version */
513 PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100514 lenp = p;
515 PUTSHORT(0, p); /* RDLEN */
516 rdlen = 0;
517 if (((ssize_t)optlen) > (limit - (p + 4)))
518 return plen; /* Too big */
Simon Kelleya25720a2014-01-14 23:13:55 +0000519 header->arcount = htons(ntohs(header->arcount) + 1);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100520 datap = p;
521 }
522 else
523 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000524 int i;
Simon Kelley3a237152013-12-12 12:15:50 +0000525 unsigned short code, len, flags;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100526
Simon Kelleya25720a2014-01-14 23:13:55 +0000527 /* Must be at the end, if exists */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100528 if (ntohs(header->arcount) != 1 ||
Simon Kelleyed4c0762013-10-08 20:46:34 +0100529 is_sign ||
530 (!(p = skip_name(p, header, plen, 10))))
531 return plen;
532
Simon Kelley3a237152013-12-12 12:15:50 +0000533 p += 6; /* skip UDP length and RCODE */
534 GETSHORT(flags, p);
535 if (set_do)
536 {
537 p -=2;
538 PUTSHORT(flags | 0x8000, p);
539 }
540
Simon Kelleyed4c0762013-10-08 20:46:34 +0100541 lenp = p;
542 GETSHORT(rdlen, p);
543 if (!CHECK_LEN(header, p, plen, rdlen))
544 return plen; /* bad packet */
545 datap = p;
546
Simon Kelley3a237152013-12-12 12:15:50 +0000547 /* no option to add */
548 if (optno == 0)
549 return plen;
550
Simon Kelleyed4c0762013-10-08 20:46:34 +0100551 /* check if option already there */
552 for (i = 0; i + 4 < rdlen; i += len + 4)
553 {
554 GETSHORT(code, p);
555 GETSHORT(len, p);
556 if (code == optno)
557 return plen;
558 p += len;
559 }
560
561 if (((ssize_t)optlen) > (limit - (p + 4)))
562 return plen; /* Too big */
563 }
564
Simon Kelley0fc2f312014-01-08 10:26:58 +0000565 if (optno != 0)
566 {
567 PUTSHORT(optno, p);
568 PUTSHORT(optlen, p);
569 memcpy(p, opt, optlen);
570 p += optlen;
571 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100572
573 PUTSHORT(p - datap, lenp);
574 return p - (unsigned char *)header;
575
576}
Simon Kelley28866e92011-02-14 20:19:14 +0000577
578static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
579{
580 struct macparm *parm = parmv;
581 int match = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100582
Simon Kelley28866e92011-02-14 20:19:14 +0000583 if (family == parm->l3->sa.sa_family)
584 {
Simon Kelley613ad152014-02-25 23:02:28 +0000585 if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000586 match = 1;
587#ifdef HAVE_IPV6
588 else
Simon Kelley613ad152014-02-25 23:02:28 +0000589 if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000590 match = 1;
591#endif
592 }
593
594 if (!match)
595 return 1; /* continue */
Simon Kelley28866e92011-02-14 20:19:14 +0000596
Simon Kelley3a237152013-12-12 12:15:50 +0000597 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 +0000598
599 return 0; /* done */
600}
601
Simon Kelley572b41e2011-02-18 18:11:18 +0000602size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
Simon Kelley28866e92011-02-14 20:19:14 +0000603{
604 struct macparm parm;
605
606/* Must have an existing pseudoheader as the only ar-record,
607 or have no ar-records. Must also not be signed */
608
609 if (ntohs(header->arcount) > 1)
610 return plen;
611
612 parm.header = header;
613 parm.limit = (unsigned char *)limit;
614 parm.plen = plen;
615 parm.l3 = l3;
616
617 iface_enumerate(AF_UNSPEC, &parm, filter_mac);
618
619 return parm.plen;
620}
621
Simon Kelleyed4c0762013-10-08 20:46:34 +0100622struct subnet_opt {
623 u16 family;
624 u8 source_netmask, scope_netmask;
625#ifdef HAVE_IPV6
626 u8 addr[IN6ADDRSZ];
627#else
628 u8 addr[INADDRSZ];
629#endif
630};
631
Simon Kelley44de6492013-11-06 11:36:57 +0000632static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100633{
634 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
635
636 int len;
637 void *addrp;
638
Simon Kelleyed4c0762013-10-08 20:46:34 +0100639#ifdef HAVE_IPV6
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100640 if (source->sa.sa_family == AF_INET6)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100641 {
642 opt->family = htons(2);
643 opt->source_netmask = daemon->addr6_netmask;
644 addrp = &source->in6.sin6_addr;
645 }
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100646 else
Simon Kelleyed4c0762013-10-08 20:46:34 +0100647#endif
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100648 {
649 opt->family = htons(1);
650 opt->source_netmask = daemon->addr4_netmask;
651 addrp = &source->in.sin_addr;
652 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100653
654 opt->scope_netmask = 0;
655 len = 0;
656
657 if (opt->source_netmask != 0)
658 {
659 len = ((opt->source_netmask - 1) >> 3) + 1;
660 memcpy(opt->addr, addrp, len);
661 if (opt->source_netmask & 7)
662 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
663 }
664
665 return len + 4;
666}
667
668size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
669{
670 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
671
672 int len;
673 struct subnet_opt opt;
674
675 len = calc_subnet_opt(&opt, source);
Simon Kelley3a237152013-12-12 12:15:50 +0000676 return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100677}
Simon Kelley3a237152013-12-12 12:15:50 +0000678
679#ifdef HAVE_DNSSEC
680size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
681{
682 return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
683}
684#endif
685
Simon Kelleyed4c0762013-10-08 20:46:34 +0100686int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
687{
688 /* Section 9.2, Check that subnet option in reply matches. */
689
690
691 int len, calc_len;
692 struct subnet_opt opt;
693 unsigned char *p;
694 int code, i, rdlen;
695
696 calc_len = calc_subnet_opt(&opt, peer);
697
698 if (!(p = skip_name(pseudoheader, header, plen, 10)))
699 return 1;
700
701 p += 8; /* skip UDP length and RCODE */
702
703 GETSHORT(rdlen, p);
704 if (!CHECK_LEN(header, p, plen, rdlen))
705 return 1; /* bad packet */
706
707 /* check if option there */
708 for (i = 0; i + 4 < rdlen; i += len + 4)
709 {
710 GETSHORT(code, p);
711 GETSHORT(len, p);
712 if (code == EDNS0_OPTION_CLIENT_SUBNET)
713 {
714 /* make sure this doesn't mismatch. */
715 opt.scope_netmask = p[3];
716 if (len != calc_len || memcmp(p, &opt, len) != 0)
717 return 0;
718 }
719 p += len;
720 }
721
722 return 1;
723}
724
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000725/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100726int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000727{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100728 in_addr_t ip_addr = ntohl(addr.s_addr);
729
730 return
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100731 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100732 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
733 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
734 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
735 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000736}
Simon Kelley1cff1662004-03-12 08:12:58 +0000737
Simon Kelley6938f342014-01-26 22:47:39 +0000738static 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 +0000739{
740 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000741
742 for (i = count; i != 0; i--)
743 {
Simon Kelley28866e92011-02-14 20:19:14 +0000744 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100745 {
746 if (!extract_name(header, qlen, &p, name, 1, 10))
747 return 0;
748 }
749 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000750 return 0; /* bad packet */
751
752 GETSHORT(qtype, p);
753 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100754 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000755 GETSHORT(rdlen, p);
756
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100757 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000758 {
759 struct doctor *doctor;
760 struct in_addr addr;
761
Simon Kelley9009d742008-11-14 20:04:27 +0000762 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
763 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100764
765 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000766 memcpy(&addr, p, INADDRSZ);
767
768 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000769 {
770 if (doctor->end.s_addr == 0)
771 {
772 if (!is_same_net(doctor->in, addr, doctor->mask))
773 continue;
774 }
775 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
776 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
777 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100778
Simon Kelley73a08a22009-02-05 20:28:08 +0000779 addr.s_addr &= ~doctor->mask.s_addr;
780 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
781 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000782 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000783 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000784 memcpy(p, &addr, INADDRSZ);
785 break;
786 }
Simon Kelley824af852008-02-12 20:43:05 +0000787 }
Simon Kelley28866e92011-02-14 20:19:14 +0000788 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100789 {
790 unsigned char *p1 = p;
791 if (!CHECK_LEN(header, p1, qlen, rdlen))
792 return 0;
793 while ((p1 - p) < rdlen)
794 {
795 unsigned int i, len = *p1;
796 unsigned char *p2 = p1;
797 /* make counted string zero-term and sanitise */
798 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100799 {
800 if (!isprint((int)*(p2+1)))
801 break;
802
803 *p2 = *(p2+1);
804 p2++;
805 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100806 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000807 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100808 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100809 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100810 *p1 = len;
811 p1 += len+1;
812 }
813 }
Simon Kelley824af852008-02-12 20:43:05 +0000814
Simon Kelley9009d742008-11-14 20:04:27 +0000815 if (!ADD_RDLEN(header, p, qlen, rdlen))
816 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000817 }
818
819 return p;
820}
821
Simon Kelley6938f342014-01-26 22:47:39 +0000822static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000823{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100824 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000825 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100826 unsigned long ttl, minttl = ULONG_MAX;
827 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000828
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100829 /* first move to NS section and find TTL from any SOA section */
830 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000831 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000832 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000833
Simon Kelley5aabfc72007-08-29 11:24:47 +0100834 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000835 {
Simon Kelley9009d742008-11-14 20:04:27 +0000836 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100837 return 0; /* bad packet */
838
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000839 GETSHORT(qtype, p);
840 GETSHORT(qclass, p);
841 GETLONG(ttl, p);
842 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100843
844 if ((qclass == C_IN) && (qtype == T_SOA))
845 {
846 found_soa = 1;
847 if (ttl < minttl)
848 minttl = ttl;
849
850 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000851 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100852 return 0;
853 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000854 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100855 return 0;
856 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
857
858 GETLONG(ttl, p); /* minTTL */
859 if (ttl < minttl)
860 minttl = ttl;
861 }
Simon Kelley9009d742008-11-14 20:04:27 +0000862 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100863 return 0; /* bad packet */
864 }
Simon Kelley9009d742008-11-14 20:04:27 +0000865
Simon Kelley6938f342014-01-26 22:47:39 +0000866 /* rewrite addresses in additional section too */
867 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000868 return 0;
869
870 if (!found_soa)
871 minttl = daemon->neg_ttl;
872
873 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100874}
875
876/* Note that the following code can create CNAME chains that don't point to a real record,
877 either because of lack of memory, or lack of SOA records. These are treated by the cache code as
Simon Kelley824af852008-02-12 20:43:05 +0000878 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100879 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000880int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelley6938f342014-01-26 22:47:39 +0000881 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882{
Simon Kelley824af852008-02-12 20:43:05 +0000883 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100884 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000885 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100886 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000887#ifdef HAVE_IPSET
888 char **ipsets_cur;
889#else
890 (void)ipsets; /* unused */
891#endif
892
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100893 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000894
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100895 /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
Simon Kelley6938f342014-01-26 22:47:39 +0000896 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000897 {
898 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000899 ttl = find_soa(header, qlen, name, doctored);
900#ifdef HAVE_DNSSEC
Simon Kelleyd1fbb772014-03-01 20:08:58 +0000901 if (*doctored && secure)
902 return 0;
Simon Kelley6938f342014-01-26 22:47:39 +0000903#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000904 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100905
906 /* go through the questions. */
907 p = (unsigned char *)(header+1);
908
Simon Kelley5aabfc72007-08-29 11:24:47 +0100909 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100910 {
Simon Kelley1fbe4d22014-03-01 20:03:47 +0000911 int found = 0, cname_count = CNAME_CHAIN;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100912 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000913 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0435d042014-01-08 18:22:37 +0000914 int secflag = secure ? F_DNSSECOK : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000915 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000916
Simon Kelley824af852008-02-12 20:43:05 +0000917 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000918 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000919 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100920
921 GETSHORT(qtype, p);
922 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000923
924 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100925 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000926
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100927 /* PTRs: we chase CNAMEs here, since we have no way to
928 represent them in the cache. */
929 if (qtype == T_PTR)
930 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000931 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100932
933 if (!name_encoding)
934 continue;
935
936 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000937 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100938 cname_loop:
939 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000940 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100941
Simon Kelley5aabfc72007-08-29 11:24:47 +0100942 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100943 {
Simon Kelley824af852008-02-12 20:43:05 +0000944 unsigned char *tmp = namep;
945 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000946 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
947 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000948 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100949
950 GETSHORT(aqtype, p1);
951 GETSHORT(aqclass, p1);
952 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100953 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
954 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000955 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100956 PUTLONG(daemon->max_ttl, p1);
957 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100958 GETSHORT(ardlen, p1);
959 endrr = p1+ardlen;
960
961 /* TTL of record is minimum of CNAMES and PTR */
962 if (attl < cttl)
963 cttl = attl;
964
965 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
966 {
Simon Kelley9009d742008-11-14 20:04:27 +0000967 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000968 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100969
970 if (aqtype == T_CNAME)
971 {
Simon Kelleyd1fbb772014-03-01 20:08:58 +0000972 if (!cname_count-- || secure)
973 return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100974 goto cname_loop;
975 }
976
Simon Kelley0435d042014-01-08 18:22:37 +0000977 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100978 found = 1;
979 }
980
981 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000982 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000983 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100984 }
985 }
986
Simon Kelley28866e92011-02-14 20:19:14 +0000987 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100988 {
989 if (!searched_soa)
990 {
991 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000992 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100993 }
994 if (ttl)
Simon Kelley0435d042014-01-08 18:22:37 +0000995 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000996 }
997 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100998 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000999 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001000 /* everything other than PTR */
1001 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001002 int addrlen;
1003
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001004 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001005 {
1006 addrlen = INADDRSZ;
1007 flags |= F_IPV4;
1008 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001009#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001010 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001011 {
1012 addrlen = IN6ADDRSZ;
1013 flags |= F_IPV6;
1014 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001015#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001016 else
1017 continue;
1018
Simon Kelley45cca582013-10-15 10:20:13 +01001019 cname_loop1:
1020 if (!(p1 = skip_questions(header, qlen)))
1021 return 0;
1022
1023 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001024 {
Simon Kelley45cca582013-10-15 10:20:13 +01001025 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
1026 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001027
Simon Kelley45cca582013-10-15 10:20:13 +01001028 GETSHORT(aqtype, p1);
1029 GETSHORT(aqclass, p1);
1030 GETLONG(attl, p1);
1031 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001032 {
Simon Kelley45cca582013-10-15 10:20:13 +01001033 (p1) -= 4;
1034 PUTLONG(daemon->max_ttl, p1);
1035 }
1036 GETSHORT(ardlen, p1);
1037 endrr = p1+ardlen;
1038
1039 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
1040 {
1041 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001042 {
Simon Kelley45cca582013-10-15 10:20:13 +01001043 if (!cname_count--)
1044 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +00001045 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001046 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001047 {
Simon Kelley45cca582013-10-15 10:20:13 +01001048 newc->addr.cname.target.cache = NULL;
Simon Kelley03431d62014-03-20 16:25:43 +00001049 /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
1050 newc->addr.cname.uid = 1;
Simon Kelley45cca582013-10-15 10:20:13 +01001051 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001052 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001053 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001054 cpp->addr.cname.uid = newc->uid;
1055 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001056 }
Simon Kelley45cca582013-10-15 10:20:13 +01001057
1058 cpp = newc;
1059 if (attl < cttl)
1060 cttl = attl;
1061
1062 if (!extract_name(header, qlen, &p1, name, 1, 0))
1063 return 0;
1064 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001065 }
Simon Kelley45cca582013-10-15 10:20:13 +01001066 else if (!(flags & F_NXDOMAIN))
1067 {
1068 found = 1;
1069
1070 /* copy address into aligned storage */
1071 if (!CHECK_LEN(header, p1, qlen, addrlen))
1072 return 0; /* bad packet */
1073 memcpy(&addr, p1, addrlen);
1074
1075 /* check for returned address in private space */
Simon Kelleyb059c962015-05-08 20:25:51 +01001076 if (check_rebind)
1077 {
1078 if ((flags & F_IPV4) &&
1079 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
1080 return 1;
1081
1082#ifdef HAVE_IPV6
1083 if ((flags & F_IPV6) &&
1084 IN6_IS_ADDR_V4MAPPED(&addr.addr.addr6))
1085 {
1086 struct in_addr v4;
1087 v4.s_addr = ((const uint32_t *) (&addr.addr.addr6))[3];
1088 if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
1089 return 1;
1090 }
1091#endif
1092 }
Simon Kelley45cca582013-10-15 10:20:13 +01001093
1094#ifdef HAVE_IPSET
1095 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
1096 {
1097 ipsets_cur = ipsets;
1098 while (*ipsets_cur)
Wang Jian49752b92014-03-28 20:52:47 +00001099 {
Simon Kelleyb7639d52014-03-29 09:20:07 +00001100 log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
Wang Jian49752b92014-03-28 20:52:47 +00001101 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
1102 }
Simon Kelley45cca582013-10-15 10:20:13 +01001103 }
1104#endif
1105
Simon Kelley0435d042014-01-08 18:22:37 +00001106 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001107 if (newc && cpp)
1108 {
1109 cpp->addr.cname.target.cache = newc;
1110 cpp->addr.cname.uid = newc->uid;
1111 }
1112 cpp = NULL;
1113 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001114 }
Simon Kelley45cca582013-10-15 10:20:13 +01001115
1116 p1 = endrr;
1117 if (!CHECK_LEN(header, p1, qlen, 0))
1118 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001119 }
1120
Simon Kelley28866e92011-02-14 20:19:14 +00001121 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001122 {
1123 if (!searched_soa)
1124 {
1125 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001126 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001127 }
1128 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001129 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001130 if (ttl || cpp)
1131 {
Simon Kelley0435d042014-01-08 18:22:37 +00001132 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
Simon Kelley26128d22004-11-14 16:43:54 +00001133 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001134 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001135 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001136 cpp->addr.cname.uid = newc->uid;
1137 }
1138 }
1139 }
1140 }
1141 }
1142
Simon Kelley1023dcb2012-04-09 18:00:08 +01001143 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +01001144 Don't cache replies from non-recursive nameservers, since we may get a
1145 reply containing a CNAME but not its target, even though the target
1146 does exist. */
1147 if (!(header->hb3 & HB3_TC) &&
1148 !(header->hb4 & HB4_CD) &&
1149 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +00001150 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +00001151 cache_end_insert();
1152
1153 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001154}
1155
1156/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001157 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +00001158unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001159{
1160 unsigned char *p = (unsigned char *)(header+1);
1161 int qtype, qclass;
1162
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001163 if (typep)
1164 *typep = 0;
1165
Simon Kelley572b41e2011-02-18 18:11:18 +00001166 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001167 return 0; /* must be exactly one query. */
1168
Simon Kelley9009d742008-11-14 20:04:27 +00001169 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001170 return 0; /* bad packet */
1171
1172 GETSHORT(qtype, p);
1173 GETSHORT(qclass, p);
1174
Simon Kelley0a852542005-03-23 20:28:59 +00001175 if (typep)
1176 *typep = qtype;
1177
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001178 if (qclass == C_IN)
1179 {
1180 if (qtype == T_A)
1181 return F_IPV4;
1182 if (qtype == T_AAAA)
1183 return F_IPV6;
1184 if (qtype == T_ANY)
1185 return F_IPV4 | F_IPV6;
1186 }
1187
1188 return F_QUERY;
1189}
1190
1191
Simon Kelley572b41e2011-02-18 18:11:18 +00001192size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001193 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001194{
Simon Kelleyad4a8ff2015-04-09 21:48:00 +01001195 unsigned char *p;
1196
1197 if (!(p = skip_questions(header, qlen)))
1198 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001199
Simon Kelley572b41e2011-02-18 18:11:18 +00001200 /* clear authoritative and truncated flags, set QR flag */
1201 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1202 /* set RA flag */
1203 header->hb4 |= HB4_RA;
1204
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001205 header->nscount = htons(0);
1206 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001207 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001208 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001209 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001210 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001211 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001212 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001213 SET_RCODE(header, NXDOMAIN);
Simon Kelleyad4a8ff2015-04-09 21:48:00 +01001214 else if (flags == F_IPV4)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001215 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001216 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001217 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001218 header->hb3 |= HB3_AA;
1219 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 +00001220 }
1221#ifdef HAVE_IPV6
Simon Kelleyad4a8ff2015-04-09 21:48:00 +01001222 else if (flags == F_IPV6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001223 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001224 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001225 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001226 header->hb3 |= HB3_AA;
1227 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 +00001228 }
1229#endif
1230 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001231 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001232
1233 return p - (unsigned char *)header;
1234}
Simon Kelley36717ee2004-09-20 19:20:58 +01001235
1236/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001237int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001238{
1239 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001240 struct mx_srv_record *mx;
1241 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001242 struct interface_name *intr;
1243 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001244 struct naptr *naptr;
1245
Simon Kelley288df492014-09-18 21:48:51 +01001246 /* Note: the call to cache_find_by_name is intended to find any record which matches
1247 ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
1248 cache_find_by name ordinarily only returns records with an exact match on those bits (ie
1249 for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
1250
1251 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +00001252 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +01001253 return 1;
1254
Simon Kelley7de060b2011-08-26 17:24:52 +01001255 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1256 if (hostname_isequal(name, naptr->name))
1257 return 1;
1258
1259 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001260 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001261 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001262
Simon Kelley0a852542005-03-23 20:28:59 +00001263 for (txt = daemon->txt; txt; txt = txt->next)
1264 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001265 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001266
1267 for (intr = daemon->int_names; intr; intr = intr->next)
1268 if (hostname_isequal(name, intr->name))
1269 return 1;
1270
1271 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1272 if (hostname_isequal(name, ptr->name))
1273 return 1;
1274
Simon Kelley36717ee2004-09-20 19:20:58 +01001275 return 0;
1276}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001277
1278/* Is the packet a reply with the answer address equal to addr?
1279 If so mung is into an NXDOMAIN reply and also put that information
1280 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001281int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001282 struct bogus_addr *baddr, time_t now)
1283{
1284 unsigned char *p;
1285 int i, qtype, qclass, rdlen;
1286 unsigned long ttl;
1287 struct bogus_addr *baddrp;
1288
1289 /* skip over questions */
1290 if (!(p = skip_questions(header, qlen)))
1291 return 0; /* bad packet */
1292
Simon Kelley5aabfc72007-08-29 11:24:47 +01001293 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001294 {
Simon Kelley9009d742008-11-14 20:04:27 +00001295 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001296 return 0; /* bad packet */
1297
1298 GETSHORT(qtype, p);
1299 GETSHORT(qclass, p);
1300 GETLONG(ttl, p);
1301 GETSHORT(rdlen, p);
1302
1303 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001304 {
1305 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1306 return 0;
1307
1308 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1309 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1310 {
1311 /* Found a bogus address. Insert that info here, since there no SOA record
1312 to get the ttl from in the normal processing */
1313 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001314 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001315 cache_end_insert();
1316
1317 return 1;
1318 }
1319 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001320
Simon Kelley9009d742008-11-14 20:04:27 +00001321 if (!ADD_RDLEN(header, p, qlen, rdlen))
1322 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001323 }
1324
1325 return 0;
1326}
1327
Glen Huang32fc6db2014-12-27 15:28:12 +00001328int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
1329{
1330 unsigned char *p;
1331 int i, qtype, qclass, rdlen;
1332 struct bogus_addr *baddrp;
1333
1334 /* skip over questions */
1335 if (!(p = skip_questions(header, qlen)))
1336 return 0; /* bad packet */
1337
1338 for (i = ntohs(header->ancount); i != 0; i--)
1339 {
1340 if (!(p = skip_name(p, header, qlen, 10)))
1341 return 0; /* bad packet */
1342
1343 GETSHORT(qtype, p);
1344 GETSHORT(qclass, p);
1345 p += 4; /* TTL */
1346 GETSHORT(rdlen, p);
1347
1348 if (qclass == C_IN && qtype == T_A)
1349 {
1350 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1351 return 0;
1352
1353 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1354 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1355 return 1;
1356 }
1357
1358 if (!ADD_RDLEN(header, p, qlen, rdlen))
1359 return 0;
1360 }
1361
1362 return 0;
1363}
1364
Simon Kelleyb75e9362012-12-07 11:50:41 +00001365int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001366 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001367{
1368 va_list ap;
1369 unsigned char *sav, *p = *pp;
1370 int j;
1371 unsigned short usval;
1372 long lval;
1373 char *sval;
1374
1375 if (truncp && *truncp)
1376 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001377
1378 va_start(ap, format); /* make ap point to 1st unamed argument */
1379
Simon Kelleyb75e9362012-12-07 11:50:41 +00001380 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001381 {
1382 PUTSHORT(nameoffset | 0xc000, p);
1383 }
1384 else
1385 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001386 char *name = va_arg(ap, char *);
1387 if (name)
1388 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001389 if (nameoffset < 0)
1390 {
1391 PUTSHORT(-nameoffset | 0xc000, p);
1392 }
1393 else
1394 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001395 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001396
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001397 PUTSHORT(type, p);
1398 PUTSHORT(class, p);
1399 PUTLONG(ttl, p); /* TTL */
1400
1401 sav = p; /* Save pointer to RDLength field */
1402 PUTSHORT(0, p); /* Placeholder RDLength */
1403
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001404 for (; *format; format++)
1405 switch (*format)
1406 {
1407#ifdef HAVE_IPV6
1408 case '6':
1409 sval = va_arg(ap, char *);
1410 memcpy(p, sval, IN6ADDRSZ);
1411 p += IN6ADDRSZ;
1412 break;
1413#endif
1414
1415 case '4':
1416 sval = va_arg(ap, char *);
1417 memcpy(p, sval, INADDRSZ);
1418 p += INADDRSZ;
1419 break;
1420
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001421 case 'b':
1422 usval = va_arg(ap, int);
1423 *p++ = usval;
1424 break;
1425
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001426 case 's':
1427 usval = va_arg(ap, int);
1428 PUTSHORT(usval, p);
1429 break;
1430
1431 case 'l':
1432 lval = va_arg(ap, long);
1433 PUTLONG(lval, p);
1434 break;
1435
1436 case 'd':
1437 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001438 if (offset)
1439 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001440 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001441 *p++ = 0;
1442 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001443
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001444 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001445 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001446 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001447 if (usval != 0)
1448 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001449 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001450 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001451
1452 case 'z':
1453 sval = va_arg(ap, char *);
1454 usval = sval ? strlen(sval) : 0;
1455 if (usval > 255)
1456 usval = 255;
1457 *p++ = (unsigned char)usval;
1458 memcpy(p, sval, usval);
1459 p += usval;
1460 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001461 }
1462
1463 va_end(ap); /* clean up variable argument pointer */
1464
1465 j = p - sav - 2;
1466 PUTSHORT(j, sav); /* Now, store real RDLength */
1467
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001468 /* check for overflow of buffer */
1469 if (limit && ((unsigned char *)limit - p) < 0)
1470 {
1471 if (truncp)
1472 *truncp = 1;
1473 return 0;
1474 }
1475
1476 *pp = p;
1477 return 1;
1478}
1479
Simon Kelley9009d742008-11-14 20:04:27 +00001480static unsigned long crec_ttl(struct crec *crecp, time_t now)
1481{
1482 /* Return 0 ttl for DHCP entries, which might change
1483 before the lease expires. */
1484
1485 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1486 return daemon->local_ttl;
1487
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001488 /* Return the Max TTL value if it is lower then the actual TTL */
1489 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1490 return crecp->ttd - now;
1491 else
1492 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001493}
1494
1495
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001496/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001497size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001498 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelley613ad152014-02-25 23:02:28 +00001499 time_t now, int *ad_reqd, int *do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001500{
Simon Kelley3be34542004-09-11 19:12:13 +01001501 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001502 unsigned char *p, *ansp, *pheader;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001503 unsigned int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001504 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001505 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001506 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001507 int q, ans, anscount = 0, addncount = 0;
Simon Kelleya25720a2014-01-14 23:13:55 +00001508 int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001509 struct crec *crecp;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001510 int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001511 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001512 size_t len;
Simon Kelley0a852542005-03-23 20:28:59 +00001513
Simon Kelleye243c072014-02-06 18:14:09 +00001514 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001515 if (header->hb4 & HB4_CD)
1516 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001517
1518 /* RFC 6840 5.7 */
1519 *ad_reqd = header->hb4 & HB4_AD;
Simon Kelley613ad152014-02-25 23:02:28 +00001520 *do_bit = 0;
1521
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001522 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1523 partial replies, so we have to do a dry run to see if we can answer
1524 the query. We check to see if the do bit is set, if so we always
1525 forward rather than answering from the cache, which doesn't include
Simon Kelleya25720a2014-01-14 23:13:55 +00001526 security information, unless we're in DNSSEC validation mode. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001527
Simon Kelleya77cec82015-05-08 16:25:38 +01001528 if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001529 {
Simon Kelleya77cec82015-05-08 16:25:38 +01001530 unsigned short flags;
1531
Simon Kelleya25720a2014-01-14 23:13:55 +00001532 have_pseudoheader = 1;
1533
Simon Kelleya77cec82015-05-08 16:25:38 +01001534 pheader += 4; /* udp size, ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001535 GETSHORT(flags, pheader);
1536
Simon Kelley613ad152014-02-25 23:02:28 +00001537 if ((sec_reqd = flags & 0x8000))
1538 *do_bit = 1;/* do bit */
Simon Kelleya77cec82015-05-08 16:25:38 +01001539
Simon Kelley83349b82014-02-10 21:02:01 +00001540 *ad_reqd = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001541 dryrun = 1;
1542 }
1543
Simon Kelley572b41e2011-02-18 18:11:18 +00001544 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001545 return 0;
1546
Simon Kelley0a852542005-03-23 20:28:59 +00001547 for (rec = daemon->mxnames; rec; rec = rec->next)
1548 rec->offset = 0;
1549
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001550 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001551 /* determine end of question section (we put answers there) */
1552 if (!(ansp = skip_questions(header, qlen)))
1553 return 0; /* bad packet */
1554
1555 /* now process each question, answers go in RRs after the question */
1556 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001557
Simon Kelley5aabfc72007-08-29 11:24:47 +01001558 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001559 {
1560 /* save pointer to name for copying into answers */
1561 nameoffset = p - (unsigned char *)header;
1562
1563 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001564 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001565 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001566
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001567 GETSHORT(qtype, p);
1568 GETSHORT(qclass, p);
1569
Simon Kelley2ed162a2015-04-28 21:26:35 +01001570 /* Don't filter RRSIGS from answers to ANY queries, even if do-bit
1571 not set. */
1572 if (qtype == T_ANY)
1573 *do_bit = 1;
1574
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001575 ans = 0; /* have we answered this question */
1576
Simon Kelley0a852542005-03-23 20:28:59 +00001577 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001578 {
Simon Kelley0a852542005-03-23 20:28:59 +00001579 struct txt_record *t;
1580 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001581 {
Simon Kelley0a852542005-03-23 20:28:59 +00001582 if (t->class == qclass && hostname_isequal(name, t->name))
1583 {
1584 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001585 if (!dryrun)
1586 {
Simon Kelleyfec216d2014-03-27 20:54:34 +00001587 unsigned long ttl = daemon->local_ttl;
1588 int ok = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001589 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleyfec216d2014-03-27 20:54:34 +00001590 /* Dynamically generate stat record */
1591 if (t->stat != 0)
1592 {
1593 ttl = 0;
1594 if (!cache_make_stat(t))
1595 ok = 0;
1596 }
1597
1598 if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1599 ttl, NULL,
1600 T_TXT, t->class, "t", t->len, t->txt))
Simon Kelleye17fb622006-01-14 20:33:46 +00001601 anscount++;
1602
1603 }
Simon Kelley0a852542005-03-23 20:28:59 +00001604 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001605 }
Simon Kelley0a852542005-03-23 20:28:59 +00001606 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001607
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001608#ifdef HAVE_DNSSEC
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001609 if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001610 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001611 int gotone = 0;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001612 struct blockdata *keydata;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001613
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001614 /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001615 if (sec_reqd)
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001616 {
Simon Kelley5f938532014-02-03 16:44:32 +00001617 crecp = NULL;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001618 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1619 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
1620 break;
1621 }
1622
1623 if (!sec_reqd || crecp)
1624 {
1625 if (qtype == T_DS)
1626 {
1627 crecp = NULL;
1628 while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
1629 if (crecp->uid == qclass)
1630 {
Simon Kelleyb8eac192014-02-27 14:30:03 +00001631 gotone = 1;
1632 if (!dryrun)
1633 {
1634 if (crecp->flags & F_NEG)
1635 {
1636 if (crecp->flags & F_NXDOMAIN)
1637 nxdomain = 1;
Simon Kelleyae4624b2015-01-12 23:22:08 +00001638 log_query(F_UPSTREAM, name, NULL, "no DS");
Simon Kelleyb8eac192014-02-27 14:30:03 +00001639 }
1640 else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
1641 {
1642 struct all_addr a;
1643 a.addr.keytag = crecp->addr.ds.keytag;
1644 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
1645 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1646 crec_ttl(crecp, now), &nameoffset,
1647 T_DS, qclass, "sbbt",
1648 crecp->addr.ds.keytag, crecp->addr.ds.algo,
1649 crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
1650 anscount++;
1651
1652 }
1653 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001654 }
1655 }
1656 else /* DNSKEY */
1657 {
1658 crecp = NULL;
1659 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
1660 if (crecp->uid == qclass)
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001661 {
Simon Kelleyee415862014-02-11 11:07:22 +00001662 gotone = 1;
1663 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
1664 {
1665 struct all_addr a;
1666 a.addr.keytag = crecp->addr.key.keytag;
1667 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
1668 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1669 crec_ttl(crecp, now), &nameoffset,
1670 T_DNSKEY, qclass, "sbbt",
1671 crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
1672 anscount++;
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001673 }
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001674 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001675 }
Simon Kelley5f938532014-02-03 16:44:32 +00001676 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001677
Simon Kelley5f938532014-02-03 16:44:32 +00001678 /* Now do RRSIGs */
1679 if (gotone)
1680 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001681 ans = 1;
1682 auth = 0;
1683 if (!dryrun && sec_reqd)
1684 {
1685 crecp = NULL;
1686 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1687 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
1688 (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
1689 {
Simon Kelley5f938532014-02-03 16:44:32 +00001690 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1691 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001692 T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
1693 anscount++;
1694 }
1695 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001696 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001697 }
1698#endif
1699
Simon Kelley0a852542005-03-23 20:28:59 +00001700 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001701 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001702 struct txt_record *t;
1703
1704 for (t = daemon->rr; t; t = t->next)
1705 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1706 {
1707 ans = 1;
1708 if (!dryrun)
1709 {
1710 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1711 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1712 daemon->local_ttl, NULL,
1713 t->class, C_IN, "t", t->len, t->txt))
1714 anscount ++;
1715 }
1716 }
1717
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001718 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001719 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001720 /* see if it's w.z.y.z.in-addr.arpa format */
1721 int is_arpa = in_arpa_name_2_addr(name, &addr);
1722 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001723 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001724
1725 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1726 if (hostname_isequal(name, ptr->name))
1727 break;
1728
Simon Kelleyf2621c72007-04-29 19:47:21 +01001729 if (is_arpa == F_IPV4)
1730 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001731 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001732 struct addrlist *addrlist;
1733
Simon Kelley376d48c2013-11-13 13:04:30 +00001734 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1735 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001736 break;
1737
1738 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001739 break;
1740 else
1741 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1742 intr = intr->next;
1743 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001744#ifdef HAVE_IPV6
1745 else if (is_arpa == F_IPV6)
1746 for (intr = daemon->int_names; intr; intr = intr->next)
1747 {
1748 struct addrlist *addrlist;
1749
Simon Kelley376d48c2013-11-13 13:04:30 +00001750 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1751 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001752 break;
1753
1754 if (addrlist)
1755 break;
1756 else
1757 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1758 intr = intr->next;
1759 }
1760#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001761
1762 if (intr)
1763 {
1764 ans = 1;
1765 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001766 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001767 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001768 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1769 daemon->local_ttl, NULL,
1770 T_PTR, C_IN, "d", intr->name))
1771 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001772 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001773 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001774 else if (ptr)
1775 {
1776 ans = 1;
1777 if (!dryrun)
1778 {
Simon Kelley28866e92011-02-14 20:19:14 +00001779 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001780 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001781 if (hostname_isequal(name, ptr->name) &&
1782 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1783 daemon->local_ttl, NULL,
1784 T_PTR, C_IN, "d", ptr->ptr))
1785 anscount++;
1786
Simon Kelley832af0b2007-01-21 20:01:28 +00001787 }
1788 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001789 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001790 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001791 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001792 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001793 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1794 crecp = NULL;
1795#ifdef HAVE_DNSSEC
1796 else if (crecp->flags & F_DNSSECOK)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001797 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001798 int gotsig = 0;
Simon Kelley12fae492014-02-04 22:03:06 +00001799 struct crec *rr_crec = NULL;
1800
1801 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001802 {
Simon Kelley12fae492014-02-04 22:03:06 +00001803 if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001804 {
Simon Kelley12fae492014-02-04 22:03:06 +00001805 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001806 gotsig = 1;
1807
1808 if (!dryrun &&
1809 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001810 rr_crec->ttd - now, &nameoffset,
Simon Kelley0744ca62014-01-25 16:40:15 +00001811 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
1812 anscount++;
1813 }
1814 }
Simon Kelley12fae492014-02-04 22:03:06 +00001815
1816 if (!gotsig)
1817 crecp = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001818 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001819#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001820 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001821
1822 if (crecp)
1823 {
1824 do
1825 {
1826 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1827 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1828 continue;
1829
1830 if (!(crecp->flags & F_DNSSECOK))
1831 sec_data = 0;
1832
1833 if (crecp->flags & F_NEG)
1834 {
1835 ans = 1;
1836 auth = 0;
1837 if (crecp->flags & F_NXDOMAIN)
1838 nxdomain = 1;
1839 if (!dryrun)
1840 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1841 }
1842 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
1843 {
1844 ans = 1;
1845 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1846 auth = 0;
1847 if (!dryrun)
1848 {
1849 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1850 record_source(crecp->uid));
1851
1852 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1853 crec_ttl(crecp, now), NULL,
1854 T_PTR, C_IN, "d", cache_get_name(crecp)))
1855 anscount++;
1856 }
1857 }
1858 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1859 }
1860 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001861 else if (is_rev_synth(is_arpa, &addr, name))
1862 {
1863 ans = 1;
1864 if (!dryrun)
1865 {
1866 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1867
1868 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1869 daemon->local_ttl, NULL,
1870 T_PTR, C_IN, "d", name))
1871 anscount++;
1872 }
1873 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001874 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001875 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001876 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001877 {
1878 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1879 ans = 1;
1880 nxdomain = 1;
1881 if (!dryrun)
1882 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001883 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001884 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001885 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001886
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001887 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1888 {
1889 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001890 struct interface_name *intr;
1891
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001892 if (flag == F_IPV6)
1893#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001894 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001895#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001896 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001897#endif
1898
1899 if (qtype != type && qtype != T_ANY)
1900 continue;
1901
Simon Kelley316e2732010-01-22 20:16:09 +00001902 /* Check for "A for A" queries; be rather conservative
1903 about what looks like dotted-quad. */
1904 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001905 {
Simon Kelley316e2732010-01-22 20:16:09 +00001906 char *cp;
1907 unsigned int i, a;
1908 int x;
1909
1910 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001911 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001912 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001913 {
1914 i = 5;
1915 break;
1916 }
1917
1918 a = (a << 8) + x;
1919
1920 if (*cp == '.')
1921 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001922 }
Simon Kelley316e2732010-01-22 20:16:09 +00001923
1924 if (i == 4)
1925 {
1926 ans = 1;
1927 if (!dryrun)
1928 {
1929 addr.addr.addr4.s_addr = htonl(a);
1930 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1931 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1932 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1933 anscount++;
1934 }
1935 continue;
1936 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001937 }
1938
Simon Kelleyf2621c72007-04-29 19:47:21 +01001939 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001940 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001941 for (intr = daemon->int_names; intr; intr = intr->next)
1942 if (hostname_isequal(name, intr->name))
1943 break;
1944
1945 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001946 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001947 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001948 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001949
Simon Kelley115ac3e2013-05-20 11:28:32 +01001950 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001951
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001952 for (intr = daemon->int_names; intr; intr = intr->next)
1953 if (hostname_isequal(name, intr->name))
1954 {
Simon Kelley47669362014-12-17 12:41:56 +00001955 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley376d48c2013-11-13 13:04:30 +00001956#ifdef HAVE_IPV6
Simon Kelley47669362014-12-17 12:41:56 +00001957 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
Simon Kelley376d48c2013-11-13 13:04:30 +00001958#endif
Simon Kelley47669362014-12-17 12:41:56 +00001959 {
1960#ifdef HAVE_IPV6
1961 if (addrlist->flags & ADDRLIST_REVONLY)
1962 continue;
1963#endif
1964 ans = 1;
1965 if (!dryrun)
Simon Kelley376d48c2013-11-13 13:04:30 +00001966 {
1967 gotit = 1;
1968 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1969 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1970 daemon->local_ttl, NULL, type, C_IN,
1971 type == T_A ? "4" : "6", &addrlist->addr))
1972 anscount++;
1973 }
Simon Kelley47669362014-12-17 12:41:56 +00001974 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001975 }
1976
1977 if (!dryrun && !gotit)
1978 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1979
Simon Kelley115ac3e2013-05-20 11:28:32 +01001980 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001981 }
1982
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001983 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00001984 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001985 {
1986 int localise = 0;
1987
1988 /* See if a putative address is on the network from which we recieved
1989 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001990 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001991 {
1992 struct crec *save = crecp;
1993 do {
1994 if ((crecp->flags & F_HOSTS) &&
1995 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1996 {
1997 localise = 1;
1998 break;
1999 }
2000 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
2001 crecp = save;
2002 }
Simon Kelley824202e2014-01-23 20:59:46 +00002003
Simon Kelley0744ca62014-01-25 16:40:15 +00002004 /* If the client asked for DNSSEC and we can't provide RRSIGs, either
2005 because we've not doing DNSSEC or the cached answer is signed by negative,
2006 don't answer from the cache, forward instead. */
2007 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley824202e2014-01-23 20:59:46 +00002008 {
Simon Kelley0744ca62014-01-25 16:40:15 +00002009 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
2010 crecp = NULL;
2011#ifdef HAVE_DNSSEC
2012 else if (crecp->flags & F_DNSSECOK)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002013 {
Simon Kelley0744ca62014-01-25 16:40:15 +00002014 /* We're returning validated data, need to return the RRSIG too. */
Simon Kelley12fae492014-02-04 22:03:06 +00002015 struct crec *rr_crec = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00002016 int sigtype = type;
2017 /* The signature may have expired even though the data is still in cache,
2018 forward instead of answering from cache if so. */
2019 int gotsig = 0;
2020
2021 if (crecp->flags & F_CNAME)
2022 sigtype = T_CNAME;
2023
Simon Kelley12fae492014-02-04 22:03:06 +00002024 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002025 {
Simon Kelley12fae492014-02-04 22:03:06 +00002026 if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00002027 {
Simon Kelley12fae492014-02-04 22:03:06 +00002028 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00002029 gotsig = 1;
2030
2031 if (!dryrun &&
2032 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00002033 rr_crec->ttd - now, &nameoffset,
2034 T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
Simon Kelley0744ca62014-01-25 16:40:15 +00002035 anscount++;
2036 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002037 }
Simon Kelley12fae492014-02-04 22:03:06 +00002038
2039 if (!gotsig)
2040 crecp = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002041 }
Simon Kelley824202e2014-01-23 20:59:46 +00002042#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00002043 }
2044
Simon Kelley824202e2014-01-23 20:59:46 +00002045 if (crecp)
2046 do
2047 {
2048 /* don't answer wildcard queries with data not from /etc/hosts
2049 or DHCP leases */
2050 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
2051 break;
2052
2053 if (!(crecp->flags & F_DNSSECOK))
2054 sec_data = 0;
2055
2056 if (crecp->flags & F_CNAME)
2057 {
2058 char *cname_target = cache_get_cname_target(crecp);
2059
2060 if (!dryrun)
2061 {
2062 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2063 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2064 crec_ttl(crecp, now), &nameoffset,
2065 T_CNAME, C_IN, "d", cname_target))
2066 anscount++;
2067 }
2068
2069 strcpy(name, cname_target);
2070 /* check if target interface_name */
Andy3e21a1a2014-03-22 19:10:07 +00002071 if (crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelley824202e2014-01-23 20:59:46 +00002072 goto intname_restart;
2073 else
2074 goto cname_restart;
2075 }
2076
2077 if (crecp->flags & F_NEG)
2078 {
2079 /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
2080 is cached and the client wants DNSSEC, forward rather than answering from the cache */
2081 if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
2082 {
2083 ans = 1;
2084 auth = 0;
2085 if (crecp->flags & F_NXDOMAIN)
2086 nxdomain = 1;
2087 if (!dryrun)
2088 log_query(crecp->flags, name, NULL, NULL);
2089 }
2090 }
2091 else
2092 {
2093 /* If we are returning local answers depending on network,
2094 filter here. */
2095 if (localise &&
2096 (crecp->flags & F_HOSTS) &&
2097 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
2098 continue;
2099
2100 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
2101 auth = 0;
2102
2103 ans = 1;
2104 if (!dryrun)
2105 {
2106 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
2107 record_source(crecp->uid));
2108
2109 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2110 crec_ttl(crecp, now), NULL, type, C_IN,
2111 type == T_A ? "4" : "6", &crecp->addr))
2112 anscount++;
2113 }
2114 }
2115 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002116 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002117 else if (is_name_synthetic(flag, name, &addr))
2118 {
2119 ans = 1;
2120 if (!dryrun)
2121 {
2122 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
2123 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2124 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
2125 anscount++;
2126 }
2127 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002128 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002129
2130 if (qtype == T_CNAME || qtype == T_ANY)
2131 {
2132 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002133 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002134 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00002135 if (!(crecp->flags & F_DNSSECOK))
2136 sec_data = 0;
2137
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002138 ans = 1;
2139 if (!dryrun)
2140 {
2141 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2142 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2143 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01002144 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002145 anscount++;
2146 }
2147 }
2148 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002149
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002150 if (qtype == T_MX || qtype == T_ANY)
2151 {
2152 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00002153 for (rec = daemon->mxnames; rec; rec = rec->next)
2154 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002155 {
2156 ans = found = 1;
2157 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002158 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002159 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002160 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00002161 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2162 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
2163 {
2164 anscount++;
2165 if (rec->target)
2166 rec->offset = offset;
2167 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002168 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002169 }
2170
Simon Kelley28866e92011-02-14 20:19:14 +00002171 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002172 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002173 {
2174 ans = 1;
2175 if (!dryrun)
2176 {
Simon Kelley28866e92011-02-14 20:19:14 +00002177 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002178 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
2179 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00002180 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002181 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002182 }
2183 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002184 }
2185
2186 if (qtype == T_SRV || qtype == T_ANY)
2187 {
2188 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00002189 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
2190
Simon Kelley0a852542005-03-23 20:28:59 +00002191 for (rec = daemon->mxnames; rec; rec = rec->next)
2192 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002193 {
2194 found = ans = 1;
2195 if (!dryrun)
2196 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002197 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002198 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002199 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00002200 &offset, T_SRV, C_IN, "sssd",
2201 rec->priority, rec->weight, rec->srvport, rec->target))
2202 {
2203 anscount++;
2204 if (rec->target)
2205 rec->offset = offset;
2206 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002207 }
Simon Kelley28866e92011-02-14 20:19:14 +00002208
2209 /* unlink first SRV record found */
2210 if (!move)
2211 {
2212 move = rec;
2213 *up = rec->next;
2214 }
2215 else
2216 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002217 }
Simon Kelley28866e92011-02-14 20:19:14 +00002218 else
2219 up = &rec->next;
2220
2221 /* put first SRV record back at the end. */
2222 if (move)
2223 {
2224 *up = move;
2225 move->next = NULL;
2226 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002227
Simon Kelley28866e92011-02-14 20:19:14 +00002228 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002229 {
2230 ans = 1;
2231 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002232 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002233 }
2234 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002235
2236 if (qtype == T_NAPTR || qtype == T_ANY)
2237 {
2238 struct naptr *na;
2239 for (na = daemon->naptr; na; na = na->next)
2240 if (hostname_isequal(name, na->name))
2241 {
2242 ans = 1;
2243 if (!dryrun)
2244 {
Simon Kelley28866e92011-02-14 20:19:14 +00002245 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01002246 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2247 NULL, T_NAPTR, C_IN, "sszzzd",
2248 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
2249 anscount++;
2250 }
2251 }
2252 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002253
2254 if (qtype == T_MAILB)
2255 ans = 1, nxdomain = 1;
2256
Simon Kelley28866e92011-02-14 20:19:14 +00002257 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002258 {
2259 ans = 1;
2260 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002261 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002262 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002263 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002264
2265 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002266 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002267 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002268
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002269 if (dryrun)
2270 {
2271 dryrun = 0;
2272 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002273 }
2274
Simon Kelley0a852542005-03-23 20:28:59 +00002275 /* create an additional data section, for stuff in SRV and MX record replies. */
2276 for (rec = daemon->mxnames; rec; rec = rec->next)
2277 if (rec->offset != 0)
2278 {
2279 /* squash dupes */
2280 struct mx_srv_record *tmp;
2281 for (tmp = rec->next; tmp; tmp = tmp->next)
2282 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2283 tmp->offset = 0;
2284
2285 crecp = NULL;
2286 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2287 {
Simon Kelley0a852542005-03-23 20:28:59 +00002288#ifdef HAVE_IPV6
2289 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2290#else
2291 int type = T_A;
2292#endif
2293 if (crecp->flags & F_NEG)
2294 continue;
2295
Simon Kelley9009d742008-11-14 20:04:27 +00002296 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2297 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002298 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2299 addncount++;
2300 }
2301 }
2302
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002303 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002304 /* clear authoritative and truncated flags, set QR flag */
2305 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2306 /* set RA flag */
2307 header->hb4 |= HB4_RA;
2308
2309 /* authoritive - only hosts and DHCP derived names. */
2310 if (auth)
2311 header->hb3 |= HB3_AA;
2312
2313 /* truncation */
2314 if (trunc)
2315 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002316
Simon Kelley45cca582013-10-15 10:20:13 +01002317 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002318 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002319 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002320 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002321 header->ancount = htons(anscount);
2322 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002323 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00002324
Simon Kelleya25720a2014-01-14 23:13:55 +00002325 len = ansp - (unsigned char *)header;
2326
2327 if (have_pseudoheader)
Simon Kelleye243c072014-02-06 18:14:09 +00002328 len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
2329
Simon Kelley83349b82014-02-10 21:02:01 +00002330 if (*ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00002331 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00002332 else
2333 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00002334
Simon Kelley7c286122014-01-27 21:38:11 +00002335 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002336}
2337