blob: b078b597928a3ddd58c7ca5f52023ff4f8beb910 [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 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 {
Josh Soref74f0f9a2017-12-01 21:38:27 +000039 /* check that there are the correct no. of bytes after the name */
Simon Kelley6a0b00f2017-09-25 20:19:55 +010040 if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes))
Simon Kelley9009d742008-11-14 20:04:27 +000041 return 0;
42
43 if (isExtract)
44 {
45 if (cp != (unsigned char *)name)
46 cp--;
47 *cp = 0; /* terminate: lose final period */
48 }
49 else if (*cp != 0)
50 retvalue = 2;
51
52 if (p1) /* we jumped via compression */
53 *pp = p1;
54 else
55 *pp = p;
56
57 return retvalue;
58 }
59
60 label_type = l & 0xc0;
61
Simon Kelley9e4abcb2004-01-22 19:47:41 +000062 if (label_type == 0xc0) /* pointer */
63 {
Simon Kelley9009d742008-11-14 20:04:27 +000064 if (!CHECK_LEN(header, p, plen, 1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065 return 0;
66
67 /* get offset */
68 l = (l&0x3f) << 8;
69 l |= *p++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000070
71 if (!p1) /* first jump, save location to go back to */
72 p1 = p;
73
74 hops++; /* break malicious infinite loops */
75 if (hops > 255)
76 return 0;
77
78 p = l + (unsigned char *)header;
79 }
Simon Kelley06568c62015-05-15 20:43:48 +010080 else if (label_type == 0x00)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000081 { /* label_type = 0 -> label. */
Simon Kelley5d07d772015-05-15 18:13:06 +010082 namelen += l + 1; /* include period */
83 if (namelen >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +000085 if (!CHECK_LEN(header, p, plen, l))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000086 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +000087
Simon Kelley9e4abcb2004-01-22 19:47:41 +000088 for(j=0; j<l; j++, p++)
89 if (isExtract)
90 {
Simon Kelley1f15b812009-10-13 17:49:32 +010091 unsigned char c = *p;
Simon Kelleycbe379a2015-04-21 22:57:06 +010092#ifdef HAVE_DNSSEC
93 if (option_bool(OPT_DNSSEC_VALID))
94 {
95 if (c == 0 || c == '.' || c == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +010096 {
97 *cp++ = NAME_ESCAPE;
98 *cp++ = c+1;
99 }
100 else
101 *cp++ = c;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100102 }
103 else
104#endif
Simon Kelley394ff492015-03-29 22:17:14 +0100105 if (c != 0 && c != '.')
106 *cp++ = c;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107 else
108 return 0;
109 }
110 else
111 {
112 unsigned char c1 = *cp, c2 = *p;
113
114 if (c1 == 0)
115 retvalue = 2;
116 else
117 {
118 cp++;
119 if (c1 >= 'A' && c1 <= 'Z')
120 c1 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100121#ifdef HAVE_DNSSEC
122 if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +0100123 c1 = (*cp++)-1;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100124#endif
125
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000126 if (c2 >= 'A' && c2 <= 'Z')
127 c2 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100128
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000129 if (c1 != c2)
130 retvalue = 2;
131 }
132 }
Simon Kelley06568c62015-05-15 20:43:48 +0100133
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000134 if (isExtract)
135 *cp++ = '.';
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000136 else if (*cp != 0 && *cp++ != '.')
137 retvalue = 2;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000138 }
Simon Kelley06568c62015-05-15 20:43:48 +0100139 else
140 return 0; /* label types 0x40 and 0x80 not supported */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000141 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000142}
143
144/* Max size of input string (for IPv6) is 75 chars.) */
145#define MAXARPANAME 75
Simon Kelley4f7b3042012-11-28 21:27:02 +0000146int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000147{
148 int j;
149 char name[MAXARPANAME+1], *cp1;
150 unsigned char *addr = (unsigned char *)addrp;
151 char *lastchunk = NULL, *penchunk = NULL;
152
153 if (strlen(namein) > MAXARPANAME)
154 return 0;
155
156 memset(addrp, 0, sizeof(struct all_addr));
157
158 /* turn name into a series of asciiz strings */
Josh Soref74f0f9a2017-12-01 21:38:27 +0000159 /* j counts no. of labels */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000160 for(j = 1,cp1 = name; *namein; cp1++, namein++)
161 if (*namein == '.')
162 {
163 penchunk = lastchunk;
164 lastchunk = cp1 + 1;
165 *cp1 = 0;
166 j++;
167 }
168 else
169 *cp1 = *namein;
170
171 *cp1 = 0;
172
173 if (j<3)
174 return 0;
175
176 if (hostname_isequal(lastchunk, "arpa") && hostname_isequal(penchunk, "in-addr"))
177 {
178 /* IP v4 */
Josh Soref730c6742017-02-06 16:14:04 +0000179 /* address arrives as a name of the form
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000180 www.xxx.yyy.zzz.in-addr.arpa
181 some of the low order address octets might be missing
182 and should be set to zero. */
183 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
184 {
185 /* check for digits only (weeds out things like
186 50.0/24.67.28.64.in-addr.arpa which are used
187 as CNAME targets according to RFC 2317 */
188 char *cp;
189 for (cp = cp1; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000190 if (!isdigit((unsigned char)*cp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000191 return 0;
192
193 addr[3] = addr[2];
194 addr[2] = addr[1];
195 addr[1] = addr[0];
196 addr[0] = atoi(cp1);
197 }
198
199 return F_IPV4;
200 }
201#ifdef HAVE_IPV6
202 else if (hostname_isequal(penchunk, "ip6") &&
203 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
204 {
205 /* IP v6:
206 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
207 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
208
Josh Soref730c6742017-02-06 16:14:04 +0000209 Note that most of these the various representations are obsolete and
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000210 left-over from the many DNS-for-IPv6 wars. We support all the formats
211 that we can since there is no reason not to.
212 */
213
214 if (*name == '\\' && *(name+1) == '[' &&
215 (*(name+2) == 'x' || *(name+2) == 'X'))
216 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000217 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000218 {
219 char xdig[2];
220 xdig[0] = *cp1;
221 xdig[1] = 0;
222 if (j%2)
223 addr[j/2] |= strtol(xdig, NULL, 16);
224 else
225 addr[j/2] = strtol(xdig, NULL, 16) << 4;
226 }
227
228 if (*cp1 == '/' && j == 32)
229 return F_IPV6;
230 }
231 else
232 {
233 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
234 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000235 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000236 return 0;
237
238 for (j = sizeof(struct all_addr)-1; j>0; j--)
239 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
240 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
241 }
242
243 return F_IPV6;
244 }
245 }
246#endif
247
248 return 0;
249}
250
Giovanni Bajo32f82c62012-04-28 01:01:16 +0200251unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100252{
253 while(1)
254 {
Simon Kelley9009d742008-11-14 20:04:27 +0000255 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100256
Simon Kelley9009d742008-11-14 20:04:27 +0000257 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100258 return NULL;
259
Simon Kelley9009d742008-11-14 20:04:27 +0000260 label_type = (*ansp) & 0xc0;
261
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100262 if (label_type == 0xc0)
263 {
264 /* pointer for compression. */
265 ansp += 2;
266 break;
267 }
268 else if (label_type == 0x80)
269 return NULL; /* reserved */
270 else if (label_type == 0x40)
271 {
272 /* Extended label type */
273 unsigned int count;
274
Simon Kelley9009d742008-11-14 20:04:27 +0000275 if (!CHECK_LEN(header, ansp, plen, 2))
276 return NULL;
277
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100278 if (((*ansp++) & 0x3f) != 1)
279 return NULL; /* we only understand bitstrings */
280
281 count = *(ansp++); /* Bits in bitstring */
282
283 if (count == 0) /* count == 0 means 256 bits */
284 ansp += 32;
285 else
286 ansp += ((count-1)>>3)+1;
287 }
288 else
289 { /* label type == 0 Bottom six bits is length */
290 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000291
292 if (!ADD_RDLEN(header, ansp, plen, len))
293 return NULL;
294
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100295 if (len == 0)
296 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100297 }
298 }
Simon Kelley9009d742008-11-14 20:04:27 +0000299
300 if (!CHECK_LEN(header, ansp, plen, extrabytes))
301 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100302
303 return ansp;
304}
305
Simon Kelley4f7b3042012-11-28 21:27:02 +0000306unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000307{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100308 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000309 unsigned char *ansp = (unsigned char *)(header+1);
310
Simon Kelley5aabfc72007-08-29 11:24:47 +0100311 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000312 {
Simon Kelley9009d742008-11-14 20:04:27 +0000313 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100314 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000315 ansp += 4; /* class and type */
316 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000317
318 return ansp;
319}
320
Simon Kelley5107ace2014-02-23 10:48:32 +0000321unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100322{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100323 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100324
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100325 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100326 {
Simon Kelley9009d742008-11-14 20:04:27 +0000327 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100328 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100329 ansp += 8; /* type, class, TTL */
330 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000331 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100332 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100333 }
334
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100335 return ansp;
336}
337
Simon Kelley0a852542005-03-23 20:28:59 +0000338/* CRC the question section. This is used to safely detect query
Josh Soref730c6742017-02-06 16:14:04 +0000339 retransmission and to detect answers to questions we didn't ask, which
Simon Kelley0a852542005-03-23 20:28:59 +0000340 might be poisoning attacks. Note that we decode the name rather
341 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000342 We ignore case in the names for the same reason. Return all-ones
343 if there is not question section. */
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000344#ifndef HAVE_DNSSEC
Simon Kelley572b41e2011-02-18 18:11:18 +0000345unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100346{
Simon Kelley91dccd02005-03-31 17:48:32 +0100347 int q;
348 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000349 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100350
Simon Kelley5aabfc72007-08-29 11:24:47 +0100351 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000352 {
Simon Kelley9009d742008-11-14 20:04:27 +0000353 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000354 return crc; /* bad packet */
355
Simon Kelley3d8df262005-08-29 12:19:27 +0100356 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000357 {
358 int i = 8;
359 char c = *p1;
360
361 if (c >= 'A' && c <= 'Z')
362 c += 'a' - 'A';
363
364 crc ^= c << 24;
365 while (i--)
366 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
367 }
368
369 /* CRC the class and type as well */
370 for (p1 = p; p1 < p+4; p1++)
371 {
372 int i = 8;
373 crc ^= *p1 << 24;
374 while (i--)
375 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
376 }
377
378 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000379 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000380 return crc; /* bad packet */
381 }
382
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100383 return crc;
384}
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000385#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100386
Simon Kelley572b41e2011-02-18 18:11:18 +0000387size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100388{
389 unsigned char *ansp = skip_questions(header, plen);
390
Simon Kelley9009d742008-11-14 20:04:27 +0000391 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100392 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000393 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100394
395 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
396 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000397 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100398
Simon Kelley36717ee2004-09-20 19:20:58 +0100399 /* restore pseudoheader */
400 if (pheader && ntohs(header->arcount) == 0)
401 {
402 /* must use memmove, may overlap */
403 memmove(ansp, pheader, hlen);
404 header->arcount = htons(1);
405 ansp += hlen;
406 }
407
408 return ansp - (unsigned char *)header;
409}
410
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000411/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100412int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000413{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100414 in_addr_t ip_addr = ntohl(addr.s_addr);
415
416 return
Simon Kelleyd2aa7df2015-08-03 21:52:12 +0100417 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
418 ((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. "here" network */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100419 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
420 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
Simon Kelley90477fb2015-10-20 21:21:32 +0100421 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
422 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
423 ((ip_addr & 0xFFFFFF00) == 0xC0000200) /* 192.0.2.0/24 (test-net) */ ||
424 ((ip_addr & 0xFFFFFF00) == 0xC6336400) /* 198.51.100.0/24(test-net) */ ||
425 ((ip_addr & 0xFFFFFF00) == 0xCB007100) /* 203.0.113.0/24 (test-net) */ ||
426 ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 (broadcast)*/ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000427}
Simon Kelley1cff1662004-03-12 08:12:58 +0000428
Simon Kelleyfca008d2017-02-19 18:50:41 +0000429#ifdef HAVE_IPV6
430static int private_net6(struct in6_addr *a)
431{
432 return
433 IN6_IS_ADDR_UNSPECIFIED(a) || /* RFC 6303 4.3 */
434 IN6_IS_ADDR_LOOPBACK(a) || /* RFC 6303 4.3 */
435 IN6_IS_ADDR_LINKLOCAL(a) || /* RFC 6303 4.5 */
436 ((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
437 ((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
438}
439#endif
440
441
Simon Kelley6938f342014-01-26 22:47:39 +0000442static 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 +0000443{
444 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000445
446 for (i = count; i != 0; i--)
447 {
Simon Kelley28866e92011-02-14 20:19:14 +0000448 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100449 {
450 if (!extract_name(header, qlen, &p, name, 1, 10))
451 return 0;
452 }
453 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000454 return 0; /* bad packet */
455
456 GETSHORT(qtype, p);
457 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100458 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000459 GETSHORT(rdlen, p);
460
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100461 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000462 {
463 struct doctor *doctor;
464 struct in_addr addr;
465
Simon Kelley9009d742008-11-14 20:04:27 +0000466 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
467 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100468
469 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000470 memcpy(&addr, p, INADDRSZ);
471
472 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000473 {
474 if (doctor->end.s_addr == 0)
475 {
476 if (!is_same_net(doctor->in, addr, doctor->mask))
477 continue;
478 }
479 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
480 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
481 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100482
Simon Kelley73a08a22009-02-05 20:28:08 +0000483 addr.s_addr &= ~doctor->mask.s_addr;
484 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
485 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000486 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000487 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000488 memcpy(p, &addr, INADDRSZ);
489 break;
490 }
Simon Kelley824af852008-02-12 20:43:05 +0000491 }
Simon Kelley28866e92011-02-14 20:19:14 +0000492 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100493 {
494 unsigned char *p1 = p;
495 if (!CHECK_LEN(header, p1, qlen, rdlen))
496 return 0;
497 while ((p1 - p) < rdlen)
498 {
499 unsigned int i, len = *p1;
500 unsigned char *p2 = p1;
Simon Kelley6a0b00f2017-09-25 20:19:55 +0100501 if ((p1 + len - p) >= rdlen)
502 return 0; /* bad packet */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100503 /* make counted string zero-term and sanitise */
504 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100505 {
506 if (!isprint((int)*(p2+1)))
507 break;
508
509 *p2 = *(p2+1);
510 p2++;
511 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100512 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000513 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100514 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100515 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100516 *p1 = len;
517 p1 += len+1;
518 }
519 }
Simon Kelley824af852008-02-12 20:43:05 +0000520
Simon Kelley9009d742008-11-14 20:04:27 +0000521 if (!ADD_RDLEN(header, p, qlen, rdlen))
522 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000523 }
524
525 return p;
526}
527
Simon Kelley6938f342014-01-26 22:47:39 +0000528static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000529{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100530 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000531 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100532 unsigned long ttl, minttl = ULONG_MAX;
533 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000534
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100535 /* first move to NS section and find TTL from any SOA section */
536 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000537 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000538 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000539
Simon Kelley5aabfc72007-08-29 11:24:47 +0100540 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000541 {
Simon Kelley9009d742008-11-14 20:04:27 +0000542 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100543 return 0; /* bad packet */
544
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000545 GETSHORT(qtype, p);
546 GETSHORT(qclass, p);
547 GETLONG(ttl, p);
548 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100549
550 if ((qclass == C_IN) && (qtype == T_SOA))
551 {
552 found_soa = 1;
553 if (ttl < minttl)
554 minttl = ttl;
555
556 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000557 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100558 return 0;
559 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000560 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100561 return 0;
562 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
563
564 GETLONG(ttl, p); /* minTTL */
565 if (ttl < minttl)
566 minttl = ttl;
567 }
Simon Kelley9009d742008-11-14 20:04:27 +0000568 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100569 return 0; /* bad packet */
570 }
Simon Kelley9009d742008-11-14 20:04:27 +0000571
Simon Kelley6938f342014-01-26 22:47:39 +0000572 /* rewrite addresses in additional section too */
573 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000574 return 0;
575
576 if (!found_soa)
577 minttl = daemon->neg_ttl;
578
579 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100580}
581
582/* Note that the following code can create CNAME chains that don't point to a real record,
583 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 +0000584 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100585 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000586int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelleya6004d72017-10-25 17:48:19 +0100587 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
Simon Kelley373e9172017-12-01 22:40:56 +0000588 int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100589{
Simon Kelley824af852008-02-12 20:43:05 +0000590 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100591 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000592 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100593 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000594#ifdef HAVE_IPSET
595 char **ipsets_cur;
596#else
597 (void)ipsets; /* unused */
598#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100599
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000600
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100601 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000602
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100603 /* 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 +0000604 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000605 {
606 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000607 ttl = find_soa(header, qlen, name, doctored);
Simon Kelleya6004d72017-10-25 17:48:19 +0100608
609 if (*doctored)
610 {
611 if (secure)
612 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000613#ifdef HAVE_DNSSEC
Simon Kelley373e9172017-12-01 22:40:56 +0000614 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleya6004d72017-10-25 17:48:19 +0100615 for (i = 0; i < ntohs(header->ancount); i++)
Simon Kelley373e9172017-12-01 22:40:56 +0000616 if (daemon->rr_status[i])
Simon Kelleya6004d72017-10-25 17:48:19 +0100617 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000618#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100619 }
Simon Kelley0a852542005-03-23 20:28:59 +0000620 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100621
622 /* go through the questions. */
623 p = (unsigned char *)(header+1);
624
Simon Kelley5aabfc72007-08-29 11:24:47 +0100625 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100626 {
Simon Kelley1fbe4d22014-03-01 20:03:47 +0000627 int found = 0, cname_count = CNAME_CHAIN;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100628 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000629 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000630#ifdef HAVE_DNSSEC
Simon Kelleya6004d72017-10-25 17:48:19 +0100631 int cname_short = 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000632#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000633 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000634
Simon Kelley824af852008-02-12 20:43:05 +0000635 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000636 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000637 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100638
639 GETSHORT(qtype, p);
640 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000641
642 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100643 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000644
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100645 /* PTRs: we chase CNAMEs here, since we have no way to
646 represent them in the cache. */
647 if (qtype == T_PTR)
648 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100650
651 if (!name_encoding)
652 continue;
653
654 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000655 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100656 cname_loop:
657 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000658 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100659
Simon Kelleya6004d72017-10-25 17:48:19 +0100660 for (j = 0; j < ntohs(header->ancount); j++)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100661 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100662 int secflag = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000663 unsigned char *tmp = namep;
664 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000665 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
666 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000667 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100668
669 GETSHORT(aqtype, p1);
670 GETSHORT(aqclass, p1);
671 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100672 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
673 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000674 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100675 PUTLONG(daemon->max_ttl, p1);
676 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100677 GETSHORT(ardlen, p1);
678 endrr = p1+ardlen;
679
680 /* TTL of record is minimum of CNAMES and PTR */
681 if (attl < cttl)
682 cttl = attl;
683
684 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
685 {
Simon Kelley9009d742008-11-14 20:04:27 +0000686 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000687 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000688#ifdef HAVE_DNSSEC
Simon Kelley373e9172017-12-01 22:40:56 +0000689 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
Simon Kelleya6004d72017-10-25 17:48:19 +0100690 {
691 /* validated RR anywhere in CNAME chain, don't cache. */
692 if (cname_short || aqtype == T_CNAME)
693 return 0;
694
695 secflag = F_DNSSECOK;
696 }
Simon Kelley8c707e12017-12-05 22:28:10 +0000697#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100698
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100699 if (aqtype == T_CNAME)
700 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100701 if (!cname_count--)
702 return 0; /* looped CNAMES, we can't cache. */
Simon Kelley8c707e12017-12-05 22:28:10 +0000703#ifdef HAVE_DNSSEC
Simon Kelleya6004d72017-10-25 17:48:19 +0100704 cname_short = 1;
Simon Kelley8c707e12017-12-05 22:28:10 +0000705#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100706 goto cname_loop;
707 }
708
Simon Kelley0435d042014-01-08 18:22:37 +0000709 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100710 found = 1;
711 }
712
713 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000714 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000715 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100716 }
717 }
718
Simon Kelley28866e92011-02-14 20:19:14 +0000719 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100720 {
721 if (!searched_soa)
722 {
723 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000724 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100725 }
726 if (ttl)
Simon Kelleya6004d72017-10-25 17:48:19 +0100727 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000728 }
729 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100730 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000731 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100732 /* everything other than PTR */
733 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100734 int addrlen;
735
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100736 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100737 {
738 addrlen = INADDRSZ;
739 flags |= F_IPV4;
740 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000741#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100742 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100743 {
744 addrlen = IN6ADDRSZ;
745 flags |= F_IPV6;
746 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000747#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100748 else
749 continue;
750
Simon Kelley45cca582013-10-15 10:20:13 +0100751 cname_loop1:
752 if (!(p1 = skip_questions(header, qlen)))
753 return 0;
754
Simon Kelleya6004d72017-10-25 17:48:19 +0100755 for (j = 0; j < ntohs(header->ancount); j++)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100756 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100757 int secflag = 0;
758
Simon Kelley45cca582013-10-15 10:20:13 +0100759 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
760 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100761
Simon Kelley45cca582013-10-15 10:20:13 +0100762 GETSHORT(aqtype, p1);
763 GETSHORT(aqclass, p1);
764 GETLONG(attl, p1);
765 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000766 {
Simon Kelley45cca582013-10-15 10:20:13 +0100767 (p1) -= 4;
768 PUTLONG(daemon->max_ttl, p1);
769 }
770 GETSHORT(ardlen, p1);
771 endrr = p1+ardlen;
772
773 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
774 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100775#ifdef HAVE_DNSSEC
Simon Kelley373e9172017-12-01 22:40:56 +0000776 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
Simon Kelleya6004d72017-10-25 17:48:19 +0100777 secflag = F_DNSSECOK;
778#endif
Simon Kelley45cca582013-10-15 10:20:13 +0100779 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100780 {
Simon Kelley45cca582013-10-15 10:20:13 +0100781 if (!cname_count--)
782 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +0000783 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100784 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100785 {
Simon Kelley45cca582013-10-15 10:20:13 +0100786 newc->addr.cname.target.cache = NULL;
Simon Kelley03431d62014-03-20 16:25:43 +0000787 /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
788 newc->addr.cname.uid = 1;
Simon Kelley45cca582013-10-15 10:20:13 +0100789 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100790 {
Simon Kelleyd56a6042013-10-11 14:39:03 +0100791 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100792 cpp->addr.cname.uid = newc->uid;
793 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100794 }
Simon Kelley45cca582013-10-15 10:20:13 +0100795
796 cpp = newc;
797 if (attl < cttl)
798 cttl = attl;
799
800 if (!extract_name(header, qlen, &p1, name, 1, 0))
801 return 0;
802 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100803 }
Simon Kelley45cca582013-10-15 10:20:13 +0100804 else if (!(flags & F_NXDOMAIN))
805 {
806 found = 1;
807
808 /* copy address into aligned storage */
809 if (!CHECK_LEN(header, p1, qlen, addrlen))
810 return 0; /* bad packet */
811 memcpy(&addr, p1, addrlen);
812
813 /* check for returned address in private space */
Simon Kelleyb059c962015-05-08 20:25:51 +0100814 if (check_rebind)
815 {
816 if ((flags & F_IPV4) &&
817 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
818 return 1;
819
820#ifdef HAVE_IPV6
821 if ((flags & F_IPV6) &&
822 IN6_IS_ADDR_V4MAPPED(&addr.addr.addr6))
823 {
824 struct in_addr v4;
825 v4.s_addr = ((const uint32_t *) (&addr.addr.addr6))[3];
826 if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
827 return 1;
828 }
829#endif
830 }
Simon Kelley45cca582013-10-15 10:20:13 +0100831
832#ifdef HAVE_IPSET
833 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
834 {
835 ipsets_cur = ipsets;
836 while (*ipsets_cur)
Wang Jian49752b92014-03-28 20:52:47 +0000837 {
Simon Kelleyb7639d52014-03-29 09:20:07 +0000838 log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
Wang Jian49752b92014-03-28 20:52:47 +0000839 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
840 }
Simon Kelley45cca582013-10-15 10:20:13 +0100841 }
842#endif
843
Simon Kelley0435d042014-01-08 18:22:37 +0000844 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100845 if (newc && cpp)
846 {
847 cpp->addr.cname.target.cache = newc;
848 cpp->addr.cname.uid = newc->uid;
849 }
850 cpp = NULL;
851 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100852 }
Simon Kelley45cca582013-10-15 10:20:13 +0100853
854 p1 = endrr;
855 if (!CHECK_LEN(header, p1, qlen, 0))
856 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100857 }
858
Simon Kelley28866e92011-02-14 20:19:14 +0000859 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100860 {
861 if (!searched_soa)
862 {
863 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000864 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100865 }
866 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +0000867 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100868 if (ttl || cpp)
869 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100870 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
Simon Kelley26128d22004-11-14 16:43:54 +0000871 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100872 {
Simon Kelleyd56a6042013-10-11 14:39:03 +0100873 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100874 cpp->addr.cname.uid = newc->uid;
875 }
876 }
877 }
878 }
879 }
880
Simon Kelley1023dcb2012-04-09 18:00:08 +0100881 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +0100882 Don't cache replies from non-recursive nameservers, since we may get a
883 reply containing a CNAME but not its target, even though the target
884 does exist. */
885 if (!(header->hb3 & HB3_TC) &&
886 !(header->hb4 & HB4_CD) &&
887 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +0000888 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +0000889 cache_end_insert();
890
891 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000892}
893
894/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +0000895 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +0000896unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000897{
898 unsigned char *p = (unsigned char *)(header+1);
899 int qtype, qclass;
900
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100901 if (typep)
902 *typep = 0;
903
Simon Kelley572b41e2011-02-18 18:11:18 +0000904 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000905 return 0; /* must be exactly one query. */
906
Simon Kelley9009d742008-11-14 20:04:27 +0000907 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000908 return 0; /* bad packet */
909
910 GETSHORT(qtype, p);
911 GETSHORT(qclass, p);
912
Simon Kelley0a852542005-03-23 20:28:59 +0000913 if (typep)
914 *typep = qtype;
915
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000916 if (qclass == C_IN)
917 {
918 if (qtype == T_A)
919 return F_IPV4;
920 if (qtype == T_AAAA)
921 return F_IPV6;
922 if (qtype == T_ANY)
923 return F_IPV4 | F_IPV6;
924 }
925
926 return F_QUERY;
927}
928
929
Simon Kelley572b41e2011-02-18 18:11:18 +0000930size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +0000931 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000932{
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100933 unsigned char *p;
934
935 if (!(p = skip_questions(header, qlen)))
936 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000937
Simon Kelley572b41e2011-02-18 18:11:18 +0000938 /* clear authoritative and truncated flags, set QR flag */
939 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
940 /* set RA flag */
941 header->hb4 |= HB4_RA;
942
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000943 header->nscount = htons(0);
944 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100945 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000946 if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +0000947 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000948 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +0000949 SET_RCODE(header, NXDOMAIN);
Simon Kelley087eb762017-10-30 23:16:54 +0000950 else if (flags == F_SERVFAIL)
951 SET_RCODE(header, SERVFAIL);
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100952 else if (flags == F_IPV4)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000953 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +0000954 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000955 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +0000956 header->hb3 |= HB3_AA;
957 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 +0000958 }
959#ifdef HAVE_IPV6
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100960 else if (flags == F_IPV6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000961 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000962 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000963 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +0000964 header->hb3 |= HB3_AA;
965 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 +0000966 }
967#endif
968 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +0000969 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970
971 return p - (unsigned char *)header;
972}
Simon Kelley36717ee2004-09-20 19:20:58 +0100973
974/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100975int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +0100976{
977 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +0000978 struct mx_srv_record *mx;
979 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100980 struct interface_name *intr;
981 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +0100982 struct naptr *naptr;
983
Simon Kelley288df492014-09-18 21:48:51 +0100984 /* Note: the call to cache_find_by_name is intended to find any record which matches
Simon Kelley93be5b12015-12-15 12:04:40 +0000985 ie A, AAAA, CNAME. */
Simon Kelley288df492014-09-18 21:48:51 +0100986
Simon Kelleya6004d72017-10-25 17:48:19 +0100987 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +0000988 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +0100989 return 1;
990
Simon Kelley7de060b2011-08-26 17:24:52 +0100991 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
992 if (hostname_isequal(name, naptr->name))
993 return 1;
994
995 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +0000996 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +0100997 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000998
Simon Kelley0a852542005-03-23 20:28:59 +0000999 for (txt = daemon->txt; txt; txt = txt->next)
1000 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001001 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001002
1003 for (intr = daemon->int_names; intr; intr = intr->next)
1004 if (hostname_isequal(name, intr->name))
1005 return 1;
1006
1007 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1008 if (hostname_isequal(name, ptr->name))
1009 return 1;
1010
Simon Kelley36717ee2004-09-20 19:20:58 +01001011 return 0;
1012}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001013
1014/* Is the packet a reply with the answer address equal to addr?
1015 If so mung is into an NXDOMAIN reply and also put that information
1016 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001017int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001018 struct bogus_addr *baddr, time_t now)
1019{
1020 unsigned char *p;
1021 int i, qtype, qclass, rdlen;
1022 unsigned long ttl;
1023 struct bogus_addr *baddrp;
1024
1025 /* skip over questions */
1026 if (!(p = skip_questions(header, qlen)))
1027 return 0; /* bad packet */
1028
Simon Kelley5aabfc72007-08-29 11:24:47 +01001029 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001030 {
Simon Kelley9009d742008-11-14 20:04:27 +00001031 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001032 return 0; /* bad packet */
1033
1034 GETSHORT(qtype, p);
1035 GETSHORT(qclass, p);
1036 GETLONG(ttl, p);
1037 GETSHORT(rdlen, p);
1038
1039 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001040 {
1041 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1042 return 0;
1043
1044 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1045 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1046 {
1047 /* Found a bogus address. Insert that info here, since there no SOA record
1048 to get the ttl from in the normal processing */
1049 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001050 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001051 cache_end_insert();
1052
1053 return 1;
1054 }
1055 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001056
Simon Kelley9009d742008-11-14 20:04:27 +00001057 if (!ADD_RDLEN(header, p, qlen, rdlen))
1058 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001059 }
1060
1061 return 0;
1062}
1063
Glen Huang32fc6db2014-12-27 15:28:12 +00001064int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
1065{
1066 unsigned char *p;
1067 int i, qtype, qclass, rdlen;
1068 struct bogus_addr *baddrp;
1069
1070 /* skip over questions */
1071 if (!(p = skip_questions(header, qlen)))
1072 return 0; /* bad packet */
1073
1074 for (i = ntohs(header->ancount); i != 0; i--)
1075 {
1076 if (!(p = skip_name(p, header, qlen, 10)))
1077 return 0; /* bad packet */
1078
1079 GETSHORT(qtype, p);
1080 GETSHORT(qclass, p);
1081 p += 4; /* TTL */
1082 GETSHORT(rdlen, p);
1083
1084 if (qclass == C_IN && qtype == T_A)
1085 {
1086 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1087 return 0;
1088
1089 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1090 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1091 return 1;
1092 }
1093
1094 if (!ADD_RDLEN(header, p, qlen, rdlen))
1095 return 0;
1096 }
1097
1098 return 0;
1099}
1100
Simon Kelley0549c732017-09-25 18:17:11 +01001101
Simon Kelleyb75e9362012-12-07 11:50:41 +00001102int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001103 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001104{
1105 va_list ap;
1106 unsigned char *sav, *p = *pp;
1107 int j;
1108 unsigned short usval;
1109 long lval;
1110 char *sval;
Simon Kelleyc3667172017-10-13 23:26:29 +01001111
Simon Kelley0549c732017-09-25 18:17:11 +01001112#define CHECK_LIMIT(size) \
Simon Kelleyc3667172017-10-13 23:26:29 +01001113 if (limit && p + (size) > (unsigned char*)limit) goto truncated;
Simon Kelley0549c732017-09-25 18:17:11 +01001114
Simon Kelley4f7b3042012-11-28 21:27:02 +00001115 va_start(ap, format); /* make ap point to 1st unamed argument */
Simon Kelleyc3667172017-10-13 23:26:29 +01001116
1117 if (truncp && *truncp)
1118 goto truncated;
1119
Simon Kelleyb75e9362012-12-07 11:50:41 +00001120 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001121 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001122 CHECK_LIMIT(2);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001123 PUTSHORT(nameoffset | 0xc000, p);
1124 }
1125 else
1126 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001127 char *name = va_arg(ap, char *);
Simon Kelley62cb9362017-09-26 22:00:11 +01001128 if (name && !(p = do_rfc1035_name(p, name, limit)))
Simon Kelleyc3667172017-10-13 23:26:29 +01001129 goto truncated;
Simon Kelley62cb9362017-09-26 22:00:11 +01001130
Simon Kelleyb75e9362012-12-07 11:50:41 +00001131 if (nameoffset < 0)
1132 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001133 CHECK_LIMIT(2);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001134 PUTSHORT(-nameoffset | 0xc000, p);
1135 }
1136 else
Simon Kelley62cb9362017-09-26 22:00:11 +01001137 {
1138 CHECK_LIMIT(1);
1139 *p++ = 0;
1140 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001141 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001142
Simon Kelley62cb9362017-09-26 22:00:11 +01001143 /* type (2) + class (2) + ttl (4) + rdlen (2) */
1144 CHECK_LIMIT(10);
1145
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001146 PUTSHORT(type, p);
1147 PUTSHORT(class, p);
1148 PUTLONG(ttl, p); /* TTL */
1149
1150 sav = p; /* Save pointer to RDLength field */
1151 PUTSHORT(0, p); /* Placeholder RDLength */
1152
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001153 for (; *format; format++)
1154 switch (*format)
1155 {
1156#ifdef HAVE_IPV6
1157 case '6':
Simon Kelley0549c732017-09-25 18:17:11 +01001158 CHECK_LIMIT(IN6ADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001159 sval = va_arg(ap, char *);
1160 memcpy(p, sval, IN6ADDRSZ);
1161 p += IN6ADDRSZ;
1162 break;
1163#endif
1164
1165 case '4':
Simon Kelley0549c732017-09-25 18:17:11 +01001166 CHECK_LIMIT(INADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001167 sval = va_arg(ap, char *);
1168 memcpy(p, sval, INADDRSZ);
1169 p += INADDRSZ;
1170 break;
1171
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001172 case 'b':
Simon Kelley0549c732017-09-25 18:17:11 +01001173 CHECK_LIMIT(1);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001174 usval = va_arg(ap, int);
1175 *p++ = usval;
1176 break;
1177
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001178 case 's':
Simon Kelley0549c732017-09-25 18:17:11 +01001179 CHECK_LIMIT(2);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001180 usval = va_arg(ap, int);
1181 PUTSHORT(usval, p);
1182 break;
1183
1184 case 'l':
Simon Kelley0549c732017-09-25 18:17:11 +01001185 CHECK_LIMIT(4);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001186 lval = va_arg(ap, long);
1187 PUTLONG(lval, p);
1188 break;
1189
1190 case 'd':
Simon Kelley0549c732017-09-25 18:17:11 +01001191 /* get domain-name answer arg and store it in RDATA field */
1192 if (offset)
1193 *offset = p - (unsigned char *)header;
Simon Kelleyc3667172017-10-13 23:26:29 +01001194 if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
1195 goto truncated;
1196 CHECK_LIMIT(1);
Simon Kelley0549c732017-09-25 18:17:11 +01001197 *p++ = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001198 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001199
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001200 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001201 usval = va_arg(ap, int);
Simon Kelley0549c732017-09-25 18:17:11 +01001202 CHECK_LIMIT(usval);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001203 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001204 if (usval != 0)
1205 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001206 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001207 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001208
1209 case 'z':
1210 sval = va_arg(ap, char *);
1211 usval = sval ? strlen(sval) : 0;
1212 if (usval > 255)
1213 usval = 255;
Simon Kelley0549c732017-09-25 18:17:11 +01001214 CHECK_LIMIT(usval + 1);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001215 *p++ = (unsigned char)usval;
1216 memcpy(p, sval, usval);
1217 p += usval;
1218 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001219 }
1220
1221 va_end(ap); /* clean up variable argument pointer */
1222
Simon Kelleyc3667172017-10-13 23:26:29 +01001223 /* Now, store real RDLength. sav already checked against limit. */
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001224 j = p - sav - 2;
Simon Kelleyc3667172017-10-13 23:26:29 +01001225 PUTSHORT(j, sav);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001226
1227 *pp = p;
1228 return 1;
Simon Kelleyc3667172017-10-13 23:26:29 +01001229
1230 truncated:
1231 va_end(ap);
1232 if (truncp)
1233 *truncp = 1;
1234 return 0;
1235
1236#undef CHECK_LIMIT
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001237}
1238
Simon Kelley9009d742008-11-14 20:04:27 +00001239static unsigned long crec_ttl(struct crec *crecp, time_t now)
1240{
1241 /* Return 0 ttl for DHCP entries, which might change
Simon Kelley7480aef2016-02-26 21:58:20 +00001242 before the lease expires, unless configured otherwise. */
Simon Kelley9009d742008-11-14 20:04:27 +00001243
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001244 if (crecp->flags & F_DHCP)
Simon Kelley7480aef2016-02-26 21:58:20 +00001245 {
1246 int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
1247
1248 /* Apply ceiling of actual lease length to configured TTL. */
1249 if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
1250 return crecp->ttd - now;
1251
1252 return conf_ttl;
1253 }
Simon Kelley9009d742008-11-14 20:04:27 +00001254
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001255 /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
1256 if (crecp->flags & F_IMMORTAL)
1257 return crecp->ttd;
1258
klemens43517fc2017-02-19 15:53:37 +00001259 /* Return the Max TTL value if it is lower than the actual TTL */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001260 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1261 return crecp->ttd - now;
1262 else
1263 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001264}
1265
1266
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001267/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001268size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001269 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001270 time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001271{
Simon Kelley3be34542004-09-11 19:12:13 +01001272 char *name = daemon->namebuff;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001273 unsigned char *p, *ansp;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001274 unsigned int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001275 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001276 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001277 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001278 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001279 int dryrun = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001280 struct crec *crecp;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001281 int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001282 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001283 size_t len;
Simon Kelleyfa785732016-07-22 20:56:01 +01001284
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001285 if (ntohs(header->ancount) != 0 ||
1286 ntohs(header->nscount) != 0 ||
1287 ntohs(header->qdcount) == 0 ||
1288 OPCODE(header) != QUERY )
1289 return 0;
Simon Kelley087eb762017-10-30 23:16:54 +00001290
1291 /* always servfail queries with RD unset, to avoid cache snooping. */
1292 if (!(header->hb3 & HB3_RD))
1293 return setup_reply(header, qlen, NULL, F_SERVFAIL, 0);
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001294
Simon Kelleye243c072014-02-06 18:14:09 +00001295 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001296 if (header->hb4 & HB4_CD)
1297 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001298
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001299 /* If there is an additional data section then it will be overwritten by
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001300 partial replies, so we have to do a dry run to see if we can answer
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001301 the query. */
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001302 if (ntohs(header->arcount) != 0)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001303 dryrun = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001304
Simon Kelley0a852542005-03-23 20:28:59 +00001305 for (rec = daemon->mxnames; rec; rec = rec->next)
1306 rec->offset = 0;
1307
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001308 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001309 /* determine end of question section (we put answers there) */
1310 if (!(ansp = skip_questions(header, qlen)))
1311 return 0; /* bad packet */
1312
1313 /* now process each question, answers go in RRs after the question */
1314 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001315
Simon Kelley5aabfc72007-08-29 11:24:47 +01001316 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001317 {
1318 /* save pointer to name for copying into answers */
1319 nameoffset = p - (unsigned char *)header;
1320
1321 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001322 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001323 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001324
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001325 GETSHORT(qtype, p);
1326 GETSHORT(qclass, p);
1327
1328 ans = 0; /* have we answered this question */
1329
Simon Kelley0a852542005-03-23 20:28:59 +00001330 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001331 {
Simon Kelley0a852542005-03-23 20:28:59 +00001332 struct txt_record *t;
1333 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001334 {
Simon Kelley0a852542005-03-23 20:28:59 +00001335 if (t->class == qclass && hostname_isequal(name, t->name))
1336 {
1337 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001338 if (!dryrun)
1339 {
Simon Kelleyfec216d2014-03-27 20:54:34 +00001340 unsigned long ttl = daemon->local_ttl;
1341 int ok = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001342 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001343#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001344 /* Dynamically generate stat record */
1345 if (t->stat != 0)
1346 {
1347 ttl = 0;
1348 if (!cache_make_stat(t))
1349 ok = 0;
1350 }
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001351#endif
Simon Kelleyfec216d2014-03-27 20:54:34 +00001352 if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1353 ttl, NULL,
1354 T_TXT, t->class, "t", t->len, t->txt))
Simon Kelleye17fb622006-01-14 20:33:46 +00001355 anscount++;
1356
1357 }
Simon Kelley0a852542005-03-23 20:28:59 +00001358 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001359 }
Simon Kelley0a852542005-03-23 20:28:59 +00001360 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001361
Simon Kelley0a852542005-03-23 20:28:59 +00001362 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001363 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001364 struct txt_record *t;
1365
1366 for (t = daemon->rr; t; t = t->next)
1367 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1368 {
1369 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001370 sec_data = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001371 if (!dryrun)
1372 {
1373 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1374 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1375 daemon->local_ttl, NULL,
1376 t->class, C_IN, "t", t->len, t->txt))
1377 anscount ++;
1378 }
1379 }
1380
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001381 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001382 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001383 /* see if it's w.z.y.z.in-addr.arpa format */
1384 int is_arpa = in_arpa_name_2_addr(name, &addr);
1385 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001386 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001387
1388 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1389 if (hostname_isequal(name, ptr->name))
1390 break;
1391
Simon Kelleyf2621c72007-04-29 19:47:21 +01001392 if (is_arpa == F_IPV4)
1393 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001394 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001395 struct addrlist *addrlist;
1396
Simon Kelley376d48c2013-11-13 13:04:30 +00001397 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1398 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001399 break;
1400
1401 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001402 break;
1403 else
1404 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1405 intr = intr->next;
1406 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001407#ifdef HAVE_IPV6
1408 else if (is_arpa == F_IPV6)
1409 for (intr = daemon->int_names; intr; intr = intr->next)
1410 {
1411 struct addrlist *addrlist;
1412
Simon Kelley376d48c2013-11-13 13:04:30 +00001413 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1414 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001415 break;
1416
1417 if (addrlist)
1418 break;
1419 else
1420 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1421 intr = intr->next;
1422 }
1423#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001424
1425 if (intr)
1426 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001427 sec_data = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001428 ans = 1;
1429 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001430 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001431 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001432 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1433 daemon->local_ttl, NULL,
1434 T_PTR, C_IN, "d", intr->name))
1435 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001436 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001437 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001438 else if (ptr)
1439 {
1440 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001441 sec_data = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001442 if (!dryrun)
1443 {
Simon Kelley28866e92011-02-14 20:19:14 +00001444 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001445 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001446 if (hostname_isequal(name, ptr->name) &&
1447 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1448 daemon->local_ttl, NULL,
1449 T_PTR, C_IN, "d", ptr->ptr))
1450 anscount++;
1451
Simon Kelley832af0b2007-01-21 20:01:28 +00001452 }
1453 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001454 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001455 {
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001456 /* Don't use cache when DNSSEC data required, unless we know that
1457 the zone is unsigned, which implies that we're doing
1458 validation. */
1459 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001460 !do_bit ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001461 (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001462 {
1463 do
1464 {
1465 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1466 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1467 continue;
1468
1469 if (!(crecp->flags & F_DNSSECOK))
1470 sec_data = 0;
Simon Kelley93be5b12015-12-15 12:04:40 +00001471
1472 ans = 1;
1473
Simon Kelley2d33bda2014-01-24 22:37:25 +00001474 if (crecp->flags & F_NEG)
1475 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001476 auth = 0;
1477 if (crecp->flags & F_NXDOMAIN)
1478 nxdomain = 1;
1479 if (!dryrun)
1480 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1481 }
Simon Kelley93be5b12015-12-15 12:04:40 +00001482 else
Simon Kelley2d33bda2014-01-24 22:37:25 +00001483 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001484 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1485 auth = 0;
1486 if (!dryrun)
1487 {
1488 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1489 record_source(crecp->uid));
1490
1491 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1492 crec_ttl(crecp, now), NULL,
1493 T_PTR, C_IN, "d", cache_get_name(crecp)))
1494 anscount++;
1495 }
1496 }
1497 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1498 }
1499 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001500 else if (is_rev_synth(is_arpa, &addr, name))
1501 {
1502 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001503 sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001504 if (!dryrun)
1505 {
1506 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1507
1508 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1509 daemon->local_ttl, NULL,
1510 T_PTR, C_IN, "d", name))
1511 anscount++;
1512 }
1513 }
Simon Kelleyfca008d2017-02-19 18:50:41 +00001514 else if (option_bool(OPT_BOGUSPRIV) && (
1515#ifdef HAVE_IPV6
1516 (is_arpa == F_IPV6 && private_net6(&addr.addr.addr6)) ||
1517#endif
1518 (is_arpa == F_IPV4 && private_net(addr.addr.addr4, 1))))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001519 {
Vladislav Grishenko5a7212c2017-04-24 22:19:57 +01001520 struct server *serv;
1521 unsigned int namelen = strlen(name);
1522 char *nameend = name + namelen;
1523
1524 /* see if have rev-server set */
1525 for (serv = daemon->servers; serv; serv = serv->next)
1526 {
1527 unsigned int domainlen;
1528 char *matchstart;
1529
1530 if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
1531 continue;
1532
1533 domainlen = strlen(serv->domain);
1534 if (domainlen == 0 || domainlen > namelen)
1535 continue;
1536
1537 matchstart = nameend - domainlen;
1538 if (hostname_isequal(matchstart, serv->domain) &&
1539 (namelen == domainlen || *(matchstart-1) == '.' ))
1540 break;
1541 }
1542
1543 /* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
1544 if (!serv)
1545 {
1546 ans = 1;
1547 sec_data = 0;
1548 nxdomain = 1;
1549 if (!dryrun)
1550 log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
1551 name, &addr, NULL);
1552 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001553 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001554 }
Simon Kelleyfca008d2017-02-19 18:50:41 +00001555
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001556 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1557 {
1558 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001559 struct interface_name *intr;
1560
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001561 if (flag == F_IPV6)
1562#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001563 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001564#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001565 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001566#endif
1567
1568 if (qtype != type && qtype != T_ANY)
1569 continue;
1570
Simon Kelleyf2621c72007-04-29 19:47:21 +01001571 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001572 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001573 for (intr = daemon->int_names; intr; intr = intr->next)
1574 if (hostname_isequal(name, intr->name))
1575 break;
1576
1577 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001578 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001579 struct addrlist *addrlist;
Simon Kelleyd42d4702017-02-02 16:52:06 +00001580 int gotit = 0, localise = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001581
Simon Kelley115ac3e2013-05-20 11:28:32 +01001582 enumerate_interfaces(0);
Simon Kelleyd42d4702017-02-02 16:52:06 +00001583
klemens43517fc2017-02-19 15:53:37 +00001584 /* See if a putative address is on the network from which we received
Simon Kelleyd42d4702017-02-02 16:52:06 +00001585 the query, is so we'll filter other answers. */
1586 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && type == T_A)
1587 for (intr = daemon->int_names; intr; intr = intr->next)
1588 if (hostname_isequal(name, intr->name))
1589 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1590#ifdef HAVE_IPV6
1591 if (!(addrlist->flags & ADDRLIST_IPV6))
1592#endif
1593 if (is_same_net(*((struct in_addr *)&addrlist->addr), local_addr, local_netmask))
1594 {
1595 localise = 1;
1596 break;
1597 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001598
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001599 for (intr = daemon->int_names; intr; intr = intr->next)
1600 if (hostname_isequal(name, intr->name))
1601 {
Simon Kelley47669362014-12-17 12:41:56 +00001602 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley376d48c2013-11-13 13:04:30 +00001603#ifdef HAVE_IPV6
Simon Kelley47669362014-12-17 12:41:56 +00001604 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
Simon Kelley376d48c2013-11-13 13:04:30 +00001605#endif
Simon Kelley47669362014-12-17 12:41:56 +00001606 {
Simon Kelleyd42d4702017-02-02 16:52:06 +00001607 if (localise &&
1608 !is_same_net(*((struct in_addr *)&addrlist->addr), local_addr, local_netmask))
1609 continue;
1610
Simon Kelley47669362014-12-17 12:41:56 +00001611#ifdef HAVE_IPV6
1612 if (addrlist->flags & ADDRLIST_REVONLY)
1613 continue;
1614#endif
1615 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001616 sec_data = 0;
Simon Kelley47669362014-12-17 12:41:56 +00001617 if (!dryrun)
Simon Kelley376d48c2013-11-13 13:04:30 +00001618 {
1619 gotit = 1;
1620 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1621 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1622 daemon->local_ttl, NULL, type, C_IN,
1623 type == T_A ? "4" : "6", &addrlist->addr))
1624 anscount++;
1625 }
Simon Kelley47669362014-12-17 12:41:56 +00001626 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001627 }
1628
1629 if (!dryrun && !gotit)
1630 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1631
Simon Kelley115ac3e2013-05-20 11:28:32 +01001632 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001633 }
1634
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001635 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00001636 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001637 {
1638 int localise = 0;
1639
Josh Soref730c6742017-02-06 16:14:04 +00001640 /* See if a putative address is on the network from which we received
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001641 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001642 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001643 {
1644 struct crec *save = crecp;
1645 do {
1646 if ((crecp->flags & F_HOSTS) &&
1647 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1648 {
1649 localise = 1;
1650 break;
1651 }
1652 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1653 crecp = save;
1654 }
Simon Kelley824202e2014-01-23 20:59:46 +00001655
Simon Kelley93be5b12015-12-15 12:04:40 +00001656 /* If the client asked for DNSSEC don't use cached data. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001657 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
Simon Kelley824202e2014-01-23 20:59:46 +00001658 do
1659 {
1660 /* don't answer wildcard queries with data not from /etc/hosts
1661 or DHCP leases */
1662 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1663 break;
1664
1665 if (!(crecp->flags & F_DNSSECOK))
1666 sec_data = 0;
1667
1668 if (crecp->flags & F_CNAME)
1669 {
1670 char *cname_target = cache_get_cname_target(crecp);
1671
1672 if (!dryrun)
1673 {
1674 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1675 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1676 crec_ttl(crecp, now), &nameoffset,
1677 T_CNAME, C_IN, "d", cname_target))
1678 anscount++;
1679 }
1680
1681 strcpy(name, cname_target);
1682 /* check if target interface_name */
Andy3e21a1a2014-03-22 19:10:07 +00001683 if (crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelley824202e2014-01-23 20:59:46 +00001684 goto intname_restart;
1685 else
1686 goto cname_restart;
1687 }
1688
1689 if (crecp->flags & F_NEG)
1690 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001691 ans = 1;
1692 auth = 0;
1693 if (crecp->flags & F_NXDOMAIN)
1694 nxdomain = 1;
1695 if (!dryrun)
1696 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley824202e2014-01-23 20:59:46 +00001697 }
1698 else
1699 {
1700 /* If we are returning local answers depending on network,
1701 filter here. */
1702 if (localise &&
1703 (crecp->flags & F_HOSTS) &&
1704 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1705 continue;
1706
1707 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1708 auth = 0;
1709
1710 ans = 1;
1711 if (!dryrun)
1712 {
1713 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
1714 record_source(crecp->uid));
1715
1716 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1717 crec_ttl(crecp, now), NULL, type, C_IN,
1718 type == T_A ? "4" : "6", &crecp->addr))
1719 anscount++;
1720 }
1721 }
1722 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001723 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001724 else if (is_name_synthetic(flag, name, &addr))
1725 {
1726 ans = 1;
1727 if (!dryrun)
1728 {
1729 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
1730 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1731 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
1732 anscount++;
1733 }
1734 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001735 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001736
1737 if (qtype == T_CNAME || qtype == T_ANY)
1738 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001739 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
1740 (qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
1741 ((crecp->flags & F_CONFIG) || !do_bit || !(crecp->flags & F_DNSSECOK)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001742 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001743 if (!(crecp->flags & F_DNSSECOK))
1744 sec_data = 0;
1745
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001746 ans = 1;
1747 if (!dryrun)
1748 {
1749 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1750 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1751 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01001752 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001753 anscount++;
1754 }
1755 }
1756 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001757
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001758 if (qtype == T_MX || qtype == T_ANY)
1759 {
1760 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001761 for (rec = daemon->mxnames; rec; rec = rec->next)
1762 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001763 {
1764 ans = found = 1;
1765 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001766 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001767 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001768 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00001769 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1770 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1771 {
1772 anscount++;
1773 if (rec->target)
1774 rec->offset = offset;
1775 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001776 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001777 }
1778
Simon Kelley28866e92011-02-14 20:19:14 +00001779 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00001780 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001781 {
1782 ans = 1;
1783 if (!dryrun)
1784 {
Simon Kelley28866e92011-02-14 20:19:14 +00001785 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001786 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1787 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00001788 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001789 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001790 }
1791 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001792 }
1793
1794 if (qtype == T_SRV || qtype == T_ANY)
1795 {
1796 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001797 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
1798
Simon Kelley0a852542005-03-23 20:28:59 +00001799 for (rec = daemon->mxnames; rec; rec = rec->next)
1800 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001801 {
1802 found = ans = 1;
1803 if (!dryrun)
1804 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001805 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001806 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001807 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001808 &offset, T_SRV, C_IN, "sssd",
1809 rec->priority, rec->weight, rec->srvport, rec->target))
1810 {
1811 anscount++;
1812 if (rec->target)
1813 rec->offset = offset;
1814 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001815 }
Simon Kelley28866e92011-02-14 20:19:14 +00001816
1817 /* unlink first SRV record found */
1818 if (!move)
1819 {
1820 move = rec;
1821 *up = rec->next;
1822 }
1823 else
1824 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001825 }
Simon Kelley28866e92011-02-14 20:19:14 +00001826 else
1827 up = &rec->next;
1828
1829 /* put first SRV record back at the end. */
1830 if (move)
1831 {
1832 *up = move;
1833 move->next = NULL;
1834 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001835
Simon Kelley28866e92011-02-14 20:19:14 +00001836 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001837 {
1838 ans = 1;
1839 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001840 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001841 }
1842 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001843
1844 if (qtype == T_NAPTR || qtype == T_ANY)
1845 {
1846 struct naptr *na;
1847 for (na = daemon->naptr; na; na = na->next)
1848 if (hostname_isequal(name, na->name))
1849 {
1850 ans = 1;
1851 if (!dryrun)
1852 {
Simon Kelley28866e92011-02-14 20:19:14 +00001853 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001854 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1855 NULL, T_NAPTR, C_IN, "sszzzd",
1856 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1857 anscount++;
1858 }
1859 }
1860 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001861
1862 if (qtype == T_MAILB)
1863 ans = 1, nxdomain = 1;
1864
Simon Kelley28866e92011-02-14 20:19:14 +00001865 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001866 {
1867 ans = 1;
1868 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001869 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001870 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001871 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001872
1873 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001874 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001875 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001876
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001877 if (dryrun)
1878 {
1879 dryrun = 0;
1880 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001881 }
1882
Simon Kelley0a852542005-03-23 20:28:59 +00001883 /* create an additional data section, for stuff in SRV and MX record replies. */
1884 for (rec = daemon->mxnames; rec; rec = rec->next)
1885 if (rec->offset != 0)
1886 {
1887 /* squash dupes */
1888 struct mx_srv_record *tmp;
1889 for (tmp = rec->next; tmp; tmp = tmp->next)
1890 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1891 tmp->offset = 0;
1892
1893 crecp = NULL;
1894 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1895 {
Simon Kelley0a852542005-03-23 20:28:59 +00001896#ifdef HAVE_IPV6
1897 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
1898#else
1899 int type = T_A;
1900#endif
1901 if (crecp->flags & F_NEG)
1902 continue;
1903
Simon Kelley9009d742008-11-14 20:04:27 +00001904 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
1905 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00001906 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1907 addncount++;
1908 }
1909 }
1910
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001911 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00001912 /* clear authoritative and truncated flags, set QR flag */
1913 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1914 /* set RA flag */
1915 header->hb4 |= HB4_RA;
1916
Josh Soref730c6742017-02-06 16:14:04 +00001917 /* authoritative - only hosts and DHCP derived names. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001918 if (auth)
1919 header->hb3 |= HB3_AA;
1920
1921 /* truncation */
1922 if (trunc)
1923 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001924
Simon Kelley45cca582013-10-15 10:20:13 +01001925 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00001926 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001927 else
Simon Kelley572b41e2011-02-18 18:11:18 +00001928 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001929 header->ancount = htons(anscount);
1930 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00001931 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00001932
Simon Kelleya25720a2014-01-14 23:13:55 +00001933 len = ansp - (unsigned char *)header;
1934
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001935 /* Advertise our packet size limit in our reply */
Simon Kelleya25720a2014-01-14 23:13:55 +00001936 if (have_pseudoheader)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00001937 len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
Simon Kelleye243c072014-02-06 18:14:09 +00001938
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001939 if (ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00001940 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00001941 else
1942 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00001943
Simon Kelley7c286122014-01-27 21:38:11 +00001944 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001945}