blob: 4da380ae8d0d37201dd569432603727c9bcc8bf5 [file] [log] [blame]
Simon Kelleyaff33962015-01-31 20:13:40 +00001/* dnsmasq is Copyright (c) 2000-2015 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)
777 if (hostname_isequal(cache_get_name(target), a->target) &&
778 (crec = whine_malloc(sizeof(struct crec))))
779 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000780 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelley611ebc52012-07-16 16:23:46 +0100781 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100782 crec->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +0100783 crec->addr.cname.uid = target->uid;
Simon Kelley19c51cf2014-03-18 22:38:30 +0000784 crec->uid = next_uid();
Simon Kelley611ebc52012-07-16 16:23:46 +0100785 cache_hash(crec);
786 add_hosts_cname(crec); /* handle chains */
787 }
788}
789
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100790static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelley19c51cf2014-03-18 22:38:30 +0000791 unsigned int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000792{
Simon Kelleye759d422012-03-16 13:18:57 +0000793 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 +0000794 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000795 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000796
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000797 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000798 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000799 {
Simon Kelley9009d742008-11-14 20:04:27 +0000800 nameexists = 1;
801 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
802 {
803 free(cache);
804 return;
805 }
806 }
807
808 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000809 We do this by steam here, The entries are kept in hash chains, linked
810 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000811 the array rhash, hashed on address. Note that rhash and the values
812 in ->next are only valid whilst reading hosts files: the buckets are
813 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000814
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000815 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000816
817 This complexity avoids O(n^2) divergent CPU use whilst reading
Simon Kelley70d18732015-01-31 19:59:29 +0000818 large (10000 entry) hosts files.
819
820 Note that we only do this process when bulk-reading hosts files,
821 for incremental reads, rhash is NULL, and we use cache lookups
822 instead.
823 */
Simon Kelley9009d742008-11-14 20:04:27 +0000824
Simon Kelley70d18732015-01-31 19:59:29 +0000825 if (rhash)
Simon Kelley915363f2012-01-11 22:00:48 +0000826 {
Simon Kelley70d18732015-01-31 19:59:29 +0000827 /* hash address */
828 for (j = 0, i = 0; i < addrlen; i++)
829 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
830
831 for (lookup = rhash[j]; lookup; lookup = lookup->next)
832 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
833 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
834 {
835 cache->flags &= ~F_REVERSE;
836 break;
837 }
838
839 /* maintain address hash chain, insert new unique address */
840 if (!lookup)
841 {
842 cache->next = rhash[j];
843 rhash[j] = cache;
844 }
Simon Kelley915363f2012-01-11 22:00:48 +0000845 }
Simon Kelley70d18732015-01-31 19:59:29 +0000846 else
847 {
848 /* incremental read, lookup in cache */
849 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
850 if (lookup && lookup->flags & F_HOSTS)
851 cache->flags &= ~F_REVERSE;
852 }
853
Simon Kelley9009d742008-11-14 20:04:27 +0000854 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000855 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000856 cache_hash(cache);
857
858 /* don't need to do alias stuff for second and subsequent addresses. */
859 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100860 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000861}
862
863static int eatspace(FILE *f)
864{
865 int c, nl = 0;
866
867 while (1)
868 {
869 if ((c = getc(f)) == '#')
870 while (c != '\n' && c != EOF)
871 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000872
Simon Kelley9009d742008-11-14 20:04:27 +0000873 if (c == EOF)
874 return 1;
875
876 if (!isspace(c))
877 {
878 ungetc(c, f);
879 return nl;
880 }
881
882 if (c == '\n')
883 nl = 1;
884 }
885}
886
887static int gettok(FILE *f, char *token)
888{
889 int c, count = 0;
890
891 while (1)
892 {
893 if ((c = getc(f)) == EOF)
894 return (count == 0) ? EOF : 1;
895
896 if (isspace(c) || c == '#')
897 {
898 ungetc(c, f);
899 return eatspace(f);
900 }
901
902 if (count < (MAXDNAME - 1))
903 {
904 token[count++] = c;
905 token[count] = 0;
906 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000907 }
908}
909
Simon Kelley70d18732015-01-31 19:59:29 +0000910int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000911{
912 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000913 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100914 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000915 unsigned short flags = 0;
916 struct all_addr addr;
917 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100918
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000919 if (!f)
920 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100921 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
Simon Kelley4011c4e2006-10-28 16:26:19 +0100922 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000923 }
Simon Kelley9009d742008-11-14 20:04:27 +0000924
925 eatspace(f);
926
927 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000928 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000929 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000930
Simon Kelley3d8df262005-08-29 12:19:27 +0100931 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000932 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000933 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000934 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000935 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000936 }
Simon Kelleye759d422012-03-16 13:18:57 +0000937#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100938 else if (inet_pton(AF_INET6, 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_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000941 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000942 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000943 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000944#endif
945 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000946 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100947 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +0000948 while (atnl == 0)
949 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000950 continue;
951 }
Simon Kelley9009d742008-11-14 20:04:27 +0000952
Simon Kelley9009d742008-11-14 20:04:27 +0000953 addr_count++;
954
955 /* rehash every 1000 names. */
Simon Kelley70d18732015-01-31 19:59:29 +0000956 if (rhash && ((name_count - cache_size) > 1000))
Simon Kelley9009d742008-11-14 20:04:27 +0000957 {
958 rehash(name_count);
959 cache_size = name_count;
960 }
961
962 while (atnl == 0)
963 {
964 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +0100965 int fqdn, nomem;
966 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +0000967
968 if ((atnl = gettok(f, token)) == EOF)
969 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000970
Simon Kelley9009d742008-11-14 20:04:27 +0000971 fqdn = !!strchr(token, '.');
972
Simon Kelley1f15b812009-10-13 17:49:32 +0100973 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +0000974 {
975 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +0000976 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley9009d742008-11-14 20:04:27 +0000977 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +0100978 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000979 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100980 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +0000981 strcat(cache->name.sname, ".");
982 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +0000983 cache->flags = flags;
984 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000985 name_count++;
986 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100987 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000988 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100989 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +0000990 cache->flags = flags;
991 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000992 name_count++;
993 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100994 free(canon);
995
Simon Kelley9009d742008-11-14 20:04:27 +0000996 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100997 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +0000998 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
999 }
1000 }
1001
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001002 fclose(f);
Simon Kelley9009d742008-11-14 20:04:27 +00001003
Simon Kelley70d18732015-01-31 19:59:29 +00001004 if (rhash)
Simon Kelleyf9c86372015-02-03 21:52:48 +00001005 rehash(name_count);
1006
1007 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1008
Simon Kelley4011c4e2006-10-28 16:26:19 +01001009 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001010}
1011
Simon Kelley7622fc02009-06-04 20:32:05 +01001012void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001013{
1014 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001015 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +01001016 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +00001017 struct host_record *hr;
1018 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001019 struct cname *a;
1020 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001021#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001022 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001023#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001024
Simon Kelley59353a62004-11-21 19:34:28 +00001025 cache_inserted = cache_live_freed = 0;
1026
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001027 for (i=0; i<hash_size; i++)
1028 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1029 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001030#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +00001031 cache_blockdata_free(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001032#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001033 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001034 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001035 {
1036 *up = cache->hash_next;
1037 free(cache);
1038 }
1039 else if (!(cache->flags & F_DHCP))
1040 {
1041 *up = cache->hash_next;
1042 if (cache->flags & F_BIGNAME)
1043 {
1044 cache->name.bname->next = big_free;
1045 big_free = cache->name.bname;
1046 }
1047 cache->flags = 0;
1048 }
1049 else
1050 up = &cache->hash_next;
1051 }
1052
Simon Kelleyd56a6042013-10-11 14:39:03 +01001053 /* Add CNAMEs to interface_names to the cache */
1054 for (a = daemon->cnames; a; a = a->next)
1055 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley532066e2013-11-26 10:14:47 +00001056 if (hostname_isequal(a->target, intr->name) &&
1057 ((cache = whine_malloc(sizeof(struct crec)))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001058 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001059 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelley532066e2013-11-26 10:14:47 +00001060 cache->name.namep = a->alias;
1061 cache->addr.cname.target.int_name = intr;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001062 cache->addr.cname.uid = SRC_INTERFACE;
1063 cache->uid = next_uid();
Simon Kelley532066e2013-11-26 10:14:47 +00001064 cache_hash(cache);
1065 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001066 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001067
1068#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001069 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001070 if ((cache = whine_malloc(sizeof(struct crec))) &&
Simon Kelleyee415862014-02-11 11:07:22 +00001071 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001072 {
Simon Kelleyee415862014-02-11 11:07:22 +00001073 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
1074 cache->name.namep = ds->name;
1075 cache->addr.ds.keylen = ds->digestlen;
1076 cache->addr.ds.algo = ds->algo;
1077 cache->addr.ds.keytag = ds->keytag;
1078 cache->addr.ds.digest = ds->digest_type;
1079 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001080 cache_hash(cache);
1081 }
1082#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001083
Simon Kelleye759d422012-03-16 13:18:57 +00001084 /* borrow the packet buffer for a temporary by-address hash */
1085 memset(daemon->packet, 0, daemon->packet_buff_sz);
1086 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1087 /* we overwrote the buffer... */
1088 daemon->srv_save = NULL;
1089
1090 /* Do host_records in config. */
1091 for (hr = daemon->host_records; hr; hr = hr->next)
1092 for (nl = hr->names; nl; nl = nl->next)
1093 {
1094 if (hr->addr.s_addr != 0 &&
1095 (cache = whine_malloc(sizeof(struct crec))))
1096 {
1097 cache->name.namep = nl->name;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001098 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001099 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001100 }
1101#ifdef HAVE_IPV6
1102 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1103 (cache = whine_malloc(sizeof(struct crec))))
1104 {
1105 cache->name.namep = nl->name;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001106 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001107 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
Simon Kelleye759d422012-03-16 13:18:57 +00001108 }
1109#endif
1110 }
1111
Simon Kelley28866e92011-02-14 20:19:14 +00001112 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001113 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001114 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001115 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001116 }
Simon Kelleycaeea192015-02-14 20:08:56 +00001117 else
1118 {
1119 if (!option_bool(OPT_NO_HOSTS))
1120 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1121
1122 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1123 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1124 if (!(ah->flags & AH_INACTIVE))
1125 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1126 }
1127
Simon Kelley70d18732015-01-31 19:59:29 +00001128#ifdef HAVE_INOTIFY
1129 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1130#endif
1131
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001132}
1133
Simon Kelley7622fc02009-06-04 20:32:05 +01001134#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001135struct in_addr a_record_from_hosts(char *name, time_t now)
1136{
1137 struct crec *crecp = NULL;
1138 struct in_addr ret;
1139
1140 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1141 if (crecp->flags & F_HOSTS)
1142 return *(struct in_addr *)&crecp->addr;
1143
1144 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1145
1146 ret.s_addr = 0;
1147 return ret;
1148}
1149
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001150void cache_unhash_dhcp(void)
1151{
Simon Kelley6b010842007-02-12 20:32:07 +00001152 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001153 int i;
1154
1155 for (i=0; i<hash_size; i++)
1156 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1157 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001158 {
1159 *up = cache->hash_next;
1160 cache->next = dhcp_spare;
1161 dhcp_spare = cache;
1162 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001163 else
1164 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001165}
1166
Simon Kelley611ebc52012-07-16 16:23:46 +01001167static void add_dhcp_cname(struct crec *target, time_t ttd)
1168{
1169 struct crec *aliasc;
1170 struct cname *a;
1171
1172 for (a = daemon->cnames; a; a = a->next)
1173 if (hostname_isequal(cache_get_name(target), a->target))
1174 {
1175 if ((aliasc = dhcp_spare))
1176 dhcp_spare = dhcp_spare->next;
1177 else /* need new one */
1178 aliasc = whine_malloc(sizeof(struct crec));
1179
1180 if (aliasc)
1181 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001182 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001183 if (ttd == 0)
1184 aliasc->flags |= F_IMMORTAL;
1185 else
1186 aliasc->ttd = ttd;
1187 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001188 aliasc->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +01001189 aliasc->addr.cname.uid = target->uid;
Simon Kelley19c51cf2014-03-18 22:38:30 +00001190 aliasc->uid = next_uid();
Simon Kelley611ebc52012-07-16 16:23:46 +01001191 cache_hash(aliasc);
1192 add_dhcp_cname(aliasc, ttd);
1193 }
1194 }
1195}
1196
Simon Kelley4cb1b322012-02-06 14:30:41 +00001197void cache_add_dhcp_entry(char *host_name, int prot,
1198 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001199{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001200 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001201 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001202 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001203 size_t addrlen = sizeof(struct in_addr);
1204
1205#ifdef HAVE_IPV6
1206 if (prot == AF_INET6)
1207 {
1208 flags = F_IPV6;
1209 addrlen = sizeof(struct in6_addr);
1210 }
1211#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001212
Simon Kelley12d71ed2012-08-30 15:16:41 +01001213 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1214
Simon Kelley4cb1b322012-02-06 14:30:41 +00001215 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001216 {
Simon Kelley824af852008-02-12 20:43:05 +00001217 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001218 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001219 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001220 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001221 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001222 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001223 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001224 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1225 in_hosts = 1;
1226 else
1227 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001228 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001229 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001230 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001231 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
Simon Kelley824af852008-02-12 20:43:05 +00001232 /* scan_free deletes all addresses associated with name */
1233 break;
1234 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001235 }
Simon Kelley824af852008-02-12 20:43:05 +00001236
Simon Kelley12d71ed2012-08-30 15:16:41 +01001237 /* if in hosts, don't need DHCP record */
1238 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001239 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001240
1241 /* Name in hosts, address doesn't match */
1242 if (fail_crec)
1243 {
1244 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1245 my_syslog(MS_DHCP | LOG_WARNING,
1246 _("not giving name %s to the DHCP lease of %s because "
1247 "the name exists in %s with address %s"),
1248 host_name, daemon->addrbuff,
1249 record_source(fail_crec->uid), daemon->namebuff);
1250 return;
1251 }
1252
1253 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1254 {
1255 if (crec->flags & F_NEG)
1256 {
1257 flags |= F_REVERSE;
1258 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1259 }
1260 }
1261 else
1262 flags |= F_REVERSE;
1263
1264 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001265 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001266 else /* need new one */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001267 crec = whine_malloc(sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001268
1269 if (crec) /* malloc may fail */
1270 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001271 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001272 if (ttd == 0)
1273 crec->flags |= F_IMMORTAL;
1274 else
1275 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001276 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001277 crec->name.namep = host_name;
Simon Kelley3f7483e2014-03-16 22:56:58 +00001278 crec->uid = next_uid();
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001279 cache_hash(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001280
Simon Kelley611ebc52012-07-16 16:23:46 +01001281 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001282 }
1283}
Simon Kelley7622fc02009-06-04 20:32:05 +01001284#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001285
Simon Kelleyfec216d2014-03-27 20:54:34 +00001286int cache_make_stat(struct txt_record *t)
1287{
1288 static char *buff = NULL;
1289 static int bufflen = 60;
1290 int len;
1291 struct server *serv, *serv1;
1292 char *p;
1293
1294 if (!buff && !(buff = whine_malloc(60)))
1295 return 0;
1296
1297 p = buff;
1298
1299 switch (t->stat)
1300 {
1301 case TXT_STAT_CACHESIZE:
1302 sprintf(buff+1, "%d", daemon->cachesize);
1303 break;
1304
1305 case TXT_STAT_INSERTS:
1306 sprintf(buff+1, "%d", cache_inserted);
1307 break;
1308
1309 case TXT_STAT_EVICTIONS:
1310 sprintf(buff+1, "%d", cache_live_freed);
1311 break;
1312
1313 case TXT_STAT_MISSES:
1314 sprintf(buff+1, "%u", daemon->queries_forwarded);
1315 break;
1316
1317 case TXT_STAT_HITS:
1318 sprintf(buff+1, "%u", daemon->local_answer);
1319 break;
1320
1321#ifdef HAVE_AUTH
1322 case TXT_STAT_AUTH:
1323 sprintf(buff+1, "%u", daemon->auth_answer);
1324 break;
1325#endif
1326
1327 case TXT_STAT_SERVERS:
1328 /* sum counts from different records for same server */
1329 for (serv = daemon->servers; serv; serv = serv->next)
1330 serv->flags &= ~SERV_COUNTED;
1331
1332 for (serv = daemon->servers; serv; serv = serv->next)
1333 if (!(serv->flags &
1334 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1335 {
1336 char *new, *lenp;
1337 int port, newlen, bytes_avail, bytes_needed;
1338 unsigned int queries = 0, failed_queries = 0;
1339 for (serv1 = serv; serv1; serv1 = serv1->next)
1340 if (!(serv1->flags &
1341 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1342 sockaddr_isequal(&serv->addr, &serv1->addr))
1343 {
1344 serv1->flags |= SERV_COUNTED;
1345 queries += serv1->queries;
1346 failed_queries += serv1->failed_queries;
1347 }
1348 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1349 lenp = p++; /* length */
Simon Kelley04b0ac02015-04-06 17:19:13 +01001350 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001351 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1352 if (bytes_needed >= bytes_avail)
1353 {
1354 /* expand buffer if necessary */
1355 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1356 if (!(new = whine_malloc(newlen)))
1357 return 0;
1358 memcpy(new, buff, bufflen);
1359 free(buff);
1360 p = new + (p - buff);
1361 lenp = p - 1;
1362 buff = new;
1363 bufflen = newlen;
Simon Kelley04b0ac02015-04-06 17:19:13 +01001364 bytes_avail = bufflen - (p - buff );
Simon Kelleyfec216d2014-03-27 20:54:34 +00001365 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1366 }
1367 *lenp = bytes_needed;
1368 p += bytes_needed;
1369 }
1370 t->txt = (unsigned char *)buff;
1371 t->len = p - buff;
1372 return 1;
1373 }
1374
1375 len = strlen(buff+1);
1376 t->txt = (unsigned char *)buff;
1377 t->len = len + 1;
1378 *buff = len;
1379 return 1;
1380}
Simon Kelley9009d742008-11-14 20:04:27 +00001381
Simon Kelley394ff492015-03-29 22:17:14 +01001382/* There can be names in the cache containing control chars, don't
1383 mess up logging or open security holes. */
1384static char *sanitise(char *name)
1385{
1386 unsigned char *r;
Simon Kelley794fccc2015-03-29 22:35:44 +01001387 if (name)
1388 for (r = (unsigned char *)name; *r; r++)
1389 if (!isprint((int)*r))
1390 return "<name unprintable>";
Simon Kelley394ff492015-03-29 22:17:14 +01001391
1392 return name;
1393}
1394
1395
Simon Kelley5aabfc72007-08-29 11:24:47 +01001396void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001397{
Simon Kelley824af852008-02-12 20:43:05 +00001398 struct server *serv, *serv1;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001399 char *t = "";
Simon Kelley824af852008-02-12 20:43:05 +00001400
1401 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1402 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1403 daemon->cachesize, cache_live_freed, cache_inserted);
1404 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1405 daemon->queries_forwarded, daemon->local_answer);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001406#ifdef HAVE_AUTH
1407 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
1408#endif
Simon Kelleyc2207682014-01-08 18:04:20 +00001409#ifdef HAVE_DNSSEC
1410 blockdata_report();
1411#endif
Simon Kelley824af852008-02-12 20:43:05 +00001412
Simon Kelley824af852008-02-12 20:43:05 +00001413 /* sum counts from different records for same server */
1414 for (serv = daemon->servers; serv; serv = serv->next)
1415 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001416
Simon Kelley824af852008-02-12 20:43:05 +00001417 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001418 if (!(serv->flags &
1419 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001420 {
1421 int port;
1422 unsigned int queries = 0, failed_queries = 0;
1423 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001424 if (!(serv1->flags &
1425 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1426 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001427 {
1428 serv1->flags |= SERV_COUNTED;
1429 queries += serv1->queries;
1430 failed_queries += serv1->failed_queries;
1431 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001432 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1433 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 +00001434 }
1435
Simon Kelley28866e92011-02-14 20:19:14 +00001436 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001437 {
1438 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001439 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001440 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001441
1442 for (i=0; i<hash_size; i++)
1443 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1444 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001445 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1446 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001447 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001448 n = "<Root>";
Simon Kelley394ff492015-03-29 22:17:14 +01001449 p += sprintf(p, "%-30.30s ", sanitise(n));
Simon Kelley0fc2f312014-01-08 10:26:58 +00001450 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
Simon Kelley394ff492015-03-29 22:17:14 +01001451 a = sanitise(cache_get_cname_target(cache));
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001452#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001453 else if (cache->flags & F_DS)
1454 {
Simon Kelley93be5b12015-12-15 12:04:40 +00001455 if (!(cache->flags & F_NEG))
Simon Kelleyb8eac192014-02-27 14:30:03 +00001456 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1457 cache->addr.ds.algo, cache->addr.ds.digest);
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001458 }
1459 else if (cache->flags & F_DNSKEY)
Simon Kelleyb8eac192014-02-27 14:30:03 +00001460 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1461 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001462#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001463 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001464 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001465 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001466 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001467 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001468#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001469 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001470 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001471#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001472 }
1473
Simon Kelleye7829ae2014-01-22 22:21:51 +00001474 if (cache->flags & F_IPV4)
1475 t = "4";
1476 else if (cache->flags & F_IPV6)
1477 t = "6";
1478 else if (cache->flags & F_CNAME)
1479 t = "C";
1480#ifdef HAVE_DNSSEC
Simon Kelleye7829ae2014-01-22 22:21:51 +00001481 else if (cache->flags & F_DS)
1482 t = "S";
1483 else if (cache->flags & F_DNSKEY)
1484 t = "K";
1485#endif
Simon Kelley32678042014-12-17 20:38:20 +00001486 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001487 cache->flags & F_FORWARD ? "F" : " ",
1488 cache->flags & F_REVERSE ? "R" : " ",
1489 cache->flags & F_IMMORTAL ? "I" : " ",
1490 cache->flags & F_DHCP ? "D" : " ",
1491 cache->flags & F_NEG ? "N" : " ",
1492 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001493 cache->flags & F_HOSTS ? "H" : " ",
1494 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001495#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001496 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001497#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001498 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1499 /* ctime includes trailing \n - eat it */
1500 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001501#endif
Simon Kelley28866e92011-02-14 20:19:14 +00001502 my_syslog(LOG_INFO, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001503 }
1504 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001505}
1506
Simon Kelley19c51cf2014-03-18 22:38:30 +00001507char *record_source(unsigned int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001508{
Simon Kelley7622fc02009-06-04 20:32:05 +01001509 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001510
Simon Kelley19c51cf2014-03-18 22:38:30 +00001511 if (index == SRC_CONFIG)
1512 return "config";
1513 else if (index == SRC_HOSTS)
Simon Kelley7622fc02009-06-04 20:32:05 +01001514 return HOSTSFILE;
1515
1516 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1517 if (ah->index == index)
1518 return ah->fname;
Simon Kelley70d18732015-01-31 19:59:29 +00001519
1520#ifdef HAVE_INOTIFY
1521 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1522 if (ah->index == index)
1523 return ah->fname;
1524#endif
1525
Simon Kelley7622fc02009-06-04 20:32:05 +01001526 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001527}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001528
Simon Kelley610e7822014-02-06 14:45:17 +00001529char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001530{
1531 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001532 int len = 10; /* strlen("type=xxxxx") */
1533 const char *types = NULL;
1534 static char *buff = NULL;
1535 static int bufflen = 0;
1536
Simon Kelley1a6bca82008-07-11 11:11:42 +01001537 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1538 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001539 {
1540 types = typestr[i].name;
1541 len = strlen(types);
1542 break;
1543 }
1544
1545 len += 3; /* braces, terminator */
1546 len += strlen(desc);
1547
1548 if (!buff || bufflen < len)
1549 {
1550 if (buff)
1551 free(buff);
1552 else if (len < 20)
1553 len = 20;
1554
1555 buff = whine_malloc(len);
1556 bufflen = len;
1557 }
1558
1559 if (buff)
1560 {
1561 if (types)
1562 sprintf(buff, "%s[%s]", desc, types);
1563 else
1564 sprintf(buff, "%s[type=%d]", desc, type);
1565 }
1566
1567 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001568}
1569
Simon Kelley28866e92011-02-14 20:19:14 +00001570void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001571{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001572 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001573 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001574
Simon Kelley28866e92011-02-14 20:19:14 +00001575 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001576 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001577
Simon Kelley394ff492015-03-29 22:17:14 +01001578 name = sanitise(name);
1579
Simon Kelley5aabfc72007-08-29 11:24:47 +01001580 if (addr)
1581 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001582 if (flags & F_KEYTAG)
Simon Kelley15379ea2015-12-21 18:31:55 +00001583 sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001584 else
1585 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001586#ifdef HAVE_IPV6
Simon Kelley0fc2f312014-01-08 10:26:58 +00001587 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1588 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001589#else
Simon Kelley0fc2f312014-01-08 10:26:58 +00001590 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001591#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001592 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001593 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001594 else
1595 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001596
1597 if (flags & F_REVERSE)
1598 {
1599 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001600 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001601 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001602
1603 if (flags & F_NEG)
1604 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001605 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001606 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001607 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001608 {
1609 if (flags & F_IPV4)
1610 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001611 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001612 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001613 else
1614 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001615 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001616 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001617 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001618 dest = "<CNAME>";
1619 else if (flags & F_RRNAME)
1620 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001621
Simon Kelley1f15b812009-10-13 17:49:32 +01001622 if (flags & F_CONFIG)
1623 source = "config";
1624 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001625 source = "DHCP";
1626 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001627 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001628 else if (flags & F_UPSTREAM)
1629 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001630 else if (flags & F_SECSTAT)
1631 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001632 else if (flags & F_AUTH)
1633 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001634 else if (flags & F_SERVER)
1635 {
1636 source = "forwarded";
1637 verb = "to";
1638 }
1639 else if (flags & F_QUERY)
1640 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001641 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001642 verb = "from";
1643 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001644 else if (flags & F_DNSSEC)
1645 {
1646 source = arg;
1647 verb = "to";
1648 }
Wang Jian49752b92014-03-28 20:52:47 +00001649 else if (flags & F_IPSET)
1650 {
1651 source = "ipset add";
1652 dest = name;
1653 name = arg;
1654 verb = daemon->addrbuff;
1655 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001656 else
1657 source = "cached";
1658
Simon Kelley3d8df262005-08-29 12:19:27 +01001659 if (strlen(name) == 0)
1660 name = ".";
1661
Simon Kelley25cf5e32015-01-09 15:53:03 +00001662 if (option_bool(OPT_EXTRALOG))
1663 {
Simon Kelley9f79ee42015-01-12 20:18:18 +00001664 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001665 if (flags & F_NOEXTRA)
Simon Kelley9f79ee42015-01-12 20:18:18 +00001666 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
Simon Kelley25cf5e32015-01-09 15:53:03 +00001667 else
Simon Kelley9f79ee42015-01-12 20:18:18 +00001668 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 +00001669 }
1670 else
1671 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001672}
1673
Simon Kelley98c098b2014-01-08 17:31:16 +00001674