blob: 30c9c41ce6a7965f9524560c25f2186c218b3d46 [file] [log] [blame]
Simon Kelley2a8710a2020-01-05 16:40:06 +00001/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
Simon Kelley9e4abcb2004-01-22 19:47:41 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
Simon Kelley824af852008-02-12 20:43:05 +00005 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
Simon Kelley9e4abcb2004-01-22 19:47:41 +00008 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
Simon Kelley824af852008-02-12 20:43:05 +000012
Simon Kelley73a08a22009-02-05 20:28:08 +000013 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
Simon Kelley9e4abcb2004-01-22 19:47:41 +000015*/
16
17#include "dnsmasq.h"
18
Simon Kelley5aabfc72007-08-29 11:24:47 +010019static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
Simon Kelley7622fc02009-06-04 20:32:05 +010020#ifdef HAVE_DHCP
21static struct crec *dhcp_spare = NULL;
22#endif
23static struct crec *new_chain = NULL;
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +010024static int insert_error;
Simon Kelley5aabfc72007-08-29 11:24:47 +010025static union bigname *big_free = NULL;
26static int bignames_left, hash_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000027
Simon Kelleyb6f926f2018-08-21 17:46:52 +010028static void make_non_terminals(struct crec *source);
Simon Kelleycc921df2019-01-02 22:48:59 +000029static struct crec *really_insert(char *name, union all_addr *addr, unsigned short class,
Simon Kelley5b99eae2019-01-06 23:09:50 +000030 time_t now, unsigned long ttl, unsigned int flags);
Simon Kelleyb6f926f2018-08-21 17:46:52 +010031
Simon Kelley16972692006-10-16 20:04:18 +010032/* type->string mapping: this is also used by the name-hash function as a mixing table. */
33static const struct {
34 unsigned int type;
35 const char * const name;
36} typestr[] = {
37 { 1, "A" },
38 { 2, "NS" },
39 { 5, "CNAME" },
40 { 6, "SOA" },
41 { 10, "NULL" },
42 { 11, "WKS" },
43 { 12, "PTR" },
44 { 13, "HINFO" },
45 { 15, "MX" },
46 { 16, "TXT" },
47 { 22, "NSAP" },
48 { 23, "NSAP_PTR" },
49 { 24, "SIG" },
50 { 25, "KEY" },
51 { 28, "AAAA" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010052 { 29, "LOC" },
Simon Kelley16972692006-10-16 20:04:18 +010053 { 33, "SRV" },
Simon Kelley1a6bca82008-07-11 11:11:42 +010054 { 35, "NAPTR" },
Simon Kelley16972692006-10-16 20:04:18 +010055 { 36, "KX" },
56 { 37, "CERT" },
57 { 38, "A6" },
58 { 39, "DNAME" },
59 { 41, "OPT" },
Simon Kelley0fc2f312014-01-08 10:26:58 +000060 { 43, "DS" },
61 { 46, "RRSIG" },
Simon Kelley610e7822014-02-06 14:45:17 +000062 { 47, "NSEC" },
Simon Kelley832af0b2007-01-21 20:01:28 +000063 { 48, "DNSKEY" },
Simon Kelley610e7822014-02-06 14:45:17 +000064 { 50, "NSEC3" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010065 { 51, "NSEC3PARAM" },
66 { 52, "TLSA" },
67 { 53, "SMIMEA" },
68 { 55, "HIP" },
Simon Kelley832af0b2007-01-21 20:01:28 +000069 { 249, "TKEY" },
Simon Kelley16972692006-10-16 20:04:18 +010070 { 250, "TSIG" },
71 { 251, "IXFR" },
72 { 252, "AXFR" },
73 { 253, "MAILB" },
74 { 254, "MAILA" },
Simon Kelleyb758b672018-08-23 21:41:23 +010075 { 255, "ANY" },
76 { 257, "CAA" }
Simon Kelley16972692006-10-16 20:04:18 +010077};
78
Simon Kelley9e4abcb2004-01-22 19:47:41 +000079static void cache_free(struct crec *crecp);
80static void cache_unlink(struct crec *crecp);
81static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010082static void rehash(int size);
83static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084
Simon Kelley45d8a242018-07-17 21:01:14 +010085void next_uid(struct crec *crecp)
Simon Kelley3f7483e2014-03-16 22:56:58 +000086{
Andyd5082152014-03-17 19:50:29 +000087 static unsigned int uid = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +000088
Simon Kelley45d8a242018-07-17 21:01:14 +010089 if (crecp->uid == UID_NONE)
90 {
91 uid++;
Andyd5082152014-03-17 19:50:29 +000092
Simon Kelley45d8a242018-07-17 21:01:14 +010093 /* uid == 0 used to indicate CNAME to interface name. */
94 if (uid == UID_NONE)
95 uid++;
96
97 crecp->uid = uid;
98 }
Simon Kelley3f7483e2014-03-16 22:56:58 +000099}
100
Simon Kelley5aabfc72007-08-29 11:24:47 +0100101void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000102{
103 struct crec *crecp;
104 int i;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100105
Simon Kelley5aabfc72007-08-29 11:24:47 +0100106 bignames_left = daemon->cachesize/10;
107
108 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100110 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000111
Simon Kelley5aabfc72007-08-29 11:24:47 +0100112 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000113 {
114 cache_link(crecp);
115 crecp->flags = 0;
Simon Kelley45d8a242018-07-17 21:01:14 +0100116 crecp->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000117 }
118 }
119
Simon Kelley4011c4e2006-10-28 16:26:19 +0100120 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +0100121 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000122}
123
Simon Kelley4011c4e2006-10-28 16:26:19 +0100124/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
125 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
126 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
127 expand the table. */
128static void rehash(int size)
129{
130 struct crec **new, **old, *p, *tmp;
131 int i, new_size, old_size;
132
133 /* hash_size is a power of two. */
134 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
135
136 /* must succeed in getting first instance, failure later is non-fatal */
137 if (!hash_table)
138 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100139 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100140 return;
141
142 for(i = 0; i < new_size; i++)
143 new[i] = NULL;
144
145 old = hash_table;
146 old_size = hash_size;
147 hash_table = new;
148 hash_size = new_size;
149
150 if (old)
151 {
152 for (i = 0; i < old_size; i++)
153 for (p = old[i]; p ; p = tmp)
154 {
155 tmp = p->hash_next;
156 cache_hash(p);
157 }
158 free(old);
159 }
160}
161
Simon Kelley3d8df262005-08-29 12:19:27 +0100162static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000163{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100164 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100165 const unsigned char *mix_tab = (const unsigned char*)typestr;
166
Simon Kelley3d8df262005-08-29 12:19:27 +0100167 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100168 {
169 /* don't use tolower and friends here - they may be messed up by LOCALE */
170 if (c >= 'A' && c <= 'Z')
171 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100172 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100173 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000174
175 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100176 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000177}
178
179static void cache_hash(struct crec *crecp)
180{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000181 /* maintain an invariant that all entries with F_REVERSE set
182 are at the start of the hash-chain and all non-reverse
183 immortal entries are at the end of the hash-chain.
184 This allows reverse searches and garbage collection to be optimised */
185
186 struct crec **up = hash_bucket(cache_get_name(crecp));
187
188 if (!(crecp->flags & F_REVERSE))
189 {
190 while (*up && ((*up)->flags & F_REVERSE))
191 up = &((*up)->hash_next);
192
193 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000194 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000195 up = &((*up)->hash_next);
196 }
197 crecp->hash_next = *up;
198 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000199}
Simon Kelley82e3f452014-01-31 21:05:48 +0000200
Simon Kelley82e3f452014-01-31 21:05:48 +0000201static void cache_blockdata_free(struct crec *crecp)
202{
Simon Kelley4bf62f62019-01-10 21:54:22 +0000203 if (!(crecp->flags & F_NEG))
204 {
205 if (crecp->flags & F_SRV)
206 blockdata_free(crecp->addr.srv.target);
Simon Kelley5b99eae2019-01-06 23:09:50 +0000207#ifdef HAVE_DNSSEC
Simon Kelley4bf62f62019-01-10 21:54:22 +0000208 else if (crecp->flags & F_DNSKEY)
209 blockdata_free(crecp->addr.key.keydata);
210 else if (crecp->flags & F_DS)
211 blockdata_free(crecp->addr.ds.keydata);
Simon Kelley82e3f452014-01-31 21:05:48 +0000212#endif
Simon Kelley4bf62f62019-01-10 21:54:22 +0000213 }
Simon Kelley5b99eae2019-01-06 23:09:50 +0000214}
Simon Kelley82e3f452014-01-31 21:05:48 +0000215
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000216static void cache_free(struct crec *crecp)
217{
218 crecp->flags &= ~F_FORWARD;
219 crecp->flags &= ~F_REVERSE;
Simon Kelley45d8a242018-07-17 21:01:14 +0100220 crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100221
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000222 if (cache_tail)
223 cache_tail->next = crecp;
224 else
225 cache_head = crecp;
226 crecp->prev = cache_tail;
227 crecp->next = NULL;
228 cache_tail = crecp;
229
230 /* retrieve big name for further use. */
231 if (crecp->flags & F_BIGNAME)
232 {
233 crecp->name.bname->next = big_free;
234 big_free = crecp->name.bname;
235 crecp->flags &= ~F_BIGNAME;
236 }
Simon Kelley072e81b2014-01-31 12:42:54 +0000237
Simon Kelley82e3f452014-01-31 21:05:48 +0000238 cache_blockdata_free(crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000239}
240
241/* insert a new cache entry at the head of the list (youngest entry) */
242static void cache_link(struct crec *crecp)
243{
244 if (cache_head) /* check needed for init code */
245 cache_head->prev = crecp;
246 crecp->next = cache_head;
247 crecp->prev = NULL;
248 cache_head = crecp;
249 if (!cache_tail)
250 cache_tail = crecp;
251}
252
253/* remove an arbitrary cache entry for promotion */
254static void cache_unlink (struct crec *crecp)
255{
256 if (crecp->prev)
257 crecp->prev->next = crecp->next;
258 else
259 cache_head = crecp->next;
260
261 if (crecp->next)
262 crecp->next->prev = crecp->prev;
263 else
264 cache_tail = crecp->prev;
265}
266
267char *cache_get_name(struct crec *crecp)
268{
269 if (crecp->flags & F_BIGNAME)
270 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000271 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000272 return crecp->name.namep;
273
274 return crecp->name.sname;
275}
276
Simon Kelleyd56a6042013-10-11 14:39:03 +0100277char *cache_get_cname_target(struct crec *crecp)
278{
Simon Kelley1fd56c02019-10-30 12:58:28 +0000279 if (crecp->addr.cname.is_name_ptr)
280 return crecp->addr.cname.target.name;
281 else
Simon Kelleyd56a6042013-10-11 14:39:03 +0100282 return cache_get_name(crecp->addr.cname.target.cache);
Simon Kelleyd56a6042013-10-11 14:39:03 +0100283}
284
285
286
Simon Kelleyb75e9362012-12-07 11:50:41 +0000287struct crec *cache_enumerate(int init)
288{
289 static int bucket;
290 static struct crec *cache;
291
292 if (init)
293 {
294 bucket = 0;
295 cache = NULL;
296 }
297 else if (cache && cache->hash_next)
298 cache = cache->hash_next;
299 else
300 {
301 cache = NULL;
302 while (bucket < hash_size)
303 if ((cache = hash_table[bucket++]))
304 break;
305 }
306
307 return cache;
308}
309
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100310static int is_outdated_cname_pointer(struct crec *crecp)
311{
Simon Kelley1fd56c02019-10-30 12:58:28 +0000312 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.is_name_ptr)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100313 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100314
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100315 /* NB. record may be reused as DS or DNSKEY, where uid is
316 overloaded for something completely different */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100317 if (crecp->addr.cname.target.cache &&
Simon Kelley2896e242019-01-09 15:12:34 +0000318 !(crecp->addr.cname.target.cache->flags & (F_DNSKEY | F_DS)) &&
Simon Kelleyd56a6042013-10-11 14:39:03 +0100319 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100320 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100321
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100322 return 1;
323}
324
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000325static int is_expired(time_t now, struct crec *crecp)
326{
327 if (crecp->flags & F_IMMORTAL)
328 return 0;
329
330 if (difftime(now, crecp->ttd) < 0)
331 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100332
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000333 return 1;
334}
335
Simon Kelleycc921df2019-01-02 22:48:59 +0000336static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned short class, time_t now,
Simon Kelley5b99eae2019-01-06 23:09:50 +0000337 unsigned int flags, struct crec **target_crec, unsigned int *target_uid)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000338{
339 /* Scan and remove old entries.
340 If (flags & F_FORWARD) then remove any forward entries for name and any expired
341 entries but only in the same hash bucket as name.
342 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
343 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000344 If (flags == 0) remove any expired entries in the whole cache.
345
Simon Kelleycbc65242014-12-21 21:21:53 +0000346 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
347 to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000348
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000349 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100350 so that when we hit an entry which isn't reverse and is immortal, we're done.
351
352 If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid.
353 This entry will get re-used with the same name, to preserve CNAMEs. */
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000354
355 struct crec *crecp, **up;
Simon Kelley65a01b72018-12-31 23:56:33 +0000356
357 (void)class;
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000358
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000359 if (flags & F_FORWARD)
360 {
Simon Kelley6b010842007-02-12 20:32:07 +0000361 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000362 {
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000363 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
364 {
Simon Kelleye7829ae2014-01-22 22:21:51 +0000365 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
Simon Kelley5b99eae2019-01-06 23:09:50 +0000366 if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
Simon Kelley6429e422014-01-23 12:09:36 +0000367 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000368 {
369 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelleycbc65242014-12-21 21:21:53 +0000370 return crecp;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000371 *up = crecp->hash_next;
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100372 /* If this record is for the name we're inserting and is the target
373 of a CNAME record. Make the new record for the same name, in the same
374 crec, with the same uid to avoid breaking the existing CNAME. */
375 if (crecp->uid != UID_NONE)
376 {
377 if (target_crec)
378 *target_crec = crecp;
379 if (target_uid)
380 *target_uid = crecp->uid;
381 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000382 cache_unlink(crecp);
383 cache_free(crecp);
384 continue;
385 }
386
387#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000388 /* Deletion has to be class-sensitive for DS and DNSKEY */
Simon Kelley65a01b72018-12-31 23:56:33 +0000389 if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == class)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000390 {
Simon Kelley824202e2014-01-23 20:59:46 +0000391 if (crecp->flags & F_CONFIG)
Simon Kelleycbc65242014-12-21 21:21:53 +0000392 return crecp;
Simon Kelley824202e2014-01-23 20:59:46 +0000393 *up = crecp->hash_next;
394 cache_unlink(crecp);
395 cache_free(crecp);
396 continue;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000397 }
398#endif
399 }
Simon Kelleyeb1fe152018-07-18 20:59:52 +0100400
401 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
402 {
403 *up = crecp->hash_next;
404 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
405 {
406 cache_unlink(crecp);
407 cache_free(crecp);
408 }
409 continue;
410 }
411
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000412 up = &crecp->hash_next;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000413 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000414 }
415 else
416 {
417 int i;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000418 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
Simon Kelleyee875042018-10-23 22:10:17 +0100419
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000420 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000421 for (crecp = hash_table[i], up = &hash_table[i];
422 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
423 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000424 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000425 {
426 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000427 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000428 {
429 cache_unlink(crecp);
430 cache_free(crecp);
431 }
432 }
Simon Kelley25439062013-11-25 21:14:51 +0000433 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000434 (flags & crecp->flags & F_REVERSE) &&
435 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000436 memcmp(&crecp->addr, addr, addrlen) == 0)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000437 {
438 *up = crecp->hash_next;
439 cache_unlink(crecp);
440 cache_free(crecp);
441 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000442 else
443 up = &crecp->hash_next;
444 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000445
Simon Kelleycbc65242014-12-21 21:21:53 +0000446 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000447}
448
449/* Note: The normal calling sequence is
450 cache_start_insert
451 cache_insert * n
452 cache_end_insert
453
454 but an abort can cause the cache_end_insert to be missed
455 in which can the next cache_start_insert cleans things up. */
456
457void cache_start_insert(void)
458{
459 /* Free any entries which didn't get committed during the last
460 insert due to error.
461 */
462 while (new_chain)
463 {
464 struct crec *tmp = new_chain->next;
465 cache_free(new_chain);
466 new_chain = tmp;
467 }
468 new_chain = NULL;
469 insert_error = 0;
470}
Simon Kelleya799ca02018-10-18 19:35:29 +0100471
Simon Kelleycc921df2019-01-02 22:48:59 +0000472struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
Simon Kelley5b99eae2019-01-06 23:09:50 +0000473 time_t now, unsigned long ttl, unsigned int flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000474{
Simon 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
Simon Kelley84449bf2019-10-29 22:24:19 +0000516 existing record is for an A or AAAA or CNAME and
Simon Kelleycbc65242014-12-21 21:21:53 +0000517 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 }
Simon Kelley84449bf2019-10-29 22:24:19 +0000528
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);
Ville Skyttäbf23c8a2019-12-05 16:50:57 +0000774 /* This relies on the fact that the target of a CNAME immediately precedes
Simon Kelleya799ca02018-10-18 19:35:29 +0100775 it because of the order of extraction in extract_addresses, and
776 the order reversal on the new_chain. */
777 if (newc)
778 {
Simon Kelley1fd56c02019-10-30 12:58:28 +0000779 newc->addr.cname.is_name_ptr = 0;
780
781 if (!crecp)
782 newc->addr.cname.target.cache = NULL;
783 else
Simon Kelleya799ca02018-10-18 19:35:29 +0100784 {
785 next_uid(crecp);
786 newc->addr.cname.target.cache = crecp;
787 newc->addr.cname.uid = crecp->uid;
788 }
789 }
790 }
Simon Kelleya799ca02018-10-18 19:35:29 +0100791 }
792}
793
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100794int cache_find_non_terminal(char *name, time_t now)
795{
796 struct crec *crecp;
797
798 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
799 if (!is_outdated_cname_pointer(crecp) &&
800 !is_expired(now, crecp) &&
801 (crecp->flags & F_FORWARD) &&
Sven Mueller162e5e02019-02-27 21:17:37 +0000802 !(crecp->flags & F_NXDOMAIN) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +0100803 hostname_isequal(name, cache_get_name(crecp)))
804 return 1;
805
806 return 0;
807}
808
Simon Kelley12fae492014-02-04 22:03:06 +0000809struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000810{
811 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000812 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000813
Simon Kelley12fae492014-02-04 22:03:06 +0000814 prot &= ~F_NO_RR;
815
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000816 if (crecp) /* iterating */
817 ans = crecp->next;
818 else
819 {
820 /* first search, look for relevant entries and push to top of list
821 also free anything which has expired */
822 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley5b99eae2019-01-06 23:09:50 +0000823 unsigned int ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000824
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000825 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
826 {
827 next = crecp->hash_next;
828
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000829 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000830 {
831 if ((crecp->flags & F_FORWARD) &&
832 (crecp->flags & prot) &&
833 hostname_isequal(cache_get_name(crecp), name))
834 {
Simon Kelley25439062013-11-25 21:14:51 +0000835 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000836 {
837 *chainp = crecp;
838 chainp = &crecp->next;
839 }
840 else
841 {
842 cache_unlink(crecp);
843 cache_link(crecp);
844 }
845
Simon Kelley824af852008-02-12 20:43:05 +0000846 /* Move all but the first entry up the hash chain
847 this implements round-robin.
848 Make sure that re-ordering doesn't break the hash-chain
849 order invariants.
850 */
Simon Kelley9e038942008-05-30 20:06:34 +0100851 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000852 {
853 *up = crecp->hash_next;
854 crecp->hash_next = *insert;
855 *insert = crecp;
856 insert = &crecp->hash_next;
857 }
Simon Kelley9e038942008-05-30 20:06:34 +0100858 else
859 {
Simon Kelley12fae492014-02-04 22:03:06 +0000860 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100861 {
862 insert = up;
863 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
864 }
865 up = &crecp->hash_next;
866 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000867 }
868 else
869 /* case : not expired, incorrect entry. */
870 up = &crecp->hash_next;
871 }
872 else
873 {
874 /* expired entry, free it */
875 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000876 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000877 {
878 cache_unlink(crecp);
879 cache_free(crecp);
880 }
881 }
882 }
883
884 *chainp = cache_head;
885 }
886
887 if (ans &&
888 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000889 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000890 hostname_isequal(cache_get_name(ans), name))
891 return ans;
892
893 return NULL;
894}
895
Simon Kelleycc921df2019-01-02 22:48:59 +0000896struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000897 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898{
899 struct crec *ans;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000900 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000901
902 if (crecp) /* iterating */
903 ans = crecp->next;
904 else
905 {
906 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000907 also free anything which has expired. All the reverse entries are at the
908 start of the hash chain, so we can give up when we find the first
909 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000910 int i;
911 struct crec **up, **chainp = &ans;
912
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000913 for (i=0; i<hash_size; i++)
914 for (crecp = hash_table[i], up = &hash_table[i];
915 crecp && (crecp->flags & F_REVERSE);
916 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000917 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000918 {
Simon Kelley6b010842007-02-12 20:32:07 +0000919 if ((crecp->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000920 memcmp(&crecp->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000921 {
Simon Kelley25439062013-11-25 21:14:51 +0000922 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000923 {
924 *chainp = crecp;
925 chainp = &crecp->next;
926 }
927 else
928 {
929 cache_unlink(crecp);
930 cache_link(crecp);
931 }
932 }
933 up = &crecp->hash_next;
934 }
935 else
936 {
937 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000938 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000939 {
940 cache_unlink(crecp);
941 cache_free(crecp);
942 }
943 }
944
945 *chainp = cache_head;
946 }
947
948 if (ans &&
949 (ans->flags & F_REVERSE) &&
950 (ans->flags & prot) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000951 memcmp(&ans->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000952 return ans;
953
954 return NULL;
955}
956
Simon Kelleycc921df2019-01-02 22:48:59 +0000957static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000958 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000959{
Simon Kelleye759d422012-03-16 13:18:57 +0000960 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
Simon Kelley84449bf2019-10-29 22:24:19 +0000961 int i;
Simon Kelley205fafa2012-01-11 21:31:51 +0000962 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000963
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000964 /* Remove duplicates in hosts files. */
Simon Kelley84449bf2019-10-29 22:24:19 +0000965 if (lookup && (lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000966 {
Simon Kelley84449bf2019-10-29 22:24:19 +0000967 free(cache);
968 return;
Simon Kelley9009d742008-11-14 20:04:27 +0000969 }
Simon Kelley84449bf2019-10-29 22:24:19 +0000970
Simon Kelley9009d742008-11-14 20:04:27 +0000971 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000972 We do this by steam here, The entries are kept in hash chains, linked
973 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000974 the array rhash, hashed on address. Note that rhash and the values
975 in ->next are only valid whilst reading hosts files: the buckets are
976 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000977
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000978 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000979
980 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +0000981 large (10000 entry) hosts files.
982
983 Note that we only do this process when bulk-reading hosts files,
984 for incremental reads, rhash is NULL, and we use cache lookups
985 instead.
986 */
Simon Kelley9009d742008-11-14 20:04:27 +0000987
Simon Kelley70d18732015-01-31 19:59:29 +0000988 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +0000989 {
Simon Kelley70d18732015-01-31 19:59:29 +0000990 /* hash address */
991 for (j = 0, i = 0; i < addrlen; i++)
992 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
993
994 for (lookup = rhash[j]; lookup; lookup = lookup->next)
995 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +0000996 memcmp(&lookup->addr, addr, addrlen) == 0)
Simon Kelley70d18732015-01-31 19:59:29 +0000997 {
998 cache->flags &= ~F_REVERSE;
999 break;
1000 }
1001
1002 /* maintain address hash chain, insert new unique address */
1003 if (!lookup)
1004 {
1005 cache->next = rhash[j];
1006 rhash[j] = cache;
1007 }
Simon Kelley915363f2012-01-11 22:00:48 +00001008 }
Simon Kelley70d18732015-01-31 19:59:29 +00001009 else
1010 {
1011 /* incremental read, lookup in cache */
1012 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
1013 if (lookup && lookup->flags & F_HOSTS)
1014 cache->flags &= ~F_REVERSE;
1015 }
1016
Simon Kelley9009d742008-11-14 20:04:27 +00001017 cache->uid = index;
Simon Kelleycc921df2019-01-02 22:48:59 +00001018 memcpy(&cache->addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +00001019 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001020 make_non_terminals(cache);
Simon Kelley9009d742008-11-14 20:04:27 +00001021}
1022
1023static int eatspace(FILE *f)
1024{
1025 int c, nl = 0;
1026
1027 while (1)
1028 {
1029 if ((c = getc(f)) == '#')
1030 while (c != '\n' && c != EOF)
1031 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +00001032
Simon Kelley9009d742008-11-14 20:04:27 +00001033 if (c == EOF)
1034 return 1;
1035
1036 if (!isspace(c))
1037 {
1038 ungetc(c, f);
1039 return nl;
1040 }
1041
1042 if (c == '\n')
Simon Kelley4219ade2019-02-27 20:30:21 +00001043 nl++;
Simon Kelley9009d742008-11-14 20:04:27 +00001044 }
1045}
1046
1047static int gettok(FILE *f, char *token)
1048{
1049 int c, count = 0;
1050
1051 while (1)
1052 {
1053 if ((c = getc(f)) == EOF)
Simon Kelley4219ade2019-02-27 20:30:21 +00001054 return (count == 0) ? -1 : 1;
Simon Kelley9009d742008-11-14 20:04:27 +00001055
1056 if (isspace(c) || c == '#')
1057 {
1058 ungetc(c, f);
1059 return eatspace(f);
1060 }
1061
1062 if (count < (MAXDNAME - 1))
1063 {
1064 token[count++] = c;
1065 token[count] = 0;
1066 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001067 }
1068}
1069
Simon Kelley70d18732015-01-31 19:59:29 +00001070int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001071{
1072 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +00001073 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4219ade2019-02-27 20:30:21 +00001074 int addr_count = 0, name_count = cache_size, lineno = 1;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001075 unsigned int flags = 0;
Simon Kelleycc921df2019-01-02 22:48:59 +00001076 union all_addr addr;
Simon Kelley205fafa2012-01-11 21:31:51 +00001077 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +01001078
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001079 if (!f)
1080 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001081 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +00001082 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001083 }
Simon Kelley9009d742008-11-14 20:04:27 +00001084
Simon Kelley4219ade2019-02-27 20:30:21 +00001085 lineno += eatspace(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001086
Simon Kelley4219ade2019-02-27 20:30:21 +00001087 while ((atnl = gettok(f, token)) != -1)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001088 {
Simon Kelley3d8df262005-08-29 12:19:27 +01001089 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001090 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001091 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001092 addrlen = INADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001093 domain_suffix = get_domain(addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001094 }
Simon Kelley3d8df262005-08-29 12:19:27 +01001095 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001096 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001097 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001098 addrlen = IN6ADDRSZ;
Simon Kelleycc921df2019-01-02 22:48:59 +00001099 domain_suffix = get_domain6(&addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001100 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001101 else
Simon Kelleyb8187c82005-11-26 21:46:27 +00001102 {
Simon Kelleyf2621c72007-04-29 19:47:21 +01001103 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +00001104 while (atnl == 0)
1105 atnl = gettok(f, token);
Simon Kelley065e5bb2019-03-01 14:38:51 +00001106 lineno += atnl;
Simon Kelleyb8187c82005-11-26 21:46:27 +00001107 continue;
1108 }
Simon Kelley9009d742008-11-14 20:04:27 +00001109
Simon Kelley9009d742008-11-14 20:04:27 +00001110 addr_count++;
1111
1112 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +00001113 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +00001114 {
1115 rehash(name_count);
1116 cache_size = name_count;
1117 }
1118
1119 while (atnl == 0)
1120 {
1121 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +01001122 int fqdn, nomem;
1123 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +00001124
Simon Kelley4219ade2019-02-27 20:30:21 +00001125 if ((atnl = gettok(f, token)) == -1)
Simon Kelley9009d742008-11-14 20:04:27 +00001126 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001127
Simon Kelley9009d742008-11-14 20:04:27 +00001128 fqdn = !!strchr(token, '.');
1129
Simon Kelley1f15b812009-10-13 17:49:32 +01001130 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +00001131 {
1132 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +00001133 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001134 (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
Simon Kelley9009d742008-11-14 20:04:27 +00001135 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001136 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +00001137 strcat(cache->name.sname, ".");
1138 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +00001139 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001140 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001141 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001142 name_count++;
1143 }
Simon Kelley3a610a02018-09-26 16:50:35 +01001144 if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
Simon Kelley9009d742008-11-14 20:04:27 +00001145 {
Simon Kelley1f15b812009-10-13 17:49:32 +01001146 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +00001147 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001148 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001149 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001150 name_count++;
1151 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001152 free(canon);
1153
Simon Kelley9009d742008-11-14 20:04:27 +00001154 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001155 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001156 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1157 }
Simon Kelley4219ade2019-02-27 20:30:21 +00001158
1159 lineno += atnl;
Simon Kelley9009d742008-11-14 20:04:27 +00001160 }
1161
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001162 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001163
Simon Kelley70d18732015-01-31 19:59:29 +00001164 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001165 rehash(name_count);
1166
1167 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1168
Simon Kelley4011c4e2006-10-28 16:26:19 +01001169 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001170}
1171
Simon Kelley7622fc02009-06-04 20:32:05 +01001172void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001173{
1174 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001175 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001176 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001177 struct host_record *hr;
1178 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001179 struct cname *a;
Simon Kelley376cb972019-10-29 22:58:55 +00001180 struct crec lrec;
1181 struct mx_srv_record *mx;
1182 struct txt_record *txt;
1183 struct interface_name *intr;
1184 struct ptr_record *ptr;
1185 struct naptr *naptr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001186#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001187 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001188#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001189
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001190 daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
1191 daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
Simon Kelley59353a62004-11-21 19:34:28 +00001192
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001193 for (i=0; i<hash_size; i++)
1194 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1195 {
Simon Kelley82e3f452014-01-31 21:05:48 +00001196 cache_blockdata_free(cache);
Simon Kelley5b99eae2019-01-06 23:09:50 +00001197
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001198 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001199 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001200 {
1201 *up = cache->hash_next;
1202 free(cache);
1203 }
1204 else if (!(cache->flags & F_DHCP))
1205 {
1206 *up = cache->hash_next;
1207 if (cache->flags & F_BIGNAME)
1208 {
1209 cache->name.bname->next = big_free;
1210 big_free = cache->name.bname;
1211 }
1212 cache->flags = 0;
1213 }
1214 else
1215 up = &cache->hash_next;
1216 }
1217
Simon Kelley84449bf2019-10-29 22:24:19 +00001218 /* Add locally-configured CNAMEs to the cache */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001219 for (a = daemon->cnames; a; a = a->next)
Simon Kelley84449bf2019-10-29 22:24:19 +00001220 if (a->alias[1] != '*' &&
1221 ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
1222 {
1223 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
1224 cache->ttd = a->ttl;
1225 cache->name.namep = a->alias;
1226 cache->addr.cname.target.name = a->target;
Simon Kelley1fd56c02019-10-30 12:58:28 +00001227 cache->addr.cname.is_name_ptr = 1;
Simon Kelley84449bf2019-10-29 22:24:19 +00001228 cache->uid = UID_NONE;
1229 cache_hash(cache);
1230 make_non_terminals(cache);
1231 }
1232
Simon Kelley0fc2f312014-01-08 10:26:58 +00001233#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001234 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley3a610a02018-09-26 16:50:35 +01001235 if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
Simon Kelleycc921df2019-01-02 22:48:59 +00001236 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001237 {
Simon Kelleyee415862014-02-11 11:07:22 +00001238 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001239 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001240 cache->name.namep = ds->name;
Simon Kelleycc921df2019-01-02 22:48:59 +00001241 cache->addr.ds.keylen = ds->digestlen;
1242 cache->addr.ds.algo = ds->algo;
1243 cache->addr.ds.keytag = ds->keytag;
1244 cache->addr.ds.digest = ds->digest_type;
Simon Kelleyee415862014-02-11 11:07:22 +00001245 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001246 cache_hash(cache);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001247 make_non_terminals(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001248 }
1249#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001250
Simon Kelleye759d422012-03-16 13:18:57 +00001251 /* borrow the packet buffer for a temporary by-address hash */
1252 memset(daemon->packet, 0, daemon->packet_buff_sz);
1253 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1254 /* we overwrote the buffer... */
1255 daemon->srv_save = NULL;
1256
1257 /* Do host_records in config. */
1258 for (hr = daemon->host_records; hr; hr = hr->next)
1259 for (nl = hr->names; nl; nl = nl->next)
1260 {
Simon Kelley157d8cf2019-10-25 17:46:49 +01001261 if ((hr->flags & HR_4) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001262 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001263 {
1264 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001265 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001266 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001267 add_hosts_entry(cache, (union all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001268 }
Simon Kelleyee875042018-10-23 22:10:17 +01001269
Simon Kelley157d8cf2019-10-25 17:46:49 +01001270 if ((hr->flags & HR_6) &&
Simon Kelley3a610a02018-09-26 16:50:35 +01001271 (cache = whine_malloc(SIZEOF_POINTER_CREC)))
Simon Kelleye759d422012-03-16 13:18:57 +00001272 {
1273 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001274 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001275 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelleycc921df2019-01-02 22:48:59 +00001276 add_hosts_entry(cache, (union all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001277 }
Simon Kelleye759d422012-03-16 13:18:57 +00001278 }
1279
Simon Kelley28866e92011-02-14 20:19:14 +00001280 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001281 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001282 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001283 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001284 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001285 else
1286 {
1287 if (!option_bool(OPT_NO_HOSTS))
1288 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1289
1290 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1291 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1292 if (!(ah->flags & AH_INACTIVE))
1293 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1294 }
Simon Kelley376cb972019-10-29 22:58:55 +00001295
1296 /* Make non-terminal records for all locally-define RRs */
1297 lrec.flags = F_FORWARD | F_CONFIG | F_NAMEP | F_IMMORTAL;
1298
1299 for (txt = daemon->txt; txt; txt = txt->next)
1300 {
1301 lrec.name.namep = txt->name;
1302 make_non_terminals(&lrec);
1303 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001304
Simon Kelley376cb972019-10-29 22:58:55 +00001305 for (naptr = daemon->naptr; naptr; naptr = naptr->next)
1306 {
1307 lrec.name.namep = naptr->name;
1308 make_non_terminals(&lrec);
1309 }
1310
1311 for (mx = daemon->mxnames; mx; mx = mx->next)
1312 {
1313 lrec.name.namep = mx->name;
1314 make_non_terminals(&lrec);
1315 }
1316
1317 for (intr = daemon->int_names; intr; intr = intr->next)
1318 {
1319 lrec.name.namep = intr->name;
1320 make_non_terminals(&lrec);
1321 }
1322
1323 for (ptr = daemon->ptr; ptr; ptr = ptr->next)
1324 {
1325 lrec.name.namep = ptr->name;
1326 make_non_terminals(&lrec);
1327 }
1328
Simon Kelley70d18732015-01-31 19:59:29 +00001329#ifdef HAVE_INOTIFY
1330 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1331#endif
1332
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001333}
1334
Simon Kelley7622fc02009-06-04 20:32:05 +01001335#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001336struct in_addr a_record_from_hosts(char *name, time_t now)
1337{
1338 struct crec *crecp = NULL;
1339 struct in_addr ret;
1340
1341 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1342 if (crecp->flags & F_HOSTS)
Simon Kelleycc921df2019-01-02 22:48:59 +00001343 return crecp->addr.addr4;
Simon Kelley7de060b2011-08-26 17:24:52 +01001344
1345 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1346
1347 ret.s_addr = 0;
1348 return ret;
1349}
1350
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001351void cache_unhash_dhcp(void)
1352{
Simon Kelley6b010842007-02-12 20:32:07 +00001353 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001354 int i;
1355
1356 for (i=0; i<hash_size; i++)
1357 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1358 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001359 {
1360 *up = cache->hash_next;
1361 cache->next = dhcp_spare;
1362 dhcp_spare = cache;
1363 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001364 else
1365 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001366}
1367
Simon Kelley4cb1b322012-02-06 14:30:41 +00001368void cache_add_dhcp_entry(char *host_name, int prot,
Simon Kelleycc921df2019-01-02 22:48:59 +00001369 union all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001370{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001371 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley5b99eae2019-01-06 23:09:50 +00001372 unsigned int flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001373 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001374 size_t addrlen = sizeof(struct in_addr);
1375
Simon Kelley4cb1b322012-02-06 14:30:41 +00001376 if (prot == AF_INET6)
1377 {
1378 flags = F_IPV6;
1379 addrlen = sizeof(struct in6_addr);
1380 }
Simon Kelley9009d742008-11-14 20:04:27 +00001381
Simon Kelley12d71ed2012-08-30 15:16:41 +01001382 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1383
Simon Kelley4cb1b322012-02-06 14:30:41 +00001384 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001385 {
Simon Kelley824af852008-02-12 20:43:05 +00001386 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001387 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001388 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001389 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001390 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001391 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001392 host_name, daemon->addrbuff);
Simon Kelleycc921df2019-01-02 22:48:59 +00001393 else if (memcmp(&crec->addr, host_address, addrlen) == 0)
Simon Kelley12d71ed2012-08-30 15:16:41 +01001394 in_hosts = 1;
1395 else
1396 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001397 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001398 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001399 {
Simon Kelley65a01b72018-12-31 23:56:33 +00001400 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 +00001401 /* scan_free deletes all addresses associated with name */
1402 break;
1403 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001404 }
Simon Kelley824af852008-02-12 20:43:05 +00001405
Simon Kelley12d71ed2012-08-30 15:16:41 +01001406 /* if in hosts, don't need DHCP record */
1407 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001408 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001409
1410 /* Name in hosts, address doesn't match */
1411 if (fail_crec)
1412 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001413 inet_ntop(prot, &fail_crec->addr, daemon->namebuff, MAXDNAME);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001414 my_syslog(MS_DHCP | LOG_WARNING,
1415 _("not giving name %s to the DHCP lease of %s because "
1416 "the name exists in %s with address %s"),
1417 host_name, daemon->addrbuff,
1418 record_source(fail_crec->uid), daemon->namebuff);
1419 return;
1420 }
1421
Simon Kelleycc921df2019-01-02 22:48:59 +00001422 if ((crec = cache_find_by_addr(NULL, (union all_addr *)host_address, 0, flags)))
Simon Kelley12d71ed2012-08-30 15:16:41 +01001423 {
1424 if (crec->flags & F_NEG)
1425 {
1426 flags |= F_REVERSE;
Simon Kelleycc921df2019-01-02 22:48:59 +00001427 cache_scan_free(NULL, (union all_addr *)host_address, C_IN, 0, flags, NULL, NULL);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001428 }
1429 }
1430 else
1431 flags |= F_REVERSE;
1432
1433 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001434 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001435 else /* need new one */
Simon Kelley3a610a02018-09-26 16:50:35 +01001436 crec = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001437
1438 if (crec) /* malloc may fail */
1439 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001440 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001441 if (ttd == 0)
1442 crec->flags |= F_IMMORTAL;
1443 else
1444 crec->ttd = ttd;
Simon Kelleycc921df2019-01-02 22:48:59 +00001445 crec->addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001446 crec->name.namep = host_name;
Simon Kelley45d8a242018-07-17 21:01:14 +01001447 crec->uid = UID_NONE;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001448 cache_hash(crec);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001449 make_non_terminals(crec);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001450 }
1451}
Simon Kelley7622fc02009-06-04 20:32:05 +01001452#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001453
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001454/* Called when we put a local or DHCP name into the cache.
1455 Creates empty cache entries for subnames (ie,
1456 for three.two.one, for two.one and one), without
1457 F_IPV4 or F_IPV6 or F_CNAME set. These convert
1458 NXDOMAIN answers to NoData ones. */
1459static void make_non_terminals(struct crec *source)
1460{
1461 char *name = cache_get_name(source);
Simon Kelleyea6cc332018-09-18 23:21:17 +01001462 struct crec *crecp, *tmp, **up;
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001463 int type = F_HOSTS | F_CONFIG;
1464#ifdef HAVE_DHCP
1465 if (source->flags & F_DHCP)
1466 type = F_DHCP;
1467#endif
1468
1469 /* First delete any empty entries for our new real name. Note that
1470 we only delete empty entries deriving from DHCP for a new DHCP-derived
1471 entry and vice-versa for HOSTS and CONFIG. This ensures that
1472 non-terminals from DHCP go when we reload DHCP and
1473 for HOSTS/CONFIG when we re-read. */
1474 for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
1475 {
1476 tmp = crecp->hash_next;
1477
1478 if (!is_outdated_cname_pointer(crecp) &&
1479 (crecp->flags & F_FORWARD) &&
1480 (crecp->flags & type) &&
Simon Kelley376cb972019-10-29 22:58:55 +00001481 !(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS)) &&
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001482 hostname_isequal(name, cache_get_name(crecp)))
1483 {
1484 *up = crecp->hash_next;
1485#ifdef HAVE_DHCP
1486 if (type & F_DHCP)
1487 {
1488 crecp->next = dhcp_spare;
1489 dhcp_spare = crecp;
1490 }
1491 else
1492#endif
1493 free(crecp);
1494 break;
1495 }
1496 else
1497 up = &crecp->hash_next;
1498 }
1499
1500 while ((name = strchr(name, '.')))
1501 {
1502 name++;
1503
1504 /* Look for one existing, don't need another */
1505 for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
1506 if (!is_outdated_cname_pointer(crecp) &&
1507 (crecp->flags & F_FORWARD) &&
1508 (crecp->flags & type) &&
1509 hostname_isequal(name, cache_get_name(crecp)))
1510 break;
1511
1512 if (crecp)
1513 {
1514 /* If the new name expires later, transfer that time to
1515 empty non-terminal entry. */
1516 if (!(crecp->flags & F_IMMORTAL))
1517 {
1518 if (source->flags & F_IMMORTAL)
1519 crecp->flags |= F_IMMORTAL;
1520 else if (difftime(crecp->ttd, source->ttd) < 0)
1521 crecp->ttd = source->ttd;
1522 }
1523 continue;
1524 }
1525
1526#ifdef HAVE_DHCP
1527 if ((source->flags & F_DHCP) && dhcp_spare)
1528 {
1529 crecp = dhcp_spare;
1530 dhcp_spare = dhcp_spare->next;
1531 }
1532 else
1533#endif
Simon Kelley3a610a02018-09-26 16:50:35 +01001534 crecp = whine_malloc(SIZEOF_POINTER_CREC);
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001535
Simon Kelleyea6cc332018-09-18 23:21:17 +01001536 if (crecp)
1537 {
Simon Kelley376cb972019-10-29 22:58:55 +00001538 crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
Simon Kelley48b090c2018-09-26 12:53:59 +01001539 crecp->ttd = source->ttd;
Simon Kelleyea6cc332018-09-18 23:21:17 +01001540 crecp->name.namep = name;
1541
1542 cache_hash(crecp);
1543 }
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001544 }
1545}
1546
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001547#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001548int cache_make_stat(struct txt_record *t)
1549{
1550 static char *buff = NULL;
1551 static int bufflen = 60;
1552 int len;
1553 struct server *serv, *serv1;
1554 char *p;
1555
1556 if (!buff && !(buff = whine_malloc(60)))
1557 return 0;
1558
1559 p = buff;
1560
1561 switch (t->stat)
1562 {
1563 case TXT_STAT_CACHESIZE:
1564 sprintf(buff+1, "%d", daemon->cachesize);
1565 break;
1566
1567 case TXT_STAT_INSERTS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001568 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001569 break;
1570
1571 case TXT_STAT_EVICTIONS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001572 sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001573 break;
1574
1575 case TXT_STAT_MISSES:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001576 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001577 break;
1578
1579 case TXT_STAT_HITS:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001580 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001581 break;
1582
1583#ifdef HAVE_AUTH
1584 case TXT_STAT_AUTH:
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001585 sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyfec216d2014-03-27 20:54:34 +00001586 break;
1587#endif
1588
1589 case TXT_STAT_SERVERS:
1590 /* sum counts from different records for same server */
1591 for (serv = daemon->servers; serv; serv = serv->next)
1592 serv->flags &= ~SERV_COUNTED;
1593
1594 for (serv = daemon->servers; serv; serv = serv->next)
1595 if (!(serv->flags &
1596 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1597 {
1598 char *new, *lenp;
1599 int port, newlen, bytes_avail, bytes_needed;
1600 unsigned int queries = 0, failed_queries = 0;
1601 for (serv1 = serv; serv1; serv1 = serv1->next)
1602 if (!(serv1->flags &
1603 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1604 sockaddr_isequal(&serv->addr, &serv1->addr))
1605 {
1606 serv1->flags |= SERV_COUNTED;
1607 queries += serv1->queries;
1608 failed_queries += serv1->failed_queries;
1609 }
1610 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1611 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001612 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001613 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1614 if (bytes_needed >= bytes_avail)
1615 {
1616 /* expand buffer if necessary */
1617 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1618 if (!(new = whine_malloc(newlen)))
1619 return 0;
1620 memcpy(new, buff, bufflen);
1621 free(buff);
1622 p = new + (p - buff);
1623 lenp = p - 1;
1624 buff = new;
1625 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001626 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001627 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1628 }
1629 *lenp = bytes_needed;
1630 p += bytes_needed;
1631 }
1632 t->txt = (unsigned char *)buff;
1633 t->len = p - buff;
1634 return 1;
1635 }
1636
1637 len = strlen(buff+1);
1638 t->txt = (unsigned char *)buff;
1639 t->len = len + 1;
1640 *buff = len;
1641 return 1;
1642}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001643#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001644
Simon Kelley394ff492015-03-29 22:17:14 +01001645/* There can be names in the cache containing control chars, don't
1646 mess up logging or open security holes. */
1647static char *sanitise(char *name)
1648{
1649 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001650 if (name)
1651 for (r = (unsigned char *)name; *r; r++)
1652 if (!isprint((int)*r))
1653 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001654
1655 return name;
1656}
1657
1658
Simon Kelley5aabfc72007-08-29 11:24:47 +01001659void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001660{
Simon Kelley824af852008-02-12 20:43:05 +00001661 struct server *serv, *serv1;
1662
1663 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1664 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001665 daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
Simon Kelley824af852008-02-12 20:43:05 +00001666 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001667 daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001668#ifdef HAVE_AUTH
Julian Kornbergeraba8bbb2018-07-21 21:55:08 +01001669 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001670#endif
Simon Kelley5b99eae2019-01-06 23:09:50 +00001671
Simon Kelleyc2207682014-01-08 18:04:20 +00001672 blockdata_report();
Simon Kelley824af852008-02-12 20:43:05 +00001673
Simon Kelley824af852008-02-12 20:43:05 +00001674 /* sum counts from different records for same server */
1675 for (serv = daemon->servers; serv; serv = serv->next)
1676 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001677
Simon Kelley824af852008-02-12 20:43:05 +00001678 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001679 if (!(serv->flags &
1680 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001681 {
1682 int port;
1683 unsigned int queries = 0, failed_queries = 0;
1684 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001685 if (!(serv1->flags &
1686 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1687 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001688 {
1689 serv1->flags |= SERV_COUNTED;
1690 queries += serv1->queries;
1691 failed_queries += serv1->failed_queries;
1692 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001693 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1694 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 +00001695 }
1696
Simon Kelley28866e92011-02-14 20:19:14 +00001697 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001698 {
1699 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001700 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001701 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001702
1703 for (i=0; i<hash_size; i++)
1704 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1705 {
Simon Kelleyb6f926f2018-08-21 17:46:52 +01001706 char *t = " ";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001707 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1708 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001709 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001710 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001711 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001712 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001713 a = sanitise(cache_get_cname_target(cache));
Simon Kelley5b99eae2019-01-06 23:09:50 +00001714 else if ((cache->flags & F_SRV) && !(cache->flags & F_NEG))
1715 {
1716 int targetlen = cache->addr.srv.targetlen;
1717 ssize_t len = sprintf(a, "%u %u %u ", cache->addr.srv.priority,
1718 cache->addr.srv.weight, cache->addr.srv.srvport);
1719
1720 if (targetlen > (40 - len))
1721 targetlen = 40 - len;
1722 blockdata_retrieve(cache->addr.srv.target, targetlen, a + len);
1723 a[len + targetlen] = 0;
1724 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001725#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001726 else if (cache->flags & F_DS)
1727 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001728 if (!(cache->flags & F_NEG))
Simon Kelleycc921df2019-01-02 22:48:59 +00001729 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1730 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001731 }
1732 else if (cache->flags & F_DNSKEY)
Simon Kelleycc921df2019-01-02 22:48:59 +00001733 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1734 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001735#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001736 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001737 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001738 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001739 if (cache->flags & F_IPV4)
Simon Kelleycc921df2019-01-02 22:48:59 +00001740 inet_ntop(AF_INET, &cache->addr, a, ADDRSTRLEN);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001741 else if (cache->flags & F_IPV6)
Simon Kelleycc921df2019-01-02 22:48:59 +00001742 inet_ntop(AF_INET6, &cache->addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001743 }
1744
Simon Kelleye7829ae2014-01-22 22:21:51 +00001745 if (cache->flags & F_IPV4)
1746 t = "4";
1747 else if (cache->flags & F_IPV6)
1748 t = "6";
1749 else if (cache->flags & F_CNAME)
1750 t = "C";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001751 else if (cache->flags & F_SRV)
1752 t = "V";
Simon Kelleye7829ae2014-01-22 22:21:51 +00001753#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001754 else if (cache->flags & F_DS)
1755 t = "S";
1756 else if (cache->flags & F_DNSKEY)
1757 t = "K";
1758#endif
Simon Kelley32678042014-12-17 20:38:20 +00001759 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001760 cache->flags & F_FORWARD ? "F" : " ",
1761 cache->flags & F_REVERSE ? "R" : " ",
1762 cache->flags & F_IMMORTAL ? "I" : " ",
1763 cache->flags & F_DHCP ? "D" : " ",
1764 cache->flags & F_NEG ? "N" : " ",
1765 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001766 cache->flags & F_HOSTS ? "H" : " ",
1767 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001768#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001769 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001770#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001771 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1772 /* ctime includes trailing \n - eat it */
1773 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001774#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001775 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001776 }
1777 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001778}
1779
Simon Kelley19c51cf2014-03-18 22:38:30 +00001780char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001781{
Simon Kelley7622fc02009-06-04 20:32:05 +01001782 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001783
Simon Kelley19c51cf2014-03-18 22:38:30 +00001784 if (index == SRC_CONFIG)
1785 return "config";
1786 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001787 return HOSTSFILE;
1788
1789 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1790 if (ah->index == index)
1791 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001792
1793#ifdef HAVE_INOTIFY
1794 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1795 if (ah->index == index)
1796 return ah->fname;
1797#endif
1798
Simon Kelley7622fc02009-06-04 20:32:05 +01001799 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001800}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001801
Simon Kelley610e7822014-02-06 14:45:17 +00001802char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001803{
1804 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001805 int len = 10; /* strlen("type=xxxxx") */
1806 const char *types = NULL;
1807 static char *buff = NULL;
1808 static int bufflen = 0;
1809
Simon Kelley1a6bca82008-07-11 11:11:42 +01001810 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1811 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001812 {
1813 types = typestr[i].name;
1814 len = strlen(types);
1815 break;
1816 }
1817
Simon Kelleyb758b672018-08-23 21:41:23 +01001818 if (desc)
1819 {
1820 len += 2; /* braces */
1821 len += strlen(desc);
1822 }
1823 len++; /* terminator */
1824
Simon Kelley610e7822014-02-06 14:45:17 +00001825 if (!buff || bufflen < len)
1826 {
1827 if (buff)
1828 free(buff);
1829 else if (len < 20)
1830 len = 20;
1831
1832 buff = whine_malloc(len);
1833 bufflen = len;
1834 }
1835
1836 if (buff)
1837 {
Simon Kelleyb758b672018-08-23 21:41:23 +01001838 if (desc)
1839 {
1840 if (types)
1841 sprintf(buff, "%s[%s]", desc, types);
1842 else
1843 sprintf(buff, "%s[type=%d]", desc, type);
1844 }
Simon Kelley610e7822014-02-06 14:45:17 +00001845 else
Simon Kelleyb758b672018-08-23 21:41:23 +01001846 {
1847 if (types)
1848 sprintf(buff, "<%s>", types);
1849 else
1850 sprintf(buff, "type=%d", type);
1851 }
Simon Kelley610e7822014-02-06 14:45:17 +00001852 }
Simon Kelleyb758b672018-08-23 21:41:23 +01001853
Simon Kelley610e7822014-02-06 14:45:17 +00001854 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001855}
1856
Simon Kelleycc921df2019-01-02 22:48:59 +00001857void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001858{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001859 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001860 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001861
Simon Kelley28866e92011-02-14 20:19:14 +00001862 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001863 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001864
Simon Kelley394ff492015-03-29 22:17:14 +01001865 name = sanitise(name);
1866
Simon Kelley5aabfc72007-08-29 11:24:47 +01001867 if (addr)
1868 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001869 if (flags & F_KEYTAG)
Simon Kelleycc921df2019-01-02 22:48:59 +00001870 sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
Simon Kelley07ed5852018-05-04 21:52:22 +01001871 else if (flags & F_RCODE)
1872 {
Simon Kelleycc921df2019-01-02 22:48:59 +00001873 unsigned int rcode = addr->log.rcode;
Simon Kelley07ed5852018-05-04 21:52:22 +01001874
1875 if (rcode == SERVFAIL)
1876 dest = "SERVFAIL";
1877 else if (rcode == REFUSED)
1878 dest = "REFUSED";
1879 else if (rcode == NOTIMP)
1880 dest = "not implemented";
1881 else
1882 sprintf(daemon->addrbuff, "%u", rcode);
1883 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001884 else
Simon Kelleyee875042018-10-23 22:10:17 +01001885 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1886 addr, daemon->addrbuff, ADDRSTRLEN);
1887
Simon Kelley5aabfc72007-08-29 11:24:47 +01001888 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001889 else
1890 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001891
1892 if (flags & F_REVERSE)
1893 {
1894 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001895 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001896 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001897
1898 if (flags & F_NEG)
1899 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001900 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001901 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001902 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001903 {
1904 if (flags & F_IPV4)
1905 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001906 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001907 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001908 else
1909 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001910 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001911 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001912 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001913 dest = "<CNAME>";
Simon Kelley5b99eae2019-01-06 23:09:50 +00001914 else if (flags & F_SRV)
1915 dest = "<SRV>";
Simon Kelley28866e92011-02-14 20:19:14 +00001916 else if (flags & F_RRNAME)
1917 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001918
Simon Kelley1f15b812009-10-13 17:49:32 +01001919 if (flags & F_CONFIG)
1920 source = "config";
1921 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001922 source = "DHCP";
1923 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001924 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001925 else if (flags & F_UPSTREAM)
1926 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001927 else if (flags & F_SECSTAT)
1928 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001929 else if (flags & F_AUTH)
1930 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001931 else if (flags & F_SERVER)
1932 {
1933 source = "forwarded";
1934 verb = "to";
1935 }
1936 else if (flags & F_QUERY)
1937 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001938 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001939 verb = "from";
1940 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001941 else if (flags & F_DNSSEC)
1942 {
1943 source = arg;
1944 verb = "to";
1945 }
Wang Jian49752b92014-03-28 20:52:47 +00001946 else if (flags & F_IPSET)
1947 {
1948 source = "ipset add";
1949 dest = name;
1950 name = arg;
1951 verb = daemon->addrbuff;
1952 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001953 else
1954 source = "cached";
1955
Simon Kelley3d8df262005-08-29 12:19:27 +01001956 if (strlen(name) == 0)
1957 name = ".";
1958
Simon Kelley25cf5e32015-01-09 15:53:03 +00001959 if (option_bool(OPT_EXTRALOG))
1960 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001961 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001962 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001963 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001964 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001965 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 +00001966 }
1967 else
1968 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001969}
1970
Simon Kelley98c098b2014-01-08 17:31:16 +00001971