blob: bf585fe0ce0249cfc4c7bcda434eeb15965362c8 [file] [log] [blame]
Simon Kelley50ca8552017-06-24 22:36:43 +01001/* dnsmasq is Copyright (c) 2000-2017 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" },
48 { 33, "SRV" },
Simon Kelley1a6bca82008-07-11 11:11:42 +010049 { 35, "NAPTR" },
Simon Kelley16972692006-10-16 20:04:18 +010050 { 36, "KX" },
51 { 37, "CERT" },
52 { 38, "A6" },
53 { 39, "DNAME" },
54 { 41, "OPT" },
Simon Kelley0fc2f312014-01-08 10:26:58 +000055 { 43, "DS" },
56 { 46, "RRSIG" },
Simon Kelley610e7822014-02-06 14:45:17 +000057 { 47, "NSEC" },
Simon Kelley832af0b2007-01-21 20:01:28 +000058 { 48, "DNSKEY" },
Simon Kelley610e7822014-02-06 14:45:17 +000059 { 50, "NSEC3" },
Simon Kelley832af0b2007-01-21 20:01:28 +000060 { 249, "TKEY" },
Simon Kelley16972692006-10-16 20:04:18 +010061 { 250, "TSIG" },
62 { 251, "IXFR" },
63 { 252, "AXFR" },
64 { 253, "MAILB" },
65 { 254, "MAILA" },
66 { 255, "ANY" }
67};
68
Simon Kelley9e4abcb2004-01-22 19:47:41 +000069static void cache_free(struct crec *crecp);
70static void cache_unlink(struct crec *crecp);
71static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010072static void rehash(int size);
73static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000074
Simon Kelley3f7483e2014-03-16 22:56:58 +000075static unsigned int next_uid(void)
76{
Andyd5082152014-03-17 19:50:29 +000077 static unsigned int uid = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +000078
Andyd5082152014-03-17 19:50:29 +000079 uid++;
80
Simon Kelley3f7483e2014-03-16 22:56:58 +000081 /* uid == 0 used to indicate CNAME to interface name. */
Simon Kelley19c51cf2014-03-18 22:38:30 +000082 if (uid == SRC_INTERFACE)
Simon Kelley3f7483e2014-03-16 22:56:58 +000083 uid++;
84
Andyd5082152014-03-17 19:50:29 +000085 return uid;
Simon Kelley3f7483e2014-03-16 22:56:58 +000086}
87
Simon Kelley5aabfc72007-08-29 11:24:47 +010088void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000089{
90 struct crec *crecp;
91 int i;
Simon Kelleyd56a6042013-10-11 14:39:03 +010092
Simon Kelley5aabfc72007-08-29 11:24:47 +010093 bignames_left = daemon->cachesize/10;
94
95 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000096 {
Simon Kelley5aabfc72007-08-29 11:24:47 +010097 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +000098
Simon Kelley5aabfc72007-08-29 11:24:47 +010099 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000100 {
101 cache_link(crecp);
102 crecp->flags = 0;
Simon Kelley3f7483e2014-03-16 22:56:58 +0000103 crecp->uid = next_uid();
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000104 }
105 }
106
Simon Kelley4011c4e2006-10-28 16:26:19 +0100107 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +0100108 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000109}
110
Simon Kelley4011c4e2006-10-28 16:26:19 +0100111/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
112 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
113 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
114 expand the table. */
115static void rehash(int size)
116{
117 struct crec **new, **old, *p, *tmp;
118 int i, new_size, old_size;
119
120 /* hash_size is a power of two. */
121 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
122
123 /* must succeed in getting first instance, failure later is non-fatal */
124 if (!hash_table)
125 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100126 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100127 return;
128
129 for(i = 0; i < new_size; i++)
130 new[i] = NULL;
131
132 old = hash_table;
133 old_size = hash_size;
134 hash_table = new;
135 hash_size = new_size;
136
137 if (old)
138 {
139 for (i = 0; i < old_size; i++)
140 for (p = old[i]; p ; p = tmp)
141 {
142 tmp = p->hash_next;
143 cache_hash(p);
144 }
145 free(old);
146 }
147}
148
Simon Kelley3d8df262005-08-29 12:19:27 +0100149static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000150{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100151 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100152 const unsigned char *mix_tab = (const unsigned char*)typestr;
153
Simon Kelley3d8df262005-08-29 12:19:27 +0100154 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100155 {
156 /* don't use tolower and friends here - they may be messed up by LOCALE */
157 if (c >= 'A' && c <= 'Z')
158 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100159 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100160 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000161
162 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100163 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000164}
165
166static void cache_hash(struct crec *crecp)
167{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000168 /* maintain an invariant that all entries with F_REVERSE set
169 are at the start of the hash-chain and all non-reverse
170 immortal entries are at the end of the hash-chain.
171 This allows reverse searches and garbage collection to be optimised */
172
173 struct crec **up = hash_bucket(cache_get_name(crecp));
174
175 if (!(crecp->flags & F_REVERSE))
176 {
177 while (*up && ((*up)->flags & F_REVERSE))
178 up = &((*up)->hash_next);
179
180 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000181 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000182 up = &((*up)->hash_next);
183 }
184 crecp->hash_next = *up;
185 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000186}
Simon Kelley82e3f452014-01-31 21:05:48 +0000187
188#ifdef HAVE_DNSSEC
189static void cache_blockdata_free(struct crec *crecp)
190{
191 if (crecp->flags & F_DNSKEY)
Simon Kelley93be5b12015-12-15 12:04:40 +0000192 blockdata_free(crecp->addr.key.keydata);
Simon Kelleye3f14552014-03-01 17:58:28 +0000193 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
Simon Kelley82e3f452014-01-31 21:05:48 +0000194 blockdata_free(crecp->addr.ds.keydata);
195}
196#endif
197
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000198static void cache_free(struct crec *crecp)
199{
200 crecp->flags &= ~F_FORWARD;
201 crecp->flags &= ~F_REVERSE;
Simon Kelley3f7483e2014-03-16 22:56:58 +0000202 crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100203
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000204 if (cache_tail)
205 cache_tail->next = crecp;
206 else
207 cache_head = crecp;
208 crecp->prev = cache_tail;
209 crecp->next = NULL;
210 cache_tail = crecp;
211
212 /* retrieve big name for further use. */
213 if (crecp->flags & F_BIGNAME)
214 {
215 crecp->name.bname->next = big_free;
216 big_free = crecp->name.bname;
217 crecp->flags &= ~F_BIGNAME;
218 }
Simon Kelley072e81b2014-01-31 12:42:54 +0000219
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100220#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +0000221 cache_blockdata_free(crecp);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100222#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000223}
224
225/* insert a new cache entry at the head of the list (youngest entry) */
226static void cache_link(struct crec *crecp)
227{
228 if (cache_head) /* check needed for init code */
229 cache_head->prev = crecp;
230 crecp->next = cache_head;
231 crecp->prev = NULL;
232 cache_head = crecp;
233 if (!cache_tail)
234 cache_tail = crecp;
235}
236
237/* remove an arbitrary cache entry for promotion */
238static void cache_unlink (struct crec *crecp)
239{
240 if (crecp->prev)
241 crecp->prev->next = crecp->next;
242 else
243 cache_head = crecp->next;
244
245 if (crecp->next)
246 crecp->next->prev = crecp->prev;
247 else
248 cache_tail = crecp->prev;
249}
250
251char *cache_get_name(struct crec *crecp)
252{
253 if (crecp->flags & F_BIGNAME)
254 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000255 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000256 return crecp->name.namep;
257
258 return crecp->name.sname;
259}
260
Simon Kelleyd56a6042013-10-11 14:39:03 +0100261char *cache_get_cname_target(struct crec *crecp)
262{
Simon Kelley19c51cf2014-03-18 22:38:30 +0000263 if (crecp->addr.cname.uid != SRC_INTERFACE)
Simon Kelleyd56a6042013-10-11 14:39:03 +0100264 return cache_get_name(crecp->addr.cname.target.cache);
265
266 return crecp->addr.cname.target.int_name->name;
267}
268
269
270
Simon Kelleyb75e9362012-12-07 11:50:41 +0000271struct crec *cache_enumerate(int init)
272{
273 static int bucket;
274 static struct crec *cache;
275
276 if (init)
277 {
278 bucket = 0;
279 cache = NULL;
280 }
281 else if (cache && cache->hash_next)
282 cache = cache->hash_next;
283 else
284 {
285 cache = NULL;
286 while (bucket < hash_size)
287 if ((cache = hash_table[bucket++]))
288 break;
289 }
290
291 return cache;
292}
293
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100294static int is_outdated_cname_pointer(struct crec *crecp)
295{
Andy3e21a1a2014-03-22 19:10:07 +0000296 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100297 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100298
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100299 /* NB. record may be reused as DS or DNSKEY, where uid is
300 overloaded for something completely different */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100301 if (crecp->addr.cname.target.cache &&
302 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
303 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100304 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100305
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100306 return 1;
307}
308
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000309static int is_expired(time_t now, struct crec *crecp)
310{
311 if (crecp->flags & F_IMMORTAL)
312 return 0;
313
314 if (difftime(now, crecp->ttd) < 0)
315 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100316
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000317 return 1;
318}
319
Simon Kelleycbc65242014-12-21 21:21:53 +0000320static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000321{
322 /* Scan and remove old entries.
323 If (flags & F_FORWARD) then remove any forward entries for name and any expired
324 entries but only in the same hash bucket as name.
325 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
326 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000327 If (flags == 0) remove any expired entries in the whole cache.
328
Simon Kelleycbc65242014-12-21 21:21:53 +0000329 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
330 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 +0000331
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000332 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
333 so that when we hit an entry which isn't reverse and is immortal, we're done. */
334
335 struct crec *crecp, **up;
336
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000337 if (flags & F_FORWARD)
338 {
Simon Kelley6b010842007-02-12 20:32:07 +0000339 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000340 {
341 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
342 {
343 *up = crecp->hash_next;
344 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
345 {
346 cache_unlink(crecp);
347 cache_free(crecp);
348 }
349 continue;
350 }
351
352 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
353 {
Simon Kelleye7829ae2014-01-22 22:21:51 +0000354 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
355 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
Simon Kelley6429e422014-01-23 12:09:36 +0000356 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000357 {
358 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelleycbc65242014-12-21 21:21:53 +0000359 return crecp;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000360 *up = crecp->hash_next;
361 cache_unlink(crecp);
362 cache_free(crecp);
363 continue;
364 }
365
366#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000367 /* Deletion has to be class-sensitive for DS and DNSKEY */
368 if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000369 {
Simon Kelley824202e2014-01-23 20:59:46 +0000370 if (crecp->flags & F_CONFIG)
Simon Kelleycbc65242014-12-21 21:21:53 +0000371 return crecp;
Simon Kelley824202e2014-01-23 20:59:46 +0000372 *up = crecp->hash_next;
373 cache_unlink(crecp);
374 cache_free(crecp);
375 continue;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000376 }
377#endif
378 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000379 up = &crecp->hash_next;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000380 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000381 }
382 else
383 {
384 int i;
385#ifdef HAVE_IPV6
386 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
387#else
388 int addrlen = INADDRSZ;
389#endif
390 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000391 for (crecp = hash_table[i], up = &hash_table[i];
392 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
393 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000394 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000395 {
396 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000397 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000398 {
399 cache_unlink(crecp);
400 cache_free(crecp);
401 }
402 }
Simon Kelley25439062013-11-25 21:14:51 +0000403 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000404 (flags & crecp->flags & F_REVERSE) &&
405 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
406 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
407 {
408 *up = crecp->hash_next;
409 cache_unlink(crecp);
410 cache_free(crecp);
411 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000412 else
413 up = &crecp->hash_next;
414 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000415
Simon Kelleycbc65242014-12-21 21:21:53 +0000416 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000417}
418
419/* Note: The normal calling sequence is
420 cache_start_insert
421 cache_insert * n
422 cache_end_insert
423
424 but an abort can cause the cache_end_insert to be missed
425 in which can the next cache_start_insert cleans things up. */
426
427void cache_start_insert(void)
428{
429 /* Free any entries which didn't get committed during the last
430 insert due to error.
431 */
432 while (new_chain)
433 {
434 struct crec *tmp = new_chain->next;
435 cache_free(new_chain);
436 new_chain = tmp;
437 }
438 new_chain = NULL;
439 insert_error = 0;
440}
441
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100442struct crec *cache_insert(char *name, struct all_addr *addr,
443 time_t now, unsigned long ttl, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000444{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000445 struct crec *new;
446 union bigname *big_name = NULL;
447 int freed_all = flags & F_REVERSE;
Simon Kelley9e038942008-05-30 20:06:34 +0100448 int free_avail = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000449
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000450 /* Don't log DNSSEC records here, done elsewhere */
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000451 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000452 {
453 log_query(flags | F_UPSTREAM, name, addr, NULL);
RinSatsuki28de3872015-01-10 15:22:21 +0000454 /* Don't mess with TTL for DNSSEC records. */
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000455 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
456 ttl = daemon->max_cache_ttl;
RinSatsuki28de3872015-01-10 15:22:21 +0000457 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
458 ttl = daemon->min_cache_ttl;
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000459 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000460
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000461 /* if previous insertion failed give up now. */
462 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100463 return NULL;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000464
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000465 /* First remove any expired entries and entries for the name/address we
Simon Kelleycbc65242014-12-21 21:21:53 +0000466 are currently inserting. */
467 if ((new = cache_scan_free(name, addr, now, flags)))
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000468 {
Simon Kelleycbc65242014-12-21 21:21:53 +0000469 /* We're trying to insert a record over one from
470 /etc/hosts or DHCP, or other config. If the
471 existing record is for an A or AAAA and
472 the record we're trying to insert is the same,
473 just drop the insert, but don't error the whole process. */
Edwin Török41a8d9e2015-11-14 17:45:48 +0000474 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
Simon Kelleycbc65242014-12-21 21:21:53 +0000475 {
476 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
477 new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
478 return new;
479#ifdef HAVE_IPV6
480 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
481 IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
482 return new;
483#endif
484 }
485
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000486 insert_error = 1;
487 return NULL;
488 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000489
490 /* Now get a cache entry from the end of the LRU list */
491 while (1) {
492 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
493 {
494 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100495 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000496 }
497
498 /* End of LRU list is still in use: if we didn't scan all the hash
499 chains for expired entries do that now. If we already tried that
500 then it's time to start spilling things. */
501
502 if (new->flags & (F_FORWARD | F_REVERSE))
503 {
Simon Kelley9e038942008-05-30 20:06:34 +0100504 /* If free_avail set, we believe that an entry has been freed.
505 Bugs have been known to make this not true, resulting in
Simon Kelley1a6bca82008-07-11 11:11:42 +0100506 a tight loop here. If that happens, abandon the
Simon Kelley9e038942008-05-30 20:06:34 +0100507 insert. Once in this state, all inserts will probably fail. */
Simon Kelley9e038942008-05-30 20:06:34 +0100508 if (free_avail)
509 {
Simon Kelley5f938532014-02-03 16:44:32 +0000510 static int warned = 0;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000511 if (!warned)
512 {
513 my_syslog(LOG_ERR, _("Internal error in cache."));
514 warned = 1;
515 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100516 insert_error = 1;
Simon Kelley9e038942008-05-30 20:06:34 +0100517 return NULL;
518 }
519
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000520 if (freed_all)
521 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000522 struct all_addr free_addr = new->addr.addr;;
523
524#ifdef HAVE_DNSSEC
Simon Kelley93be5b12015-12-15 12:04:40 +0000525 /* For DNSSEC records, addr holds class. */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000526 if (new->flags & (F_DS | F_DNSKEY))
Simon Kelley93be5b12015-12-15 12:04:40 +0000527 free_addr.addr.dnssec.class = new->uid;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000528#endif
529
Simon Kelley9e038942008-05-30 20:06:34 +0100530 free_avail = 1; /* Must be free space now. */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000531 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000532 cache_live_freed++;
533 }
534 else
535 {
536 cache_scan_free(NULL, NULL, now, 0);
537 freed_all = 1;
538 }
539 continue;
540 }
541
542 /* Check if we need to and can allocate extra memory for a long name.
Simon Kelley8d718cb2014-02-03 16:27:37 +0000543 If that fails, give up now, always succeed for DNSSEC records. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000544 if (name && (strlen(name) > SMALLDNAME-1))
545 {
546 if (big_free)
547 {
548 big_name = big_free;
549 big_free = big_free->next;
550 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000551 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100552 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000553 {
554 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100555 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000556 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000557 else if (bignames_left != 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000558 bignames_left--;
559
560 }
561
562 /* Got the rest: finally grab entry. */
563 cache_unlink(new);
564 break;
565 }
566
567 new->flags = flags;
568 if (big_name)
569 {
570 new->name.bname = big_name;
571 new->flags |= F_BIGNAME;
572 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100573
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000574 if (name)
575 strcpy(cache_get_name(new), name);
576 else
577 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100578
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000579 if (addr)
Simon Kelleyb8eac192014-02-27 14:30:03 +0000580 {
581#ifdef HAVE_DNSSEC
582 if (flags & (F_DS | F_DNSKEY))
583 new->uid = addr->addr.dnssec.class;
584 else
585#endif
586 new->addr.addr = *addr;
587 }
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100588
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000589 new->ttd = now + (time_t)ttl;
590 new->next = new_chain;
591 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100592
593 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000594}
595
596/* after end of insertion, commit the new entries */
597void cache_end_insert(void)
598{
599 if (insert_error)
600 return;
601
602 while (new_chain)
603 {
604 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100605 /* drop CNAMEs which didn't find a target. */
606 if (is_outdated_cname_pointer(new_chain))
607 cache_free(new_chain);
608 else
609 {
610 cache_hash(new_chain);
611 cache_link(new_chain);
612 cache_inserted++;
613 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000614 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000615 }
616 new_chain = NULL;
617}
618
Simon Kelley12fae492014-02-04 22:03:06 +0000619struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000620{
621 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000622 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000623
Simon Kelley12fae492014-02-04 22:03:06 +0000624 prot &= ~F_NO_RR;
625
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000626 if (crecp) /* iterating */
627 ans = crecp->next;
628 else
629 {
630 /* first search, look for relevant entries and push to top of list
631 also free anything which has expired */
632 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley28866e92011-02-14 20:19:14 +0000633 unsigned short ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000634
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000635 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
636 {
637 next = crecp->hash_next;
638
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000639 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000640 {
641 if ((crecp->flags & F_FORWARD) &&
642 (crecp->flags & prot) &&
643 hostname_isequal(cache_get_name(crecp), name))
644 {
Simon Kelley25439062013-11-25 21:14:51 +0000645 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000646 {
647 *chainp = crecp;
648 chainp = &crecp->next;
649 }
650 else
651 {
652 cache_unlink(crecp);
653 cache_link(crecp);
654 }
655
Simon Kelley824af852008-02-12 20:43:05 +0000656 /* Move all but the first entry up the hash chain
657 this implements round-robin.
658 Make sure that re-ordering doesn't break the hash-chain
659 order invariants.
660 */
Simon Kelley9e038942008-05-30 20:06:34 +0100661 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000662 {
663 *up = crecp->hash_next;
664 crecp->hash_next = *insert;
665 *insert = crecp;
666 insert = &crecp->hash_next;
667 }
Simon Kelley9e038942008-05-30 20:06:34 +0100668 else
669 {
Simon Kelley12fae492014-02-04 22:03:06 +0000670 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100671 {
672 insert = up;
673 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
674 }
675 up = &crecp->hash_next;
676 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000677 }
678 else
679 /* case : not expired, incorrect entry. */
680 up = &crecp->hash_next;
681 }
682 else
683 {
684 /* expired entry, free it */
685 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000686 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000687 {
688 cache_unlink(crecp);
689 cache_free(crecp);
690 }
691 }
692 }
693
694 *chainp = cache_head;
695 }
696
697 if (ans &&
698 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000699 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000700 hostname_isequal(cache_get_name(ans), name))
701 return ans;
702
703 return NULL;
704}
705
706struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000707 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000708{
709 struct crec *ans;
710#ifdef HAVE_IPV6
711 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
712#else
713 int addrlen = INADDRSZ;
714#endif
715
716 if (crecp) /* iterating */
717 ans = crecp->next;
718 else
719 {
720 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000721 also free anything which has expired. All the reverse entries are at the
722 start of the hash chain, so we can give up when we find the first
723 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000724 int i;
725 struct crec **up, **chainp = &ans;
726
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000727 for (i=0; i<hash_size; i++)
728 for (crecp = hash_table[i], up = &hash_table[i];
729 crecp && (crecp->flags & F_REVERSE);
730 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000731 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000732 {
Simon Kelley6b010842007-02-12 20:32:07 +0000733 if ((crecp->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100734 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000735 {
Simon Kelley25439062013-11-25 21:14:51 +0000736 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000737 {
738 *chainp = crecp;
739 chainp = &crecp->next;
740 }
741 else
742 {
743 cache_unlink(crecp);
744 cache_link(crecp);
745 }
746 }
747 up = &crecp->hash_next;
748 }
749 else
750 {
751 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000752 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000753 {
754 cache_unlink(crecp);
755 cache_free(crecp);
756 }
757 }
758
759 *chainp = cache_head;
760 }
761
762 if (ans &&
763 (ans->flags & F_REVERSE) &&
764 (ans->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100765 memcmp(&ans->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000766 return ans;
767
768 return NULL;
769}
770
Simon Kelley611ebc52012-07-16 16:23:46 +0100771static void add_hosts_cname(struct crec *target)
772{
773 struct crec *crec;
774 struct cname *a;
775
776 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +0000777 if (a->alias[1] != '*' &&
778 hostname_isequal(cache_get_name(target), a->target) &&
Simon Kelley611ebc52012-07-16 16:23:46 +0100779 (crec = whine_malloc(sizeof(struct crec))))
780 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000781 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000782 crec->ttd = a->ttl;
Simon Kelley611ebc52012-07-16 16:23:46 +0100783 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100784 crec->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +0100785 crec->addr.cname.uid = target->uid;
Simon Kelley19c51cf2014-03-18 22:38:30 +0000786 crec->uid = next_uid();
Simon Kelley611ebc52012-07-16 16:23:46 +0100787 cache_hash(crec);
788 add_hosts_cname(crec); /* handle chains */
789 }
790}
791
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100792static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000793 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000794{
Simon Kelleye759d422012-03-16 13:18:57 +0000795 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 +0000796 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000797 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000798
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000799 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000800 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000801 {
Simon Kelley9009d742008-11-14 20:04:27 +0000802 nameexists = 1;
803 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
804 {
805 free(cache);
806 return;
807 }
808 }
809
810 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000811 We do this by steam here, The entries are kept in hash chains, linked
812 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000813 the array rhash, hashed on address. Note that rhash and the values
814 in ->next are only valid whilst reading hosts files: the buckets are
815 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000816
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000817 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000818
819 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +0000820 large (10000 entry) hosts files.
821
822 Note that we only do this process when bulk-reading hosts files,
823 for incremental reads, rhash is NULL, and we use cache lookups
824 instead.
825 */
Simon Kelley9009d742008-11-14 20:04:27 +0000826
Simon Kelley70d18732015-01-31 19:59:29 +0000827 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +0000828 {
Simon Kelley70d18732015-01-31 19:59:29 +0000829 /* hash address */
830 for (j = 0, i = 0; i < addrlen; i++)
831 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
832
833 for (lookup = rhash[j]; lookup; lookup = lookup->next)
834 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
835 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
836 {
837 cache->flags &= ~F_REVERSE;
838 break;
839 }
840
841 /* maintain address hash chain, insert new unique address */
842 if (!lookup)
843 {
844 cache->next = rhash[j];
845 rhash[j] = cache;
846 }
Simon Kelley915363f2012-01-11 22:00:48 +0000847 }
Simon Kelley70d18732015-01-31 19:59:29 +0000848 else
849 {
850 /* incremental read, lookup in cache */
851 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
852 if (lookup && lookup->flags & F_HOSTS)
853 cache->flags &= ~F_REVERSE;
854 }
855
Simon Kelley9009d742008-11-14 20:04:27 +0000856 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000857 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000858 cache_hash(cache);
859
860 /* don't need to do alias stuff for second and subsequent addresses. */
861 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100862 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000863}
864
865static int eatspace(FILE *f)
866{
867 int c, nl = 0;
868
869 while (1)
870 {
871 if ((c = getc(f)) == '#')
872 while (c != '\n' && c != EOF)
873 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000874
Simon Kelley9009d742008-11-14 20:04:27 +0000875 if (c == EOF)
876 return 1;
877
878 if (!isspace(c))
879 {
880 ungetc(c, f);
881 return nl;
882 }
883
884 if (c == '\n')
885 nl = 1;
886 }
887}
888
889static int gettok(FILE *f, char *token)
890{
891 int c, count = 0;
892
893 while (1)
894 {
895 if ((c = getc(f)) == EOF)
896 return (count == 0) ? EOF : 1;
897
898 if (isspace(c) || c == '#')
899 {
900 ungetc(c, f);
901 return eatspace(f);
902 }
903
904 if (count < (MAXDNAME - 1))
905 {
906 token[count++] = c;
907 token[count] = 0;
908 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000909 }
910}
911
Simon Kelley70d18732015-01-31 19:59:29 +0000912int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000913{
914 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000915 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100916 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000917 unsigned short flags = 0;
918 struct all_addr addr;
919 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100920
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000921 if (!f)
922 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100923 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
André Glüpkereddf3652016-01-12 12:54:17 +0000924 return cache_size;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000925 }
Simon Kelley9009d742008-11-14 20:04:27 +0000926
927 eatspace(f);
928
929 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000930 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000931 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000932
Simon Kelley3d8df262005-08-29 12:19:27 +0100933 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000934 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000935 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000937 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000938 }
Simon Kelleye759d422012-03-16 13:18:57 +0000939#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100940 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000941 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000942 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000943 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000944 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000945 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000946#endif
947 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000948 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100949 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +0000950 while (atnl == 0)
951 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000952 continue;
953 }
Simon Kelley9009d742008-11-14 20:04:27 +0000954
Simon Kelley9009d742008-11-14 20:04:27 +0000955 addr_count++;
956
957 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +0000958 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +0000959 {
960 rehash(name_count);
961 cache_size = name_count;
962 }
963
964 while (atnl == 0)
965 {
966 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +0100967 int fqdn, nomem;
968 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +0000969
970 if ((atnl = gettok(f, token)) == EOF)
971 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000972
Simon Kelley9009d742008-11-14 20:04:27 +0000973 fqdn = !!strchr(token, '.');
974
Simon Kelley1f15b812009-10-13 17:49:32 +0100975 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +0000976 {
977 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +0000978 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley9009d742008-11-14 20:04:27 +0000979 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +0100980 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000981 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100982 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +0000983 strcat(cache->name.sname, ".");
984 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +0000985 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000986 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +0000987 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000988 name_count++;
989 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100990 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000991 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100992 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +0000993 cache->flags = flags;
Simon Kelleydf3d54f2016-02-24 21:03:38 +0000994 cache->ttd = daemon->local_ttl;
Simon Kelleye759d422012-03-16 13:18:57 +0000995 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000996 name_count++;
997 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100998 free(canon);
999
Simon Kelley9009d742008-11-14 20:04:27 +00001000 }
Simon Kelley1f15b812009-10-13 17:49:32 +01001001 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +00001002 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1003 }
1004 }
1005
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001006 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001007
Simon Kelley70d18732015-01-31 19:59:29 +00001008 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001009 rehash(name_count);
1010
1011 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1012
Simon Kelley4011c4e2006-10-28 16:26:19 +01001013 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001014}
1015
Simon Kelley7622fc02009-06-04 20:32:05 +01001016void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001017{
1018 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001019 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001020 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001021 struct host_record *hr;
1022 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001023 struct cname *a;
1024 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001025#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001026 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001027#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001028
Simon Kelley59353a62004-11-21 19:34:28 +00001029 cache_inserted = cache_live_freed = 0;
1030
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001031 for (i=0; i<hash_size; i++)
1032 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1033 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001034#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +00001035 cache_blockdata_free(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001036#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001037 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001038 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001039 {
1040 *up = cache->hash_next;
1041 free(cache);
1042 }
1043 else if (!(cache->flags & F_DHCP))
1044 {
1045 *up = cache->hash_next;
1046 if (cache->flags & F_BIGNAME)
1047 {
1048 cache->name.bname->next = big_free;
1049 big_free = cache->name.bname;
1050 }
1051 cache->flags = 0;
1052 }
1053 else
1054 up = &cache->hash_next;
1055 }
1056
Simon Kelleyd56a6042013-10-11 14:39:03 +01001057 /* Add CNAMEs to interface_names to the cache */
1058 for (a = daemon->cnames; a; a = a->next)
1059 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001060 if (a->alias[1] != '*' &&
1061 hostname_isequal(a->target, intr->name) &&
Simon Kelley532066e2013-11-26 10:14:47 +00001062 ((cache = whine_malloc(sizeof(struct crec)))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001063 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001064 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001065 cache->ttd = a->ttl;
Simon Kelley532066e2013-11-26 10:14:47 +00001066 cache->name.namep = a->alias;
1067 cache->addr.cname.target.int_name = intr;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001068 cache->addr.cname.uid = SRC_INTERFACE;
1069 cache->uid = next_uid();
Simon Kelley532066e2013-11-26 10:14:47 +00001070 cache_hash(cache);
1071 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001072 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001073
1074#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001075 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001076 if ((cache = whine_malloc(sizeof(struct crec))) &&
Simon Kelleyee415862014-02-11 11:07:22 +00001077 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001078 {
Simon Kelleyee415862014-02-11 11:07:22 +00001079 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001080 cache->ttd = daemon->local_ttl;
Simon Kelleyee415862014-02-11 11:07:22 +00001081 cache->name.namep = ds->name;
1082 cache->addr.ds.keylen = ds->digestlen;
1083 cache->addr.ds.algo = ds->algo;
1084 cache->addr.ds.keytag = ds->keytag;
1085 cache->addr.ds.digest = ds->digest_type;
1086 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001087 cache_hash(cache);
1088 }
1089#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001090
Simon Kelleye759d422012-03-16 13:18:57 +00001091 /* borrow the packet buffer for a temporary by-address hash */
1092 memset(daemon->packet, 0, daemon->packet_buff_sz);
1093 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1094 /* we overwrote the buffer... */
1095 daemon->srv_save = NULL;
1096
1097 /* Do host_records in config. */
1098 for (hr = daemon->host_records; hr; hr = hr->next)
1099 for (nl = hr->names; nl; nl = nl->next)
1100 {
1101 if (hr->addr.s_addr != 0 &&
1102 (cache = whine_malloc(sizeof(struct crec))))
1103 {
1104 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001105 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001106 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001107 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001108 }
1109#ifdef HAVE_IPV6
1110 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1111 (cache = whine_malloc(sizeof(struct crec))))
1112 {
1113 cache->name.namep = nl->name;
Simon Kelleydf3d54f2016-02-24 21:03:38 +00001114 cache->ttd = hr->ttl;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001115 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001116 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001117 }
1118#endif
1119 }
1120
Simon Kelley28866e92011-02-14 20:19:14 +00001121 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001122 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001123 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001124 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001125 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001126 else
1127 {
1128 if (!option_bool(OPT_NO_HOSTS))
1129 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1130
1131 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1132 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1133 if (!(ah->flags & AH_INACTIVE))
1134 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1135 }
1136
Simon Kelley70d18732015-01-31 19:59:29 +00001137#ifdef HAVE_INOTIFY
1138 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1139#endif
1140
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001141}
1142
Simon Kelley7622fc02009-06-04 20:32:05 +01001143#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001144struct in_addr a_record_from_hosts(char *name, time_t now)
1145{
1146 struct crec *crecp = NULL;
1147 struct in_addr ret;
1148
1149 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1150 if (crecp->flags & F_HOSTS)
1151 return *(struct in_addr *)&crecp->addr;
1152
1153 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1154
1155 ret.s_addr = 0;
1156 return ret;
1157}
1158
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001159void cache_unhash_dhcp(void)
1160{
Simon Kelley6b010842007-02-12 20:32:07 +00001161 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001162 int i;
1163
1164 for (i=0; i<hash_size; i++)
1165 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1166 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001167 {
1168 *up = cache->hash_next;
1169 cache->next = dhcp_spare;
1170 dhcp_spare = cache;
1171 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001172 else
1173 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001174}
1175
Simon Kelley611ebc52012-07-16 16:23:46 +01001176static void add_dhcp_cname(struct crec *target, time_t ttd)
1177{
1178 struct crec *aliasc;
1179 struct cname *a;
1180
1181 for (a = daemon->cnames; a; a = a->next)
Simon Kelleyb637d782016-12-13 16:44:11 +00001182 if (a->alias[1] != '*' &&
1183 hostname_isequal(cache_get_name(target), a->target))
Simon Kelley611ebc52012-07-16 16:23:46 +01001184 {
1185 if ((aliasc = dhcp_spare))
1186 dhcp_spare = dhcp_spare->next;
1187 else /* need new one */
1188 aliasc = whine_malloc(sizeof(struct crec));
1189
1190 if (aliasc)
1191 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001192 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001193 if (ttd == 0)
1194 aliasc->flags |= F_IMMORTAL;
1195 else
1196 aliasc->ttd = ttd;
1197 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001198 aliasc->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +01001199 aliasc->addr.cname.uid = target->uid;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001200 aliasc->uid = next_uid();
Simon Kelley611ebc52012-07-16 16:23:46 +01001201 cache_hash(aliasc);
1202 add_dhcp_cname(aliasc, ttd);
1203 }
1204 }
1205}
1206
Simon Kelley4cb1b322012-02-06 14:30:41 +00001207void cache_add_dhcp_entry(char *host_name, int prot,
1208 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001209{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001210 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001211 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001212 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001213 size_t addrlen = sizeof(struct in_addr);
1214
1215#ifdef HAVE_IPV6
1216 if (prot == AF_INET6)
1217 {
1218 flags = F_IPV6;
1219 addrlen = sizeof(struct in6_addr);
1220 }
1221#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001222
Simon Kelley12d71ed2012-08-30 15:16:41 +01001223 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1224
Simon Kelley4cb1b322012-02-06 14:30:41 +00001225 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001226 {
Simon Kelley824af852008-02-12 20:43:05 +00001227 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001228 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001229 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001230 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001231 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001232 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001233 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001234 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1235 in_hosts = 1;
1236 else
1237 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001238 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001239 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001240 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001241 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
Simon Kelley824af852008-02-12 20:43:05 +00001242 /* scan_free deletes all addresses associated with name */
1243 break;
1244 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001245 }
Simon Kelley824af852008-02-12 20:43:05 +00001246
Simon Kelley12d71ed2012-08-30 15:16:41 +01001247 /* if in hosts, don't need DHCP record */
1248 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001249 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001250
1251 /* Name in hosts, address doesn't match */
1252 if (fail_crec)
1253 {
1254 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1255 my_syslog(MS_DHCP | LOG_WARNING,
1256 _("not giving name %s to the DHCP lease of %s because "
1257 "the name exists in %s with address %s"),
1258 host_name, daemon->addrbuff,
1259 record_source(fail_crec->uid), daemon->namebuff);
1260 return;
1261 }
1262
1263 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1264 {
1265 if (crec->flags & F_NEG)
1266 {
1267 flags |= F_REVERSE;
1268 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1269 }
1270 }
1271 else
1272 flags |= F_REVERSE;
1273
1274 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001275 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001276 else /* need new one */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001277 crec = whine_malloc(sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001278
1279 if (crec) /* malloc may fail */
1280 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001281 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001282 if (ttd == 0)
1283 crec->flags |= F_IMMORTAL;
1284 else
1285 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001286 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001287 crec->name.namep = host_name;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001288 crec->uid = next_uid();
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001289 cache_hash(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001290
Simon Kelley611ebc52012-07-16 16:23:46 +01001291 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001292 }
1293}
Simon Kelley7622fc02009-06-04 20:32:05 +01001294#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001295
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001296#ifndef NO_ID
Simon Kelleyfec216d2014-03-27 20:54:34 +00001297int cache_make_stat(struct txt_record *t)
1298{
1299 static char *buff = NULL;
1300 static int bufflen = 60;
1301 int len;
1302 struct server *serv, *serv1;
1303 char *p;
1304
1305 if (!buff && !(buff = whine_malloc(60)))
1306 return 0;
1307
1308 p = buff;
1309
1310 switch (t->stat)
1311 {
1312 case TXT_STAT_CACHESIZE:
1313 sprintf(buff+1, "%d", daemon->cachesize);
1314 break;
1315
1316 case TXT_STAT_INSERTS:
1317 sprintf(buff+1, "%d", cache_inserted);
1318 break;
1319
1320 case TXT_STAT_EVICTIONS:
1321 sprintf(buff+1, "%d", cache_live_freed);
1322 break;
1323
1324 case TXT_STAT_MISSES:
1325 sprintf(buff+1, "%u", daemon->queries_forwarded);
1326 break;
1327
1328 case TXT_STAT_HITS:
1329 sprintf(buff+1, "%u", daemon->local_answer);
1330 break;
1331
1332#ifdef HAVE_AUTH
1333 case TXT_STAT_AUTH:
1334 sprintf(buff+1, "%u", daemon->auth_answer);
1335 break;
1336#endif
1337
1338 case TXT_STAT_SERVERS:
1339 /* sum counts from different records for same server */
1340 for (serv = daemon->servers; serv; serv = serv->next)
1341 serv->flags &= ~SERV_COUNTED;
1342
1343 for (serv = daemon->servers; serv; serv = serv->next)
1344 if (!(serv->flags &
1345 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1346 {
1347 char *new, *lenp;
1348 int port, newlen, bytes_avail, bytes_needed;
1349 unsigned int queries = 0, failed_queries = 0;
1350 for (serv1 = serv; serv1; serv1 = serv1->next)
1351 if (!(serv1->flags &
1352 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1353 sockaddr_isequal(&serv->addr, &serv1->addr))
1354 {
1355 serv1->flags |= SERV_COUNTED;
1356 queries += serv1->queries;
1357 failed_queries += serv1->failed_queries;
1358 }
1359 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1360 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001361 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001362 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1363 if (bytes_needed >= bytes_avail)
1364 {
1365 /* expand buffer if necessary */
1366 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1367 if (!(new = whine_malloc(newlen)))
1368 return 0;
1369 memcpy(new, buff, bufflen);
1370 free(buff);
1371 p = new + (p - buff);
1372 lenp = p - 1;
1373 buff = new;
1374 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001375 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001376 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1377 }
1378 *lenp = bytes_needed;
1379 p += bytes_needed;
1380 }
1381 t->txt = (unsigned char *)buff;
1382 t->len = p - buff;
1383 return 1;
1384 }
1385
1386 len = strlen(buff+1);
1387 t->txt = (unsigned char *)buff;
1388 t->len = len + 1;
1389 *buff = len;
1390 return 1;
1391}
Kevin Darbyshire-Bryant7ac9ae12016-09-09 20:52:08 +01001392#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001393
Simon Kelley394ff492015-03-29 22:17:14 +01001394/* There can be names in the cache containing control chars, don't
1395 mess up logging or open security holes. */
1396static char *sanitise(char *name)
1397{
1398 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001399 if (name)
1400 for (r = (unsigned char *)name; *r; r++)
1401 if (!isprint((int)*r))
1402 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001403
1404 return name;
1405}
1406
1407
Simon Kelley5aabfc72007-08-29 11:24:47 +01001408void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001409{
Simon Kelley824af852008-02-12 20:43:05 +00001410 struct server *serv, *serv1;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001411 char *t = "";
Simon Kelley824af852008-02-12 20:43:05 +00001412
1413 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1414 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1415 daemon->cachesize, cache_live_freed, cache_inserted);
1416 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1417 daemon->queries_forwarded, daemon->local_answer);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001418#ifdef HAVE_AUTH
1419 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
1420#endif
Simon Kelleyc2207682014-01-08 18:04:20 +00001421#ifdef HAVE_DNSSEC
1422 blockdata_report();
1423#endif
Simon Kelley824af852008-02-12 20:43:05 +00001424
Simon Kelley824af852008-02-12 20:43:05 +00001425 /* sum counts from different records for same server */
1426 for (serv = daemon->servers; serv; serv = serv->next)
1427 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001428
Simon Kelley824af852008-02-12 20:43:05 +00001429 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001430 if (!(serv->flags &
1431 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001432 {
1433 int port;
1434 unsigned int queries = 0, failed_queries = 0;
1435 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001436 if (!(serv1->flags &
1437 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1438 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001439 {
1440 serv1->flags |= SERV_COUNTED;
1441 queries += serv1->queries;
1442 failed_queries += serv1->failed_queries;
1443 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001444 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1445 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 +00001446 }
1447
Simon Kelley28866e92011-02-14 20:19:14 +00001448 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001449 {
1450 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001451 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001452 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001453
1454 for (i=0; i<hash_size; i++)
1455 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1456 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001457 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1458 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001459 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001460 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001461 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001462 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001463 a = sanitise(cache_get_cname_target(cache));
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001464#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001465 else if (cache->flags & F_DS)
1466 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001467 if (!(cache->flags & F_NEG))
Simon Kelleyb8eac192014-02-27 14:30:03 +00001468 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1469 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001470 }
1471 else if (cache->flags & F_DNSKEY)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001472 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1473 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001474#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001475 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001476 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001477 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001478 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001479 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001480#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001481 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001482 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001483#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001484 }
1485
Simon Kelleye7829ae2014-01-22 22:21:51 +00001486 if (cache->flags & F_IPV4)
1487 t = "4";
1488 else if (cache->flags & F_IPV6)
1489 t = "6";
1490 else if (cache->flags & F_CNAME)
1491 t = "C";
1492#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001493 else if (cache->flags & F_DS)
1494 t = "S";
1495 else if (cache->flags & F_DNSKEY)
1496 t = "K";
1497#endif
Simon Kelley32678042014-12-17 20:38:20 +00001498 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001499 cache->flags & F_FORWARD ? "F" : " ",
1500 cache->flags & F_REVERSE ? "R" : " ",
1501 cache->flags & F_IMMORTAL ? "I" : " ",
1502 cache->flags & F_DHCP ? "D" : " ",
1503 cache->flags & F_NEG ? "N" : " ",
1504 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001505 cache->flags & F_HOSTS ? "H" : " ",
1506 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001507#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001508 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001509#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001510 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1511 /* ctime includes trailing \n - eat it */
1512 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001513#endif
Simon Kelley28866e92011-02-14 20:19:14 +00001514 my_syslog(LOG_INFO, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001515 }
1516 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001517}
1518
Simon Kelley19c51cf2014-03-18 22:38:30 +00001519char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001520{
Simon Kelley7622fc02009-06-04 20:32:05 +01001521 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001522
Simon Kelley19c51cf2014-03-18 22:38:30 +00001523 if (index == SRC_CONFIG)
1524 return "config";
1525 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001526 return HOSTSFILE;
1527
1528 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1529 if (ah->index == index)
1530 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001531
1532#ifdef HAVE_INOTIFY
1533 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1534 if (ah->index == index)
1535 return ah->fname;
1536#endif
1537
Simon Kelley7622fc02009-06-04 20:32:05 +01001538 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001539}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001540
Simon Kelley610e7822014-02-06 14:45:17 +00001541char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001542{
1543 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001544 int len = 10; /* strlen("type=xxxxx") */
1545 const char *types = NULL;
1546 static char *buff = NULL;
1547 static int bufflen = 0;
1548
Simon Kelley1a6bca82008-07-11 11:11:42 +01001549 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1550 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001551 {
1552 types = typestr[i].name;
1553 len = strlen(types);
1554 break;
1555 }
1556
1557 len += 3; /* braces, terminator */
1558 len += strlen(desc);
1559
1560 if (!buff || bufflen < len)
1561 {
1562 if (buff)
1563 free(buff);
1564 else if (len < 20)
1565 len = 20;
1566
1567 buff = whine_malloc(len);
1568 bufflen = len;
1569 }
1570
1571 if (buff)
1572 {
1573 if (types)
1574 sprintf(buff, "%s[%s]", desc, types);
1575 else
1576 sprintf(buff, "%s[type=%d]", desc, type);
1577 }
1578
1579 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001580}
1581
Simon Kelley28866e92011-02-14 20:19:14 +00001582void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001583{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001584 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001585 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001586
Simon Kelley28866e92011-02-14 20:19:14 +00001587 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001588 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001589
Simon Kelley394ff492015-03-29 22:17:14 +01001590 name = sanitise(name);
1591
Simon Kelley5aabfc72007-08-29 11:24:47 +01001592 if (addr)
1593 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001594 if (flags & F_KEYTAG)
Simon Kelley15379ea2015-12-21 18:31:55 +00001595 sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001596 else
1597 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001598#ifdef HAVE_IPV6
Simon Kelley0fc2f312014-01-08 10:26:58 +00001599 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1600 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001601#else
Simon Kelley0fc2f312014-01-08 10:26:58 +00001602 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001603#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001604 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001605 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001606 else
1607 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001608
1609 if (flags & F_REVERSE)
1610 {
1611 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001612 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001613 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001614
1615 if (flags & F_NEG)
1616 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001617 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001618 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001619 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001620 {
1621 if (flags & F_IPV4)
1622 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001623 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001624 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001625 else
1626 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001627 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001628 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001629 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001630 dest = "<CNAME>";
1631 else if (flags & F_RRNAME)
1632 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001633
Simon Kelley1f15b812009-10-13 17:49:32 +01001634 if (flags & F_CONFIG)
1635 source = "config";
1636 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001637 source = "DHCP";
1638 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001639 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001640 else if (flags & F_UPSTREAM)
1641 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001642 else if (flags & F_SECSTAT)
1643 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001644 else if (flags & F_AUTH)
1645 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001646 else if (flags & F_SERVER)
1647 {
1648 source = "forwarded";
1649 verb = "to";
1650 }
1651 else if (flags & F_QUERY)
1652 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001653 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001654 verb = "from";
1655 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001656 else if (flags & F_DNSSEC)
1657 {
1658 source = arg;
1659 verb = "to";
1660 }
Wang Jian49752b92014-03-28 20:52:47 +00001661 else if (flags & F_IPSET)
1662 {
1663 source = "ipset add";
1664 dest = name;
1665 name = arg;
1666 verb = daemon->addrbuff;
1667 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001668 else
1669 source = "cached";
1670
Simon Kelley3d8df262005-08-29 12:19:27 +01001671 if (strlen(name) == 0)
1672 name = ".";
1673
Simon Kelley25cf5e32015-01-09 15:53:03 +00001674 if (option_bool(OPT_EXTRALOG))
1675 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001676 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001677 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001678 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001679 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001680 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 +00001681 }
1682 else
1683 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001684}
1685
Simon Kelley98c098b2014-01-08 17:31:16 +00001686