blob: b3ed50ba9f3e791b39e36be3085f8df607d456c8 [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 Kelley8d718cb2014-02-03 16:27:37 +0000502
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000503 /* First remove any expired entries and entries for the name/address we
Simon Kelleycbc65242014-12-21 21:21:53 +0000504 are currently inserting. */
Simon Kelley65a01b72018-12-31 23:56:33 +0000505 if ((new = cache_scan_free(name, addr, class, now, flags, &target_crec, &target_uid)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000506 {
Simon Kelleycbc65242014-12-21 21:21:53 +0000507 /* We're trying to insert a record over one from
508 /etc/hosts or DHCP, or other config. If the
509 existing record is for an A or AAAA and
510 the record we're trying to insert is the same,
511 just drop the insert, but don't error the whole process. */
Edwin Török41a8d9e2015-11-14 17:45:48 +0000512 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000513 {
514 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000515 new->addr.addr4.s_addr == addr->addr4.s_addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000516 return new;
Simon Kelleycbc65242014-12-21 21:21:53 +0000517 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000518 IN6_ARE_ADDR_EQUAL(&new->addr.addr6, &addr->addr6))
Simon Kelleycbc65242014-12-21 21:21:53 +0000519 return new;
Simon Kelleycbc65242014-12-21 21:21:53 +0000520 }
521
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000522 insert_error = 1;
523 return NULL;
524 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000525
526 /* Now get a cache entry from the end of the LRU list */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100527 if (!target_crec)
528 while (1) {
529 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
530 {
531 insert_error = 1;
532 return NULL;
533 }
534
535 /* Free entry at end of LRU list, use it. */
536 if (!(new->flags & (F_FORWARD | F_REVERSE)))
537 break;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000538
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100539 /* End of LRU list is still in use: if we didn't scan all the hash
540 chains for expired entries do that now. If we already tried that
541 then it's time to start spilling things. */
542
543 /* If free_avail set, we believe that an entry has been freed.
544 Bugs have been known to make this not true, resulting in
545 a tight loop here. If that happens, abandon the
546 insert. Once in this state, all inserts will probably fail. */
547 if (free_avail)
548 {
549 static int warned = 0;
550 if (!warned)
551 {
552 my_syslog(LOG_ERR, _("Internal error in cache."));
553 warned = 1;
554 }
555 insert_error = 1;
556 return NULL;
557 }
558
559 if (freed_all)
560 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000561 /* For DNSSEC records, uid holds class. */
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100562 free_avail = 1; /* Must be free space now. */
Simon Kelleycc921df2019-01-02 22:48:59 +0000563 cache_scan_free(cache_get_name(new), &new->addr, new->uid, now, new->flags, NULL, NULL);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100564 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100565 }
566 else
567 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000568 cache_scan_free(NULL, NULL, class, now, 0, NULL, NULL);
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100569 freed_all = 1;
570 }
571 }
572
573 /* Check if we need to and can allocate extra memory for a long name.
574 If that fails, give up now, always succeed for DNSSEC records. */
575 if (name && (strlen(name) > SMALLDNAME-1))
576 {
577 if (big_free)
578 {
579 big_name = big_free;
580 big_free = big_free->next;
581 }
582 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
583 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
584 {
585 insert_error = 1;
586 return NULL;
587 }
588 else if (bignames_left != 0)
589 bignames_left--;
590
591 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000592
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100593 /* If we freed a cache entry for our name which was a CNAME target, use that.
594 and preserve the uid, so that existing CNAMES are not broken. */
595 if (target_crec)
596 {
597 new = target_crec;
598 new->uid = target_uid;
599 }
600
601 /* Got the rest: finally grab entry. */
602 cache_unlink(new);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000603
604 new->flags = flags;
605 if (big_name)
606 {
607 new->name.bname = big_name;
608 new->flags |= F_BIGNAME;
609 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100610
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000611 if (name)
612 strcpy(cache_get_name(new), name);
613 else
614 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100615
Simon Kelleyb8eac192014-02-27 14:30:03 +0000616#ifdef HAVE_DNSSEC
Simon Kelley65a01b72018-12-31 23:56:33 +0000617 if (flags & (F_DS | F_DNSKEY))
618 new->uid = class;
Simon Kelleyb8eac192014-02-27 14:30:03 +0000619#endif
Simon Kelley65a01b72018-12-31 23:56:33 +0000620
621 if (addr)
Simon Kelleycc921df2019-01-02 22:48:59 +0000622 new->addr = *addr;
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100623
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000624 new->ttd = now + (time_t)ttl;
625 new->next = new_chain;
626 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100627
628 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000629}
630
631/* after end of insertion, commit the new entries */
632void cache_end_insert(void)
633{
634 if (insert_error)
635 return;
636
637 while (new_chain)
638 {
639 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100640 /* drop CNAMEs which didn't find a target. */
641 if (is_outdated_cname_pointer(new_chain))
642 cache_free(new_chain);
643 else
644 {
645 cache_hash(new_chain);
646 cache_link(new_chain);
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +0100647 daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
Simon Kelleya799ca02018-10-18 19:35:29 +0100648
649 /* If we're a child process, send this cache entry up the pipe to the master.
650 The marshalling process is rather nasty. */
651 if (daemon->pipe_to_parent != -1)
652 {
653 char *name = cache_get_name(new_chain);
654 ssize_t m = strlen(name);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000655 unsigned int flags = new_chain->flags;
Simon Kelleya799ca02018-10-18 19:35:29 +0100656#ifdef HAVE_DNSSEC
657 u16 class = new_chain->uid;
658#endif
659
660 read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
661 read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
662 read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
663 read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
664
Simon Kelley5b99eae2019-01-06 23:09:50 +0000665 if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
Simon Kelleya799ca02018-10-18 19:35:29 +0100666 read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000667 if (flags & F_SRV)
Alin Nastace710c342019-09-30 15:30:26 +0100668 {
669 /* A negative SRV entry is possible and has no data, obviously. */
670 if (!(flags & F_NEG))
671 blockdata_write(new_chain->addr.srv.target, new_chain->addr.srv.targetlen, daemon->pipe_to_parent);
672 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100673#ifdef HAVE_DNSSEC
Simon Kelleyab194ed2019-01-01 01:35:30 +0000674 if (flags & F_DNSKEY)
Simon Kelleya799ca02018-10-18 19:35:29 +0100675 {
676 read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
Simon Kelleycc921df2019-01-02 22:48:59 +0000677 blockdata_write(new_chain->addr.key.keydata, new_chain->addr.key.keylen, daemon->pipe_to_parent);
Simon Kelleya799ca02018-10-18 19:35:29 +0100678 }
679 else if (flags & F_DS)
680 {
681 read_write(daemon->pipe_to_parent, (unsigned char *)&class, sizeof(class), 0);
682 /* A negative DS entry is possible and has no data, obviously. */
683 if (!(flags & F_NEG))
Simon Kelleycc921df2019-01-02 22:48:59 +0000684 blockdata_write(new_chain->addr.ds.keydata, new_chain->addr.ds.keylen, daemon->pipe_to_parent);
Simon Kelleya799ca02018-10-18 19:35:29 +0100685 }
686#endif
Simon Kelleya799ca02018-10-18 19:35:29 +0100687 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100688 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100689
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000690 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000691 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100692
693 /* signal end of cache insert in master process */
694 if (daemon->pipe_to_parent != -1)
695 {
696 ssize_t m = -1;
697 read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), 0);
698 }
699
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000700 new_chain = NULL;
701}
702
Simon Kelleya799ca02018-10-18 19:35:29 +0100703
704/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */
705int cache_recv_insert(time_t now, int fd)
706{
707 ssize_t m;
Simon Kelleycc921df2019-01-02 22:48:59 +0000708 union all_addr addr;
Simon Kelleya799ca02018-10-18 19:35:29 +0100709 unsigned long ttl;
710 time_t ttd;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000711 unsigned int flags;
Simon Kelleya799ca02018-10-18 19:35:29 +0100712 struct crec *crecp = NULL;
713
714 cache_start_insert();
715
716 while(1)
717 {
718
719 if (!read_write(fd, (unsigned char *)&m, sizeof(m), 1))
720 return 0;
721
722 if (m == -1)
723 {
724 cache_end_insert();
725 return 1;
726 }
727
728 if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
729 !read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
730 !read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
731 return 0;
732
733 daemon->namebuff[m] = 0;
734
735 ttl = difftime(ttd, now);
736
Simon Kelley5b99eae2019-01-06 23:09:50 +0000737 if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_SRV))
Simon Kelleya799ca02018-10-18 19:35:29 +0100738 {
Simon Kelleyab194ed2019-01-01 01:35:30 +0000739 unsigned short class = C_IN;
740
Simon Kelleya799ca02018-10-18 19:35:29 +0100741 if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
742 return 0;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000743
Alin Nastace710c342019-09-30 15:30:26 +0100744 if ((flags & F_SRV) && !(flags & F_NEG) && !(addr.srv.target = blockdata_read(fd, addr.srv.targetlen)))
Simon Kelley5b99eae2019-01-06 23:09:50 +0000745 return 0;
746
Simon Kelleyab194ed2019-01-01 01:35:30 +0000747#ifdef HAVE_DNSSEC
748 if (flags & F_DNSKEY)
749 {
750 if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
Simon Kelleycc921df2019-01-02 22:48:59 +0000751 !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
Simon Kelleyab194ed2019-01-01 01:35:30 +0000752 return 0;
753 }
754 else if (flags & F_DS)
755 {
756 if (!read_write(fd, (unsigned char *)&class, sizeof(class), 1) ||
Simon Kelley2c594732019-01-03 13:42:03 +0000757 (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
Simon Kelleyab194ed2019-01-01 01:35:30 +0000758 return 0;
759 }
760#endif
761
762 crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
Simon Kelleya799ca02018-10-18 19:35:29 +0100763 }
764 else if (flags & F_CNAME)
765 {
Simon Kelley65a01b72018-12-31 23:56:33 +0000766 struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
Simon Kelleya799ca02018-10-18 19:35:29 +0100767 /* This relies on the fact the the target of a CNAME immediately preceeds
768 it because of the order of extraction in extract_addresses, and
769 the order reversal on the new_chain. */
770 if (newc)
771 {
772 if (!crecp)
773 {
774 newc->addr.cname.target.cache = NULL;
775 /* anything other than zero, to avoid being mistaken for CNAME to interface-name */
776 newc->addr.cname.uid = 1;
777 }
778 else
779 {
780 next_uid(crecp);
781 newc->addr.cname.target.cache = crecp;
782 newc->addr.cname.uid = crecp->uid;
783 }
784 }
785 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100786 }
787}
788
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100789int cache_find_non_terminal(char *name, time_t now)
790{
791 struct crec *crecp;
792
793 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
794 if (!is_outdated_cname_pointer(crecp) &&
795 !is_expired(now, crecp) &&
796 (crecp->flags & F_FORWARD) &&
Sven Mueller162e5e02019-02-27 21:17:37 +0000797 !(crecp->flags & F_NXDOMAIN) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100798 hostname_isequal(name, cache_get_name(crecp)))
799 return 1;
800
801 return 0;
802}
803
Simon Kelley12fae492014-02-04 22:03:06 +0000804struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000805{
806 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000807 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000808
Simon Kelley12fae492014-02-04 22:03:06 +0000809 prot &= ~F_NO_RR;
810
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000811 if (crecp) /* iterating */
812 ans = crecp->next;
813 else
814 {
815 /* first search, look for relevant entries and push to top of list
816 also free anything which has expired */
817 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000818 unsigned int ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000819
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000820 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
821 {
822 next = crecp->hash_next;
823
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000824 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000825 {
826 if ((crecp->flags & F_FORWARD) &&
827 (crecp->flags & prot) &&
828 hostname_isequal(cache_get_name(crecp), name))
829 {
Simon Kelley25439062013-11-25 21:14:51 +0000830 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000831 {
832 *chainp = crecp;
833 chainp = &crecp->next;
834 }
835 else
836 {
837 cache_unlink(crecp);
838 cache_link(crecp);
839 }
840
Simon Kelley824af852008-02-12 20:43:05 +0000841 /* Move all but the first entry up the hash chain
842 this implements round-robin.
843 Make sure that re-ordering doesn't break the hash-chain
844 order invariants.
845 */
Simon Kelley9e038942008-05-30 20:06:34 +0100846 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000847 {
848 *up = crecp->hash_next;
849 crecp->hash_next = *insert;
850 *insert = crecp;
851 insert = &crecp->hash_next;
852 }
Simon Kelley9e038942008-05-30 20:06:34 +0100853 else
854 {
Simon Kelley12fae492014-02-04 22:03:06 +0000855 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100856 {
857 insert = up;
858 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
859 }
860 up = &crecp->hash_next;
861 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000862 }
863 else
864 /* case : not expired, incorrect entry. */
865 up = &crecp->hash_next;
866 }
867 else
868 {
869 /* expired entry, free it */
870 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000871 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000872 {
873 cache_unlink(crecp);
874 cache_free(crecp);
875 }
876 }
877 }
878
879 *chainp = cache_head;
880 }
881
882 if (ans &&
883 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000884 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000885 hostname_isequal(cache_get_name(ans), name))
886 return ans;
887
888 return NULL;
889}
890
Simon Kelleycc921df2019-01-02 22:48:59 +0000891struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000892 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000893{
894 struct crec *ans;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000895 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000896
897 if (crecp) /* iterating */
898 ans = crecp->next;
899 else
900 {
901 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000902 also free anything which has expired. All the reverse entries are at the
903 start of the hash chain, so we can give up when we find the first
904 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000905 int i;
906 struct crec **up, **chainp = &ans;
907
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000908 for (i=0; i<hash_size; i++)
909 for (crecp = hash_table[i], up = &hash_table[i];
910 crecp && (crecp->flags & F_REVERSE);
911 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000912 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000913 {
Simon Kelley6b010842007-02-12 20:32:07 +0000914 if ((crecp->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000915 memcmp(&crecp->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000916 {
Simon Kelley25439062013-11-25 21:14:51 +0000917 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000918 {
919 *chainp = crecp;
920 chainp = &crecp->next;
921 }
922 else
923 {
924 cache_unlink(crecp);
925 cache_link(crecp);
926 }
927 }
928 up = &crecp->hash_next;
929 }
930 else
931 {
932 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000933 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000934 {
935 cache_unlink(crecp);
936 cache_free(crecp);
937 }
938 }
939
940 *chainp = cache_head;
941 }
942
943 if (ans &&
944 (ans->flags & F_REVERSE) &&
945 (ans->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000946 memcmp(&ans->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000947 return ans;
948
949 return NULL;
950}
951
Simon Kelley611ebc52012-07-16 16:23:46 +0100952static void add_hosts_cname(struct crec *target)
953{
954 struct crec *crec;
955 struct cname *a;
956
957 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +0000958 if (a->alias[1] != '*' &&
959 hostname_isequal(cache_get_name(target), a->target) &&
Simon Kelley3a610a02018-09-26 16:50:35 +0100960 (crec = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelley611ebc52012-07-16 16:23:46 +0100961 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000962 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000963 crec->ttd = a->ttl;
Simon Kelley611ebc52012-07-16 16:23:46 +0100964 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100965 crec->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +0100966 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +0100967 crec->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +0100968 crec->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +0100969 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100970 make_non_terminals(crec);
971
Simon Kelley611ebc52012-07-16 16:23:46 +0100972 add_hosts_cname(crec); /* handle chains */
973 }
974}
975
Simon Kelleycc921df2019-01-02 22:48:59 +0000976static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000977 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000978{
Simon Kelleye759d422012-03-16 13:18:57 +0000979 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 +0000980 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000981 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000982
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000983 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000984 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000985 {
Simon Kelley9009d742008-11-14 20:04:27 +0000986 nameexists = 1;
Simon Kelleycc921df2019-01-02 22:48:59 +0000987 if (memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley9009d742008-11-14 20:04:27 +0000988 {
989 free(cache);
990 return;
991 }
992 }
993
994 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000995 We do this by steam here, The entries are kept in hash chains, linked
996 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000997 the array rhash, hashed on address. Note that rhash and the values
998 in ->next are only valid whilst reading hosts files: the buckets are
999 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +00001000
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001001 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +00001002
1003 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +00001004 large (10000 entry) hosts files.
1005
1006 Note that we only do this process when bulk-reading hosts files,
1007 for incremental reads, rhash is NULL, and we use cache lookups
1008 instead.
1009 */
Simon Kelley9009d742008-11-14 20:04:27 +00001010
Simon Kelley70d18732015-01-31 19:59:29 +00001011 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +00001012 {
Simon Kelley70d18732015-01-31 19:59:29 +00001013 /* hash address */
1014 for (j = 0, i = 0; i < addrlen; i++)
1015 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
1016
1017 for (lookup = rhash[j]; lookup; lookup = lookup->next)
1018 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001019 memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley70d18732015-01-31 19:59:29 +00001020 {
1021 cache->flags &= ~F_REVERSE;
1022 break;
1023 }
1024
1025 /* maintain address hash chain, insert new unique address */
1026 if (!lookup)
1027 {
1028 cache->next = rhash[j];
1029 rhash[j] = cache;
1030 }
Simon Kelley915363f2012-01-11 22:00:48 +00001031 }
Simon Kelley70d18732015-01-31 19:59:29 +00001032 else
1033 {
1034 /* incremental read, lookup in cache */
1035 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
1036 if (lookup && lookup->flags & F_HOSTS)
1037 cache->flags &= ~F_REVERSE;
1038 }
1039
Simon Kelley9009d742008-11-14 20:04:27 +00001040 cache->uid = index;
Simon Kelleycc921df2019-01-02 22:48:59 +00001041 memcpy(&cache->addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +00001042 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001043 make_non_terminals(cache);
Simon Kelley9009d742008-11-14 20:04:27 +00001044
1045 /* don't need to do alias stuff for second and subsequent addresses. */
1046 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +01001047 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +00001048}
1049
1050static int eatspace(FILE *f)
1051{
1052 int c, nl = 0;
1053
1054 while (1)
1055 {
1056 if ((c = getc(f)) == '#')
1057 while (c != '\n' && c != EOF)
1058 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +00001059
Simon Kelley9009d742008-11-14 20:04:27 +00001060 if (c == EOF)
1061 return 1;
1062
1063 if (!isspace(c))
1064 {
1065 ungetc(c, f);
1066 return nl;
1067 }
1068
1069 if (c == '\n')
Simon Kelley4219ade2019-02-27 20:30:21 +00001070 nl++;
Simon Kelley9009d742008-11-14 20:04:27 +00001071 }
1072}
1073
1074static int gettok(FILE *f, char *token)
1075{
1076 int c, count = 0;
1077
1078 while (1)
1079 {
1080 if ((c = getc(f)) == EOF)
Simon Kelley4219ade2019-02-27 20:30:21 +00001081 return (count == 0) ? -1 : 1;
Simon Kelley9009d742008-11-14 20:04:27 +00001082
1083 if (isspace(c) || c == '#')
1084 {
1085 ungetc(c, f);
1086 return eatspace(f);
1087 }
1088
1089 if (count < (MAXDNAME - 1))
1090 {
1091 token[count++] = c;
1092 token[count] = 0;
1093 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001094 }
1095}
1096
Simon Kelley70d18732015-01-31 19:59:29 +00001097int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001098{
1099 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +00001100 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4219ade2019-02-27 20:30:21 +00001101 int addr_count = 0, name_count = cache_size, lineno = 1;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001102 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001103 union all_addr addr;
Simon Kelley205fafa2012-01-11 21:31:51 +00001104 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +01001105
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001106 if (!f)
1107 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001108 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +00001109 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001110 }
Simon Kelley9009d742008-11-14 20:04:27 +00001111
Simon Kelley4219ade2019-02-27 20:30:21 +00001112 lineno += eatspace(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001113
Simon Kelley4219ade2019-02-27 20:30:21 +00001114 while ((atnl = gettok(f, token)) != -1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001115 {
Simon Kelley3d8df262005-08-29 12:19:27 +01001116 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001117 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001118 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001119 addrlen = INADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001120 domain_suffix = get_domain(addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001121 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001122 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001123 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001124 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001125 addrlen = IN6ADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001126 domain_suffix = get_domain6(&addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001127 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001128 else
Simon Kelleyb8187c82005-11-26 21:46:27 +00001129 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001130 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +00001131 while (atnl == 0)
1132 atnl = gettok(f, token);
Simon Kelley065e5bb2019-03-01 14:38:51 +00001133 lineno += atnl;
Simon Kelleyb8187c82005-11-26 21:46:27 +00001134 continue;
1135 }
Simon Kelley9009d742008-11-14 20:04:27 +00001136
Simon Kelley9009d742008-11-14 20:04:27 +00001137 addr_count++;
1138
1139 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +00001140 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +00001141 {
1142 rehash(name_count);
1143 cache_size = name_count;
1144 }
1145
1146 while (atnl == 0)
1147 {
1148 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +01001149 int fqdn, nomem;
1150 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +00001151
Simon Kelley4219ade2019-02-27 20:30:21 +00001152 if ((atnl = gettok(f, token)) == -1)
Simon Kelley9009d742008-11-14 20:04:27 +00001153 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001154
Simon Kelley9009d742008-11-14 20:04:27 +00001155 fqdn = !!strchr(token, '.');
1156
Simon Kelley1f15b812009-10-13 17:49:32 +01001157 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +00001158 {
1159 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +00001160 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001161 (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
Simon Kelley9009d742008-11-14 20:04:27 +00001162 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001163 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +00001164 strcat(cache->name.sname, ".");
1165 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +00001166 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001167 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001168 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001169 name_count++;
1170 }
Simon Kelley3a610a02018-09-26 16:50:35 +01001171 if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
Simon Kelley9009d742008-11-14 20:04:27 +00001172 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001173 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +00001174 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001175 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001176 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001177 name_count++;
1178 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001179 free(canon);
1180
Simon Kelley9009d742008-11-14 20:04:27 +00001181 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001182 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001183 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1184 }
Simon Kelley4219ade2019-02-27 20:30:21 +00001185
1186 lineno += atnl;
Simon Kelley9009d742008-11-14 20:04:27 +00001187 }
1188
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001189 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001190
Simon Kelley70d18732015-01-31 19:59:29 +00001191 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001192 rehash(name_count);
1193
1194 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1195
Simon Kelley4011c4e2006-10-28 16:26:19 +01001196 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001197}
1198
Simon Kelley7622fc02009-06-04 20:32:05 +01001199void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001200{
1201 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001202 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001203 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001204 struct host_record *hr;
1205 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001206 struct cname *a;
1207 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001208#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001209 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001210#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001211
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001212 daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
1213 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
Simon Kelley59353a62004-11-21 19:34:28 +00001214
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001215 for (i=0; i<hash_size; i++)
1216 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1217 {
Simon Kelley82e3f452014-01-31 21:05:48 +00001218 cache_blockdata_free(cache);
Simon Kelley5b99eae2019-01-06 23:09:50 +00001219
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001220 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001221 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001222 {
1223 *up = cache->hash_next;
1224 free(cache);
1225 }
1226 else if (!(cache->flags & F_DHCP))
1227 {
1228 *up = cache->hash_next;
1229 if (cache->flags & F_BIGNAME)
1230 {
1231 cache->name.bname->next = big_free;
1232 big_free = cache->name.bname;
1233 }
1234 cache->flags = 0;
1235 }
1236 else
1237 up = &cache->hash_next;
1238 }
1239
Simon Kelleyd56a6042013-10-11 14:39:03 +01001240 /* Add CNAMEs to interface_names to the cache */
1241 for (a = daemon->cnames; a; a = a->next)
1242 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001243 if (a->alias[1] != '*' &&
1244 hostname_isequal(a->target, intr->name) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001245 ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001246 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001247 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001248 cache->ttd = a->ttl;
Simon Kelley532066e2013-11-26 10:14:47 +00001249 cache->name.namep = a->alias;
1250 cache->addr.cname.target.int_name = intr;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001251 cache->addr.cname.uid = SRC_INTERFACE;
Simon Kelley45d8a242018-07-17 21:01:14 +01001252 cache->uid = UID_NONE;
Simon Kelley532066e2013-11-26 10:14:47 +00001253 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001254 make_non_terminals(cache);
Simon Kelley532066e2013-11-26 10:14:47 +00001255 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001256 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001257
1258#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001259 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley3a610a02018-09-26 16:50:35 +01001260 if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001261 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001262 {
Simon Kelleyee415862014-02-11 11:07:22 +00001263 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001264 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001265 cache->name.namep = ds->name;
Simon Kelleycc921df2019-01-02 22:48:59 +00001266 cache->addr.ds.keylen = ds->digestlen;
1267 cache->addr.ds.algo = ds->algo;
1268 cache->addr.ds.keytag = ds->keytag;
1269 cache->addr.ds.digest = ds->digest_type;
Simon Kelleyee415862014-02-11 11:07:22 +00001270 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001271 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001272 make_non_terminals(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001273 }
1274#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001275
Simon Kelleye759d422012-03-16 13:18:57 +00001276 /* borrow the packet buffer for a temporary by-address hash */
1277 memset(daemon->packet, 0, daemon->packet_buff_sz);
1278 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1279 /* we overwrote the buffer... */
1280 daemon->srv_save = NULL;
1281
1282 /* Do host_records in config. */
1283 for (hr = daemon->host_records; hr; hr = hr->next)
1284 for (nl = hr->names; nl; nl = nl->next)
1285 {
1286 if (hr->addr.s_addr != 0 &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001287 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001288 {
1289 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001290 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001291 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001292 add_hosts_entry(cache, (union all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001293 }
Simon Kelleyee875042018-10-23 22:10:17 +01001294
Simon Kelleye759d422012-03-16 13:18:57 +00001295 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001296 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001297 {
1298 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001299 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001300 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001301 add_hosts_entry(cache, (union all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001302 }
Simon Kelleye759d422012-03-16 13:18:57 +00001303 }
1304
Simon Kelley28866e92011-02-14 20:19:14 +00001305 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001306 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001307 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001308 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001309 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001310 else
1311 {
1312 if (!option_bool(OPT_NO_HOSTS))
1313 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1314
1315 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1316 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1317 if (!(ah->flags & AH_INACTIVE))
1318 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1319 }
1320
Simon Kelley70d18732015-01-31 19:59:29 +00001321#ifdef HAVE_INOTIFY
1322 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1323#endif
1324
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001325}
1326
Simon Kelley7622fc02009-06-04 20:32:05 +01001327#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001328struct in_addr a_record_from_hosts(char *name, time_t now)
1329{
1330 struct crec *crecp = NULL;
1331 struct in_addr ret;
1332
1333 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1334 if (crecp->flags & F_HOSTS)
Simon Kelleycc921df2019-01-02 22:48:59 +00001335 return crecp->addr.addr4;
Simon Kelley7de060b2011-08-26 17:24:52 +01001336
1337 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1338
1339 ret.s_addr = 0;
1340 return ret;
1341}
1342
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001343void cache_unhash_dhcp(void)
1344{
Simon Kelley6b010842007-02-12 20:32:07 +00001345 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001346 int i;
1347
1348 for (i=0; i<hash_size; i++)
1349 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1350 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001351 {
1352 *up = cache->hash_next;
1353 cache->next = dhcp_spare;
1354 dhcp_spare = cache;
1355 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001356 else
1357 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001358}
1359
Simon Kelley611ebc52012-07-16 16:23:46 +01001360static void add_dhcp_cname(struct crec *target, time_t ttd)
1361{
1362 struct crec *aliasc;
1363 struct cname *a;
1364
1365 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001366 if (a->alias[1] != '*' &&
1367 hostname_isequal(cache_get_name(target), a->target))
Simon Kelley611ebc52012-07-16 16:23:46 +01001368 {
1369 if ((aliasc = dhcp_spare))
1370 dhcp_spare = dhcp_spare->next;
1371 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001372 aliasc = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley611ebc52012-07-16 16:23:46 +01001373
1374 if (aliasc)
1375 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001376 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001377 if (ttd == 0)
1378 aliasc->flags |= F_IMMORTAL;
1379 else
1380 aliasc->ttd = ttd;
1381 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001382 aliasc->addr.cname.target.cache = target;
Simon Kelley45d8a242018-07-17 21:01:14 +01001383 next_uid(target);
Simon Kelley611ebc52012-07-16 16:23:46 +01001384 aliasc->addr.cname.uid = target->uid;
Simon Kelley45d8a242018-07-17 21:01:14 +01001385 aliasc->uid = UID_NONE;
Simon Kelley611ebc52012-07-16 16:23:46 +01001386 cache_hash(aliasc);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001387 make_non_terminals(aliasc);
Simon Kelley611ebc52012-07-16 16:23:46 +01001388 add_dhcp_cname(aliasc, ttd);
1389 }
1390 }
1391}
1392
Simon Kelley4cb1b322012-02-06 14:30:41 +00001393void cache_add_dhcp_entry(char *host_name, int prot,
Simon Kelleycc921df2019-01-02 22:48:59 +00001394 union all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001395{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001396 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001397 unsigned int flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001398 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001399 size_t addrlen = sizeof(struct in_addr);
1400
Simon Kelley4cb1b322012-02-06 14:30:41 +00001401 if (prot == AF_INET6)
1402 {
1403 flags = F_IPV6;
1404 addrlen = sizeof(struct in6_addr);
1405 }
Simon Kelley9009d742008-11-14 20:04:27 +00001406
Simon Kelley12d71ed2012-08-30 15:16:41 +01001407 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1408
Simon Kelley4cb1b322012-02-06 14:30:41 +00001409 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001410 {
Simon Kelley824af852008-02-12 20:43:05 +00001411 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001412 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001413 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001414 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001415 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001416 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001417 host_name, daemon->addrbuff);
Simon Kelleycc921df2019-01-02 22:48:59 +00001418 else if (memcmp(&crec->addr, host_address, addrlen) == 0)
Simon Kelley12d71ed2012-08-30 15:16:41 +01001419 in_hosts = 1;
1420 else
1421 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001422 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001423 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001424 {
Simon Kelley65a01b72018-12-31 23:56:33 +00001425 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 +00001426 /* scan_free deletes all addresses associated with name */
1427 break;
1428 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001429 }
Simon Kelley824af852008-02-12 20:43:05 +00001430
Simon Kelley12d71ed2012-08-30 15:16:41 +01001431 /* if in hosts, don't need DHCP record */
1432 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001433 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001434
1435 /* Name in hosts, address doesn't match */
1436 if (fail_crec)
1437 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001438 inet_ntop(prot, &fail_crec->addr, daemon->namebuff, MAXDNAME);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001439 my_syslog(MS_DHCP | LOG_WARNING,
1440 _("not giving name %s to the DHCP lease of %s because "
1441 "the name exists in %s with address %s"),
1442 host_name, daemon->addrbuff,
1443 record_source(fail_crec->uid), daemon->namebuff);
1444 return;
1445 }
1446
Simon Kelleycc921df2019-01-02 22:48:59 +00001447 if ((crec = cache_find_by_addr(NULL, (union all_addr *)host_address, 0, flags)))
Simon Kelley12d71ed2012-08-30 15:16:41 +01001448 {
1449 if (crec->flags & F_NEG)
1450 {
1451 flags |= F_REVERSE;
Simon Kelleycc921df2019-01-02 22:48:59 +00001452 cache_scan_free(NULL, (union all_addr *)host_address, C_IN, 0, flags, NULL, NULL);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001453 }
1454 }
1455 else
1456 flags |= F_REVERSE;
1457
1458 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001459 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001460 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001461 crec = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001462
1463 if (crec) /* malloc may fail */
1464 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001465 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001466 if (ttd == 0)
1467 crec->flags |= F_IMMORTAL;
1468 else
1469 crec->ttd = ttd;
Simon Kelleycc921df2019-01-02 22:48:59 +00001470 crec->addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001471 crec->name.namep = host_name;
Simon Kelley45d8a242018-07-17 21:01:14 +01001472 crec->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001473 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001474 make_non_terminals(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001475
Simon Kelley611ebc52012-07-16 16:23:46 +01001476 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001477 }
1478}
Simon Kelley7622fc02009-06-04 20:32:05 +01001479#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001480
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001481/* Called when we put a local or DHCP name into the cache.
1482 Creates empty cache entries for subnames (ie,
1483 for three.two.one, for two.one and one), without
1484 F_IPV4 or F_IPV6 or F_CNAME set. These convert
1485 NXDOMAIN answers to NoData ones. */
1486static void make_non_terminals(struct crec *source)
1487{
1488 char *name = cache_get_name(source);
Simon Kelleyea6cc332018-09-18 23:21:17 +01001489 struct crec *crecp, *tmp, **up;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001490 int type = F_HOSTS | F_CONFIG;
1491#ifdef HAVE_DHCP
1492 if (source->flags & F_DHCP)
1493 type = F_DHCP;
1494#endif
1495
1496 /* First delete any empty entries for our new real name. Note that
1497 we only delete empty entries deriving from DHCP for a new DHCP-derived
1498 entry and vice-versa for HOSTS and CONFIG. This ensures that
1499 non-terminals from DHCP go when we reload DHCP and
1500 for HOSTS/CONFIG when we re-read. */
1501 for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
1502 {
1503 tmp = crecp->hash_next;
1504
1505 if (!is_outdated_cname_pointer(crecp) &&
1506 (crecp->flags & F_FORWARD) &&
1507 (crecp->flags & type) &&
Simon Kelleycbfbd172018-08-21 18:25:18 +01001508 !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS)) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001509 hostname_isequal(name, cache_get_name(crecp)))
1510 {
1511 *up = crecp->hash_next;
1512#ifdef HAVE_DHCP
1513 if (type & F_DHCP)
1514 {
1515 crecp->next = dhcp_spare;
1516 dhcp_spare = crecp;
1517 }
1518 else
1519#endif
1520 free(crecp);
1521 break;
1522 }
1523 else
1524 up = &crecp->hash_next;
1525 }
1526
1527 while ((name = strchr(name, '.')))
1528 {
1529 name++;
1530
1531 /* Look for one existing, don't need another */
1532 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
1533 if (!is_outdated_cname_pointer(crecp) &&
1534 (crecp->flags & F_FORWARD) &&
1535 (crecp->flags & type) &&
1536 hostname_isequal(name, cache_get_name(crecp)))
1537 break;
1538
1539 if (crecp)
1540 {
1541 /* If the new name expires later, transfer that time to
1542 empty non-terminal entry. */
1543 if (!(crecp->flags & F_IMMORTAL))
1544 {
1545 if (source->flags & F_IMMORTAL)
1546 crecp->flags |= F_IMMORTAL;
1547 else if (difftime(crecp->ttd, source->ttd) < 0)
1548 crecp->ttd = source->ttd;
1549 }
1550 continue;
1551 }
1552
1553#ifdef HAVE_DHCP
1554 if ((source->flags & F_DHCP) && dhcp_spare)
1555 {
1556 crecp = dhcp_spare;
1557 dhcp_spare = dhcp_spare->next;
1558 }
1559 else
1560#endif
Simon Kelley3a610a02018-09-26 16:50:35 +01001561 crecp = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001562
Simon Kelleyea6cc332018-09-18 23:21:17 +01001563 if (crecp)
1564 {
Simon Kelley48b090c2018-09-26 12:53:59 +01001565 crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
1566 crecp->ttd = source->ttd;
Simon Kelleyea6cc332018-09-18 23:21:17 +01001567 crecp->name.namep = name;
1568
1569 cache_hash(crecp);
1570 }
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001571 }
1572}
1573
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001574#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001575int cache_make_stat(struct txt_record *t)
1576{
1577 static char *buff = NULL;
1578 static int bufflen = 60;
1579 int len;
1580 struct server *serv, *serv1;
1581 char *p;
1582
1583 if (!buff && !(buff = whine_malloc(60)))
1584 return 0;
1585
1586 p = buff;
1587
1588 switch (t->stat)
1589 {
1590 case TXT_STAT_CACHESIZE:
1591 sprintf(buff+1, "%d", daemon->cachesize);
1592 break;
1593
1594 case TXT_STAT_INSERTS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001595 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001596 break;
1597
1598 case TXT_STAT_EVICTIONS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001599 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001600 break;
1601
1602 case TXT_STAT_MISSES:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001603 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001604 break;
1605
1606 case TXT_STAT_HITS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001607 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001608 break;
1609
1610#ifdef HAVE_AUTH
1611 case TXT_STAT_AUTH:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001612 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001613 break;
1614#endif
1615
1616 case TXT_STAT_SERVERS:
1617 /* sum counts from different records for same server */
1618 for (serv = daemon->servers; serv; serv = serv->next)
1619 serv->flags &= ~SERV_COUNTED;
1620
1621 for (serv = daemon->servers; serv; serv = serv->next)
1622 if (!(serv->flags &
1623 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1624 {
1625 char *new, *lenp;
1626 int port, newlen, bytes_avail, bytes_needed;
1627 unsigned int queries = 0, failed_queries = 0;
1628 for (serv1 = serv; serv1; serv1 = serv1->next)
1629 if (!(serv1->flags &
1630 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1631 sockaddr_isequal(&serv->addr, &serv1->addr))
1632 {
1633 serv1->flags |= SERV_COUNTED;
1634 queries += serv1->queries;
1635 failed_queries += serv1->failed_queries;
1636 }
1637 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1638 lenp = p++; /* length */
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 if (bytes_needed >= bytes_avail)
1642 {
1643 /* expand buffer if necessary */
1644 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1645 if (!(new = whine_malloc(newlen)))
1646 return 0;
1647 memcpy(new, buff, bufflen);
1648 free(buff);
1649 p = new + (p - buff);
1650 lenp = p - 1;
1651 buff = new;
1652 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001653 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001654 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1655 }
1656 *lenp = bytes_needed;
1657 p += bytes_needed;
1658 }
1659 t->txt = (unsigned char *)buff;
1660 t->len = p - buff;
1661 return 1;
1662 }
1663
1664 len = strlen(buff+1);
1665 t->txt = (unsigned char *)buff;
1666 t->len = len + 1;
1667 *buff = len;
1668 return 1;
1669}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001670#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001671
Simon Kelley394ff492015-03-29 22:17:14 +01001672/* There can be names in the cache containing control chars, don't
1673 mess up logging or open security holes. */
1674static char *sanitise(char *name)
1675{
1676 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001677 if (name)
1678 for (r = (unsigned char *)name; *r; r++)
1679 if (!isprint((int)*r))
1680 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001681
1682 return name;
1683}
1684
1685
Simon Kelley5aabfc72007-08-29 11:24:47 +01001686void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001687{
Simon Kelley824af852008-02-12 20:43:05 +00001688 struct server *serv, *serv1;
1689
1690 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1691 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001692 daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelley824af852008-02-12 20:43:05 +00001693 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001694 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001695#ifdef HAVE_AUTH
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001696 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001697#endif
Simon Kelley5b99eae2019-01-06 23:09:50 +00001698
Simon Kelleyc2207682014-01-08 18:04:20 +00001699 blockdata_report();
Simon Kelley824af852008-02-12 20:43:05 +00001700
Simon Kelley824af852008-02-12 20:43:05 +00001701 /* sum counts from different records for same server */
1702 for (serv = daemon->servers; serv; serv = serv->next)
1703 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001704
Simon Kelley824af852008-02-12 20:43:05 +00001705 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001706 if (!(serv->flags &
1707 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001708 {
1709 int port;
1710 unsigned int queries = 0, failed_queries = 0;
1711 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001712 if (!(serv1->flags &
1713 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1714 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001715 {
1716 serv1->flags |= SERV_COUNTED;
1717 queries += serv1->queries;
1718 failed_queries += serv1->failed_queries;
1719 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001720 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1721 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 +00001722 }
1723
Simon Kelley28866e92011-02-14 20:19:14 +00001724 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001725 {
1726 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001727 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001728 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001729
1730 for (i=0; i<hash_size; i++)
1731 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1732 {
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001733 char *t = " ";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001734 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1735 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001736 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001737 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001738 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001739 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001740 a = sanitise(cache_get_cname_target(cache));
Simon Kelley5b99eae2019-01-06 23:09:50 +00001741 else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG))
1742 {
1743 int targetlen = cache->addr.srv.targetlen;
1744 ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority,
1745 cache->addr.srv.weight, cache->addr.srv.srvport);
1746
1747 if (targetlen > (40 - len))
1748 targetlen = 40 - len;
1749 blockdata_retrieve(cache->addr.srv.target, targetlen, a + len);
1750 a[len + targetlen] = 0;
1751 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001752#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001753 else if (cache->flags & F_DS)
1754 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001755 if (!(cache->flags & F_NEG))
Simon Kelleycc921df2019-01-02 22:48:59 +00001756 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1757 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001758 }
1759 else if (cache->flags & F_DNSKEY)
Simon Kelleycc921df2019-01-02 22:48:59 +00001760 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1761 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001762#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001763 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001764 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001765 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001766 if (cache->flags & F_IPV4)
Simon Kelleycc921df2019-01-02 22:48:59 +00001767 inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001768 else if (cache->flags & F_IPV6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001769 inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001770 }
1771
Simon Kelleye7829ae2014-01-22 22:21:51 +00001772 if (cache->flags & F_IPV4)
1773 t = "4";
1774 else if (cache->flags & F_IPV6)
1775 t = "6";
1776 else if (cache->flags & F_CNAME)
1777 t = "C";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001778 else if (cache->flags & F_SRV)
1779 t = "V";
Simon Kelleye7829ae2014-01-22 22:21:51 +00001780#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001781 else if (cache->flags & F_DS)
1782 t = "S";
1783 else if (cache->flags & F_DNSKEY)
1784 t = "K";
1785#endif
Simon Kelley32678042014-12-17 20:38:20 +00001786 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001787 cache->flags & F_FORWARD ? "F" : " ",
1788 cache->flags & F_REVERSE ? "R" : " ",
1789 cache->flags & F_IMMORTAL ? "I" : " ",
1790 cache->flags & F_DHCP ? "D" : " ",
1791 cache->flags & F_NEG ? "N" : " ",
1792 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001793 cache->flags & F_HOSTS ? "H" : " ",
1794 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001795#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001796 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001797#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001798 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1799 /* ctime includes trailing \n - eat it */
1800 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001801#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001802 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001803 }
1804 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001805}
1806
Simon Kelley19c51cf2014-03-18 22:38:30 +00001807char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001808{
Simon Kelley7622fc02009-06-04 20:32:05 +01001809 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001810
Simon Kelley19c51cf2014-03-18 22:38:30 +00001811 if (index == SRC_CONFIG)
1812 return "config";
1813 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001814 return HOSTSFILE;
1815
1816 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1817 if (ah->index == index)
1818 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001819
1820#ifdef HAVE_INOTIFY
1821 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1822 if (ah->index == index)
1823 return ah->fname;
1824#endif
1825
Simon Kelley7622fc02009-06-04 20:32:05 +01001826 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001827}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001828
Simon Kelley610e7822014-02-06 14:45:17 +00001829char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001830{
1831 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001832 int len = 10; /* strlen("type=xxxxx") */
1833 const char *types = NULL;
1834 static char *buff = NULL;
1835 static int bufflen = 0;
1836
Simon Kelley1a6bca82008-07-11 11:11:42 +01001837 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1838 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001839 {
1840 types = typestr[i].name;
1841 len = strlen(types);
1842 break;
1843 }
1844
Simon Kelleyb758b672018-08-23 21:41:23 +01001845 if (desc)
1846 {
1847 len += 2; /* braces */
1848 len += strlen(desc);
1849 }
1850 len++; /* terminator */
1851
Simon Kelley610e7822014-02-06 14:45:17 +00001852 if (!buff || bufflen < len)
1853 {
1854 if (buff)
1855 free(buff);
1856 else if (len < 20)
1857 len = 20;
1858
1859 buff = whine_malloc(len);
1860 bufflen = len;
1861 }
1862
1863 if (buff)
1864 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001865 if (desc)
1866 {
1867 if (types)
1868 sprintf(buff, "%s[%s]", desc, types);
1869 else
1870 sprintf(buff, "%s[type=%d]", desc, type);
1871 }
Simon Kelley610e7822014-02-06 14:45:17 +00001872 else
Simon Kelleyb758b672018-08-23 21:41:23 +01001873 {
1874 if (types)
1875 sprintf(buff, "<%s>", types);
1876 else
1877 sprintf(buff, "type=%d", type);
1878 }
Simon Kelley610e7822014-02-06 14:45:17 +00001879 }
Simon Kelleyb758b672018-08-23 21:41:23 +01001880
Simon Kelley610e7822014-02-06 14:45:17 +00001881 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001882}
1883
Simon Kelleycc921df2019-01-02 22:48:59 +00001884void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001885{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001886 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001887 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001888
Simon Kelley28866e92011-02-14 20:19:14 +00001889 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001890 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001891
Simon Kelley394ff492015-03-29 22:17:14 +01001892 name = sanitise(name);
1893
Simon Kelley5aabfc72007-08-29 11:24:47 +01001894 if (addr)
1895 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001896 if (flags & F_KEYTAG)
Simon Kelleycc921df2019-01-02 22:48:59 +00001897 sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
Simon Kelley07ed5852018-05-04 21:52:22 +01001898 else if (flags & F_RCODE)
1899 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001900 unsigned int rcode = addr->log.rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +01001901
1902 if (rcode == SERVFAIL)
1903 dest = "SERVFAIL";
1904 else if (rcode == REFUSED)
1905 dest = "REFUSED";
1906 else if (rcode == NOTIMP)
1907 dest = "not implemented";
1908 else
1909 sprintf(daemon->addrbuff, "%u", rcode);
1910 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001911 else
Simon Kelleyee875042018-10-23 22:10:17 +01001912 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1913 addr, daemon->addrbuff, ADDRSTRLEN);
1914
Simon Kelley5aabfc72007-08-29 11:24:47 +01001915 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001916 else
1917 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001918
1919 if (flags & F_REVERSE)
1920 {
1921 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001922 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001923 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001924
1925 if (flags & F_NEG)
1926 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001927 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001928 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001929 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001930 {
1931 if (flags & F_IPV4)
1932 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001933 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001934 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001935 else
1936 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001937 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001938 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001939 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001940 dest = "<CNAME>";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001941 else if (flags & F_SRV)
1942 dest = "<SRV>";
Simon Kelley28866e92011-02-14 20:19:14 +00001943 else if (flags & F_RRNAME)
1944 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001945
Simon Kelley1f15b812009-10-13 17:49:32 +01001946 if (flags & F_CONFIG)
1947 source = "config";
1948 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001949 source = "DHCP";
1950 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001951 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001952 else if (flags & F_UPSTREAM)
1953 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001954 else if (flags & F_SECSTAT)
1955 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001956 else if (flags & F_AUTH)
1957 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001958 else if (flags & F_SERVER)
1959 {
1960 source = "forwarded";
1961 verb = "to";
1962 }
1963 else if (flags & F_QUERY)
1964 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001965 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001966 verb = "from";
1967 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001968 else if (flags & F_DNSSEC)
1969 {
1970 source = arg;
1971 verb = "to";
1972 }
Wang Jian49752b92014-03-28 20:52:47 +00001973 else if (flags & F_IPSET)
1974 {
1975 source = "ipset add";
1976 dest = name;
1977 name = arg;
1978 verb = daemon->addrbuff;
1979 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001980 else
1981 source = "cached";
1982
Simon Kelley3d8df262005-08-29 12:19:27 +01001983 if (strlen(name) == 0)
1984 name = ".";
1985
Simon Kelley25cf5e32015-01-09 15:53:03 +00001986 if (option_bool(OPT_EXTRALOG))
1987 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001988 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001989 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001990 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001991 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001992 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 +00001993 }
1994 else
1995 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001996}
1997
Simon Kelley98c098b2014-01-08 17:31:16 +00001998