blob: ea438c249990fced0b2de60d928c098632617ca0 [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 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 Kelleycc921df2019-01-02 22:48:59 +0000146int in_arpa_name_2_addr(char *namein, union 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
Simon Kelleycc921df2019-01-02 22:48:59 +0000156 memset(addrp, 0, sizeof(union all_addr));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000157
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 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000201 else if (hostname_isequal(penchunk, "ip6") &&
202 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
203 {
204 /* IP v6:
205 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
206 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
207
Josh Soref730c6742017-02-06 16:14:04 +0000208 Note that most of these the various representations are obsolete and
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000209 left-over from the many DNS-for-IPv6 wars. We support all the formats
210 that we can since there is no reason not to.
211 */
212
213 if (*name == '\\' && *(name+1) == '[' &&
214 (*(name+2) == 'x' || *(name+2) == 'X'))
215 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000216 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000217 {
218 char xdig[2];
219 xdig[0] = *cp1;
220 xdig[1] = 0;
221 if (j%2)
222 addr[j/2] |= strtol(xdig, NULL, 16);
223 else
224 addr[j/2] = strtol(xdig, NULL, 16) << 4;
225 }
226
227 if (*cp1 == '/' && j == 32)
228 return F_IPV6;
229 }
230 else
231 {
232 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
233 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000234 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000235 return 0;
236
Simon Kelleycc921df2019-01-02 22:48:59 +0000237 for (j = sizeof(struct in6_addr)-1; j>0; j--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000238 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
239 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
240 }
241
242 return F_IPV6;
243 }
244 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000245
246 return 0;
247}
248
Giovanni Bajo32f82c62012-04-28 01:01:16 +0200249unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100250{
251 while(1)
252 {
Simon Kelley9009d742008-11-14 20:04:27 +0000253 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100254
Simon Kelley9009d742008-11-14 20:04:27 +0000255 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100256 return NULL;
257
Simon Kelley9009d742008-11-14 20:04:27 +0000258 label_type = (*ansp) & 0xc0;
259
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100260 if (label_type == 0xc0)
261 {
262 /* pointer for compression. */
263 ansp += 2;
264 break;
265 }
266 else if (label_type == 0x80)
267 return NULL; /* reserved */
268 else if (label_type == 0x40)
269 {
270 /* Extended label type */
271 unsigned int count;
272
Simon Kelley9009d742008-11-14 20:04:27 +0000273 if (!CHECK_LEN(header, ansp, plen, 2))
274 return NULL;
275
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100276 if (((*ansp++) & 0x3f) != 1)
277 return NULL; /* we only understand bitstrings */
278
279 count = *(ansp++); /* Bits in bitstring */
280
281 if (count == 0) /* count == 0 means 256 bits */
282 ansp += 32;
283 else
284 ansp += ((count-1)>>3)+1;
285 }
286 else
287 { /* label type == 0 Bottom six bits is length */
288 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000289
290 if (!ADD_RDLEN(header, ansp, plen, len))
291 return NULL;
292
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100293 if (len == 0)
294 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100295 }
296 }
Simon Kelley9009d742008-11-14 20:04:27 +0000297
298 if (!CHECK_LEN(header, ansp, plen, extrabytes))
299 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100300
301 return ansp;
302}
303
Simon Kelley4f7b3042012-11-28 21:27:02 +0000304unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000305{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100306 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000307 unsigned char *ansp = (unsigned char *)(header+1);
308
Simon Kelley5aabfc72007-08-29 11:24:47 +0100309 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000310 {
Simon Kelley9009d742008-11-14 20:04:27 +0000311 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100312 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000313 ansp += 4; /* class and type */
314 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000315
316 return ansp;
317}
318
Simon Kelley5107ace2014-02-23 10:48:32 +0000319unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100320{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100321 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100322
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100323 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100324 {
Simon Kelley9009d742008-11-14 20:04:27 +0000325 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100326 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100327 ansp += 8; /* type, class, TTL */
328 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000329 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100330 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100331 }
332
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100333 return ansp;
334}
335
Simon Kelley572b41e2011-02-18 18:11:18 +0000336size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100337{
338 unsigned char *ansp = skip_questions(header, plen);
339
Simon Kelley9009d742008-11-14 20:04:27 +0000340 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100341 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000342 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100343
344 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
345 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000346 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100347
Simon Kelley36717ee2004-09-20 19:20:58 +0100348 /* restore pseudoheader */
349 if (pheader && ntohs(header->arcount) == 0)
350 {
351 /* must use memmove, may overlap */
352 memmove(ansp, pheader, hlen);
353 header->arcount = htons(1);
354 ansp += hlen;
355 }
356
357 return ansp - (unsigned char *)header;
358}
359
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000360/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100361int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000362{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100363 in_addr_t ip_addr = ntohl(addr.s_addr);
364
365 return
Simon Kelleyd2aa7df2015-08-03 21:52:12 +0100366 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
367 ((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. "here" network */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100368 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
369 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
Simon Kelley90477fb2015-10-20 21:21:32 +0100370 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
371 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
372 ((ip_addr & 0xFFFFFF00) == 0xC0000200) /* 192.0.2.0/24 (test-net) */ ||
373 ((ip_addr & 0xFFFFFF00) == 0xC6336400) /* 198.51.100.0/24(test-net) */ ||
374 ((ip_addr & 0xFFFFFF00) == 0xCB007100) /* 203.0.113.0/24 (test-net) */ ||
375 ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 (broadcast)*/ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000376}
Simon Kelley1cff1662004-03-12 08:12:58 +0000377
Simon Kelleyfca008d2017-02-19 18:50:41 +0000378static int private_net6(struct in6_addr *a)
379{
380 return
381 IN6_IS_ADDR_UNSPECIFIED(a) || /* RFC 6303 4.3 */
382 IN6_IS_ADDR_LOOPBACK(a) || /* RFC 6303 4.3 */
383 IN6_IS_ADDR_LINKLOCAL(a) || /* RFC 6303 4.5 */
384 ((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
385 ((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
386}
Simon Kelleyfca008d2017-02-19 18:50:41 +0000387
Simon Kelley6938f342014-01-26 22:47:39 +0000388static 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 +0000389{
390 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000391
392 for (i = count; i != 0; i--)
393 {
Simon Kelley28866e92011-02-14 20:19:14 +0000394 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100395 {
396 if (!extract_name(header, qlen, &p, name, 1, 10))
397 return 0;
398 }
399 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000400 return 0; /* bad packet */
401
402 GETSHORT(qtype, p);
403 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100404 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000405 GETSHORT(rdlen, p);
406
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100407 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000408 {
409 struct doctor *doctor;
410 struct in_addr addr;
411
Simon Kelley9009d742008-11-14 20:04:27 +0000412 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
413 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100414
415 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000416 memcpy(&addr, p, INADDRSZ);
417
418 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000419 {
420 if (doctor->end.s_addr == 0)
421 {
422 if (!is_same_net(doctor->in, addr, doctor->mask))
423 continue;
424 }
425 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
426 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
427 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100428
Simon Kelley73a08a22009-02-05 20:28:08 +0000429 addr.s_addr &= ~doctor->mask.s_addr;
430 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
431 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000432 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000433 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000434 memcpy(p, &addr, INADDRSZ);
435 break;
436 }
Simon Kelley824af852008-02-12 20:43:05 +0000437 }
Simon Kelley28866e92011-02-14 20:19:14 +0000438 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100439 {
440 unsigned char *p1 = p;
441 if (!CHECK_LEN(header, p1, qlen, rdlen))
442 return 0;
443 while ((p1 - p) < rdlen)
444 {
445 unsigned int i, len = *p1;
446 unsigned char *p2 = p1;
Simon Kelley6a0b00f2017-09-25 20:19:55 +0100447 if ((p1 + len - p) >= rdlen)
448 return 0; /* bad packet */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100449 /* make counted string zero-term and sanitise */
450 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100451 {
452 if (!isprint((int)*(p2+1)))
453 break;
454
455 *p2 = *(p2+1);
456 p2++;
457 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100458 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000459 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100460 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100461 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100462 *p1 = len;
463 p1 += len+1;
464 }
465 }
Simon Kelley824af852008-02-12 20:43:05 +0000466
Simon Kelley9009d742008-11-14 20:04:27 +0000467 if (!ADD_RDLEN(header, p, qlen, rdlen))
468 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000469 }
470
471 return p;
472}
473
Simon Kelley6938f342014-01-26 22:47:39 +0000474static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000475{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100476 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000477 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100478 unsigned long ttl, minttl = ULONG_MAX;
479 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000480
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100481 /* first move to NS section and find TTL from any SOA section */
482 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000483 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000484 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000485
Simon Kelley5aabfc72007-08-29 11:24:47 +0100486 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000487 {
Simon Kelley9009d742008-11-14 20:04:27 +0000488 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100489 return 0; /* bad packet */
490
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000491 GETSHORT(qtype, p);
492 GETSHORT(qclass, p);
493 GETLONG(ttl, p);
494 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100495
496 if ((qclass == C_IN) && (qtype == T_SOA))
497 {
498 found_soa = 1;
499 if (ttl < minttl)
500 minttl = ttl;
501
502 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000503 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100504 return 0;
505 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000506 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100507 return 0;
508 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
509
510 GETLONG(ttl, p); /* minTTL */
511 if (ttl < minttl)
512 minttl = ttl;
513 }
Simon Kelley9009d742008-11-14 20:04:27 +0000514 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100515 return 0; /* bad packet */
516 }
Simon Kelley9009d742008-11-14 20:04:27 +0000517
Simon Kelley6938f342014-01-26 22:47:39 +0000518 /* rewrite addresses in additional section too */
519 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000520 return 0;
521
522 if (!found_soa)
523 minttl = daemon->neg_ttl;
524
525 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100526}
527
528/* Note that the following code can create CNAME chains that don't point to a real record,
529 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 +0000530 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100531 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000532int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelleya6004d72017-10-25 17:48:19 +0100533 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
Simon Kelley373e9172017-12-01 22:40:56 +0000534 int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100535{
Simon Kelley824af852008-02-12 20:43:05 +0000536 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100537 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000538 unsigned long ttl = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000539 union all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000540#ifdef HAVE_IPSET
541 char **ipsets_cur;
542#else
543 (void)ipsets; /* unused */
544#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100545
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000546
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100547 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000548
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100549 /* 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 +0000550 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000551 {
552 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000553 ttl = find_soa(header, qlen, name, doctored);
Simon Kelleya6004d72017-10-25 17:48:19 +0100554
555 if (*doctored)
556 {
557 if (secure)
558 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000559#ifdef HAVE_DNSSEC
Simon Kelley373e9172017-12-01 22:40:56 +0000560 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleya6004d72017-10-25 17:48:19 +0100561 for (i = 0; i < ntohs(header->ancount); i++)
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100562 if (daemon->rr_status[i] != 0)
Simon Kelleya6004d72017-10-25 17:48:19 +0100563 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000564#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100565 }
Simon Kelley0a852542005-03-23 20:28:59 +0000566 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100567
568 /* go through the questions. */
569 p = (unsigned char *)(header+1);
570
Simon Kelley5aabfc72007-08-29 11:24:47 +0100571 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100572 {
Simon Kelley1fbe4d22014-03-01 20:03:47 +0000573 int found = 0, cname_count = CNAME_CHAIN;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100574 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000575 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000576#ifdef HAVE_DNSSEC
Simon Kelleya6004d72017-10-25 17:48:19 +0100577 int cname_short = 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000578#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000579 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000580
Simon Kelley824af852008-02-12 20:43:05 +0000581 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000582 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000583 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100584
585 GETSHORT(qtype, p);
586 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000587
588 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100589 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000590
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100591 /* PTRs: we chase CNAMEs here, since we have no way to
592 represent them in the cache. */
593 if (qtype == T_PTR)
594 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000595 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100596
597 if (!name_encoding)
598 continue;
599
600 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000601 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100602 cname_loop:
603 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000604 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100605
Simon Kelleya6004d72017-10-25 17:48:19 +0100606 for (j = 0; j < ntohs(header->ancount); j++)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100607 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100608 int secflag = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000609 unsigned char *tmp = namep;
610 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000611 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
612 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000613 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100614
615 GETSHORT(aqtype, p1);
616 GETSHORT(aqclass, p1);
617 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100618 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
619 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000620 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100621 PUTLONG(daemon->max_ttl, p1);
622 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100623 GETSHORT(ardlen, p1);
624 endrr = p1+ardlen;
625
626 /* TTL of record is minimum of CNAMES and PTR */
627 if (attl < cttl)
628 cttl = attl;
629
630 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
631 {
Simon Kelley9009d742008-11-14 20:04:27 +0000632 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000633 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000634#ifdef HAVE_DNSSEC
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100635 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
Simon Kelleya6004d72017-10-25 17:48:19 +0100636 {
637 /* validated RR anywhere in CNAME chain, don't cache. */
638 if (cname_short || aqtype == T_CNAME)
639 return 0;
640
641 secflag = F_DNSSECOK;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100642 /* limit TTL based on signature. */
643 if (daemon->rr_status[j] < cttl)
644 cttl = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +0100645 }
Simon Kelley8c707e12017-12-05 22:28:10 +0000646#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100647
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100648 if (aqtype == T_CNAME)
649 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100650 if (!cname_count--)
651 return 0; /* looped CNAMES, we can't cache. */
Simon Kelley8c707e12017-12-05 22:28:10 +0000652#ifdef HAVE_DNSSEC
Simon Kelleya6004d72017-10-25 17:48:19 +0100653 cname_short = 1;
Simon Kelley8c707e12017-12-05 22:28:10 +0000654#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100655 goto cname_loop;
656 }
657
Simon Kelley65a01b72018-12-31 23:56:33 +0000658 cache_insert(name, &addr, C_IN, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100659 found = 1;
660 }
661
662 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000663 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000664 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100665 }
666 }
667
Simon Kelley28866e92011-02-14 20:19:14 +0000668 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100669 {
670 if (!searched_soa)
671 {
672 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000673 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100674 }
675 if (ttl)
Simon Kelley65a01b72018-12-31 23:56:33 +0000676 cache_insert(NULL, &addr, C_IN, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000677 }
678 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100679 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000680 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100681 /* everything other than PTR */
682 struct crec *newc;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000683 int addrlen = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100684
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100685 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100686 {
687 addrlen = INADDRSZ;
688 flags |= F_IPV4;
689 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100690 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100691 {
692 addrlen = IN6ADDRSZ;
693 flags |= F_IPV6;
694 }
Simon Kelley5b99eae2019-01-06 23:09:50 +0000695 else if (qtype == T_SRV)
696 flags |= F_SRV;
697 else
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100698 continue;
699
Simon Kelley45cca582013-10-15 10:20:13 +0100700 cname_loop1:
701 if (!(p1 = skip_questions(header, qlen)))
702 return 0;
703
Simon Kelleya6004d72017-10-25 17:48:19 +0100704 for (j = 0; j < ntohs(header->ancount); j++)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100705 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100706 int secflag = 0;
707
Simon Kelley45cca582013-10-15 10:20:13 +0100708 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
709 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100710
Simon Kelley45cca582013-10-15 10:20:13 +0100711 GETSHORT(aqtype, p1);
712 GETSHORT(aqclass, p1);
713 GETLONG(attl, p1);
714 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000715 {
Simon Kelley45cca582013-10-15 10:20:13 +0100716 (p1) -= 4;
717 PUTLONG(daemon->max_ttl, p1);
718 }
719 GETSHORT(ardlen, p1);
720 endrr = p1+ardlen;
721
722 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
723 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100724#ifdef HAVE_DNSSEC
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100725 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
726 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100727 secflag = F_DNSSECOK;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100728
729 /* limit TTl based on sig. */
730 if (daemon->rr_status[j] < attl)
731 attl = daemon->rr_status[j];
732 }
Simon Kelleya6004d72017-10-25 17:48:19 +0100733#endif
Simon Kelley45cca582013-10-15 10:20:13 +0100734 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100735 {
Simon Kelley45cca582013-10-15 10:20:13 +0100736 if (!cname_count--)
737 return 0; /* looped CNAMES */
Simon Kelley1fd56c02019-10-30 12:58:28 +0000738
739 if ((newc = cache_insert(name, NULL, C_IN, now, attl, F_CNAME | F_FORWARD | secflag)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100740 {
Simon Kelley45cca582013-10-15 10:20:13 +0100741 newc->addr.cname.target.cache = NULL;
Simon Kelley1fd56c02019-10-30 12:58:28 +0000742 newc->addr.cname.is_name_ptr = 0;
Simon Kelley45cca582013-10-15 10:20:13 +0100743 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100744 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100745 next_uid(newc);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100746 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100747 cpp->addr.cname.uid = newc->uid;
748 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100749 }
Simon Kelley45cca582013-10-15 10:20:13 +0100750
751 cpp = newc;
752 if (attl < cttl)
753 cttl = attl;
754
Simon Kelley122997d2019-10-25 17:23:56 +0100755 namep = p1;
Simon Kelley45cca582013-10-15 10:20:13 +0100756 if (!extract_name(header, qlen, &p1, name, 1, 0))
757 return 0;
Simon Kelley122997d2019-10-25 17:23:56 +0100758
Simon Kelley45cca582013-10-15 10:20:13 +0100759 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100760 }
Simon Kelley45cca582013-10-15 10:20:13 +0100761 else if (!(flags & F_NXDOMAIN))
762 {
763 found = 1;
764
Simon Kelley5b99eae2019-01-06 23:09:50 +0000765 if (flags & F_SRV)
Simon Kelleyb059c962015-05-08 20:25:51 +0100766 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000767 unsigned char *tmp = namep;
768
769 if (!CHECK_LEN(header, p1, qlen, 6))
770 return 0; /* bad packet */
771 GETSHORT(addr.srv.priority, p1);
772 GETSHORT(addr.srv.weight, p1);
773 GETSHORT(addr.srv.srvport, p1);
774 if (!extract_name(header, qlen, &p1, name, 1, 0))
775 return 0;
776 addr.srv.targetlen = strlen(name) + 1; /* include terminating zero */
777 if (!(addr.srv.target = blockdata_alloc(name, addr.srv.targetlen)))
778 return 0;
779
780 /* we overwrote the original name, so get it back here. */
781 if (!extract_name(header, qlen, &tmp, name, 1, 0))
782 return 0;
783 }
784 else
785 {
786 /* copy address into aligned storage */
787 if (!CHECK_LEN(header, p1, qlen, addrlen))
788 return 0; /* bad packet */
789 memcpy(&addr, p1, addrlen);
790
791 /* check for returned address in private space */
792 if (check_rebind)
Simon Kelleyb059c962015-05-08 20:25:51 +0100793 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000794 if ((flags & F_IPV4) &&
795 private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
Simon Kelleyb059c962015-05-08 20:25:51 +0100796 return 1;
Dominik DL6ERe7ee1aa2020-03-17 22:59:17 +0000797
798 /* Block IPv4-mapped IPv6 addresses in private IPv4 address space */
799 if (flags & F_IPV6)
Simon Kelley5b99eae2019-01-06 23:09:50 +0000800 {
Dominik DL6ERe7ee1aa2020-03-17 22:59:17 +0000801 if (IN6_IS_ADDR_V4MAPPED(&addr.addr6))
802 {
803 struct in_addr v4;
804 v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
805 if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
806 return 1;
807 }
808
809 /* Check for link-local (LL) and site-local (ULA) IPv6 addresses */
810 if (IN6_IS_ADDR_LINKLOCAL(&addr.addr6) ||
811 IN6_IS_ADDR_SITELOCAL(&addr.addr6))
812 return 1;
813
814 /* Check for the IPv6 loopback address (::1) when
815 option rebind-localhost-ok is NOT set */
816 if (!option_bool(OPT_LOCAL_REBIND) &&
817 IN6_IS_ADDR_LOOPBACK(&addr.addr6))
Simon Kelley5b99eae2019-01-06 23:09:50 +0000818 return 1;
819 }
Simon Kelleyb059c962015-05-08 20:25:51 +0100820 }
Dominik DL6ERe7ee1aa2020-03-17 22:59:17 +0000821
Simon Kelley45cca582013-10-15 10:20:13 +0100822#ifdef HAVE_IPSET
Simon Kelley5b99eae2019-01-06 23:09:50 +0000823 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
Wang Jian49752b92014-03-28 20:52:47 +0000824 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000825 ipsets_cur = ipsets;
826 while (*ipsets_cur)
827 {
828 log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
829 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
830 }
Wang Jian49752b92014-03-28 20:52:47 +0000831 }
Simon Kelley45cca582013-10-15 10:20:13 +0100832#endif
Simon Kelley5b99eae2019-01-06 23:09:50 +0000833 }
Simon Kelley45cca582013-10-15 10:20:13 +0100834
Simon Kelley65a01b72018-12-31 23:56:33 +0000835 newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100836 if (newc && cpp)
837 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100838 next_uid(newc);
Simon Kelley45cca582013-10-15 10:20:13 +0100839 cpp->addr.cname.target.cache = newc;
840 cpp->addr.cname.uid = newc->uid;
841 }
842 cpp = NULL;
843 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100844 }
Simon Kelley45cca582013-10-15 10:20:13 +0100845
846 p1 = endrr;
847 if (!CHECK_LEN(header, p1, qlen, 0))
848 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100849 }
850
Simon Kelley28866e92011-02-14 20:19:14 +0000851 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100852 {
853 if (!searched_soa)
854 {
855 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000856 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100857 }
858 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +0000859 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100860 if (ttl || cpp)
861 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000862 newc = cache_insert(name, NULL, C_IN, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
Simon Kelley26128d22004-11-14 16:43:54 +0000863 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100864 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100865 next_uid(newc);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100866 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100867 cpp->addr.cname.uid = newc->uid;
868 }
869 }
870 }
871 }
872 }
873
Simon Kelley1023dcb2012-04-09 18:00:08 +0100874 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +0100875 Don't cache replies from non-recursive nameservers, since we may get a
876 reply containing a CNAME but not its target, even though the target
877 does exist. */
878 if (!(header->hb3 & HB3_TC) &&
879 !(header->hb4 & HB4_CD) &&
880 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +0000881 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +0000882 cache_end_insert();
883
884 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000885}
886
887/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +0000888 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +0000889unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000890{
891 unsigned char *p = (unsigned char *)(header+1);
892 int qtype, qclass;
893
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100894 if (typep)
895 *typep = 0;
896
Simon Kelley572b41e2011-02-18 18:11:18 +0000897 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898 return 0; /* must be exactly one query. */
899
Simon Kelley9009d742008-11-14 20:04:27 +0000900 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000901 return 0; /* bad packet */
902
903 GETSHORT(qtype, p);
904 GETSHORT(qclass, p);
905
Simon Kelley0a852542005-03-23 20:28:59 +0000906 if (typep)
907 *typep = qtype;
908
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000909 if (qclass == C_IN)
910 {
911 if (qtype == T_A)
912 return F_IPV4;
913 if (qtype == T_AAAA)
914 return F_IPV6;
915 if (qtype == T_ANY)
916 return F_IPV4 | F_IPV6;
917 }
Simon Kelley07e25da2018-12-16 18:21:58 +0000918
919 /* F_DNSSECOK as agument to search_servers() inhibits forwarding
920 to servers for domains without a trust anchor. This make the
921 behaviour for DS and DNSKEY queries we forward the same
922 as for DS and DNSKEY queries we originate. */
923 if (qtype == T_DS || qtype == T_DNSKEY)
924 return F_DNSSECOK;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000925
926 return F_QUERY;
927}
928
Simon Kelley572b41e2011-02-18 18:11:18 +0000929size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelleycc921df2019-01-02 22:48:59 +0000930 union all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000931{
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100932 unsigned char *p;
Simon Kelley07ed5852018-05-04 21:52:22 +0100933
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100934 if (!(p = skip_questions(header, qlen)))
935 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936
Simon Kelley572b41e2011-02-18 18:11:18 +0000937 /* clear authoritative and truncated flags, set QR flag */
Simon Kelleya2205452018-10-22 18:21:48 +0100938 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
939 /* clear AD flag, set RA flag */
940 header->hb4 = (header->hb4 & ~HB4_AD) | HB4_RA;
Simon Kelley572b41e2011-02-18 18:11:18 +0000941
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000942 header->nscount = htons(0);
943 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100944 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000945 if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +0000946 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000947 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +0000948 SET_RCODE(header, NXDOMAIN);
Simon Kelley087eb762017-10-30 23:16:54 +0000949 else if (flags == F_SERVFAIL)
Simon Kelley07ed5852018-05-04 21:52:22 +0100950 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000951 union all_addr a;
952 a.log.rcode = SERVFAIL;
Simon Kelley07ed5852018-05-04 21:52:22 +0100953 log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
954 SET_RCODE(header, SERVFAIL);
955 }
Simon Kelleyc346f612018-09-04 21:14:18 +0100956 else if (flags & ( F_IPV4 | F_IPV6))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000957 {
Simon Kelleyc346f612018-09-04 21:14:18 +0100958 if (flags & F_IPV4)
959 { /* we know the address */
960 SET_RCODE(header, NOERROR);
961 header->ancount = htons(1);
962 header->hb3 |= HB3_AA;
963 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
964 }
965
Simon Kelleyc346f612018-09-04 21:14:18 +0100966 if (flags & F_IPV6)
967 {
968 SET_RCODE(header, NOERROR);
969 header->ancount = htons(ntohs(header->ancount) + 1);
970 header->hb3 |= HB3_AA;
971 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
972 }
Simon Kelleyc346f612018-09-04 21:14:18 +0100973 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000974 else /* nowhere to forward to */
Simon Kelley07ed5852018-05-04 21:52:22 +0100975 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000976 union all_addr a;
977 a.log.rcode = REFUSED;
Simon Kelley07ed5852018-05-04 21:52:22 +0100978 log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
979 SET_RCODE(header, REFUSED);
980 }
981
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000982 return p - (unsigned char *)header;
983}
Simon Kelley36717ee2004-09-20 19:20:58 +0100984
985/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100986int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +0100987{
Simon Kelley0a852542005-03-23 20:28:59 +0000988 struct mx_srv_record *mx;
989 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100990 struct interface_name *intr;
991 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +0100992 struct naptr *naptr;
993
Simon Kelley7de060b2011-08-26 17:24:52 +0100994 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100995 if (hostname_issubdomain(name, naptr->name))
Simon Kelley7de060b2011-08-26 17:24:52 +0100996 return 1;
997
998 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100999 if (hostname_issubdomain(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001000 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001001
Simon Kelley0a852542005-03-23 20:28:59 +00001002 for (txt = daemon->txt; txt; txt = txt->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001003 if (hostname_issubdomain(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001004 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001005
1006 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001007 if (hostname_issubdomain(name, intr->name))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001008 return 1;
1009
1010 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001011 if (hostname_issubdomain(name, ptr->name))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001012 return 1;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001013
1014 if (cache_find_non_terminal(name, now))
1015 return 1;
1016
Simon Kelley36717ee2004-09-20 19:20:58 +01001017 return 0;
1018}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001019
1020/* Is the packet a reply with the answer address equal to addr?
1021 If so mung is into an NXDOMAIN reply and also put that information
1022 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001023int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001024 struct bogus_addr *baddr, time_t now)
1025{
1026 unsigned char *p;
1027 int i, qtype, qclass, rdlen;
1028 unsigned long ttl;
1029 struct bogus_addr *baddrp;
1030
1031 /* skip over questions */
1032 if (!(p = skip_questions(header, qlen)))
1033 return 0; /* bad packet */
1034
Simon Kelley5aabfc72007-08-29 11:24:47 +01001035 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001036 {
Simon Kelley9009d742008-11-14 20:04:27 +00001037 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001038 return 0; /* bad packet */
1039
1040 GETSHORT(qtype, p);
1041 GETSHORT(qclass, p);
1042 GETLONG(ttl, p);
1043 GETSHORT(rdlen, p);
1044
1045 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001046 {
1047 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1048 return 0;
1049
1050 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1051 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1052 {
1053 /* Found a bogus address. Insert that info here, since there no SOA record
1054 to get the ttl from in the normal processing */
1055 cache_start_insert();
Simon Kelley65a01b72018-12-31 23:56:33 +00001056 cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001057 cache_end_insert();
1058
1059 return 1;
1060 }
1061 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001062
Simon Kelley9009d742008-11-14 20:04:27 +00001063 if (!ADD_RDLEN(header, p, qlen, rdlen))
1064 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001065 }
1066
1067 return 0;
1068}
1069
Glen Huang32fc6db2014-12-27 15:28:12 +00001070int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
1071{
1072 unsigned char *p;
1073 int i, qtype, qclass, rdlen;
1074 struct bogus_addr *baddrp;
1075
1076 /* skip over questions */
1077 if (!(p = skip_questions(header, qlen)))
1078 return 0; /* bad packet */
1079
1080 for (i = ntohs(header->ancount); i != 0; i--)
1081 {
1082 if (!(p = skip_name(p, header, qlen, 10)))
1083 return 0; /* bad packet */
1084
1085 GETSHORT(qtype, p);
1086 GETSHORT(qclass, p);
1087 p += 4; /* TTL */
1088 GETSHORT(rdlen, p);
1089
1090 if (qclass == C_IN && qtype == T_A)
1091 {
1092 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1093 return 0;
1094
1095 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1096 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1097 return 1;
1098 }
1099
1100 if (!ADD_RDLEN(header, p, qlen, rdlen))
1101 return 0;
1102 }
1103
1104 return 0;
1105}
1106
Simon Kelley0549c732017-09-25 18:17:11 +01001107
Simon Kelleyb75e9362012-12-07 11:50:41 +00001108int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001109 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001110{
1111 va_list ap;
1112 unsigned char *sav, *p = *pp;
1113 int j;
1114 unsigned short usval;
1115 long lval;
1116 char *sval;
Simon Kelleyc3667172017-10-13 23:26:29 +01001117
Simon Kelley0549c732017-09-25 18:17:11 +01001118#define CHECK_LIMIT(size) \
Simon Kelleyc3667172017-10-13 23:26:29 +01001119 if (limit && p + (size) > (unsigned char*)limit) goto truncated;
Simon Kelley0549c732017-09-25 18:17:11 +01001120
Simon Kelley4f7b3042012-11-28 21:27:02 +00001121 va_start(ap, format); /* make ap point to 1st unamed argument */
Simon Kelleyc3667172017-10-13 23:26:29 +01001122
1123 if (truncp && *truncp)
1124 goto truncated;
1125
Simon Kelleyb75e9362012-12-07 11:50:41 +00001126 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001127 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001128 CHECK_LIMIT(2);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001129 PUTSHORT(nameoffset | 0xc000, p);
1130 }
1131 else
1132 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001133 char *name = va_arg(ap, char *);
Simon Kelley62cb9362017-09-26 22:00:11 +01001134 if (name && !(p = do_rfc1035_name(p, name, limit)))
Simon Kelleyc3667172017-10-13 23:26:29 +01001135 goto truncated;
Simon Kelley62cb9362017-09-26 22:00:11 +01001136
Simon Kelleyb75e9362012-12-07 11:50:41 +00001137 if (nameoffset < 0)
1138 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001139 CHECK_LIMIT(2);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001140 PUTSHORT(-nameoffset | 0xc000, p);
1141 }
1142 else
Simon Kelley62cb9362017-09-26 22:00:11 +01001143 {
1144 CHECK_LIMIT(1);
1145 *p++ = 0;
1146 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001147 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001148
Simon Kelley62cb9362017-09-26 22:00:11 +01001149 /* type (2) + class (2) + ttl (4) + rdlen (2) */
1150 CHECK_LIMIT(10);
1151
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001152 PUTSHORT(type, p);
1153 PUTSHORT(class, p);
1154 PUTLONG(ttl, p); /* TTL */
1155
1156 sav = p; /* Save pointer to RDLength field */
1157 PUTSHORT(0, p); /* Placeholder RDLength */
1158
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001159 for (; *format; format++)
1160 switch (*format)
1161 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001162 case '6':
Simon Kelley0549c732017-09-25 18:17:11 +01001163 CHECK_LIMIT(IN6ADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001164 sval = va_arg(ap, char *);
1165 memcpy(p, sval, IN6ADDRSZ);
1166 p += IN6ADDRSZ;
1167 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001168
1169 case '4':
Simon Kelley0549c732017-09-25 18:17:11 +01001170 CHECK_LIMIT(INADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001171 sval = va_arg(ap, char *);
1172 memcpy(p, sval, INADDRSZ);
1173 p += INADDRSZ;
1174 break;
1175
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001176 case 'b':
Simon Kelley0549c732017-09-25 18:17:11 +01001177 CHECK_LIMIT(1);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001178 usval = va_arg(ap, int);
1179 *p++ = usval;
1180 break;
1181
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001182 case 's':
Simon Kelley0549c732017-09-25 18:17:11 +01001183 CHECK_LIMIT(2);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001184 usval = va_arg(ap, int);
1185 PUTSHORT(usval, p);
1186 break;
1187
1188 case 'l':
Simon Kelley0549c732017-09-25 18:17:11 +01001189 CHECK_LIMIT(4);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001190 lval = va_arg(ap, long);
1191 PUTLONG(lval, p);
1192 break;
1193
1194 case 'd':
Simon Kelley0549c732017-09-25 18:17:11 +01001195 /* get domain-name answer arg and store it in RDATA field */
1196 if (offset)
1197 *offset = p - (unsigned char *)header;
Simon Kelleyc3667172017-10-13 23:26:29 +01001198 if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
1199 goto truncated;
1200 CHECK_LIMIT(1);
Simon Kelley0549c732017-09-25 18:17:11 +01001201 *p++ = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001202 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001203
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001204 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001205 usval = va_arg(ap, int);
Simon Kelley0549c732017-09-25 18:17:11 +01001206 CHECK_LIMIT(usval);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001207 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001208 if (usval != 0)
1209 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001210 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001211 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001212
1213 case 'z':
1214 sval = va_arg(ap, char *);
1215 usval = sval ? strlen(sval) : 0;
1216 if (usval > 255)
1217 usval = 255;
Simon Kelley0549c732017-09-25 18:17:11 +01001218 CHECK_LIMIT(usval + 1);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001219 *p++ = (unsigned char)usval;
1220 memcpy(p, sval, usval);
1221 p += usval;
1222 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001223 }
1224
1225 va_end(ap); /* clean up variable argument pointer */
1226
Simon Kelleyc3667172017-10-13 23:26:29 +01001227 /* Now, store real RDLength. sav already checked against limit. */
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001228 j = p - sav - 2;
Simon Kelleyc3667172017-10-13 23:26:29 +01001229 PUTSHORT(j, sav);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001230
1231 *pp = p;
1232 return 1;
Simon Kelleyc3667172017-10-13 23:26:29 +01001233
1234 truncated:
1235 va_end(ap);
1236 if (truncp)
1237 *truncp = 1;
1238 return 0;
1239
1240#undef CHECK_LIMIT
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001241}
1242
Simon Kelley9009d742008-11-14 20:04:27 +00001243static unsigned long crec_ttl(struct crec *crecp, time_t now)
1244{
1245 /* Return 0 ttl for DHCP entries, which might change
Simon Kelley7480aef2016-02-26 21:58:20 +00001246 before the lease expires, unless configured otherwise. */
Simon Kelley9009d742008-11-14 20:04:27 +00001247
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001248 if (crecp->flags & F_DHCP)
Simon Kelley7480aef2016-02-26 21:58:20 +00001249 {
1250 int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
1251
1252 /* Apply ceiling of actual lease length to configured TTL. */
1253 if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
1254 return crecp->ttd - now;
1255
1256 return conf_ttl;
1257 }
Simon Kelley9009d742008-11-14 20:04:27 +00001258
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001259 /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
1260 if (crecp->flags & F_IMMORTAL)
1261 return crecp->ttd;
1262
klemens43517fc2017-02-19 15:53:37 +00001263 /* Return the Max TTL value if it is lower than the actual TTL */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001264 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1265 return crecp->ttd - now;
1266 else
1267 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001268}
Petr Menšík29ae3082019-04-12 15:29:00 +02001269
1270static int cache_validated(const struct crec *crecp)
1271{
1272 return (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK));
1273}
Simon Kelley9009d742008-11-14 20:04:27 +00001274
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001275/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001276size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001277 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001278 time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001279{
Simon Kelley3be34542004-09-11 19:12:13 +01001280 char *name = daemon->namebuff;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001281 unsigned char *p, *ansp;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001282 unsigned int qtype, qclass;
Simon Kelleycc921df2019-01-02 22:48:59 +00001283 union all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001284 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001285 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001286 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001287 int dryrun = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001288 struct crec *crecp;
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001289 int nxdomain = 0, notimp = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001290 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001291 size_t len;
Petr Menšík29ae3082019-04-12 15:29:00 +02001292 int rd_bit = (header->hb3 & HB3_RD);
Simon Kelleyfa785732016-07-22 20:56:01 +01001293
Simon Kelley41392982018-09-19 22:27:11 +01001294 /* never answer queries with RD unset, to avoid cache snooping. */
Petr Menšík29ae3082019-04-12 15:29:00 +02001295 if (ntohs(header->ancount) != 0 ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001296 ntohs(header->nscount) != 0 ||
Petr Menšík29ae3082019-04-12 15:29:00 +02001297 ntohs(header->qdcount) == 0 ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001298 OPCODE(header) != QUERY )
1299 return 0;
Simon Kelley087eb762017-10-30 23:16:54 +00001300
Simon Kelleye243c072014-02-06 18:14:09 +00001301 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001302 if (header->hb4 & HB4_CD)
1303 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001304
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001305 /* If there is an additional data section then it will be overwritten by
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001306 partial replies, so we have to do a dry run to see if we can answer
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001307 the query. */
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001308 if (ntohs(header->arcount) != 0)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001309 dryrun = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001310
Simon Kelley0a852542005-03-23 20:28:59 +00001311 for (rec = daemon->mxnames; rec; rec = rec->next)
1312 rec->offset = 0;
1313
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001314 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001315 /* determine end of question section (we put answers there) */
1316 if (!(ansp = skip_questions(header, qlen)))
1317 return 0; /* bad packet */
1318
1319 /* now process each question, answers go in RRs after the question */
1320 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001321
Simon Kelley5aabfc72007-08-29 11:24:47 +01001322 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001323 {
Simon Kelley1aef66b2019-11-30 21:07:15 +00001324 int count = 255; /* catch loops */
1325
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001326 /* save pointer to name for copying into answers */
1327 nameoffset = p - (unsigned char *)header;
1328
1329 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001330 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001331 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001332
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001333 GETSHORT(qtype, p);
1334 GETSHORT(qclass, p);
1335
1336 ans = 0; /* have we answered this question */
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001337
Simon Kelley1aef66b2019-11-30 21:07:15 +00001338 while (--count != 0 && (crecp = cache_find_by_name(NULL, name, now, F_CNAME)))
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001339 {
1340 char *cname_target = cache_get_cname_target(crecp);
1341
1342 /* If the client asked for DNSSEC don't use cached data. */
1343 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
Petr Menšík29ae3082019-04-12 15:29:00 +02001344 (rd_bit && (!do_bit || cache_validated(crecp))))
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001345 {
1346 if (crecp->flags & F_CONFIG || qtype == T_CNAME)
1347 ans = 1;
1348
1349 if (!(crecp->flags & F_DNSSECOK))
1350 sec_data = 0;
1351
1352 if (!dryrun)
1353 {
1354 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1355 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1356 crec_ttl(crecp, now), &nameoffset,
1357 T_CNAME, C_IN, "d", cname_target))
1358 anscount++;
1359 }
Simon Kelley4a1c21d2019-11-30 20:59:44 +00001360
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001361 }
Simon Kelley1eb6ced2020-11-14 15:29:34 +00001362 else
1363 return 0; /* give up if any cached CNAME in chain can't be used for DNSSEC reasons. */
Simon Kelley4a1c21d2019-11-30 20:59:44 +00001364
1365 strcpy(name, cname_target);
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001366 }
1367
Simon Kelley0a852542005-03-23 20:28:59 +00001368 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001369 {
Simon Kelley0a852542005-03-23 20:28:59 +00001370 struct txt_record *t;
1371 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001372 {
Simon Kelley0a852542005-03-23 20:28:59 +00001373 if (t->class == qclass && hostname_isequal(name, t->name))
1374 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001375 ans = 1, sec_data = 0;
Simon Kelleye17fb622006-01-14 20:33:46 +00001376 if (!dryrun)
1377 {
Simon Kelleyfec216d2014-03-27 20:54:34 +00001378 unsigned long ttl = daemon->local_ttl;
1379 int ok = 1;
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001380#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001381 /* Dynamically generate stat record */
1382 if (t->stat != 0)
1383 {
1384 ttl = 0;
1385 if (!cache_make_stat(t))
1386 ok = 0;
1387 }
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001388#endif
Simon Kelleycbb5b172018-10-23 23:45:57 +01001389 if (ok)
1390 {
1391 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
1392 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1393 ttl, NULL,
1394 T_TXT, t->class, "t", t->len, t->txt))
1395 anscount++;
1396 }
Simon Kelleye17fb622006-01-14 20:33:46 +00001397 }
Simon Kelley0a852542005-03-23 20:28:59 +00001398 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001399 }
Simon Kelley0a852542005-03-23 20:28:59 +00001400 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001401
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001402 if (qclass == C_CHAOS)
1403 {
Simon Kelleycbb5b172018-10-23 23:45:57 +01001404 /* don't forward *.bind and *.server chaos queries - always reply with NOTIMP */
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001405 if (hostname_issubdomain("bind", name) || hostname_issubdomain("server", name))
1406 {
1407 if (!ans)
Simon Kelleycbb5b172018-10-23 23:45:57 +01001408 {
1409 notimp = 1, auth = 0;
1410 if (!dryrun)
1411 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001412 addr.log.rcode = NOTIMP;
Simon Kelleycbb5b172018-10-23 23:45:57 +01001413 log_query(F_CONFIG | F_RCODE, name, &addr, NULL);
1414 }
Simon Kelley6f7812d2018-10-23 23:54:44 +01001415 ans = 1, sec_data = 0;
Simon Kelleycbb5b172018-10-23 23:45:57 +01001416 }
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001417 }
1418 }
1419
Simon Kelley0a852542005-03-23 20:28:59 +00001420 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001421 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001422 struct txt_record *t;
1423
1424 for (t = daemon->rr; t; t = t->next)
1425 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1426 {
1427 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001428 sec_data = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001429 if (!dryrun)
1430 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001431 log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, t->class));
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001432 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1433 daemon->local_ttl, NULL,
1434 t->class, C_IN, "t", t->len, t->txt))
Simon Kelley97f876b2018-08-21 22:06:36 +01001435 anscount++;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001436 }
1437 }
1438
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001439 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001440 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001441 /* see if it's w.z.y.z.in-addr.arpa format */
1442 int is_arpa = in_arpa_name_2_addr(name, &addr);
1443 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001444 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001445
1446 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1447 if (hostname_isequal(name, ptr->name))
1448 break;
1449
Simon Kelleyf2621c72007-04-29 19:47:21 +01001450 if (is_arpa == F_IPV4)
1451 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001452 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001453 struct addrlist *addrlist;
1454
Simon Kelley376d48c2013-11-13 13:04:30 +00001455 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00001456 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001457 break;
1458
1459 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001460 break;
1461 else
1462 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1463 intr = intr->next;
1464 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001465 else if (is_arpa == F_IPV6)
1466 for (intr = daemon->int_names; intr; intr = intr->next)
1467 {
1468 struct addrlist *addrlist;
1469
Simon Kelley376d48c2013-11-13 13:04:30 +00001470 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00001471 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001472 break;
1473
1474 if (addrlist)
1475 break;
1476 else
1477 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1478 intr = intr->next;
1479 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001480
1481 if (intr)
1482 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001483 sec_data = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001484 ans = 1;
1485 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001486 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001487 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001488 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1489 daemon->local_ttl, NULL,
1490 T_PTR, C_IN, "d", intr->name))
1491 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001492 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001493 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001494 else if (ptr)
1495 {
1496 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001497 sec_data = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001498 if (!dryrun)
1499 {
Simon Kelley28866e92011-02-14 20:19:14 +00001500 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001501 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001502 if (hostname_isequal(name, ptr->name) &&
1503 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1504 daemon->local_ttl, NULL,
1505 T_PTR, C_IN, "d", ptr->ptr))
1506 anscount++;
1507
Simon Kelley832af0b2007-01-21 20:01:28 +00001508 }
1509 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001510 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001511 {
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001512 /* Don't use cache when DNSSEC data required, unless we know that
1513 the zone is unsigned, which implies that we're doing
1514 validation. */
Petr Menšík29ae3082019-04-12 15:29:00 +02001515 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
1516 (rd_bit && (!do_bit || cache_validated(crecp)) ))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001517 {
1518 do
1519 {
1520 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1521 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1522 continue;
1523
1524 if (!(crecp->flags & F_DNSSECOK))
1525 sec_data = 0;
Simon Kelley93be5b12015-12-15 12:04:40 +00001526
1527 ans = 1;
1528
Simon Kelley2d33bda2014-01-24 22:37:25 +00001529 if (crecp->flags & F_NEG)
1530 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001531 auth = 0;
1532 if (crecp->flags & F_NXDOMAIN)
1533 nxdomain = 1;
1534 if (!dryrun)
1535 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1536 }
Simon Kelley93be5b12015-12-15 12:04:40 +00001537 else
Simon Kelley2d33bda2014-01-24 22:37:25 +00001538 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001539 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1540 auth = 0;
1541 if (!dryrun)
1542 {
1543 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1544 record_source(crecp->uid));
1545
1546 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1547 crec_ttl(crecp, now), NULL,
1548 T_PTR, C_IN, "d", cache_get_name(crecp)))
1549 anscount++;
1550 }
1551 }
1552 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1553 }
1554 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001555 else if (is_rev_synth(is_arpa, &addr, name))
1556 {
1557 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001558 sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001559 if (!dryrun)
1560 {
1561 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1562
1563 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1564 daemon->local_ttl, NULL,
1565 T_PTR, C_IN, "d", name))
1566 anscount++;
1567 }
1568 }
Simon Kelleyfca008d2017-02-19 18:50:41 +00001569 else if (option_bool(OPT_BOGUSPRIV) && (
Simon Kelleycc921df2019-01-02 22:48:59 +00001570 (is_arpa == F_IPV6 && private_net6(&addr.addr6)) ||
1571 (is_arpa == F_IPV4 && private_net(addr.addr4, 1))))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001572 {
Vladislav Grishenko5a7212c2017-04-24 22:19:57 +01001573 struct server *serv;
1574 unsigned int namelen = strlen(name);
1575 char *nameend = name + namelen;
1576
1577 /* see if have rev-server set */
1578 for (serv = daemon->servers; serv; serv = serv->next)
1579 {
1580 unsigned int domainlen;
1581 char *matchstart;
1582
1583 if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
1584 continue;
1585
1586 domainlen = strlen(serv->domain);
1587 if (domainlen == 0 || domainlen > namelen)
1588 continue;
1589
1590 matchstart = nameend - domainlen;
1591 if (hostname_isequal(matchstart, serv->domain) &&
1592 (namelen == domainlen || *(matchstart-1) == '.' ))
1593 break;
1594 }
1595
1596 /* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
1597 if (!serv)
1598 {
1599 ans = 1;
1600 sec_data = 0;
1601 nxdomain = 1;
1602 if (!dryrun)
1603 log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
1604 name, &addr, NULL);
1605 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001606 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001607 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001608
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001609 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1610 {
Simon Kelleyee875042018-10-23 22:10:17 +01001611 unsigned short type = (flag == F_IPV6) ? T_AAAA : T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001612 struct interface_name *intr;
1613
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001614 if (qtype != type && qtype != T_ANY)
1615 continue;
1616
Simon Kelleyf2621c72007-04-29 19:47:21 +01001617 /* interface name stuff */
Simon Kelley115ac3e2013-05-20 11:28:32 +01001618 for (intr = daemon->int_names; intr; intr = intr->next)
1619 if (hostname_isequal(name, intr->name))
1620 break;
1621
1622 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001623 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001624 struct addrlist *addrlist;
Simon Kelleyd42d4702017-02-02 16:52:06 +00001625 int gotit = 0, localise = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001626
Simon Kelley115ac3e2013-05-20 11:28:32 +01001627 enumerate_interfaces(0);
Simon Kelleyd42d4702017-02-02 16:52:06 +00001628
klemens43517fc2017-02-19 15:53:37 +00001629 /* See if a putative address is on the network from which we received
Simon Kelleyd42d4702017-02-02 16:52:06 +00001630 the query, is so we'll filter other answers. */
1631 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && type == T_A)
1632 for (intr = daemon->int_names; intr; intr = intr->next)
1633 if (hostname_isequal(name, intr->name))
1634 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleyee875042018-10-23 22:10:17 +01001635 if (!(addrlist->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001636 is_same_net(addrlist->addr.addr4, local_addr, local_netmask))
Simon Kelleyee875042018-10-23 22:10:17 +01001637 {
1638 localise = 1;
1639 break;
1640 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001641
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001642 for (intr = daemon->int_names; intr; intr = intr->next)
1643 if (hostname_isequal(name, intr->name))
1644 {
Simon Kelley47669362014-12-17 12:41:56 +00001645 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley47669362014-12-17 12:41:56 +00001646 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
Simon Kelley47669362014-12-17 12:41:56 +00001647 {
Simon Kelleyd42d4702017-02-02 16:52:06 +00001648 if (localise &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001649 !is_same_net(addrlist->addr.addr4, local_addr, local_netmask))
Simon Kelleyd42d4702017-02-02 16:52:06 +00001650 continue;
1651
Simon Kelley47669362014-12-17 12:41:56 +00001652 if (addrlist->flags & ADDRLIST_REVONLY)
1653 continue;
Simon Kelleyee875042018-10-23 22:10:17 +01001654
Simon Kelley47669362014-12-17 12:41:56 +00001655 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001656 sec_data = 0;
Simon Kelley47669362014-12-17 12:41:56 +00001657 if (!dryrun)
Simon Kelley376d48c2013-11-13 13:04:30 +00001658 {
1659 gotit = 1;
1660 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1661 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1662 daemon->local_ttl, NULL, type, C_IN,
1663 type == T_A ? "4" : "6", &addrlist->addr))
1664 anscount++;
1665 }
Simon Kelley47669362014-12-17 12:41:56 +00001666 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001667 }
1668
1669 if (!dryrun && !gotit)
1670 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1671
Simon Kelley115ac3e2013-05-20 11:28:32 +01001672 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001673 }
1674
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001675 if ((crecp = cache_find_by_name(NULL, name, now, flag | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001676 {
1677 int localise = 0;
1678
Josh Soref730c6742017-02-06 16:14:04 +00001679 /* See if a putative address is on the network from which we received
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001680 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001681 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001682 {
1683 struct crec *save = crecp;
1684 do {
1685 if ((crecp->flags & F_HOSTS) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001686 is_same_net(crecp->addr.addr4, local_addr, local_netmask))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001687 {
1688 localise = 1;
1689 break;
1690 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001691 } while ((crecp = cache_find_by_name(crecp, name, now, flag)));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001692 crecp = save;
1693 }
Simon Kelley824202e2014-01-23 20:59:46 +00001694
Simon Kelley93be5b12015-12-15 12:04:40 +00001695 /* If the client asked for DNSSEC don't use cached data. */
Simon Kelleya997ca02018-06-29 14:39:41 +01001696 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
Petr Menšík29ae3082019-04-12 15:29:00 +02001697 (rd_bit && (!do_bit || cache_validated(crecp)) ))
Simon Kelley824202e2014-01-23 20:59:46 +00001698 do
1699 {
1700 /* don't answer wildcard queries with data not from /etc/hosts
1701 or DHCP leases */
1702 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1703 break;
1704
1705 if (!(crecp->flags & F_DNSSECOK))
1706 sec_data = 0;
1707
Simon Kelley824202e2014-01-23 20:59:46 +00001708 if (crecp->flags & F_NEG)
1709 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001710 ans = 1;
1711 auth = 0;
1712 if (crecp->flags & F_NXDOMAIN)
1713 nxdomain = 1;
1714 if (!dryrun)
1715 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley824202e2014-01-23 20:59:46 +00001716 }
1717 else
1718 {
1719 /* If we are returning local answers depending on network,
1720 filter here. */
1721 if (localise &&
1722 (crecp->flags & F_HOSTS) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001723 !is_same_net(crecp->addr.addr4, local_addr, local_netmask))
Simon Kelley824202e2014-01-23 20:59:46 +00001724 continue;
1725
1726 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1727 auth = 0;
1728
1729 ans = 1;
1730 if (!dryrun)
1731 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001732 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr,
Simon Kelley824202e2014-01-23 20:59:46 +00001733 record_source(crecp->uid));
1734
1735 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1736 crec_ttl(crecp, now), NULL, type, C_IN,
1737 type == T_A ? "4" : "6", &crecp->addr))
1738 anscount++;
1739 }
1740 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001741 } while ((crecp = cache_find_by_name(crecp, name, now, flag)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001742 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001743 else if (is_name_synthetic(flag, name, &addr))
1744 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001745 ans = 1, sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001746 if (!dryrun)
1747 {
1748 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
1749 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1750 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
1751 anscount++;
1752 }
1753 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001754 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001755
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001756 if (qtype == T_MX || qtype == T_ANY)
1757 {
1758 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001759 for (rec = daemon->mxnames; rec; rec = rec->next)
1760 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001761 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001762 ans = found = 1;
1763 sec_data = 0;
1764 if (!dryrun)
1765 {
1766 int offset;
1767 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
1768 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1769 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1770 {
1771 anscount++;
1772 if (rec->target)
1773 rec->offset = offset;
1774 }
1775 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001776 }
1777
Petr Menšík29ae3082019-04-12 15:29:00 +02001778 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00001779 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001780 {
1781 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001782 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001783 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;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001803 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001804 if (!dryrun)
1805 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001806 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001807 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001808 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001809 &offset, T_SRV, C_IN, "sssd",
1810 rec->priority, rec->weight, rec->srvport, rec->target))
1811 {
1812 anscount++;
1813 if (rec->target)
1814 rec->offset = offset;
1815 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001816 }
Simon Kelley28866e92011-02-14 20:19:14 +00001817
1818 /* unlink first SRV record found */
1819 if (!move)
1820 {
1821 move = rec;
1822 *up = rec->next;
1823 }
1824 else
1825 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001826 }
Simon Kelley28866e92011-02-14 20:19:14 +00001827 else
1828 up = &rec->next;
1829
1830 /* put first SRV record back at the end. */
1831 if (move)
1832 {
1833 *up = move;
1834 move->next = NULL;
1835 }
Simon Kelley5b99eae2019-01-06 23:09:50 +00001836
1837 if (!found)
1838 {
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001839 if ((crecp = cache_find_by_name(NULL, name, now, F_SRV | (dryrun ? F_NO_RR : 0))) &&
Petr Menšík29ae3082019-04-12 15:29:00 +02001840 rd_bit && (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
Simon Kelley5b99eae2019-01-06 23:09:50 +00001841 {
1842 if (!(crecp->flags & F_DNSSECOK))
1843 sec_data = 0;
1844
1845 auth = 0;
1846 found = ans = 1;
1847
1848 do {
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001849 if (crecp->flags & F_NEG)
Simon Kelley5b99eae2019-01-06 23:09:50 +00001850 {
1851 if (crecp->flags & F_NXDOMAIN)
1852 nxdomain = 1;
1853 if (!dryrun)
1854 log_query(crecp->flags, name, NULL, NULL);
1855 }
Simon Kelley122997d2019-10-25 17:23:56 +01001856 else if (!dryrun)
Simon Kelley5b99eae2019-01-06 23:09:50 +00001857 {
Simon Kelley122997d2019-10-25 17:23:56 +01001858 char *target = blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, NULL);
1859 log_query(crecp->flags, name, NULL, 0);
Simon Kelley5b99eae2019-01-06 23:09:50 +00001860
Simon Kelley122997d2019-10-25 17:23:56 +01001861 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1862 crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd",
1863 crecp->addr.srv.priority, crecp->addr.srv.weight, crecp->addr.srv.srvport,
1864 target))
1865 anscount++;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001866 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001867 } while ((crecp = cache_find_by_name(crecp, name, now, F_SRV)));
Simon Kelley5b99eae2019-01-06 23:09:50 +00001868 }
1869 }
1870
Simon Kelley28866e92011-02-14 20:19:14 +00001871 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001872 {
1873 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001874 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001875 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001876 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001877 }
1878 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001879
1880 if (qtype == T_NAPTR || qtype == T_ANY)
1881 {
1882 struct naptr *na;
1883 for (na = daemon->naptr; na; na = na->next)
1884 if (hostname_isequal(name, na->name))
1885 {
1886 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001887 sec_data = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001888 if (!dryrun)
1889 {
Simon Kelley28866e92011-02-14 20:19:14 +00001890 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001891 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1892 NULL, T_NAPTR, C_IN, "sszzzd",
1893 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1894 anscount++;
1895 }
1896 }
1897 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001898
1899 if (qtype == T_MAILB)
Simon Kelley6f7812d2018-10-23 23:54:44 +01001900 ans = 1, nxdomain = 1, sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001901
Simon Kelley28866e92011-02-14 20:19:14 +00001902 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001903 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001904 ans = 1;
1905 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001906 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001907 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001908 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001909 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001910
1911 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001912 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001913 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001914
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001915 if (dryrun)
1916 {
1917 dryrun = 0;
1918 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001919 }
1920
Simon Kelley0a852542005-03-23 20:28:59 +00001921 /* create an additional data section, for stuff in SRV and MX record replies. */
1922 for (rec = daemon->mxnames; rec; rec = rec->next)
1923 if (rec->offset != 0)
1924 {
1925 /* squash dupes */
1926 struct mx_srv_record *tmp;
1927 for (tmp = rec->next; tmp; tmp = tmp->next)
1928 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1929 tmp->offset = 0;
1930
1931 crecp = NULL;
1932 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1933 {
Simon Kelley0a852542005-03-23 20:28:59 +00001934 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
Simon Kelleyee875042018-10-23 22:10:17 +01001935
Simon Kelley0a852542005-03-23 20:28:59 +00001936 if (crecp->flags & F_NEG)
1937 continue;
1938
Simon Kelley9009d742008-11-14 20:04:27 +00001939 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
1940 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00001941 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1942 addncount++;
1943 }
1944 }
1945
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001946 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00001947 /* clear authoritative and truncated flags, set QR flag */
1948 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1949 /* set RA flag */
1950 header->hb4 |= HB4_RA;
1951
Josh Soref730c6742017-02-06 16:14:04 +00001952 /* authoritative - only hosts and DHCP derived names. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001953 if (auth)
1954 header->hb3 |= HB3_AA;
1955
1956 /* truncation */
1957 if (trunc)
1958 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001959
Simon Kelley45cca582013-10-15 10:20:13 +01001960 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00001961 SET_RCODE(header, NXDOMAIN);
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001962 else if (notimp)
1963 SET_RCODE(header, NOTIMP);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001964 else
Simon Kelley572b41e2011-02-18 18:11:18 +00001965 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001966 header->ancount = htons(anscount);
1967 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00001968 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00001969
Simon Kelleya25720a2014-01-14 23:13:55 +00001970 len = ansp - (unsigned char *)header;
1971
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001972 /* Advertise our packet size limit in our reply */
Simon Kelleya25720a2014-01-14 23:13:55 +00001973 if (have_pseudoheader)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00001974 len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
Simon Kelleye243c072014-02-06 18:14:09 +00001975
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001976 if (ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00001977 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00001978 else
1979 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00001980
Simon Kelley7c286122014-01-27 21:38:11 +00001981 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001982}