blob: 5828055caa5db86f00919d43a2aeb9a47d312e2d [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 }
80 else if (label_type == 0x80)
81 return 0; /* reserved */
82 else if (label_type == 0x40)
83 { /* ELT */
84 unsigned int count, digs;
85
86 if ((l & 0x3f) != 1)
87 return 0; /* we only understand bitstrings */
88
Simon Kelley394ff492015-03-29 22:17:14 +010089 if (!isExtract)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000090 return 0; /* Cannot compare bitsrings */
91
92 count = *p++;
93 if (count == 0)
94 count = 256;
95 digs = ((count-1)>>2)+1;
96
Simon Kelleyb8f16552015-04-22 21:14:31 +010097 /* output is \[x<hex>/siz]. which is digs+6/7/8 chars */
98 namelen += digs+6;
99 if (count > 9)
100 namelen++;
101 if (count > 99)
102 namelen++;
103 if (namelen+1 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000104 return 0;
Simon Kelleyb8f16552015-04-22 21:14:31 +0100105
Simon Kelley9009d742008-11-14 20:04:27 +0000106 if (!CHECK_LEN(header, p, plen, (count-1)>>3))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107 return 0;
108
109 *cp++ = '\\';
110 *cp++ = '[';
111 *cp++ = 'x';
112 for (j=0; j<digs; j++)
113 {
114 unsigned int dig;
115 if (j%2 == 0)
116 dig = *p >> 4;
117 else
118 dig = *p++ & 0x0f;
119
120 *cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
121 }
Simon Kelley3d8df262005-08-29 12:19:27 +0100122 cp += sprintf((char *)cp, "/%d]", count);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000123 /* do this here to overwrite the zero char from sprintf */
124 *cp++ = '.';
125 }
126 else
127 { /* label_type = 0 -> label. */
Simon Kelleyb8f16552015-04-22 21:14:31 +0100128 namelen += l;
129 if (namelen+1 >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000130 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000131 if (!CHECK_LEN(header, p, plen, l))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000132 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +0000133
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000134 for(j=0; j<l; j++, p++)
135 if (isExtract)
136 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100137 unsigned char c = *p;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100138#ifdef HAVE_DNSSEC
139 if (option_bool(OPT_DNSSEC_VALID))
140 {
141 if (c == 0 || c == '.' || c == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +0100142 {
143 *cp++ = NAME_ESCAPE;
144 *cp++ = c+1;
145 }
146 else
147 *cp++ = c;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100148 }
149 else
150#endif
Simon Kelley394ff492015-03-29 22:17:14 +0100151 if (c != 0 && c != '.')
152 *cp++ = c;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000153 else
154 return 0;
155 }
156 else
157 {
158 unsigned char c1 = *cp, c2 = *p;
159
160 if (c1 == 0)
161 retvalue = 2;
162 else
163 {
164 cp++;
165 if (c1 >= 'A' && c1 <= 'Z')
166 c1 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100167#ifdef HAVE_DNSSEC
168 if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +0100169 c1 = (*cp++)-1;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100170#endif
171
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000172 if (c2 >= 'A' && c2 <= 'Z')
173 c2 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100174
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000175 if (c1 != c2)
176 retvalue = 2;
177 }
178 }
179
180 if (isExtract)
181 *cp++ = '.';
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000182 else if (*cp != 0 && *cp++ != '.')
183 retvalue = 2;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000184 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000185 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000186}
187
188/* Max size of input string (for IPv6) is 75 chars.) */
189#define MAXARPANAME 75
Simon Kelley4f7b3042012-11-28 21:27:02 +0000190int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000191{
192 int j;
193 char name[MAXARPANAME+1], *cp1;
194 unsigned char *addr = (unsigned char *)addrp;
195 char *lastchunk = NULL, *penchunk = NULL;
196
197 if (strlen(namein) > MAXARPANAME)
198 return 0;
199
200 memset(addrp, 0, sizeof(struct all_addr));
201
202 /* turn name into a series of asciiz strings */
203 /* j counts no of labels */
204 for(j = 1,cp1 = name; *namein; cp1++, namein++)
205 if (*namein == '.')
206 {
207 penchunk = lastchunk;
208 lastchunk = cp1 + 1;
209 *cp1 = 0;
210 j++;
211 }
212 else
213 *cp1 = *namein;
214
215 *cp1 = 0;
216
217 if (j<3)
218 return 0;
219
220 if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
221 {
222 /* IP v4 */
223 /* address arives as a name of the form
224 www.xxx.yyy.zzz.in-addr.arpa
225 some of the low order address octets might be missing
226 and should be set to zero. */
227 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
228 {
229 /* check for digits only (weeds out things like
230 50.0/24.67.28.64.in-addr.arpa which are used
231 as CNAME targets according to RFC 2317 */
232 char *cp;
233 for (cp = cp1; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000234 if (!isdigit((unsigned char)*cp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000235 return 0;
236
237 addr[3] = addr[2];
238 addr[2] = addr[1];
239 addr[1] = addr[0];
240 addr[0] = atoi(cp1);
241 }
242
243 return F_IPV4;
244 }
245#ifdef HAVE_IPV6
246 else if (hostname_isequal(penchunk, "ip6") &&
247 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
248 {
249 /* IP v6:
250 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
251 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
252
253 Note that most of these the various reprentations are obsolete and
254 left-over from the many DNS-for-IPv6 wars. We support all the formats
255 that we can since there is no reason not to.
256 */
257
258 if (*name == '\\' && *(name+1) == '[' &&
259 (*(name+2) == 'x' || *(name+2) == 'X'))
260 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000261 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000262 {
263 char xdig[2];
264 xdig[0] = *cp1;
265 xdig[1] = 0;
266 if (j%2)
267 addr[j/2] |= strtol(xdig, NULL, 16);
268 else
269 addr[j/2] = strtol(xdig, NULL, 16) << 4;
270 }
271
272 if (*cp1 == '/' && j == 32)
273 return F_IPV6;
274 }
275 else
276 {
277 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
278 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000279 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000280 return 0;
281
282 for (j = sizeof(struct all_addr)-1; j>0; j--)
283 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
284 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
285 }
286
287 return F_IPV6;
288 }
289 }
290#endif
291
292 return 0;
293}
294
Giovanni Bajo32f82c62012-04-28 01:01:16 +0200295unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100296{
297 while(1)
298 {
Simon Kelley9009d742008-11-14 20:04:27 +0000299 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100300
Simon Kelley9009d742008-11-14 20:04:27 +0000301 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100302 return NULL;
303
Simon Kelley9009d742008-11-14 20:04:27 +0000304 label_type = (*ansp) & 0xc0;
305
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100306 if (label_type == 0xc0)
307 {
308 /* pointer for compression. */
309 ansp += 2;
310 break;
311 }
312 else if (label_type == 0x80)
313 return NULL; /* reserved */
314 else if (label_type == 0x40)
315 {
316 /* Extended label type */
317 unsigned int count;
318
Simon Kelley9009d742008-11-14 20:04:27 +0000319 if (!CHECK_LEN(header, ansp, plen, 2))
320 return NULL;
321
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100322 if (((*ansp++) & 0x3f) != 1)
323 return NULL; /* we only understand bitstrings */
324
325 count = *(ansp++); /* Bits in bitstring */
326
327 if (count == 0) /* count == 0 means 256 bits */
328 ansp += 32;
329 else
330 ansp += ((count-1)>>3)+1;
331 }
332 else
333 { /* label type == 0 Bottom six bits is length */
334 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000335
336 if (!ADD_RDLEN(header, ansp, plen, len))
337 return NULL;
338
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100339 if (len == 0)
340 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100341 }
342 }
Simon Kelley9009d742008-11-14 20:04:27 +0000343
344 if (!CHECK_LEN(header, ansp, plen, extrabytes))
345 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100346
347 return ansp;
348}
349
Simon Kelley4f7b3042012-11-28 21:27:02 +0000350unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000351{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100352 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000353 unsigned char *ansp = (unsigned char *)(header+1);
354
Simon Kelley5aabfc72007-08-29 11:24:47 +0100355 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000356 {
Simon Kelley9009d742008-11-14 20:04:27 +0000357 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100358 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000359 ansp += 4; /* class and type */
360 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000361
362 return ansp;
363}
364
Simon Kelley5107ace2014-02-23 10:48:32 +0000365unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100366{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100367 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100368
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100369 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100370 {
Simon Kelley9009d742008-11-14 20:04:27 +0000371 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100372 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100373 ansp += 8; /* type, class, TTL */
374 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000375 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100376 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100377 }
378
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100379 return ansp;
380}
381
Simon Kelley0a852542005-03-23 20:28:59 +0000382/* CRC the question section. This is used to safely detect query
383 retransmision and to detect answers to questions we didn't ask, which
384 might be poisoning attacks. Note that we decode the name rather
385 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000386 We ignore case in the names for the same reason. Return all-ones
387 if there is not question section. */
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000388#ifndef HAVE_DNSSEC
Simon Kelley572b41e2011-02-18 18:11:18 +0000389unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100390{
Simon Kelley91dccd02005-03-31 17:48:32 +0100391 int q;
392 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000393 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100394
Simon Kelley5aabfc72007-08-29 11:24:47 +0100395 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000396 {
Simon Kelley9009d742008-11-14 20:04:27 +0000397 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000398 return crc; /* bad packet */
399
Simon Kelley3d8df262005-08-29 12:19:27 +0100400 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000401 {
402 int i = 8;
403 char c = *p1;
404
405 if (c >= 'A' && c <= 'Z')
406 c += 'a' - 'A';
407
408 crc ^= c << 24;
409 while (i--)
410 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
411 }
412
413 /* CRC the class and type as well */
414 for (p1 = p; p1 < p+4; p1++)
415 {
416 int i = 8;
417 crc ^= *p1 << 24;
418 while (i--)
419 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
420 }
421
422 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000423 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000424 return crc; /* bad packet */
425 }
426
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100427 return crc;
428}
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000429#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100430
Simon Kelley572b41e2011-02-18 18:11:18 +0000431size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100432{
433 unsigned char *ansp = skip_questions(header, plen);
434
Simon Kelley9009d742008-11-14 20:04:27 +0000435 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100436 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000437 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100438
439 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
440 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000441 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100442
Simon Kelley36717ee2004-09-20 19:20:58 +0100443 /* restore pseudoheader */
444 if (pheader && ntohs(header->arcount) == 0)
445 {
446 /* must use memmove, may overlap */
447 memmove(ansp, pheader, hlen);
448 header->arcount = htons(1);
449 ansp += hlen;
450 }
451
452 return ansp - (unsigned char *)header;
453}
454
Simon Kelley572b41e2011-02-18 18:11:18 +0000455unsigned 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 +0100456{
457 /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
Simon Kelley832af0b2007-01-21 20:01:28 +0000458 also return length of pseudoheader in *len and pointer to the UDP size in *p
459 Finally, check to see if a packet is signed. If it is we cannot change a single bit before
460 forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100461
462 int i, arcount = ntohs(header->arcount);
Simon Kelley832af0b2007-01-21 20:01:28 +0000463 unsigned char *ansp = (unsigned char *)(header+1);
464 unsigned short rdlen, type, class;
465 unsigned char *ret = NULL;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000466
467 if (is_sign)
Simon Kelley832af0b2007-01-21 20:01:28 +0000468 {
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000469 *is_sign = 0;
470
Simon Kelley572b41e2011-02-18 18:11:18 +0000471 if (OPCODE(header) == QUERY)
Simon Kelley832af0b2007-01-21 20:01:28 +0000472 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100473 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000474 {
Simon Kelley9009d742008-11-14 20:04:27 +0000475 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000476 return NULL;
477
478 GETSHORT(type, ansp);
479 GETSHORT(class, ansp);
480
481 if (class == C_IN && type == T_TKEY)
482 *is_sign = 1;
483 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000484 }
485 }
486 else
487 {
488 if (!(ansp = skip_questions(header, plen)))
489 return NULL;
490 }
491
492 if (arcount == 0)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100493 return NULL;
494
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100495 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
496 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000497
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100498 for (i = 0; i < arcount; i++)
499 {
Simon Kelley36717ee2004-09-20 19:20:58 +0100500 unsigned char *save, *start = ansp;
Simon Kelley9009d742008-11-14 20:04:27 +0000501 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100502 return NULL;
503
504 GETSHORT(type, ansp);
505 save = ansp;
Simon Kelley832af0b2007-01-21 20:01:28 +0000506 GETSHORT(class, ansp);
507 ansp += 4; /* TTL */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100508 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000509 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100510 return NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +0000511 if (type == T_OPT)
Simon Kelley36717ee2004-09-20 19:20:58 +0100512 {
513 if (len)
514 *len = ansp - start;
515 if (p)
516 *p = save;
Simon Kelley832af0b2007-01-21 20:01:28 +0000517 ret = start;
Simon Kelley36717ee2004-09-20 19:20:58 +0100518 }
Simon Kelley832af0b2007-01-21 20:01:28 +0000519 else if (is_sign &&
520 i == arcount - 1 &&
521 class == C_ANY &&
Simon Kelley5f8e58f2014-01-09 17:31:19 +0000522 type == T_TSIG)
Simon Kelley832af0b2007-01-21 20:01:28 +0000523 *is_sign = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100524 }
525
Simon Kelley832af0b2007-01-21 20:01:28 +0000526 return ret;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100527}
Simon Kelley28866e92011-02-14 20:19:14 +0000528
529struct macparm {
530 unsigned char *limit;
Simon Kelley572b41e2011-02-18 18:11:18 +0000531 struct dns_header *header;
Simon Kelley28866e92011-02-14 20:19:14 +0000532 size_t plen;
533 union mysockaddr *l3;
534};
Simon Kelleyed4c0762013-10-08 20:46:34 +0100535
536static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
Simon Kelley3a237152013-12-12 12:15:50 +0000537 int optno, unsigned char *opt, size_t optlen, int set_do)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100538{
539 unsigned char *lenp, *datap, *p;
Simon Kelleya25720a2014-01-14 23:13:55 +0000540 int rdlen, is_sign;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100541
Simon Kelleya25720a2014-01-14 23:13:55 +0000542 if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
Simon Kelleyed4c0762013-10-08 20:46:34 +0100543 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000544 if (is_sign)
545 return plen;
546
Simon Kelleyed4c0762013-10-08 20:46:34 +0100547 /* We are adding the pseudoheader */
548 if (!(p = skip_questions(header, plen)) ||
549 !(p = skip_section(p,
Simon Kelleya25720a2014-01-14 23:13:55 +0000550 ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
Simon Kelleyed4c0762013-10-08 20:46:34 +0100551 header, plen)))
552 return plen;
553 *p++ = 0; /* empty name */
554 PUTSHORT(T_OPT, p);
555 PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
Simon Kelley3a237152013-12-12 12:15:50 +0000556 PUTSHORT(0, p); /* extended RCODE and version */
557 PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100558 lenp = p;
559 PUTSHORT(0, p); /* RDLEN */
560 rdlen = 0;
561 if (((ssize_t)optlen) > (limit - (p + 4)))
562 return plen; /* Too big */
Simon Kelleya25720a2014-01-14 23:13:55 +0000563 header->arcount = htons(ntohs(header->arcount) + 1);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100564 datap = p;
565 }
566 else
567 {
Simon Kelleya25720a2014-01-14 23:13:55 +0000568 int i;
Simon Kelley3a237152013-12-12 12:15:50 +0000569 unsigned short code, len, flags;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100570
Simon Kelleya25720a2014-01-14 23:13:55 +0000571 /* Must be at the end, if exists */
Simon Kelleyed4c0762013-10-08 20:46:34 +0100572 if (ntohs(header->arcount) != 1 ||
Simon Kelleyed4c0762013-10-08 20:46:34 +0100573 is_sign ||
574 (!(p = skip_name(p, header, plen, 10))))
575 return plen;
576
Simon Kelley3a237152013-12-12 12:15:50 +0000577 p += 6; /* skip UDP length and RCODE */
578 GETSHORT(flags, p);
579 if (set_do)
580 {
581 p -=2;
582 PUTSHORT(flags | 0x8000, p);
583 }
584
Simon Kelleyed4c0762013-10-08 20:46:34 +0100585 lenp = p;
586 GETSHORT(rdlen, p);
587 if (!CHECK_LEN(header, p, plen, rdlen))
588 return plen; /* bad packet */
589 datap = p;
590
Simon Kelley3a237152013-12-12 12:15:50 +0000591 /* no option to add */
592 if (optno == 0)
593 return plen;
594
Simon Kelleyed4c0762013-10-08 20:46:34 +0100595 /* check if option already there */
596 for (i = 0; i + 4 < rdlen; i += len + 4)
597 {
598 GETSHORT(code, p);
599 GETSHORT(len, p);
600 if (code == optno)
601 return plen;
602 p += len;
603 }
604
605 if (((ssize_t)optlen) > (limit - (p + 4)))
606 return plen; /* Too big */
607 }
608
Simon Kelley0fc2f312014-01-08 10:26:58 +0000609 if (optno != 0)
610 {
611 PUTSHORT(optno, p);
612 PUTSHORT(optlen, p);
613 memcpy(p, opt, optlen);
614 p += optlen;
615 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100616
617 PUTSHORT(p - datap, lenp);
618 return p - (unsigned char *)header;
619
620}
Simon Kelley28866e92011-02-14 20:19:14 +0000621
622static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
623{
624 struct macparm *parm = parmv;
625 int match = 0;
Simon Kelleyed4c0762013-10-08 20:46:34 +0100626
Simon Kelley28866e92011-02-14 20:19:14 +0000627 if (family == parm->l3->sa.sa_family)
628 {
Simon Kelley613ad152014-02-25 23:02:28 +0000629 if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000630 match = 1;
631#ifdef HAVE_IPV6
632 else
Simon Kelley613ad152014-02-25 23:02:28 +0000633 if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
Simon Kelley28866e92011-02-14 20:19:14 +0000634 match = 1;
635#endif
636 }
637
638 if (!match)
639 return 1; /* continue */
Simon Kelley28866e92011-02-14 20:19:14 +0000640
Simon Kelley3a237152013-12-12 12:15:50 +0000641 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 +0000642
643 return 0; /* done */
644}
645
Simon Kelley572b41e2011-02-18 18:11:18 +0000646size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
Simon Kelley28866e92011-02-14 20:19:14 +0000647{
648 struct macparm parm;
649
650/* Must have an existing pseudoheader as the only ar-record,
651 or have no ar-records. Must also not be signed */
652
653 if (ntohs(header->arcount) > 1)
654 return plen;
655
656 parm.header = header;
657 parm.limit = (unsigned char *)limit;
658 parm.plen = plen;
659 parm.l3 = l3;
660
661 iface_enumerate(AF_UNSPEC, &parm, filter_mac);
662
663 return parm.plen;
664}
665
Simon Kelleyed4c0762013-10-08 20:46:34 +0100666struct subnet_opt {
667 u16 family;
668 u8 source_netmask, scope_netmask;
669#ifdef HAVE_IPV6
670 u8 addr[IN6ADDRSZ];
671#else
672 u8 addr[INADDRSZ];
673#endif
674};
675
Simon Kelley44de6492013-11-06 11:36:57 +0000676static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100677{
678 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
679
680 int len;
681 void *addrp;
682
Simon Kelleyed4c0762013-10-08 20:46:34 +0100683#ifdef HAVE_IPV6
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100684 if (source->sa.sa_family == AF_INET6)
Simon Kelleyed4c0762013-10-08 20:46:34 +0100685 {
686 opt->family = htons(2);
687 opt->source_netmask = daemon->addr6_netmask;
688 addrp = &source->in6.sin6_addr;
689 }
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100690 else
Simon Kelleyed4c0762013-10-08 20:46:34 +0100691#endif
Simon Kelley24b5a5d2013-10-11 15:19:28 +0100692 {
693 opt->family = htons(1);
694 opt->source_netmask = daemon->addr4_netmask;
695 addrp = &source->in.sin_addr;
696 }
Simon Kelleyed4c0762013-10-08 20:46:34 +0100697
698 opt->scope_netmask = 0;
699 len = 0;
700
701 if (opt->source_netmask != 0)
702 {
703 len = ((opt->source_netmask - 1) >> 3) + 1;
704 memcpy(opt->addr, addrp, len);
705 if (opt->source_netmask & 7)
706 opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
707 }
708
709 return len + 4;
710}
711
712size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source)
713{
714 /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
715
716 int len;
717 struct subnet_opt opt;
718
719 len = calc_subnet_opt(&opt, source);
Simon Kelley3a237152013-12-12 12:15:50 +0000720 return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
Simon Kelleyed4c0762013-10-08 20:46:34 +0100721}
Simon Kelley3a237152013-12-12 12:15:50 +0000722
723#ifdef HAVE_DNSSEC
724size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
725{
726 return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1);
727}
728#endif
729
Simon Kelleyed4c0762013-10-08 20:46:34 +0100730int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
731{
732 /* Section 9.2, Check that subnet option in reply matches. */
733
734
735 int len, calc_len;
736 struct subnet_opt opt;
737 unsigned char *p;
738 int code, i, rdlen;
739
740 calc_len = calc_subnet_opt(&opt, peer);
741
742 if (!(p = skip_name(pseudoheader, header, plen, 10)))
743 return 1;
744
745 p += 8; /* skip UDP length and RCODE */
746
747 GETSHORT(rdlen, p);
748 if (!CHECK_LEN(header, p, plen, rdlen))
749 return 1; /* bad packet */
750
751 /* check if option there */
752 for (i = 0; i + 4 < rdlen; i += len + 4)
753 {
754 GETSHORT(code, p);
755 GETSHORT(len, p);
756 if (code == EDNS0_OPTION_CLIENT_SUBNET)
757 {
758 /* make sure this doesn't mismatch. */
759 opt.scope_netmask = p[3];
760 if (len != calc_len || memcmp(p, &opt, len) != 0)
761 return 0;
762 }
763 p += len;
764 }
765
766 return 1;
767}
768
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000769/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100770int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000771{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100772 in_addr_t ip_addr = ntohl(addr.s_addr);
773
774 return
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100775 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100776 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
777 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
778 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
779 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000780}
Simon Kelley1cff1662004-03-12 08:12:58 +0000781
Simon Kelley6938f342014-01-26 22:47:39 +0000782static 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 +0000783{
784 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000785
786 for (i = count; i != 0; i--)
787 {
Simon Kelley28866e92011-02-14 20:19:14 +0000788 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100789 {
790 if (!extract_name(header, qlen, &p, name, 1, 10))
791 return 0;
792 }
793 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000794 return 0; /* bad packet */
795
796 GETSHORT(qtype, p);
797 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100798 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000799 GETSHORT(rdlen, p);
800
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100801 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000802 {
803 struct doctor *doctor;
804 struct in_addr addr;
805
Simon Kelley9009d742008-11-14 20:04:27 +0000806 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
807 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100808
809 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000810 memcpy(&addr, p, INADDRSZ);
811
812 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000813 {
814 if (doctor->end.s_addr == 0)
815 {
816 if (!is_same_net(doctor->in, addr, doctor->mask))
817 continue;
818 }
819 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
820 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
821 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100822
Simon Kelley73a08a22009-02-05 20:28:08 +0000823 addr.s_addr &= ~doctor->mask.s_addr;
824 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
825 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000826 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000827 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000828 memcpy(p, &addr, INADDRSZ);
829 break;
830 }
Simon Kelley824af852008-02-12 20:43:05 +0000831 }
Simon Kelley28866e92011-02-14 20:19:14 +0000832 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100833 {
834 unsigned char *p1 = p;
835 if (!CHECK_LEN(header, p1, qlen, rdlen))
836 return 0;
837 while ((p1 - p) < rdlen)
838 {
839 unsigned int i, len = *p1;
840 unsigned char *p2 = p1;
841 /* make counted string zero-term and sanitise */
842 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100843 {
844 if (!isprint((int)*(p2+1)))
845 break;
846
847 *p2 = *(p2+1);
848 p2++;
849 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100850 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000851 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100852 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100853 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100854 *p1 = len;
855 p1 += len+1;
856 }
857 }
Simon Kelley824af852008-02-12 20:43:05 +0000858
Simon Kelley9009d742008-11-14 20:04:27 +0000859 if (!ADD_RDLEN(header, p, qlen, rdlen))
860 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000861 }
862
863 return p;
864}
865
Simon Kelley6938f342014-01-26 22:47:39 +0000866static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000867{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100868 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100870 unsigned long ttl, minttl = ULONG_MAX;
871 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000872
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100873 /* first move to NS section and find TTL from any SOA section */
874 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000875 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000876 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000877
Simon Kelley5aabfc72007-08-29 11:24:47 +0100878 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000879 {
Simon Kelley9009d742008-11-14 20:04:27 +0000880 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100881 return 0; /* bad packet */
882
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000883 GETSHORT(qtype, p);
884 GETSHORT(qclass, p);
885 GETLONG(ttl, p);
886 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100887
888 if ((qclass == C_IN) && (qtype == T_SOA))
889 {
890 found_soa = 1;
891 if (ttl < minttl)
892 minttl = ttl;
893
894 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000895 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100896 return 0;
897 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000898 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100899 return 0;
900 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
901
902 GETLONG(ttl, p); /* minTTL */
903 if (ttl < minttl)
904 minttl = ttl;
905 }
Simon Kelley9009d742008-11-14 20:04:27 +0000906 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100907 return 0; /* bad packet */
908 }
Simon Kelley9009d742008-11-14 20:04:27 +0000909
Simon Kelley6938f342014-01-26 22:47:39 +0000910 /* rewrite addresses in additional section too */
911 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000912 return 0;
913
914 if (!found_soa)
915 minttl = daemon->neg_ttl;
916
917 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100918}
919
920/* Note that the following code can create CNAME chains that don't point to a real record,
921 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 +0000922 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100923 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000924int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelley6938f342014-01-26 22:47:39 +0000925 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100926{
Simon Kelley824af852008-02-12 20:43:05 +0000927 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100928 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000929 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100930 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000931#ifdef HAVE_IPSET
932 char **ipsets_cur;
933#else
934 (void)ipsets; /* unused */
935#endif
936
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100937 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000938
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100939 /* 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 +0000940 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000941 {
942 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000943 ttl = find_soa(header, qlen, name, doctored);
944#ifdef HAVE_DNSSEC
Simon Kelleyd1fbb772014-03-01 20:08:58 +0000945 if (*doctored && secure)
946 return 0;
Simon Kelley6938f342014-01-26 22:47:39 +0000947#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000948 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100949
950 /* go through the questions. */
951 p = (unsigned char *)(header+1);
952
Simon Kelley5aabfc72007-08-29 11:24:47 +0100953 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100954 {
Simon Kelley1fbe4d22014-03-01 20:03:47 +0000955 int found = 0, cname_count = CNAME_CHAIN;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100956 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000957 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0435d042014-01-08 18:22:37 +0000958 int secflag = secure ? F_DNSSECOK : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000959 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000960
Simon Kelley824af852008-02-12 20:43:05 +0000961 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000962 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000963 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100964
965 GETSHORT(qtype, p);
966 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000967
968 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100969 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100971 /* PTRs: we chase CNAMEs here, since we have no way to
972 represent them in the cache. */
973 if (qtype == T_PTR)
974 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000975 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100976
977 if (!name_encoding)
978 continue;
979
980 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000981 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100982 cname_loop:
983 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000984 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100985
Simon Kelley5aabfc72007-08-29 11:24:47 +0100986 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100987 {
Simon Kelley824af852008-02-12 20:43:05 +0000988 unsigned char *tmp = namep;
989 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000990 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
991 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000992 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100993
994 GETSHORT(aqtype, p1);
995 GETSHORT(aqclass, p1);
996 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100997 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
998 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000999 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001000 PUTLONG(daemon->max_ttl, p1);
1001 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001002 GETSHORT(ardlen, p1);
1003 endrr = p1+ardlen;
1004
1005 /* TTL of record is minimum of CNAMES and PTR */
1006 if (attl < cttl)
1007 cttl = attl;
1008
1009 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
1010 {
Simon Kelley9009d742008-11-14 20:04:27 +00001011 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +00001012 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001013
1014 if (aqtype == T_CNAME)
1015 {
Simon Kelleyd1fbb772014-03-01 20:08:58 +00001016 if (!cname_count-- || secure)
1017 return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001018 goto cname_loop;
1019 }
1020
Simon Kelley0435d042014-01-08 18:22:37 +00001021 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001022 found = 1;
1023 }
1024
1025 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +00001026 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +00001027 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001028 }
1029 }
1030
Simon Kelley28866e92011-02-14 20:19:14 +00001031 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001032 {
1033 if (!searched_soa)
1034 {
1035 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001036 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001037 }
1038 if (ttl)
Simon Kelley0435d042014-01-08 18:22:37 +00001039 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001040 }
1041 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001042 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001043 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001044 /* everything other than PTR */
1045 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001046 int addrlen;
1047
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001048 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001049 {
1050 addrlen = INADDRSZ;
1051 flags |= F_IPV4;
1052 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001053#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001054 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001055 {
1056 addrlen = IN6ADDRSZ;
1057 flags |= F_IPV6;
1058 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001059#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001060 else
1061 continue;
1062
Simon Kelley45cca582013-10-15 10:20:13 +01001063 cname_loop1:
1064 if (!(p1 = skip_questions(header, qlen)))
1065 return 0;
1066
1067 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001068 {
Simon Kelley45cca582013-10-15 10:20:13 +01001069 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
1070 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001071
Simon Kelley45cca582013-10-15 10:20:13 +01001072 GETSHORT(aqtype, p1);
1073 GETSHORT(aqclass, p1);
1074 GETLONG(attl, p1);
1075 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001076 {
Simon Kelley45cca582013-10-15 10:20:13 +01001077 (p1) -= 4;
1078 PUTLONG(daemon->max_ttl, p1);
1079 }
1080 GETSHORT(ardlen, p1);
1081 endrr = p1+ardlen;
1082
1083 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
1084 {
1085 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001086 {
Simon Kelley45cca582013-10-15 10:20:13 +01001087 if (!cname_count--)
1088 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +00001089 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001090 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001091 {
Simon Kelley45cca582013-10-15 10:20:13 +01001092 newc->addr.cname.target.cache = NULL;
Simon Kelley03431d62014-03-20 16:25:43 +00001093 /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
1094 newc->addr.cname.uid = 1;
Simon Kelley45cca582013-10-15 10:20:13 +01001095 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001096 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001097 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001098 cpp->addr.cname.uid = newc->uid;
1099 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001100 }
Simon Kelley45cca582013-10-15 10:20:13 +01001101
1102 cpp = newc;
1103 if (attl < cttl)
1104 cttl = attl;
1105
1106 if (!extract_name(header, qlen, &p1, name, 1, 0))
1107 return 0;
1108 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001109 }
Simon Kelley45cca582013-10-15 10:20:13 +01001110 else if (!(flags & F_NXDOMAIN))
1111 {
1112 found = 1;
1113
1114 /* copy address into aligned storage */
1115 if (!CHECK_LEN(header, p1, qlen, addrlen))
1116 return 0; /* bad packet */
1117 memcpy(&addr, p1, addrlen);
1118
1119 /* check for returned address in private space */
1120 if (check_rebind &&
1121 (flags & F_IPV4) &&
1122 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
1123 return 1;
1124
1125#ifdef HAVE_IPSET
1126 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
1127 {
1128 ipsets_cur = ipsets;
1129 while (*ipsets_cur)
Wang Jian49752b92014-03-28 20:52:47 +00001130 {
Simon Kelleyb7639d52014-03-29 09:20:07 +00001131 log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
Wang Jian49752b92014-03-28 20:52:47 +00001132 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
1133 }
Simon Kelley45cca582013-10-15 10:20:13 +01001134 }
1135#endif
1136
Simon Kelley0435d042014-01-08 18:22:37 +00001137 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +01001138 if (newc && cpp)
1139 {
1140 cpp->addr.cname.target.cache = newc;
1141 cpp->addr.cname.uid = newc->uid;
1142 }
1143 cpp = NULL;
1144 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001145 }
Simon Kelley45cca582013-10-15 10:20:13 +01001146
1147 p1 = endrr;
1148 if (!CHECK_LEN(header, p1, qlen, 0))
1149 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001150 }
1151
Simon Kelley28866e92011-02-14 20:19:14 +00001152 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001153 {
1154 if (!searched_soa)
1155 {
1156 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +00001157 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001158 }
1159 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +00001160 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001161 if (ttl || cpp)
1162 {
Simon Kelley0435d042014-01-08 18:22:37 +00001163 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
Simon Kelley26128d22004-11-14 16:43:54 +00001164 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001165 {
Simon Kelleyd56a6042013-10-11 14:39:03 +01001166 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001167 cpp->addr.cname.uid = newc->uid;
1168 }
1169 }
1170 }
1171 }
1172 }
1173
Simon Kelley1023dcb2012-04-09 18:00:08 +01001174 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +01001175 Don't cache replies from non-recursive nameservers, since we may get a
1176 reply containing a CNAME but not its target, even though the target
1177 does exist. */
1178 if (!(header->hb3 & HB3_TC) &&
1179 !(header->hb4 & HB4_CD) &&
1180 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +00001181 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +00001182 cache_end_insert();
1183
1184 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001185}
1186
1187/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +00001188 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +00001189unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001190{
1191 unsigned char *p = (unsigned char *)(header+1);
1192 int qtype, qclass;
1193
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001194 if (typep)
1195 *typep = 0;
1196
Simon Kelley572b41e2011-02-18 18:11:18 +00001197 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001198 return 0; /* must be exactly one query. */
1199
Simon Kelley9009d742008-11-14 20:04:27 +00001200 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001201 return 0; /* bad packet */
1202
1203 GETSHORT(qtype, p);
1204 GETSHORT(qclass, p);
1205
Simon Kelley0a852542005-03-23 20:28:59 +00001206 if (typep)
1207 *typep = qtype;
1208
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001209 if (qclass == C_IN)
1210 {
1211 if (qtype == T_A)
1212 return F_IPV4;
1213 if (qtype == T_AAAA)
1214 return F_IPV6;
1215 if (qtype == T_ANY)
1216 return F_IPV4 | F_IPV6;
1217 }
1218
1219 return F_QUERY;
1220}
1221
1222
Simon Kelley572b41e2011-02-18 18:11:18 +00001223size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +00001224 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001225{
Simon Kelleyad4a8ff2015-04-09 21:48:00 +01001226 unsigned char *p;
1227
1228 if (!(p = skip_questions(header, qlen)))
1229 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001230
Simon Kelley572b41e2011-02-18 18:11:18 +00001231 /* clear authoritative and truncated flags, set QR flag */
1232 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1233 /* set RA flag */
1234 header->hb4 |= HB4_RA;
1235
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001236 header->nscount = htons(0);
1237 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001238 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001239 if (flags == F_NEG)
Simon Kelley572b41e2011-02-18 18:11:18 +00001240 SET_RCODE(header, SERVFAIL); /* couldn't get memory */
Simon Kelley824af852008-02-12 20:43:05 +00001241 else if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +00001242 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001243 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +00001244 SET_RCODE(header, NXDOMAIN);
Simon Kelleyad4a8ff2015-04-09 21:48:00 +01001245 else if (flags == F_IPV4)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001246 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +00001247 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001248 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001249 header->hb3 |= HB3_AA;
1250 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 +00001251 }
1252#ifdef HAVE_IPV6
Simon Kelleyad4a8ff2015-04-09 21:48:00 +01001253 else if (flags == F_IPV6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001254 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001255 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001256 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +00001257 header->hb3 |= HB3_AA;
1258 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 +00001259 }
1260#endif
1261 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +00001262 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001263
1264 return p - (unsigned char *)header;
1265}
Simon Kelley36717ee2004-09-20 19:20:58 +01001266
1267/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001268int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001269{
1270 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +00001271 struct mx_srv_record *mx;
1272 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001273 struct interface_name *intr;
1274 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001275 struct naptr *naptr;
1276
Simon Kelley288df492014-09-18 21:48:51 +01001277 /* Note: the call to cache_find_by_name is intended to find any record which matches
1278 ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
1279 cache_find_by name ordinarily only returns records with an exact match on those bits (ie
1280 for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
1281
1282 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 +00001283 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +01001284 return 1;
1285
Simon Kelley7de060b2011-08-26 17:24:52 +01001286 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1287 if (hostname_isequal(name, naptr->name))
1288 return 1;
1289
1290 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +00001291 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001292 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001293
Simon Kelley0a852542005-03-23 20:28:59 +00001294 for (txt = daemon->txt; txt; txt = txt->next)
1295 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001296 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001297
1298 for (intr = daemon->int_names; intr; intr = intr->next)
1299 if (hostname_isequal(name, intr->name))
1300 return 1;
1301
1302 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1303 if (hostname_isequal(name, ptr->name))
1304 return 1;
1305
Simon Kelley36717ee2004-09-20 19:20:58 +01001306 return 0;
1307}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001308
1309/* Is the packet a reply with the answer address equal to addr?
1310 If so mung is into an NXDOMAIN reply and also put that information
1311 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001312int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001313 struct bogus_addr *baddr, time_t now)
1314{
1315 unsigned char *p;
1316 int i, qtype, qclass, rdlen;
1317 unsigned long ttl;
1318 struct bogus_addr *baddrp;
1319
1320 /* skip over questions */
1321 if (!(p = skip_questions(header, qlen)))
1322 return 0; /* bad packet */
1323
Simon Kelley5aabfc72007-08-29 11:24:47 +01001324 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001325 {
Simon Kelley9009d742008-11-14 20:04:27 +00001326 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001327 return 0; /* bad packet */
1328
1329 GETSHORT(qtype, p);
1330 GETSHORT(qclass, p);
1331 GETLONG(ttl, p);
1332 GETSHORT(rdlen, p);
1333
1334 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001335 {
1336 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1337 return 0;
1338
1339 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1340 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1341 {
1342 /* Found a bogus address. Insert that info here, since there no SOA record
1343 to get the ttl from in the normal processing */
1344 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001345 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001346 cache_end_insert();
1347
1348 return 1;
1349 }
1350 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001351
Simon Kelley9009d742008-11-14 20:04:27 +00001352 if (!ADD_RDLEN(header, p, qlen, rdlen))
1353 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001354 }
1355
1356 return 0;
1357}
1358
Glen Huang32fc6db2014-12-27 15:28:12 +00001359int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
1360{
1361 unsigned char *p;
1362 int i, qtype, qclass, rdlen;
1363 struct bogus_addr *baddrp;
1364
1365 /* skip over questions */
1366 if (!(p = skip_questions(header, qlen)))
1367 return 0; /* bad packet */
1368
1369 for (i = ntohs(header->ancount); i != 0; i--)
1370 {
1371 if (!(p = skip_name(p, header, qlen, 10)))
1372 return 0; /* bad packet */
1373
1374 GETSHORT(qtype, p);
1375 GETSHORT(qclass, p);
1376 p += 4; /* TTL */
1377 GETSHORT(rdlen, p);
1378
1379 if (qclass == C_IN && qtype == T_A)
1380 {
1381 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1382 return 0;
1383
1384 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1385 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1386 return 1;
1387 }
1388
1389 if (!ADD_RDLEN(header, p, qlen, rdlen))
1390 return 0;
1391 }
1392
1393 return 0;
1394}
1395
Simon Kelleyb75e9362012-12-07 11:50:41 +00001396int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001397 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001398{
1399 va_list ap;
1400 unsigned char *sav, *p = *pp;
1401 int j;
1402 unsigned short usval;
1403 long lval;
1404 char *sval;
1405
1406 if (truncp && *truncp)
1407 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001408
1409 va_start(ap, format); /* make ap point to 1st unamed argument */
1410
Simon Kelleyb75e9362012-12-07 11:50:41 +00001411 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001412 {
1413 PUTSHORT(nameoffset | 0xc000, p);
1414 }
1415 else
1416 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001417 char *name = va_arg(ap, char *);
1418 if (name)
1419 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001420 if (nameoffset < 0)
1421 {
1422 PUTSHORT(-nameoffset | 0xc000, p);
1423 }
1424 else
1425 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001426 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001427
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001428 PUTSHORT(type, p);
1429 PUTSHORT(class, p);
1430 PUTLONG(ttl, p); /* TTL */
1431
1432 sav = p; /* Save pointer to RDLength field */
1433 PUTSHORT(0, p); /* Placeholder RDLength */
1434
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001435 for (; *format; format++)
1436 switch (*format)
1437 {
1438#ifdef HAVE_IPV6
1439 case '6':
1440 sval = va_arg(ap, char *);
1441 memcpy(p, sval, IN6ADDRSZ);
1442 p += IN6ADDRSZ;
1443 break;
1444#endif
1445
1446 case '4':
1447 sval = va_arg(ap, char *);
1448 memcpy(p, sval, INADDRSZ);
1449 p += INADDRSZ;
1450 break;
1451
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001452 case 'b':
1453 usval = va_arg(ap, int);
1454 *p++ = usval;
1455 break;
1456
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001457 case 's':
1458 usval = va_arg(ap, int);
1459 PUTSHORT(usval, p);
1460 break;
1461
1462 case 'l':
1463 lval = va_arg(ap, long);
1464 PUTLONG(lval, p);
1465 break;
1466
1467 case 'd':
1468 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001469 if (offset)
1470 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001471 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001472 *p++ = 0;
1473 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001474
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001475 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001476 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001477 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001478 if (usval != 0)
1479 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001480 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001481 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001482
1483 case 'z':
1484 sval = va_arg(ap, char *);
1485 usval = sval ? strlen(sval) : 0;
1486 if (usval > 255)
1487 usval = 255;
1488 *p++ = (unsigned char)usval;
1489 memcpy(p, sval, usval);
1490 p += usval;
1491 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001492 }
1493
1494 va_end(ap); /* clean up variable argument pointer */
1495
1496 j = p - sav - 2;
1497 PUTSHORT(j, sav); /* Now, store real RDLength */
1498
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001499 /* check for overflow of buffer */
1500 if (limit && ((unsigned char *)limit - p) < 0)
1501 {
1502 if (truncp)
1503 *truncp = 1;
1504 return 0;
1505 }
1506
1507 *pp = p;
1508 return 1;
1509}
1510
Simon Kelley9009d742008-11-14 20:04:27 +00001511static unsigned long crec_ttl(struct crec *crecp, time_t now)
1512{
1513 /* Return 0 ttl for DHCP entries, which might change
1514 before the lease expires. */
1515
1516 if (crecp->flags & (F_IMMORTAL | F_DHCP))
1517 return daemon->local_ttl;
1518
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001519 /* Return the Max TTL value if it is lower then the actual TTL */
1520 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1521 return crecp->ttd - now;
1522 else
1523 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001524}
1525
1526
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001527/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001528size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001529 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelley613ad152014-02-25 23:02:28 +00001530 time_t now, int *ad_reqd, int *do_bit)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001531{
Simon Kelley3be34542004-09-11 19:12:13 +01001532 char *name = daemon->namebuff;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001533 unsigned char *p, *ansp, *pheader;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001534 unsigned int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001535 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001536 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001537 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001538 int q, ans, anscount = 0, addncount = 0;
Simon Kelleya25720a2014-01-14 23:13:55 +00001539 int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001540 int is_sign;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001541 struct crec *crecp;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001542 int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001543 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001544 size_t len;
Simon Kelley0a852542005-03-23 20:28:59 +00001545
Simon Kelleye243c072014-02-06 18:14:09 +00001546 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001547 if (header->hb4 & HB4_CD)
1548 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001549
1550 /* RFC 6840 5.7 */
1551 *ad_reqd = header->hb4 & HB4_AD;
Simon Kelley613ad152014-02-25 23:02:28 +00001552 *do_bit = 0;
1553
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001554 /* If there is an RFC2671 pseudoheader then it will be overwritten by
1555 partial replies, so we have to do a dry run to see if we can answer
1556 the query. We check to see if the do bit is set, if so we always
1557 forward rather than answering from the cache, which doesn't include
Simon Kelleya25720a2014-01-14 23:13:55 +00001558 security information, unless we're in DNSSEC validation mode. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001559
Simon Kelley832af0b2007-01-21 20:01:28 +00001560 if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001561 {
Simon Kelley7de060b2011-08-26 17:24:52 +01001562 unsigned short udpsz, flags;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001563 unsigned char *psave = pheader;
1564
Simon Kelleya25720a2014-01-14 23:13:55 +00001565 have_pseudoheader = 1;
1566
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001567 GETSHORT(udpsz, pheader);
Simon Kelley7de060b2011-08-26 17:24:52 +01001568 pheader += 2; /* ext_rcode */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001569 GETSHORT(flags, pheader);
1570
Simon Kelley613ad152014-02-25 23:02:28 +00001571 if ((sec_reqd = flags & 0x8000))
1572 *do_bit = 1;/* do bit */
Simon Kelley83349b82014-02-10 21:02:01 +00001573 *ad_reqd = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001574
1575 /* If our client is advertising a larger UDP packet size
1576 than we allow, trim it so that we don't get an overlarge
1577 response from upstream */
1578
Simon Kelley832af0b2007-01-21 20:01:28 +00001579 if (!is_sign && (udpsz > daemon->edns_pktsz))
Simon Kelley3be34542004-09-11 19:12:13 +01001580 PUTSHORT(daemon->edns_pktsz, psave);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001581
1582 dryrun = 1;
1583 }
1584
Simon Kelley572b41e2011-02-18 18:11:18 +00001585 if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
Simon Kelley832af0b2007-01-21 20:01:28 +00001586 return 0;
1587
Simon Kelley0a852542005-03-23 20:28:59 +00001588 for (rec = daemon->mxnames; rec; rec = rec->next)
1589 rec->offset = 0;
1590
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001591 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001592 /* determine end of question section (we put answers there) */
1593 if (!(ansp = skip_questions(header, qlen)))
1594 return 0; /* bad packet */
1595
1596 /* now process each question, answers go in RRs after the question */
1597 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001598
Simon Kelley5aabfc72007-08-29 11:24:47 +01001599 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001600 {
1601 /* save pointer to name for copying into answers */
1602 nameoffset = p - (unsigned char *)header;
1603
1604 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001605 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001606 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001607
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001608 GETSHORT(qtype, p);
1609 GETSHORT(qclass, p);
1610
Simon Kelley2ed162a2015-04-28 21:26:35 +01001611 /* Don't filter RRSIGS from answers to ANY queries, even if do-bit
1612 not set. */
1613 if (qtype == T_ANY)
1614 *do_bit = 1;
1615
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001616 ans = 0; /* have we answered this question */
1617
Simon Kelley0a852542005-03-23 20:28:59 +00001618 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001619 {
Simon Kelley0a852542005-03-23 20:28:59 +00001620 struct txt_record *t;
1621 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001622 {
Simon Kelley0a852542005-03-23 20:28:59 +00001623 if (t->class == qclass && hostname_isequal(name, t->name))
1624 {
1625 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001626 if (!dryrun)
1627 {
Simon Kelleyfec216d2014-03-27 20:54:34 +00001628 unsigned long ttl = daemon->local_ttl;
1629 int ok = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001630 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleyfec216d2014-03-27 20:54:34 +00001631 /* Dynamically generate stat record */
1632 if (t->stat != 0)
1633 {
1634 ttl = 0;
1635 if (!cache_make_stat(t))
1636 ok = 0;
1637 }
1638
1639 if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1640 ttl, NULL,
1641 T_TXT, t->class, "t", t->len, t->txt))
Simon Kelleye17fb622006-01-14 20:33:46 +00001642 anscount++;
1643
1644 }
Simon Kelley0a852542005-03-23 20:28:59 +00001645 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001646 }
Simon Kelley0a852542005-03-23 20:28:59 +00001647 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001648
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001649#ifdef HAVE_DNSSEC
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001650 if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001651 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001652 int gotone = 0;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001653 struct blockdata *keydata;
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001654
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001655 /* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001656 if (sec_reqd)
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001657 {
Simon Kelley5f938532014-02-03 16:44:32 +00001658 crecp = NULL;
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001659 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1660 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
1661 break;
1662 }
1663
1664 if (!sec_reqd || crecp)
1665 {
1666 if (qtype == T_DS)
1667 {
1668 crecp = NULL;
1669 while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
1670 if (crecp->uid == qclass)
1671 {
Simon Kelleyb8eac192014-02-27 14:30:03 +00001672 gotone = 1;
1673 if (!dryrun)
1674 {
1675 if (crecp->flags & F_NEG)
1676 {
1677 if (crecp->flags & F_NXDOMAIN)
1678 nxdomain = 1;
Simon Kelleyae4624b2015-01-12 23:22:08 +00001679 log_query(F_UPSTREAM, name, NULL, "no DS");
Simon Kelleyb8eac192014-02-27 14:30:03 +00001680 }
1681 else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
1682 {
1683 struct all_addr a;
1684 a.addr.keytag = crecp->addr.ds.keytag;
1685 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
1686 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1687 crec_ttl(crecp, now), &nameoffset,
1688 T_DS, qclass, "sbbt",
1689 crecp->addr.ds.keytag, crecp->addr.ds.algo,
1690 crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
1691 anscount++;
1692
1693 }
1694 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001695 }
1696 }
1697 else /* DNSKEY */
1698 {
1699 crecp = NULL;
1700 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
1701 if (crecp->uid == qclass)
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001702 {
Simon Kelleyee415862014-02-11 11:07:22 +00001703 gotone = 1;
1704 if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
1705 {
1706 struct all_addr a;
1707 a.addr.keytag = crecp->addr.key.keytag;
1708 log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DNSKEY keytag %u");
1709 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1710 crec_ttl(crecp, now), &nameoffset,
1711 T_DNSKEY, qclass, "sbbt",
1712 crecp->addr.key.flags, 3, crecp->addr.key.algo, crecp->addr.key.keylen, keydata))
1713 anscount++;
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001714 }
Simon Kelleyb5dbfd12014-01-25 18:19:51 +00001715 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001716 }
Simon Kelley5f938532014-02-03 16:44:32 +00001717 }
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001718
Simon Kelley5f938532014-02-03 16:44:32 +00001719 /* Now do RRSIGs */
1720 if (gotone)
1721 {
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001722 ans = 1;
1723 auth = 0;
1724 if (!dryrun && sec_reqd)
1725 {
1726 crecp = NULL;
1727 while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
1728 if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
1729 (keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
1730 {
Simon Kelley5f938532014-02-03 16:44:32 +00001731 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1732 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyc8ca33f2014-02-10 10:35:42 +00001733 T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
1734 anscount++;
1735 }
1736 }
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001737 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001738 }
1739#endif
1740
Simon Kelley0a852542005-03-23 20:28:59 +00001741 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001742 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001743 struct txt_record *t;
1744
1745 for (t = daemon->rr; t; t = t->next)
1746 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1747 {
1748 ans = 1;
1749 if (!dryrun)
1750 {
1751 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1752 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1753 daemon->local_ttl, NULL,
1754 t->class, C_IN, "t", t->len, t->txt))
1755 anscount ++;
1756 }
1757 }
1758
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001759 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001760 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001761 /* see if it's w.z.y.z.in-addr.arpa format */
1762 int is_arpa = in_arpa_name_2_addr(name, &addr);
1763 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001764 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001765
1766 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1767 if (hostname_isequal(name, ptr->name))
1768 break;
1769
Simon Kelleyf2621c72007-04-29 19:47:21 +01001770 if (is_arpa == F_IPV4)
1771 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001772 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001773 struct addrlist *addrlist;
1774
Simon Kelley376d48c2013-11-13 13:04:30 +00001775 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1776 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001777 break;
1778
1779 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001780 break;
1781 else
1782 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1783 intr = intr->next;
1784 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001785#ifdef HAVE_IPV6
1786 else if (is_arpa == F_IPV6)
1787 for (intr = daemon->int_names; intr; intr = intr->next)
1788 {
1789 struct addrlist *addrlist;
1790
Simon Kelley376d48c2013-11-13 13:04:30 +00001791 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1792 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001793 break;
1794
1795 if (addrlist)
1796 break;
1797 else
1798 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1799 intr = intr->next;
1800 }
1801#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001802
1803 if (intr)
1804 {
1805 ans = 1;
1806 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001807 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001808 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001809 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1810 daemon->local_ttl, NULL,
1811 T_PTR, C_IN, "d", intr->name))
1812 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001813 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001814 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001815 else if (ptr)
1816 {
1817 ans = 1;
1818 if (!dryrun)
1819 {
Simon Kelley28866e92011-02-14 20:19:14 +00001820 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001821 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001822 if (hostname_isequal(name, ptr->name) &&
1823 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1824 daemon->local_ttl, NULL,
1825 T_PTR, C_IN, "d", ptr->ptr))
1826 anscount++;
1827
Simon Kelley832af0b2007-01-21 20:01:28 +00001828 }
1829 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001830 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001831 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001832 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001833 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001834 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
1835 crecp = NULL;
1836#ifdef HAVE_DNSSEC
1837 else if (crecp->flags & F_DNSSECOK)
Simon Kelley2d33bda2014-01-24 22:37:25 +00001838 {
Simon Kelley0744ca62014-01-25 16:40:15 +00001839 int gotsig = 0;
Simon Kelley12fae492014-02-04 22:03:06 +00001840 struct crec *rr_crec = NULL;
1841
1842 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001843 {
Simon Kelley12fae492014-02-04 22:03:06 +00001844 if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00001845 {
Simon Kelley12fae492014-02-04 22:03:06 +00001846 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00001847 gotsig = 1;
1848
1849 if (!dryrun &&
1850 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00001851 rr_crec->ttd - now, &nameoffset,
Simon Kelley0744ca62014-01-25 16:40:15 +00001852 T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
1853 anscount++;
1854 }
1855 }
Simon Kelley12fae492014-02-04 22:03:06 +00001856
1857 if (!gotsig)
1858 crecp = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00001859 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001860#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00001861 }
Simon Kelley2d33bda2014-01-24 22:37:25 +00001862
1863 if (crecp)
1864 {
1865 do
1866 {
1867 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1868 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1869 continue;
1870
1871 if (!(crecp->flags & F_DNSSECOK))
1872 sec_data = 0;
1873
1874 if (crecp->flags & F_NEG)
1875 {
1876 ans = 1;
1877 auth = 0;
1878 if (crecp->flags & F_NXDOMAIN)
1879 nxdomain = 1;
1880 if (!dryrun)
1881 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1882 }
1883 else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd || option_bool(OPT_DNSSEC_VALID))
1884 {
1885 ans = 1;
1886 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1887 auth = 0;
1888 if (!dryrun)
1889 {
1890 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1891 record_source(crecp->uid));
1892
1893 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1894 crec_ttl(crecp, now), NULL,
1895 T_PTR, C_IN, "d", cache_get_name(crecp)))
1896 anscount++;
1897 }
1898 }
1899 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1900 }
1901 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001902 else if (is_rev_synth(is_arpa, &addr, name))
1903 {
1904 ans = 1;
1905 if (!dryrun)
1906 {
1907 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1908
1909 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1910 daemon->local_ttl, NULL,
1911 T_PTR, C_IN, "d", name))
1912 anscount++;
1913 }
1914 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001915 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001916 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001917 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001918 {
1919 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1920 ans = 1;
1921 nxdomain = 1;
1922 if (!dryrun)
1923 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001924 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001925 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001926 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001927
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001928 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1929 {
1930 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001931 struct interface_name *intr;
1932
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001933 if (flag == F_IPV6)
1934#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001935 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001936#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001937 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001938#endif
1939
1940 if (qtype != type && qtype != T_ANY)
1941 continue;
1942
Simon Kelley316e2732010-01-22 20:16:09 +00001943 /* Check for "A for A" queries; be rather conservative
1944 about what looks like dotted-quad. */
1945 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001946 {
Simon Kelley316e2732010-01-22 20:16:09 +00001947 char *cp;
1948 unsigned int i, a;
1949 int x;
1950
1951 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001952 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001953 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001954 {
1955 i = 5;
1956 break;
1957 }
1958
1959 a = (a << 8) + x;
1960
1961 if (*cp == '.')
1962 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001963 }
Simon Kelley316e2732010-01-22 20:16:09 +00001964
1965 if (i == 4)
1966 {
1967 ans = 1;
1968 if (!dryrun)
1969 {
1970 addr.addr.addr4.s_addr = htonl(a);
1971 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1972 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1973 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1974 anscount++;
1975 }
1976 continue;
1977 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001978 }
1979
Simon Kelleyf2621c72007-04-29 19:47:21 +01001980 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001981 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001982 for (intr = daemon->int_names; intr; intr = intr->next)
1983 if (hostname_isequal(name, intr->name))
1984 break;
1985
1986 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001987 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001988 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001989 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001990
Simon Kelley115ac3e2013-05-20 11:28:32 +01001991 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001992
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001993 for (intr = daemon->int_names; intr; intr = intr->next)
1994 if (hostname_isequal(name, intr->name))
1995 {
Simon Kelley47669362014-12-17 12:41:56 +00001996 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley376d48c2013-11-13 13:04:30 +00001997#ifdef HAVE_IPV6
Simon Kelley47669362014-12-17 12:41:56 +00001998 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
Simon Kelley376d48c2013-11-13 13:04:30 +00001999#endif
Simon Kelley47669362014-12-17 12:41:56 +00002000 {
2001#ifdef HAVE_IPV6
2002 if (addrlist->flags & ADDRLIST_REVONLY)
2003 continue;
2004#endif
2005 ans = 1;
2006 if (!dryrun)
Simon Kelley376d48c2013-11-13 13:04:30 +00002007 {
2008 gotit = 1;
2009 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
2010 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2011 daemon->local_ttl, NULL, type, C_IN,
2012 type == T_A ? "4" : "6", &addrlist->addr))
2013 anscount++;
2014 }
Simon Kelley47669362014-12-17 12:41:56 +00002015 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01002016 }
2017
2018 if (!dryrun && !gotit)
2019 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
2020
Simon Kelley115ac3e2013-05-20 11:28:32 +01002021 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01002022 }
2023
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002024 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00002025 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002026 {
2027 int localise = 0;
2028
2029 /* See if a putative address is on the network from which we recieved
2030 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00002031 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002032 {
2033 struct crec *save = crecp;
2034 do {
2035 if ((crecp->flags & F_HOSTS) &&
2036 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
2037 {
2038 localise = 1;
2039 break;
2040 }
2041 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
2042 crecp = save;
2043 }
Simon Kelley824202e2014-01-23 20:59:46 +00002044
Simon Kelley0744ca62014-01-25 16:40:15 +00002045 /* If the client asked for DNSSEC and we can't provide RRSIGs, either
2046 because we've not doing DNSSEC or the cached answer is signed by negative,
2047 don't answer from the cache, forward instead. */
2048 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && sec_reqd)
Simon Kelley824202e2014-01-23 20:59:46 +00002049 {
Simon Kelley0744ca62014-01-25 16:40:15 +00002050 if (!option_bool(OPT_DNSSEC_VALID) || ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK)))
2051 crecp = NULL;
2052#ifdef HAVE_DNSSEC
2053 else if (crecp->flags & F_DNSSECOK)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002054 {
Simon Kelley0744ca62014-01-25 16:40:15 +00002055 /* We're returning validated data, need to return the RRSIG too. */
Simon Kelley12fae492014-02-04 22:03:06 +00002056 struct crec *rr_crec = NULL;
Simon Kelley0744ca62014-01-25 16:40:15 +00002057 int sigtype = type;
2058 /* The signature may have expired even though the data is still in cache,
2059 forward instead of answering from cache if so. */
2060 int gotsig = 0;
2061
2062 if (crecp->flags & F_CNAME)
2063 sigtype = T_CNAME;
2064
Simon Kelley12fae492014-02-04 22:03:06 +00002065 while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002066 {
Simon Kelley12fae492014-02-04 22:03:06 +00002067 if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
Simon Kelley0744ca62014-01-25 16:40:15 +00002068 {
Simon Kelley12fae492014-02-04 22:03:06 +00002069 char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
Simon Kelley0744ca62014-01-25 16:40:15 +00002070 gotsig = 1;
2071
2072 if (!dryrun &&
2073 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
Simon Kelley12fae492014-02-04 22:03:06 +00002074 rr_crec->ttd - now, &nameoffset,
2075 T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
Simon Kelley0744ca62014-01-25 16:40:15 +00002076 anscount++;
2077 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002078 }
Simon Kelley12fae492014-02-04 22:03:06 +00002079
2080 if (!gotsig)
2081 crecp = NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002082 }
Simon Kelley824202e2014-01-23 20:59:46 +00002083#endif
Simon Kelley5b3bf922014-01-25 17:03:07 +00002084 }
2085
Simon Kelley824202e2014-01-23 20:59:46 +00002086 if (crecp)
2087 do
2088 {
2089 /* don't answer wildcard queries with data not from /etc/hosts
2090 or DHCP leases */
2091 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
2092 break;
2093
2094 if (!(crecp->flags & F_DNSSECOK))
2095 sec_data = 0;
2096
2097 if (crecp->flags & F_CNAME)
2098 {
2099 char *cname_target = cache_get_cname_target(crecp);
2100
2101 if (!dryrun)
2102 {
2103 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2104 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2105 crec_ttl(crecp, now), &nameoffset,
2106 T_CNAME, C_IN, "d", cname_target))
2107 anscount++;
2108 }
2109
2110 strcpy(name, cname_target);
2111 /* check if target interface_name */
Andy3e21a1a2014-03-22 19:10:07 +00002112 if (crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelley824202e2014-01-23 20:59:46 +00002113 goto intname_restart;
2114 else
2115 goto cname_restart;
2116 }
2117
2118 if (crecp->flags & F_NEG)
2119 {
2120 /* We don't cache NSEC records, so if a DNSSEC-validated negative answer
2121 is cached and the client wants DNSSEC, forward rather than answering from the cache */
2122 if (!sec_reqd || !(crecp->flags & F_DNSSECOK))
2123 {
2124 ans = 1;
2125 auth = 0;
2126 if (crecp->flags & F_NXDOMAIN)
2127 nxdomain = 1;
2128 if (!dryrun)
2129 log_query(crecp->flags, name, NULL, NULL);
2130 }
2131 }
2132 else
2133 {
2134 /* If we are returning local answers depending on network,
2135 filter here. */
2136 if (localise &&
2137 (crecp->flags & F_HOSTS) &&
2138 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
2139 continue;
2140
2141 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
2142 auth = 0;
2143
2144 ans = 1;
2145 if (!dryrun)
2146 {
2147 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
2148 record_source(crecp->uid));
2149
2150 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2151 crec_ttl(crecp, now), NULL, type, C_IN,
2152 type == T_A ? "4" : "6", &crecp->addr))
2153 anscount++;
2154 }
2155 }
2156 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002157 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01002158 else if (is_name_synthetic(flag, name, &addr))
2159 {
2160 ans = 1;
2161 if (!dryrun)
2162 {
2163 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
2164 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2165 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
2166 anscount++;
2167 }
2168 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002169 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002170
2171 if (qtype == T_CNAME || qtype == T_ANY)
2172 {
2173 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002174 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002175 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00002176 if (!(crecp->flags & F_DNSSECOK))
2177 sec_data = 0;
2178
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002179 ans = 1;
2180 if (!dryrun)
2181 {
2182 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
2183 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
2184 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01002185 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01002186 anscount++;
2187 }
2188 }
2189 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00002190
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002191 if (qtype == T_MX || qtype == T_ANY)
2192 {
2193 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00002194 for (rec = daemon->mxnames; rec; rec = rec->next)
2195 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002196 {
2197 ans = found = 1;
2198 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002199 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002200 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002201 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00002202 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2203 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
2204 {
2205 anscount++;
2206 if (rec->target)
2207 rec->offset = offset;
2208 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002209 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002210 }
2211
Simon Kelley28866e92011-02-14 20:19:14 +00002212 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00002213 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002214 {
2215 ans = 1;
2216 if (!dryrun)
2217 {
Simon Kelley28866e92011-02-14 20:19:14 +00002218 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002219 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
2220 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00002221 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002222 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002223 }
2224 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002225 }
2226
2227 if (qtype == T_SRV || qtype == T_ANY)
2228 {
2229 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00002230 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
2231
Simon Kelley0a852542005-03-23 20:28:59 +00002232 for (rec = daemon->mxnames; rec; rec = rec->next)
2233 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002234 {
2235 found = ans = 1;
2236 if (!dryrun)
2237 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00002238 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00002239 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002240 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00002241 &offset, T_SRV, C_IN, "sssd",
2242 rec->priority, rec->weight, rec->srvport, rec->target))
2243 {
2244 anscount++;
2245 if (rec->target)
2246 rec->offset = offset;
2247 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002248 }
Simon Kelley28866e92011-02-14 20:19:14 +00002249
2250 /* unlink first SRV record found */
2251 if (!move)
2252 {
2253 move = rec;
2254 *up = rec->next;
2255 }
2256 else
2257 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002258 }
Simon Kelley28866e92011-02-14 20:19:14 +00002259 else
2260 up = &rec->next;
2261
2262 /* put first SRV record back at the end. */
2263 if (move)
2264 {
2265 *up = move;
2266 move->next = NULL;
2267 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002268
Simon Kelley28866e92011-02-14 20:19:14 +00002269 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002270 {
2271 ans = 1;
2272 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002273 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002274 }
2275 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01002276
2277 if (qtype == T_NAPTR || qtype == T_ANY)
2278 {
2279 struct naptr *na;
2280 for (na = daemon->naptr; na; na = na->next)
2281 if (hostname_isequal(name, na->name))
2282 {
2283 ans = 1;
2284 if (!dryrun)
2285 {
Simon Kelley28866e92011-02-14 20:19:14 +00002286 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01002287 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
2288 NULL, T_NAPTR, C_IN, "sszzzd",
2289 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
2290 anscount++;
2291 }
2292 }
2293 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002294
2295 if (qtype == T_MAILB)
2296 ans = 1, nxdomain = 1;
2297
Simon Kelley28866e92011-02-14 20:19:14 +00002298 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002299 {
2300 ans = 1;
2301 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01002302 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002303 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002304 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002305
2306 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002307 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002308 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00002309
Simon Kelleyfeba5c12004-07-27 20:28:58 +01002310 if (dryrun)
2311 {
2312 dryrun = 0;
2313 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002314 }
2315
Simon Kelley0a852542005-03-23 20:28:59 +00002316 /* create an additional data section, for stuff in SRV and MX record replies. */
2317 for (rec = daemon->mxnames; rec; rec = rec->next)
2318 if (rec->offset != 0)
2319 {
2320 /* squash dupes */
2321 struct mx_srv_record *tmp;
2322 for (tmp = rec->next; tmp; tmp = tmp->next)
2323 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
2324 tmp->offset = 0;
2325
2326 crecp = NULL;
2327 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
2328 {
Simon Kelley0a852542005-03-23 20:28:59 +00002329#ifdef HAVE_IPV6
2330 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
2331#else
2332 int type = T_A;
2333#endif
2334 if (crecp->flags & F_NEG)
2335 continue;
2336
Simon Kelley9009d742008-11-14 20:04:27 +00002337 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2338 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002339 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2340 addncount++;
2341 }
2342 }
2343
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002344 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002345 /* clear authoritative and truncated flags, set QR flag */
2346 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2347 /* set RA flag */
2348 header->hb4 |= HB4_RA;
2349
2350 /* authoritive - only hosts and DHCP derived names. */
2351 if (auth)
2352 header->hb3 |= HB3_AA;
2353
2354 /* truncation */
2355 if (trunc)
2356 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002357
Simon Kelley45cca582013-10-15 10:20:13 +01002358 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002359 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002360 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002361 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002362 header->ancount = htons(anscount);
2363 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002364 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00002365
Simon Kelleya25720a2014-01-14 23:13:55 +00002366 len = ansp - (unsigned char *)header;
2367
2368 if (have_pseudoheader)
Simon Kelleye243c072014-02-06 18:14:09 +00002369 len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
2370
Simon Kelley83349b82014-02-10 21:02:01 +00002371 if (*ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00002372 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00002373 else
2374 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00002375
Simon Kelley7c286122014-01-27 21:38:11 +00002376 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002377}
2378