blob: 8b1b5607f912ed07cee67fa17e048a60e822f17b [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;
Simon Kelley5aabfc72007-08-29 11:24:47 +010024static int cache_inserted = 0, cache_live_freed = 0, insert_error;
25static union bigname *big_free = NULL;
26static int bignames_left, hash_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000027
Simon Kelley16972692006-10-16 20:04:18 +010028/* type->string mapping: this is also used by the name-hash function as a mixing table. */
29static const struct {
30 unsigned int type;
31 const char * const name;
32} typestr[] = {
33 { 1, "A" },
34 { 2, "NS" },
35 { 5, "CNAME" },
36 { 6, "SOA" },
37 { 10, "NULL" },
38 { 11, "WKS" },
39 { 12, "PTR" },
40 { 13, "HINFO" },
41 { 15, "MX" },
42 { 16, "TXT" },
43 { 22, "NSAP" },
44 { 23, "NSAP_PTR" },
45 { 24, "SIG" },
46 { 25, "KEY" },
47 { 28, "AAAA" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010048 { 29, "LOC" },
Simon Kelley16972692006-10-16 20:04:18 +010049 { 33, "SRV" },
Simon Kelley1a6bca82008-07-11 11:11:42 +010050 { 35, "NAPTR" },
Simon Kelley16972692006-10-16 20:04:18 +010051 { 36, "KX" },
52 { 37, "CERT" },
53 { 38, "A6" },
54 { 39, "DNAME" },
55 { 41, "OPT" },
Simon Kelley0fc2f312014-01-08 10:26:58 +000056 { 43, "DS" },
57 { 46, "RRSIG" },
Simon Kelley610e7822014-02-06 14:45:17 +000058 { 47, "NSEC" },
Simon Kelley832af0b2007-01-21 20:01:28 +000059 { 48, "DNSKEY" },
Simon Kelley610e7822014-02-06 14:45:17 +000060 { 50, "NSEC3" },
Simon Kelleyaa6f8322017-10-27 22:52:26 +010061 { 51, "NSEC3PARAM" },
62 { 52, "TLSA" },
63 { 53, "SMIMEA" },
64 { 55, "HIP" },
Simon Kelley832af0b2007-01-21 20:01:28 +000065 { 249, "TKEY" },
Simon Kelley16972692006-10-16 20:04:18 +010066 { 250, "TSIG" },
67 { 251, "IXFR" },
68 { 252, "AXFR" },
69 { 253, "MAILB" },
70 { 254, "MAILA" },
71 { 255, "ANY" }
72};
73
Simon Kelley9e4abcb2004-01-22 19:47:41 +000074static void cache_free(struct crec *crecp);
75static void cache_unlink(struct crec *crecp);
76static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010077static void rehash(int size);
78static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000079
Simon Kelley3f7483e2014-03-16 22:56:58 +000080static unsigned int next_uid(void)
81{
Andyd5082152014-03-17 19:50:29 +000082 static unsigned int uid = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +000083
Andyd5082152014-03-17 19:50:29 +000084 uid++;
85
Simon Kelley3f7483e2014-03-16 22:56:58 +000086 /* uid == 0 used to indicate CNAME to interface name. */
Simon Kelley19c51cf2014-03-18 22:38:30 +000087 if (uid == SRC_INTERFACE)
Simon Kelley3f7483e2014-03-16 22:56:58 +000088 uid++;
89
Andyd5082152014-03-17 19:50:29 +000090 return uid;
Simon Kelley3f7483e2014-03-16 22:56:58 +000091}
92
Simon Kelley5aabfc72007-08-29 11:24:47 +010093void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000094{
95 struct crec *crecp;
96 int i;
Simon Kelleyd56a6042013-10-11 14:39:03 +010097
Simon Kelley5aabfc72007-08-29 11:24:47 +010098 bignames_left = daemon->cachesize/10;
99
100 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000101 {
Simon Kelley5aabfc72007-08-29 11:24:47 +0100102 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000103
Simon Kelley5aabfc72007-08-29 11:24:47 +0100104 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000105 {
106 cache_link(crecp);
107 crecp->flags = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +0000108 crecp->uid = next_uid();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109 }
110 }
111
Simon Kelley4011c4e2006-10-28 16:26:19 +0100112 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +0100113 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000114}
115
Simon Kelley4011c4e2006-10-28 16:26:19 +0100116/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
117 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
118 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
119 expand the table. */
120static void rehash(int size)
121{
122 struct crec **new, **old, *p, *tmp;
123 int i, new_size, old_size;
124
125 /* hash_size is a power of two. */
126 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
127
128 /* must succeed in getting first instance, failure later is non-fatal */
129 if (!hash_table)
130 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100131 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100132 return;
133
134 for(i = 0; i < new_size; i++)
135 new[i] = NULL;
136
137 old = hash_table;
138 old_size = hash_size;
139 hash_table = new;
140 hash_size = new_size;
141
142 if (old)
143 {
144 for (i = 0; i < old_size; i++)
145 for (p = old[i]; p ; p = tmp)
146 {
147 tmp = p->hash_next;
148 cache_hash(p);
149 }
150 free(old);
151 }
152}
153
Simon Kelley3d8df262005-08-29 12:19:27 +0100154static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000155{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100156 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100157 const unsigned char *mix_tab = (const unsigned char*)typestr;
158
Simon Kelley3d8df262005-08-29 12:19:27 +0100159 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100160 {
161 /* don't use tolower and friends here - they may be messed up by LOCALE */
162 if (c >= 'A' && c <= 'Z')
163 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100164 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100165 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000166
167 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100168 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000169}
170
171static void cache_hash(struct crec *crecp)
172{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000173 /* maintain an invariant that all entries with F_REVERSE set
174 are at the start of the hash-chain and all non-reverse
175 immortal entries are at the end of the hash-chain.
176 This allows reverse searches and garbage collection to be optimised */
177
178 struct crec **up = hash_bucket(cache_get_name(crecp));
179
180 if (!(crecp->flags & F_REVERSE))
181 {
182 while (*up && ((*up)->flags & F_REVERSE))
183 up = &((*up)->hash_next);
184
185 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000186 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000187 up = &((*up)->hash_next);
188 }
189 crecp->hash_next = *up;
190 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000191}
Simon Kelley82e3f452014-01-31 21:05:48 +0000192
193#ifdef HAVE_DNSSEC
194static void cache_blockdata_free(struct crec *crecp)
195{
196 if (crecp->flags & F_DNSKEY)
Simon Kelley93be5b12015-12-15 12:04:40 +0000197 blockdata_free(crecp->addr.key.keydata);
Simon Kelleye3f14552014-03-01 17:58:28 +0000198 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
Simon Kelley82e3f452014-01-31 21:05:48 +0000199 blockdata_free(crecp->addr.ds.keydata);
200}
201#endif
202
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000203static void cache_free(struct crec *crecp)
204{
205 crecp->flags &= ~F_FORWARD;
206 crecp->flags &= ~F_REVERSE;
Simon Kelley3f7483e2014-03-16 22:56:58 +0000207 crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100208
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000209 if (cache_tail)
210 cache_tail->next = crecp;
211 else
212 cache_head = crecp;
213 crecp->prev = cache_tail;
214 crecp->next = NULL;
215 cache_tail = crecp;
216
217 /* retrieve big name for further use. */
218 if (crecp->flags & F_BIGNAME)
219 {
220 crecp->name.bname->next = big_free;
221 big_free = crecp->name.bname;
222 crecp->flags &= ~F_BIGNAME;
223 }
Simon Kelley072e81b2014-01-31 12:42:54 +0000224
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100225#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +0000226 cache_blockdata_free(crecp);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100227#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000228}
229
230/* insert a new cache entry at the head of the list (youngest entry) */
231static void cache_link(struct crec *crecp)
232{
233 if (cache_head) /* check needed for init code */
234 cache_head->prev = crecp;
235 crecp->next = cache_head;
236 crecp->prev = NULL;
237 cache_head = crecp;
238 if (!cache_tail)
239 cache_tail = crecp;
240}
241
242/* remove an arbitrary cache entry for promotion */
243static void cache_unlink (struct crec *crecp)
244{
245 if (crecp->prev)
246 crecp->prev->next = crecp->next;
247 else
248 cache_head = crecp->next;
249
250 if (crecp->next)
251 crecp->next->prev = crecp->prev;
252 else
253 cache_tail = crecp->prev;
254}
255
256char *cache_get_name(struct crec *crecp)
257{
258 if (crecp->flags & F_BIGNAME)
259 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000260 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000261 return crecp->name.namep;
262
263 return crecp->name.sname;
264}
265
Simon Kelleyd56a6042013-10-11 14:39:03 +0100266char *cache_get_cname_target(struct crec *crecp)
267{
Simon Kelley19c51cf2014-03-18 22:38:30 +0000268 if (crecp->addr.cname.uid != SRC_INTERFACE)
Simon Kelleyd56a6042013-10-11 14:39:03 +0100269 return cache_get_name(crecp->addr.cname.target.cache);
270
271 return crecp->addr.cname.target.int_name->name;
272}
273
274
275
Simon Kelleyb75e9362012-12-07 11:50:41 +0000276struct crec *cache_enumerate(int init)
277{
278 static int bucket;
279 static struct crec *cache;
280
281 if (init)
282 {
283 bucket = 0;
284 cache = NULL;
285 }
286 else if (cache && cache->hash_next)
287 cache = cache->hash_next;
288 else
289 {
290 cache = NULL;
291 while (bucket < hash_size)
292 if ((cache = hash_table[bucket++]))
293 break;
294 }
295
296 return cache;
297}
298
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100299static int is_outdated_cname_pointer(struct crec *crecp)
300{
Andy3e21a1a2014-03-22 19:10:07 +0000301 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100302 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100303
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100304 /* NB. record may be reused as DS or DNSKEY, where uid is
305 overloaded for something completely different */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100306 if (crecp->addr.cname.target.cache &&
307 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
308 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100309 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100310
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100311 return 1;
312}
313
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000314static int is_expired(time_t now, struct crec *crecp)
315{
316 if (crecp->flags & F_IMMORTAL)
317 return 0;
318
319 if (difftime(now, crecp->ttd) < 0)
320 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100321
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000322 return 1;
323}
324
Simon Kelleycbc65242014-12-21 21:21:53 +0000325static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000326{
327 /* Scan and remove old entries.
328 If (flags & F_FORWARD) then remove any forward entries for name and any expired
329 entries but only in the same hash bucket as name.
330 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
331 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000332 If (flags == 0) remove any expired entries in the whole cache.
333
Simon Kelleycbc65242014-12-21 21:21:53 +0000334 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
335 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 +0000336
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000337 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
338 so that when we hit an entry which isn't reverse and is immortal, we're done. */
339
340 struct crec *crecp, **up;
341
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000342 if (flags & F_FORWARD)
343 {
Simon Kelley6b010842007-02-12 20:32:07 +0000344 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000345 {
346 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
347 {
348 *up = crecp->hash_next;
349 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
350 {
351 cache_unlink(crecp);
352 cache_free(crecp);
353 }
354 continue;
355 }
356
357 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
358 {
Simon Kelleye7829ae2014-01-22 22:21:51 +0000359 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
360 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
Simon Kelley6429e422014-01-23 12:09:36 +0000361 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000362 {
363 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelleycbc65242014-12-21 21:21:53 +0000364 return crecp;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000365 *up = crecp->hash_next;
366 cache_unlink(crecp);
367 cache_free(crecp);
368 continue;
369 }
370
371#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000372 /* Deletion has to be class-sensitive for DS and DNSKEY */
373 if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000374 {
Simon Kelley824202e2014-01-23 20:59:46 +0000375 if (crecp->flags & F_CONFIG)
Simon Kelleycbc65242014-12-21 21:21:53 +0000376 return crecp;
Simon Kelley824202e2014-01-23 20:59:46 +0000377 *up = crecp->hash_next;
378 cache_unlink(crecp);
379 cache_free(crecp);
380 continue;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000381 }
382#endif
383 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000384 up = &crecp->hash_next;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000385 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000386 }
387 else
388 {
389 int i;
390#ifdef HAVE_IPV6
391 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
392#else
393 int addrlen = INADDRSZ;
394#endif
395 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000396 for (crecp = hash_table[i], up = &hash_table[i];
397 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
398 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000399 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000400 {
401 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000402 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000403 {
404 cache_unlink(crecp);
405 cache_free(crecp);
406 }
407 }
Simon Kelley25439062013-11-25 21:14:51 +0000408 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000409 (flags & crecp->flags & F_REVERSE) &&
410 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
411 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
412 {
413 *up = crecp->hash_next;
414 cache_unlink(crecp);
415 cache_free(crecp);
416 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000417 else
418 up = &crecp->hash_next;
419 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000420
Simon Kelleycbc65242014-12-21 21:21:53 +0000421 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000422}
423
424/* Note: The normal calling sequence is
425 cache_start_insert
426 cache_insert * n
427 cache_end_insert
428
429 but an abort can cause the cache_end_insert to be missed
430 in which can the next cache_start_insert cleans things up. */
431
432void cache_start_insert(void)
433{
434 /* Free any entries which didn't get committed during the last
435 insert due to error.
436 */
437 while (new_chain)
438 {
439 struct crec *tmp = new_chain->next;
440 cache_free(new_chain);
441 new_chain = tmp;
442 }
443 new_chain = NULL;
444 insert_error = 0;
445}
446
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100447struct crec *cache_insert(char *name, struct all_addr *addr,
448 time_t now, unsigned long ttl, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000449{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450 struct crec *new;
451 union bigname *big_name = NULL;
452 int freed_all = flags & F_REVERSE;
Simon Kelley9e038942008-05-30 20:06:34 +0100453 int free_avail = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000454
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000455 /* Don't log DNSSEC records here, done elsewhere */
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000456 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000457 {
458 log_query(flags | F_UPSTREAM, name, addr, NULL);
RinSatsuki28de3872015-01-10 15:22:21 +0000459 /* Don't mess with TTL for DNSSEC records. */
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000460 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
461 ttl = daemon->max_cache_ttl;
RinSatsuki28de3872015-01-10 15:22:21 +0000462 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
463 ttl = daemon->min_cache_ttl;
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000464 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000465
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000466 /* if previous insertion failed give up now. */
467 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100468 return NULL;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000469
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000470 /* First remove any expired entries and entries for the name/address we
Simon Kelleycbc65242014-12-21 21:21:53 +0000471 are currently inserting. */
472 if ((new = cache_scan_free(name, addr, now, flags)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000473 {
Simon Kelleycbc65242014-12-21 21:21:53 +0000474 /* We're trying to insert a record over one from
475 /etc/hosts or DHCP, or other config. If the
476 existing record is for an A or AAAA and
477 the record we're trying to insert is the same,
478 just drop the insert, but don't error the whole process. */
Edwin Török41a8d9e2015-11-14 17:45:48 +0000479 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000480 {
481 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
482 new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
483 return new;
484#ifdef HAVE_IPV6
485 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
486 IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
487 return new;
488#endif
489 }
490
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000491 insert_error = 1;
492 return NULL;
493 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000494
495 /* Now get a cache entry from the end of the LRU list */
496 while (1) {
497 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
498 {
499 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100500 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000501 }
502
503 /* End of LRU list is still in use: if we didn't scan all the hash
504 chains for expired entries do that now. If we already tried that
505 then it's time to start spilling things. */
506
507 if (new->flags & (F_FORWARD | F_REVERSE))
508 {
Simon Kelley9e038942008-05-30 20:06:34 +0100509 /* If free_avail set, we believe that an entry has been freed.
510 Bugs have been known to make this not true, resulting in
Simon Kelley1a6bca82008-07-11 11:11:42 +0100511 a tight loop here. If that happens, abandon the
Simon Kelley9e038942008-05-30 20:06:34 +0100512 insert. Once in this state, all inserts will probably fail. */
Simon Kelley9e038942008-05-30 20:06:34 +0100513 if (free_avail)
514 {
Simon Kelley5f938532014-02-03 16:44:32 +0000515 static int warned = 0;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000516 if (!warned)
517 {
518 my_syslog(LOG_ERR, _("Internal error in cache."));
519 warned = 1;
520 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100521 insert_error = 1;
Simon Kelley9e038942008-05-30 20:06:34 +0100522 return NULL;
523 }
524
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000525 if (freed_all)
526 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000527 struct all_addr free_addr = new->addr.addr;;
528
529#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000530 /* For DNSSEC records, addr holds class. */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000531 if (new->flags & (F_DS | F_DNSKEY))
Simon Kelley93be5b12015-12-15 12:04:40 +0000532 free_addr.addr.dnssec.class = new->uid;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000533#endif
534
Simon Kelley9e038942008-05-30 20:06:34 +0100535 free_avail = 1; /* Must be free space now. */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000536 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000537 cache_live_freed++;
538 }
539 else
540 {
541 cache_scan_free(NULL, NULL, now, 0);
542 freed_all = 1;
543 }
544 continue;
545 }
546
547 /* Check if we need to and can allocate extra memory for a long name.
Simon Kelley8d718cb2014-02-03 16:27:37 +0000548 If that fails, give up now, always succeed for DNSSEC records. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000549 if (name && (strlen(name) > SMALLDNAME-1))
550 {
551 if (big_free)
552 {
553 big_name = big_free;
554 big_free = big_free->next;
555 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000556 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100557 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000558 {
559 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100560 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000561 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000562 else if (bignames_left != 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000563 bignames_left--;
564
565 }
566
567 /* Got the rest: finally grab entry. */
568 cache_unlink(new);
569 break;
570 }
571
572 new->flags = flags;
573 if (big_name)
574 {
575 new->name.bname = big_name;
576 new->flags |= F_BIGNAME;
577 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100578
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000579 if (name)
580 strcpy(cache_get_name(new), name);
581 else
582 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100583
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000584 if (addr)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000585 {
586#ifdef HAVE_DNSSEC
587 if (flags & (F_DS | F_DNSKEY))
588 new->uid = addr->addr.dnssec.class;
589 else
590#endif
591 new->addr.addr = *addr;
592 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100593
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000594 new->ttd = now + (time_t)ttl;
595 new->next = new_chain;
596 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100597
598 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000599}
600
601/* after end of insertion, commit the new entries */
602void cache_end_insert(void)
603{
604 if (insert_error)
605 return;
606
607 while (new_chain)
608 {
609 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100610 /* drop CNAMEs which didn't find a target. */
611 if (is_outdated_cname_pointer(new_chain))
612 cache_free(new_chain);
613 else
614 {
615 cache_hash(new_chain);
616 cache_link(new_chain);
617 cache_inserted++;
618 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000619 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000620 }
621 new_chain = NULL;
622}
623
Simon Kelley12fae492014-02-04 22:03:06 +0000624struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000625{
626 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000627 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000628
Simon Kelley12fae492014-02-04 22:03:06 +0000629 prot &= ~F_NO_RR;
630
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000631 if (crecp) /* iterating */
632 ans = crecp->next;
633 else
634 {
635 /* first search, look for relevant entries and push to top of list
636 also free anything which has expired */
637 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley28866e92011-02-14 20:19:14 +0000638 unsigned short ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000639
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000640 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
641 {
642 next = crecp->hash_next;
643
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000644 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000645 {
646 if ((crecp->flags & F_FORWARD) &&
647 (crecp->flags & prot) &&
648 hostname_isequal(cache_get_name(crecp), name))
649 {
Simon Kelley25439062013-11-25 21:14:51 +0000650 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000651 {
652 *chainp = crecp;
653 chainp = &crecp->next;
654 }
655 else
656 {
657 cache_unlink(crecp);
658 cache_link(crecp);
659 }
660
Simon Kelley824af852008-02-12 20:43:05 +0000661 /* Move all but the first entry up the hash chain
662 this implements round-robin.
663 Make sure that re-ordering doesn't break the hash-chain
664 order invariants.
665 */
Simon Kelley9e038942008-05-30 20:06:34 +0100666 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000667 {
668 *up = crecp->hash_next;
669 crecp->hash_next = *insert;
670 *insert = crecp;
671 insert = &crecp->hash_next;
672 }
Simon Kelley9e038942008-05-30 20:06:34 +0100673 else
674 {
Simon Kelley12fae492014-02-04 22:03:06 +0000675 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100676 {
677 insert = up;
678 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
679 }
680 up = &crecp->hash_next;
681 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000682 }
683 else
684 /* case : not expired, incorrect entry. */
685 up = &crecp->hash_next;
686 }
687 else
688 {
689 /* expired entry, free it */
690 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000691 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000692 {
693 cache_unlink(crecp);
694 cache_free(crecp);
695 }
696 }
697 }
698
699 *chainp = cache_head;
700 }
701
702 if (ans &&
703 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000704 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000705 hostname_isequal(cache_get_name(ans), name))
706 return ans;
707
708 return NULL;
709}
710
711struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000712 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000713{
714 struct crec *ans;
715#ifdef HAVE_IPV6
716 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
717#else
718 int addrlen = INADDRSZ;
719#endif
720
721 if (crecp) /* iterating */
722 ans = crecp->next;
723 else
724 {
725 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000726 also free anything which has expired. All the reverse entries are at the
727 start of the hash chain, so we can give up when we find the first
728 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000729 int i;
730 struct crec **up, **chainp = &ans;
731
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000732 for (i=0; i<hash_size; i++)
733 for (crecp = hash_table[i], up = &hash_table[i];
734 crecp && (crecp->flags & F_REVERSE);
735 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000736 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000737 {
Simon Kelley6b010842007-02-12 20:32:07 +0000738 if ((crecp->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100739 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000740 {
Simon Kelley25439062013-11-25 21:14:51 +0000741 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000742 {
743 *chainp = crecp;
744 chainp = &crecp->next;
745 }
746 else
747 {
748 cache_unlink(crecp);
749 cache_link(crecp);
750 }
751 }
752 up = &crecp->hash_next;
753 }
754 else
755 {
756 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000757 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000758 {
759 cache_unlink(crecp);
760 cache_free(crecp);
761 }
762 }
763
764 *chainp = cache_head;
765 }
766
767 if (ans &&
768 (ans->flags & F_REVERSE) &&
769 (ans->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100770 memcmp(&ans->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000771 return ans;
772
773 return NULL;
774}
775
Simon Kelley611ebc52012-07-16 16:23:46 +0100776static void add_hosts_cname(struct crec *target)
777{
778 struct crec *crec;
779 struct cname *a;
780
781 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +0000782 if (a->alias[1] != '*' &&
783 hostname_isequal(cache_get_name(target), a->target) &&
Simon Kelley611ebc52012-07-16 16:23:46 +0100784 (crec = whine_malloc(sizeof(struct crec))))
785 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000786 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000787 crec->ttd = a->ttl;
Simon Kelley611ebc52012-07-16 16:23:46 +0100788 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100789 crec->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +0100790 crec->addr.cname.uid = target->uid;
Simon Kelley19c51cf2014-03-18 22:38:30 +0000791 crec->uid = next_uid();
Simon Kelley611ebc52012-07-16 16:23:46 +0100792 cache_hash(crec);
793 add_hosts_cname(crec); /* handle chains */
794 }
795}
796
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100797static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000798 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000799{
Simon Kelleye759d422012-03-16 13:18:57 +0000800 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 +0000801 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000802 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000803
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000804 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000805 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000806 {
Simon Kelley9009d742008-11-14 20:04:27 +0000807 nameexists = 1;
808 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
809 {
810 free(cache);
811 return;
812 }
813 }
814
815 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000816 We do this by steam here, The entries are kept in hash chains, linked
817 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000818 the array rhash, hashed on address. Note that rhash and the values
819 in ->next are only valid whilst reading hosts files: the buckets are
820 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000821
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000822 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000823
824 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +0000825 large (10000 entry) hosts files.
826
827 Note that we only do this process when bulk-reading hosts files,
828 for incremental reads, rhash is NULL, and we use cache lookups
829 instead.
830 */
Simon Kelley9009d742008-11-14 20:04:27 +0000831
Simon Kelley70d18732015-01-31 19:59:29 +0000832 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +0000833 {
Simon Kelley70d18732015-01-31 19:59:29 +0000834 /* hash address */
835 for (j = 0, i = 0; i < addrlen; i++)
836 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
837
838 for (lookup = rhash[j]; lookup; lookup = lookup->next)
839 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
840 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
841 {
842 cache->flags &= ~F_REVERSE;
843 break;
844 }
845
846 /* maintain address hash chain, insert new unique address */
847 if (!lookup)
848 {
849 cache->next = rhash[j];
850 rhash[j] = cache;
851 }
Simon Kelley915363f2012-01-11 22:00:48 +0000852 }
Simon Kelley70d18732015-01-31 19:59:29 +0000853 else
854 {
855 /* incremental read, lookup in cache */
856 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
857 if (lookup && lookup->flags & F_HOSTS)
858 cache->flags &= ~F_REVERSE;
859 }
860
Simon Kelley9009d742008-11-14 20:04:27 +0000861 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000862 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000863 cache_hash(cache);
864
865 /* don't need to do alias stuff for second and subsequent addresses. */
866 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100867 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000868}
869
870static int eatspace(FILE *f)
871{
872 int c, nl = 0;
873
874 while (1)
875 {
876 if ((c = getc(f)) == '#')
877 while (c != '\n' && c != EOF)
878 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000879
Simon Kelley9009d742008-11-14 20:04:27 +0000880 if (c == EOF)
881 return 1;
882
883 if (!isspace(c))
884 {
885 ungetc(c, f);
886 return nl;
887 }
888
889 if (c == '\n')
890 nl = 1;
891 }
892}
893
894static int gettok(FILE *f, char *token)
895{
896 int c, count = 0;
897
898 while (1)
899 {
900 if ((c = getc(f)) == EOF)
901 return (count == 0) ? EOF : 1;
902
903 if (isspace(c) || c == '#')
904 {
905 ungetc(c, f);
906 return eatspace(f);
907 }
908
909 if (count < (MAXDNAME - 1))
910 {
911 token[count++] = c;
912 token[count] = 0;
913 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000914 }
915}
916
Simon Kelley70d18732015-01-31 19:59:29 +0000917int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000918{
919 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000920 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100921 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000922 unsigned short flags = 0;
923 struct all_addr addr;
924 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100925
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000926 if (!f)
927 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100928 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +0000929 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000930 }
Simon Kelley9009d742008-11-14 20:04:27 +0000931
932 eatspace(f);
933
934 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000935 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000937
Simon Kelley3d8df262005-08-29 12:19:27 +0100938 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000939 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000940 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000941 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000942 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000943 }
Simon Kelleye759d422012-03-16 13:18:57 +0000944#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100945 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000946 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000947 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000948 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000949 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000950 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000951#endif
952 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000953 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100954 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +0000955 while (atnl == 0)
956 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000957 continue;
958 }
Simon Kelley9009d742008-11-14 20:04:27 +0000959
Simon Kelley9009d742008-11-14 20:04:27 +0000960 addr_count++;
961
962 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +0000963 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +0000964 {
965 rehash(name_count);
966 cache_size = name_count;
967 }
968
969 while (atnl == 0)
970 {
971 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +0100972 int fqdn, nomem;
973 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +0000974
975 if ((atnl = gettok(f, token)) == EOF)
976 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000977
Simon Kelley9009d742008-11-14 20:04:27 +0000978 fqdn = !!strchr(token, '.');
979
Simon Kelley1f15b812009-10-13 17:49:32 +0100980 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +0000981 {
982 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +0000983 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley9009d742008-11-14 20:04:27 +0000984 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +0100985 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000986 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100987 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +0000988 strcat(cache->name.sname, ".");
989 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +0000990 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000991 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +0000992 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000993 name_count++;
994 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100995 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000996 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100997 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +0000998 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000999 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +00001000 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +00001001 name_count++;
1002 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001003 free(canon);
1004
Simon Kelley9009d742008-11-14 20:04:27 +00001005 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001006 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001007 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1008 }
1009 }
1010
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001011 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001012
Simon Kelley70d18732015-01-31 19:59:29 +00001013 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001014 rehash(name_count);
1015
1016 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1017
Simon Kelley4011c4e2006-10-28 16:26:19 +01001018 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001019}
1020
Simon Kelley7622fc02009-06-04 20:32:05 +01001021void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001022{
1023 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001024 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001025 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001026 struct host_record *hr;
1027 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001028 struct cname *a;
1029 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001030#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001031 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001032#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001033
Simon Kelley59353a62004-11-21 19:34:28 +00001034 cache_inserted = cache_live_freed = 0;
1035
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001036 for (i=0; i<hash_size; i++)
1037 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1038 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001039#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +00001040 cache_blockdata_free(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001041#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001042 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001043 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001044 {
1045 *up = cache->hash_next;
1046 free(cache);
1047 }
1048 else if (!(cache->flags & F_DHCP))
1049 {
1050 *up = cache->hash_next;
1051 if (cache->flags & F_BIGNAME)
1052 {
1053 cache->name.bname->next = big_free;
1054 big_free = cache->name.bname;
1055 }
1056 cache->flags = 0;
1057 }
1058 else
1059 up = &cache->hash_next;
1060 }
1061
Simon Kelleyd56a6042013-10-11 14:39:03 +01001062 /* Add CNAMEs to interface_names to the cache */
1063 for (a = daemon->cnames; a; a = a->next)
1064 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001065 if (a->alias[1] != '*' &&
1066 hostname_isequal(a->target, intr->name) &&
Simon Kelley532066e2013-11-26 10:14:47 +00001067 ((cache = whine_malloc(sizeof(struct crec)))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001068 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001069 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001070 cache->ttd = a->ttl;
Simon Kelley532066e2013-11-26 10:14:47 +00001071 cache->name.namep = a->alias;
1072 cache->addr.cname.target.int_name = intr;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001073 cache->addr.cname.uid = SRC_INTERFACE;
1074 cache->uid = next_uid();
Simon Kelley532066e2013-11-26 10:14:47 +00001075 cache_hash(cache);
1076 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001077 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001078
1079#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001080 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001081 if ((cache = whine_malloc(sizeof(struct crec))) &&
Simon Kelleyee415862014-02-11 11:07:22 +00001082 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001083 {
Simon Kelleyee415862014-02-11 11:07:22 +00001084 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001085 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001086 cache->name.namep = ds->name;
1087 cache->addr.ds.keylen = ds->digestlen;
1088 cache->addr.ds.algo = ds->algo;
1089 cache->addr.ds.keytag = ds->keytag;
1090 cache->addr.ds.digest = ds->digest_type;
1091 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001092 cache_hash(cache);
1093 }
1094#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001095
Simon Kelleye759d422012-03-16 13:18:57 +00001096 /* borrow the packet buffer for a temporary by-address hash */
1097 memset(daemon->packet, 0, daemon->packet_buff_sz);
1098 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1099 /* we overwrote the buffer... */
1100 daemon->srv_save = NULL;
1101
1102 /* Do host_records in config. */
1103 for (hr = daemon->host_records; hr; hr = hr->next)
1104 for (nl = hr->names; nl; nl = nl->next)
1105 {
1106 if (hr->addr.s_addr != 0 &&
1107 (cache = whine_malloc(sizeof(struct crec))))
1108 {
1109 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001110 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001111 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001112 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001113 }
1114#ifdef HAVE_IPV6
1115 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1116 (cache = whine_malloc(sizeof(struct crec))))
1117 {
1118 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001119 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001120 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001121 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001122 }
1123#endif
1124 }
1125
Simon Kelley28866e92011-02-14 20:19:14 +00001126 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001127 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001128 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001129 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001130 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001131 else
1132 {
1133 if (!option_bool(OPT_NO_HOSTS))
1134 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1135
1136 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1137 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1138 if (!(ah->flags & AH_INACTIVE))
1139 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1140 }
1141
Simon Kelley70d18732015-01-31 19:59:29 +00001142#ifdef HAVE_INOTIFY
1143 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1144#endif
1145
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001146}
1147
Simon Kelley7622fc02009-06-04 20:32:05 +01001148#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001149struct in_addr a_record_from_hosts(char *name, time_t now)
1150{
1151 struct crec *crecp = NULL;
1152 struct in_addr ret;
1153
1154 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1155 if (crecp->flags & F_HOSTS)
1156 return *(struct in_addr *)&crecp->addr;
1157
1158 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1159
1160 ret.s_addr = 0;
1161 return ret;
1162}
1163
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001164void cache_unhash_dhcp(void)
1165{
Simon Kelley6b010842007-02-12 20:32:07 +00001166 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001167 int i;
1168
1169 for (i=0; i<hash_size; i++)
1170 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1171 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001172 {
1173 *up = cache->hash_next;
1174 cache->next = dhcp_spare;
1175 dhcp_spare = cache;
1176 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001177 else
1178 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001179}
1180
Simon Kelley611ebc52012-07-16 16:23:46 +01001181static void add_dhcp_cname(struct crec *target, time_t ttd)
1182{
1183 struct crec *aliasc;
1184 struct cname *a;
1185
1186 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001187 if (a->alias[1] != '*' &&
1188 hostname_isequal(cache_get_name(target), a->target))
Simon Kelley611ebc52012-07-16 16:23:46 +01001189 {
1190 if ((aliasc = dhcp_spare))
1191 dhcp_spare = dhcp_spare->next;
1192 else /* need new one */
1193 aliasc = whine_malloc(sizeof(struct crec));
1194
1195 if (aliasc)
1196 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001197 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001198 if (ttd == 0)
1199 aliasc->flags |= F_IMMORTAL;
1200 else
1201 aliasc->ttd = ttd;
1202 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001203 aliasc->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +01001204 aliasc->addr.cname.uid = target->uid;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001205 aliasc->uid = next_uid();
Simon Kelley611ebc52012-07-16 16:23:46 +01001206 cache_hash(aliasc);
1207 add_dhcp_cname(aliasc, ttd);
1208 }
1209 }
1210}
1211
Simon Kelley4cb1b322012-02-06 14:30:41 +00001212void cache_add_dhcp_entry(char *host_name, int prot,
1213 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001214{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001215 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001216 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001217 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001218 size_t addrlen = sizeof(struct in_addr);
1219
1220#ifdef HAVE_IPV6
1221 if (prot == AF_INET6)
1222 {
1223 flags = F_IPV6;
1224 addrlen = sizeof(struct in6_addr);
1225 }
1226#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001227
Simon Kelley12d71ed2012-08-30 15:16:41 +01001228 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1229
Simon Kelley4cb1b322012-02-06 14:30:41 +00001230 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001231 {
Simon Kelley824af852008-02-12 20:43:05 +00001232 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001233 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001234 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001235 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001236 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001237 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001238 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001239 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1240 in_hosts = 1;
1241 else
1242 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001243 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001244 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001245 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001246 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
Simon Kelley824af852008-02-12 20:43:05 +00001247 /* scan_free deletes all addresses associated with name */
1248 break;
1249 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001250 }
Simon Kelley824af852008-02-12 20:43:05 +00001251
Simon Kelley12d71ed2012-08-30 15:16:41 +01001252 /* if in hosts, don't need DHCP record */
1253 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001254 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001255
1256 /* Name in hosts, address doesn't match */
1257 if (fail_crec)
1258 {
1259 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1260 my_syslog(MS_DHCP | LOG_WARNING,
1261 _("not giving name %s to the DHCP lease of %s because "
1262 "the name exists in %s with address %s"),
1263 host_name, daemon->addrbuff,
1264 record_source(fail_crec->uid), daemon->namebuff);
1265 return;
1266 }
1267
1268 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1269 {
1270 if (crec->flags & F_NEG)
1271 {
1272 flags |= F_REVERSE;
1273 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1274 }
1275 }
1276 else
1277 flags |= F_REVERSE;
1278
1279 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001280 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001281 else /* need new one */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001282 crec = whine_malloc(sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001283
1284 if (crec) /* malloc may fail */
1285 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001286 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001287 if (ttd == 0)
1288 crec->flags |= F_IMMORTAL;
1289 else
1290 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001291 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001292 crec->name.namep = host_name;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001293 crec->uid = next_uid();
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001294 cache_hash(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001295
Simon Kelley611ebc52012-07-16 16:23:46 +01001296 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001297 }
1298}
Simon Kelley7622fc02009-06-04 20:32:05 +01001299#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001300
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001301#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001302int cache_make_stat(struct txt_record *t)
1303{
1304 static char *buff = NULL;
1305 static int bufflen = 60;
1306 int len;
1307 struct server *serv, *serv1;
1308 char *p;
1309
1310 if (!buff && !(buff = whine_malloc(60)))
1311 return 0;
1312
1313 p = buff;
1314
1315 switch (t->stat)
1316 {
1317 case TXT_STAT_CACHESIZE:
1318 sprintf(buff+1, "%d", daemon->cachesize);
1319 break;
1320
1321 case TXT_STAT_INSERTS:
1322 sprintf(buff+1, "%d", cache_inserted);
1323 break;
1324
1325 case TXT_STAT_EVICTIONS:
1326 sprintf(buff+1, "%d", cache_live_freed);
1327 break;
1328
1329 case TXT_STAT_MISSES:
1330 sprintf(buff+1, "%u", daemon->queries_forwarded);
1331 break;
1332
1333 case TXT_STAT_HITS:
1334 sprintf(buff+1, "%u", daemon->local_answer);
1335 break;
1336
1337#ifdef HAVE_AUTH
1338 case TXT_STAT_AUTH:
1339 sprintf(buff+1, "%u", daemon->auth_answer);
1340 break;
1341#endif
1342
1343 case TXT_STAT_SERVERS:
1344 /* sum counts from different records for same server */
1345 for (serv = daemon->servers; serv; serv = serv->next)
1346 serv->flags &= ~SERV_COUNTED;
1347
1348 for (serv = daemon->servers; serv; serv = serv->next)
1349 if (!(serv->flags &
1350 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1351 {
1352 char *new, *lenp;
1353 int port, newlen, bytes_avail, bytes_needed;
1354 unsigned int queries = 0, failed_queries = 0;
1355 for (serv1 = serv; serv1; serv1 = serv1->next)
1356 if (!(serv1->flags &
1357 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1358 sockaddr_isequal(&serv->addr, &serv1->addr))
1359 {
1360 serv1->flags |= SERV_COUNTED;
1361 queries += serv1->queries;
1362 failed_queries += serv1->failed_queries;
1363 }
1364 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1365 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001366 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001367 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1368 if (bytes_needed >= bytes_avail)
1369 {
1370 /* expand buffer if necessary */
1371 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1372 if (!(new = whine_malloc(newlen)))
1373 return 0;
1374 memcpy(new, buff, bufflen);
1375 free(buff);
1376 p = new + (p - buff);
1377 lenp = p - 1;
1378 buff = new;
1379 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001380 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001381 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1382 }
1383 *lenp = bytes_needed;
1384 p += bytes_needed;
1385 }
1386 t->txt = (unsigned char *)buff;
1387 t->len = p - buff;
1388 return 1;
1389 }
1390
1391 len = strlen(buff+1);
1392 t->txt = (unsigned char *)buff;
1393 t->len = len + 1;
1394 *buff = len;
1395 return 1;
1396}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001397#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001398
Simon Kelley394ff492015-03-29 22:17:14 +01001399/* There can be names in the cache containing control chars, don't
1400 mess up logging or open security holes. */
1401static char *sanitise(char *name)
1402{
1403 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001404 if (name)
1405 for (r = (unsigned char *)name; *r; r++)
1406 if (!isprint((int)*r))
1407 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001408
1409 return name;
1410}
1411
1412
Simon Kelley5aabfc72007-08-29 11:24:47 +01001413void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001414{
Simon Kelley824af852008-02-12 20:43:05 +00001415 struct server *serv, *serv1;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001416 char *t = "";
Simon Kelley824af852008-02-12 20:43:05 +00001417
1418 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1419 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1420 daemon->cachesize, cache_live_freed, cache_inserted);
1421 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1422 daemon->queries_forwarded, daemon->local_answer);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001423#ifdef HAVE_AUTH
1424 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
1425#endif
Simon Kelleyc2207682014-01-08 18:04:20 +00001426#ifdef HAVE_DNSSEC
1427 blockdata_report();
1428#endif
Simon Kelley824af852008-02-12 20:43:05 +00001429
Simon Kelley824af852008-02-12 20:43:05 +00001430 /* sum counts from different records for same server */
1431 for (serv = daemon->servers; serv; serv = serv->next)
1432 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001433
Simon Kelley824af852008-02-12 20:43:05 +00001434 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001435 if (!(serv->flags &
1436 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001437 {
1438 int port;
1439 unsigned int queries = 0, failed_queries = 0;
1440 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001441 if (!(serv1->flags &
1442 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1443 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001444 {
1445 serv1->flags |= SERV_COUNTED;
1446 queries += serv1->queries;
1447 failed_queries += serv1->failed_queries;
1448 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001449 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1450 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 +00001451 }
1452
Simon Kelley28866e92011-02-14 20:19:14 +00001453 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001454 {
1455 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001456 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001457 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001458
1459 for (i=0; i<hash_size; i++)
1460 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1461 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001462 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1463 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001464 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001465 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001466 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001467 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001468 a = sanitise(cache_get_cname_target(cache));
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001469#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001470 else if (cache->flags & F_DS)
1471 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001472 if (!(cache->flags & F_NEG))
Simon Kelleyb8eac192014-02-27 14:30:03 +00001473 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1474 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001475 }
1476 else if (cache->flags & F_DNSKEY)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001477 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1478 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001479#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001480 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001481 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001482 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001483 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001484 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001485#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001486 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001487 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001488#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001489 }
1490
Simon Kelleye7829ae2014-01-22 22:21:51 +00001491 if (cache->flags & F_IPV4)
1492 t = "4";
1493 else if (cache->flags & F_IPV6)
1494 t = "6";
1495 else if (cache->flags & F_CNAME)
1496 t = "C";
1497#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001498 else if (cache->flags & F_DS)
1499 t = "S";
1500 else if (cache->flags & F_DNSKEY)
1501 t = "K";
1502#endif
Simon Kelley32678042014-12-17 20:38:20 +00001503 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001504 cache->flags & F_FORWARD ? "F" : " ",
1505 cache->flags & F_REVERSE ? "R" : " ",
1506 cache->flags & F_IMMORTAL ? "I" : " ",
1507 cache->flags & F_DHCP ? "D" : " ",
1508 cache->flags & F_NEG ? "N" : " ",
1509 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001510 cache->flags & F_HOSTS ? "H" : " ",
1511 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001512#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001513 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001514#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001515 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1516 /* ctime includes trailing \n - eat it */
1517 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001518#endif
Rosen Penevcbd29e52017-06-27 22:29:51 +01001519 my_syslog(LOG_INFO, "%s", daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001520 }
1521 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001522}
1523
Simon Kelley19c51cf2014-03-18 22:38:30 +00001524char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001525{
Simon Kelley7622fc02009-06-04 20:32:05 +01001526 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001527
Simon Kelley19c51cf2014-03-18 22:38:30 +00001528 if (index == SRC_CONFIG)
1529 return "config";
1530 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001531 return HOSTSFILE;
1532
1533 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1534 if (ah->index == index)
1535 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001536
1537#ifdef HAVE_INOTIFY
1538 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1539 if (ah->index == index)
1540 return ah->fname;
1541#endif
1542
Simon Kelley7622fc02009-06-04 20:32:05 +01001543 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001544}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001545
Simon Kelley610e7822014-02-06 14:45:17 +00001546char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001547{
1548 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001549 int len = 10; /* strlen("type=xxxxx") */
1550 const char *types = NULL;
1551 static char *buff = NULL;
1552 static int bufflen = 0;
1553
Simon Kelley1a6bca82008-07-11 11:11:42 +01001554 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1555 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001556 {
1557 types = typestr[i].name;
1558 len = strlen(types);
1559 break;
1560 }
1561
1562 len += 3; /* braces, terminator */
1563 len += strlen(desc);
1564
1565 if (!buff || bufflen < len)
1566 {
1567 if (buff)
1568 free(buff);
1569 else if (len < 20)
1570 len = 20;
1571
1572 buff = whine_malloc(len);
1573 bufflen = len;
1574 }
1575
1576 if (buff)
1577 {
1578 if (types)
1579 sprintf(buff, "%s[%s]", desc, types);
1580 else
1581 sprintf(buff, "%s[type=%d]", desc, type);
1582 }
1583
1584 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001585}
1586
Simon Kelley28866e92011-02-14 20:19:14 +00001587void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001588{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001589 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001590 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001591
Simon Kelley28866e92011-02-14 20:19:14 +00001592 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001593 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001594
Simon Kelley394ff492015-03-29 22:17:14 +01001595 name = sanitise(name);
1596
Simon Kelley5aabfc72007-08-29 11:24:47 +01001597 if (addr)
1598 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001599 if (flags & F_KEYTAG)
Simon Kelley15379ea2015-12-21 18:31:55 +00001600 sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001601 else
1602 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001603#ifdef HAVE_IPV6
Simon Kelley0fc2f312014-01-08 10:26:58 +00001604 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1605 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001606#else
Simon Kelley0fc2f312014-01-08 10:26:58 +00001607 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001608#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001609 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001610 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001611 else
1612 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001613
1614 if (flags & F_REVERSE)
1615 {
1616 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001617 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001618 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001619
1620 if (flags & F_NEG)
1621 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001622 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001623 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001624 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001625 {
1626 if (flags & F_IPV4)
1627 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001628 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001629 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001630 else
1631 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001632 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001633 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001634 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001635 dest = "<CNAME>";
1636 else if (flags & F_RRNAME)
1637 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001638
Simon Kelley1f15b812009-10-13 17:49:32 +01001639 if (flags & F_CONFIG)
1640 source = "config";
1641 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001642 source = "DHCP";
1643 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001644 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001645 else if (flags & F_UPSTREAM)
1646 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001647 else if (flags & F_SECSTAT)
1648 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001649 else if (flags & F_AUTH)
1650 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001651 else if (flags & F_SERVER)
1652 {
1653 source = "forwarded";
1654 verb = "to";
1655 }
1656 else if (flags & F_QUERY)
1657 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001658 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001659 verb = "from";
1660 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001661 else if (flags & F_DNSSEC)
1662 {
1663 source = arg;
1664 verb = "to";
1665 }
Wang Jian49752b92014-03-28 20:52:47 +00001666 else if (flags & F_IPSET)
1667 {
1668 source = "ipset add";
1669 dest = name;
1670 name = arg;
1671 verb = daemon->addrbuff;
1672 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001673 else
1674 source = "cached";
1675
Simon Kelley3d8df262005-08-29 12:19:27 +01001676 if (strlen(name) == 0)
1677 name = ".";
1678
Simon Kelley25cf5e32015-01-09 15:53:03 +00001679 if (option_bool(OPT_EXTRALOG))
1680 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001681 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001682 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001683 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001684 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001685 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 +00001686 }
1687 else
1688 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001689}
1690
Simon Kelley98c098b2014-01-08 17:31:16 +00001691