blob: 79270ef79955030ee77fe3453b3a245cbdaa0cb4 [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 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 Kelley0a852542005-03-23 20:28:59 +0000336/* CRC the question section. This is used to safely detect query
Josh Soref730c6742017-02-06 16:14:04 +0000337 retransmission and to detect answers to questions we didn't ask, which
Simon Kelley0a852542005-03-23 20:28:59 +0000338 might be poisoning attacks. Note that we decode the name rather
339 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000340 We ignore case in the names for the same reason. Return all-ones
341 if there is not question section. */
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000342#ifndef HAVE_DNSSEC
Simon Kelley572b41e2011-02-18 18:11:18 +0000343unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100344{
Simon Kelley91dccd02005-03-31 17:48:32 +0100345 int q;
346 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000347 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100348
Simon Kelley5aabfc72007-08-29 11:24:47 +0100349 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000350 {
Simon Kelley9009d742008-11-14 20:04:27 +0000351 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000352 return crc; /* bad packet */
353
Simon Kelley3d8df262005-08-29 12:19:27 +0100354 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000355 {
356 int i = 8;
357 char c = *p1;
358
359 if (c >= 'A' && c <= 'Z')
360 c += 'a' - 'A';
361
362 crc ^= c << 24;
363 while (i--)
364 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
365 }
366
367 /* CRC the class and type as well */
368 for (p1 = p; p1 < p+4; p1++)
369 {
370 int i = 8;
371 crc ^= *p1 << 24;
372 while (i--)
373 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
374 }
375
376 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000377 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000378 return crc; /* bad packet */
379 }
380
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100381 return crc;
382}
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000383#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100384
Simon Kelley572b41e2011-02-18 18:11:18 +0000385size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100386{
387 unsigned char *ansp = skip_questions(header, plen);
388
Simon Kelley9009d742008-11-14 20:04:27 +0000389 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100390 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000391 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100392
393 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
394 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000395 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100396
Simon Kelley36717ee2004-09-20 19:20:58 +0100397 /* restore pseudoheader */
398 if (pheader && ntohs(header->arcount) == 0)
399 {
400 /* must use memmove, may overlap */
401 memmove(ansp, pheader, hlen);
402 header->arcount = htons(1);
403 ansp += hlen;
404 }
405
406 return ansp - (unsigned char *)header;
407}
408
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000409/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100410int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000411{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100412 in_addr_t ip_addr = ntohl(addr.s_addr);
413
414 return
Simon Kelleyd2aa7df2015-08-03 21:52:12 +0100415 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
416 ((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. "here" network */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100417 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
418 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
Simon Kelley90477fb2015-10-20 21:21:32 +0100419 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
420 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
421 ((ip_addr & 0xFFFFFF00) == 0xC0000200) /* 192.0.2.0/24 (test-net) */ ||
422 ((ip_addr & 0xFFFFFF00) == 0xC6336400) /* 198.51.100.0/24(test-net) */ ||
423 ((ip_addr & 0xFFFFFF00) == 0xCB007100) /* 203.0.113.0/24 (test-net) */ ||
424 ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 (broadcast)*/ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000425}
Simon Kelley1cff1662004-03-12 08:12:58 +0000426
Simon Kelleyfca008d2017-02-19 18:50:41 +0000427static int private_net6(struct in6_addr *a)
428{
429 return
430 IN6_IS_ADDR_UNSPECIFIED(a) || /* RFC 6303 4.3 */
431 IN6_IS_ADDR_LOOPBACK(a) || /* RFC 6303 4.3 */
432 IN6_IS_ADDR_LINKLOCAL(a) || /* RFC 6303 4.5 */
433 ((unsigned char *)a)[0] == 0xfd || /* RFC 6303 4.4 */
434 ((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
435}
Simon Kelleyfca008d2017-02-19 18:50:41 +0000436
Simon Kelley6938f342014-01-26 22:47:39 +0000437static 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 +0000438{
439 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000440
441 for (i = count; i != 0; i--)
442 {
Simon Kelley28866e92011-02-14 20:19:14 +0000443 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100444 {
445 if (!extract_name(header, qlen, &p, name, 1, 10))
446 return 0;
447 }
448 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000449 return 0; /* bad packet */
450
451 GETSHORT(qtype, p);
452 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100453 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000454 GETSHORT(rdlen, p);
455
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100456 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000457 {
458 struct doctor *doctor;
459 struct in_addr addr;
460
Simon Kelley9009d742008-11-14 20:04:27 +0000461 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
462 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100463
464 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000465 memcpy(&addr, p, INADDRSZ);
466
467 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000468 {
469 if (doctor->end.s_addr == 0)
470 {
471 if (!is_same_net(doctor->in, addr, doctor->mask))
472 continue;
473 }
474 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
475 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
476 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100477
Simon Kelley73a08a22009-02-05 20:28:08 +0000478 addr.s_addr &= ~doctor->mask.s_addr;
479 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
480 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000481 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000482 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000483 memcpy(p, &addr, INADDRSZ);
484 break;
485 }
Simon Kelley824af852008-02-12 20:43:05 +0000486 }
Simon Kelley28866e92011-02-14 20:19:14 +0000487 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100488 {
489 unsigned char *p1 = p;
490 if (!CHECK_LEN(header, p1, qlen, rdlen))
491 return 0;
492 while ((p1 - p) < rdlen)
493 {
494 unsigned int i, len = *p1;
495 unsigned char *p2 = p1;
Simon Kelley6a0b00f2017-09-25 20:19:55 +0100496 if ((p1 + len - p) >= rdlen)
497 return 0; /* bad packet */
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100498 /* make counted string zero-term and sanitise */
499 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100500 {
501 if (!isprint((int)*(p2+1)))
502 break;
503
504 *p2 = *(p2+1);
505 p2++;
506 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100507 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000508 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100509 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100510 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100511 *p1 = len;
512 p1 += len+1;
513 }
514 }
Simon Kelley824af852008-02-12 20:43:05 +0000515
Simon Kelley9009d742008-11-14 20:04:27 +0000516 if (!ADD_RDLEN(header, p, qlen, rdlen))
517 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000518 }
519
520 return p;
521}
522
Simon Kelley6938f342014-01-26 22:47:39 +0000523static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000524{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100525 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000526 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100527 unsigned long ttl, minttl = ULONG_MAX;
528 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000529
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100530 /* first move to NS section and find TTL from any SOA section */
531 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000532 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000533 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000534
Simon Kelley5aabfc72007-08-29 11:24:47 +0100535 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000536 {
Simon Kelley9009d742008-11-14 20:04:27 +0000537 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100538 return 0; /* bad packet */
539
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000540 GETSHORT(qtype, p);
541 GETSHORT(qclass, p);
542 GETLONG(ttl, p);
543 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100544
545 if ((qclass == C_IN) && (qtype == T_SOA))
546 {
547 found_soa = 1;
548 if (ttl < minttl)
549 minttl = ttl;
550
551 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000552 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100553 return 0;
554 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000555 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100556 return 0;
557 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
558
559 GETLONG(ttl, p); /* minTTL */
560 if (ttl < minttl)
561 minttl = ttl;
562 }
Simon Kelley9009d742008-11-14 20:04:27 +0000563 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100564 return 0; /* bad packet */
565 }
Simon Kelley9009d742008-11-14 20:04:27 +0000566
Simon Kelley6938f342014-01-26 22:47:39 +0000567 /* rewrite addresses in additional section too */
568 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000569 return 0;
570
571 if (!found_soa)
572 minttl = daemon->neg_ttl;
573
574 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100575}
576
577/* Note that the following code can create CNAME chains that don't point to a real record,
578 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 +0000579 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100580 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000581int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelleya6004d72017-10-25 17:48:19 +0100582 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
Simon Kelley373e9172017-12-01 22:40:56 +0000583 int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100584{
Simon Kelley824af852008-02-12 20:43:05 +0000585 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100586 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000587 unsigned long ttl = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +0000588 union all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000589#ifdef HAVE_IPSET
590 char **ipsets_cur;
591#else
592 (void)ipsets; /* unused */
593#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100594
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000595
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100596 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000597
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100598 /* 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 +0000599 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000600 {
601 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000602 ttl = find_soa(header, qlen, name, doctored);
Simon Kelleya6004d72017-10-25 17:48:19 +0100603
604 if (*doctored)
605 {
606 if (secure)
607 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000608#ifdef HAVE_DNSSEC
Simon Kelley373e9172017-12-01 22:40:56 +0000609 if (option_bool(OPT_DNSSEC_VALID))
Simon Kelleya6004d72017-10-25 17:48:19 +0100610 for (i = 0; i < ntohs(header->ancount); i++)
Simon Kelley373e9172017-12-01 22:40:56 +0000611 if (daemon->rr_status[i])
Simon Kelleya6004d72017-10-25 17:48:19 +0100612 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000613#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100614 }
Simon Kelley0a852542005-03-23 20:28:59 +0000615 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100616
617 /* go through the questions. */
618 p = (unsigned char *)(header+1);
619
Simon Kelley5aabfc72007-08-29 11:24:47 +0100620 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100621 {
Simon Kelley1fbe4d22014-03-01 20:03:47 +0000622 int found = 0, cname_count = CNAME_CHAIN;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100623 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000624 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000625#ifdef HAVE_DNSSEC
Simon Kelleya6004d72017-10-25 17:48:19 +0100626 int cname_short = 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000627#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000628 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000629
Simon Kelley824af852008-02-12 20:43:05 +0000630 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000631 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000632 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100633
634 GETSHORT(qtype, p);
635 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000636
637 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100638 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000639
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100640 /* PTRs: we chase CNAMEs here, since we have no way to
641 represent them in the cache. */
642 if (qtype == T_PTR)
643 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000644 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100645
646 if (!name_encoding)
647 continue;
648
649 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000650 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100651 cname_loop:
652 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000653 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100654
Simon Kelleya6004d72017-10-25 17:48:19 +0100655 for (j = 0; j < ntohs(header->ancount); j++)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100656 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100657 int secflag = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000658 unsigned char *tmp = namep;
659 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000660 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
661 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000662 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100663
664 GETSHORT(aqtype, p1);
665 GETSHORT(aqclass, p1);
666 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100667 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
668 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000669 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100670 PUTLONG(daemon->max_ttl, p1);
671 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100672 GETSHORT(ardlen, p1);
673 endrr = p1+ardlen;
674
675 /* TTL of record is minimum of CNAMES and PTR */
676 if (attl < cttl)
677 cttl = attl;
678
679 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
680 {
Simon Kelley9009d742008-11-14 20:04:27 +0000681 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000682 return 0;
Simon Kelley8c707e12017-12-05 22:28:10 +0000683#ifdef HAVE_DNSSEC
Simon Kelley373e9172017-12-01 22:40:56 +0000684 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
Simon Kelleya6004d72017-10-25 17:48:19 +0100685 {
686 /* validated RR anywhere in CNAME chain, don't cache. */
687 if (cname_short || aqtype == T_CNAME)
688 return 0;
689
690 secflag = F_DNSSECOK;
691 }
Simon Kelley8c707e12017-12-05 22:28:10 +0000692#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100693
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100694 if (aqtype == T_CNAME)
695 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100696 if (!cname_count--)
697 return 0; /* looped CNAMES, we can't cache. */
Simon Kelley8c707e12017-12-05 22:28:10 +0000698#ifdef HAVE_DNSSEC
Simon Kelleya6004d72017-10-25 17:48:19 +0100699 cname_short = 1;
Simon Kelley8c707e12017-12-05 22:28:10 +0000700#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100701 goto cname_loop;
702 }
703
Simon Kelley65a01b72018-12-31 23:56:33 +0000704 cache_insert(name, &addr, C_IN, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100705 found = 1;
706 }
707
708 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000709 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000710 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100711 }
712 }
713
Simon Kelley28866e92011-02-14 20:19:14 +0000714 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100715 {
716 if (!searched_soa)
717 {
718 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000719 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100720 }
721 if (ttl)
Simon Kelley65a01b72018-12-31 23:56:33 +0000722 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 +0000723 }
724 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100725 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000726 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100727 /* everything other than PTR */
728 struct crec *newc;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000729 int addrlen = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100730
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100731 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100732 {
733 addrlen = INADDRSZ;
734 flags |= F_IPV4;
735 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100736 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100737 {
738 addrlen = IN6ADDRSZ;
739 flags |= F_IPV6;
740 }
Simon Kelley5b99eae2019-01-06 23:09:50 +0000741 else if (qtype == T_SRV)
742 flags |= F_SRV;
743 else
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100744 continue;
745
Simon Kelley45cca582013-10-15 10:20:13 +0100746 cname_loop1:
747 if (!(p1 = skip_questions(header, qlen)))
748 return 0;
749
Simon Kelleya6004d72017-10-25 17:48:19 +0100750 for (j = 0; j < ntohs(header->ancount); j++)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100751 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100752 int secflag = 0;
753
Simon Kelley45cca582013-10-15 10:20:13 +0100754 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
755 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100756
Simon Kelley45cca582013-10-15 10:20:13 +0100757 GETSHORT(aqtype, p1);
758 GETSHORT(aqclass, p1);
759 GETLONG(attl, p1);
760 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000761 {
Simon Kelley45cca582013-10-15 10:20:13 +0100762 (p1) -= 4;
763 PUTLONG(daemon->max_ttl, p1);
764 }
765 GETSHORT(ardlen, p1);
766 endrr = p1+ardlen;
767
768 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
769 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100770#ifdef HAVE_DNSSEC
Simon Kelley373e9172017-12-01 22:40:56 +0000771 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
Simon Kelleya6004d72017-10-25 17:48:19 +0100772 secflag = F_DNSSECOK;
773#endif
Simon Kelley45cca582013-10-15 10:20:13 +0100774 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100775 {
Simon Kelley45cca582013-10-15 10:20:13 +0100776 if (!cname_count--)
777 return 0; /* looped CNAMES */
Simon Kelley65a01b72018-12-31 23:56:33 +0000778 newc = cache_insert(name, NULL, C_IN, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100779 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100780 {
Simon Kelley45cca582013-10-15 10:20:13 +0100781 newc->addr.cname.target.cache = NULL;
Simon Kelley03431d62014-03-20 16:25:43 +0000782 /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
783 newc->addr.cname.uid = 1;
Simon Kelley45cca582013-10-15 10:20:13 +0100784 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100785 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100786 next_uid(newc);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100787 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100788 cpp->addr.cname.uid = newc->uid;
789 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100790 }
Simon Kelley45cca582013-10-15 10:20:13 +0100791
792 cpp = newc;
793 if (attl < cttl)
794 cttl = attl;
795
796 if (!extract_name(header, qlen, &p1, name, 1, 0))
797 return 0;
798 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100799 }
Simon Kelley45cca582013-10-15 10:20:13 +0100800 else if (!(flags & F_NXDOMAIN))
801 {
802 found = 1;
803
Simon Kelley5b99eae2019-01-06 23:09:50 +0000804 if (flags & F_SRV)
Simon Kelleyb059c962015-05-08 20:25:51 +0100805 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000806 unsigned char *tmp = namep;
807
808 if (!CHECK_LEN(header, p1, qlen, 6))
809 return 0; /* bad packet */
810 GETSHORT(addr.srv.priority, p1);
811 GETSHORT(addr.srv.weight, p1);
812 GETSHORT(addr.srv.srvport, p1);
813 if (!extract_name(header, qlen, &p1, name, 1, 0))
814 return 0;
815 addr.srv.targetlen = strlen(name) + 1; /* include terminating zero */
816 if (!(addr.srv.target = blockdata_alloc(name, addr.srv.targetlen)))
817 return 0;
818
819 /* we overwrote the original name, so get it back here. */
820 if (!extract_name(header, qlen, &tmp, name, 1, 0))
821 return 0;
822 }
823 else
824 {
825 /* copy address into aligned storage */
826 if (!CHECK_LEN(header, p1, qlen, addrlen))
827 return 0; /* bad packet */
828 memcpy(&addr, p1, addrlen);
829
830 /* check for returned address in private space */
831 if (check_rebind)
Simon Kelleyb059c962015-05-08 20:25:51 +0100832 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000833 if ((flags & F_IPV4) &&
834 private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
Simon Kelleyb059c962015-05-08 20:25:51 +0100835 return 1;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000836
837 if ((flags & F_IPV6) &&
838 IN6_IS_ADDR_V4MAPPED(&addr.addr6))
839 {
840 struct in_addr v4;
841 v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
842 if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
843 return 1;
844 }
Simon Kelleyb059c962015-05-08 20:25:51 +0100845 }
Simon Kelley5b99eae2019-01-06 23:09:50 +0000846
Simon Kelley45cca582013-10-15 10:20:13 +0100847#ifdef HAVE_IPSET
Simon Kelley5b99eae2019-01-06 23:09:50 +0000848 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
Wang Jian49752b92014-03-28 20:52:47 +0000849 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000850 ipsets_cur = ipsets;
851 while (*ipsets_cur)
852 {
853 log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
854 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
855 }
Wang Jian49752b92014-03-28 20:52:47 +0000856 }
Simon Kelley45cca582013-10-15 10:20:13 +0100857#endif
Simon Kelley5b99eae2019-01-06 23:09:50 +0000858 }
Simon Kelley45cca582013-10-15 10:20:13 +0100859
Simon Kelley65a01b72018-12-31 23:56:33 +0000860 newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100861 if (newc && cpp)
862 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100863 next_uid(newc);
Simon Kelley45cca582013-10-15 10:20:13 +0100864 cpp->addr.cname.target.cache = newc;
865 cpp->addr.cname.uid = newc->uid;
866 }
867 cpp = NULL;
868 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100869 }
Simon Kelley45cca582013-10-15 10:20:13 +0100870
871 p1 = endrr;
872 if (!CHECK_LEN(header, p1, qlen, 0))
873 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100874 }
875
Simon Kelley28866e92011-02-14 20:19:14 +0000876 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100877 {
878 if (!searched_soa)
879 {
880 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000881 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100882 }
883 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +0000884 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100885 if (ttl || cpp)
886 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000887 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 +0000888 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100889 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100890 next_uid(newc);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100891 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100892 cpp->addr.cname.uid = newc->uid;
893 }
894 }
895 }
896 }
897 }
898
Simon Kelley1023dcb2012-04-09 18:00:08 +0100899 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +0100900 Don't cache replies from non-recursive nameservers, since we may get a
901 reply containing a CNAME but not its target, even though the target
902 does exist. */
903 if (!(header->hb3 & HB3_TC) &&
904 !(header->hb4 & HB4_CD) &&
905 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +0000906 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +0000907 cache_end_insert();
908
909 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000910}
911
912/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +0000913 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +0000914unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000915{
916 unsigned char *p = (unsigned char *)(header+1);
917 int qtype, qclass;
918
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100919 if (typep)
920 *typep = 0;
921
Simon Kelley572b41e2011-02-18 18:11:18 +0000922 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000923 return 0; /* must be exactly one query. */
924
Simon Kelley9009d742008-11-14 20:04:27 +0000925 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000926 return 0; /* bad packet */
927
928 GETSHORT(qtype, p);
929 GETSHORT(qclass, p);
930
Simon Kelley0a852542005-03-23 20:28:59 +0000931 if (typep)
932 *typep = qtype;
933
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000934 if (qclass == C_IN)
935 {
936 if (qtype == T_A)
937 return F_IPV4;
938 if (qtype == T_AAAA)
939 return F_IPV6;
940 if (qtype == T_ANY)
941 return F_IPV4 | F_IPV6;
942 }
Simon Kelley07e25da2018-12-16 18:21:58 +0000943
944 /* F_DNSSECOK as agument to search_servers() inhibits forwarding
945 to servers for domains without a trust anchor. This make the
946 behaviour for DS and DNSKEY queries we forward the same
947 as for DS and DNSKEY queries we originate. */
948 if (qtype == T_DS || qtype == T_DNSKEY)
949 return F_DNSSECOK;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000950
951 return F_QUERY;
952}
953
Simon Kelley572b41e2011-02-18 18:11:18 +0000954size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelleycc921df2019-01-02 22:48:59 +0000955 union all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000956{
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100957 unsigned char *p;
Simon Kelley07ed5852018-05-04 21:52:22 +0100958
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100959 if (!(p = skip_questions(header, qlen)))
960 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000961
Simon Kelley572b41e2011-02-18 18:11:18 +0000962 /* clear authoritative and truncated flags, set QR flag */
Simon Kelleya2205452018-10-22 18:21:48 +0100963 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
964 /* clear AD flag, set RA flag */
965 header->hb4 = (header->hb4 & ~HB4_AD) | HB4_RA;
Simon Kelley572b41e2011-02-18 18:11:18 +0000966
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000967 header->nscount = htons(0);
968 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100969 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000970 if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +0000971 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000972 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +0000973 SET_RCODE(header, NXDOMAIN);
Simon Kelley087eb762017-10-30 23:16:54 +0000974 else if (flags == F_SERVFAIL)
Simon Kelley07ed5852018-05-04 21:52:22 +0100975 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000976 union all_addr a;
977 a.log.rcode = SERVFAIL;
Simon Kelley07ed5852018-05-04 21:52:22 +0100978 log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
979 SET_RCODE(header, SERVFAIL);
980 }
Simon Kelleyc346f612018-09-04 21:14:18 +0100981 else if (flags & ( F_IPV4 | F_IPV6))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000982 {
Simon Kelleyc346f612018-09-04 21:14:18 +0100983 if (flags & F_IPV4)
984 { /* we know the address */
985 SET_RCODE(header, NOERROR);
986 header->ancount = htons(1);
987 header->hb3 |= HB3_AA;
988 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
989 }
990
Simon Kelleyc346f612018-09-04 21:14:18 +0100991 if (flags & F_IPV6)
992 {
993 SET_RCODE(header, NOERROR);
994 header->ancount = htons(ntohs(header->ancount) + 1);
995 header->hb3 |= HB3_AA;
996 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
997 }
Simon Kelleyc346f612018-09-04 21:14:18 +0100998 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000999 else /* nowhere to forward to */
Simon Kelley07ed5852018-05-04 21:52:22 +01001000 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001001 union all_addr a;
1002 a.log.rcode = REFUSED;
Simon Kelley07ed5852018-05-04 21:52:22 +01001003 log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
1004 SET_RCODE(header, REFUSED);
1005 }
1006
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001007 return p - (unsigned char *)header;
1008}
Simon Kelley36717ee2004-09-20 19:20:58 +01001009
1010/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001011int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001012{
Simon Kelley0a852542005-03-23 20:28:59 +00001013 struct mx_srv_record *mx;
1014 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001015 struct interface_name *intr;
1016 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001017 struct naptr *naptr;
1018
Simon Kelley7de060b2011-08-26 17:24:52 +01001019 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001020 if (hostname_issubdomain(name, naptr->name))
Simon Kelley7de060b2011-08-26 17:24:52 +01001021 return 1;
1022
1023 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001024 if (hostname_issubdomain(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001025 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001026
Simon Kelley0a852542005-03-23 20:28:59 +00001027 for (txt = daemon->txt; txt; txt = txt->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001028 if (hostname_issubdomain(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001029 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001030
1031 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001032 if (hostname_issubdomain(name, intr->name))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001033 return 1;
1034
1035 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001036 if (hostname_issubdomain(name, ptr->name))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001037 return 1;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001038
1039 if (cache_find_non_terminal(name, now))
1040 return 1;
1041
Simon Kelley36717ee2004-09-20 19:20:58 +01001042 return 0;
1043}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001044
1045/* Is the packet a reply with the answer address equal to addr?
1046 If so mung is into an NXDOMAIN reply and also put that information
1047 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001048int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001049 struct bogus_addr *baddr, time_t now)
1050{
1051 unsigned char *p;
1052 int i, qtype, qclass, rdlen;
1053 unsigned long ttl;
1054 struct bogus_addr *baddrp;
1055
1056 /* skip over questions */
1057 if (!(p = skip_questions(header, qlen)))
1058 return 0; /* bad packet */
1059
Simon Kelley5aabfc72007-08-29 11:24:47 +01001060 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001061 {
Simon Kelley9009d742008-11-14 20:04:27 +00001062 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001063 return 0; /* bad packet */
1064
1065 GETSHORT(qtype, p);
1066 GETSHORT(qclass, p);
1067 GETLONG(ttl, p);
1068 GETSHORT(rdlen, p);
1069
1070 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001071 {
1072 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1073 return 0;
1074
1075 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1076 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1077 {
1078 /* Found a bogus address. Insert that info here, since there no SOA record
1079 to get the ttl from in the normal processing */
1080 cache_start_insert();
Simon Kelley65a01b72018-12-31 23:56:33 +00001081 cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001082 cache_end_insert();
1083
1084 return 1;
1085 }
1086 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001087
Simon Kelley9009d742008-11-14 20:04:27 +00001088 if (!ADD_RDLEN(header, p, qlen, rdlen))
1089 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001090 }
1091
1092 return 0;
1093}
1094
Glen Huang32fc6db2014-12-27 15:28:12 +00001095int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
1096{
1097 unsigned char *p;
1098 int i, qtype, qclass, rdlen;
1099 struct bogus_addr *baddrp;
1100
1101 /* skip over questions */
1102 if (!(p = skip_questions(header, qlen)))
1103 return 0; /* bad packet */
1104
1105 for (i = ntohs(header->ancount); i != 0; i--)
1106 {
1107 if (!(p = skip_name(p, header, qlen, 10)))
1108 return 0; /* bad packet */
1109
1110 GETSHORT(qtype, p);
1111 GETSHORT(qclass, p);
1112 p += 4; /* TTL */
1113 GETSHORT(rdlen, p);
1114
1115 if (qclass == C_IN && qtype == T_A)
1116 {
1117 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1118 return 0;
1119
1120 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1121 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1122 return 1;
1123 }
1124
1125 if (!ADD_RDLEN(header, p, qlen, rdlen))
1126 return 0;
1127 }
1128
1129 return 0;
1130}
1131
Simon Kelley0549c732017-09-25 18:17:11 +01001132
Simon Kelleyb75e9362012-12-07 11:50:41 +00001133int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001134 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001135{
1136 va_list ap;
1137 unsigned char *sav, *p = *pp;
1138 int j;
1139 unsigned short usval;
1140 long lval;
1141 char *sval;
Simon Kelleyc3667172017-10-13 23:26:29 +01001142
Simon Kelley0549c732017-09-25 18:17:11 +01001143#define CHECK_LIMIT(size) \
Simon Kelleyc3667172017-10-13 23:26:29 +01001144 if (limit && p + (size) > (unsigned char*)limit) goto truncated;
Simon Kelley0549c732017-09-25 18:17:11 +01001145
Simon Kelley4f7b3042012-11-28 21:27:02 +00001146 va_start(ap, format); /* make ap point to 1st unamed argument */
Simon Kelleyc3667172017-10-13 23:26:29 +01001147
1148 if (truncp && *truncp)
1149 goto truncated;
1150
Simon Kelleyb75e9362012-12-07 11:50:41 +00001151 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001152 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001153 CHECK_LIMIT(2);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001154 PUTSHORT(nameoffset | 0xc000, p);
1155 }
1156 else
1157 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001158 char *name = va_arg(ap, char *);
Simon Kelley62cb9362017-09-26 22:00:11 +01001159 if (name && !(p = do_rfc1035_name(p, name, limit)))
Simon Kelleyc3667172017-10-13 23:26:29 +01001160 goto truncated;
Simon Kelley62cb9362017-09-26 22:00:11 +01001161
Simon Kelleyb75e9362012-12-07 11:50:41 +00001162 if (nameoffset < 0)
1163 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001164 CHECK_LIMIT(2);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001165 PUTSHORT(-nameoffset | 0xc000, p);
1166 }
1167 else
Simon Kelley62cb9362017-09-26 22:00:11 +01001168 {
1169 CHECK_LIMIT(1);
1170 *p++ = 0;
1171 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001172 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001173
Simon Kelley62cb9362017-09-26 22:00:11 +01001174 /* type (2) + class (2) + ttl (4) + rdlen (2) */
1175 CHECK_LIMIT(10);
1176
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001177 PUTSHORT(type, p);
1178 PUTSHORT(class, p);
1179 PUTLONG(ttl, p); /* TTL */
1180
1181 sav = p; /* Save pointer to RDLength field */
1182 PUTSHORT(0, p); /* Placeholder RDLength */
1183
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001184 for (; *format; format++)
1185 switch (*format)
1186 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001187 case '6':
Simon Kelley0549c732017-09-25 18:17:11 +01001188 CHECK_LIMIT(IN6ADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001189 sval = va_arg(ap, char *);
1190 memcpy(p, sval, IN6ADDRSZ);
1191 p += IN6ADDRSZ;
1192 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001193
1194 case '4':
Simon Kelley0549c732017-09-25 18:17:11 +01001195 CHECK_LIMIT(INADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001196 sval = va_arg(ap, char *);
1197 memcpy(p, sval, INADDRSZ);
1198 p += INADDRSZ;
1199 break;
1200
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001201 case 'b':
Simon Kelley0549c732017-09-25 18:17:11 +01001202 CHECK_LIMIT(1);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001203 usval = va_arg(ap, int);
1204 *p++ = usval;
1205 break;
1206
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001207 case 's':
Simon Kelley0549c732017-09-25 18:17:11 +01001208 CHECK_LIMIT(2);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001209 usval = va_arg(ap, int);
1210 PUTSHORT(usval, p);
1211 break;
1212
1213 case 'l':
Simon Kelley0549c732017-09-25 18:17:11 +01001214 CHECK_LIMIT(4);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001215 lval = va_arg(ap, long);
1216 PUTLONG(lval, p);
1217 break;
1218
1219 case 'd':
Simon Kelley0549c732017-09-25 18:17:11 +01001220 /* get domain-name answer arg and store it in RDATA field */
1221 if (offset)
1222 *offset = p - (unsigned char *)header;
Simon Kelleyc3667172017-10-13 23:26:29 +01001223 if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
1224 goto truncated;
1225 CHECK_LIMIT(1);
Simon Kelley0549c732017-09-25 18:17:11 +01001226 *p++ = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001227 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001228
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001229 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001230 usval = va_arg(ap, int);
Simon Kelley0549c732017-09-25 18:17:11 +01001231 CHECK_LIMIT(usval);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001232 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001233 if (usval != 0)
1234 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001235 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001236 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001237
1238 case 'z':
1239 sval = va_arg(ap, char *);
1240 usval = sval ? strlen(sval) : 0;
1241 if (usval > 255)
1242 usval = 255;
Simon Kelley0549c732017-09-25 18:17:11 +01001243 CHECK_LIMIT(usval + 1);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001244 *p++ = (unsigned char)usval;
1245 memcpy(p, sval, usval);
1246 p += usval;
1247 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001248 }
1249
1250 va_end(ap); /* clean up variable argument pointer */
1251
Simon Kelleyc3667172017-10-13 23:26:29 +01001252 /* Now, store real RDLength. sav already checked against limit. */
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001253 j = p - sav - 2;
Simon Kelleyc3667172017-10-13 23:26:29 +01001254 PUTSHORT(j, sav);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001255
1256 *pp = p;
1257 return 1;
Simon Kelleyc3667172017-10-13 23:26:29 +01001258
1259 truncated:
1260 va_end(ap);
1261 if (truncp)
1262 *truncp = 1;
1263 return 0;
1264
1265#undef CHECK_LIMIT
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001266}
1267
Simon Kelley9009d742008-11-14 20:04:27 +00001268static unsigned long crec_ttl(struct crec *crecp, time_t now)
1269{
1270 /* Return 0 ttl for DHCP entries, which might change
Simon Kelley7480aef2016-02-26 21:58:20 +00001271 before the lease expires, unless configured otherwise. */
Simon Kelley9009d742008-11-14 20:04:27 +00001272
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001273 if (crecp->flags & F_DHCP)
Simon Kelley7480aef2016-02-26 21:58:20 +00001274 {
1275 int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
1276
1277 /* Apply ceiling of actual lease length to configured TTL. */
1278 if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
1279 return crecp->ttd - now;
1280
1281 return conf_ttl;
1282 }
Simon Kelley9009d742008-11-14 20:04:27 +00001283
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001284 /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
1285 if (crecp->flags & F_IMMORTAL)
1286 return crecp->ttd;
1287
klemens43517fc2017-02-19 15:53:37 +00001288 /* Return the Max TTL value if it is lower than the actual TTL */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001289 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1290 return crecp->ttd - now;
1291 else
1292 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001293}
1294
1295
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001296/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001297size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001298 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001299 time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001300{
Simon Kelley3be34542004-09-11 19:12:13 +01001301 char *name = daemon->namebuff;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001302 unsigned char *p, *ansp;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001303 unsigned int qtype, qclass;
Simon Kelleycc921df2019-01-02 22:48:59 +00001304 union all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001305 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001306 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001307 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001308 int dryrun = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001309 struct crec *crecp;
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001310 int nxdomain = 0, notimp = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001311 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001312 size_t len;
Simon Kelleyfa785732016-07-22 20:56:01 +01001313
Simon Kelley41392982018-09-19 22:27:11 +01001314 /* never answer queries with RD unset, to avoid cache snooping. */
1315 if (!(header->hb3 & HB3_RD) ||
1316 ntohs(header->ancount) != 0 ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001317 ntohs(header->nscount) != 0 ||
1318 ntohs(header->qdcount) == 0 ||
1319 OPCODE(header) != QUERY )
1320 return 0;
Simon Kelley087eb762017-10-30 23:16:54 +00001321
Simon Kelleye243c072014-02-06 18:14:09 +00001322 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001323 if (header->hb4 & HB4_CD)
1324 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001325
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001326 /* If there is an additional data section then it will be overwritten by
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001327 partial replies, so we have to do a dry run to see if we can answer
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001328 the query. */
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001329 if (ntohs(header->arcount) != 0)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001330 dryrun = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001331
Simon Kelley0a852542005-03-23 20:28:59 +00001332 for (rec = daemon->mxnames; rec; rec = rec->next)
1333 rec->offset = 0;
1334
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001335 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001336 /* determine end of question section (we put answers there) */
1337 if (!(ansp = skip_questions(header, qlen)))
1338 return 0; /* bad packet */
1339
1340 /* now process each question, answers go in RRs after the question */
1341 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001342
Simon Kelley5aabfc72007-08-29 11:24:47 +01001343 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001344 {
1345 /* save pointer to name for copying into answers */
1346 nameoffset = p - (unsigned char *)header;
1347
1348 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001349 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001350 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001351
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001352 GETSHORT(qtype, p);
1353 GETSHORT(qclass, p);
1354
1355 ans = 0; /* have we answered this question */
1356
Simon Kelley0a852542005-03-23 20:28:59 +00001357 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001358 {
Simon Kelley0a852542005-03-23 20:28:59 +00001359 struct txt_record *t;
1360 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001361 {
Simon Kelley0a852542005-03-23 20:28:59 +00001362 if (t->class == qclass && hostname_isequal(name, t->name))
1363 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001364 ans = 1, sec_data = 0;
Simon Kelleye17fb622006-01-14 20:33:46 +00001365 if (!dryrun)
1366 {
Simon Kelleyfec216d2014-03-27 20:54:34 +00001367 unsigned long ttl = daemon->local_ttl;
1368 int ok = 1;
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001369#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001370 /* Dynamically generate stat record */
1371 if (t->stat != 0)
1372 {
1373 ttl = 0;
1374 if (!cache_make_stat(t))
1375 ok = 0;
1376 }
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001377#endif
Simon Kelleycbb5b172018-10-23 23:45:57 +01001378 if (ok)
1379 {
1380 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
1381 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1382 ttl, NULL,
1383 T_TXT, t->class, "t", t->len, t->txt))
1384 anscount++;
1385 }
Simon Kelleye17fb622006-01-14 20:33:46 +00001386 }
Simon Kelley0a852542005-03-23 20:28:59 +00001387 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001388 }
Simon Kelley0a852542005-03-23 20:28:59 +00001389 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001390
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001391 if (qclass == C_CHAOS)
1392 {
Simon Kelleycbb5b172018-10-23 23:45:57 +01001393 /* don't forward *.bind and *.server chaos queries - always reply with NOTIMP */
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001394 if (hostname_issubdomain("bind", name) || hostname_issubdomain("server", name))
1395 {
1396 if (!ans)
Simon Kelleycbb5b172018-10-23 23:45:57 +01001397 {
1398 notimp = 1, auth = 0;
1399 if (!dryrun)
1400 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001401 addr.log.rcode = NOTIMP;
Simon Kelleycbb5b172018-10-23 23:45:57 +01001402 log_query(F_CONFIG | F_RCODE, name, &addr, NULL);
1403 }
Simon Kelley6f7812d2018-10-23 23:54:44 +01001404 ans = 1, sec_data = 0;
Simon Kelleycbb5b172018-10-23 23:45:57 +01001405 }
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001406 }
1407 }
1408
Simon Kelley0a852542005-03-23 20:28:59 +00001409 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001410 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001411 struct txt_record *t;
1412
1413 for (t = daemon->rr; t; t = t->next)
1414 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1415 {
1416 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001417 sec_data = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001418 if (!dryrun)
1419 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001420 log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, t->class));
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001421 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1422 daemon->local_ttl, NULL,
1423 t->class, C_IN, "t", t->len, t->txt))
Simon Kelley97f876b2018-08-21 22:06:36 +01001424 anscount++;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001425 }
1426 }
1427
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001428 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001429 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001430 /* see if it's w.z.y.z.in-addr.arpa format */
1431 int is_arpa = in_arpa_name_2_addr(name, &addr);
1432 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001433 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001434
1435 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1436 if (hostname_isequal(name, ptr->name))
1437 break;
1438
Simon Kelleyf2621c72007-04-29 19:47:21 +01001439 if (is_arpa == F_IPV4)
1440 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001441 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001442 struct addrlist *addrlist;
1443
Simon Kelley376d48c2013-11-13 13:04:30 +00001444 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00001445 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001446 break;
1447
1448 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001449 break;
1450 else
1451 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1452 intr = intr->next;
1453 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001454 else if (is_arpa == F_IPV6)
1455 for (intr = daemon->int_names; intr; intr = intr->next)
1456 {
1457 struct addrlist *addrlist;
1458
Simon Kelley376d48c2013-11-13 13:04:30 +00001459 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00001460 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001461 break;
1462
1463 if (addrlist)
1464 break;
1465 else
1466 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1467 intr = intr->next;
1468 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001469
1470 if (intr)
1471 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001472 sec_data = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001473 ans = 1;
1474 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001475 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001476 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001477 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1478 daemon->local_ttl, NULL,
1479 T_PTR, C_IN, "d", intr->name))
1480 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001481 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001482 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001483 else if (ptr)
1484 {
1485 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001486 sec_data = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001487 if (!dryrun)
1488 {
Simon Kelley28866e92011-02-14 20:19:14 +00001489 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001490 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001491 if (hostname_isequal(name, ptr->name) &&
1492 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1493 daemon->local_ttl, NULL,
1494 T_PTR, C_IN, "d", ptr->ptr))
1495 anscount++;
1496
Simon Kelley832af0b2007-01-21 20:01:28 +00001497 }
1498 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001499 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001500 {
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001501 /* Don't use cache when DNSSEC data required, unless we know that
1502 the zone is unsigned, which implies that we're doing
1503 validation. */
1504 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001505 !do_bit ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001506 (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001507 {
1508 do
1509 {
1510 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1511 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1512 continue;
1513
1514 if (!(crecp->flags & F_DNSSECOK))
1515 sec_data = 0;
Simon Kelley93be5b12015-12-15 12:04:40 +00001516
1517 ans = 1;
1518
Simon Kelley2d33bda2014-01-24 22:37:25 +00001519 if (crecp->flags & F_NEG)
1520 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001521 auth = 0;
1522 if (crecp->flags & F_NXDOMAIN)
1523 nxdomain = 1;
1524 if (!dryrun)
1525 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1526 }
Simon Kelley93be5b12015-12-15 12:04:40 +00001527 else
Simon Kelley2d33bda2014-01-24 22:37:25 +00001528 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001529 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1530 auth = 0;
1531 if (!dryrun)
1532 {
1533 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1534 record_source(crecp->uid));
1535
1536 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1537 crec_ttl(crecp, now), NULL,
1538 T_PTR, C_IN, "d", cache_get_name(crecp)))
1539 anscount++;
1540 }
1541 }
1542 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1543 }
1544 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001545 else if (is_rev_synth(is_arpa, &addr, name))
1546 {
1547 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001548 sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001549 if (!dryrun)
1550 {
1551 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1552
1553 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1554 daemon->local_ttl, NULL,
1555 T_PTR, C_IN, "d", name))
1556 anscount++;
1557 }
1558 }
Simon Kelleyfca008d2017-02-19 18:50:41 +00001559 else if (option_bool(OPT_BOGUSPRIV) && (
Simon Kelleycc921df2019-01-02 22:48:59 +00001560 (is_arpa == F_IPV6 && private_net6(&addr.addr6)) ||
1561 (is_arpa == F_IPV4 && private_net(addr.addr4, 1))))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001562 {
Vladislav Grishenko5a7212c2017-04-24 22:19:57 +01001563 struct server *serv;
1564 unsigned int namelen = strlen(name);
1565 char *nameend = name + namelen;
1566
1567 /* see if have rev-server set */
1568 for (serv = daemon->servers; serv; serv = serv->next)
1569 {
1570 unsigned int domainlen;
1571 char *matchstart;
1572
1573 if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
1574 continue;
1575
1576 domainlen = strlen(serv->domain);
1577 if (domainlen == 0 || domainlen > namelen)
1578 continue;
1579
1580 matchstart = nameend - domainlen;
1581 if (hostname_isequal(matchstart, serv->domain) &&
1582 (namelen == domainlen || *(matchstart-1) == '.' ))
1583 break;
1584 }
1585
1586 /* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
1587 if (!serv)
1588 {
1589 ans = 1;
1590 sec_data = 0;
1591 nxdomain = 1;
1592 if (!dryrun)
1593 log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
1594 name, &addr, NULL);
1595 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001596 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001597 }
Simon Kelleyfca008d2017-02-19 18:50:41 +00001598
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001599 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1600 {
Simon Kelleyee875042018-10-23 22:10:17 +01001601 unsigned short type = (flag == F_IPV6) ? T_AAAA : T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001602 struct interface_name *intr;
1603
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001604 if (qtype != type && qtype != T_ANY)
1605 continue;
1606
Simon Kelleyf2621c72007-04-29 19:47:21 +01001607 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001608 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001609 for (intr = daemon->int_names; intr; intr = intr->next)
1610 if (hostname_isequal(name, intr->name))
1611 break;
1612
1613 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001614 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001615 struct addrlist *addrlist;
Simon Kelleyd42d4702017-02-02 16:52:06 +00001616 int gotit = 0, localise = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001617
Simon Kelley115ac3e2013-05-20 11:28:32 +01001618 enumerate_interfaces(0);
Simon Kelleyd42d4702017-02-02 16:52:06 +00001619
klemens43517fc2017-02-19 15:53:37 +00001620 /* See if a putative address is on the network from which we received
Simon Kelleyd42d4702017-02-02 16:52:06 +00001621 the query, is so we'll filter other answers. */
1622 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && type == T_A)
1623 for (intr = daemon->int_names; intr; intr = intr->next)
1624 if (hostname_isequal(name, intr->name))
1625 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleyee875042018-10-23 22:10:17 +01001626 if (!(addrlist->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001627 is_same_net(addrlist->addr.addr4, local_addr, local_netmask))
Simon Kelleyee875042018-10-23 22:10:17 +01001628 {
1629 localise = 1;
1630 break;
1631 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001632
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001633 for (intr = daemon->int_names; intr; intr = intr->next)
1634 if (hostname_isequal(name, intr->name))
1635 {
Simon Kelley47669362014-12-17 12:41:56 +00001636 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley47669362014-12-17 12:41:56 +00001637 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
Simon Kelley47669362014-12-17 12:41:56 +00001638 {
Simon Kelleyd42d4702017-02-02 16:52:06 +00001639 if (localise &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001640 !is_same_net(addrlist->addr.addr4, local_addr, local_netmask))
Simon Kelleyd42d4702017-02-02 16:52:06 +00001641 continue;
1642
Simon Kelley47669362014-12-17 12:41:56 +00001643 if (addrlist->flags & ADDRLIST_REVONLY)
1644 continue;
Simon Kelleyee875042018-10-23 22:10:17 +01001645
Simon Kelley47669362014-12-17 12:41:56 +00001646 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001647 sec_data = 0;
Simon Kelley47669362014-12-17 12:41:56 +00001648 if (!dryrun)
Simon Kelley376d48c2013-11-13 13:04:30 +00001649 {
1650 gotit = 1;
1651 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1652 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1653 daemon->local_ttl, NULL, type, C_IN,
1654 type == T_A ? "4" : "6", &addrlist->addr))
1655 anscount++;
1656 }
Simon Kelley47669362014-12-17 12:41:56 +00001657 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001658 }
1659
1660 if (!dryrun && !gotit)
1661 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1662
Simon Kelley115ac3e2013-05-20 11:28:32 +01001663 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001664 }
1665
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001666 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00001667 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001668 {
1669 int localise = 0;
1670
Josh Soref730c6742017-02-06 16:14:04 +00001671 /* See if a putative address is on the network from which we received
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001672 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001673 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001674 {
1675 struct crec *save = crecp;
1676 do {
1677 if ((crecp->flags & F_HOSTS) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001678 is_same_net(crecp->addr.addr4, local_addr, local_netmask))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001679 {
1680 localise = 1;
1681 break;
1682 }
1683 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1684 crecp = save;
1685 }
Simon Kelley824202e2014-01-23 20:59:46 +00001686
Simon Kelley93be5b12015-12-15 12:04:40 +00001687 /* If the client asked for DNSSEC don't use cached data. */
Simon Kelleya997ca02018-06-29 14:39:41 +01001688 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
1689 !do_bit ||
1690 (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
Simon Kelley824202e2014-01-23 20:59:46 +00001691 do
1692 {
1693 /* don't answer wildcard queries with data not from /etc/hosts
1694 or DHCP leases */
1695 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1696 break;
1697
1698 if (!(crecp->flags & F_DNSSECOK))
1699 sec_data = 0;
1700
1701 if (crecp->flags & F_CNAME)
1702 {
1703 char *cname_target = cache_get_cname_target(crecp);
1704
1705 if (!dryrun)
1706 {
1707 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1708 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1709 crec_ttl(crecp, now), &nameoffset,
1710 T_CNAME, C_IN, "d", cname_target))
1711 anscount++;
1712 }
1713
1714 strcpy(name, cname_target);
1715 /* check if target interface_name */
Andy3e21a1a2014-03-22 19:10:07 +00001716 if (crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelley824202e2014-01-23 20:59:46 +00001717 goto intname_restart;
1718 else
1719 goto cname_restart;
1720 }
1721
1722 if (crecp->flags & F_NEG)
1723 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001724 ans = 1;
1725 auth = 0;
1726 if (crecp->flags & F_NXDOMAIN)
1727 nxdomain = 1;
1728 if (!dryrun)
1729 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley824202e2014-01-23 20:59:46 +00001730 }
1731 else
1732 {
1733 /* If we are returning local answers depending on network,
1734 filter here. */
1735 if (localise &&
1736 (crecp->flags & F_HOSTS) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001737 !is_same_net(crecp->addr.addr4, local_addr, local_netmask))
Simon Kelley824202e2014-01-23 20:59:46 +00001738 continue;
1739
1740 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1741 auth = 0;
1742
1743 ans = 1;
1744 if (!dryrun)
1745 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001746 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr,
Simon Kelley824202e2014-01-23 20:59:46 +00001747 record_source(crecp->uid));
1748
1749 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1750 crec_ttl(crecp, now), NULL, type, C_IN,
1751 type == T_A ? "4" : "6", &crecp->addr))
1752 anscount++;
1753 }
1754 }
1755 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001756 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001757 else if (is_name_synthetic(flag, name, &addr))
1758 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001759 ans = 1, sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001760 if (!dryrun)
1761 {
1762 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
1763 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1764 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
1765 anscount++;
1766 }
1767 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001768 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001769
1770 if (qtype == T_CNAME || qtype == T_ANY)
1771 {
Simon Kelleya6004d72017-10-25 17:48:19 +01001772 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
1773 (qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
Simon Kelleya997ca02018-06-29 14:39:41 +01001774 ((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001775 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001776 if (!(crecp->flags & F_DNSSECOK))
1777 sec_data = 0;
1778
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001779 ans = 1;
1780 if (!dryrun)
1781 {
1782 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1783 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1784 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01001785 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001786 anscount++;
1787 }
1788 }
1789 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001790
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001791 if (qtype == T_MX || qtype == T_ANY)
1792 {
1793 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001794 for (rec = daemon->mxnames; rec; rec = rec->next)
1795 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001796 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001797 ans = found = 1;
1798 sec_data = 0;
1799 if (!dryrun)
1800 {
1801 int offset;
1802 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
1803 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1804 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1805 {
1806 anscount++;
1807 if (rec->target)
1808 rec->offset = offset;
1809 }
1810 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001811 }
1812
Simon Kelley28866e92011-02-14 20:19:14 +00001813 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00001814 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001815 {
1816 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001817 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001818 if (!dryrun)
1819 {
Simon Kelley28866e92011-02-14 20:19:14 +00001820 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001821 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1822 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00001823 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001824 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001825 }
1826 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001827 }
1828
1829 if (qtype == T_SRV || qtype == T_ANY)
1830 {
1831 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001832 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
1833
Simon Kelley0a852542005-03-23 20:28:59 +00001834 for (rec = daemon->mxnames; rec; rec = rec->next)
1835 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001836 {
1837 found = ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001838 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001839 if (!dryrun)
1840 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001841 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001842 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001843 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001844 &offset, T_SRV, C_IN, "sssd",
1845 rec->priority, rec->weight, rec->srvport, rec->target))
1846 {
1847 anscount++;
1848 if (rec->target)
1849 rec->offset = offset;
1850 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001851 }
Simon Kelley28866e92011-02-14 20:19:14 +00001852
1853 /* unlink first SRV record found */
1854 if (!move)
1855 {
1856 move = rec;
1857 *up = rec->next;
1858 }
1859 else
1860 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001861 }
Simon Kelley28866e92011-02-14 20:19:14 +00001862 else
1863 up = &rec->next;
1864
1865 /* put first SRV record back at the end. */
1866 if (move)
1867 {
1868 *up = move;
1869 move->next = NULL;
1870 }
Simon Kelley5b99eae2019-01-06 23:09:50 +00001871
1872 if (!found)
1873 {
1874 cname_srv_restart:
1875 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | F_SRV | (dryrun ? F_NO_RR : 0))) &&
1876 (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
1877 {
1878 if (!(crecp->flags & F_DNSSECOK))
1879 sec_data = 0;
1880
1881 auth = 0;
1882 found = ans = 1;
1883
1884 do {
1885 if (crecp->flags & F_CNAME)
1886 {
1887 char *cname_target = cache_get_cname_target(crecp);
1888
1889 if (!dryrun)
1890 {
1891 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1892 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1893 crec_ttl(crecp, now), &nameoffset,
1894 T_CNAME, C_IN, "d", cname_target))
1895 anscount++;
1896 }
1897
1898 strcpy(name, cname_target);
1899 goto cname_srv_restart;
1900 }
1901 else if (crecp->flags & F_NEG)
1902 {
1903 if (crecp->flags & F_NXDOMAIN)
1904 nxdomain = 1;
1905 if (!dryrun)
1906 log_query(crecp->flags, name, NULL, NULL);
1907 }
1908 else
1909 {
1910 unsigned char *p1 = ((unsigned char *)header) + nameoffset;
1911
1912 if (!dryrun)
1913 {
1914 log_query(crecp->flags, name, NULL, 0);
1915
1916 blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, name);
1917 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1918 crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd",
1919 crecp->addr.srv.priority, crecp->addr.srv.weight, crecp->addr.srv.srvport,
1920 name))
1921 anscount++;
1922
1923
1924 /* restore name we overwrote */
1925 if (!extract_name(header, qlen, &p1, name, 1, 0))
1926 return 0; /* bad packet */
1927 }
1928 }
1929 } while ((crecp = cache_find_by_name(crecp, name, now, F_SRV | F_CNAME)));
1930 }
1931 }
1932
Simon Kelley28866e92011-02-14 20:19:14 +00001933 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001934 {
1935 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001936 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001937 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001938 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001939 }
1940 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001941
1942 if (qtype == T_NAPTR || qtype == T_ANY)
1943 {
1944 struct naptr *na;
1945 for (na = daemon->naptr; na; na = na->next)
1946 if (hostname_isequal(name, na->name))
1947 {
1948 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001949 sec_data = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001950 if (!dryrun)
1951 {
Simon Kelley28866e92011-02-14 20:19:14 +00001952 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001953 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1954 NULL, T_NAPTR, C_IN, "sszzzd",
1955 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1956 anscount++;
1957 }
1958 }
1959 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001960
1961 if (qtype == T_MAILB)
Simon Kelley6f7812d2018-10-23 23:54:44 +01001962 ans = 1, nxdomain = 1, sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001963
Simon Kelley28866e92011-02-14 20:19:14 +00001964 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001965 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001966 ans = 1;
1967 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001968 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001969 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001970 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001971 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001972
1973 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001974 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001975 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001976
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001977 if (dryrun)
1978 {
1979 dryrun = 0;
1980 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001981 }
1982
Simon Kelley0a852542005-03-23 20:28:59 +00001983 /* create an additional data section, for stuff in SRV and MX record replies. */
1984 for (rec = daemon->mxnames; rec; rec = rec->next)
1985 if (rec->offset != 0)
1986 {
1987 /* squash dupes */
1988 struct mx_srv_record *tmp;
1989 for (tmp = rec->next; tmp; tmp = tmp->next)
1990 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1991 tmp->offset = 0;
1992
1993 crecp = NULL;
1994 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1995 {
Simon Kelley0a852542005-03-23 20:28:59 +00001996 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
Simon Kelleyee875042018-10-23 22:10:17 +01001997
Simon Kelley0a852542005-03-23 20:28:59 +00001998 if (crecp->flags & F_NEG)
1999 continue;
2000
Simon Kelley9009d742008-11-14 20:04:27 +00002001 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
2002 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00002003 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
2004 addncount++;
2005 }
2006 }
2007
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002008 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00002009 /* clear authoritative and truncated flags, set QR flag */
2010 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
2011 /* set RA flag */
2012 header->hb4 |= HB4_RA;
2013
Josh Soref730c6742017-02-06 16:14:04 +00002014 /* authoritative - only hosts and DHCP derived names. */
Simon Kelley572b41e2011-02-18 18:11:18 +00002015 if (auth)
2016 header->hb3 |= HB3_AA;
2017
2018 /* truncation */
2019 if (trunc)
2020 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00002021
Simon Kelley45cca582013-10-15 10:20:13 +01002022 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00002023 SET_RCODE(header, NXDOMAIN);
Vladislav Grishenkocf598432018-10-18 04:55:21 +05002024 else if (notimp)
2025 SET_RCODE(header, NOTIMP);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002026 else
Simon Kelley572b41e2011-02-18 18:11:18 +00002027 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002028 header->ancount = htons(anscount);
2029 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00002030 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00002031
Simon Kelleya25720a2014-01-14 23:13:55 +00002032 len = ansp - (unsigned char *)header;
2033
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002034 /* Advertise our packet size limit in our reply */
Simon Kelleya25720a2014-01-14 23:13:55 +00002035 if (have_pseudoheader)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00002036 len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
Simon Kelleye243c072014-02-06 18:14:09 +00002037
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002038 if (ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00002039 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00002040 else
2041 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00002042
Simon Kelley7c286122014-01-27 21:38:11 +00002043 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002044}