blob: 24d08c15476fec6be7f0ddda584fa91d58f6e49b [file] [log] [blame]
Simon Kelleyc49778d2016-01-06 18:52:33 +00001/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
17#include "dnsmasq.h"
18
Simon Kelley4f7b3042012-11-28 21:27:02 +000019int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
20 char *name, int isExtract, int extrabytes)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000021{
Simon Kelley3d8df262005-08-29 12:19:27 +010022 unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
Simon Kelleyb8f16552015-04-22 21:14:31 +010023 unsigned int j, l, namelen = 0, hops = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000024 int retvalue = 1;
25
Simon Kelleyf6b7dc42005-01-23 12:06:08 +000026 if (isExtract)
27 *cp = 0;
28
Simon Kelley9009d742008-11-14 20:04:27 +000029 while (1)
30 {
31 unsigned int label_type;
32
33 if (!CHECK_LEN(header, p, plen, 1))
34 return 0;
35
36 if ((l = *p++) == 0)
37 /* end marker */
38 {
39 /* check that there are the correct no of bytes after the name */
40 if (!CHECK_LEN(header, p, plen, extrabytes))
41 return 0;
42
43 if (isExtract)
44 {
45 if (cp != (unsigned char *)name)
46 cp--;
47 *cp = 0; /* terminate: lose final period */
48 }
49 else if (*cp != 0)
50 retvalue = 2;
51
52 if (p1) /* we jumped via compression */
53 *pp = p1;
54 else
55 *pp = p;
56
57 return retvalue;
58 }
59
60 label_type = l & 0xc0;
61
Simon Kelley9e4abcb2004-01-22 19:47:41 +000062 if (label_type == 0xc0) /* pointer */
63 {
Simon Kelley9009d742008-11-14 20:04:27 +000064 if (!CHECK_LEN(header, p, plen, 1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000065 return 0;
66
67 /* get offset */
68 l = (l&0x3f) << 8;
69 l |= *p++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000070
71 if (!p1) /* first jump, save location to go back to */
72 p1 = p;
73
74 hops++; /* break malicious infinite loops */
75 if (hops > 255)
76 return 0;
77
78 p = l + (unsigned char *)header;
79 }
Simon Kelley06568c62015-05-15 20:43:48 +010080 else if (label_type == 0x00)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000081 { /* label_type = 0 -> label. */
Simon Kelley5d07d772015-05-15 18:13:06 +010082 namelen += l + 1; /* include period */
83 if (namelen >= MAXDNAME)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +000085 if (!CHECK_LEN(header, p, plen, l))
Simon Kelley9e4abcb2004-01-22 19:47:41 +000086 return 0;
Simon Kelley9009d742008-11-14 20:04:27 +000087
Simon Kelley9e4abcb2004-01-22 19:47:41 +000088 for(j=0; j<l; j++, p++)
89 if (isExtract)
90 {
Simon Kelley1f15b812009-10-13 17:49:32 +010091 unsigned char c = *p;
Simon Kelleycbe379a2015-04-21 22:57:06 +010092#ifdef HAVE_DNSSEC
93 if (option_bool(OPT_DNSSEC_VALID))
94 {
95 if (c == 0 || c == '.' || c == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +010096 {
97 *cp++ = NAME_ESCAPE;
98 *cp++ = c+1;
99 }
100 else
101 *cp++ = c;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100102 }
103 else
104#endif
Simon Kelley394ff492015-03-29 22:17:14 +0100105 if (c != 0 && c != '.')
106 *cp++ = c;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000107 else
108 return 0;
109 }
110 else
111 {
112 unsigned char c1 = *cp, c2 = *p;
113
114 if (c1 == 0)
115 retvalue = 2;
116 else
117 {
118 cp++;
119 if (c1 >= 'A' && c1 <= 'Z')
120 c1 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100121#ifdef HAVE_DNSSEC
122 if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
Simon Kelleyb8f16552015-04-22 21:14:31 +0100123 c1 = (*cp++)-1;
Simon Kelleycbe379a2015-04-21 22:57:06 +0100124#endif
125
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000126 if (c2 >= 'A' && c2 <= 'Z')
127 c2 += 'a' - 'A';
Simon Kelleycbe379a2015-04-21 22:57:06 +0100128
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000129 if (c1 != c2)
130 retvalue = 2;
131 }
132 }
Simon Kelley06568c62015-05-15 20:43:48 +0100133
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000134 if (isExtract)
135 *cp++ = '.';
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000136 else if (*cp != 0 && *cp++ != '.')
137 retvalue = 2;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000138 }
Simon Kelley06568c62015-05-15 20:43:48 +0100139 else
140 return 0; /* label types 0x40 and 0x80 not supported */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000141 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000142}
143
144/* Max size of input string (for IPv6) is 75 chars.) */
145#define MAXARPANAME 75
Simon Kelley4f7b3042012-11-28 21:27:02 +0000146int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000147{
148 int j;
149 char name[MAXARPANAME+1], *cp1;
150 unsigned char *addr = (unsigned char *)addrp;
151 char *lastchunk = NULL, *penchunk = NULL;
152
153 if (strlen(namein) > MAXARPANAME)
154 return 0;
155
156 memset(addrp, 0, sizeof(struct all_addr));
157
158 /* turn name into a series of asciiz strings */
159 /* j counts no of labels */
160 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 */
179 /* address arives as a name of the form
180 www.xxx.yyy.zzz.in-addr.arpa
181 some of the low order address octets might be missing
182 and should be set to zero. */
183 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
184 {
185 /* check for digits only (weeds out things like
186 50.0/24.67.28.64.in-addr.arpa which are used
187 as CNAME targets according to RFC 2317 */
188 char *cp;
189 for (cp = cp1; *cp; cp++)
Simon Kelley572b41e2011-02-18 18:11:18 +0000190 if (!isdigit((unsigned char)*cp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000191 return 0;
192
193 addr[3] = addr[2];
194 addr[2] = addr[1];
195 addr[1] = addr[0];
196 addr[0] = atoi(cp1);
197 }
198
199 return F_IPV4;
200 }
201#ifdef HAVE_IPV6
202 else if (hostname_isequal(penchunk, "ip6") &&
203 (hostname_isequal(lastchunk, "int") || hostname_isequal(lastchunk, "arpa")))
204 {
205 /* IP v6:
206 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
207 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
208
209 Note that most of these the various reprentations are obsolete and
210 left-over from the many DNS-for-IPv6 wars. We support all the formats
211 that we can since there is no reason not to.
212 */
213
214 if (*name == '\\' && *(name+1) == '[' &&
215 (*(name+2) == 'x' || *(name+2) == 'X'))
216 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000217 for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000218 {
219 char xdig[2];
220 xdig[0] = *cp1;
221 xdig[1] = 0;
222 if (j%2)
223 addr[j/2] |= strtol(xdig, NULL, 16);
224 else
225 addr[j/2] = strtol(xdig, NULL, 16) << 4;
226 }
227
228 if (*cp1 == '/' && j == 32)
229 return F_IPV6;
230 }
231 else
232 {
233 for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
234 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000235 if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000236 return 0;
237
238 for (j = sizeof(struct all_addr)-1; j>0; j--)
239 addr[j] = (addr[j] >> 4) | (addr[j-1] << 4);
240 addr[0] = (addr[0] >> 4) | (strtol(cp1, NULL, 16) << 4);
241 }
242
243 return F_IPV6;
244 }
245 }
246#endif
247
248 return 0;
249}
250
Giovanni Bajo32f82c62012-04-28 01:01:16 +0200251unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100252{
253 while(1)
254 {
Simon Kelley9009d742008-11-14 20:04:27 +0000255 unsigned int label_type;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100256
Simon Kelley9009d742008-11-14 20:04:27 +0000257 if (!CHECK_LEN(header, ansp, plen, 1))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100258 return NULL;
259
Simon Kelley9009d742008-11-14 20:04:27 +0000260 label_type = (*ansp) & 0xc0;
261
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100262 if (label_type == 0xc0)
263 {
264 /* pointer for compression. */
265 ansp += 2;
266 break;
267 }
268 else if (label_type == 0x80)
269 return NULL; /* reserved */
270 else if (label_type == 0x40)
271 {
272 /* Extended label type */
273 unsigned int count;
274
Simon Kelley9009d742008-11-14 20:04:27 +0000275 if (!CHECK_LEN(header, ansp, plen, 2))
276 return NULL;
277
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100278 if (((*ansp++) & 0x3f) != 1)
279 return NULL; /* we only understand bitstrings */
280
281 count = *(ansp++); /* Bits in bitstring */
282
283 if (count == 0) /* count == 0 means 256 bits */
284 ansp += 32;
285 else
286 ansp += ((count-1)>>3)+1;
287 }
288 else
289 { /* label type == 0 Bottom six bits is length */
290 unsigned int len = (*ansp++) & 0x3f;
Simon Kelley9009d742008-11-14 20:04:27 +0000291
292 if (!ADD_RDLEN(header, ansp, plen, len))
293 return NULL;
294
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100295 if (len == 0)
296 break; /* zero length label marks the end. */
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100297 }
298 }
Simon Kelley9009d742008-11-14 20:04:27 +0000299
300 if (!CHECK_LEN(header, ansp, plen, extrabytes))
301 return NULL;
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100302
303 return ansp;
304}
305
Simon Kelley4f7b3042012-11-28 21:27:02 +0000306unsigned char *skip_questions(struct dns_header *header, size_t plen)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000307{
Simon Kelley5aabfc72007-08-29 11:24:47 +0100308 int q;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000309 unsigned char *ansp = (unsigned char *)(header+1);
310
Simon Kelley5aabfc72007-08-29 11:24:47 +0100311 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000312 {
Simon Kelley9009d742008-11-14 20:04:27 +0000313 if (!(ansp = skip_name(ansp, header, plen, 4)))
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100314 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000315 ansp += 4; /* class and type */
316 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000317
318 return ansp;
319}
320
Simon Kelley5107ace2014-02-23 10:48:32 +0000321unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100322{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100323 int i, rdlen;
Simon Kelley36717ee2004-09-20 19:20:58 +0100324
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100325 for (i = 0; i < count; i++)
Simon Kelley36717ee2004-09-20 19:20:58 +0100326 {
Simon Kelley9009d742008-11-14 20:04:27 +0000327 if (!(ansp = skip_name(ansp, header, plen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100328 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100329 ansp += 8; /* type, class, TTL */
330 GETSHORT(rdlen, ansp);
Simon Kelley9009d742008-11-14 20:04:27 +0000331 if (!ADD_RDLEN(header, ansp, plen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100332 return NULL;
Simon Kelley36717ee2004-09-20 19:20:58 +0100333 }
334
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100335 return ansp;
336}
337
Simon Kelley0a852542005-03-23 20:28:59 +0000338/* CRC the question section. This is used to safely detect query
339 retransmision and to detect answers to questions we didn't ask, which
340 might be poisoning attacks. Note that we decode the name rather
341 than CRC the raw bytes, since replies might be compressed differently.
Simon Kelley832af0b2007-01-21 20:01:28 +0000342 We ignore case in the names for the same reason. Return all-ones
343 if there is not question section. */
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000344#ifndef HAVE_DNSSEC
Simon Kelley572b41e2011-02-18 18:11:18 +0000345unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100346{
Simon Kelley91dccd02005-03-31 17:48:32 +0100347 int q;
348 unsigned int crc = 0xffffffff;
Simon Kelley0a852542005-03-23 20:28:59 +0000349 unsigned char *p1, *p = (unsigned char *)(header+1);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100350
Simon Kelley5aabfc72007-08-29 11:24:47 +0100351 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley0a852542005-03-23 20:28:59 +0000352 {
Simon Kelley9009d742008-11-14 20:04:27 +0000353 if (!extract_name(header, plen, &p, name, 1, 4))
Simon Kelley0a852542005-03-23 20:28:59 +0000354 return crc; /* bad packet */
355
Simon Kelley3d8df262005-08-29 12:19:27 +0100356 for (p1 = (unsigned char *)name; *p1; p1++)
Simon Kelley0a852542005-03-23 20:28:59 +0000357 {
358 int i = 8;
359 char c = *p1;
360
361 if (c >= 'A' && c <= 'Z')
362 c += 'a' - 'A';
363
364 crc ^= c << 24;
365 while (i--)
366 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
367 }
368
369 /* CRC the class and type as well */
370 for (p1 = p; p1 < p+4; p1++)
371 {
372 int i = 8;
373 crc ^= *p1 << 24;
374 while (i--)
375 crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
376 }
377
378 p += 4;
Simon Kelley9009d742008-11-14 20:04:27 +0000379 if (!CHECK_LEN(header, p, plen, 0))
Simon Kelley0a852542005-03-23 20:28:59 +0000380 return crc; /* bad packet */
381 }
382
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100383 return crc;
384}
Simon Kelley17fb9ea2014-01-26 09:36:54 +0000385#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100386
Simon Kelley572b41e2011-02-18 18:11:18 +0000387size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100388{
389 unsigned char *ansp = skip_questions(header, plen);
390
Simon Kelley9009d742008-11-14 20:04:27 +0000391 /* if packet is malformed, just return as-is. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100392 if (!ansp)
Simon Kelley9009d742008-11-14 20:04:27 +0000393 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100394
395 if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
396 header, plen)))
Simon Kelley9009d742008-11-14 20:04:27 +0000397 return plen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100398
Simon Kelley36717ee2004-09-20 19:20:58 +0100399 /* restore pseudoheader */
400 if (pheader && ntohs(header->arcount) == 0)
401 {
402 /* must use memmove, may overlap */
403 memmove(ansp, pheader, hlen);
404 header->arcount = htons(1);
405 ansp += hlen;
406 }
407
408 return ansp - (unsigned char *)header;
409}
410
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000411/* is addr in the non-globally-routed IP space? */
Simon Kelleydc27e142013-10-16 13:09:53 +0100412int private_net(struct in_addr addr, int ban_localhost)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000413{
Simon Kelleyf2621c72007-04-29 19:47:21 +0100414 in_addr_t ip_addr = ntohl(addr.s_addr);
415
416 return
Simon Kelleyd2aa7df2015-08-03 21:52:12 +0100417 (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
418 ((ip_addr & 0xFF000000) == 0x00000000) /* RFC 5735 section 3. "here" network */ ||
Simon Kelleyf2621c72007-04-29 19:47:21 +0100419 ((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
420 ((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
Simon Kelley90477fb2015-10-20 21:21:32 +0100421 ((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
422 ((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
423 ((ip_addr & 0xFFFFFF00) == 0xC0000200) /* 192.0.2.0/24 (test-net) */ ||
424 ((ip_addr & 0xFFFFFF00) == 0xC6336400) /* 198.51.100.0/24(test-net) */ ||
425 ((ip_addr & 0xFFFFFF00) == 0xCB007100) /* 203.0.113.0/24 (test-net) */ ||
426 ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF) /* 255.255.255.255/32 (broadcast)*/ ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000427}
Simon Kelley1cff1662004-03-12 08:12:58 +0000428
Simon Kelley6938f342014-01-26 22:47:39 +0000429static 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 +0000430{
431 int i, qtype, qclass, rdlen;
Simon Kelley824af852008-02-12 20:43:05 +0000432
433 for (i = count; i != 0; i--)
434 {
Simon Kelley28866e92011-02-14 20:19:14 +0000435 if (name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100436 {
437 if (!extract_name(header, qlen, &p, name, 1, 10))
438 return 0;
439 }
440 else if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000441 return 0; /* bad packet */
442
443 GETSHORT(qtype, p);
444 GETSHORT(qclass, p);
Simon Kelley7de060b2011-08-26 17:24:52 +0100445 p += 4; /* ttl */
Simon Kelley824af852008-02-12 20:43:05 +0000446 GETSHORT(rdlen, p);
447
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100448 if (qclass == C_IN && qtype == T_A)
Simon Kelley824af852008-02-12 20:43:05 +0000449 {
450 struct doctor *doctor;
451 struct in_addr addr;
452
Simon Kelley9009d742008-11-14 20:04:27 +0000453 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
454 return 0;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100455
456 /* alignment */
Simon Kelley824af852008-02-12 20:43:05 +0000457 memcpy(&addr, p, INADDRSZ);
458
459 for (doctor = daemon->doctors; doctor; doctor = doctor->next)
Simon Kelley73a08a22009-02-05 20:28:08 +0000460 {
461 if (doctor->end.s_addr == 0)
462 {
463 if (!is_same_net(doctor->in, addr, doctor->mask))
464 continue;
465 }
466 else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
467 ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
468 continue;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100469
Simon Kelley73a08a22009-02-05 20:28:08 +0000470 addr.s_addr &= ~doctor->mask.s_addr;
471 addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
472 /* Since we munged the data, the server it came from is no longer authoritative */
Simon Kelley572b41e2011-02-18 18:11:18 +0000473 header->hb3 &= ~HB3_AA;
Simon Kelley6938f342014-01-26 22:47:39 +0000474 *doctored = 1;
Simon Kelley73a08a22009-02-05 20:28:08 +0000475 memcpy(p, &addr, INADDRSZ);
476 break;
477 }
Simon Kelley824af852008-02-12 20:43:05 +0000478 }
Simon Kelley28866e92011-02-14 20:19:14 +0000479 else if (qtype == T_TXT && name && option_bool(OPT_LOG))
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100480 {
481 unsigned char *p1 = p;
482 if (!CHECK_LEN(header, p1, qlen, rdlen))
483 return 0;
484 while ((p1 - p) < rdlen)
485 {
486 unsigned int i, len = *p1;
487 unsigned char *p2 = p1;
488 /* make counted string zero-term and sanitise */
489 for (i = 0; i < len; i++)
Simon Kelley231d0612012-04-27 13:50:45 +0100490 {
491 if (!isprint((int)*(p2+1)))
492 break;
493
494 *p2 = *(p2+1);
495 p2++;
496 }
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100497 *p2 = 0;
Simon Kelley28866e92011-02-14 20:19:14 +0000498 my_syslog(LOG_INFO, "reply %s is %s", name, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100499 /* restore */
Simon Kelley231d0612012-04-27 13:50:45 +0100500 memmove(p1 + 1, p1, i);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100501 *p1 = len;
502 p1 += len+1;
503 }
504 }
Simon Kelley824af852008-02-12 20:43:05 +0000505
Simon Kelley9009d742008-11-14 20:04:27 +0000506 if (!ADD_RDLEN(header, p, qlen, rdlen))
507 return 0; /* bad packet */
Simon Kelley824af852008-02-12 20:43:05 +0000508 }
509
510 return p;
511}
512
Simon Kelley6938f342014-01-26 22:47:39 +0000513static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000514{
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100515 unsigned char *p;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000516 int qtype, qclass, rdlen;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100517 unsigned long ttl, minttl = ULONG_MAX;
518 int i, found_soa = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000519
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100520 /* first move to NS section and find TTL from any SOA section */
521 if (!(p = skip_questions(header, qlen)) ||
Simon Kelley6938f342014-01-26 22:47:39 +0000522 !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
Simon Kelley824af852008-02-12 20:43:05 +0000523 return 0; /* bad packet */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000524
Simon Kelley5aabfc72007-08-29 11:24:47 +0100525 for (i = ntohs(header->nscount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000526 {
Simon Kelley9009d742008-11-14 20:04:27 +0000527 if (!(p = skip_name(p, header, qlen, 10)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100528 return 0; /* bad packet */
529
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000530 GETSHORT(qtype, p);
531 GETSHORT(qclass, p);
532 GETLONG(ttl, p);
533 GETSHORT(rdlen, p);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100534
535 if ((qclass == C_IN) && (qtype == T_SOA))
536 {
537 found_soa = 1;
538 if (ttl < minttl)
539 minttl = ttl;
540
541 /* MNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000542 if (!(p = skip_name(p, header, qlen, 0)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100543 return 0;
544 /* RNAME */
Simon Kelley9009d742008-11-14 20:04:27 +0000545 if (!(p = skip_name(p, header, qlen, 20)))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100546 return 0;
547 p += 16; /* SERIAL REFRESH RETRY EXPIRE */
548
549 GETLONG(ttl, p); /* minTTL */
550 if (ttl < minttl)
551 minttl = ttl;
552 }
Simon Kelley9009d742008-11-14 20:04:27 +0000553 else if (!ADD_RDLEN(header, p, qlen, rdlen))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100554 return 0; /* bad packet */
555 }
Simon Kelley9009d742008-11-14 20:04:27 +0000556
Simon Kelley6938f342014-01-26 22:47:39 +0000557 /* rewrite addresses in additional section too */
558 if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
Simon Kelley824af852008-02-12 20:43:05 +0000559 return 0;
560
561 if (!found_soa)
562 minttl = daemon->neg_ttl;
563
564 return minttl;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100565}
566
567/* Note that the following code can create CNAME chains that don't point to a real record,
568 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 +0000569 expired and cleaned out that way.
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100570 Return 1 if we reject an address because it look like part of dns-rebinding attack. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000571int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
Simon Kelley6938f342014-01-26 22:47:39 +0000572 char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100573{
Simon Kelley824af852008-02-12 20:43:05 +0000574 unsigned char *p, *p1, *endrr, *namep;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100575 int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000576 unsigned long ttl = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100577 struct all_addr addr;
Jason A. Donenfeld13d86c72013-02-22 18:20:53 +0000578#ifdef HAVE_IPSET
579 char **ipsets_cur;
580#else
581 (void)ipsets; /* unused */
582#endif
583
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100584 cache_start_insert();
Simon Kelley0a852542005-03-23 20:28:59 +0000585
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100586 /* 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 +0000587 if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
Simon Kelley0a852542005-03-23 20:28:59 +0000588 {
589 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000590 ttl = find_soa(header, qlen, name, doctored);
591#ifdef HAVE_DNSSEC
Simon Kelleyd1fbb772014-03-01 20:08:58 +0000592 if (*doctored && secure)
593 return 0;
Simon Kelley6938f342014-01-26 22:47:39 +0000594#endif
Simon Kelley0a852542005-03-23 20:28:59 +0000595 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100596
597 /* go through the questions. */
598 p = (unsigned char *)(header+1);
599
Simon Kelley5aabfc72007-08-29 11:24:47 +0100600 for (i = ntohs(header->qdcount); i != 0; i--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100601 {
Simon Kelley1fbe4d22014-03-01 20:03:47 +0000602 int found = 0, cname_count = CNAME_CHAIN;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100603 struct crec *cpp = NULL;
Simon Kelley572b41e2011-02-18 18:11:18 +0000604 int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
Simon Kelley0435d042014-01-08 18:22:37 +0000605 int secflag = secure ? F_DNSSECOK : 0;
Simon Kelley0a852542005-03-23 20:28:59 +0000606 unsigned long cttl = ULONG_MAX, attl;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000607
Simon Kelley824af852008-02-12 20:43:05 +0000608 namep = p;
Simon Kelley9009d742008-11-14 20:04:27 +0000609 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley824af852008-02-12 20:43:05 +0000610 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100611
612 GETSHORT(qtype, p);
613 GETSHORT(qclass, p);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000614
615 if (qclass != C_IN)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100616 continue;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000617
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100618 /* PTRs: we chase CNAMEs here, since we have no way to
619 represent them in the cache. */
620 if (qtype == T_PTR)
621 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000622 int name_encoding = in_arpa_name_2_addr(name, &addr);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100623
624 if (!name_encoding)
625 continue;
626
627 if (!(flags & F_NXDOMAIN))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000628 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100629 cname_loop:
630 if (!(p1 = skip_questions(header, qlen)))
Simon Kelley824af852008-02-12 20:43:05 +0000631 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100632
Simon Kelley5aabfc72007-08-29 11:24:47 +0100633 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100634 {
Simon Kelley824af852008-02-12 20:43:05 +0000635 unsigned char *tmp = namep;
636 /* the loop body overwrites the original name, so get it back here. */
Simon Kelley9009d742008-11-14 20:04:27 +0000637 if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
638 !(res = extract_name(header, qlen, &p1, name, 0, 10)))
Simon Kelley824af852008-02-12 20:43:05 +0000639 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100640
641 GETSHORT(aqtype, p1);
642 GETSHORT(aqclass, p1);
643 GETLONG(attl, p1);
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100644 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
645 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000646 (p1) -= 4;
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100647 PUTLONG(daemon->max_ttl, p1);
648 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100649 GETSHORT(ardlen, p1);
650 endrr = p1+ardlen;
651
652 /* TTL of record is minimum of CNAMES and PTR */
653 if (attl < cttl)
654 cttl = attl;
655
656 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
657 {
Simon Kelley9009d742008-11-14 20:04:27 +0000658 if (!extract_name(header, qlen, &p1, name, 1, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000659 return 0;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100660
661 if (aqtype == T_CNAME)
662 {
Simon Kelleyd1fbb772014-03-01 20:08:58 +0000663 if (!cname_count-- || secure)
664 return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100665 goto cname_loop;
666 }
667
Simon Kelley0435d042014-01-08 18:22:37 +0000668 cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100669 found = 1;
670 }
671
672 p1 = endrr;
Simon Kelley9009d742008-11-14 20:04:27 +0000673 if (!CHECK_LEN(header, p1, qlen, 0))
Simon Kelley824af852008-02-12 20:43:05 +0000674 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100675 }
676 }
677
Simon Kelley28866e92011-02-14 20:19:14 +0000678 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100679 {
680 if (!searched_soa)
681 {
682 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000683 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100684 }
685 if (ttl)
Simon Kelley0435d042014-01-08 18:22:37 +0000686 cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000687 }
688 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100689 else
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000690 {
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100691 /* everything other than PTR */
692 struct crec *newc;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100693 int addrlen;
694
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100695 if (qtype == T_A)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100696 {
697 addrlen = INADDRSZ;
698 flags |= F_IPV4;
699 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000700#ifdef HAVE_IPV6
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100701 else if (qtype == T_AAAA)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100702 {
703 addrlen = IN6ADDRSZ;
704 flags |= F_IPV6;
705 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000706#endif
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100707 else
708 continue;
709
Simon Kelley45cca582013-10-15 10:20:13 +0100710 cname_loop1:
711 if (!(p1 = skip_questions(header, qlen)))
712 return 0;
713
714 for (j = ntohs(header->ancount); j != 0; j--)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100715 {
Simon Kelley45cca582013-10-15 10:20:13 +0100716 if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
717 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100718
Simon Kelley45cca582013-10-15 10:20:13 +0100719 GETSHORT(aqtype, p1);
720 GETSHORT(aqclass, p1);
721 GETLONG(attl, p1);
722 if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000723 {
Simon Kelley45cca582013-10-15 10:20:13 +0100724 (p1) -= 4;
725 PUTLONG(daemon->max_ttl, p1);
726 }
727 GETSHORT(ardlen, p1);
728 endrr = p1+ardlen;
729
730 if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
731 {
732 if (aqtype == T_CNAME)
Simon Kelley8ef5ada2010-06-03 19:42:45 +0100733 {
Simon Kelley45cca582013-10-15 10:20:13 +0100734 if (!cname_count--)
735 return 0; /* looped CNAMES */
Simon Kelley0435d042014-01-08 18:22:37 +0000736 newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100737 if (newc)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100738 {
Simon Kelley45cca582013-10-15 10:20:13 +0100739 newc->addr.cname.target.cache = NULL;
Simon Kelley03431d62014-03-20 16:25:43 +0000740 /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
741 newc->addr.cname.uid = 1;
Simon Kelley45cca582013-10-15 10:20:13 +0100742 if (cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100743 {
Simon Kelleyd56a6042013-10-11 14:39:03 +0100744 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100745 cpp->addr.cname.uid = newc->uid;
746 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100747 }
Simon Kelley45cca582013-10-15 10:20:13 +0100748
749 cpp = newc;
750 if (attl < cttl)
751 cttl = attl;
752
753 if (!extract_name(header, qlen, &p1, name, 1, 0))
754 return 0;
755 goto cname_loop1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100756 }
Simon Kelley45cca582013-10-15 10:20:13 +0100757 else if (!(flags & F_NXDOMAIN))
758 {
759 found = 1;
760
761 /* copy address into aligned storage */
762 if (!CHECK_LEN(header, p1, qlen, addrlen))
763 return 0; /* bad packet */
764 memcpy(&addr, p1, addrlen);
765
766 /* check for returned address in private space */
Simon Kelleyb059c962015-05-08 20:25:51 +0100767 if (check_rebind)
768 {
769 if ((flags & F_IPV4) &&
770 private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
771 return 1;
772
773#ifdef HAVE_IPV6
774 if ((flags & F_IPV6) &&
775 IN6_IS_ADDR_V4MAPPED(&addr.addr.addr6))
776 {
777 struct in_addr v4;
778 v4.s_addr = ((const uint32_t *) (&addr.addr.addr6))[3];
779 if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
780 return 1;
781 }
782#endif
783 }
Simon Kelley45cca582013-10-15 10:20:13 +0100784
785#ifdef HAVE_IPSET
786 if (ipsets && (flags & (F_IPV4 | F_IPV6)))
787 {
788 ipsets_cur = ipsets;
789 while (*ipsets_cur)
Wang Jian49752b92014-03-28 20:52:47 +0000790 {
Simon Kelleyb7639d52014-03-29 09:20:07 +0000791 log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
Wang Jian49752b92014-03-28 20:52:47 +0000792 add_to_ipset(*ipsets_cur++, &addr, flags, 0);
793 }
Simon Kelley45cca582013-10-15 10:20:13 +0100794 }
795#endif
796
Simon Kelley0435d042014-01-08 18:22:37 +0000797 newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
Simon Kelley45cca582013-10-15 10:20:13 +0100798 if (newc && cpp)
799 {
800 cpp->addr.cname.target.cache = newc;
801 cpp->addr.cname.uid = newc->uid;
802 }
803 cpp = NULL;
804 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100805 }
Simon Kelley45cca582013-10-15 10:20:13 +0100806
807 p1 = endrr;
808 if (!CHECK_LEN(header, p1, qlen, 0))
809 return 0; /* bad packet */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100810 }
811
Simon Kelley28866e92011-02-14 20:19:14 +0000812 if (!found && !option_bool(OPT_NO_NEG))
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100813 {
814 if (!searched_soa)
815 {
816 searched_soa = 1;
Simon Kelley6938f342014-01-26 22:47:39 +0000817 ttl = find_soa(header, qlen, NULL, doctored);
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100818 }
819 /* If there's no SOA to get the TTL from, but there is a CNAME
Simon Kelley824af852008-02-12 20:43:05 +0000820 pointing at this, inherit its TTL */
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100821 if (ttl || cpp)
822 {
Simon Kelley0435d042014-01-08 18:22:37 +0000823 newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
Simon Kelley26128d22004-11-14 16:43:54 +0000824 if (newc && cpp)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100825 {
Simon Kelleyd56a6042013-10-11 14:39:03 +0100826 cpp->addr.cname.target.cache = newc;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100827 cpp->addr.cname.uid = newc->uid;
828 }
829 }
830 }
831 }
832 }
833
Simon Kelley1023dcb2012-04-09 18:00:08 +0100834 /* Don't put stuff from a truncated packet into the cache.
Simon Kelley1023dcb2012-04-09 18:00:08 +0100835 Don't cache replies from non-recursive nameservers, since we may get a
836 reply containing a CNAME but not its target, even though the target
837 does exist. */
838 if (!(header->hb3 & HB3_TC) &&
839 !(header->hb4 & HB4_CD) &&
840 (header->hb4 & HB4_RA) &&
Simon Kelley3a237152013-12-12 12:15:50 +0000841 !no_cache_dnssec)
Simon Kelley824af852008-02-12 20:43:05 +0000842 cache_end_insert();
843
844 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000845}
846
847/* If the packet holds exactly one query
Simon Kelley28866e92011-02-14 20:19:14 +0000848 return F_IPV4 or F_IPV6 and leave the name from the query in name */
Simon Kelley572b41e2011-02-18 18:11:18 +0000849unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000850{
851 unsigned char *p = (unsigned char *)(header+1);
852 int qtype, qclass;
853
Simon Kelleyc1bb8502004-08-11 18:40:17 +0100854 if (typep)
855 *typep = 0;
856
Simon Kelley572b41e2011-02-18 18:11:18 +0000857 if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000858 return 0; /* must be exactly one query. */
859
Simon Kelley9009d742008-11-14 20:04:27 +0000860 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000861 return 0; /* bad packet */
862
863 GETSHORT(qtype, p);
864 GETSHORT(qclass, p);
865
Simon Kelley0a852542005-03-23 20:28:59 +0000866 if (typep)
867 *typep = qtype;
868
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869 if (qclass == C_IN)
870 {
871 if (qtype == T_A)
872 return F_IPV4;
873 if (qtype == T_AAAA)
874 return F_IPV6;
875 if (qtype == T_ANY)
876 return F_IPV4 | F_IPV6;
877 }
878
879 return F_QUERY;
880}
881
882
Simon Kelley572b41e2011-02-18 18:11:18 +0000883size_t setup_reply(struct dns_header *header, size_t qlen,
Simon Kelley28866e92011-02-14 20:19:14 +0000884 struct all_addr *addrp, unsigned int flags, unsigned long ttl)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000885{
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100886 unsigned char *p;
887
888 if (!(p = skip_questions(header, qlen)))
889 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000890
Simon Kelley572b41e2011-02-18 18:11:18 +0000891 /* clear authoritative and truncated flags, set QR flag */
892 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
893 /* set RA flag */
894 header->hb4 |= HB4_RA;
895
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000896 header->nscount = htons(0);
897 header->arcount = htons(0);
Simon Kelleyfeba5c12004-07-27 20:28:58 +0100898 header->ancount = htons(0); /* no answers unless changed below */
Simon Kelleyd05dd582016-01-19 21:23:30 +0000899 if (flags == F_NOERR)
Simon Kelley572b41e2011-02-18 18:11:18 +0000900 SET_RCODE(header, NOERROR); /* empty domain */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000901 else if (flags == F_NXDOMAIN)
Simon Kelley572b41e2011-02-18 18:11:18 +0000902 SET_RCODE(header, NXDOMAIN);
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100903 else if (flags == F_IPV4)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000904 { /* we know the address */
Simon Kelley572b41e2011-02-18 18:11:18 +0000905 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000906 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +0000907 header->hb3 |= HB3_AA;
908 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000909 }
910#ifdef HAVE_IPV6
Simon Kelleyad4a8ff2015-04-09 21:48:00 +0100911 else if (flags == F_IPV6)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000912 {
Simon Kelley572b41e2011-02-18 18:11:18 +0000913 SET_RCODE(header, NOERROR);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000914 header->ancount = htons(1);
Simon Kelley572b41e2011-02-18 18:11:18 +0000915 header->hb3 |= HB3_AA;
916 add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000917 }
918#endif
919 else /* nowhere to forward to */
Simon Kelley572b41e2011-02-18 18:11:18 +0000920 SET_RCODE(header, REFUSED);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000921
922 return p - (unsigned char *)header;
923}
Simon Kelley36717ee2004-09-20 19:20:58 +0100924
925/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
Simon Kelley5aabfc72007-08-29 11:24:47 +0100926int check_for_local_domain(char *name, time_t now)
Simon Kelley36717ee2004-09-20 19:20:58 +0100927{
928 struct crec *crecp;
Simon Kelley0a852542005-03-23 20:28:59 +0000929 struct mx_srv_record *mx;
930 struct txt_record *txt;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100931 struct interface_name *intr;
932 struct ptr_record *ptr;
Simon Kelley7de060b2011-08-26 17:24:52 +0100933 struct naptr *naptr;
934
Simon Kelley288df492014-09-18 21:48:51 +0100935 /* Note: the call to cache_find_by_name is intended to find any record which matches
Simon Kelley93be5b12015-12-15 12:04:40 +0000936 ie A, AAAA, CNAME. */
Simon Kelley288df492014-09-18 21:48:51 +0100937
Simon Kelley93be5b12015-12-15 12:04:40 +0000938 if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
Simon Kelley7b174c22013-10-28 13:14:03 +0000939 (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley36717ee2004-09-20 19:20:58 +0100940 return 1;
941
Simon Kelley7de060b2011-08-26 17:24:52 +0100942 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
943 if (hostname_isequal(name, naptr->name))
944 return 1;
945
946 for (mx = daemon->mxnames; mx; mx = mx->next)
Simon Kelley0a852542005-03-23 20:28:59 +0000947 if (hostname_isequal(name, mx->name))
Simon Kelley36717ee2004-09-20 19:20:58 +0100948 return 1;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000949
Simon Kelley0a852542005-03-23 20:28:59 +0000950 for (txt = daemon->txt; txt; txt = txt->next)
951 if (hostname_isequal(name, txt->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000952 return 1;
Simon Kelleyf2621c72007-04-29 19:47:21 +0100953
954 for (intr = daemon->int_names; intr; intr = intr->next)
955 if (hostname_isequal(name, intr->name))
956 return 1;
957
958 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
959 if (hostname_isequal(name, ptr->name))
960 return 1;
961
Simon Kelley36717ee2004-09-20 19:20:58 +0100962 return 0;
963}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000964
965/* Is the packet a reply with the answer address equal to addr?
966 If so mung is into an NXDOMAIN reply and also put that information
967 in the cache. */
Simon Kelley572b41e2011-02-18 18:11:18 +0000968int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000969 struct bogus_addr *baddr, time_t now)
970{
971 unsigned char *p;
972 int i, qtype, qclass, rdlen;
973 unsigned long ttl;
974 struct bogus_addr *baddrp;
975
976 /* skip over questions */
977 if (!(p = skip_questions(header, qlen)))
978 return 0; /* bad packet */
979
Simon Kelley5aabfc72007-08-29 11:24:47 +0100980 for (i = ntohs(header->ancount); i != 0; i--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000981 {
Simon Kelley9009d742008-11-14 20:04:27 +0000982 if (!extract_name(header, qlen, &p, name, 1, 10))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000983 return 0; /* bad packet */
984
985 GETSHORT(qtype, p);
986 GETSHORT(qclass, p);
987 GETLONG(ttl, p);
988 GETSHORT(rdlen, p);
989
990 if (qclass == C_IN && qtype == T_A)
Simon Kelley9009d742008-11-14 20:04:27 +0000991 {
992 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
993 return 0;
994
995 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
996 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
997 {
998 /* Found a bogus address. Insert that info here, since there no SOA record
999 to get the ttl from in the normal processing */
1000 cache_start_insert();
Simon Kelley8db957d2013-12-17 15:47:10 +00001001 cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
Simon Kelley9009d742008-11-14 20:04:27 +00001002 cache_end_insert();
1003
1004 return 1;
1005 }
1006 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001007
Simon Kelley9009d742008-11-14 20:04:27 +00001008 if (!ADD_RDLEN(header, p, qlen, rdlen))
1009 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001010 }
1011
1012 return 0;
1013}
1014
Glen Huang32fc6db2014-12-27 15:28:12 +00001015int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
1016{
1017 unsigned char *p;
1018 int i, qtype, qclass, rdlen;
1019 struct bogus_addr *baddrp;
1020
1021 /* skip over questions */
1022 if (!(p = skip_questions(header, qlen)))
1023 return 0; /* bad packet */
1024
1025 for (i = ntohs(header->ancount); i != 0; i--)
1026 {
1027 if (!(p = skip_name(p, header, qlen, 10)))
1028 return 0; /* bad packet */
1029
1030 GETSHORT(qtype, p);
1031 GETSHORT(qclass, p);
1032 p += 4; /* TTL */
1033 GETSHORT(rdlen, p);
1034
1035 if (qclass == C_IN && qtype == T_A)
1036 {
1037 if (!CHECK_LEN(header, p, qlen, INADDRSZ))
1038 return 0;
1039
1040 for (baddrp = baddr; baddrp; baddrp = baddrp->next)
1041 if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
1042 return 1;
1043 }
1044
1045 if (!ADD_RDLEN(header, p, qlen, rdlen))
1046 return 0;
1047 }
1048
1049 return 0;
1050}
1051
Simon Kelleyb75e9362012-12-07 11:50:41 +00001052int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
Simon Kelleye1ff4192012-12-09 17:08:47 +00001053 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001054{
1055 va_list ap;
1056 unsigned char *sav, *p = *pp;
1057 int j;
1058 unsigned short usval;
1059 long lval;
1060 char *sval;
1061
1062 if (truncp && *truncp)
1063 return 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001064
1065 va_start(ap, format); /* make ap point to 1st unamed argument */
1066
Simon Kelleyb75e9362012-12-07 11:50:41 +00001067 if (nameoffset > 0)
Simon Kelley4f7b3042012-11-28 21:27:02 +00001068 {
1069 PUTSHORT(nameoffset | 0xc000, p);
1070 }
1071 else
1072 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001073 char *name = va_arg(ap, char *);
1074 if (name)
1075 p = do_rfc1035_name(p, name);
Simon Kelleyb75e9362012-12-07 11:50:41 +00001076 if (nameoffset < 0)
1077 {
1078 PUTSHORT(-nameoffset | 0xc000, p);
1079 }
1080 else
1081 *p++ = 0;
Simon Kelley4f7b3042012-11-28 21:27:02 +00001082 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001083
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001084 PUTSHORT(type, p);
1085 PUTSHORT(class, p);
1086 PUTLONG(ttl, p); /* TTL */
1087
1088 sav = p; /* Save pointer to RDLength field */
1089 PUTSHORT(0, p); /* Placeholder RDLength */
1090
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001091 for (; *format; format++)
1092 switch (*format)
1093 {
1094#ifdef HAVE_IPV6
1095 case '6':
1096 sval = va_arg(ap, char *);
1097 memcpy(p, sval, IN6ADDRSZ);
1098 p += IN6ADDRSZ;
1099 break;
1100#endif
1101
1102 case '4':
1103 sval = va_arg(ap, char *);
1104 memcpy(p, sval, INADDRSZ);
1105 p += INADDRSZ;
1106 break;
1107
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001108 case 'b':
1109 usval = va_arg(ap, int);
1110 *p++ = usval;
1111 break;
1112
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001113 case 's':
1114 usval = va_arg(ap, int);
1115 PUTSHORT(usval, p);
1116 break;
1117
1118 case 'l':
1119 lval = va_arg(ap, long);
1120 PUTLONG(lval, p);
1121 break;
1122
1123 case 'd':
1124 /* get domain-name answer arg and store it in RDATA field */
Simon Kelley0a852542005-03-23 20:28:59 +00001125 if (offset)
1126 *offset = p - (unsigned char *)header;
Simon Kelley3d8df262005-08-29 12:19:27 +01001127 p = do_rfc1035_name(p, va_arg(ap, char *));
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001128 *p++ = 0;
1129 break;
Simon Kelley3d8df262005-08-29 12:19:27 +01001130
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001131 case 't':
Simon Kelley0a852542005-03-23 20:28:59 +00001132 usval = va_arg(ap, int);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001133 sval = va_arg(ap, char *);
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001134 if (usval != 0)
1135 memcpy(p, sval, usval);
Simon Kelley0a852542005-03-23 20:28:59 +00001136 p += usval;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001137 break;
Simon Kelley1a6bca82008-07-11 11:11:42 +01001138
1139 case 'z':
1140 sval = va_arg(ap, char *);
1141 usval = sval ? strlen(sval) : 0;
1142 if (usval > 255)
1143 usval = 255;
1144 *p++ = (unsigned char)usval;
1145 memcpy(p, sval, usval);
1146 p += usval;
1147 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001148 }
1149
1150 va_end(ap); /* clean up variable argument pointer */
1151
1152 j = p - sav - 2;
1153 PUTSHORT(j, sav); /* Now, store real RDLength */
1154
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001155 /* check for overflow of buffer */
1156 if (limit && ((unsigned char *)limit - p) < 0)
1157 {
1158 if (truncp)
1159 *truncp = 1;
1160 return 0;
1161 }
1162
1163 *pp = p;
1164 return 1;
1165}
1166
Simon Kelley9009d742008-11-14 20:04:27 +00001167static unsigned long crec_ttl(struct crec *crecp, time_t now)
1168{
1169 /* Return 0 ttl for DHCP entries, which might change
Simon Kelley7480aef2016-02-26 21:58:20 +00001170 before the lease expires, unless configured otherwise. */
Simon Kelley9009d742008-11-14 20:04:27 +00001171
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001172 if (crecp->flags & F_DHCP)
Simon Kelley7480aef2016-02-26 21:58:20 +00001173 {
1174 int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
1175
1176 /* Apply ceiling of actual lease length to configured TTL. */
1177 if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
1178 return crecp->ttd - now;
1179
1180 return conf_ttl;
1181 }
Simon Kelley9009d742008-11-14 20:04:27 +00001182
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001183 /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
1184 if (crecp->flags & F_IMMORTAL)
1185 return crecp->ttd;
1186
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001187 /* Return the Max TTL value if it is lower then the actual TTL */
1188 if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
1189 return crecp->ttd - now;
1190 else
1191 return daemon->max_ttl;
Simon Kelley9009d742008-11-14 20:04:27 +00001192}
1193
1194
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001195/* return zero if we can't answer from cache, or packet size if we can */
Simon Kelley572b41e2011-02-18 18:11:18 +00001196size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
Simon Kelley83349b82014-02-10 21:02:01 +00001197 struct in_addr local_addr, struct in_addr local_netmask,
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001198 time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001199{
Simon Kelley3be34542004-09-11 19:12:13 +01001200 char *name = daemon->namebuff;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001201 unsigned char *p, *ansp;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001202 unsigned int qtype, qclass;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001203 struct all_addr addr;
Simon Kelleyb75e9362012-12-07 11:50:41 +00001204 int nameoffset;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001205 unsigned short flag;
Simon Kelley0a852542005-03-23 20:28:59 +00001206 int q, ans, anscount = 0, addncount = 0;
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001207 int dryrun = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001208 struct crec *crecp;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001209 int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
Simon Kelley0a852542005-03-23 20:28:59 +00001210 struct mx_srv_record *rec;
Simon Kelleya25720a2014-01-14 23:13:55 +00001211 size_t len;
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001212
1213 if (ntohs(header->ancount) != 0 ||
1214 ntohs(header->nscount) != 0 ||
1215 ntohs(header->qdcount) == 0 ||
1216 OPCODE(header) != QUERY )
1217 return 0;
1218
Simon Kelleye243c072014-02-06 18:14:09 +00001219 /* Don't return AD set if checking disabled. */
Simon Kelleya25720a2014-01-14 23:13:55 +00001220 if (header->hb4 & HB4_CD)
1221 sec_data = 0;
Simon Kelley83349b82014-02-10 21:02:01 +00001222
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001223 /* If there is an additional data section then it will be overwritten by
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001224 partial replies, so we have to do a dry run to see if we can answer
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001225 the query. */
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001226 if (ntohs(header->arcount) != 0)
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001227 dryrun = 1;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001228
Simon Kelley0a852542005-03-23 20:28:59 +00001229 for (rec = daemon->mxnames; rec; rec = rec->next)
1230 rec->offset = 0;
1231
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001232 rerun:
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001233 /* determine end of question section (we put answers there) */
1234 if (!(ansp = skip_questions(header, qlen)))
1235 return 0; /* bad packet */
1236
1237 /* now process each question, answers go in RRs after the question */
1238 p = (unsigned char *)(header+1);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001239
Simon Kelley5aabfc72007-08-29 11:24:47 +01001240 for (q = ntohs(header->qdcount); q != 0; q--)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001241 {
1242 /* save pointer to name for copying into answers */
1243 nameoffset = p - (unsigned char *)header;
1244
1245 /* now extract name as .-concatenated string into name */
Simon Kelley9009d742008-11-14 20:04:27 +00001246 if (!extract_name(header, qlen, &p, name, 1, 4))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001247 return 0; /* bad packet */
Simon Kelley832af0b2007-01-21 20:01:28 +00001248
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001249 GETSHORT(qtype, p);
1250 GETSHORT(qclass, p);
1251
1252 ans = 0; /* have we answered this question */
1253
Simon Kelley0a852542005-03-23 20:28:59 +00001254 if (qtype == T_TXT || qtype == T_ANY)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001255 {
Simon Kelley0a852542005-03-23 20:28:59 +00001256 struct txt_record *t;
1257 for(t = daemon->txt; t ; t = t->next)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001258 {
Simon Kelley0a852542005-03-23 20:28:59 +00001259 if (t->class == qclass && hostname_isequal(name, t->name))
1260 {
1261 ans = 1;
Simon Kelleye17fb622006-01-14 20:33:46 +00001262 if (!dryrun)
1263 {
Simon Kelleyfec216d2014-03-27 20:54:34 +00001264 unsigned long ttl = daemon->local_ttl;
1265 int ok = 1;
Simon Kelley28866e92011-02-14 20:19:14 +00001266 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
Simon Kelleyfec216d2014-03-27 20:54:34 +00001267 /* Dynamically generate stat record */
1268 if (t->stat != 0)
1269 {
1270 ttl = 0;
1271 if (!cache_make_stat(t))
1272 ok = 0;
1273 }
1274
1275 if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1276 ttl, NULL,
1277 T_TXT, t->class, "t", t->len, t->txt))
Simon Kelleye17fb622006-01-14 20:33:46 +00001278 anscount++;
1279
1280 }
Simon Kelley0a852542005-03-23 20:28:59 +00001281 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001282 }
Simon Kelley0a852542005-03-23 20:28:59 +00001283 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001284
Simon Kelley0a852542005-03-23 20:28:59 +00001285 if (qclass == C_IN)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001286 {
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001287 struct txt_record *t;
1288
1289 for (t = daemon->rr; t; t = t->next)
1290 if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
1291 {
1292 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001293 sec_data = 0;
Simon Kelley9f7f3b12012-05-28 21:39:57 +01001294 if (!dryrun)
1295 {
1296 log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
1297 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1298 daemon->local_ttl, NULL,
1299 t->class, C_IN, "t", t->len, t->txt))
1300 anscount ++;
1301 }
1302 }
1303
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001304 if (qtype == T_PTR || qtype == T_ANY)
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001305 {
Simon Kelley832af0b2007-01-21 20:01:28 +00001306 /* see if it's w.z.y.z.in-addr.arpa format */
1307 int is_arpa = in_arpa_name_2_addr(name, &addr);
1308 struct ptr_record *ptr;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001309 struct interface_name* intr = NULL;
Simon Kelley832af0b2007-01-21 20:01:28 +00001310
1311 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1312 if (hostname_isequal(name, ptr->name))
1313 break;
1314
Simon Kelleyf2621c72007-04-29 19:47:21 +01001315 if (is_arpa == F_IPV4)
1316 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001317 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001318 struct addrlist *addrlist;
1319
Simon Kelley376d48c2013-11-13 13:04:30 +00001320 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1321 if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
Simon Kelley115ac3e2013-05-20 11:28:32 +01001322 break;
1323
1324 if (addrlist)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001325 break;
1326 else
1327 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1328 intr = intr->next;
1329 }
Simon Kelley115ac3e2013-05-20 11:28:32 +01001330#ifdef HAVE_IPV6
1331 else if (is_arpa == F_IPV6)
1332 for (intr = daemon->int_names; intr; intr = intr->next)
1333 {
1334 struct addrlist *addrlist;
1335
Simon Kelley376d48c2013-11-13 13:04:30 +00001336 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
1337 if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
Simon Kelley115ac3e2013-05-20 11:28:32 +01001338 break;
1339
1340 if (addrlist)
1341 break;
1342 else
1343 while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
1344 intr = intr->next;
1345 }
1346#endif
Simon Kelleyf2621c72007-04-29 19:47:21 +01001347
1348 if (intr)
1349 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001350 sec_data = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001351 ans = 1;
1352 if (!dryrun)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001353 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001354 log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001355 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1356 daemon->local_ttl, NULL,
1357 T_PTR, C_IN, "d", intr->name))
1358 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001359 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001360 }
Simon Kelley832af0b2007-01-21 20:01:28 +00001361 else if (ptr)
1362 {
1363 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001364 sec_data = 0;
Simon Kelley832af0b2007-01-21 20:01:28 +00001365 if (!dryrun)
1366 {
Simon Kelley28866e92011-02-14 20:19:14 +00001367 log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Simon Kelley832af0b2007-01-21 20:01:28 +00001368 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001369 if (hostname_isequal(name, ptr->name) &&
1370 add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1371 daemon->local_ttl, NULL,
1372 T_PTR, C_IN, "d", ptr->ptr))
1373 anscount++;
1374
Simon Kelley832af0b2007-01-21 20:01:28 +00001375 }
1376 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001377 else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001378 {
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001379 /* Don't use cache when DNSSEC data required, unless we know that
1380 the zone is unsigned, which implies that we're doing
1381 validation. */
1382 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001383 !do_bit ||
Simon Kelleydd4ad9a2015-12-17 10:44:58 +00001384 (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
Simon Kelley2d33bda2014-01-24 22:37:25 +00001385 {
1386 do
1387 {
1388 /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
1389 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
1390 continue;
1391
1392 if (!(crecp->flags & F_DNSSECOK))
1393 sec_data = 0;
Simon Kelley93be5b12015-12-15 12:04:40 +00001394
1395 ans = 1;
1396
Simon Kelley2d33bda2014-01-24 22:37:25 +00001397 if (crecp->flags & F_NEG)
1398 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001399 auth = 0;
1400 if (crecp->flags & F_NXDOMAIN)
1401 nxdomain = 1;
1402 if (!dryrun)
1403 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
1404 }
Simon Kelley93be5b12015-12-15 12:04:40 +00001405 else
Simon Kelley2d33bda2014-01-24 22:37:25 +00001406 {
Simon Kelley2d33bda2014-01-24 22:37:25 +00001407 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1408 auth = 0;
1409 if (!dryrun)
1410 {
1411 log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
1412 record_source(crecp->uid));
1413
1414 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1415 crec_ttl(crecp, now), NULL,
1416 T_PTR, C_IN, "d", cache_get_name(crecp)))
1417 anscount++;
1418 }
1419 }
1420 } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
1421 }
1422 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001423 else if (is_rev_synth(is_arpa, &addr, name))
1424 {
1425 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001426 sec_data = 0;
Simon Kelley2bb73af2013-04-24 17:38:19 +01001427 if (!dryrun)
1428 {
1429 log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
1430
1431 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1432 daemon->local_ttl, NULL,
1433 T_PTR, C_IN, "d", name))
1434 anscount++;
1435 }
1436 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001437 else if (is_arpa == F_IPV4 &&
Simon Kelley28866e92011-02-14 20:19:14 +00001438 option_bool(OPT_BOGUSPRIV) &&
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001439 private_net(addr.addr.addr4, 1))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001440 {
1441 /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
1442 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001443 sec_data = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001444 nxdomain = 1;
1445 if (!dryrun)
1446 log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,
Simon Kelley1a6bca82008-07-11 11:11:42 +01001447 name, &addr, NULL);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001448 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001449 }
Simon Kelleyf2621c72007-04-29 19:47:21 +01001450
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001451 for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
1452 {
1453 unsigned short type = T_A;
Simon Kelley115ac3e2013-05-20 11:28:32 +01001454 struct interface_name *intr;
1455
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001456 if (flag == F_IPV6)
1457#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +01001458 type = T_AAAA;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001459#else
Simon Kelley3d8df262005-08-29 12:19:27 +01001460 break;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001461#endif
1462
1463 if (qtype != type && qtype != T_ANY)
1464 continue;
1465
Simon Kelley316e2732010-01-22 20:16:09 +00001466 /* Check for "A for A" queries; be rather conservative
1467 about what looks like dotted-quad. */
1468 if (qtype == T_A)
Simon Kelley3d8df262005-08-29 12:19:27 +01001469 {
Simon Kelley316e2732010-01-22 20:16:09 +00001470 char *cp;
1471 unsigned int i, a;
1472 int x;
1473
1474 for (cp = name, i = 0, a = 0; *cp; i++)
Simon Kelley3d8df262005-08-29 12:19:27 +01001475 {
Simon Kelley572b41e2011-02-18 18:11:18 +00001476 if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
Simon Kelley316e2732010-01-22 20:16:09 +00001477 {
1478 i = 5;
1479 break;
1480 }
1481
1482 a = (a << 8) + x;
1483
1484 if (*cp == '.')
1485 cp++;
Simon Kelley3d8df262005-08-29 12:19:27 +01001486 }
Simon Kelley316e2732010-01-22 20:16:09 +00001487
1488 if (i == 4)
1489 {
1490 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001491 sec_data = 0;
Simon Kelley316e2732010-01-22 20:16:09 +00001492 if (!dryrun)
1493 {
1494 addr.addr.addr4.s_addr = htonl(a);
1495 log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
1496 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1497 daemon->local_ttl, NULL, type, C_IN, "4", &addr))
1498 anscount++;
1499 }
1500 continue;
1501 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001502 }
1503
Simon Kelleyf2621c72007-04-29 19:47:21 +01001504 /* interface name stuff */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001505 intname_restart:
Simon Kelley115ac3e2013-05-20 11:28:32 +01001506 for (intr = daemon->int_names; intr; intr = intr->next)
1507 if (hostname_isequal(name, intr->name))
1508 break;
1509
1510 if (intr)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001511 {
Simon Kelley115ac3e2013-05-20 11:28:32 +01001512 struct addrlist *addrlist;
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001513 int gotit = 0;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001514
Simon Kelley115ac3e2013-05-20 11:28:32 +01001515 enumerate_interfaces(0);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001516
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001517 for (intr = daemon->int_names; intr; intr = intr->next)
1518 if (hostname_isequal(name, intr->name))
1519 {
Simon Kelley47669362014-12-17 12:41:56 +00001520 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
Simon Kelley376d48c2013-11-13 13:04:30 +00001521#ifdef HAVE_IPV6
Simon Kelley47669362014-12-17 12:41:56 +00001522 if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
Simon Kelley376d48c2013-11-13 13:04:30 +00001523#endif
Simon Kelley47669362014-12-17 12:41:56 +00001524 {
1525#ifdef HAVE_IPV6
1526 if (addrlist->flags & ADDRLIST_REVONLY)
1527 continue;
1528#endif
1529 ans = 1;
Simon Kelley93be5b12015-12-15 12:04:40 +00001530 sec_data = 0;
Simon Kelley47669362014-12-17 12:41:56 +00001531 if (!dryrun)
Simon Kelley376d48c2013-11-13 13:04:30 +00001532 {
1533 gotit = 1;
1534 log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
1535 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1536 daemon->local_ttl, NULL, type, C_IN,
1537 type == T_A ? "4" : "6", &addrlist->addr))
1538 anscount++;
1539 }
Simon Kelley47669362014-12-17 12:41:56 +00001540 }
Simon Kelleyfb63dd12013-10-21 18:19:35 +01001541 }
1542
1543 if (!dryrun && !gotit)
1544 log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
1545
Simon Kelley115ac3e2013-05-20 11:28:32 +01001546 continue;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001547 }
1548
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001549 cname_restart:
Simon Kelley12fae492014-02-04 22:03:06 +00001550 if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001551 {
1552 int localise = 0;
1553
1554 /* See if a putative address is on the network from which we recieved
1555 the query, is so we'll filter other answers. */
Simon Kelley28866e92011-02-14 20:19:14 +00001556 if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001557 {
1558 struct crec *save = crecp;
1559 do {
1560 if ((crecp->flags & F_HOSTS) &&
1561 is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1562 {
1563 localise = 1;
1564 break;
1565 }
1566 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
1567 crecp = save;
1568 }
Simon Kelley824202e2014-01-23 20:59:46 +00001569
Simon Kelley93be5b12015-12-15 12:04:40 +00001570 /* If the client asked for DNSSEC don't use cached data. */
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001571 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
Simon Kelley824202e2014-01-23 20:59:46 +00001572 do
1573 {
1574 /* don't answer wildcard queries with data not from /etc/hosts
1575 or DHCP leases */
1576 if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
1577 break;
1578
1579 if (!(crecp->flags & F_DNSSECOK))
1580 sec_data = 0;
1581
1582 if (crecp->flags & F_CNAME)
1583 {
1584 char *cname_target = cache_get_cname_target(crecp);
1585
1586 if (!dryrun)
1587 {
1588 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1589 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1590 crec_ttl(crecp, now), &nameoffset,
1591 T_CNAME, C_IN, "d", cname_target))
1592 anscount++;
1593 }
1594
1595 strcpy(name, cname_target);
1596 /* check if target interface_name */
Andy3e21a1a2014-03-22 19:10:07 +00001597 if (crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelley824202e2014-01-23 20:59:46 +00001598 goto intname_restart;
1599 else
1600 goto cname_restart;
1601 }
1602
1603 if (crecp->flags & F_NEG)
1604 {
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001605 ans = 1;
1606 auth = 0;
1607 if (crecp->flags & F_NXDOMAIN)
1608 nxdomain = 1;
1609 if (!dryrun)
1610 log_query(crecp->flags, name, NULL, NULL);
Simon Kelley824202e2014-01-23 20:59:46 +00001611 }
1612 else
1613 {
1614 /* If we are returning local answers depending on network,
1615 filter here. */
1616 if (localise &&
1617 (crecp->flags & F_HOSTS) &&
1618 !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
1619 continue;
1620
1621 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
1622 auth = 0;
1623
1624 ans = 1;
1625 if (!dryrun)
1626 {
1627 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
1628 record_source(crecp->uid));
1629
1630 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1631 crec_ttl(crecp, now), NULL, type, C_IN,
1632 type == T_A ? "4" : "6", &crecp->addr))
1633 anscount++;
1634 }
1635 }
1636 } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001637 }
Simon Kelley2bb73af2013-04-24 17:38:19 +01001638 else if (is_name_synthetic(flag, name, &addr))
1639 {
1640 ans = 1;
1641 if (!dryrun)
1642 {
1643 log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
1644 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1645 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
1646 anscount++;
1647 }
1648 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001649 }
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001650
1651 if (qtype == T_CNAME || qtype == T_ANY)
1652 {
1653 if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00001654 (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001655 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001656 if (!(crecp->flags & F_DNSSECOK))
1657 sec_data = 0;
1658
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001659 ans = 1;
1660 if (!dryrun)
1661 {
1662 log_query(crecp->flags, name, NULL, record_source(crecp->uid));
1663 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
1664 crec_ttl(crecp, now), &nameoffset,
Simon Kelleyd56a6042013-10-11 14:39:03 +01001665 T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
Simon Kelleyd1c759c2012-04-16 17:26:19 +01001666 anscount++;
1667 }
1668 }
1669 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001670
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001671 if (qtype == T_MX || qtype == T_ANY)
1672 {
1673 int found = 0;
Simon Kelley0a852542005-03-23 20:28:59 +00001674 for (rec = daemon->mxnames; rec; rec = rec->next)
1675 if (!rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001676 {
1677 ans = found = 1;
1678 if (!dryrun)
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001679 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001680 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001681 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelley0a852542005-03-23 20:28:59 +00001682 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1683 &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
1684 {
1685 anscount++;
1686 if (rec->target)
1687 rec->offset = offset;
1688 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001689 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001690 }
1691
Simon Kelley28866e92011-02-14 20:19:14 +00001692 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
Simon Kelley12fae492014-02-04 22:03:06 +00001693 cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001694 {
1695 ans = 1;
1696 if (!dryrun)
1697 {
Simon Kelley28866e92011-02-14 20:19:14 +00001698 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001699 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
1700 T_MX, C_IN, "sd", 1,
Simon Kelley28866e92011-02-14 20:19:14 +00001701 option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001702 anscount++;
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001703 }
1704 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001705 }
1706
1707 if (qtype == T_SRV || qtype == T_ANY)
1708 {
1709 int found = 0;
Simon Kelley28866e92011-02-14 20:19:14 +00001710 struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
1711
Simon Kelley0a852542005-03-23 20:28:59 +00001712 for (rec = daemon->mxnames; rec; rec = rec->next)
1713 if (rec->issrv && hostname_isequal(name, rec->name))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001714 {
1715 found = ans = 1;
1716 if (!dryrun)
1717 {
Simon Kelleye1ff4192012-12-09 17:08:47 +00001718 int offset;
Simon Kelley28866e92011-02-14 20:19:14 +00001719 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001720 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
Simon Kelley0a852542005-03-23 20:28:59 +00001721 &offset, T_SRV, C_IN, "sssd",
1722 rec->priority, rec->weight, rec->srvport, rec->target))
1723 {
1724 anscount++;
1725 if (rec->target)
1726 rec->offset = offset;
1727 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001728 }
Simon Kelley28866e92011-02-14 20:19:14 +00001729
1730 /* unlink first SRV record found */
1731 if (!move)
1732 {
1733 move = rec;
1734 *up = rec->next;
1735 }
1736 else
1737 up = &rec->next;
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001738 }
Simon Kelley28866e92011-02-14 20:19:14 +00001739 else
1740 up = &rec->next;
1741
1742 /* put first SRV record back at the end. */
1743 if (move)
1744 {
1745 *up = move;
1746 move->next = NULL;
1747 }
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001748
Simon Kelley28866e92011-02-14 20:19:14 +00001749 if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001750 {
1751 ans = 1;
1752 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001753 log_query(F_CONFIG | F_NEG, name, NULL, NULL);
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001754 }
1755 }
Simon Kelley1a6bca82008-07-11 11:11:42 +01001756
1757 if (qtype == T_NAPTR || qtype == T_ANY)
1758 {
1759 struct naptr *na;
1760 for (na = daemon->naptr; na; na = na->next)
1761 if (hostname_isequal(name, na->name))
1762 {
1763 ans = 1;
1764 if (!dryrun)
1765 {
Simon Kelley28866e92011-02-14 20:19:14 +00001766 log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Simon Kelley1a6bca82008-07-11 11:11:42 +01001767 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
1768 NULL, T_NAPTR, C_IN, "sszzzd",
1769 na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
1770 anscount++;
1771 }
1772 }
1773 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001774
1775 if (qtype == T_MAILB)
1776 ans = 1, nxdomain = 1;
1777
Simon Kelley28866e92011-02-14 20:19:14 +00001778 if (qtype == T_SOA && option_bool(OPT_FILTER))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001779 {
1780 ans = 1;
1781 if (!dryrun)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001782 log_query(F_CONFIG | F_NEG, name, &addr, NULL);
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001783 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001784 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001785
1786 if (!ans)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001787 return 0; /* failed to answer a question */
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001788 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +00001789
Simon Kelleyfeba5c12004-07-27 20:28:58 +01001790 if (dryrun)
1791 {
1792 dryrun = 0;
1793 goto rerun;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001794 }
1795
Simon Kelley0a852542005-03-23 20:28:59 +00001796 /* create an additional data section, for stuff in SRV and MX record replies. */
1797 for (rec = daemon->mxnames; rec; rec = rec->next)
1798 if (rec->offset != 0)
1799 {
1800 /* squash dupes */
1801 struct mx_srv_record *tmp;
1802 for (tmp = rec->next; tmp; tmp = tmp->next)
1803 if (tmp->offset != 0 && hostname_isequal(rec->target, tmp->target))
1804 tmp->offset = 0;
1805
1806 crecp = NULL;
1807 while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
1808 {
Simon Kelley0a852542005-03-23 20:28:59 +00001809#ifdef HAVE_IPV6
1810 int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
1811#else
1812 int type = T_A;
1813#endif
1814 if (crecp->flags & F_NEG)
1815 continue;
1816
Simon Kelley9009d742008-11-14 20:04:27 +00001817 if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
1818 crec_ttl(crecp, now), NULL, type, C_IN,
Simon Kelley0a852542005-03-23 20:28:59 +00001819 crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
1820 addncount++;
1821 }
1822 }
1823
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001824 /* done all questions, set up header and return length of result */
Simon Kelley572b41e2011-02-18 18:11:18 +00001825 /* clear authoritative and truncated flags, set QR flag */
1826 header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
1827 /* set RA flag */
1828 header->hb4 |= HB4_RA;
1829
1830 /* authoritive - only hosts and DHCP derived names. */
1831 if (auth)
1832 header->hb3 |= HB3_AA;
1833
1834 /* truncation */
1835 if (trunc)
1836 header->hb3 |= HB3_TC;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001837
Simon Kelley45cca582013-10-15 10:20:13 +01001838 if (nxdomain)
Simon Kelley572b41e2011-02-18 18:11:18 +00001839 SET_RCODE(header, NXDOMAIN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001840 else
Simon Kelley572b41e2011-02-18 18:11:18 +00001841 SET_RCODE(header, NOERROR); /* no error */
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001842 header->ancount = htons(anscount);
1843 header->nscount = htons(0);
Simon Kelley0a852542005-03-23 20:28:59 +00001844 header->arcount = htons(addncount);
Simon Kelleye243c072014-02-06 18:14:09 +00001845
Simon Kelleya25720a2014-01-14 23:13:55 +00001846 len = ansp - (unsigned char *)header;
1847
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001848 /* Advertise our packet size limit in our reply */
Simon Kelleya25720a2014-01-14 23:13:55 +00001849 if (have_pseudoheader)
Simon Kelleyc7f3bd22016-02-28 21:48:34 +00001850 len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
Simon Kelleye243c072014-02-06 18:14:09 +00001851
Simon Kelleyfa14bec2015-12-20 17:12:16 +00001852 if (ad_reqd && sec_data)
Simon Kelleye243c072014-02-06 18:14:09 +00001853 header->hb4 |= HB4_AD;
Simon Kelley83349b82014-02-10 21:02:01 +00001854 else
1855 header->hb4 &= ~HB4_AD;
Simon Kelleya25720a2014-01-14 23:13:55 +00001856
Simon Kelley7c286122014-01-27 21:38:11 +00001857 return len;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001858}