blob: 2f2c519cd49a5512b36e5814ddb3a270bf7fd01c [file] [log] [blame]
Simon Kelley2a8710a2020-01-05 16:40:06 +00001/* dnsmasq is Copyright (c) 2000-2020 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 Kelley5aabfc72007-08-29 11:24:47 +010019static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +010020#ifdef HAVE_DHCP
21static struct crec *dhcp_spare = NULL;
22#endif
23static struct crec *new_chain = NULL;
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +010024static int insert_error;
Simon Kelley5aabfc72007-08-29 11:24:47 +010025static union bigname *big_free = NULL;
26static int bignames_left, hash_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000027
Simon Kelleyb6f926f2018-08-21 17:46:52 +010028static void make_non_terminals(struct crec *source);
Simon Kelleycc921df2019-01-02 22:48:59 +000029static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
Simon Kelley5b99eae2019-01-06 23:09:50 +000030 time_t now, unsigned long ttl, unsigned int flags);
Simon Kelleyb6f926f2018-08-21 17:46:52 +010031
Simon Kelley16972692006-10-16 20:04:18 +010032/* type->string mapping: this is also used by the name-hash function as a mixing table. */
33static const struct {
34 unsigned int type;
35 const char * const name;
36} typestr[] = {
37 { 1, "A" },
38 { 2, "NS" },
39 { 5, "CNAME" },
40 { 6, "SOA" },
41 { 10, "NULL" },
42 { 11, "WKS" },
43 { 12, "PTR" },
44 { 13, "HINFO" },
45 { 15, "MX" },
46 { 16, "TXT" },
47 { 22, "NSAP" },
48 { 23, "NSAP_PTR" },
49 { 24, "SIG" },
50 { 25, "KEY" },
51 { 28, "AAAA" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010052 { 29, "LOC" },
Simon Kelley16972692006-10-16 20:04:18 +010053 { 33, "SRV" },
Simon Kelley1a6bca82008-07-11 11:11:42 +010054 { 35, "NAPTR" },
Simon Kelley16972692006-10-16 20:04:18 +010055 { 36, "KX" },
56 { 37, "CERT" },
57 { 38, "A6" },
58 { 39, "DNAME" },
59 { 41, "OPT" },
Simon Kelley0fc2f312014-01-08 10:26:58 +000060 { 43, "DS" },
61 { 46, "RRSIG" },
Simon Kelley610e7822014-02-06 14:45:17 +000062 { 47, "NSEC" },
Simon Kelley832af0b2007-01-21 20:01:28 +000063 { 48, "DNSKEY" },
Simon Kelley610e7822014-02-06 14:45:17 +000064 { 50, "NSEC3" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010065 { 51, "NSEC3PARAM" },
66 { 52, "TLSA" },
67 { 53, "SMIMEA" },
68 { 55, "HIP" },
Simon Kelley832af0b2007-01-21 20:01:28 +000069 { 249, "TKEY" },
Simon Kelley16972692006-10-16 20:04:18 +010070 { 250, "TSIG" },
71 { 251, "IXFR" },
72 { 252, "AXFR" },
73 { 253, "MAILB" },
74 { 254, "MAILA" },
Simon Kelleyb758b672018-08-23 21:41:23 +010075 { 255, "ANY" },
76 { 257, "CAA" }
Simon Kelley16972692006-10-16 20:04:18 +010077};
78
Simon Kelley9e4abcb2004-01-22 19:47:41 +000079static void cache_free(struct crec *crecp);
80static void cache_unlink(struct crec *crecp);
81static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010082static void rehash(int size);
83static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084
Simon Kelley45d8a242018-07-17 21:01:14 +010085void next_uid(struct crec *crecp)
Simon Kelley3f7483e2014-03-16 22:56:58 +000086{
Andyd5082152014-03-17 19:50:29 +000087 static unsigned int uid = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +000088
Simon Kelley45d8a242018-07-17 21:01:14 +010089 if (crecp->uid == UID_NONE)
90 {
91 uid++;
Andyd5082152014-03-17 19:50:29 +000092
Simon Kelley45d8a242018-07-17 21:01:14 +010093 /* uid == 0 used to indicate CNAME to interface name. */
94 if (uid == UID_NONE)
95 uid++;
96
97 crecp->uid = uid;
98 }
Simon Kelley3f7483e2014-03-16 22:56:58 +000099}
100
Simon Kelley5aabfc72007-08-29 11:24:47 +0100101void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000102{
103 struct crec *crecp;
104 int i;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100105
Simon Kelley5aabfc72007-08-29 11:24:47 +0100106 bignames_left = daemon->cachesize/10;
107
108 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100110 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000111
Simon Kelley5aabfc72007-08-29 11:24:47 +0100112 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000113 {
114 cache_link(crecp);
115 crecp->flags = 0;
Simon Kelley45d8a242018-07-17 21:01:14 +0100116 crecp->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000117 }
118 }
119
Simon Kelley4011c4e2006-10-28 16:26:19 +0100120 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +0100121 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000122}
123
Simon Kelley4011c4e2006-10-28 16:26:19 +0100124/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
125 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
126 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
127 expand the table. */
128static void rehash(int size)
129{
130 struct crec **new, **old, *p, *tmp;
131 int i, new_size, old_size;
132
133 /* hash_size is a power of two. */
134 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
135
136 /* must succeed in getting first instance, failure later is non-fatal */
137 if (!hash_table)
138 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100139 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100140 return;
141
142 for(i = 0; i < new_size; i++)
143 new[i] = NULL;
144
145 old = hash_table;
146 old_size = hash_size;
147 hash_table = new;
148 hash_size = new_size;
149
150 if (old)
151 {
152 for (i = 0; i < old_size; i++)
153 for (p = old[i]; p ; p = tmp)
154 {
155 tmp = p->hash_next;
156 cache_hash(p);
157 }
158 free(old);
159 }
160}
161
Simon Kelley3d8df262005-08-29 12:19:27 +0100162static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000163{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100164 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100165 const unsigned char *mix_tab = (const unsigned char*)typestr;
166
Simon Kelley3d8df262005-08-29 12:19:27 +0100167 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100168 {
169 /* don't use tolower and friends here - they may be messed up by LOCALE */
170 if (c >= 'A' && c <= 'Z')
171 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100172 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100173 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000174
175 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100176 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000177}
178
179static void cache_hash(struct crec *crecp)
180{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000181 /* maintain an invariant that all entries with F_REVERSE set
182 are at the start of the hash-chain and all non-reverse
183 immortal entries are at the end of the hash-chain.
184 This allows reverse searches and garbage collection to be optimised */
185
186 struct crec **up = hash_bucket(cache_get_name(crecp));
187
188 if (!(crecp->flags & F_REVERSE))
189 {
190 while (*up && ((*up)->flags & F_REVERSE))
191 up = &((*up)->hash_next);
192
193 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000194 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000195 up = &((*up)->hash_next);
196 }
197 crecp->hash_next = *up;
198 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000199}
Simon Kelley82e3f452014-01-31 21:05:48 +0000200
Simon Kelley82e3f452014-01-31 21:05:48 +0000201static void cache_blockdata_free(struct crec *crecp)
202{
Simon Kelley4bf62f62019-01-10 21:54:22 +0000203 if (!(crecp->flags & F_NEG))
204 {
205 if (crecp->flags & F_SRV)
206 blockdata_free(crecp->addr.srv.target);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000207#ifdef HAVE_DNSSEC
Simon Kelley4bf62f62019-01-10 21:54:22 +0000208 else if (crecp->flags & F_DNSKEY)
209 blockdata_free(crecp->addr.key.keydata);
210 else if (crecp->flags & F_DS)
211 blockdata_free(crecp->addr.ds.keydata);
Simon Kelley82e3f452014-01-31 21:05:48 +0000212#endif
Simon Kelley4bf62f62019-01-10 21:54:22 +0000213 }
Simon Kelley5b99eae2019-01-06 23:09:50 +0000214}
Simon Kelley82e3f452014-01-31 21:05:48 +0000215
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000216static void cache_free(struct crec *crecp)
217{
218 crecp->flags &= ~F_FORWARD;
219 crecp->flags &= ~F_REVERSE;
Simon Kelley45d8a242018-07-17 21:01:14 +0100220 crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100221
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000222 if (cache_tail)
223 cache_tail->next = crecp;
224 else
225 cache_head = crecp;
226 crecp->prev = cache_tail;
227 crecp->next = NULL;
228 cache_tail = crecp;
229
230 /* retrieve big name for further use. */
231 if (crecp->flags & F_BIGNAME)
232 {
233 crecp->name.bname->next = big_free;
234 big_free = crecp->name.bname;
235 crecp->flags &= ~F_BIGNAME;
236 }
Simon Kelley072e81b2014-01-31 12:42:54 +0000237
Simon Kelley82e3f452014-01-31 21:05:48 +0000238 cache_blockdata_free(crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000239}
240
241/* insert a new cache entry at the head of the list (youngest entry) */
242static void cache_link(struct crec *crecp)
243{
244 if (cache_head) /* check needed for init code */
245 cache_head->prev = crecp;
246 crecp->next = cache_head;
247 crecp->prev = NULL;
248 cache_head = crecp;
249 if (!cache_tail)
250 cache_tail = crecp;
251}
252
253/* remove an arbitrary cache entry for promotion */
254static void cache_unlink (struct crec *crecp)
255{
256 if (crecp->prev)
257 crecp->prev->next = crecp->next;
258 else
259 cache_head = crecp->next;
260
261 if (crecp->next)
262 crecp->next->prev = crecp->prev;
263 else
264 cache_tail = crecp->prev;
265}
266
267char *cache_get_name(struct crec *crecp)
268{
269 if (crecp->flags & F_BIGNAME)
270 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000271 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000272 return crecp->name.namep;
273
274 return crecp->name.sname;
275}
276
Simon Kelleyd56a6042013-10-11 14:39:03 +0100277char *cache_get_cname_target(struct crec *crecp)
278{
Simon Kelley1fd56c02019-10-30 12:58:28 +0000279 if (crecp->addr.cname.is_name_ptr)
280 return crecp->addr.cname.target.name;
281 else
Simon Kelleyd56a6042013-10-11 14:39:03 +0100282 return cache_get_name(crecp->addr.cname.target.cache);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100283}
284
285
286
Simon Kelleyb75e9362012-12-07 11:50:41 +0000287struct crec *cache_enumerate(int init)
288{
289 static int bucket;
290 static struct crec *cache;
291
292 if (init)
293 {
294 bucket = 0;
295 cache = NULL;
296 }
297 else if (cache && cache->hash_next)
298 cache = cache->hash_next;
299 else
300 {
301 cache = NULL;
302 while (bucket < hash_size)
303 if ((cache = hash_table[bucket++]))
304 break;
305 }
306
307 return cache;
308}
309
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100310static int is_outdated_cname_pointer(struct crec *crecp)
311{
Simon Kelley1fd56c02019-10-30 12:58:28 +0000312 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.is_name_ptr)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100313 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100314
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100315 /* NB. record may be reused as DS or DNSKEY, where uid is
316 overloaded for something completely different */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100317 if (crecp->addr.cname.target.cache &&
Simon Kelley2896e242019-01-09 15:12:34 +0000318 !(crecp->addr.cname.target.cache->flags & (F_DNSKEY | F_DS)) &&
Simon Kelleyd56a6042013-10-11 14:39:03 +0100319 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100320 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100321
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100322 return 1;
323}
324
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000325static int is_expired(time_t now, struct crec *crecp)
326{
327 if (crecp->flags & F_IMMORTAL)
328 return 0;
329
330 if (difftime(now, crecp->ttd) < 0)
331 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100332
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000333 return 1;
334}
335
Simon Kelleycc921df2019-01-02 22:48:59 +0000336static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now,
Simon Kelley5b99eae2019-01-06 23:09:50 +0000337 unsigned int flags, struct crec **target_crec, unsigned int *target_uid)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000338{
339 /* Scan and remove old entries.
340 If (flags & F_FORWARD) then remove any forward entries for name and any expired
341 entries but only in the same hash bucket as name.
342 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
343 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000344 If (flags == 0) remove any expired entries in the whole cache.
345
Simon Kelleycbc65242014-12-21 21:21:53 +0000346 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
347 to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000348
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000349 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100350 so that when we hit an entry which isn't reverse and is immortal, we're done.
351
352 If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid.
353 This entry will get re-used with the same name, to preserve CNAMEs. */
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000354
355 struct crec *crecp, **up;
Simon Kelley65a01b72018-12-31 23:56:33 +0000356
357 (void)class;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000358
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000359 if (flags & F_FORWARD)
360 {
Simon Kelley6b010842007-02-12 20:32:07 +0000361 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000362 {
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000363 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
364 {
Simon Kelleye7829ae2014-01-22 22:21:51 +0000365 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
Simon Kelley5b99eae2019-01-06 23:09:50 +0000366 if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
Simon Kelley6429e422014-01-23 12:09:36 +0000367 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000368 {
369 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelleycbc65242014-12-21 21:21:53 +0000370 return crecp;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000371 *up = crecp->hash_next;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100372 /* If this record is for the name we're inserting and is the target
373 of a CNAME record. Make the new record for the same name, in the same
374 crec, with the same uid to avoid breaking the existing CNAME. */
375 if (crecp->uid != UID_NONE)
376 {
377 if (target_crec)
378 *target_crec = crecp;
379 if (target_uid)
380 *target_uid = crecp->uid;
381 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000382 cache_unlink(crecp);
383 cache_free(crecp);
384 continue;
385 }
386
387#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000388 /* Deletion has to be class-sensitive for DS and DNSKEY */
Simon Kelley65a01b72018-12-31 23:56:33 +0000389 if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == class)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000390 {
Simon Kelley824202e2014-01-23 20:59:46 +0000391 if (crecp->flags & F_CONFIG)
Simon Kelleycbc65242014-12-21 21:21:53 +0000392 return crecp;
Simon Kelley824202e2014-01-23 20:59:46 +0000393 *up = crecp->hash_next;
394 cache_unlink(crecp);
395 cache_free(crecp);
396 continue;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000397 }
398#endif
399 }
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100400
401 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
402 {
403 *up = crecp->hash_next;
404 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
405 {
406 cache_unlink(crecp);
407 cache_free(crecp);
408 }
409 continue;
410 }
411
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000412 up = &crecp->hash_next;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000413 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000414 }
415 else
416 {
417 int i;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000418 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
Simon Kelleyee875042018-10-23 22:10:17 +0100419
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000420 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000421 for (crecp = hash_table[i], up = &hash_table[i];
422 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
423 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000424 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000425 {
426 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000427 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000428 {
429 cache_unlink(crecp);
430 cache_free(crecp);
431 }
432 }
Simon Kelley25439062013-11-25 21:14:51 +0000433 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000434 (flags & crecp->flags & F_REVERSE) &&
435 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000436 memcmp(&crecp->addr, addr, addrlen) == 0)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000437 {
438 *up = crecp->hash_next;
439 cache_unlink(crecp);
440 cache_free(crecp);
441 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000442 else
443 up = &crecp->hash_next;
444 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000445
Simon Kelleycbc65242014-12-21 21:21:53 +0000446 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000447}
448
449/* Note: The normal calling sequence is
450 cache_start_insert
451 cache_insert * n
452 cache_end_insert
453
454 but an abort can cause the cache_end_insert to be missed
455 in which can the next cache_start_insert cleans things up. */
456
457void cache_start_insert(void)
458{
459 /* Free any entries which didn't get committed during the last
460 insert due to error.
461 */
462 while (new_chain)
463 {
464 struct crec *tmp = new_chain->next;
465 cache_free(new_chain);
466 new_chain = tmp;
467 }
468 new_chain = NULL;
469 insert_error = 0;
470}
Simon Kelleya799ca02018-10-18 19:35:29 +0100471
Simon Kelleycc921df2019-01-02 22:48:59 +0000472struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
Simon Kelley5b99eae2019-01-06 23:09:50 +0000473 time_t now, unsigned long ttl, unsigned int flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000474{
Simon Kelley7e194a02020-07-12 17:43:25 +0100475#ifdef HAVE_DNSSEC
476 if (flags & (F_DNSKEY | F_DS))
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000477 {
Simon Kelley7e194a02020-07-12 17:43:25 +0100478 /* The DNSSEC validation process works by getting needed records into the
479 cache, then retrying the validation until they are all in place.
480 This can be messed up by very short TTLs, and _really_ messed up by
481 zero TTLs, so we force the TTL to be at least long enough to do a validation.
482 Ideally, we should use some kind of reference counting so that records are
483 locked until the validation that asked for them is complete, but this
484 is much easier, and just as effective. */
485 if (ttl < DNSSEC_MIN_TTL)
486 ttl = DNSSEC_MIN_TTL;
487 }
488 else
489#endif
490 {
491 /* Don't log DNSSEC records here, done elsewhere */
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000492 log_query(flags | F_UPSTREAM, name, addr, NULL);
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000493 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
494 ttl = daemon->max_cache_ttl;
RinSatsuki28de3872015-01-10 15:22:21 +0000495 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
496 ttl = daemon->min_cache_ttl;
Simon Kelley7e194a02020-07-12 17:43:25 +0100497 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100498
Simon Kelley65a01b72018-12-31 23:56:33 +0000499 return really_insert(name, addr, class, now, ttl, flags);
Simon Kelleya799ca02018-10-18 19:35:29 +0100500}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000501
Simon Kelleya799ca02018-10-18 19:35:29 +0100502
Simon Kelleycc921df2019-01-02 22:48:59 +0000503static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
Simon Kelley5b99eae2019-01-06 23:09:50 +0000504 time_t now, unsigned long ttl, unsigned int flags)
Simon Kelleya799ca02018-10-18 19:35:29 +0100505{
506 struct crec *new, *target_crec = NULL;
507 union bigname *big_name = NULL;
508 int freed_all = flags & F_REVERSE;
509 int free_avail = 0;
510 unsigned int target_uid;
511
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000512 /* if previous insertion failed give up now. */
513 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100514 return NULL;
Simon Kelley1292e1a2019-10-25 17:31:53 +0100515
516 /* we don't cache zero-TTL records. */
517 if (ttl == 0)
518 {
519 insert_error = 1;
520 return NULL;
521 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000522
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000523 /* First remove any expired entries and entries for the name/address we
Simon Kelleycbc65242014-12-21 21:21:53 +0000524 are currently inserting. */
Simon Kelley65a01b72018-12-31 23:56:33 +0000525 if ((new = cache_scan_free(name, addr, class, now, flags, &target_crec, &target_uid)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000526 {
Simon Kelleycbc65242014-12-21 21:21:53 +0000527 /* We're trying to insert a record over one from
528 /etc/hosts or DHCP, or other config. If the
Simon Kelley84449bf2019-10-29 22:24:19 +0000529 existing record is for an A or AAAA or CNAME and
Simon Kelleycbc65242014-12-21 21:21:53 +0000530 the record we're trying to insert is the same,
531 just drop the insert, but don't error the whole process. */
Edwin Török41a8d9e2015-11-14 17:45:48 +0000532 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000533 {
534 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000535 new->addr.addr4.s_addr == addr->addr4.s_addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000536 return new;
Simon Kelleycbc65242014-12-21 21:21:53 +0000537 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000538 IN6_ARE_ADDR_EQUAL(&new->addr.addr6, &addr->addr6))
Simon Kelleycbc65242014-12-21 21:21:53 +0000539 return new;
Simon Kelleycbc65242014-12-21 21:21:53 +0000540 }
Simon Kelley84449bf2019-10-29 22:24:19 +0000541
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000542 insert_error = 1;
543 return NULL;
544 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000545
546 /* Now get a cache entry from the end of the LRU list */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100547 if (!target_crec)
548 while (1) {
549 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
550 {
551 insert_error = 1;
552 return NULL;
553 }
554
555 /* Free entry at end of LRU list, use it. */
556 if (!(new->flags & (F_FORWARD | F_REVERSE)))
557 break;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000558
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100559 /* End of LRU list is still in use: if we didn't scan all the hash
560 chains for expired entries do that now. If we already tried that
561 then it's time to start spilling things. */
562
563 /* If free_avail set, we believe that an entry has been freed.
564 Bugs have been known to make this not true, resulting in
565 a tight loop here. If that happens, abandon the
566 insert. Once in this state, all inserts will probably fail. */
567 if (free_avail)
568 {
569 static int warned = 0;
570 if (!warned)
571 {
572 my_syslog(LOG_ERR, _("Internal error in cache."));
573 warned = 1;
574 }
575 insert_error = 1;
576 return NULL;
577 }
578
579 if (freed_all)
580 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000581 /* For DNSSEC records, uid holds class. */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100582 free_avail = 1; /* Must be free space now. */
Simon Kelleycc921df2019-01-02 22:48:59 +0000583 cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100584 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100585 }
586 else
587 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000588 cache_scan_free(NULL, NULL, class, now, 0, NULL, NULL);
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100589 freed_all = 1;
590 }
591 }
592
593 /* Check if we need to and can allocate extra memory for a long name.
594 If that fails, give up now, always succeed for DNSSEC records. */
595 if (name && (strlen(name) > SMALLDNAME-1))
596 {
597 if (big_free)
598 {
599 big_name = big_free;
600 big_free = big_free->next;
601 }
602 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
603 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
604 {
605 insert_error = 1;
606 return NULL;
607 }
608 else if (bignames_left != 0)
609 bignames_left--;
610
611 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000612
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100613 /* If we freed a cache entry for our name which was a CNAME target, use that.
614 and preserve the uid, so that existing CNAMES are not broken. */
615 if (target_crec)
616 {
617 new = target_crec;
618 new->uid = target_uid;
619 }
620
621 /* Got the rest: finally grab entry. */
622 cache_unlink(new);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000623
624 new->flags = flags;
625 if (big_name)
626 {
627 new->name.bname = big_name;
628 new->flags |= F_BIGNAME;
629 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100630
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631 if (name)
632 strcpy(cache_get_name(new), name);
633 else
634 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100635
Simon Kelleyb8eac192014-02-27 14:30:03 +0000636#ifdef HAVE_DNSSEC
Simon Kelley65a01b72018-12-31 23:56:33 +0000637 if (flags & (F_DS | F_DNSKEY))
638 new->uid = class;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000639#endif
Simon Kelley65a01b72018-12-31 23:56:33 +0000640
641 if (addr)
Simon Kelleycc921df2019-01-02 22:48:59 +0000642 new->addr = *addr;
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100643
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000644 new->ttd = now + (time_t)ttl;
645 new->next = new_chain;
646 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100647
648 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000649}
650
651/* after end of insertion, commit the new entries */
652void cache_end_insert(void)
653{
654 if (insert_error)
655 return;
656
657 while (new_chain)
658 {
659 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100660 /* drop CNAMEs which didn't find a target. */
661 if (is_outdated_cname_pointer(new_chain))
662 cache_free(new_chain);
663 else
664 {
665 cache_hash(new_chain);
666 cache_link(new_chain);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100667 daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
Simon Kelleya799ca02018-10-18 19:35:29 +0100668
669 /* If we're a child process, send this cache entry up the pipe to the master.
670 The marshalling process is rather nasty. */
671 if (daemon->pipe_to_parent != -1)
672 {
673 char *name = cache_get_name(new_chain);
674 ssize_t m = strlen(name);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000675 unsigned int flags = new_chain->flags;
Simon Kelleya799ca02018-10-18 19:35:29 +0100676#ifdef HAVE_DNSSEC
677 u16 class = new_chain->uid;
678#endif
679
680 read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
681 read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
682 read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
683 read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
684
Simon Kelley5b99eae2019-01-06 23:09:50 +0000685 if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
Simon Kelleya799ca02018-10-18 19:35:29 +0100686 read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000687 if (flags & F_SRV)
Alin Nastace710c342019-09-30 15:30:26 +0100688 {
689 /* A negative SRV entry is possible and has no data, obviously. */
690 if (!(flags & F_NEG))
691 blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
692 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100693#ifdef HAVE_DNSSEC
Simon Kelleyab194ed2019-01-01 01:35:30 +0000694 if (flags & F_DNSKEY)
Simon Kelleya799ca02018-10-18 19:35:29 +0100695 {
696 read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
Simon Kelleycc921df2019-01-02 22:48:59 +0000697 blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
Simon Kelleya799ca02018-10-18 19:35:29 +0100698 }
699 else if (flags & F_DS)
700 {
701 read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
702 /* A negative DS entry is possible and has no data, obviously. */
703 if (!(flags & F_NEG))
Simon Kelleycc921df2019-01-02 22:48:59 +0000704 blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
Simon Kelleya799ca02018-10-18 19:35:29 +0100705 }
706#endif
Simon Kelleya799ca02018-10-18 19:35:29 +0100707 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100708 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100709
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000710 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000711 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100712
713 /* signal end of cache insert in master process */
714 if (daemon->pipe_to_parent != -1)
715 {
716 ssize_t m = -1;
717 read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
718 }
719
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000720 new_chain = NULL;
721}
722
Simon Kelleya799ca02018-10-18 19:35:29 +0100723
724/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */
725int cache_recv_insert(time_t now, int fd)
726{
727 ssize_t m;
Simon Kelleycc921df2019-01-02 22:48:59 +0000728 union all_addr addr;
Simon Kelleya799ca02018-10-18 19:35:29 +0100729 unsigned long ttl;
730 time_t ttd;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000731 unsigned int flags;
Simon Kelleya799ca02018-10-18 19:35:29 +0100732 struct crec *crecp = NULL;
733
734 cache_start_insert();
735
736 while(1)
737 {
738
739 if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
740 return 0;
741
742 if (m == -1)
743 {
744 cache_end_insert();
745 return 1;
746 }
747
748 if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
749 !read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
750 !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
751 return 0;
752
753 daemon->namebuff[m] = 0;
754
755 ttl = difftime(ttd, now);
756
Simon Kelley5b99eae2019-01-06 23:09:50 +0000757 if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
Simon Kelleya799ca02018-10-18 19:35:29 +0100758 {
Simon Kelleyab194ed2019-01-01 01:35:30 +0000759 unsigned short class = C_IN;
760
Simon Kelleya799ca02018-10-18 19:35:29 +0100761 if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
762 return 0;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000763
Alin Nastace710c342019-09-30 15:30:26 +0100764 if ((flags & F_SRV) && !(flags & F_NEG) && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
Simon Kelley5b99eae2019-01-06 23:09:50 +0000765 return 0;
766
Simon Kelleyab194ed2019-01-01 01:35:30 +0000767#ifdef HAVE_DNSSEC
768 if (flags & F_DNSKEY)
769 {
770 if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
Simon Kelleycc921df2019-01-02 22:48:59 +0000771 !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
Simon Kelleyab194ed2019-01-01 01:35:30 +0000772 return 0;
773 }
774 else if (flags & F_DS)
775 {
776 if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
Simon Kelley2c594732019-01-03 13:42:03 +0000777 (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
Simon Kelleyab194ed2019-01-01 01:35:30 +0000778 return 0;
779 }
780#endif
781
782 crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
Simon Kelleya799ca02018-10-18 19:35:29 +0100783 }
784 else if (flags & F_CNAME)
785 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000786 struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
Ville Skyttäbf23c8a2019-12-05 16:50:57 +0000787 /* This relies on the fact that the target of a CNAME immediately precedes
Simon Kelleya799ca02018-10-18 19:35:29 +0100788 it because of the order of extraction in extract_addresses, and
789 the order reversal on the new_chain. */
790 if (newc)
791 {
Simon Kelley1fd56c02019-10-30 12:58:28 +0000792 newc->addr.cname.is_name_ptr = 0;
793
794 if (!crecp)
795 newc->addr.cname.target.cache = NULL;
796 else
Simon Kelleya799ca02018-10-18 19:35:29 +0100797 {
798 next_uid(crecp);
799 newc->addr.cname.target.cache = crecp;
800 newc->addr.cname.uid = crecp->uid;
801 }
802 }
803 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100804 }
805}
806
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100807int cache_find_non_terminal(char *name, time_t now)
808{
809 struct crec *crecp;
810
811 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
812 if (!is_outdated_cname_pointer(crecp) &&
813 !is_expired(now, crecp) &&
814 (crecp->flags & F_FORWARD) &&
Sven Mueller162e5e02019-02-27 21:17:37 +0000815 !(crecp->flags & F_NXDOMAIN) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100816 hostname_isequal(name, cache_get_name(crecp)))
817 return 1;
818
819 return 0;
820}
821
Simon Kelley12fae492014-02-04 22:03:06 +0000822struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000823{
824 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000825 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000826
Simon Kelley12fae492014-02-04 22:03:06 +0000827 prot &= ~F_NO_RR;
828
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000829 if (crecp) /* iterating */
830 ans = crecp->next;
831 else
832 {
833 /* first search, look for relevant entries and push to top of list
834 also free anything which has expired */
835 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000836 unsigned int ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000837
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000838 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
839 {
840 next = crecp->hash_next;
841
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000842 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000843 {
844 if ((crecp->flags & F_FORWARD) &&
845 (crecp->flags & prot) &&
846 hostname_isequal(cache_get_name(crecp), name))
847 {
Simon Kelley25439062013-11-25 21:14:51 +0000848 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000849 {
850 *chainp = crecp;
851 chainp = &crecp->next;
852 }
853 else
854 {
855 cache_unlink(crecp);
856 cache_link(crecp);
857 }
858
Simon Kelley824af852008-02-12 20:43:05 +0000859 /* Move all but the first entry up the hash chain
860 this implements round-robin.
861 Make sure that re-ordering doesn't break the hash-chain
862 order invariants.
863 */
Simon Kelley9e038942008-05-30 20:06:34 +0100864 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000865 {
866 *up = crecp->hash_next;
867 crecp->hash_next = *insert;
868 *insert = crecp;
869 insert = &crecp->hash_next;
870 }
Simon Kelley9e038942008-05-30 20:06:34 +0100871 else
872 {
Simon Kelley12fae492014-02-04 22:03:06 +0000873 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100874 {
875 insert = up;
876 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
877 }
878 up = &crecp->hash_next;
879 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000880 }
881 else
882 /* case : not expired, incorrect entry. */
883 up = &crecp->hash_next;
884 }
885 else
886 {
887 /* expired entry, free it */
888 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000889 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000890 {
891 cache_unlink(crecp);
892 cache_free(crecp);
893 }
894 }
895 }
896
897 *chainp = cache_head;
898 }
899
900 if (ans &&
901 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000902 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000903 hostname_isequal(cache_get_name(ans), name))
904 return ans;
905
906 return NULL;
907}
908
Simon Kelleycc921df2019-01-02 22:48:59 +0000909struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000910 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000911{
912 struct crec *ans;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000913 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000914
915 if (crecp) /* iterating */
916 ans = crecp->next;
917 else
918 {
919 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000920 also free anything which has expired. All the reverse entries are at the
921 start of the hash chain, so we can give up when we find the first
922 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000923 int i;
924 struct crec **up, **chainp = &ans;
925
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000926 for (i=0; i<hash_size; i++)
927 for (crecp = hash_table[i], up = &hash_table[i];
928 crecp && (crecp->flags & F_REVERSE);
929 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000930 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000931 {
Simon Kelley6b010842007-02-12 20:32:07 +0000932 if ((crecp->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000933 memcmp(&crecp->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000934 {
Simon Kelley25439062013-11-25 21:14:51 +0000935 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936 {
937 *chainp = crecp;
938 chainp = &crecp->next;
939 }
940 else
941 {
942 cache_unlink(crecp);
943 cache_link(crecp);
944 }
945 }
946 up = &crecp->hash_next;
947 }
948 else
949 {
950 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000951 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000952 {
953 cache_unlink(crecp);
954 cache_free(crecp);
955 }
956 }
957
958 *chainp = cache_head;
959 }
960
961 if (ans &&
962 (ans->flags & F_REVERSE) &&
963 (ans->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000964 memcmp(&ans->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000965 return ans;
966
967 return NULL;
968}
969
Simon Kelleycc921df2019-01-02 22:48:59 +0000970static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000971 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000972{
Simon Kelleye759d422012-03-16 13:18:57 +0000973 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
Simon Kelley84449bf2019-10-29 22:24:19 +0000974 int i;
Simon Kelley205fafa2012-01-11 21:31:51 +0000975 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000976
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000977 /* Remove duplicates in hosts files. */
Simon Kelley84449bf2019-10-29 22:24:19 +0000978 if (lookup && (lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000979 {
Simon Kelley84449bf2019-10-29 22:24:19 +0000980 free(cache);
981 return;
Simon Kelley9009d742008-11-14 20:04:27 +0000982 }
Simon Kelley84449bf2019-10-29 22:24:19 +0000983
Simon Kelley9009d742008-11-14 20:04:27 +0000984 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000985 We do this by steam here, The entries are kept in hash chains, linked
986 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000987 the array rhash, hashed on address. Note that rhash and the values
988 in ->next are only valid whilst reading hosts files: the buckets are
989 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000990
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000991 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000992
993 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +0000994 large (10000 entry) hosts files.
995
996 Note that we only do this process when bulk-reading hosts files,
997 for incremental reads, rhash is NULL, and we use cache lookups
998 instead.
999 */
Simon Kelley9009d742008-11-14 20:04:27 +00001000
Simon Kelley70d18732015-01-31 19:59:29 +00001001 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +00001002 {
Simon Kelley70d18732015-01-31 19:59:29 +00001003 /* hash address */
1004 for (j = 0, i = 0; i < addrlen; i++)
1005 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
1006
1007 for (lookup = rhash[j]; lookup; lookup = lookup->next)
1008 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001009 memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley70d18732015-01-31 19:59:29 +00001010 {
1011 cache->flags &= ~F_REVERSE;
1012 break;
1013 }
1014
1015 /* maintain address hash chain, insert new unique address */
1016 if (!lookup)
1017 {
1018 cache->next = rhash[j];
1019 rhash[j] = cache;
1020 }
Simon Kelley915363f2012-01-11 22:00:48 +00001021 }
Simon Kelley70d18732015-01-31 19:59:29 +00001022 else
1023 {
1024 /* incremental read, lookup in cache */
1025 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
1026 if (lookup && lookup->flags & F_HOSTS)
1027 cache->flags &= ~F_REVERSE;
1028 }
1029
Simon Kelley9009d742008-11-14 20:04:27 +00001030 cache->uid = index;
Simon Kelleycc921df2019-01-02 22:48:59 +00001031 memcpy(&cache->addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +00001032 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001033 make_non_terminals(cache);
Simon Kelley9009d742008-11-14 20:04:27 +00001034}
1035
1036static int eatspace(FILE *f)
1037{
1038 int c, nl = 0;
1039
1040 while (1)
1041 {
1042 if ((c = getc(f)) == '#')
1043 while (c != '\n' && c != EOF)
1044 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +00001045
Simon Kelley9009d742008-11-14 20:04:27 +00001046 if (c == EOF)
1047 return 1;
1048
1049 if (!isspace(c))
1050 {
1051 ungetc(c, f);
1052 return nl;
1053 }
1054
1055 if (c == '\n')
Simon Kelley4219ade2019-02-27 20:30:21 +00001056 nl++;
Simon Kelley9009d742008-11-14 20:04:27 +00001057 }
1058}
1059
1060static int gettok(FILE *f, char *token)
1061{
1062 int c, count = 0;
1063
1064 while (1)
1065 {
1066 if ((c = getc(f)) == EOF)
Simon Kelley4219ade2019-02-27 20:30:21 +00001067 return (count == 0) ? -1 : 1;
Simon Kelley9009d742008-11-14 20:04:27 +00001068
1069 if (isspace(c) || c == '#')
1070 {
1071 ungetc(c, f);
1072 return eatspace(f);
1073 }
1074
1075 if (count < (MAXDNAME - 1))
1076 {
1077 token[count++] = c;
1078 token[count] = 0;
1079 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001080 }
1081}
1082
Simon Kelley70d18732015-01-31 19:59:29 +00001083int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001084{
1085 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +00001086 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4219ade2019-02-27 20:30:21 +00001087 int addr_count = 0, name_count = cache_size, lineno = 1;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001088 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001089 union all_addr addr;
Simon Kelley205fafa2012-01-11 21:31:51 +00001090 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +01001091
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001092 if (!f)
1093 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001094 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +00001095 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001096 }
Simon Kelley9009d742008-11-14 20:04:27 +00001097
Simon Kelley4219ade2019-02-27 20:30:21 +00001098 lineno += eatspace(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001099
Simon Kelley4219ade2019-02-27 20:30:21 +00001100 while ((atnl = gettok(f, token)) != -1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001101 {
Simon Kelley3d8df262005-08-29 12:19:27 +01001102 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001103 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001104 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001105 addrlen = INADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001106 domain_suffix = get_domain(addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001107 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001108 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001109 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001110 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001111 addrlen = IN6ADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001112 domain_suffix = get_domain6(&addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001113 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001114 else
Simon Kelleyb8187c82005-11-26 21:46:27 +00001115 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001116 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +00001117 while (atnl == 0)
1118 atnl = gettok(f, token);
Simon Kelley065e5bb2019-03-01 14:38:51 +00001119 lineno += atnl;
Simon Kelleyb8187c82005-11-26 21:46:27 +00001120 continue;
1121 }
Simon Kelley9009d742008-11-14 20:04:27 +00001122
Simon Kelley9009d742008-11-14 20:04:27 +00001123 addr_count++;
1124
1125 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +00001126 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +00001127 {
1128 rehash(name_count);
1129 cache_size = name_count;
1130 }
1131
1132 while (atnl == 0)
1133 {
1134 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +01001135 int fqdn, nomem;
1136 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +00001137
Simon Kelley4219ade2019-02-27 20:30:21 +00001138 if ((atnl = gettok(f, token)) == -1)
Simon Kelley9009d742008-11-14 20:04:27 +00001139 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001140
Simon Kelley9009d742008-11-14 20:04:27 +00001141 fqdn = !!strchr(token, '.');
1142
Simon Kelley1f15b812009-10-13 17:49:32 +01001143 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +00001144 {
1145 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +00001146 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001147 (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
Simon Kelley9009d742008-11-14 20:04:27 +00001148 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001149 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +00001150 strcat(cache->name.sname, ".");
1151 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +00001152 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001153 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001154 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001155 name_count++;
1156 }
Simon Kelley3a610a02018-09-26 16:50:35 +01001157 if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
Simon Kelley9009d742008-11-14 20:04:27 +00001158 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001159 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +00001160 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001161 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001162 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001163 name_count++;
1164 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001165 free(canon);
1166
Simon Kelley9009d742008-11-14 20:04:27 +00001167 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001168 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001169 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1170 }
Simon Kelley4219ade2019-02-27 20:30:21 +00001171
1172 lineno += atnl;
Simon Kelley9009d742008-11-14 20:04:27 +00001173 }
1174
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001175 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001176
Simon Kelley70d18732015-01-31 19:59:29 +00001177 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001178 rehash(name_count);
1179
1180 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1181
Simon Kelley4011c4e2006-10-28 16:26:19 +01001182 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001183}
1184
Simon Kelley7622fc02009-06-04 20:32:05 +01001185void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001186{
1187 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001188 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001189 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001190 struct host_record *hr;
1191 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001192 struct cname *a;
Simon Kelley376cb972019-10-29 22:58:55 +00001193 struct crec lrec;
1194 struct mx_srv_record *mx;
1195 struct txt_record *txt;
1196 struct interface_name *intr;
1197 struct ptr_record *ptr;
1198 struct naptr *naptr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001199#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001200 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001201#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001202
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001203 daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
1204 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
Simon Kelley59353a62004-11-21 19:34:28 +00001205
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001206 for (i=0; i<hash_size; i++)
1207 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1208 {
Simon Kelley82e3f452014-01-31 21:05:48 +00001209 cache_blockdata_free(cache);
Simon Kelley5b99eae2019-01-06 23:09:50 +00001210
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001211 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001212 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001213 {
1214 *up = cache->hash_next;
1215 free(cache);
1216 }
1217 else if (!(cache->flags & F_DHCP))
1218 {
1219 *up = cache->hash_next;
1220 if (cache->flags & F_BIGNAME)
1221 {
1222 cache->name.bname->next = big_free;
1223 big_free = cache->name.bname;
1224 }
1225 cache->flags = 0;
1226 }
1227 else
1228 up = &cache->hash_next;
1229 }
1230
Simon Kelley84449bf2019-10-29 22:24:19 +00001231 /* Add locally-configured CNAMEs to the cache */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001232 for (a = daemon->cnames; a; a = a->next)
Simon Kelley84449bf2019-10-29 22:24:19 +00001233 if (a->alias[1] != '*' &&
1234 ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
1235 {
1236 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
1237 cache->ttd = a->ttl;
1238 cache->name.namep = a->alias;
1239 cache->addr.cname.target.name = a->target;
Simon Kelley1fd56c02019-10-30 12:58:28 +00001240 cache->addr.cname.is_name_ptr = 1;
Simon Kelley84449bf2019-10-29 22:24:19 +00001241 cache->uid = UID_NONE;
1242 cache_hash(cache);
1243 make_non_terminals(cache);
1244 }
1245
Simon Kelley0fc2f312014-01-08 10:26:58 +00001246#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001247 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley3a610a02018-09-26 16:50:35 +01001248 if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001249 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001250 {
Simon Kelleyee415862014-02-11 11:07:22 +00001251 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001252 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001253 cache->name.namep = ds->name;
Simon Kelleycc921df2019-01-02 22:48:59 +00001254 cache->addr.ds.keylen = ds->digestlen;
1255 cache->addr.ds.algo = ds->algo;
1256 cache->addr.ds.keytag = ds->keytag;
1257 cache->addr.ds.digest = ds->digest_type;
Simon Kelleyee415862014-02-11 11:07:22 +00001258 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001259 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001260 make_non_terminals(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001261 }
1262#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001263
Simon Kelleye759d422012-03-16 13:18:57 +00001264 /* borrow the packet buffer for a temporary by-address hash */
1265 memset(daemon->packet, 0, daemon->packet_buff_sz);
1266 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1267 /* we overwrote the buffer... */
1268 daemon->srv_save = NULL;
1269
1270 /* Do host_records in config. */
1271 for (hr = daemon->host_records; hr; hr = hr->next)
1272 for (nl = hr->names; nl; nl = nl->next)
1273 {
Simon Kelley157d8cf2019-10-25 17:46:49 +01001274 if ((hr->flags & HR_4) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001275 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001276 {
1277 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001278 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001279 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001280 add_hosts_entry(cache, (union all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001281 }
Simon Kelleyee875042018-10-23 22:10:17 +01001282
Simon Kelley157d8cf2019-10-25 17:46:49 +01001283 if ((hr->flags & HR_6) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001284 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001285 {
1286 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001287 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001288 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001289 add_hosts_entry(cache, (union all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001290 }
Simon Kelleye759d422012-03-16 13:18:57 +00001291 }
1292
Simon Kelley28866e92011-02-14 20:19:14 +00001293 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001294 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001295 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001296 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001297 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001298 else
1299 {
1300 if (!option_bool(OPT_NO_HOSTS))
1301 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1302
1303 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1304 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1305 if (!(ah->flags & AH_INACTIVE))
1306 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1307 }
Simon Kelley376cb972019-10-29 22:58:55 +00001308
1309 /* Make non-terminal records for all locally-define RRs */
1310 lrec.flags = F_FORWARD | F_CONFIG | F_NAMEP | F_IMMORTAL;
1311
1312 for (txt = daemon->txt; txt; txt = txt->next)
1313 {
1314 lrec.name.namep = txt->name;
1315 make_non_terminals(&lrec);
1316 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001317
Simon Kelley376cb972019-10-29 22:58:55 +00001318 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1319 {
1320 lrec.name.namep = naptr->name;
1321 make_non_terminals(&lrec);
1322 }
1323
1324 for (mx = daemon->mxnames; mx; mx = mx->next)
1325 {
1326 lrec.name.namep = mx->name;
1327 make_non_terminals(&lrec);
1328 }
1329
1330 for (intr = daemon->int_names; intr; intr = intr->next)
1331 {
1332 lrec.name.namep = intr->name;
1333 make_non_terminals(&lrec);
1334 }
1335
1336 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1337 {
1338 lrec.name.namep = ptr->name;
1339 make_non_terminals(&lrec);
1340 }
1341
Simon Kelley70d18732015-01-31 19:59:29 +00001342#ifdef HAVE_INOTIFY
1343 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1344#endif
1345
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001346}
1347
Simon Kelley7622fc02009-06-04 20:32:05 +01001348#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001349struct in_addr a_record_from_hosts(char *name, time_t now)
1350{
1351 struct crec *crecp = NULL;
1352 struct in_addr ret;
1353
1354 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1355 if (crecp->flags & F_HOSTS)
Simon Kelleycc921df2019-01-02 22:48:59 +00001356 return crecp->addr.addr4;
Simon Kelley7de060b2011-08-26 17:24:52 +01001357
1358 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1359
1360 ret.s_addr = 0;
1361 return ret;
1362}
1363
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001364void cache_unhash_dhcp(void)
1365{
Simon Kelley6b010842007-02-12 20:32:07 +00001366 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001367 int i;
1368
1369 for (i=0; i<hash_size; i++)
1370 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1371 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001372 {
1373 *up = cache->hash_next;
1374 cache->next = dhcp_spare;
1375 dhcp_spare = cache;
1376 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001377 else
1378 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001379}
1380
Simon Kelley4cb1b322012-02-06 14:30:41 +00001381void cache_add_dhcp_entry(char *host_name, int prot,
Simon Kelleycc921df2019-01-02 22:48:59 +00001382 union all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001383{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001384 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001385 unsigned int flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001386 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001387 size_t addrlen = sizeof(struct in_addr);
1388
Simon Kelley4cb1b322012-02-06 14:30:41 +00001389 if (prot == AF_INET6)
1390 {
1391 flags = F_IPV6;
1392 addrlen = sizeof(struct in6_addr);
1393 }
Simon Kelley9009d742008-11-14 20:04:27 +00001394
Simon Kelley12d71ed2012-08-30 15:16:41 +01001395 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1396
Simon Kelley4cb1b322012-02-06 14:30:41 +00001397 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001398 {
Simon Kelley824af852008-02-12 20:43:05 +00001399 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001400 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001401 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001402 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001403 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001404 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001405 host_name, daemon->addrbuff);
Simon Kelleycc921df2019-01-02 22:48:59 +00001406 else if (memcmp(&crec->addr, host_address, addrlen) == 0)
Simon Kelley12d71ed2012-08-30 15:16:41 +01001407 in_hosts = 1;
1408 else
1409 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001410 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001411 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001412 {
Simon Kelley65a01b72018-12-31 23:56:33 +00001413 cache_scan_free(host_name, NULL, C_IN, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
Simon Kelley824af852008-02-12 20:43:05 +00001414 /* scan_free deletes all addresses associated with name */
1415 break;
1416 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001417 }
Simon Kelley824af852008-02-12 20:43:05 +00001418
Simon Kelley12d71ed2012-08-30 15:16:41 +01001419 /* if in hosts, don't need DHCP record */
1420 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001421 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001422
1423 /* Name in hosts, address doesn't match */
1424 if (fail_crec)
1425 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001426 inet_ntop(prot, &fail_crec->addr, daemon->namebuff, MAXDNAME);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001427 my_syslog(MS_DHCP | LOG_WARNING,
1428 _("not giving name %s to the DHCP lease of %s because "
1429 "the name exists in %s with address %s"),
1430 host_name, daemon->addrbuff,
1431 record_source(fail_crec->uid), daemon->namebuff);
1432 return;
1433 }
1434
Simon Kelleycc921df2019-01-02 22:48:59 +00001435 if ((crec = cache_find_by_addr(NULL, (union all_addr *)host_address, 0, flags)))
Simon Kelley12d71ed2012-08-30 15:16:41 +01001436 {
1437 if (crec->flags & F_NEG)
1438 {
1439 flags |= F_REVERSE;
Simon Kelleycc921df2019-01-02 22:48:59 +00001440 cache_scan_free(NULL, (union all_addr *)host_address, C_IN, 0, flags, NULL, NULL);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001441 }
1442 }
1443 else
1444 flags |= F_REVERSE;
1445
1446 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001447 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001448 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001449 crec = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001450
1451 if (crec) /* malloc may fail */
1452 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001453 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001454 if (ttd == 0)
1455 crec->flags |= F_IMMORTAL;
1456 else
1457 crec->ttd = ttd;
Simon Kelleycc921df2019-01-02 22:48:59 +00001458 crec->addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001459 crec->name.namep = host_name;
Simon Kelley45d8a242018-07-17 21:01:14 +01001460 crec->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001461 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001462 make_non_terminals(crec);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001463 }
1464}
Simon Kelley7622fc02009-06-04 20:32:05 +01001465#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001466
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001467/* Called when we put a local or DHCP name into the cache.
1468 Creates empty cache entries for subnames (ie,
1469 for three.two.one, for two.one and one), without
1470 F_IPV4 or F_IPV6 or F_CNAME set. These convert
1471 NXDOMAIN answers to NoData ones. */
1472static void make_non_terminals(struct crec *source)
1473{
1474 char *name = cache_get_name(source);
Simon Kelleyea6cc332018-09-18 23:21:17 +01001475 struct crec *crecp, *tmp, **up;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001476 int type = F_HOSTS | F_CONFIG;
1477#ifdef HAVE_DHCP
1478 if (source->flags & F_DHCP)
1479 type = F_DHCP;
1480#endif
1481
1482 /* First delete any empty entries for our new real name. Note that
1483 we only delete empty entries deriving from DHCP for a new DHCP-derived
1484 entry and vice-versa for HOSTS and CONFIG. This ensures that
1485 non-terminals from DHCP go when we reload DHCP and
1486 for HOSTS/CONFIG when we re-read. */
1487 for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
1488 {
1489 tmp = crecp->hash_next;
1490
1491 if (!is_outdated_cname_pointer(crecp) &&
1492 (crecp->flags & F_FORWARD) &&
1493 (crecp->flags & type) &&
Simon Kelley376cb972019-10-29 22:58:55 +00001494 !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS)) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001495 hostname_isequal(name, cache_get_name(crecp)))
1496 {
1497 *up = crecp->hash_next;
1498#ifdef HAVE_DHCP
1499 if (type & F_DHCP)
1500 {
1501 crecp->next = dhcp_spare;
1502 dhcp_spare = crecp;
1503 }
1504 else
1505#endif
1506 free(crecp);
1507 break;
1508 }
1509 else
1510 up = &crecp->hash_next;
1511 }
1512
1513 while ((name = strchr(name, '.')))
1514 {
1515 name++;
1516
1517 /* Look for one existing, don't need another */
1518 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
1519 if (!is_outdated_cname_pointer(crecp) &&
1520 (crecp->flags & F_FORWARD) &&
1521 (crecp->flags & type) &&
1522 hostname_isequal(name, cache_get_name(crecp)))
1523 break;
1524
1525 if (crecp)
1526 {
1527 /* If the new name expires later, transfer that time to
1528 empty non-terminal entry. */
1529 if (!(crecp->flags & F_IMMORTAL))
1530 {
1531 if (source->flags & F_IMMORTAL)
1532 crecp->flags |= F_IMMORTAL;
1533 else if (difftime(crecp->ttd, source->ttd) < 0)
1534 crecp->ttd = source->ttd;
1535 }
1536 continue;
1537 }
1538
1539#ifdef HAVE_DHCP
1540 if ((source->flags & F_DHCP) && dhcp_spare)
1541 {
1542 crecp = dhcp_spare;
1543 dhcp_spare = dhcp_spare->next;
1544 }
1545 else
1546#endif
Simon Kelley3a610a02018-09-26 16:50:35 +01001547 crecp = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001548
Simon Kelleyea6cc332018-09-18 23:21:17 +01001549 if (crecp)
1550 {
Simon Kelley376cb972019-10-29 22:58:55 +00001551 crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
Simon Kelley48b090c2018-09-26 12:53:59 +01001552 crecp->ttd = source->ttd;
Simon Kelleyea6cc332018-09-18 23:21:17 +01001553 crecp->name.namep = name;
1554
1555 cache_hash(crecp);
1556 }
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001557 }
1558}
1559
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001560#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001561int cache_make_stat(struct txt_record *t)
1562{
1563 static char *buff = NULL;
1564 static int bufflen = 60;
1565 int len;
1566 struct server *serv, *serv1;
1567 char *p;
1568
1569 if (!buff && !(buff = whine_malloc(60)))
1570 return 0;
1571
1572 p = buff;
1573
1574 switch (t->stat)
1575 {
1576 case TXT_STAT_CACHESIZE:
1577 sprintf(buff+1, "%d", daemon->cachesize);
1578 break;
1579
1580 case TXT_STAT_INSERTS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001581 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001582 break;
1583
1584 case TXT_STAT_EVICTIONS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001585 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001586 break;
1587
1588 case TXT_STAT_MISSES:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001589 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001590 break;
1591
1592 case TXT_STAT_HITS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001593 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001594 break;
1595
1596#ifdef HAVE_AUTH
1597 case TXT_STAT_AUTH:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001598 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001599 break;
1600#endif
1601
1602 case TXT_STAT_SERVERS:
1603 /* sum counts from different records for same server */
1604 for (serv = daemon->servers; serv; serv = serv->next)
1605 serv->flags &= ~SERV_COUNTED;
1606
1607 for (serv = daemon->servers; serv; serv = serv->next)
1608 if (!(serv->flags &
1609 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1610 {
1611 char *new, *lenp;
1612 int port, newlen, bytes_avail, bytes_needed;
1613 unsigned int queries = 0, failed_queries = 0;
1614 for (serv1 = serv; serv1; serv1 = serv1->next)
1615 if (!(serv1->flags &
1616 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1617 sockaddr_isequal(&serv->addr, &serv1->addr))
1618 {
1619 serv1->flags |= SERV_COUNTED;
1620 queries += serv1->queries;
1621 failed_queries += serv1->failed_queries;
1622 }
1623 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1624 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001625 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001626 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1627 if (bytes_needed >= bytes_avail)
1628 {
1629 /* expand buffer if necessary */
1630 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1631 if (!(new = whine_malloc(newlen)))
1632 return 0;
1633 memcpy(new, buff, bufflen);
1634 free(buff);
1635 p = new + (p - buff);
1636 lenp = p - 1;
1637 buff = new;
1638 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001639 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001640 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1641 }
1642 *lenp = bytes_needed;
1643 p += bytes_needed;
1644 }
1645 t->txt = (unsigned char *)buff;
1646 t->len = p - buff;
1647 return 1;
1648 }
1649
1650 len = strlen(buff+1);
1651 t->txt = (unsigned char *)buff;
1652 t->len = len + 1;
1653 *buff = len;
1654 return 1;
1655}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001656#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001657
Simon Kelley394ff492015-03-29 22:17:14 +01001658/* There can be names in the cache containing control chars, don't
1659 mess up logging or open security holes. */
1660static char *sanitise(char *name)
1661{
1662 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001663 if (name)
1664 for (r = (unsigned char *)name; *r; r++)
1665 if (!isprint((int)*r))
1666 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001667
1668 return name;
1669}
1670
1671
Simon Kelley5aabfc72007-08-29 11:24:47 +01001672void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001673{
Simon Kelley824af852008-02-12 20:43:05 +00001674 struct server *serv, *serv1;
1675
1676 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1677 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001678 daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelley824af852008-02-12 20:43:05 +00001679 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001680 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001681#ifdef HAVE_AUTH
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001682 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001683#endif
Simon Kelley5b99eae2019-01-06 23:09:50 +00001684
Simon Kelleyc2207682014-01-08 18:04:20 +00001685 blockdata_report();
Simon Kelley824af852008-02-12 20:43:05 +00001686
Simon Kelley824af852008-02-12 20:43:05 +00001687 /* sum counts from different records for same server */
1688 for (serv = daemon->servers; serv; serv = serv->next)
1689 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001690
Simon Kelley824af852008-02-12 20:43:05 +00001691 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001692 if (!(serv->flags &
1693 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001694 {
1695 int port;
1696 unsigned int queries = 0, failed_queries = 0;
1697 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001698 if (!(serv1->flags &
1699 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1700 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001701 {
1702 serv1->flags |= SERV_COUNTED;
1703 queries += serv1->queries;
1704 failed_queries += serv1->failed_queries;
1705 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001706 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1707 my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
Simon Kelley824af852008-02-12 20:43:05 +00001708 }
1709
Simon Kelley28866e92011-02-14 20:19:14 +00001710 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001711 {
1712 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001713 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001714 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001715
1716 for (i=0; i<hash_size; i++)
1717 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1718 {
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001719 char *t = " ";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001720 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1721 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001722 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001723 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001724 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001725 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001726 a = sanitise(cache_get_cname_target(cache));
Simon Kelley5b99eae2019-01-06 23:09:50 +00001727 else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG))
1728 {
1729 int targetlen = cache->addr.srv.targetlen;
1730 ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority,
1731 cache->addr.srv.weight, cache->addr.srv.srvport);
1732
1733 if (targetlen > (40 - len))
1734 targetlen = 40 - len;
1735 blockdata_retrieve(cache->addr.srv.target, targetlen, a + len);
1736 a[len + targetlen] = 0;
1737 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001738#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001739 else if (cache->flags & F_DS)
1740 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001741 if (!(cache->flags & F_NEG))
Simon Kelleycc921df2019-01-02 22:48:59 +00001742 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1743 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001744 }
1745 else if (cache->flags & F_DNSKEY)
Simon Kelleycc921df2019-01-02 22:48:59 +00001746 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1747 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001748#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001749 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001750 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001751 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001752 if (cache->flags & F_IPV4)
Simon Kelleycc921df2019-01-02 22:48:59 +00001753 inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001754 else if (cache->flags & F_IPV6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001755 inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001756 }
1757
Simon Kelleye7829ae2014-01-22 22:21:51 +00001758 if (cache->flags & F_IPV4)
1759 t = "4";
1760 else if (cache->flags & F_IPV6)
1761 t = "6";
1762 else if (cache->flags & F_CNAME)
1763 t = "C";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001764 else if (cache->flags & F_SRV)
1765 t = "V";
Simon Kelleye7829ae2014-01-22 22:21:51 +00001766#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001767 else if (cache->flags & F_DS)
1768 t = "S";
1769 else if (cache->flags & F_DNSKEY)
1770 t = "K";
1771#endif
Simon Kelley32678042014-12-17 20:38:20 +00001772 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001773 cache->flags & F_FORWARD ? "F" : " ",
1774 cache->flags & F_REVERSE ? "R" : " ",
1775 cache->flags & F_IMMORTAL ? "I" : " ",
1776 cache->flags & F_DHCP ? "D" : " ",
1777 cache->flags & F_NEG ? "N" : " ",
1778 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001779 cache->flags & F_HOSTS ? "H" : " ",
1780 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001781#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001782 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001783#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001784 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1785 /* ctime includes trailing \n - eat it */
1786 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001787#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001788 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001789 }
1790 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001791}
1792
Simon Kelley19c51cf2014-03-18 22:38:30 +00001793char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001794{
Simon Kelley7622fc02009-06-04 20:32:05 +01001795 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001796
Simon Kelley19c51cf2014-03-18 22:38:30 +00001797 if (index == SRC_CONFIG)
1798 return "config";
1799 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001800 return HOSTSFILE;
1801
1802 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1803 if (ah->index == index)
1804 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001805
1806#ifdef HAVE_INOTIFY
1807 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1808 if (ah->index == index)
1809 return ah->fname;
1810#endif
1811
Simon Kelley7622fc02009-06-04 20:32:05 +01001812 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001813}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001814
Simon Kelley610e7822014-02-06 14:45:17 +00001815char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001816{
1817 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001818 int len = 10; /* strlen("type=xxxxx") */
1819 const char *types = NULL;
1820 static char *buff = NULL;
1821 static int bufflen = 0;
1822
Simon Kelley1a6bca82008-07-11 11:11:42 +01001823 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1824 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001825 {
1826 types = typestr[i].name;
1827 len = strlen(types);
1828 break;
1829 }
1830
Simon Kelleyb758b672018-08-23 21:41:23 +01001831 if (desc)
1832 {
1833 len += 2; /* braces */
1834 len += strlen(desc);
1835 }
1836 len++; /* terminator */
1837
Simon Kelley610e7822014-02-06 14:45:17 +00001838 if (!buff || bufflen < len)
1839 {
1840 if (buff)
1841 free(buff);
1842 else if (len < 20)
1843 len = 20;
1844
1845 buff = whine_malloc(len);
1846 bufflen = len;
1847 }
1848
1849 if (buff)
1850 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001851 if (desc)
1852 {
1853 if (types)
1854 sprintf(buff, "%s[%s]", desc, types);
1855 else
1856 sprintf(buff, "%s[type=%d]", desc, type);
1857 }
Simon Kelley610e7822014-02-06 14:45:17 +00001858 else
Simon Kelleyb758b672018-08-23 21:41:23 +01001859 {
1860 if (types)
1861 sprintf(buff, "<%s>", types);
1862 else
1863 sprintf(buff, "type=%d", type);
1864 }
Simon Kelley610e7822014-02-06 14:45:17 +00001865 }
Simon Kelleyb758b672018-08-23 21:41:23 +01001866
Simon Kelley610e7822014-02-06 14:45:17 +00001867 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001868}
1869
Simon Kelleycc921df2019-01-02 22:48:59 +00001870void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001871{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001872 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001873 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001874
Simon Kelley28866e92011-02-14 20:19:14 +00001875 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001876 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001877
Simon Kelley394ff492015-03-29 22:17:14 +01001878 name = sanitise(name);
1879
Simon Kelley5aabfc72007-08-29 11:24:47 +01001880 if (addr)
1881 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001882 if (flags & F_KEYTAG)
Simon Kelleycc921df2019-01-02 22:48:59 +00001883 sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
Simon Kelley07ed5852018-05-04 21:52:22 +01001884 else if (flags & F_RCODE)
1885 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001886 unsigned int rcode = addr->log.rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +01001887
1888 if (rcode == SERVFAIL)
1889 dest = "SERVFAIL";
1890 else if (rcode == REFUSED)
1891 dest = "REFUSED";
1892 else if (rcode == NOTIMP)
1893 dest = "not implemented";
1894 else
1895 sprintf(daemon->addrbuff, "%u", rcode);
1896 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001897 else
Simon Kelleyee875042018-10-23 22:10:17 +01001898 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1899 addr, daemon->addrbuff, ADDRSTRLEN);
1900
Simon Kelley5aabfc72007-08-29 11:24:47 +01001901 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001902 else
1903 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001904
1905 if (flags & F_REVERSE)
1906 {
1907 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001908 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001909 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001910
1911 if (flags & F_NEG)
1912 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001913 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001914 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001915 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001916 {
1917 if (flags & F_IPV4)
1918 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001919 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001920 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001921 else
1922 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001923 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001924 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001925 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001926 dest = "<CNAME>";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001927 else if (flags & F_SRV)
1928 dest = "<SRV>";
Simon Kelley28866e92011-02-14 20:19:14 +00001929 else if (flags & F_RRNAME)
1930 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001931
Simon Kelley1f15b812009-10-13 17:49:32 +01001932 if (flags & F_CONFIG)
1933 source = "config";
1934 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001935 source = "DHCP";
1936 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001937 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001938 else if (flags & F_UPSTREAM)
1939 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001940 else if (flags & F_SECSTAT)
1941 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001942 else if (flags & F_AUTH)
1943 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001944 else if (flags & F_SERVER)
1945 {
1946 source = "forwarded";
1947 verb = "to";
1948 }
1949 else if (flags & F_QUERY)
1950 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001951 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001952 verb = "from";
1953 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001954 else if (flags & F_DNSSEC)
1955 {
1956 source = arg;
1957 verb = "to";
1958 }
Wang Jian49752b92014-03-28 20:52:47 +00001959 else if (flags & F_IPSET)
1960 {
1961 source = "ipset add";
1962 dest = name;
1963 name = arg;
1964 verb = daemon->addrbuff;
1965 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001966 else
1967 source = "cached";
1968
Simon Kelley3d8df262005-08-29 12:19:27 +01001969 if (strlen(name) == 0)
1970 name = ".";
1971
Simon Kelley25cf5e32015-01-09 15:53:03 +00001972 if (option_bool(OPT_EXTRALOG))
1973 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001974 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001975 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001976 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001977 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001978 my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001979 }
1980 else
1981 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001982}
1983
Simon Kelley98c098b2014-01-08 17:31:16 +00001984