blob: 502744bd1f847441e8a6dbf485fd9032f2a52e9f [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 Kelleyae7a3b92019-09-03 14:40:47 +0100611 if (daemon->rr_status[i] != 0)
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 Kelleyae7a3b92019-09-03 14:40:47 +0100684 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
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;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100691 /* limit TTL based on signature. */
692 if (daemon->rr_status[j] < cttl)
693 cttl = daemon->rr_status[j];
Simon Kelleya6004d72017-10-25 17:48:19 +0100694 }
Simon Kelley8c707e12017-12-05 22:28:10 +0000695#endif
Simon Kelleya6004d72017-10-25 17:48:19 +0100696
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100697 if (aqtype == T_CNAME)
698 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100699 if (!cname_count--)
700 return 0; /* looped CNAMES, we can't cache. */
Simon Kelley8c707e12017-12-05 22:28:10 +0000701#ifdef HAVE_DNSSEC
Simon Kelleya6004d72017-10-25 17:48:19 +0100702 cname_short = 1;
Simon Kelley8c707e12017-12-05 22:28:10 +0000703#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100704 goto cname_loop;
705 }
706
Simon Kelley65a01b72018-12-31 23:56:33 +0000707 cache_insert(name, &addr, C_IN, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100708 found = 1;
709 }
710
711 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000712 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000713 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100714 }
715 }
716
Simon Kelley28866e92011-02-14 20:19:14 +0000717 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100718 {
719 if (!searched_soa)
720 {
721 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000722 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100723 }
724 if (ttl)
Simon Kelley65a01b72018-12-31 23:56:33 +0000725 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 +0000726 }
727 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100728 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000729 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100730 /* everything other than PTR */
731 struct crec *newc;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000732 int addrlen = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100733
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100734 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100735 {
736 addrlen = INADDRSZ;
737 flags |= F_IPV4;
738 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100739 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100740 {
741 addrlen = IN6ADDRSZ;
742 flags |= F_IPV6;
743 }
Simon Kelley5b99eae2019-01-06 23:09:50 +0000744 else if (qtype == T_SRV)
745 flags |= F_SRV;
746 else
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100747 continue;
748
Simon Kelley45cca582013-10-15 10:20:13 +0100749 cname_loop1:
750 if (!(p1 = skip_questions(header, qlen)))
751 return 0;
752
Simon Kelleya6004d72017-10-25 17:48:19 +0100753 for (j = 0; j < ntohs(header->ancount); j++)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100754 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100755 int secflag = 0;
756
Simon Kelley45cca582013-10-15 10:20:13 +0100757 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
758 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100759
Simon Kelley45cca582013-10-15 10:20:13 +0100760 GETSHORT(aqtype, p1);
761 GETSHORT(aqclass, p1);
762 GETLONG(attl, p1);
763 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000764 {
Simon Kelley45cca582013-10-15 10:20:13 +0100765 (p1) -= 4;
766 PUTLONG(daemon->max_ttl, p1);
767 }
768 GETSHORT(ardlen, p1);
769 endrr = p1+ardlen;
770
771 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
772 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100773#ifdef HAVE_DNSSEC
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100774 if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
775 {
Simon Kelleya6004d72017-10-25 17:48:19 +0100776 secflag = F_DNSSECOK;
Simon Kelleyae7a3b92019-09-03 14:40:47 +0100777
778 /* limit TTl based on sig. */
779 if (daemon->rr_status[j] < attl)
780 attl = daemon->rr_status[j];
781 }
Simon Kelleya6004d72017-10-25 17:48:19 +0100782#endif
Simon Kelley45cca582013-10-15 10:20:13 +0100783 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100784 {
Simon Kelley45cca582013-10-15 10:20:13 +0100785 if (!cname_count--)
786 return 0; /* looped CNAMES */
Simon Kelley1fd56c02019-10-30 12:58:28 +0000787
788 if ((newc = cache_insert(name, NULL, C_IN, now, attl, F_CNAME | F_FORWARD | secflag)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100789 {
Simon Kelley45cca582013-10-15 10:20:13 +0100790 newc->addr.cname.target.cache = NULL;
Simon Kelley1fd56c02019-10-30 12:58:28 +0000791 newc->addr.cname.is_name_ptr = 0;
Simon Kelley45cca582013-10-15 10:20:13 +0100792 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100793 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100794 next_uid(newc);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100795 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100796 cpp->addr.cname.uid = newc->uid;
797 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100798 }
Simon Kelley45cca582013-10-15 10:20:13 +0100799
800 cpp = newc;
801 if (attl < cttl)
802 cttl = attl;
803
Simon Kelley122997d2019-10-25 17:23:56 +0100804 namep = p1;
Simon Kelley45cca582013-10-15 10:20:13 +0100805 if (!extract_name(header, qlen, &p1, name, 1, 0))
806 return 0;
Simon Kelley122997d2019-10-25 17:23:56 +0100807
Simon Kelley45cca582013-10-15 10:20:13 +0100808 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100809 }
Simon Kelley45cca582013-10-15 10:20:13 +0100810 else if (!(flags & F_NXDOMAIN))
811 {
812 found = 1;
813
Simon Kelley5b99eae2019-01-06 23:09:50 +0000814 if (flags & F_SRV)
Simon Kelleyb059c962015-05-08 20:25:51 +0100815 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000816 unsigned char *tmp = namep;
817
818 if (!CHECK_LEN(header, p1, qlen, 6))
819 return 0; /* bad packet */
820 GETSHORT(addr.srv.priority, p1);
821 GETSHORT(addr.srv.weight, p1);
822 GETSHORT(addr.srv.srvport, p1);
823 if (!extract_name(header, qlen, &p1, name, 1, 0))
824 return 0;
825 addr.srv.targetlen = strlen(name) + 1; /* include terminating zero */
826 if (!(addr.srv.target = blockdata_alloc(name, addr.srv.targetlen)))
827 return 0;
828
829 /* we overwrote the original name, so get it back here. */
830 if (!extract_name(header, qlen, &tmp, name, 1, 0))
831 return 0;
832 }
833 else
834 {
835 /* copy address into aligned storage */
836 if (!CHECK_LEN(header, p1, qlen, addrlen))
837 return 0; /* bad packet */
838 memcpy(&addr, p1, addrlen);
839
840 /* check for returned address in private space */
841 if (check_rebind)
Simon Kelleyb059c962015-05-08 20:25:51 +0100842 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000843 if ((flags & F_IPV4) &&
844 private_net(addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
Simon Kelleyb059c962015-05-08 20:25:51 +0100845 return 1;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000846
847 if ((flags & F_IPV6) &&
848 IN6_IS_ADDR_V4MAPPED(&addr.addr6))
849 {
850 struct in_addr v4;
851 v4.s_addr = ((const uint32_t *) (&addr.addr6))[3];
852 if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
853 return 1;
854 }
Simon Kelleyb059c962015-05-08 20:25:51 +0100855 }
Simon Kelley5b99eae2019-01-06 23:09:50 +0000856
Simon Kelley45cca582013-10-15 10:20:13 +0100857#ifdef HAVE_IPSET
Simon Kelley5b99eae2019-01-06 23:09:50 +0000858 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
Wang Jian49752b92014-03-28 20:52:47 +0000859 {
Simon Kelley5b99eae2019-01-06 23:09:50 +0000860 ipsets_cur = ipsets;
861 while (*ipsets_cur)
862 {
863 log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
864 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
865 }
Wang Jian49752b92014-03-28 20:52:47 +0000866 }
Simon Kelley45cca582013-10-15 10:20:13 +0100867#endif
Simon Kelley5b99eae2019-01-06 23:09:50 +0000868 }
Simon Kelley45cca582013-10-15 10:20:13 +0100869
Simon Kelley65a01b72018-12-31 23:56:33 +0000870 newc = cache_insert(name, &addr, C_IN, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100871 if (newc && cpp)
872 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100873 next_uid(newc);
Simon Kelley45cca582013-10-15 10:20:13 +0100874 cpp->addr.cname.target.cache = newc;
875 cpp->addr.cname.uid = newc->uid;
876 }
877 cpp = NULL;
878 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100879 }
Simon Kelley45cca582013-10-15 10:20:13 +0100880
881 p1 = endrr;
882 if (!CHECK_LEN(header, p1, qlen, 0))
883 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100884 }
885
Simon Kelley28866e92011-02-14 20:19:14 +0000886 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100887 {
888 if (!searched_soa)
889 {
890 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000891 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100892 }
893 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +0000894 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100895 if (ttl || cpp)
896 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000897 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 +0000898 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100899 {
Simon Kelley45d8a242018-07-17 21:01:14 +0100900 next_uid(newc);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100901 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100902 cpp->addr.cname.uid = newc->uid;
903 }
904 }
905 }
906 }
907 }
908
Simon Kelley1023dcb2012-04-09 18:00:08 +0100909 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +0100910 Don't cache replies from non-recursive nameservers, since we may get a
911 reply containing a CNAME but not its target, even though the target
912 does exist. */
913 if (!(header->hb3 & HB3_TC) &&
914 !(header->hb4 & HB4_CD) &&
915 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +0000916 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +0000917 cache_end_insert();
918
919 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000920}
921
922/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +0000923 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +0000924unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000925{
926 unsigned char *p = (unsigned char *)(header+1);
927 int qtype, qclass;
928
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100929 if (typep)
930 *typep = 0;
931
Simon Kelley572b41e2011-02-18 18:11:18 +0000932 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000933 return 0; /* must be exactly one query. */
934
Simon Kelley9009d742008-11-14 20:04:27 +0000935 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936 return 0; /* bad packet */
937
938 GETSHORT(qtype, p);
939 GETSHORT(qclass, p);
940
Simon Kelley0a852542005-03-23 20:28:59 +0000941 if (typep)
942 *typep = qtype;
943
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000944 if (qclass == C_IN)
945 {
946 if (qtype == T_A)
947 return F_IPV4;
948 if (qtype == T_AAAA)
949 return F_IPV6;
950 if (qtype == T_ANY)
951 return F_IPV4 | F_IPV6;
952 }
Simon Kelley07e25da2018-12-16 18:21:58 +0000953
954 /* F_DNSSECOK as agument to search_servers() inhibits forwarding
955 to servers for domains without a trust anchor. This make the
956 behaviour for DS and DNSKEY queries we forward the same
957 as for DS and DNSKEY queries we originate. */
958 if (qtype == T_DS || qtype == T_DNSKEY)
959 return F_DNSSECOK;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000960
961 return F_QUERY;
962}
963
Simon Kelley572b41e2011-02-18 18:11:18 +0000964size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelleycc921df2019-01-02 22:48:59 +0000965 union all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000966{
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100967 unsigned char *p;
Simon Kelley07ed5852018-05-04 21:52:22 +0100968
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100969 if (!(p = skip_questions(header, qlen)))
970 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000971
Simon Kelley572b41e2011-02-18 18:11:18 +0000972 /* clear authoritative and truncated flags, set QR flag */
Simon Kelleya2205452018-10-22 18:21:48 +0100973 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
974 /* clear AD flag, set RA flag */
975 header->hb4 = (header->hb4 & ~HB4_AD) | HB4_RA;
Simon Kelley572b41e2011-02-18 18:11:18 +0000976
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000977 header->nscount = htons(0);
978 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100979 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000980 if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +0000981 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000982 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +0000983 SET_RCODE(header, NXDOMAIN);
Simon Kelley087eb762017-10-30 23:16:54 +0000984 else if (flags == F_SERVFAIL)
Simon Kelley07ed5852018-05-04 21:52:22 +0100985 {
Simon Kelleycc921df2019-01-02 22:48:59 +0000986 union all_addr a;
987 a.log.rcode = SERVFAIL;
Simon Kelley07ed5852018-05-04 21:52:22 +0100988 log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
989 SET_RCODE(header, SERVFAIL);
990 }
Simon Kelleyc346f612018-09-04 21:14:18 +0100991 else if (flags & ( F_IPV4 | F_IPV6))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000992 {
Simon Kelleyc346f612018-09-04 21:14:18 +0100993 if (flags & F_IPV4)
994 { /* we know the address */
995 SET_RCODE(header, NOERROR);
996 header->ancount = htons(1);
997 header->hb3 |= HB3_AA;
998 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
999 }
1000
Simon Kelleyc346f612018-09-04 21:14:18 +01001001 if (flags & F_IPV6)
1002 {
1003 SET_RCODE(header, NOERROR);
1004 header->ancount = htons(ntohs(header->ancount) + 1);
1005 header->hb3 |= HB3_AA;
1006 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
1007 }
Simon Kelleyc346f612018-09-04 21:14:18 +01001008 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001009 else /* nowhere to forward to */
Simon Kelley07ed5852018-05-04 21:52:22 +01001010 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001011 union all_addr a;
1012 a.log.rcode = REFUSED;
Simon Kelley07ed5852018-05-04 21:52:22 +01001013 log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
1014 SET_RCODE(header, REFUSED);
1015 }
1016
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001017 return p - (unsigned char *)header;
1018}
Simon Kelley36717ee2004-09-20 19:20:58 +01001019
1020/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001021int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +01001022{
Simon Kelley0a852542005-03-23 20:28:59 +00001023 struct mx_srv_record *mx;
1024 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001025 struct interface_name *intr;
1026 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +01001027 struct naptr *naptr;
1028
Simon Kelley7de060b2011-08-26 17:24:52 +01001029 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001030 if (hostname_issubdomain(name, naptr->name))
Simon Kelley7de060b2011-08-26 17:24:52 +01001031 return 1;
1032
1033 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001034 if (hostname_issubdomain(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +01001035 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001036
Simon Kelley0a852542005-03-23 20:28:59 +00001037 for (txt = daemon->txt; txt; txt = txt->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001038 if (hostname_issubdomain(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001039 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001040
1041 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001042 if (hostname_issubdomain(name, intr->name))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001043 return 1;
1044
1045 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001046 if (hostname_issubdomain(name, ptr->name))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001047 return 1;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001048
1049 if (cache_find_non_terminal(name, now))
1050 return 1;
1051
Simon Kelley36717ee2004-09-20 19:20:58 +01001052 return 0;
1053}
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001054
1055/* Is the packet a reply with the answer address equal to addr?
1056 If so mung is into an NXDOMAIN reply and also put that information
1057 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001058int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001059 struct bogus_addr *baddr, time_t now)
1060{
1061 unsigned char *p;
1062 int i, qtype, qclass, rdlen;
1063 unsigned long ttl;
1064 struct bogus_addr *baddrp;
1065
1066 /* skip over questions */
1067 if (!(p = skip_questions(header, qlen)))
1068 return 0; /* bad packet */
1069
Simon Kelley5aabfc72007-08-29 11:24:47 +01001070 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001071 {
Simon Kelley9009d742008-11-14 20:04:27 +00001072 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001073 return 0; /* bad packet */
1074
1075 GETSHORT(qtype, p);
1076 GETSHORT(qclass, p);
1077 GETLONG(ttl, p);
1078 GETSHORT(rdlen, p);
1079
1080 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +00001081 {
1082 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1083 return 0;
1084
1085 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1086 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1087 {
1088 /* Found a bogus address. Insert that info here, since there no SOA record
1089 to get the ttl from in the normal processing */
1090 cache_start_insert();
Simon Kelley65a01b72018-12-31 23:56:33 +00001091 cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001092 cache_end_insert();
1093
1094 return 1;
1095 }
1096 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001097
Simon Kelley9009d742008-11-14 20:04:27 +00001098 if (!ADD_RDLEN(header, p, qlen, rdlen))
1099 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001100 }
1101
1102 return 0;
1103}
1104
Glen Huang32fc6db2014-12-27 15:28:12 +00001105int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
1106{
1107 unsigned char *p;
1108 int i, qtype, qclass, rdlen;
1109 struct bogus_addr *baddrp;
1110
1111 /* skip over questions */
1112 if (!(p = skip_questions(header, qlen)))
1113 return 0; /* bad packet */
1114
1115 for (i = ntohs(header->ancount); i != 0; i--)
1116 {
1117 if (!(p = skip_name(p, header, qlen, 10)))
1118 return 0; /* bad packet */
1119
1120 GETSHORT(qtype, p);
1121 GETSHORT(qclass, p);
1122 p += 4; /* TTL */
1123 GETSHORT(rdlen, p);
1124
1125 if (qclass == C_IN && qtype == T_A)
1126 {
1127 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1128 return 0;
1129
1130 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1131 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1132 return 1;
1133 }
1134
1135 if (!ADD_RDLEN(header, p, qlen, rdlen))
1136 return 0;
1137 }
1138
1139 return 0;
1140}
1141
Simon Kelley0549c732017-09-25 18:17:11 +01001142
Simon Kelleyb75e9362012-12-07 11:50:41 +00001143int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001144 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001145{
1146 va_list ap;
1147 unsigned char *sav, *p = *pp;
1148 int j;
1149 unsigned short usval;
1150 long lval;
1151 char *sval;
Simon Kelleyc3667172017-10-13 23:26:29 +01001152
Simon Kelley0549c732017-09-25 18:17:11 +01001153#define CHECK_LIMIT(size) \
Simon Kelleyc3667172017-10-13 23:26:29 +01001154 if (limit && p + (size) > (unsigned char*)limit) goto truncated;
Simon Kelley0549c732017-09-25 18:17:11 +01001155
Simon Kelley4f7b3042012-11-28 21:27:02 +00001156 va_start(ap, format); /* make ap point to 1st unamed argument */
Simon Kelleyc3667172017-10-13 23:26:29 +01001157
1158 if (truncp && *truncp)
1159 goto truncated;
1160
Simon Kelleyb75e9362012-12-07 11:50:41 +00001161 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001162 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001163 CHECK_LIMIT(2);
Simon Kelley4f7b3042012-11-28 21:27:02 +00001164 PUTSHORT(nameoffset | 0xc000, p);
1165 }
1166 else
1167 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001168 char *name = va_arg(ap, char *);
Simon Kelley62cb9362017-09-26 22:00:11 +01001169 if (name && !(p = do_rfc1035_name(p, name, limit)))
Simon Kelleyc3667172017-10-13 23:26:29 +01001170 goto truncated;
Simon Kelley62cb9362017-09-26 22:00:11 +01001171
Simon Kelleyb75e9362012-12-07 11:50:41 +00001172 if (nameoffset < 0)
1173 {
Simon Kelley62cb9362017-09-26 22:00:11 +01001174 CHECK_LIMIT(2);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001175 PUTSHORT(-nameoffset | 0xc000, p);
1176 }
1177 else
Simon Kelley62cb9362017-09-26 22:00:11 +01001178 {
1179 CHECK_LIMIT(1);
1180 *p++ = 0;
1181 }
Simon Kelley4f7b3042012-11-28 21:27:02 +00001182 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001183
Simon Kelley62cb9362017-09-26 22:00:11 +01001184 /* type (2) + class (2) + ttl (4) + rdlen (2) */
1185 CHECK_LIMIT(10);
1186
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001187 PUTSHORT(type, p);
1188 PUTSHORT(class, p);
1189 PUTLONG(ttl, p); /* TTL */
1190
1191 sav = p; /* Save pointer to RDLength field */
1192 PUTSHORT(0, p); /* Placeholder RDLength */
1193
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001194 for (; *format; format++)
1195 switch (*format)
1196 {
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001197 case '6':
Simon Kelley0549c732017-09-25 18:17:11 +01001198 CHECK_LIMIT(IN6ADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001199 sval = va_arg(ap, char *);
1200 memcpy(p, sval, IN6ADDRSZ);
1201 p += IN6ADDRSZ;
1202 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001203
1204 case '4':
Simon Kelley0549c732017-09-25 18:17:11 +01001205 CHECK_LIMIT(INADDRSZ);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001206 sval = va_arg(ap, char *);
1207 memcpy(p, sval, INADDRSZ);
1208 p += INADDRSZ;
1209 break;
1210
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001211 case 'b':
Simon Kelley0549c732017-09-25 18:17:11 +01001212 CHECK_LIMIT(1);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001213 usval = va_arg(ap, int);
1214 *p++ = usval;
1215 break;
1216
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001217 case 's':
Simon Kelley0549c732017-09-25 18:17:11 +01001218 CHECK_LIMIT(2);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001219 usval = va_arg(ap, int);
1220 PUTSHORT(usval, p);
1221 break;
1222
1223 case 'l':
Simon Kelley0549c732017-09-25 18:17:11 +01001224 CHECK_LIMIT(4);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001225 lval = va_arg(ap, long);
1226 PUTLONG(lval, p);
1227 break;
1228
1229 case 'd':
Simon Kelley0549c732017-09-25 18:17:11 +01001230 /* get domain-name answer arg and store it in RDATA field */
1231 if (offset)
1232 *offset = p - (unsigned char *)header;
Simon Kelleyc3667172017-10-13 23:26:29 +01001233 if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
1234 goto truncated;
1235 CHECK_LIMIT(1);
Simon Kelley0549c732017-09-25 18:17:11 +01001236 *p++ = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001237 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001238
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001239 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001240 usval = va_arg(ap, int);
Simon Kelley0549c732017-09-25 18:17:11 +01001241 CHECK_LIMIT(usval);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001242 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001243 if (usval != 0)
1244 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001245 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001246 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001247
1248 case 'z':
1249 sval = va_arg(ap, char *);
1250 usval = sval ? strlen(sval) : 0;
1251 if (usval > 255)
1252 usval = 255;
Simon Kelley0549c732017-09-25 18:17:11 +01001253 CHECK_LIMIT(usval + 1);
Simon Kelley1a6bca82008-07-11 11:11:42 +01001254 *p++ = (unsigned char)usval;
1255 memcpy(p, sval, usval);
1256 p += usval;
1257 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001258 }
1259
1260 va_end(ap); /* clean up variable argument pointer */
1261
Simon Kelleyc3667172017-10-13 23:26:29 +01001262 /* Now, store real RDLength. sav already checked against limit. */
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001263 j = p - sav - 2;
Simon Kelleyc3667172017-10-13 23:26:29 +01001264 PUTSHORT(j, sav);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001265
1266 *pp = p;
1267 return 1;
Simon Kelleyc3667172017-10-13 23:26:29 +01001268
1269 truncated:
1270 va_end(ap);
1271 if (truncp)
1272 *truncp = 1;
1273 return 0;
1274
1275#undef CHECK_LIMIT
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001276}
1277
Simon Kelley9009d742008-11-14 20:04:27 +00001278static unsigned long crec_ttl(struct crec *crecp, time_t now)
1279{
1280 /* Return 0 ttl for DHCP entries, which might change
Simon Kelley7480aef2016-02-26 21:58:20 +00001281 before the lease expires, unless configured otherwise. */
Simon Kelley9009d742008-11-14 20:04:27 +00001282
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001283 if (crecp->flags & F_DHCP)
Simon Kelley7480aef2016-02-26 21:58:20 +00001284 {
1285 int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
1286
1287 /* Apply ceiling of actual lease length to configured TTL. */
1288 if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
1289 return crecp->ttd - now;
1290
1291 return conf_ttl;
1292 }
Simon Kelley9009d742008-11-14 20:04:27 +00001293
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001294 /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
1295 if (crecp->flags & F_IMMORTAL)
1296 return crecp->ttd;
1297
klemens43517fc2017-02-19 15:53:37 +00001298 /* Return the Max TTL value if it is lower than the actual TTL */
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001299 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1300 return crecp->ttd - now;
1301 else
1302 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001303}
1304
1305
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001306/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001307size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001308 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001309 time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001310{
Simon Kelley3be34542004-09-11 19:12:13 +01001311 char *name = daemon->namebuff;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001312 unsigned char *p, *ansp;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001313 unsigned int qtype, qclass;
Simon Kelleycc921df2019-01-02 22:48:59 +00001314 union all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001315 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001316 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001317 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001318 int dryrun = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001319 struct crec *crecp;
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001320 int nxdomain = 0, notimp = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001321 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001322 size_t len;
Simon Kelleyfa785732016-07-22 20:56:01 +01001323
Simon Kelley41392982018-09-19 22:27:11 +01001324 /* never answer queries with RD unset, to avoid cache snooping. */
1325 if (!(header->hb3 & HB3_RD) ||
1326 ntohs(header->ancount) != 0 ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001327 ntohs(header->nscount) != 0 ||
1328 ntohs(header->qdcount) == 0 ||
1329 OPCODE(header) != QUERY )
1330 return 0;
Simon Kelley087eb762017-10-30 23:16:54 +00001331
Simon Kelleye243c072014-02-06 18:14:09 +00001332 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001333 if (header->hb4 & HB4_CD)
1334 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001335
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001336 /* If there is an additional data section then it will be overwritten by
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001337 partial replies, so we have to do a dry run to see if we can answer
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001338 the query. */
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001339 if (ntohs(header->arcount) != 0)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001340 dryrun = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001341
Simon Kelley0a852542005-03-23 20:28:59 +00001342 for (rec = daemon->mxnames; rec; rec = rec->next)
1343 rec->offset = 0;
1344
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001345 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001346 /* determine end of question section (we put answers there) */
1347 if (!(ansp = skip_questions(header, qlen)))
1348 return 0; /* bad packet */
1349
1350 /* now process each question, answers go in RRs after the question */
1351 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001352
Simon Kelley5aabfc72007-08-29 11:24:47 +01001353 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001354 {
1355 /* save pointer to name for copying into answers */
1356 nameoffset = p - (unsigned char *)header;
1357
1358 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001359 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001360 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001361
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001362 GETSHORT(qtype, p);
1363 GETSHORT(qclass, p);
1364
1365 ans = 0; /* have we answered this question */
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001366
1367 while ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)))
1368 {
1369 char *cname_target = cache_get_cname_target(crecp);
1370
1371 /* If the client asked for DNSSEC don't use cached data. */
1372 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
1373 !do_bit ||
1374 (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
1375
1376 {
1377 if (crecp->flags & F_CONFIG || qtype == T_CNAME)
1378 ans = 1;
1379
1380 if (!(crecp->flags & F_DNSSECOK))
1381 sec_data = 0;
1382
1383 if (!dryrun)
1384 {
1385 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1386 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1387 crec_ttl(crecp, now), &nameoffset,
1388 T_CNAME, C_IN, "d", cname_target))
1389 anscount++;
1390 }
1391
1392 strcpy(name, cname_target);
1393 }
1394 }
1395
Simon Kelley0a852542005-03-23 20:28:59 +00001396 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001397 {
Simon Kelley0a852542005-03-23 20:28:59 +00001398 struct txt_record *t;
1399 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001400 {
Simon Kelley0a852542005-03-23 20:28:59 +00001401 if (t->class == qclass && hostname_isequal(name, t->name))
1402 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001403 ans = 1, sec_data = 0;
Simon Kelleye17fb622006-01-14 20:33:46 +00001404 if (!dryrun)
1405 {
Simon Kelleyfec216d2014-03-27 20:54:34 +00001406 unsigned long ttl = daemon->local_ttl;
1407 int ok = 1;
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001408#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001409 /* Dynamically generate stat record */
1410 if (t->stat != 0)
1411 {
1412 ttl = 0;
1413 if (!cache_make_stat(t))
1414 ok = 0;
1415 }
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001416#endif
Simon Kelleycbb5b172018-10-23 23:45:57 +01001417 if (ok)
1418 {
1419 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
1420 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1421 ttl, NULL,
1422 T_TXT, t->class, "t", t->len, t->txt))
1423 anscount++;
1424 }
Simon Kelleye17fb622006-01-14 20:33:46 +00001425 }
Simon Kelley0a852542005-03-23 20:28:59 +00001426 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001427 }
Simon Kelley0a852542005-03-23 20:28:59 +00001428 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001429
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001430 if (qclass == C_CHAOS)
1431 {
Simon Kelleycbb5b172018-10-23 23:45:57 +01001432 /* don't forward *.bind and *.server chaos queries - always reply with NOTIMP */
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001433 if (hostname_issubdomain("bind", name) || hostname_issubdomain("server", name))
1434 {
1435 if (!ans)
Simon Kelleycbb5b172018-10-23 23:45:57 +01001436 {
1437 notimp = 1, auth = 0;
1438 if (!dryrun)
1439 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001440 addr.log.rcode = NOTIMP;
Simon Kelleycbb5b172018-10-23 23:45:57 +01001441 log_query(F_CONFIG | F_RCODE, name, &addr, NULL);
1442 }
Simon Kelley6f7812d2018-10-23 23:54:44 +01001443 ans = 1, sec_data = 0;
Simon Kelleycbb5b172018-10-23 23:45:57 +01001444 }
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001445 }
1446 }
1447
Simon Kelley0a852542005-03-23 20:28:59 +00001448 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001449 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001450 struct txt_record *t;
1451
1452 for (t = daemon->rr; t; t = t->next)
1453 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1454 {
1455 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001456 sec_data = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001457 if (!dryrun)
1458 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001459 log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, t->class));
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001460 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1461 daemon->local_ttl, NULL,
1462 t->class, C_IN, "t", t->len, t->txt))
Simon Kelley97f876b2018-08-21 22:06:36 +01001463 anscount++;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001464 }
1465 }
1466
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001467 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001468 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001469 /* see if it's w.z.y.z.in-addr.arpa format */
1470 int is_arpa = in_arpa_name_2_addr(name, &addr);
1471 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001472 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001473
1474 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1475 if (hostname_isequal(name, ptr->name))
1476 break;
1477
Simon Kelleyf2621c72007-04-29 19:47:21 +01001478 if (is_arpa == F_IPV4)
1479 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001480 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001481 struct addrlist *addrlist;
1482
Simon Kelley376d48c2013-11-13 13:04:30 +00001483 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00001484 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001485 break;
1486
1487 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001488 break;
1489 else
1490 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1491 intr = intr->next;
1492 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001493 else if (is_arpa == F_IPV6)
1494 for (intr = daemon->int_names; intr; intr = intr->next)
1495 {
1496 struct addrlist *addrlist;
1497
Simon Kelley376d48c2013-11-13 13:04:30 +00001498 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00001499 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001500 break;
1501
1502 if (addrlist)
1503 break;
1504 else
1505 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1506 intr = intr->next;
1507 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001508
1509 if (intr)
1510 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001511 sec_data = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001512 ans = 1;
1513 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001514 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001515 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001516 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1517 daemon->local_ttl, NULL,
1518 T_PTR, C_IN, "d", intr->name))
1519 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001520 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001521 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001522 else if (ptr)
1523 {
1524 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001525 sec_data = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001526 if (!dryrun)
1527 {
Simon Kelley28866e92011-02-14 20:19:14 +00001528 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001529 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001530 if (hostname_isequal(name, ptr->name) &&
1531 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1532 daemon->local_ttl, NULL,
1533 T_PTR, C_IN, "d", ptr->ptr))
1534 anscount++;
1535
Simon Kelley832af0b2007-01-21 20:01:28 +00001536 }
1537 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001538 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001539 {
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001540 /* Don't use cache when DNSSEC data required, unless we know that
1541 the zone is unsigned, which implies that we're doing
1542 validation. */
1543 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001544 !do_bit ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001545 (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001546 {
1547 do
1548 {
1549 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1550 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1551 continue;
1552
1553 if (!(crecp->flags & F_DNSSECOK))
1554 sec_data = 0;
Simon Kelley93be5b12015-12-15 12:04:40 +00001555
1556 ans = 1;
1557
Simon Kelley2d33bda2014-01-24 22:37:25 +00001558 if (crecp->flags & F_NEG)
1559 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001560 auth = 0;
1561 if (crecp->flags & F_NXDOMAIN)
1562 nxdomain = 1;
1563 if (!dryrun)
1564 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1565 }
Simon Kelley93be5b12015-12-15 12:04:40 +00001566 else
Simon Kelley2d33bda2014-01-24 22:37:25 +00001567 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001568 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1569 auth = 0;
1570 if (!dryrun)
1571 {
1572 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1573 record_source(crecp->uid));
1574
1575 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1576 crec_ttl(crecp, now), NULL,
1577 T_PTR, C_IN, "d", cache_get_name(crecp)))
1578 anscount++;
1579 }
1580 }
1581 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1582 }
1583 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001584 else if (is_rev_synth(is_arpa, &addr, name))
1585 {
1586 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001587 sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001588 if (!dryrun)
1589 {
1590 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1591
1592 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1593 daemon->local_ttl, NULL,
1594 T_PTR, C_IN, "d", name))
1595 anscount++;
1596 }
1597 }
Simon Kelleyfca008d2017-02-19 18:50:41 +00001598 else if (option_bool(OPT_BOGUSPRIV) && (
Simon Kelleycc921df2019-01-02 22:48:59 +00001599 (is_arpa == F_IPV6 && private_net6(&addr.addr6)) ||
1600 (is_arpa == F_IPV4 && private_net(addr.addr4, 1))))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001601 {
Vladislav Grishenko5a7212c2017-04-24 22:19:57 +01001602 struct server *serv;
1603 unsigned int namelen = strlen(name);
1604 char *nameend = name + namelen;
1605
1606 /* see if have rev-server set */
1607 for (serv = daemon->servers; serv; serv = serv->next)
1608 {
1609 unsigned int domainlen;
1610 char *matchstart;
1611
1612 if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
1613 continue;
1614
1615 domainlen = strlen(serv->domain);
1616 if (domainlen == 0 || domainlen > namelen)
1617 continue;
1618
1619 matchstart = nameend - domainlen;
1620 if (hostname_isequal(matchstart, serv->domain) &&
1621 (namelen == domainlen || *(matchstart-1) == '.' ))
1622 break;
1623 }
1624
1625 /* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
1626 if (!serv)
1627 {
1628 ans = 1;
1629 sec_data = 0;
1630 nxdomain = 1;
1631 if (!dryrun)
1632 log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
1633 name, &addr, NULL);
1634 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001635 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001636 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001637
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001638 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1639 {
Simon Kelleyee875042018-10-23 22:10:17 +01001640 unsigned short type = (flag == F_IPV6) ? T_AAAA : T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001641 struct interface_name *intr;
1642
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001643 if (qtype != type && qtype != T_ANY)
1644 continue;
1645
Simon Kelleyf2621c72007-04-29 19:47:21 +01001646 /* interface name stuff */
Simon Kelley115ac3e2013-05-20 11:28:32 +01001647 for (intr = daemon->int_names; intr; intr = intr->next)
1648 if (hostname_isequal(name, intr->name))
1649 break;
1650
1651 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001652 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001653 struct addrlist *addrlist;
Simon Kelleyd42d4702017-02-02 16:52:06 +00001654 int gotit = 0, localise = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001655
Simon Kelley115ac3e2013-05-20 11:28:32 +01001656 enumerate_interfaces(0);
Simon Kelleyd42d4702017-02-02 16:52:06 +00001657
klemens43517fc2017-02-19 15:53:37 +00001658 /* See if a putative address is on the network from which we received
Simon Kelleyd42d4702017-02-02 16:52:06 +00001659 the query, is so we'll filter other answers. */
1660 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && type == T_A)
1661 for (intr = daemon->int_names; intr; intr = intr->next)
1662 if (hostname_isequal(name, intr->name))
1663 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelleyee875042018-10-23 22:10:17 +01001664 if (!(addrlist->flags & ADDRLIST_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001665 is_same_net(addrlist->addr.addr4, local_addr, local_netmask))
Simon Kelleyee875042018-10-23 22:10:17 +01001666 {
1667 localise = 1;
1668 break;
1669 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001670
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001671 for (intr = daemon->int_names; intr; intr = intr->next)
1672 if (hostname_isequal(name, intr->name))
1673 {
Simon Kelley47669362014-12-17 12:41:56 +00001674 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley47669362014-12-17 12:41:56 +00001675 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
Simon Kelley47669362014-12-17 12:41:56 +00001676 {
Simon Kelleyd42d4702017-02-02 16:52:06 +00001677 if (localise &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001678 !is_same_net(addrlist->addr.addr4, local_addr, local_netmask))
Simon Kelleyd42d4702017-02-02 16:52:06 +00001679 continue;
1680
Simon Kelley47669362014-12-17 12:41:56 +00001681 if (addrlist->flags & ADDRLIST_REVONLY)
1682 continue;
Simon Kelleyee875042018-10-23 22:10:17 +01001683
Simon Kelley47669362014-12-17 12:41:56 +00001684 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001685 sec_data = 0;
Simon Kelley47669362014-12-17 12:41:56 +00001686 if (!dryrun)
Simon Kelley376d48c2013-11-13 13:04:30 +00001687 {
1688 gotit = 1;
1689 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1690 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1691 daemon->local_ttl, NULL, type, C_IN,
1692 type == T_A ? "4" : "6", &addrlist->addr))
1693 anscount++;
1694 }
Simon Kelley47669362014-12-17 12:41:56 +00001695 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001696 }
1697
1698 if (!dryrun && !gotit)
1699 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1700
Simon Kelley115ac3e2013-05-20 11:28:32 +01001701 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001702 }
1703
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001704 if ((crecp = cache_find_by_name(NULL, name, now, flag | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001705 {
1706 int localise = 0;
1707
Josh Soref730c6742017-02-06 16:14:04 +00001708 /* See if a putative address is on the network from which we received
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001709 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001710 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001711 {
1712 struct crec *save = crecp;
1713 do {
1714 if ((crecp->flags & F_HOSTS) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001715 is_same_net(crecp->addr.addr4, local_addr, local_netmask))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001716 {
1717 localise = 1;
1718 break;
1719 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001720 } while ((crecp = cache_find_by_name(crecp, name, now, flag)));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001721 crecp = save;
1722 }
Simon Kelley824202e2014-01-23 20:59:46 +00001723
Simon Kelley93be5b12015-12-15 12:04:40 +00001724 /* If the client asked for DNSSEC don't use cached data. */
Simon Kelleya997ca02018-06-29 14:39:41 +01001725 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
1726 !do_bit ||
1727 (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
Simon Kelley824202e2014-01-23 20:59:46 +00001728 do
1729 {
1730 /* don't answer wildcard queries with data not from /etc/hosts
1731 or DHCP leases */
1732 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1733 break;
1734
1735 if (!(crecp->flags & F_DNSSECOK))
1736 sec_data = 0;
1737
Simon Kelley824202e2014-01-23 20:59:46 +00001738 if (crecp->flags & F_NEG)
1739 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001740 ans = 1;
1741 auth = 0;
1742 if (crecp->flags & F_NXDOMAIN)
1743 nxdomain = 1;
1744 if (!dryrun)
1745 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley824202e2014-01-23 20:59:46 +00001746 }
1747 else
1748 {
1749 /* If we are returning local answers depending on network,
1750 filter here. */
1751 if (localise &&
1752 (crecp->flags & F_HOSTS) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001753 !is_same_net(crecp->addr.addr4, local_addr, local_netmask))
Simon Kelley824202e2014-01-23 20:59:46 +00001754 continue;
1755
1756 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1757 auth = 0;
1758
1759 ans = 1;
1760 if (!dryrun)
1761 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001762 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr,
Simon Kelley824202e2014-01-23 20:59:46 +00001763 record_source(crecp->uid));
1764
1765 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1766 crec_ttl(crecp, now), NULL, type, C_IN,
1767 type == T_A ? "4" : "6", &crecp->addr))
1768 anscount++;
1769 }
1770 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001771 } while ((crecp = cache_find_by_name(crecp, name, now, flag)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001772 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001773 else if (is_name_synthetic(flag, name, &addr))
1774 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001775 ans = 1, sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001776 if (!dryrun)
1777 {
1778 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
1779 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1780 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
1781 anscount++;
1782 }
1783 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001784 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001785
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001786 if (qtype == T_MX || qtype == T_ANY)
1787 {
1788 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001789 for (rec = daemon->mxnames; rec; rec = rec->next)
1790 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001791 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001792 ans = found = 1;
1793 sec_data = 0;
1794 if (!dryrun)
1795 {
1796 int offset;
1797 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
1798 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1799 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1800 {
1801 anscount++;
1802 if (rec->target)
1803 rec->offset = offset;
1804 }
1805 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001806 }
1807
Simon Kelley28866e92011-02-14 20:19:14 +00001808 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00001809 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001810 {
1811 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001812 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001813 if (!dryrun)
1814 {
Simon Kelley28866e92011-02-14 20:19:14 +00001815 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001816 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1817 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00001818 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001819 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001820 }
1821 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001822 }
1823
1824 if (qtype == T_SRV || qtype == T_ANY)
1825 {
1826 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001827 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
1828
Simon Kelley0a852542005-03-23 20:28:59 +00001829 for (rec = daemon->mxnames; rec; rec = rec->next)
1830 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001831 {
1832 found = ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001833 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001834 if (!dryrun)
1835 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001836 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001837 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001838 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001839 &offset, T_SRV, C_IN, "sssd",
1840 rec->priority, rec->weight, rec->srvport, rec->target))
1841 {
1842 anscount++;
1843 if (rec->target)
1844 rec->offset = offset;
1845 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001846 }
Simon Kelley28866e92011-02-14 20:19:14 +00001847
1848 /* unlink first SRV record found */
1849 if (!move)
1850 {
1851 move = rec;
1852 *up = rec->next;
1853 }
1854 else
1855 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001856 }
Simon Kelley28866e92011-02-14 20:19:14 +00001857 else
1858 up = &rec->next;
1859
1860 /* put first SRV record back at the end. */
1861 if (move)
1862 {
1863 *up = move;
1864 move->next = NULL;
1865 }
Simon Kelley5b99eae2019-01-06 23:09:50 +00001866
1867 if (!found)
1868 {
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001869 if ((crecp = cache_find_by_name(NULL, name, now, F_SRV | (dryrun ? F_NO_RR : 0))) &&
Simon Kelley5b99eae2019-01-06 23:09:50 +00001870 (!do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
1871 {
1872 if (!(crecp->flags & F_DNSSECOK))
1873 sec_data = 0;
1874
1875 auth = 0;
1876 found = ans = 1;
1877
1878 do {
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001879 if (crecp->flags & F_NEG)
Simon Kelley5b99eae2019-01-06 23:09:50 +00001880 {
1881 if (crecp->flags & F_NXDOMAIN)
1882 nxdomain = 1;
1883 if (!dryrun)
1884 log_query(crecp->flags, name, NULL, NULL);
1885 }
Simon Kelley122997d2019-10-25 17:23:56 +01001886 else if (!dryrun)
Simon Kelley5b99eae2019-01-06 23:09:50 +00001887 {
Simon Kelley122997d2019-10-25 17:23:56 +01001888 char *target = blockdata_retrieve(crecp->addr.srv.target, crecp->addr.srv.targetlen, NULL);
1889 log_query(crecp->flags, name, NULL, 0);
Simon Kelley5b99eae2019-01-06 23:09:50 +00001890
Simon Kelley122997d2019-10-25 17:23:56 +01001891 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1892 crec_ttl(crecp, now), NULL, T_SRV, C_IN, "sssd",
1893 crecp->addr.srv.priority, crecp->addr.srv.weight, crecp->addr.srv.srvport,
1894 target))
1895 anscount++;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001896 }
Simon Kelleyb59a5c22019-10-25 16:13:38 +01001897 } while ((crecp = cache_find_by_name(crecp, name, now, F_SRV)));
Simon Kelley5b99eae2019-01-06 23:09:50 +00001898 }
1899 }
1900
Simon Kelley28866e92011-02-14 20:19:14 +00001901 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001902 {
1903 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001904 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001905 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001906 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001907 }
1908 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001909
1910 if (qtype == T_NAPTR || qtype == T_ANY)
1911 {
1912 struct naptr *na;
1913 for (na = daemon->naptr; na; na = na->next)
1914 if (hostname_isequal(name, na->name))
1915 {
1916 ans = 1;
Simon Kelley6f7812d2018-10-23 23:54:44 +01001917 sec_data = 0;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001918 if (!dryrun)
1919 {
Simon Kelley28866e92011-02-14 20:19:14 +00001920 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001921 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1922 NULL, T_NAPTR, C_IN, "sszzzd",
1923 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1924 anscount++;
1925 }
1926 }
1927 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001928
1929 if (qtype == T_MAILB)
Simon Kelley6f7812d2018-10-23 23:54:44 +01001930 ans = 1, nxdomain = 1, sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001931
Simon Kelley28866e92011-02-14 20:19:14 +00001932 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001933 {
Simon Kelley6f7812d2018-10-23 23:54:44 +01001934 ans = 1;
1935 sec_data = 0;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001936 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001937 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001938 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001939 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001940
1941 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001942 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001943 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001944
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001945 if (dryrun)
1946 {
1947 dryrun = 0;
1948 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001949 }
1950
Simon Kelley0a852542005-03-23 20:28:59 +00001951 /* create an additional data section, for stuff in SRV and MX record replies. */
1952 for (rec = daemon->mxnames; rec; rec = rec->next)
1953 if (rec->offset != 0)
1954 {
1955 /* squash dupes */
1956 struct mx_srv_record *tmp;
1957 for (tmp = rec->next; tmp; tmp = tmp->next)
1958 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1959 tmp->offset = 0;
1960
1961 crecp = NULL;
1962 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1963 {
Simon Kelley0a852542005-03-23 20:28:59 +00001964 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
Simon Kelleyee875042018-10-23 22:10:17 +01001965
Simon Kelley0a852542005-03-23 20:28:59 +00001966 if (crecp->flags & F_NEG)
1967 continue;
1968
Simon Kelley9009d742008-11-14 20:04:27 +00001969 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
1970 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00001971 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1972 addncount++;
1973 }
1974 }
1975
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001976 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00001977 /* clear authoritative and truncated flags, set QR flag */
1978 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1979 /* set RA flag */
1980 header->hb4 |= HB4_RA;
1981
Josh Soref730c6742017-02-06 16:14:04 +00001982 /* authoritative - only hosts and DHCP derived names. */
Simon Kelley572b41e2011-02-18 18:11:18 +00001983 if (auth)
1984 header->hb3 |= HB3_AA;
1985
1986 /* truncation */
1987 if (trunc)
1988 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001989
Simon Kelley45cca582013-10-15 10:20:13 +01001990 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00001991 SET_RCODE(header, NXDOMAIN);
Vladislav Grishenkocf598432018-10-18 04:55:21 +05001992 else if (notimp)
1993 SET_RCODE(header, NOTIMP);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001994 else
Simon Kelley572b41e2011-02-18 18:11:18 +00001995 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001996 header->ancount = htons(anscount);
1997 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00001998 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00001999
Simon Kelleya25720a2014-01-14 23:13:55 +00002000 len = ansp - (unsigned char *)header;
2001
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002002 /* Advertise our packet size limit in our reply */
Simon Kelleya25720a2014-01-14 23:13:55 +00002003 if (have_pseudoheader)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00002004 len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
Simon Kelleye243c072014-02-06 18:14:09 +00002005
Simon Kelleyfa14bec2015-12-20 17:12:16 +00002006 if (ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00002007 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00002008 else
2009 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00002010
Simon Kelley7c286122014-01-27 21:38:11 +00002011 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002012}