blob: 733e053707e72f947325c4efa3fe8a2ef3543f0f [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
17#include "dnsmasq.h"
18
Simon 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 Kelley19c51cf2014-03-18 22:38:30 +0000279 if (crecp->addr.cname.uid != SRC_INTERFACE)
Simon Kelleyd56a6042013-10-11 14:39:03 +0100280 return cache_get_name(crecp->addr.cname.target.cache);
281
282 return crecp->addr.cname.target.int_name->name;
283}
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{
Andy3e21a1a2014-03-22 19:10:07 +0000312 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
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 Kelleya0ab18f2014-02-13 16:38:23 +0000475 /* Don't log DNSSEC records here, done elsewhere */
Simon Kelley5b99eae2019-01-06 23:09:50 +0000476 if (flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV))
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000477 {
478 log_query(flags | F_UPSTREAM, name, addr, NULL);
RinSatsuki28de3872015-01-10 15:22:21 +0000479 /* Don't mess with TTL for DNSSEC records. */
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000480 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
481 ttl = daemon->max_cache_ttl;
RinSatsuki28de3872015-01-10 15:22:21 +0000482 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
483 ttl = daemon->min_cache_ttl;
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000484 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100485
Simon Kelley65a01b72018-12-31 23:56:33 +0000486 return really_insert(name, addr, class, now, ttl, flags);
Simon Kelleya799ca02018-10-18 19:35:29 +0100487}
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000488
Simon Kelleya799ca02018-10-18 19:35:29 +0100489
Simon Kelleycc921df2019-01-02 22:48:59 +0000490static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
Simon Kelley5b99eae2019-01-06 23:09:50 +0000491 time_t now, unsigned long ttl, unsigned int flags)
Simon Kelleya799ca02018-10-18 19:35:29 +0100492{
493 struct crec *new, *target_crec = NULL;
494 union bigname *big_name = NULL;
495 int freed_all = flags & F_REVERSE;
496 int free_avail = 0;
497 unsigned int target_uid;
498
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000499 /* if previous insertion failed give up now. */
500 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100501 return NULL;
Simon Kelley1292e1a2019-10-25 17:31:53 +0100502
503 /* we don't cache zero-TTL records. */
504 if (ttl == 0)
505 {
506 insert_error = 1;
507 return NULL;
508 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000509
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000510 /* First remove any expired entries and entries for the name/address we
Simon Kelleycbc65242014-12-21 21:21:53 +0000511 are currently inserting. */
Simon Kelley65a01b72018-12-31 23:56:33 +0000512 if ((new = cache_scan_free(name, addr, class, now, flags, &target_crec, &target_uid)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000513 {
Simon Kelleycbc65242014-12-21 21:21:53 +0000514 /* We're trying to insert a record over one from
515 /etc/hosts or DHCP, or other config. If the
516 existing record is for an A or AAAA and
517 the record we're trying to insert is the same,
518 just drop the insert, but don't error the whole process. */
Edwin Török41a8d9e2015-11-14 17:45:48 +0000519 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000520 {
521 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000522 new->addr.addr4.s_addr == addr->addr4.s_addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000523 return new;
Simon Kelleycbc65242014-12-21 21:21:53 +0000524 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000525 IN6_ARE_ADDR_EQUAL(&new->addr.addr6, &addr->addr6))
Simon Kelleycbc65242014-12-21 21:21:53 +0000526 return new;
Simon Kelleycbc65242014-12-21 21:21:53 +0000527 }
528
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000529 insert_error = 1;
530 return NULL;
531 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000532
533 /* Now get a cache entry from the end of the LRU list */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100534 if (!target_crec)
535 while (1) {
536 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
537 {
538 insert_error = 1;
539 return NULL;
540 }
541
542 /* Free entry at end of LRU list, use it. */
543 if (!(new->flags & (F_FORWARD | F_REVERSE)))
544 break;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000545
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100546 /* End of LRU list is still in use: if we didn't scan all the hash
547 chains for expired entries do that now. If we already tried that
548 then it's time to start spilling things. */
549
550 /* If free_avail set, we believe that an entry has been freed.
551 Bugs have been known to make this not true, resulting in
552 a tight loop here. If that happens, abandon the
553 insert. Once in this state, all inserts will probably fail. */
554 if (free_avail)
555 {
556 static int warned = 0;
557 if (!warned)
558 {
559 my_syslog(LOG_ERR, _("Internal error in cache."));
560 warned = 1;
561 }
562 insert_error = 1;
563 return NULL;
564 }
565
566 if (freed_all)
567 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000568 /* For DNSSEC records, uid holds class. */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100569 free_avail = 1; /* Must be free space now. */
Simon Kelleycc921df2019-01-02 22:48:59 +0000570 cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100571 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100572 }
573 else
574 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000575 cache_scan_free(NULL, NULL, class, now, 0, NULL, NULL);
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100576 freed_all = 1;
577 }
578 }
579
580 /* Check if we need to and can allocate extra memory for a long name.
581 If that fails, give up now, always succeed for DNSSEC records. */
582 if (name && (strlen(name) > SMALLDNAME-1))
583 {
584 if (big_free)
585 {
586 big_name = big_free;
587 big_free = big_free->next;
588 }
589 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
590 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
591 {
592 insert_error = 1;
593 return NULL;
594 }
595 else if (bignames_left != 0)
596 bignames_left--;
597
598 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000599
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100600 /* If we freed a cache entry for our name which was a CNAME target, use that.
601 and preserve the uid, so that existing CNAMES are not broken. */
602 if (target_crec)
603 {
604 new = target_crec;
605 new->uid = target_uid;
606 }
607
608 /* Got the rest: finally grab entry. */
609 cache_unlink(new);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000610
611 new->flags = flags;
612 if (big_name)
613 {
614 new->name.bname = big_name;
615 new->flags |= F_BIGNAME;
616 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100617
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000618 if (name)
619 strcpy(cache_get_name(new), name);
620 else
621 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100622
Simon Kelleyb8eac192014-02-27 14:30:03 +0000623#ifdef HAVE_DNSSEC
Simon Kelley65a01b72018-12-31 23:56:33 +0000624 if (flags & (F_DS | F_DNSKEY))
625 new->uid = class;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000626#endif
Simon Kelley65a01b72018-12-31 23:56:33 +0000627
628 if (addr)
Simon Kelleycc921df2019-01-02 22:48:59 +0000629 new->addr = *addr;
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100630
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631 new->ttd = now + (time_t)ttl;
632 new->next = new_chain;
633 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100634
635 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000636}
637
638/* after end of insertion, commit the new entries */
639void cache_end_insert(void)
640{
641 if (insert_error)
642 return;
643
644 while (new_chain)
645 {
646 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100647 /* drop CNAMEs which didn't find a target. */
648 if (is_outdated_cname_pointer(new_chain))
649 cache_free(new_chain);
650 else
651 {
652 cache_hash(new_chain);
653 cache_link(new_chain);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100654 daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
Simon Kelleya799ca02018-10-18 19:35:29 +0100655
656 /* If we're a child process, send this cache entry up the pipe to the master.
657 The marshalling process is rather nasty. */
658 if (daemon->pipe_to_parent != -1)
659 {
660 char *name = cache_get_name(new_chain);
661 ssize_t m = strlen(name);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000662 unsigned int flags = new_chain->flags;
Simon Kelleya799ca02018-10-18 19:35:29 +0100663#ifdef HAVE_DNSSEC
664 u16 class = new_chain->uid;
665#endif
666
667 read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
668 read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
669 read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
670 read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
671
Simon Kelley5b99eae2019-01-06 23:09:50 +0000672 if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
Simon Kelleya799ca02018-10-18 19:35:29 +0100673 read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000674 if (flags & F_SRV)
Alin Nastace710c342019-09-30 15:30:26 +0100675 {
676 /* A negative SRV entry is possible and has no data, obviously. */
677 if (!(flags & F_NEG))
678 blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
679 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100680#ifdef HAVE_DNSSEC
Simon Kelleyab194ed2019-01-01 01:35:30 +0000681 if (flags & F_DNSKEY)
Simon Kelleya799ca02018-10-18 19:35:29 +0100682 {
683 read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
Simon Kelleycc921df2019-01-02 22:48:59 +0000684 blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
Simon Kelleya799ca02018-10-18 19:35:29 +0100685 }
686 else if (flags & F_DS)
687 {
688 read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
689 /* A negative DS entry is possible and has no data, obviously. */
690 if (!(flags & F_NEG))
Simon Kelleycc921df2019-01-02 22:48:59 +0000691 blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
Simon Kelleya799ca02018-10-18 19:35:29 +0100692 }
693#endif
Simon Kelleya799ca02018-10-18 19:35:29 +0100694 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100695 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100696
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000697 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000698 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100699
700 /* signal end of cache insert in master process */
701 if (daemon->pipe_to_parent != -1)
702 {
703 ssize_t m = -1;
704 read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
705 }
706
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000707 new_chain = NULL;
708}
709
Simon Kelleya799ca02018-10-18 19:35:29 +0100710
711/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */
712int cache_recv_insert(time_t now, int fd)
713{
714 ssize_t m;
Simon Kelleycc921df2019-01-02 22:48:59 +0000715 union all_addr addr;
Simon Kelleya799ca02018-10-18 19:35:29 +0100716 unsigned long ttl;
717 time_t ttd;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000718 unsigned int flags;
Simon Kelleya799ca02018-10-18 19:35:29 +0100719 struct crec *crecp = NULL;
720
721 cache_start_insert();
722
723 while(1)
724 {
725
726 if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
727 return 0;
728
729 if (m == -1)
730 {
731 cache_end_insert();
732 return 1;
733 }
734
735 if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
736 !read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
737 !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
738 return 0;
739
740 daemon->namebuff[m] = 0;
741
742 ttl = difftime(ttd, now);
743
Simon Kelley5b99eae2019-01-06 23:09:50 +0000744 if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
Simon Kelleya799ca02018-10-18 19:35:29 +0100745 {
Simon Kelleyab194ed2019-01-01 01:35:30 +0000746 unsigned short class = C_IN;
747
Simon Kelleya799ca02018-10-18 19:35:29 +0100748 if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
749 return 0;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000750
Alin Nastace710c342019-09-30 15:30:26 +0100751 if ((flags & F_SRV) && !(flags & F_NEG) && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
Simon Kelley5b99eae2019-01-06 23:09:50 +0000752 return 0;
753
Simon Kelleyab194ed2019-01-01 01:35:30 +0000754#ifdef HAVE_DNSSEC
755 if (flags & F_DNSKEY)
756 {
757 if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
Simon Kelleycc921df2019-01-02 22:48:59 +0000758 !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
Simon Kelleyab194ed2019-01-01 01:35:30 +0000759 return 0;
760 }
761 else if (flags & F_DS)
762 {
763 if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
Simon Kelley2c594732019-01-03 13:42:03 +0000764 (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
Simon Kelleyab194ed2019-01-01 01:35:30 +0000765 return 0;
766 }
767#endif
768
769 crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
Simon Kelleya799ca02018-10-18 19:35:29 +0100770 }
771 else if (flags & F_CNAME)
772 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000773 struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
Simon Kelleya799ca02018-10-18 19:35:29 +0100774 /* This relies on the fact the the target of a CNAME immediately preceeds
775 it because of the order of extraction in extract_addresses, and
776 the order reversal on the new_chain. */
777 if (newc)
778 {
779 if (!crecp)
780 {
781 newc->addr.cname.target.cache = NULL;
782 /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
783 newc->addr.cname.uid = 1;
784 }
785 else
786 {
787 next_uid(crecp);
788 newc->addr.cname.target.cache = crecp;
789 newc->addr.cname.uid = crecp->uid;
790 }
791 }
792 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100793 }
794}
795
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100796int cache_find_non_terminal(char *name, time_t now)
797{
798 struct crec *crecp;
799
800 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
801 if (!is_outdated_cname_pointer(crecp) &&
802 !is_expired(now, crecp) &&
803 (crecp->flags & F_FORWARD) &&
Sven Mueller162e5e02019-02-27 21:17:37 +0000804 !(crecp->flags & F_NXDOMAIN) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100805 hostname_isequal(name, cache_get_name(crecp)))
806 return 1;
807
808 return 0;
809}
810
Simon Kelley12fae492014-02-04 22:03:06 +0000811struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000812{
813 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000814 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000815
Simon Kelley12fae492014-02-04 22:03:06 +0000816 prot &= ~F_NO_RR;
817
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000818 if (crecp) /* iterating */
819 ans = crecp->next;
820 else
821 {
822 /* first search, look for relevant entries and push to top of list
823 also free anything which has expired */
824 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000825 unsigned int ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000826
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000827 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
828 {
829 next = crecp->hash_next;
830
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000831 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000832 {
833 if ((crecp->flags & F_FORWARD) &&
834 (crecp->flags & prot) &&
835 hostname_isequal(cache_get_name(crecp), name))
836 {
Simon Kelley25439062013-11-25 21:14:51 +0000837 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000838 {
839 *chainp = crecp;
840 chainp = &crecp->next;
841 }
842 else
843 {
844 cache_unlink(crecp);
845 cache_link(crecp);
846 }
847
Simon Kelley824af852008-02-12 20:43:05 +0000848 /* Move all but the first entry up the hash chain
849 this implements round-robin.
850 Make sure that re-ordering doesn't break the hash-chain
851 order invariants.
852 */
Simon Kelley9e038942008-05-30 20:06:34 +0100853 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000854 {
855 *up = crecp->hash_next;
856 crecp->hash_next = *insert;
857 *insert = crecp;
858 insert = &crecp->hash_next;
859 }
Simon Kelley9e038942008-05-30 20:06:34 +0100860 else
861 {
Simon Kelley12fae492014-02-04 22:03:06 +0000862 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100863 {
864 insert = up;
865 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
866 }
867 up = &crecp->hash_next;
868 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000869 }
870 else
871 /* case : not expired, incorrect entry. */
872 up = &crecp->hash_next;
873 }
874 else
875 {
876 /* expired entry, free it */
877 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000878 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000879 {
880 cache_unlink(crecp);
881 cache_free(crecp);
882 }
883 }
884 }
885
886 *chainp = cache_head;
887 }
888
889 if (ans &&
890 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000891 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000892 hostname_isequal(cache_get_name(ans), name))
893 return ans;
894
895 return NULL;
896}
897
Simon Kelleycc921df2019-01-02 22:48:59 +0000898struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000899 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000900{
901 struct crec *ans;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000902 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000903
904 if (crecp) /* iterating */
905 ans = crecp->next;
906 else
907 {
908 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000909 also free anything which has expired. All the reverse entries are at the
910 start of the hash chain, so we can give up when we find the first
911 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000912 int i;
913 struct crec **up, **chainp = &ans;
914
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000915 for (i=0; i<hash_size; i++)
916 for (crecp = hash_table[i], up = &hash_table[i];
917 crecp && (crecp->flags & F_REVERSE);
918 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000919 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000920 {
Simon Kelley6b010842007-02-12 20:32:07 +0000921 if ((crecp->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000922 memcmp(&crecp->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000923 {
Simon Kelley25439062013-11-25 21:14:51 +0000924 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000925 {
926 *chainp = crecp;
927 chainp = &crecp->next;
928 }
929 else
930 {
931 cache_unlink(crecp);
932 cache_link(crecp);
933 }
934 }
935 up = &crecp->hash_next;
936 }
937 else
938 {
939 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000940 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000941 {
942 cache_unlink(crecp);
943 cache_free(crecp);
944 }
945 }
946
947 *chainp = cache_head;
948 }
949
950 if (ans &&
951 (ans->flags & F_REVERSE) &&
952 (ans->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000953 memcmp(&ans->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000954 return ans;
955
956 return NULL;
957}
958
Simon Kelley611ebc52012-07-16 16:23:46 +0100959static void add_hosts_cname(struct crec *target)
960{
961 struct crec *crec;
962 struct cname *a;
963
964 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +0000965 if (a->alias[1] != '*' &&
966 hostname_isequal(cache_get_name(target), a->target) &&
Simon Kelley3a610a02018-09-26 16:50:35 +0100967 (crec = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelley611ebc52012-07-16 16:23:46 +0100968 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000969 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000970 crec->ttd = a->ttl;
Simon Kelley611ebc52012-07-16 16:23:46 +0100971 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100972 crec->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +0100973 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +0100974 crec->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +0100975 crec->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +0100976 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100977 make_non_terminals(crec);
978
Simon Kelley611ebc52012-07-16 16:23:46 +0100979 add_hosts_cname(crec); /* handle chains */
980 }
981}
982
Simon Kelleycc921df2019-01-02 22:48:59 +0000983static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000984 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000985{
Simon Kelleye759d422012-03-16 13:18:57 +0000986 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
Simon Kelley9009d742008-11-14 20:04:27 +0000987 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000988 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000989
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000990 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000991 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000992 {
Simon Kelley9009d742008-11-14 20:04:27 +0000993 nameexists = 1;
Simon Kelleycc921df2019-01-02 22:48:59 +0000994 if (memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley9009d742008-11-14 20:04:27 +0000995 {
996 free(cache);
997 return;
998 }
999 }
1000
1001 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +00001002 We do this by steam here, The entries are kept in hash chains, linked
1003 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001004 the array rhash, hashed on address. Note that rhash and the values
1005 in ->next are only valid whilst reading hosts files: the buckets are
1006 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +00001007
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001008 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +00001009
1010 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +00001011 large (10000 entry) hosts files.
1012
1013 Note that we only do this process when bulk-reading hosts files,
1014 for incremental reads, rhash is NULL, and we use cache lookups
1015 instead.
1016 */
Simon Kelley9009d742008-11-14 20:04:27 +00001017
Simon Kelley70d18732015-01-31 19:59:29 +00001018 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +00001019 {
Simon Kelley70d18732015-01-31 19:59:29 +00001020 /* hash address */
1021 for (j = 0, i = 0; i < addrlen; i++)
1022 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
1023
1024 for (lookup = rhash[j]; lookup; lookup = lookup->next)
1025 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001026 memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley70d18732015-01-31 19:59:29 +00001027 {
1028 cache->flags &= ~F_REVERSE;
1029 break;
1030 }
1031
1032 /* maintain address hash chain, insert new unique address */
1033 if (!lookup)
1034 {
1035 cache->next = rhash[j];
1036 rhash[j] = cache;
1037 }
Simon Kelley915363f2012-01-11 22:00:48 +00001038 }
Simon Kelley70d18732015-01-31 19:59:29 +00001039 else
1040 {
1041 /* incremental read, lookup in cache */
1042 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
1043 if (lookup && lookup->flags & F_HOSTS)
1044 cache->flags &= ~F_REVERSE;
1045 }
1046
Simon Kelley9009d742008-11-14 20:04:27 +00001047 cache->uid = index;
Simon Kelleycc921df2019-01-02 22:48:59 +00001048 memcpy(&cache->addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +00001049 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001050 make_non_terminals(cache);
Simon Kelley9009d742008-11-14 20:04:27 +00001051
1052 /* don't need to do alias stuff for second and subsequent addresses. */
1053 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +01001054 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +00001055}
1056
1057static int eatspace(FILE *f)
1058{
1059 int c, nl = 0;
1060
1061 while (1)
1062 {
1063 if ((c = getc(f)) == '#')
1064 while (c != '\n' && c != EOF)
1065 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +00001066
Simon Kelley9009d742008-11-14 20:04:27 +00001067 if (c == EOF)
1068 return 1;
1069
1070 if (!isspace(c))
1071 {
1072 ungetc(c, f);
1073 return nl;
1074 }
1075
1076 if (c == '\n')
Simon Kelley4219ade2019-02-27 20:30:21 +00001077 nl++;
Simon Kelley9009d742008-11-14 20:04:27 +00001078 }
1079}
1080
1081static int gettok(FILE *f, char *token)
1082{
1083 int c, count = 0;
1084
1085 while (1)
1086 {
1087 if ((c = getc(f)) == EOF)
Simon Kelley4219ade2019-02-27 20:30:21 +00001088 return (count == 0) ? -1 : 1;
Simon Kelley9009d742008-11-14 20:04:27 +00001089
1090 if (isspace(c) || c == '#')
1091 {
1092 ungetc(c, f);
1093 return eatspace(f);
1094 }
1095
1096 if (count < (MAXDNAME - 1))
1097 {
1098 token[count++] = c;
1099 token[count] = 0;
1100 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001101 }
1102}
1103
Simon Kelley70d18732015-01-31 19:59:29 +00001104int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001105{
1106 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +00001107 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4219ade2019-02-27 20:30:21 +00001108 int addr_count = 0, name_count = cache_size, lineno = 1;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001109 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001110 union all_addr addr;
Simon Kelley205fafa2012-01-11 21:31:51 +00001111 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +01001112
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001113 if (!f)
1114 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001115 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +00001116 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001117 }
Simon Kelley9009d742008-11-14 20:04:27 +00001118
Simon Kelley4219ade2019-02-27 20:30:21 +00001119 lineno += eatspace(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001120
Simon Kelley4219ade2019-02-27 20:30:21 +00001121 while ((atnl = gettok(f, token)) != -1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001122 {
Simon Kelley3d8df262005-08-29 12:19:27 +01001123 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001124 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001125 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001126 addrlen = INADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001127 domain_suffix = get_domain(addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001128 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001129 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001130 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001131 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001132 addrlen = IN6ADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001133 domain_suffix = get_domain6(&addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001134 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001135 else
Simon Kelleyb8187c82005-11-26 21:46:27 +00001136 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001137 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +00001138 while (atnl == 0)
1139 atnl = gettok(f, token);
Simon Kelley065e5bb2019-03-01 14:38:51 +00001140 lineno += atnl;
Simon Kelleyb8187c82005-11-26 21:46:27 +00001141 continue;
1142 }
Simon Kelley9009d742008-11-14 20:04:27 +00001143
Simon Kelley9009d742008-11-14 20:04:27 +00001144 addr_count++;
1145
1146 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +00001147 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +00001148 {
1149 rehash(name_count);
1150 cache_size = name_count;
1151 }
1152
1153 while (atnl == 0)
1154 {
1155 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +01001156 int fqdn, nomem;
1157 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +00001158
Simon Kelley4219ade2019-02-27 20:30:21 +00001159 if ((atnl = gettok(f, token)) == -1)
Simon Kelley9009d742008-11-14 20:04:27 +00001160 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001161
Simon Kelley9009d742008-11-14 20:04:27 +00001162 fqdn = !!strchr(token, '.');
1163
Simon Kelley1f15b812009-10-13 17:49:32 +01001164 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +00001165 {
1166 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +00001167 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001168 (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
Simon Kelley9009d742008-11-14 20:04:27 +00001169 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001170 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +00001171 strcat(cache->name.sname, ".");
1172 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +00001173 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001174 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001175 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001176 name_count++;
1177 }
Simon Kelley3a610a02018-09-26 16:50:35 +01001178 if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
Simon Kelley9009d742008-11-14 20:04:27 +00001179 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001180 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +00001181 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001182 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001183 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001184 name_count++;
1185 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001186 free(canon);
1187
Simon Kelley9009d742008-11-14 20:04:27 +00001188 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001189 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001190 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1191 }
Simon Kelley4219ade2019-02-27 20:30:21 +00001192
1193 lineno += atnl;
Simon Kelley9009d742008-11-14 20:04:27 +00001194 }
1195
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001196 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001197
Simon Kelley70d18732015-01-31 19:59:29 +00001198 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001199 rehash(name_count);
1200
1201 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1202
Simon Kelley4011c4e2006-10-28 16:26:19 +01001203 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001204}
1205
Simon Kelley7622fc02009-06-04 20:32:05 +01001206void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001207{
1208 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001209 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001210 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001211 struct host_record *hr;
1212 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001213 struct cname *a;
1214 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001215#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001216 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001217#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001218
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001219 daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
1220 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
Simon Kelley59353a62004-11-21 19:34:28 +00001221
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001222 for (i=0; i<hash_size; i++)
1223 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1224 {
Simon Kelley82e3f452014-01-31 21:05:48 +00001225 cache_blockdata_free(cache);
Simon Kelley5b99eae2019-01-06 23:09:50 +00001226
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001227 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001228 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001229 {
1230 *up = cache->hash_next;
1231 free(cache);
1232 }
1233 else if (!(cache->flags & F_DHCP))
1234 {
1235 *up = cache->hash_next;
1236 if (cache->flags & F_BIGNAME)
1237 {
1238 cache->name.bname->next = big_free;
1239 big_free = cache->name.bname;
1240 }
1241 cache->flags = 0;
1242 }
1243 else
1244 up = &cache->hash_next;
1245 }
1246
Simon Kelleyd56a6042013-10-11 14:39:03 +01001247 /* Add CNAMEs to interface_names to the cache */
1248 for (a = daemon->cnames; a; a = a->next)
1249 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001250 if (a->alias[1] != '*' &&
1251 hostname_isequal(a->target, intr->name) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001252 ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001253 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001254 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001255 cache->ttd = a->ttl;
Simon Kelley532066e2013-11-26 10:14:47 +00001256 cache->name.namep = a->alias;
1257 cache->addr.cname.target.int_name = intr;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001258 cache->addr.cname.uid = SRC_INTERFACE;
Simon Kelley45d8a242018-07-17 21:01:14 +01001259 cache->uid = UID_NONE;
Simon Kelley532066e2013-11-26 10:14:47 +00001260 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001261 make_non_terminals(cache);
Simon Kelley532066e2013-11-26 10:14:47 +00001262 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001263 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001264
1265#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001266 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley3a610a02018-09-26 16:50:35 +01001267 if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001268 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001269 {
Simon Kelleyee415862014-02-11 11:07:22 +00001270 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001271 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001272 cache->name.namep = ds->name;
Simon Kelleycc921df2019-01-02 22:48:59 +00001273 cache->addr.ds.keylen = ds->digestlen;
1274 cache->addr.ds.algo = ds->algo;
1275 cache->addr.ds.keytag = ds->keytag;
1276 cache->addr.ds.digest = ds->digest_type;
Simon Kelleyee415862014-02-11 11:07:22 +00001277 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001278 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001279 make_non_terminals(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001280 }
1281#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001282
Simon Kelleye759d422012-03-16 13:18:57 +00001283 /* borrow the packet buffer for a temporary by-address hash */
1284 memset(daemon->packet, 0, daemon->packet_buff_sz);
1285 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1286 /* we overwrote the buffer... */
1287 daemon->srv_save = NULL;
1288
1289 /* Do host_records in config. */
1290 for (hr = daemon->host_records; hr; hr = hr->next)
1291 for (nl = hr->names; nl; nl = nl->next)
1292 {
1293 if (hr->addr.s_addr != 0 &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001294 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001295 {
1296 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001297 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001298 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001299 add_hosts_entry(cache, (union all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001300 }
Simon Kelleyee875042018-10-23 22:10:17 +01001301
Simon Kelleye759d422012-03-16 13:18:57 +00001302 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001303 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001304 {
1305 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001306 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001307 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001308 add_hosts_entry(cache, (union all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001309 }
Simon Kelleye759d422012-03-16 13:18:57 +00001310 }
1311
Simon Kelley28866e92011-02-14 20:19:14 +00001312 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001313 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001314 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001315 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001316 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001317 else
1318 {
1319 if (!option_bool(OPT_NO_HOSTS))
1320 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1321
1322 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1323 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1324 if (!(ah->flags & AH_INACTIVE))
1325 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1326 }
1327
Simon Kelley70d18732015-01-31 19:59:29 +00001328#ifdef HAVE_INOTIFY
1329 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1330#endif
1331
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001332}
1333
Simon Kelley7622fc02009-06-04 20:32:05 +01001334#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001335struct in_addr a_record_from_hosts(char *name, time_t now)
1336{
1337 struct crec *crecp = NULL;
1338 struct in_addr ret;
1339
1340 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1341 if (crecp->flags & F_HOSTS)
Simon Kelleycc921df2019-01-02 22:48:59 +00001342 return crecp->addr.addr4;
Simon Kelley7de060b2011-08-26 17:24:52 +01001343
1344 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1345
1346 ret.s_addr = 0;
1347 return ret;
1348}
1349
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001350void cache_unhash_dhcp(void)
1351{
Simon Kelley6b010842007-02-12 20:32:07 +00001352 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001353 int i;
1354
1355 for (i=0; i<hash_size; i++)
1356 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1357 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001358 {
1359 *up = cache->hash_next;
1360 cache->next = dhcp_spare;
1361 dhcp_spare = cache;
1362 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001363 else
1364 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001365}
1366
Simon Kelley611ebc52012-07-16 16:23:46 +01001367static void add_dhcp_cname(struct crec *target, time_t ttd)
1368{
1369 struct crec *aliasc;
1370 struct cname *a;
1371
1372 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001373 if (a->alias[1] != '*' &&
1374 hostname_isequal(cache_get_name(target), a->target))
Simon Kelley611ebc52012-07-16 16:23:46 +01001375 {
1376 if ((aliasc = dhcp_spare))
1377 dhcp_spare = dhcp_spare->next;
1378 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001379 aliasc = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley611ebc52012-07-16 16:23:46 +01001380
1381 if (aliasc)
1382 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001383 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001384 if (ttd == 0)
1385 aliasc->flags |= F_IMMORTAL;
1386 else
1387 aliasc->ttd = ttd;
1388 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001389 aliasc->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +01001390 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +01001391 aliasc->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +01001392 aliasc->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +01001393 cache_hash(aliasc);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001394 make_non_terminals(aliasc);
Simon Kelley611ebc52012-07-16 16:23:46 +01001395 add_dhcp_cname(aliasc, ttd);
1396 }
1397 }
1398}
1399
Simon Kelley4cb1b322012-02-06 14:30:41 +00001400void cache_add_dhcp_entry(char *host_name, int prot,
Simon Kelleycc921df2019-01-02 22:48:59 +00001401 union all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001402{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001403 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001404 unsigned int flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001405 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001406 size_t addrlen = sizeof(struct in_addr);
1407
Simon Kelley4cb1b322012-02-06 14:30:41 +00001408 if (prot == AF_INET6)
1409 {
1410 flags = F_IPV6;
1411 addrlen = sizeof(struct in6_addr);
1412 }
Simon Kelley9009d742008-11-14 20:04:27 +00001413
Simon Kelley12d71ed2012-08-30 15:16:41 +01001414 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1415
Simon Kelley4cb1b322012-02-06 14:30:41 +00001416 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001417 {
Simon Kelley824af852008-02-12 20:43:05 +00001418 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001419 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001420 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001421 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001422 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001423 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001424 host_name, daemon->addrbuff);
Simon Kelleycc921df2019-01-02 22:48:59 +00001425 else if (memcmp(&crec->addr, host_address, addrlen) == 0)
Simon Kelley12d71ed2012-08-30 15:16:41 +01001426 in_hosts = 1;
1427 else
1428 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001429 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001430 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001431 {
Simon Kelley65a01b72018-12-31 23:56:33 +00001432 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 +00001433 /* scan_free deletes all addresses associated with name */
1434 break;
1435 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001436 }
Simon Kelley824af852008-02-12 20:43:05 +00001437
Simon Kelley12d71ed2012-08-30 15:16:41 +01001438 /* if in hosts, don't need DHCP record */
1439 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001440 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001441
1442 /* Name in hosts, address doesn't match */
1443 if (fail_crec)
1444 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001445 inet_ntop(prot, &fail_crec->addr, daemon->namebuff, MAXDNAME);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001446 my_syslog(MS_DHCP | LOG_WARNING,
1447 _("not giving name %s to the DHCP lease of %s because "
1448 "the name exists in %s with address %s"),
1449 host_name, daemon->addrbuff,
1450 record_source(fail_crec->uid), daemon->namebuff);
1451 return;
1452 }
1453
Simon Kelleycc921df2019-01-02 22:48:59 +00001454 if ((crec = cache_find_by_addr(NULL, (union all_addr *)host_address, 0, flags)))
Simon Kelley12d71ed2012-08-30 15:16:41 +01001455 {
1456 if (crec->flags & F_NEG)
1457 {
1458 flags |= F_REVERSE;
Simon Kelleycc921df2019-01-02 22:48:59 +00001459 cache_scan_free(NULL, (union all_addr *)host_address, C_IN, 0, flags, NULL, NULL);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001460 }
1461 }
1462 else
1463 flags |= F_REVERSE;
1464
1465 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001466 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001467 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001468 crec = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001469
1470 if (crec) /* malloc may fail */
1471 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001472 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001473 if (ttd == 0)
1474 crec->flags |= F_IMMORTAL;
1475 else
1476 crec->ttd = ttd;
Simon Kelleycc921df2019-01-02 22:48:59 +00001477 crec->addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001478 crec->name.namep = host_name;
Simon Kelley45d8a242018-07-17 21:01:14 +01001479 crec->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001480 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001481 make_non_terminals(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001482
Simon Kelley611ebc52012-07-16 16:23:46 +01001483 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001484 }
1485}
Simon Kelley7622fc02009-06-04 20:32:05 +01001486#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001487
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001488/* Called when we put a local or DHCP name into the cache.
1489 Creates empty cache entries for subnames (ie,
1490 for three.two.one, for two.one and one), without
1491 F_IPV4 or F_IPV6 or F_CNAME set. These convert
1492 NXDOMAIN answers to NoData ones. */
1493static void make_non_terminals(struct crec *source)
1494{
1495 char *name = cache_get_name(source);
Simon Kelleyea6cc332018-09-18 23:21:17 +01001496 struct crec *crecp, *tmp, **up;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001497 int type = F_HOSTS | F_CONFIG;
1498#ifdef HAVE_DHCP
1499 if (source->flags & F_DHCP)
1500 type = F_DHCP;
1501#endif
1502
1503 /* First delete any empty entries for our new real name. Note that
1504 we only delete empty entries deriving from DHCP for a new DHCP-derived
1505 entry and vice-versa for HOSTS and CONFIG. This ensures that
1506 non-terminals from DHCP go when we reload DHCP and
1507 for HOSTS/CONFIG when we re-read. */
1508 for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
1509 {
1510 tmp = crecp->hash_next;
1511
1512 if (!is_outdated_cname_pointer(crecp) &&
1513 (crecp->flags & F_FORWARD) &&
1514 (crecp->flags & type) &&
Simon Kelleycbfbd172018-08-21 18:25:18 +01001515 !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS)) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001516 hostname_isequal(name, cache_get_name(crecp)))
1517 {
1518 *up = crecp->hash_next;
1519#ifdef HAVE_DHCP
1520 if (type & F_DHCP)
1521 {
1522 crecp->next = dhcp_spare;
1523 dhcp_spare = crecp;
1524 }
1525 else
1526#endif
1527 free(crecp);
1528 break;
1529 }
1530 else
1531 up = &crecp->hash_next;
1532 }
1533
1534 while ((name = strchr(name, '.')))
1535 {
1536 name++;
1537
1538 /* Look for one existing, don't need another */
1539 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
1540 if (!is_outdated_cname_pointer(crecp) &&
1541 (crecp->flags & F_FORWARD) &&
1542 (crecp->flags & type) &&
1543 hostname_isequal(name, cache_get_name(crecp)))
1544 break;
1545
1546 if (crecp)
1547 {
1548 /* If the new name expires later, transfer that time to
1549 empty non-terminal entry. */
1550 if (!(crecp->flags & F_IMMORTAL))
1551 {
1552 if (source->flags & F_IMMORTAL)
1553 crecp->flags |= F_IMMORTAL;
1554 else if (difftime(crecp->ttd, source->ttd) < 0)
1555 crecp->ttd = source->ttd;
1556 }
1557 continue;
1558 }
1559
1560#ifdef HAVE_DHCP
1561 if ((source->flags & F_DHCP) && dhcp_spare)
1562 {
1563 crecp = dhcp_spare;
1564 dhcp_spare = dhcp_spare->next;
1565 }
1566 else
1567#endif
Simon Kelley3a610a02018-09-26 16:50:35 +01001568 crecp = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001569
Simon Kelleyea6cc332018-09-18 23:21:17 +01001570 if (crecp)
1571 {
Simon Kelley48b090c2018-09-26 12:53:59 +01001572 crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
1573 crecp->ttd = source->ttd;
Simon Kelleyea6cc332018-09-18 23:21:17 +01001574 crecp->name.namep = name;
1575
1576 cache_hash(crecp);
1577 }
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001578 }
1579}
1580
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001581#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001582int cache_make_stat(struct txt_record *t)
1583{
1584 static char *buff = NULL;
1585 static int bufflen = 60;
1586 int len;
1587 struct server *serv, *serv1;
1588 char *p;
1589
1590 if (!buff && !(buff = whine_malloc(60)))
1591 return 0;
1592
1593 p = buff;
1594
1595 switch (t->stat)
1596 {
1597 case TXT_STAT_CACHESIZE:
1598 sprintf(buff+1, "%d", daemon->cachesize);
1599 break;
1600
1601 case TXT_STAT_INSERTS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001602 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001603 break;
1604
1605 case TXT_STAT_EVICTIONS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001606 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001607 break;
1608
1609 case TXT_STAT_MISSES:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001610 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001611 break;
1612
1613 case TXT_STAT_HITS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001614 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001615 break;
1616
1617#ifdef HAVE_AUTH
1618 case TXT_STAT_AUTH:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001619 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001620 break;
1621#endif
1622
1623 case TXT_STAT_SERVERS:
1624 /* sum counts from different records for same server */
1625 for (serv = daemon->servers; serv; serv = serv->next)
1626 serv->flags &= ~SERV_COUNTED;
1627
1628 for (serv = daemon->servers; serv; serv = serv->next)
1629 if (!(serv->flags &
1630 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1631 {
1632 char *new, *lenp;
1633 int port, newlen, bytes_avail, bytes_needed;
1634 unsigned int queries = 0, failed_queries = 0;
1635 for (serv1 = serv; serv1; serv1 = serv1->next)
1636 if (!(serv1->flags &
1637 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1638 sockaddr_isequal(&serv->addr, &serv1->addr))
1639 {
1640 serv1->flags |= SERV_COUNTED;
1641 queries += serv1->queries;
1642 failed_queries += serv1->failed_queries;
1643 }
1644 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1645 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001646 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001647 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1648 if (bytes_needed >= bytes_avail)
1649 {
1650 /* expand buffer if necessary */
1651 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1652 if (!(new = whine_malloc(newlen)))
1653 return 0;
1654 memcpy(new, buff, bufflen);
1655 free(buff);
1656 p = new + (p - buff);
1657 lenp = p - 1;
1658 buff = new;
1659 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001660 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001661 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1662 }
1663 *lenp = bytes_needed;
1664 p += bytes_needed;
1665 }
1666 t->txt = (unsigned char *)buff;
1667 t->len = p - buff;
1668 return 1;
1669 }
1670
1671 len = strlen(buff+1);
1672 t->txt = (unsigned char *)buff;
1673 t->len = len + 1;
1674 *buff = len;
1675 return 1;
1676}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001677#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001678
Simon Kelley394ff492015-03-29 22:17:14 +01001679/* There can be names in the cache containing control chars, don't
1680 mess up logging or open security holes. */
1681static char *sanitise(char *name)
1682{
1683 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001684 if (name)
1685 for (r = (unsigned char *)name; *r; r++)
1686 if (!isprint((int)*r))
1687 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001688
1689 return name;
1690}
1691
1692
Simon Kelley5aabfc72007-08-29 11:24:47 +01001693void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001694{
Simon Kelley824af852008-02-12 20:43:05 +00001695 struct server *serv, *serv1;
1696
1697 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1698 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001699 daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelley824af852008-02-12 20:43:05 +00001700 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001701 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001702#ifdef HAVE_AUTH
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001703 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001704#endif
Simon Kelley5b99eae2019-01-06 23:09:50 +00001705
Simon Kelleyc2207682014-01-08 18:04:20 +00001706 blockdata_report();
Simon Kelley824af852008-02-12 20:43:05 +00001707
Simon Kelley824af852008-02-12 20:43:05 +00001708 /* sum counts from different records for same server */
1709 for (serv = daemon->servers; serv; serv = serv->next)
1710 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001711
Simon Kelley824af852008-02-12 20:43:05 +00001712 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001713 if (!(serv->flags &
1714 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001715 {
1716 int port;
1717 unsigned int queries = 0, failed_queries = 0;
1718 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001719 if (!(serv1->flags &
1720 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1721 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001722 {
1723 serv1->flags |= SERV_COUNTED;
1724 queries += serv1->queries;
1725 failed_queries += serv1->failed_queries;
1726 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001727 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1728 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 +00001729 }
1730
Simon Kelley28866e92011-02-14 20:19:14 +00001731 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001732 {
1733 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001734 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001735 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001736
1737 for (i=0; i<hash_size; i++)
1738 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1739 {
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001740 char *t = " ";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001741 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1742 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001743 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001744 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001745 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001746 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001747 a = sanitise(cache_get_cname_target(cache));
Simon Kelley5b99eae2019-01-06 23:09:50 +00001748 else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG))
1749 {
1750 int targetlen = cache->addr.srv.targetlen;
1751 ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority,
1752 cache->addr.srv.weight, cache->addr.srv.srvport);
1753
1754 if (targetlen > (40 - len))
1755 targetlen = 40 - len;
1756 blockdata_retrieve(cache->addr.srv.target, targetlen, a + len);
1757 a[len + targetlen] = 0;
1758 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001759#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001760 else if (cache->flags & F_DS)
1761 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001762 if (!(cache->flags & F_NEG))
Simon Kelleycc921df2019-01-02 22:48:59 +00001763 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1764 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001765 }
1766 else if (cache->flags & F_DNSKEY)
Simon Kelleycc921df2019-01-02 22:48:59 +00001767 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1768 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001769#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001770 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001771 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001772 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001773 if (cache->flags & F_IPV4)
Simon Kelleycc921df2019-01-02 22:48:59 +00001774 inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001775 else if (cache->flags & F_IPV6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001776 inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001777 }
1778
Simon Kelleye7829ae2014-01-22 22:21:51 +00001779 if (cache->flags & F_IPV4)
1780 t = "4";
1781 else if (cache->flags & F_IPV6)
1782 t = "6";
1783 else if (cache->flags & F_CNAME)
1784 t = "C";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001785 else if (cache->flags & F_SRV)
1786 t = "V";
Simon Kelleye7829ae2014-01-22 22:21:51 +00001787#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001788 else if (cache->flags & F_DS)
1789 t = "S";
1790 else if (cache->flags & F_DNSKEY)
1791 t = "K";
1792#endif
Simon Kelley32678042014-12-17 20:38:20 +00001793 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001794 cache->flags & F_FORWARD ? "F" : " ",
1795 cache->flags & F_REVERSE ? "R" : " ",
1796 cache->flags & F_IMMORTAL ? "I" : " ",
1797 cache->flags & F_DHCP ? "D" : " ",
1798 cache->flags & F_NEG ? "N" : " ",
1799 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001800 cache->flags & F_HOSTS ? "H" : " ",
1801 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001802#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001803 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001804#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001805 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1806 /* ctime includes trailing \n - eat it */
1807 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001808#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001809 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001810 }
1811 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001812}
1813
Simon Kelley19c51cf2014-03-18 22:38:30 +00001814char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001815{
Simon Kelley7622fc02009-06-04 20:32:05 +01001816 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001817
Simon Kelley19c51cf2014-03-18 22:38:30 +00001818 if (index == SRC_CONFIG)
1819 return "config";
1820 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001821 return HOSTSFILE;
1822
1823 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1824 if (ah->index == index)
1825 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001826
1827#ifdef HAVE_INOTIFY
1828 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1829 if (ah->index == index)
1830 return ah->fname;
1831#endif
1832
Simon Kelley7622fc02009-06-04 20:32:05 +01001833 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001834}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001835
Simon Kelley610e7822014-02-06 14:45:17 +00001836char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001837{
1838 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001839 int len = 10; /* strlen("type=xxxxx") */
1840 const char *types = NULL;
1841 static char *buff = NULL;
1842 static int bufflen = 0;
1843
Simon Kelley1a6bca82008-07-11 11:11:42 +01001844 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1845 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001846 {
1847 types = typestr[i].name;
1848 len = strlen(types);
1849 break;
1850 }
1851
Simon Kelleyb758b672018-08-23 21:41:23 +01001852 if (desc)
1853 {
1854 len += 2; /* braces */
1855 len += strlen(desc);
1856 }
1857 len++; /* terminator */
1858
Simon Kelley610e7822014-02-06 14:45:17 +00001859 if (!buff || bufflen < len)
1860 {
1861 if (buff)
1862 free(buff);
1863 else if (len < 20)
1864 len = 20;
1865
1866 buff = whine_malloc(len);
1867 bufflen = len;
1868 }
1869
1870 if (buff)
1871 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001872 if (desc)
1873 {
1874 if (types)
1875 sprintf(buff, "%s[%s]", desc, types);
1876 else
1877 sprintf(buff, "%s[type=%d]", desc, type);
1878 }
Simon Kelley610e7822014-02-06 14:45:17 +00001879 else
Simon Kelleyb758b672018-08-23 21:41:23 +01001880 {
1881 if (types)
1882 sprintf(buff, "<%s>", types);
1883 else
1884 sprintf(buff, "type=%d", type);
1885 }
Simon Kelley610e7822014-02-06 14:45:17 +00001886 }
Simon Kelleyb758b672018-08-23 21:41:23 +01001887
Simon Kelley610e7822014-02-06 14:45:17 +00001888 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001889}
1890
Simon Kelleycc921df2019-01-02 22:48:59 +00001891void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001892{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001893 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001894 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001895
Simon Kelley28866e92011-02-14 20:19:14 +00001896 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001897 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001898
Simon Kelley394ff492015-03-29 22:17:14 +01001899 name = sanitise(name);
1900
Simon Kelley5aabfc72007-08-29 11:24:47 +01001901 if (addr)
1902 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001903 if (flags & F_KEYTAG)
Simon Kelleycc921df2019-01-02 22:48:59 +00001904 sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
Simon Kelley07ed5852018-05-04 21:52:22 +01001905 else if (flags & F_RCODE)
1906 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001907 unsigned int rcode = addr->log.rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +01001908
1909 if (rcode == SERVFAIL)
1910 dest = "SERVFAIL";
1911 else if (rcode == REFUSED)
1912 dest = "REFUSED";
1913 else if (rcode == NOTIMP)
1914 dest = "not implemented";
1915 else
1916 sprintf(daemon->addrbuff, "%u", rcode);
1917 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001918 else
Simon Kelleyee875042018-10-23 22:10:17 +01001919 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1920 addr, daemon->addrbuff, ADDRSTRLEN);
1921
Simon Kelley5aabfc72007-08-29 11:24:47 +01001922 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001923 else
1924 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001925
1926 if (flags & F_REVERSE)
1927 {
1928 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001929 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001930 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001931
1932 if (flags & F_NEG)
1933 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001934 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001935 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001936 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001937 {
1938 if (flags & F_IPV4)
1939 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001940 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001941 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001942 else
1943 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001944 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001945 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001946 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001947 dest = "<CNAME>";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001948 else if (flags & F_SRV)
1949 dest = "<SRV>";
Simon Kelley28866e92011-02-14 20:19:14 +00001950 else if (flags & F_RRNAME)
1951 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001952
Simon Kelley1f15b812009-10-13 17:49:32 +01001953 if (flags & F_CONFIG)
1954 source = "config";
1955 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001956 source = "DHCP";
1957 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001958 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001959 else if (flags & F_UPSTREAM)
1960 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001961 else if (flags & F_SECSTAT)
1962 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001963 else if (flags & F_AUTH)
1964 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001965 else if (flags & F_SERVER)
1966 {
1967 source = "forwarded";
1968 verb = "to";
1969 }
1970 else if (flags & F_QUERY)
1971 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001972 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001973 verb = "from";
1974 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001975 else if (flags & F_DNSSEC)
1976 {
1977 source = arg;
1978 verb = "to";
1979 }
Wang Jian49752b92014-03-28 20:52:47 +00001980 else if (flags & F_IPSET)
1981 {
1982 source = "ipset add";
1983 dest = name;
1984 name = arg;
1985 verb = daemon->addrbuff;
1986 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001987 else
1988 source = "cached";
1989
Simon Kelley3d8df262005-08-29 12:19:27 +01001990 if (strlen(name) == 0)
1991 name = ".";
1992
Simon Kelley25cf5e32015-01-09 15:53:03 +00001993 if (option_bool(OPT_EXTRALOG))
1994 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001995 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001996 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001997 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001998 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001999 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 +00002000 }
2001 else
2002 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002003}
2004
Simon Kelley98c098b2014-01-08 17:31:16 +00002005