blob: dd393c4b68b8f11d476163991369e70c941cf759 [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 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 Kelleyd56a6042013-10-11 14:39:03 +010027static int uid = 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000028
Simon Kelley16972692006-10-16 20:04:18 +010029/* type->string mapping: this is also used by the name-hash function as a mixing table. */
30static const struct {
31 unsigned int type;
32 const char * const name;
33} typestr[] = {
34 { 1, "A" },
35 { 2, "NS" },
36 { 5, "CNAME" },
37 { 6, "SOA" },
38 { 10, "NULL" },
39 { 11, "WKS" },
40 { 12, "PTR" },
41 { 13, "HINFO" },
42 { 15, "MX" },
43 { 16, "TXT" },
44 { 22, "NSAP" },
45 { 23, "NSAP_PTR" },
46 { 24, "SIG" },
47 { 25, "KEY" },
48 { 28, "AAAA" },
49 { 33, "SRV" },
Simon Kelley1a6bca82008-07-11 11:11:42 +010050 { 35, "NAPTR" },
Simon Kelley16972692006-10-16 20:04:18 +010051 { 36, "KX" },
52 { 37, "CERT" },
53 { 38, "A6" },
54 { 39, "DNAME" },
55 { 41, "OPT" },
Simon Kelley0fc2f312014-01-08 10:26:58 +000056 { 43, "DS" },
57 { 46, "RRSIG" },
Simon Kelley610e7822014-02-06 14:45:17 +000058 { 47, "NSEC" },
Simon Kelley832af0b2007-01-21 20:01:28 +000059 { 48, "DNSKEY" },
Simon Kelley610e7822014-02-06 14:45:17 +000060 { 50, "NSEC3" },
Simon Kelley832af0b2007-01-21 20:01:28 +000061 { 249, "TKEY" },
Simon Kelley16972692006-10-16 20:04:18 +010062 { 250, "TSIG" },
63 { 251, "IXFR" },
64 { 252, "AXFR" },
65 { 253, "MAILB" },
66 { 254, "MAILA" },
67 { 255, "ANY" }
68};
69
Simon Kelley9e4abcb2004-01-22 19:47:41 +000070static void cache_free(struct crec *crecp);
71static void cache_unlink(struct crec *crecp);
72static void cache_link(struct crec *crecp);
Simon Kelley4011c4e2006-10-28 16:26:19 +010073static void rehash(int size);
74static void cache_hash(struct crec *crecp);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000075
Simon Kelley5aabfc72007-08-29 11:24:47 +010076void cache_init(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000077{
78 struct crec *crecp;
79 int i;
Simon Kelleyd56a6042013-10-11 14:39:03 +010080
Simon Kelley5aabfc72007-08-29 11:24:47 +010081 bignames_left = daemon->cachesize/10;
82
83 if (daemon->cachesize > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000084 {
Simon Kelley5aabfc72007-08-29 11:24:47 +010085 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +000086
Simon Kelley5aabfc72007-08-29 11:24:47 +010087 for (i=0; i < daemon->cachesize; i++, crecp++)
Simon Kelley9e4abcb2004-01-22 19:47:41 +000088 {
89 cache_link(crecp);
90 crecp->flags = 0;
Simon Kelley26128d22004-11-14 16:43:54 +000091 crecp->uid = uid++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +000092 }
93 }
94
Simon Kelley4011c4e2006-10-28 16:26:19 +010095 /* create initial hash table*/
Simon Kelley5aabfc72007-08-29 11:24:47 +010096 rehash(daemon->cachesize);
Simon Kelley9e4abcb2004-01-22 19:47:41 +000097}
98
Simon Kelley4011c4e2006-10-28 16:26:19 +010099/* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
100 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
101 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
102 expand the table. */
103static void rehash(int size)
104{
105 struct crec **new, **old, *p, *tmp;
106 int i, new_size, old_size;
107
108 /* hash_size is a power of two. */
109 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
110
111 /* must succeed in getting first instance, failure later is non-fatal */
112 if (!hash_table)
113 new = safe_malloc(new_size * sizeof(struct crec *));
Simon Kelley5aabfc72007-08-29 11:24:47 +0100114 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
Simon Kelley4011c4e2006-10-28 16:26:19 +0100115 return;
116
117 for(i = 0; i < new_size; i++)
118 new[i] = NULL;
119
120 old = hash_table;
121 old_size = hash_size;
122 hash_table = new;
123 hash_size = new_size;
124
125 if (old)
126 {
127 for (i = 0; i < old_size; i++)
128 for (p = old[i]; p ; p = tmp)
129 {
130 tmp = p->hash_next;
131 cache_hash(p);
132 }
133 free(old);
134 }
135}
136
Simon Kelley3d8df262005-08-29 12:19:27 +0100137static struct crec **hash_bucket(char *name)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000138{
Simon Kelley4011c4e2006-10-28 16:26:19 +0100139 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
Simon Kelley16972692006-10-16 20:04:18 +0100140 const unsigned char *mix_tab = (const unsigned char*)typestr;
141
Simon Kelley3d8df262005-08-29 12:19:27 +0100142 while((c = (unsigned char) *name++))
Simon Kelley16972692006-10-16 20:04:18 +0100143 {
144 /* don't use tolower and friends here - they may be messed up by LOCALE */
145 if (c >= 'A' && c <= 'Z')
146 c += 'a' - 'A';
Simon Kelley4011c4e2006-10-28 16:26:19 +0100147 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
Simon Kelley16972692006-10-16 20:04:18 +0100148 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000149
150 /* hash_size is a power of two */
Simon Kelley16972692006-10-16 20:04:18 +0100151 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000152}
153
154static void cache_hash(struct crec *crecp)
155{
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000156 /* maintain an invariant that all entries with F_REVERSE set
157 are at the start of the hash-chain and all non-reverse
158 immortal entries are at the end of the hash-chain.
159 This allows reverse searches and garbage collection to be optimised */
160
161 struct crec **up = hash_bucket(cache_get_name(crecp));
162
163 if (!(crecp->flags & F_REVERSE))
164 {
165 while (*up && ((*up)->flags & F_REVERSE))
166 up = &((*up)->hash_next);
167
168 if (crecp->flags & F_IMMORTAL)
Simon Kelley6b010842007-02-12 20:32:07 +0000169 while (*up && !((*up)->flags & F_IMMORTAL))
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000170 up = &((*up)->hash_next);
171 }
172 crecp->hash_next = *up;
173 *up = crecp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000174}
Simon Kelley82e3f452014-01-31 21:05:48 +0000175
176#ifdef HAVE_DNSSEC
177static void cache_blockdata_free(struct crec *crecp)
178{
179 if (crecp->flags & F_DNSKEY)
180 {
181 if (crecp->flags & F_DS)
182 blockdata_free(crecp->addr.sig.keydata);
183 else
184 blockdata_free(crecp->addr.key.keydata);
185 }
186 else if (crecp->flags & F_DS)
187 blockdata_free(crecp->addr.ds.keydata);
188}
189#endif
190
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000191static void cache_free(struct crec *crecp)
192{
193 crecp->flags &= ~F_FORWARD;
194 crecp->flags &= ~F_REVERSE;
Simon Kelley26128d22004-11-14 16:43:54 +0000195 crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100196
197 if (uid == -1)
198 uid++;
199
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000200 if (cache_tail)
201 cache_tail->next = crecp;
202 else
203 cache_head = crecp;
204 crecp->prev = cache_tail;
205 crecp->next = NULL;
206 cache_tail = crecp;
207
208 /* retrieve big name for further use. */
209 if (crecp->flags & F_BIGNAME)
210 {
211 crecp->name.bname->next = big_free;
212 big_free = crecp->name.bname;
213 crecp->flags &= ~F_BIGNAME;
214 }
Simon Kelley072e81b2014-01-31 12:42:54 +0000215
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100216#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +0000217 cache_blockdata_free(crecp);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100218#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000219}
220
221/* insert a new cache entry at the head of the list (youngest entry) */
222static void cache_link(struct crec *crecp)
223{
224 if (cache_head) /* check needed for init code */
225 cache_head->prev = crecp;
226 crecp->next = cache_head;
227 crecp->prev = NULL;
228 cache_head = crecp;
229 if (!cache_tail)
230 cache_tail = crecp;
231}
232
233/* remove an arbitrary cache entry for promotion */
234static void cache_unlink (struct crec *crecp)
235{
236 if (crecp->prev)
237 crecp->prev->next = crecp->next;
238 else
239 cache_head = crecp->next;
240
241 if (crecp->next)
242 crecp->next->prev = crecp->prev;
243 else
244 cache_tail = crecp->prev;
245}
246
247char *cache_get_name(struct crec *crecp)
248{
249 if (crecp->flags & F_BIGNAME)
250 return crecp->name.bname->name;
Simon Kelley28866e92011-02-14 20:19:14 +0000251 else if (crecp->flags & F_NAMEP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000252 return crecp->name.namep;
253
254 return crecp->name.sname;
255}
256
Simon Kelleyd56a6042013-10-11 14:39:03 +0100257char *cache_get_cname_target(struct crec *crecp)
258{
259 if (crecp->addr.cname.uid != -1)
260 return cache_get_name(crecp->addr.cname.target.cache);
261
262 return crecp->addr.cname.target.int_name->name;
263}
264
265
266
Simon Kelleyb75e9362012-12-07 11:50:41 +0000267struct crec *cache_enumerate(int init)
268{
269 static int bucket;
270 static struct crec *cache;
271
272 if (init)
273 {
274 bucket = 0;
275 cache = NULL;
276 }
277 else if (cache && cache->hash_next)
278 cache = cache->hash_next;
279 else
280 {
281 cache = NULL;
282 while (bucket < hash_size)
283 if ((cache = hash_table[bucket++]))
284 break;
285 }
286
287 return cache;
288}
289
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100290static int is_outdated_cname_pointer(struct crec *crecp)
291{
Simon Kelleyd56a6042013-10-11 14:39:03 +0100292 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == -1)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100293 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100294
Simon Kelleycdbee9a2012-04-04 21:55:59 +0100295 /* NB. record may be reused as DS or DNSKEY, where uid is
296 overloaded for something completely different */
Simon Kelleyd56a6042013-10-11 14:39:03 +0100297 if (crecp->addr.cname.target.cache &&
298 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
299 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100300 return 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100301
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100302 return 1;
303}
304
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000305static int is_expired(time_t now, struct crec *crecp)
306{
307 if (crecp->flags & F_IMMORTAL)
308 return 0;
309
310 if (difftime(now, crecp->ttd) < 0)
311 return 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100312
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000313 return 1;
314}
315
316static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000317{
318 /* Scan and remove old entries.
319 If (flags & F_FORWARD) then remove any forward entries for name and any expired
320 entries but only in the same hash bucket as name.
321 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
322 entries in the whole cache.
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000323 If (flags == 0) remove any expired entries in the whole cache.
324
325 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000326 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000327
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000328 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
329 so that when we hit an entry which isn't reverse and is immortal, we're done. */
330
331 struct crec *crecp, **up;
332
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000333 if (flags & F_FORWARD)
334 {
Simon Kelley6b010842007-02-12 20:32:07 +0000335 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000336 {
337 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
338 {
339 *up = crecp->hash_next;
340 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
341 {
342 cache_unlink(crecp);
343 cache_free(crecp);
344 }
345 continue;
346 }
347
348 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
349 {
Simon Kelleye7829ae2014-01-22 22:21:51 +0000350 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
351 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
Simon Kelley6429e422014-01-23 12:09:36 +0000352 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000353 {
354 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
355 return 0;
356 *up = crecp->hash_next;
357 cache_unlink(crecp);
358 cache_free(crecp);
359 continue;
360 }
361
362#ifdef HAVE_DNSSEC
363 /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
364 type-covered sensitive for RRSIG */
Simon Kelley583043f2014-01-28 14:54:46 +0000365 if ((flags & (F_DNSKEY | F_DS)) &&
366 (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
Simon Kelley824202e2014-01-23 20:59:46 +0000367 crecp->uid == addr->addr.dnssec.class &&
368 (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
369 crecp->addr.sig.type_covered == addr->addr.dnssec.type))
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000370 {
Simon Kelley824202e2014-01-23 20:59:46 +0000371 if (crecp->flags & F_CONFIG)
372 return 0;
373 *up = crecp->hash_next;
374 cache_unlink(crecp);
375 cache_free(crecp);
376 continue;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000377 }
378#endif
379 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000380 up = &crecp->hash_next;
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000381 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000382 }
383 else
384 {
385 int i;
386#ifdef HAVE_IPV6
387 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
388#else
389 int addrlen = INADDRSZ;
390#endif
391 for (i = 0; i < hash_size; i++)
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000392 for (crecp = hash_table[i], up = &hash_table[i];
393 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
394 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000395 if (is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000396 {
397 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000398 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000399 {
400 cache_unlink(crecp);
401 cache_free(crecp);
402 }
403 }
Simon Kelley25439062013-11-25 21:14:51 +0000404 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000405 (flags & crecp->flags & F_REVERSE) &&
406 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
407 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
408 {
409 *up = crecp->hash_next;
410 cache_unlink(crecp);
411 cache_free(crecp);
412 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000413 else
414 up = &crecp->hash_next;
415 }
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000416
417 return 1;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000418}
419
420/* Note: The normal calling sequence is
421 cache_start_insert
422 cache_insert * n
423 cache_end_insert
424
425 but an abort can cause the cache_end_insert to be missed
426 in which can the next cache_start_insert cleans things up. */
427
428void cache_start_insert(void)
429{
430 /* Free any entries which didn't get committed during the last
431 insert due to error.
432 */
433 while (new_chain)
434 {
435 struct crec *tmp = new_chain->next;
436 cache_free(new_chain);
437 new_chain = tmp;
438 }
439 new_chain = NULL;
440 insert_error = 0;
441}
442
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100443struct crec *cache_insert(char *name, struct all_addr *addr,
444 time_t now, unsigned long ttl, unsigned short flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000445{
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000446 struct crec *new;
447 union bigname *big_name = NULL;
448 int freed_all = flags & F_REVERSE;
Simon Kelley9e038942008-05-30 20:06:34 +0100449 int free_avail = 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000450
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000451 /* Don't log DNSSEC records here, done elsewhere */
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000452 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
Simon Kelleya0ab18f2014-02-13 16:38:23 +0000453 {
454 log_query(flags | F_UPSTREAM, name, addr, NULL);
455 /* Don;t mess with TTL for DNSSEC records. */
456 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
457 ttl = daemon->max_cache_ttl;
458 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000459
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000460 /* if previous insertion failed give up now. */
461 if (insert_error)
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100462 return NULL;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000463
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000464 /* First remove any expired entries and entries for the name/address we
Simon Kelleyc8ca33f2014-02-10 10:35:42 +0000465 are currently inserting. Fail if we attempt to delete a name from
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000466 /etc/hosts or DHCP. */
467 if (!cache_scan_free(name, addr, now, flags))
468 {
469 insert_error = 1;
470 return NULL;
471 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000472
473 /* Now get a cache entry from the end of the LRU list */
474 while (1) {
475 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
476 {
477 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100478 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000479 }
480
481 /* End of LRU list is still in use: if we didn't scan all the hash
482 chains for expired entries do that now. If we already tried that
483 then it's time to start spilling things. */
484
485 if (new->flags & (F_FORWARD | F_REVERSE))
486 {
Simon Kelley9e038942008-05-30 20:06:34 +0100487 /* If free_avail set, we believe that an entry has been freed.
488 Bugs have been known to make this not true, resulting in
Simon Kelley1a6bca82008-07-11 11:11:42 +0100489 a tight loop here. If that happens, abandon the
Simon Kelley9e038942008-05-30 20:06:34 +0100490 insert. Once in this state, all inserts will probably fail. */
Simon Kelley9e038942008-05-30 20:06:34 +0100491 if (free_avail)
492 {
Simon Kelley5f938532014-02-03 16:44:32 +0000493 static int warned = 0;
Simon Kelley8d718cb2014-02-03 16:27:37 +0000494 if (!warned)
495 {
496 my_syslog(LOG_ERR, _("Internal error in cache."));
497 warned = 1;
498 }
Simon Kelley1a6bca82008-07-11 11:11:42 +0100499 insert_error = 1;
Simon Kelley9e038942008-05-30 20:06:34 +0100500 return NULL;
501 }
502
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000503 if (freed_all)
504 {
Simon Kelley8d718cb2014-02-03 16:27:37 +0000505 struct all_addr free_addr = new->addr.addr;;
506
507#ifdef HAVE_DNSSEC
508 /* For DNSSEC records, addr holds class and type_covered for RRSIG */
509 if (new->flags & (F_DS | F_DNSKEY))
510 {
511 free_addr.addr.dnssec.class = new->uid;
512 if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
513 free_addr.addr.dnssec.type = new->addr.sig.type_covered;
514 }
515#endif
516
Simon Kelley9e038942008-05-30 20:06:34 +0100517 free_avail = 1; /* Must be free space now. */
Simon Kelley8d718cb2014-02-03 16:27:37 +0000518 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000519 cache_live_freed++;
520 }
521 else
522 {
523 cache_scan_free(NULL, NULL, now, 0);
524 freed_all = 1;
525 }
526 continue;
527 }
528
529 /* Check if we need to and can allocate extra memory for a long name.
Simon Kelley8d718cb2014-02-03 16:27:37 +0000530 If that fails, give up now, always succeed for DNSSEC records. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000531 if (name && (strlen(name) > SMALLDNAME-1))
532 {
533 if (big_free)
534 {
535 big_name = big_free;
536 big_free = big_free->next;
537 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000538 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
Simon Kelley5aabfc72007-08-29 11:24:47 +0100539 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000540 {
541 insert_error = 1;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100542 return NULL;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000543 }
Simon Kelley8d718cb2014-02-03 16:27:37 +0000544 else if (bignames_left != 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000545 bignames_left--;
546
547 }
548
549 /* Got the rest: finally grab entry. */
550 cache_unlink(new);
551 break;
552 }
553
554 new->flags = flags;
555 if (big_name)
556 {
557 new->name.bname = big_name;
558 new->flags |= F_BIGNAME;
559 }
Simon Kelley5aabfc72007-08-29 11:24:47 +0100560
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000561 if (name)
562 strcpy(cache_get_name(new), name);
563 else
564 *cache_get_name(new) = 0;
Simon Kelley5aabfc72007-08-29 11:24:47 +0100565
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000566 if (addr)
Simon Kelley5aabfc72007-08-29 11:24:47 +0100567 new->addr.addr = *addr;
Simon Kelley7b4ad2e2012-04-04 14:05:35 +0100568
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000569 new->ttd = now + (time_t)ttl;
570 new->next = new_chain;
571 new_chain = new;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100572
573 return new;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000574}
575
576/* after end of insertion, commit the new entries */
577void cache_end_insert(void)
578{
579 if (insert_error)
580 return;
581
582 while (new_chain)
583 {
584 struct crec *tmp = new_chain->next;
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100585 /* drop CNAMEs which didn't find a target. */
586 if (is_outdated_cname_pointer(new_chain))
587 cache_free(new_chain);
588 else
589 {
590 cache_hash(new_chain);
591 cache_link(new_chain);
592 cache_inserted++;
593 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000594 new_chain = tmp;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000595 }
596 new_chain = NULL;
597}
598
Simon Kelley12fae492014-02-04 22:03:06 +0000599struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000600{
601 struct crec *ans;
Simon Kelley12fae492014-02-04 22:03:06 +0000602 int no_rr = prot & F_NO_RR;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000603
Simon Kelley12fae492014-02-04 22:03:06 +0000604 prot &= ~F_NO_RR;
605
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000606 if (crecp) /* iterating */
607 ans = crecp->next;
608 else
609 {
610 /* first search, look for relevant entries and push to top of list
611 also free anything which has expired */
612 struct crec *next, **up, **insert = NULL, **chainp = &ans;
Simon Kelley28866e92011-02-14 20:19:14 +0000613 unsigned short ins_flags = 0;
Simon Kelley824af852008-02-12 20:43:05 +0000614
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000615 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
616 {
617 next = crecp->hash_next;
618
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000619 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000620 {
621 if ((crecp->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000622#ifdef HAVE_DNSSEC
623 ((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
624#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000625 (crecp->flags & prot) &&
626 hostname_isequal(cache_get_name(crecp), name))
627 {
Simon Kelley25439062013-11-25 21:14:51 +0000628 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000629 {
630 *chainp = crecp;
631 chainp = &crecp->next;
632 }
633 else
634 {
635 cache_unlink(crecp);
636 cache_link(crecp);
637 }
638
Simon Kelley824af852008-02-12 20:43:05 +0000639 /* Move all but the first entry up the hash chain
640 this implements round-robin.
641 Make sure that re-ordering doesn't break the hash-chain
642 order invariants.
643 */
Simon Kelley9e038942008-05-30 20:06:34 +0100644 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000645 {
646 *up = crecp->hash_next;
647 crecp->hash_next = *insert;
648 *insert = crecp;
649 insert = &crecp->hash_next;
650 }
Simon Kelley9e038942008-05-30 20:06:34 +0100651 else
652 {
Simon Kelley12fae492014-02-04 22:03:06 +0000653 if (!insert && !no_rr)
Simon Kelley9e038942008-05-30 20:06:34 +0100654 {
655 insert = up;
656 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
657 }
658 up = &crecp->hash_next;
659 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000660 }
661 else
662 /* case : not expired, incorrect entry. */
663 up = &crecp->hash_next;
664 }
665 else
666 {
667 /* expired entry, free it */
668 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000669 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000670 {
671 cache_unlink(crecp);
672 cache_free(crecp);
673 }
674 }
675 }
676
677 *chainp = cache_head;
678 }
679
680 if (ans &&
681 (ans->flags & F_FORWARD) &&
Simon Kelley51ea3ca2014-01-22 19:31:38 +0000682#ifdef HAVE_DNSSEC
683 ((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
684#endif
685 (ans->flags & prot) &&
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000686 hostname_isequal(cache_get_name(ans), name))
687 return ans;
688
689 return NULL;
690}
691
692struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
Simon Kelley12fae492014-02-04 22:03:06 +0000693 time_t now, unsigned int prot)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000694{
695 struct crec *ans;
696#ifdef HAVE_IPV6
697 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
698#else
699 int addrlen = INADDRSZ;
700#endif
701
702 if (crecp) /* iterating */
703 ans = crecp->next;
704 else
705 {
706 /* first search, look for relevant entries and push to top of list
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000707 also free anything which has expired. All the reverse entries are at the
708 start of the hash chain, so we can give up when we find the first
709 non-REVERSE one. */
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000710 int i;
711 struct crec **up, **chainp = &ans;
712
Simon Kelley1b7ecd12007-02-05 14:57:57 +0000713 for (i=0; i<hash_size; i++)
714 for (crecp = hash_table[i], up = &hash_table[i];
715 crecp && (crecp->flags & F_REVERSE);
716 crecp = crecp->hash_next)
Simon Kelleyf6b7dc42005-01-23 12:06:08 +0000717 if (!is_expired(now, crecp))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000718 {
Simon Kelley6b010842007-02-12 20:32:07 +0000719 if ((crecp->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100720 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000721 {
Simon Kelley25439062013-11-25 21:14:51 +0000722 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000723 {
724 *chainp = crecp;
725 chainp = &crecp->next;
726 }
727 else
728 {
729 cache_unlink(crecp);
730 cache_link(crecp);
731 }
732 }
733 up = &crecp->hash_next;
734 }
735 else
736 {
737 *up = crecp->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +0000738 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000739 {
740 cache_unlink(crecp);
741 cache_free(crecp);
742 }
743 }
744
745 *chainp = cache_head;
746 }
747
748 if (ans &&
749 (ans->flags & F_REVERSE) &&
750 (ans->flags & prot) &&
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100751 memcmp(&ans->addr.addr, addr, addrlen) == 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000752 return ans;
753
754 return NULL;
755}
756
Simon Kelley611ebc52012-07-16 16:23:46 +0100757static void add_hosts_cname(struct crec *target)
758{
759 struct crec *crec;
760 struct cname *a;
761
762 for (a = daemon->cnames; a; a = a->next)
763 if (hostname_isequal(cache_get_name(target), a->target) &&
764 (crec = whine_malloc(sizeof(struct crec))))
765 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000766 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
Simon Kelley611ebc52012-07-16 16:23:46 +0100767 crec->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100768 crec->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +0100769 crec->addr.cname.uid = target->uid;
770 cache_hash(crec);
771 add_hosts_cname(crec); /* handle chains */
772 }
773}
774
Simon Kelleyfd9fa482004-10-21 20:24:00 +0100775static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
Simon Kelleye759d422012-03-16 13:18:57 +0000776 int index, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000777{
Simon Kelleye759d422012-03-16 13:18:57 +0000778 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 +0000779 int i, nameexists = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000780 unsigned int j;
Simon Kelley9009d742008-11-14 20:04:27 +0000781
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000782 /* Remove duplicates in hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000783 if (lookup && (lookup->flags & F_HOSTS))
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000784 {
Simon Kelley9009d742008-11-14 20:04:27 +0000785 nameexists = 1;
786 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
787 {
788 free(cache);
789 return;
790 }
791 }
792
793 /* Ensure there is only one address -> name mapping (first one trumps)
Simon Kelley205fafa2012-01-11 21:31:51 +0000794 We do this by steam here, The entries are kept in hash chains, linked
795 by ->next (which is unused at this point) held in hash buckets in
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000796 the array rhash, hashed on address. Note that rhash and the values
797 in ->next are only valid whilst reading hosts files: the buckets are
798 then freed, and the ->next pointer used for other things.
Simon Kelley205fafa2012-01-11 21:31:51 +0000799
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000800 Only insert each unique address once into this hashing structure.
Simon Kelley205fafa2012-01-11 21:31:51 +0000801
802 This complexity avoids O(n^2) divergent CPU use whilst reading
803 large (10000 entry) hosts files. */
Simon Kelley9009d742008-11-14 20:04:27 +0000804
Simon Kelley205fafa2012-01-11 21:31:51 +0000805 /* hash address */
806 for (j = 0, i = 0; i < addrlen; i++)
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000807 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
Simon Kelley915363f2012-01-11 22:00:48 +0000808
809 for (lookup = rhash[j]; lookup; lookup = lookup->next)
Simon Kelleye759d422012-03-16 13:18:57 +0000810 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
Simon Kelley205fafa2012-01-11 21:31:51 +0000811 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
Simon Kelley9009d742008-11-14 20:04:27 +0000812 {
Simon Kelleye759d422012-03-16 13:18:57 +0000813 cache->flags &= ~F_REVERSE;
Simon Kelley205fafa2012-01-11 21:31:51 +0000814 break;
Simon Kelley9009d742008-11-14 20:04:27 +0000815 }
816
Simon Kelley915363f2012-01-11 22:00:48 +0000817 /* maintain address hash chain, insert new unique address */
818 if (!lookup)
819 {
820 cache->next = rhash[j];
821 rhash[j] = cache;
822 }
823
Simon Kelley9009d742008-11-14 20:04:27 +0000824 cache->uid = index;
Simon Kelley915363f2012-01-11 22:00:48 +0000825 memcpy(&cache->addr.addr, addr, addrlen);
Simon Kelley9009d742008-11-14 20:04:27 +0000826 cache_hash(cache);
827
828 /* don't need to do alias stuff for second and subsequent addresses. */
829 if (!nameexists)
Simon Kelley611ebc52012-07-16 16:23:46 +0100830 add_hosts_cname(cache);
Simon Kelley9009d742008-11-14 20:04:27 +0000831}
832
833static int eatspace(FILE *f)
834{
835 int c, nl = 0;
836
837 while (1)
838 {
839 if ((c = getc(f)) == '#')
840 while (c != '\n' && c != EOF)
841 c = getc(f);
Simon Kelley832af0b2007-01-21 20:01:28 +0000842
Simon Kelley9009d742008-11-14 20:04:27 +0000843 if (c == EOF)
844 return 1;
845
846 if (!isspace(c))
847 {
848 ungetc(c, f);
849 return nl;
850 }
851
852 if (c == '\n')
853 nl = 1;
854 }
855}
856
857static int gettok(FILE *f, char *token)
858{
859 int c, count = 0;
860
861 while (1)
862 {
863 if ((c = getc(f)) == EOF)
864 return (count == 0) ? EOF : 1;
865
866 if (isspace(c) || c == '#')
867 {
868 ungetc(c, f);
869 return eatspace(f);
870 }
871
872 if (count < (MAXDNAME - 1))
873 {
874 token[count++] = c;
875 token[count] = 0;
876 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000877 }
878}
879
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000880static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000881{
882 FILE *f = fopen(filename, "r");
Simon Kelley9009d742008-11-14 20:04:27 +0000883 char *token = daemon->namebuff, *domain_suffix = NULL;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100884 int addr_count = 0, name_count = cache_size, lineno = 0;
Simon Kelley205fafa2012-01-11 21:31:51 +0000885 unsigned short flags = 0;
886 struct all_addr addr;
887 int atnl, addrlen = 0;
Simon Kelley4011c4e2006-10-28 16:26:19 +0100888
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000889 if (!f)
890 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100891 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
Simon Kelley4011c4e2006-10-28 16:26:19 +0100892 return 0;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000893 }
Simon Kelley9009d742008-11-14 20:04:27 +0000894
895 eatspace(f);
896
897 while ((atnl = gettok(f, token)) != EOF)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000898 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000899 lineno++;
Simon Kelley9009d742008-11-14 20:04:27 +0000900
Simon Kelley3d8df262005-08-29 12:19:27 +0100901 if (inet_pton(AF_INET, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000902 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000903 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000904 addrlen = INADDRSZ;
Simon Kelley9009d742008-11-14 20:04:27 +0000905 domain_suffix = get_domain(addr.addr.addr4);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000906 }
Simon Kelleye759d422012-03-16 13:18:57 +0000907#ifdef HAVE_IPV6
Simon Kelley3d8df262005-08-29 12:19:27 +0100908 else if (inet_pton(AF_INET6, token, &addr) > 0)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000909 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +0000910 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000911 addrlen = IN6ADDRSZ;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000912 domain_suffix = get_domain6(&addr.addr.addr6);
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000913 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000914#endif
915 else
Simon Kelleyb8187c82005-11-26 21:46:27 +0000916 {
Simon Kelleyf2621c72007-04-29 19:47:21 +0100917 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
Simon Kelley9009d742008-11-14 20:04:27 +0000918 while (atnl == 0)
919 atnl = gettok(f, token);
Simon Kelleyb8187c82005-11-26 21:46:27 +0000920 continue;
921 }
Simon Kelley9009d742008-11-14 20:04:27 +0000922
Simon Kelley9009d742008-11-14 20:04:27 +0000923 addr_count++;
924
925 /* rehash every 1000 names. */
926 if ((name_count - cache_size) > 1000)
927 {
928 rehash(name_count);
929 cache_size = name_count;
930 }
931
932 while (atnl == 0)
933 {
934 struct crec *cache;
Simon Kelley1f15b812009-10-13 17:49:32 +0100935 int fqdn, nomem;
936 char *canon;
Simon Kelley9009d742008-11-14 20:04:27 +0000937
938 if ((atnl = gettok(f, token)) == EOF)
939 break;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000940
Simon Kelley9009d742008-11-14 20:04:27 +0000941 fqdn = !!strchr(token, '.');
942
Simon Kelley1f15b812009-10-13 17:49:32 +0100943 if ((canon = canonicalise(token, &nomem)))
Simon Kelley9009d742008-11-14 20:04:27 +0000944 {
945 /* If set, add a version of the name with a default domain appended */
Simon Kelley28866e92011-02-14 20:19:14 +0000946 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
Simon Kelley9009d742008-11-14 20:04:27 +0000947 (cache = whine_malloc(sizeof(struct crec) +
Simon Kelley1f15b812009-10-13 17:49:32 +0100948 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000949 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100950 strcpy(cache->name.sname, canon);
Simon Kelley9009d742008-11-14 20:04:27 +0000951 strcat(cache->name.sname, ".");
952 strcat(cache->name.sname, domain_suffix);
Simon Kelleye759d422012-03-16 13:18:57 +0000953 cache->flags = flags;
954 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000955 name_count++;
956 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100957 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
Simon Kelley9009d742008-11-14 20:04:27 +0000958 {
Simon Kelley1f15b812009-10-13 17:49:32 +0100959 strcpy(cache->name.sname, canon);
Simon Kelleye759d422012-03-16 13:18:57 +0000960 cache->flags = flags;
961 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
Simon Kelley9009d742008-11-14 20:04:27 +0000962 name_count++;
963 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100964 free(canon);
965
Simon Kelley9009d742008-11-14 20:04:27 +0000966 }
Simon Kelley1f15b812009-10-13 17:49:32 +0100967 else if (!nomem)
Simon Kelley9009d742008-11-14 20:04:27 +0000968 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
969 }
970 }
971
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000972 fclose(f);
Simon Kelley4011c4e2006-10-28 16:26:19 +0100973 rehash(name_count);
Simon Kelley9009d742008-11-14 20:04:27 +0000974
Simon Kelleyf2621c72007-04-29 19:47:21 +0100975 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
Simon Kelley9009d742008-11-14 20:04:27 +0000976
Simon Kelley4011c4e2006-10-28 16:26:19 +0100977 return name_count;
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000978}
979
Simon Kelley7622fc02009-06-04 20:32:05 +0100980void cache_reload(void)
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000981{
982 struct crec *cache, **up, *tmp;
Simon Kelley1ab62ae2012-01-12 11:33:16 +0000983 int revhashsz, i, total_size = daemon->cachesize;
Simon Kelley7622fc02009-06-04 20:32:05 +0100984 struct hostsfile *ah;
Simon Kelleye759d422012-03-16 13:18:57 +0000985 struct host_record *hr;
986 struct name_list *nl;
Simon Kelleyd56a6042013-10-11 14:39:03 +0100987 struct cname *a;
988 struct interface_name *intr;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000989#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +0000990 struct ds_config *ds;
Simon Kelley0fc2f312014-01-08 10:26:58 +0000991#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000992
Simon Kelley59353a62004-11-21 19:34:28 +0000993 cache_inserted = cache_live_freed = 0;
994
Simon Kelley9e4abcb2004-01-22 19:47:41 +0000995 for (i=0; i<hash_size; i++)
996 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
997 {
Simon Kelley0fc2f312014-01-08 10:26:58 +0000998#ifdef HAVE_DNSSEC
Simon Kelley82e3f452014-01-31 21:05:48 +0000999 cache_blockdata_free(cache);
Simon Kelley0fc2f312014-01-08 10:26:58 +00001000#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001001 tmp = cache->hash_next;
Simon Kelley25439062013-11-25 21:14:51 +00001002 if (cache->flags & (F_HOSTS | F_CONFIG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001003 {
1004 *up = cache->hash_next;
1005 free(cache);
1006 }
1007 else if (!(cache->flags & F_DHCP))
1008 {
1009 *up = cache->hash_next;
1010 if (cache->flags & F_BIGNAME)
1011 {
1012 cache->name.bname->next = big_free;
1013 big_free = cache->name.bname;
1014 }
1015 cache->flags = 0;
1016 }
1017 else
1018 up = &cache->hash_next;
1019 }
1020
Simon Kelleyd56a6042013-10-11 14:39:03 +01001021 /* Add CNAMEs to interface_names to the cache */
1022 for (a = daemon->cnames; a; a = a->next)
1023 for (intr = daemon->int_names; intr; intr = intr->next)
Simon Kelley532066e2013-11-26 10:14:47 +00001024 if (hostname_isequal(a->target, intr->name) &&
1025 ((cache = whine_malloc(sizeof(struct crec)))))
Simon Kelleyd56a6042013-10-11 14:39:03 +01001026 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001027 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
Simon Kelley532066e2013-11-26 10:14:47 +00001028 cache->name.namep = a->alias;
1029 cache->addr.cname.target.int_name = intr;
1030 cache->addr.cname.uid = -1;
1031 cache_hash(cache);
1032 add_hosts_cname(cache); /* handle chains */
Simon Kelleyd56a6042013-10-11 14:39:03 +01001033 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001034
1035#ifdef HAVE_DNSSEC
Simon Kelleyee415862014-02-11 11:07:22 +00001036 for (ds = daemon->ds; ds; ds = ds->next)
Simon Kelley0fc2f312014-01-08 10:26:58 +00001037 if ((cache = whine_malloc(sizeof(struct crec))) &&
Simon Kelleyee415862014-02-11 11:07:22 +00001038 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001039 {
Simon Kelleyee415862014-02-11 11:07:22 +00001040 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
1041 cache->name.namep = ds->name;
1042 cache->addr.ds.keylen = ds->digestlen;
1043 cache->addr.ds.algo = ds->algo;
1044 cache->addr.ds.keytag = ds->keytag;
1045 cache->addr.ds.digest = ds->digest_type;
1046 cache->uid = ds->class;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001047 cache_hash(cache);
1048 }
1049#endif
Simon Kelleyd56a6042013-10-11 14:39:03 +01001050
Simon Kelleye759d422012-03-16 13:18:57 +00001051 /* borrow the packet buffer for a temporary by-address hash */
1052 memset(daemon->packet, 0, daemon->packet_buff_sz);
1053 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1054 /* we overwrote the buffer... */
1055 daemon->srv_save = NULL;
1056
1057 /* Do host_records in config. */
1058 for (hr = daemon->host_records; hr; hr = hr->next)
1059 for (nl = hr->names; nl; nl = nl->next)
1060 {
1061 if (hr->addr.s_addr != 0 &&
1062 (cache = whine_malloc(sizeof(struct crec))))
1063 {
1064 cache->name.namep = nl->name;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001065 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
Simon Kelleye759d422012-03-16 13:18:57 +00001066 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
1067 }
1068#ifdef HAVE_IPV6
1069 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1070 (cache = whine_malloc(sizeof(struct crec))))
1071 {
1072 cache->name.namep = nl->name;
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001073 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
Simon Kelleye759d422012-03-16 13:18:57 +00001074 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
1075 }
1076#endif
1077 }
1078
Simon Kelley28866e92011-02-14 20:19:14 +00001079 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001080 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001081 if (daemon->cachesize > 0)
Simon Kelleyf2621c72007-04-29 19:47:21 +01001082 my_syslog(LOG_INFO, _("cleared cache"));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001083 return;
1084 }
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001085
Simon Kelley28866e92011-02-14 20:19:14 +00001086 if (!option_bool(OPT_NO_HOSTS))
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001087 total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
Simon Kelley28866e92011-02-14 20:19:14 +00001088
1089 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
Simon Kelley7622fc02009-06-04 20:32:05 +01001090 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1091 if (!(ah->flags & AH_INACTIVE))
Simon Kelley1ab62ae2012-01-12 11:33:16 +00001092 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001093}
1094
Simon Kelley7622fc02009-06-04 20:32:05 +01001095#ifdef HAVE_DHCP
Simon Kelley7de060b2011-08-26 17:24:52 +01001096struct in_addr a_record_from_hosts(char *name, time_t now)
1097{
1098 struct crec *crecp = NULL;
1099 struct in_addr ret;
1100
1101 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1102 if (crecp->flags & F_HOSTS)
1103 return *(struct in_addr *)&crecp->addr;
1104
1105 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1106
1107 ret.s_addr = 0;
1108 return ret;
1109}
1110
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001111void cache_unhash_dhcp(void)
1112{
Simon Kelley6b010842007-02-12 20:32:07 +00001113 struct crec *cache, **up;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001114 int i;
1115
1116 for (i=0; i<hash_size; i++)
1117 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1118 if (cache->flags & F_DHCP)
Simon Kelley6b010842007-02-12 20:32:07 +00001119 {
1120 *up = cache->hash_next;
1121 cache->next = dhcp_spare;
1122 dhcp_spare = cache;
1123 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001124 else
1125 up = &cache->hash_next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001126}
1127
Simon Kelley611ebc52012-07-16 16:23:46 +01001128static void add_dhcp_cname(struct crec *target, time_t ttd)
1129{
1130 struct crec *aliasc;
1131 struct cname *a;
1132
1133 for (a = daemon->cnames; a; a = a->next)
1134 if (hostname_isequal(cache_get_name(target), a->target))
1135 {
1136 if ((aliasc = dhcp_spare))
1137 dhcp_spare = dhcp_spare->next;
1138 else /* need new one */
1139 aliasc = whine_malloc(sizeof(struct crec));
1140
1141 if (aliasc)
1142 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001143 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
Simon Kelley611ebc52012-07-16 16:23:46 +01001144 if (ttd == 0)
1145 aliasc->flags |= F_IMMORTAL;
1146 else
1147 aliasc->ttd = ttd;
1148 aliasc->name.namep = a->alias;
Simon Kelleyd56a6042013-10-11 14:39:03 +01001149 aliasc->addr.cname.target.cache = target;
Simon Kelley611ebc52012-07-16 16:23:46 +01001150 aliasc->addr.cname.uid = target->uid;
1151 cache_hash(aliasc);
1152 add_dhcp_cname(aliasc, ttd);
1153 }
1154 }
1155}
1156
Simon Kelley4cb1b322012-02-06 14:30:41 +00001157void cache_add_dhcp_entry(char *host_name, int prot,
1158 struct all_addr *host_address, time_t ttd)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001159{
Simon Kelley12d71ed2012-08-30 15:16:41 +01001160 struct crec *crec = NULL, *fail_crec = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001161 unsigned short flags = F_IPV4;
Simon Kelley824af852008-02-12 20:43:05 +00001162 int in_hosts = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001163 size_t addrlen = sizeof(struct in_addr);
1164
1165#ifdef HAVE_IPV6
1166 if (prot == AF_INET6)
1167 {
1168 flags = F_IPV6;
1169 addrlen = sizeof(struct in6_addr);
1170 }
1171#endif
Simon Kelley9009d742008-11-14 20:04:27 +00001172
Simon Kelley12d71ed2012-08-30 15:16:41 +01001173 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1174
Simon Kelley4cb1b322012-02-06 14:30:41 +00001175 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001176 {
Simon Kelley824af852008-02-12 20:43:05 +00001177 /* check all addresses associated with name */
Simon Kelley25439062013-11-25 21:14:51 +00001178 if (crec->flags & (F_HOSTS | F_CONFIG))
Simon Kelley1ab84e22004-01-29 16:48:35 +00001179 {
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001180 if (crec->flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001181 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelley8ef5ada2010-06-03 19:42:45 +01001182 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
Simon Kelley4cb1b322012-02-06 14:30:41 +00001183 host_name, daemon->addrbuff);
Simon Kelley12d71ed2012-08-30 15:16:41 +01001184 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1185 in_hosts = 1;
1186 else
1187 fail_crec = crec;
Simon Kelley1ab84e22004-01-29 16:48:35 +00001188 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001189 else if (!(crec->flags & F_DHCP))
Simon Kelley824af852008-02-12 20:43:05 +00001190 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001191 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
Simon Kelley824af852008-02-12 20:43:05 +00001192 /* scan_free deletes all addresses associated with name */
1193 break;
1194 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001195 }
Simon Kelley824af852008-02-12 20:43:05 +00001196
Simon Kelley12d71ed2012-08-30 15:16:41 +01001197 /* if in hosts, don't need DHCP record */
1198 if (in_hosts)
Simon Kelley824af852008-02-12 20:43:05 +00001199 return;
Simon Kelley12d71ed2012-08-30 15:16:41 +01001200
1201 /* Name in hosts, address doesn't match */
1202 if (fail_crec)
1203 {
1204 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1205 my_syslog(MS_DHCP | LOG_WARNING,
1206 _("not giving name %s to the DHCP lease of %s because "
1207 "the name exists in %s with address %s"),
1208 host_name, daemon->addrbuff,
1209 record_source(fail_crec->uid), daemon->namebuff);
1210 return;
1211 }
1212
1213 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1214 {
1215 if (crec->flags & F_NEG)
1216 {
1217 flags |= F_REVERSE;
1218 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1219 }
1220 }
1221 else
1222 flags |= F_REVERSE;
1223
1224 if ((crec = dhcp_spare))
Simon Kelley6b010842007-02-12 20:32:07 +00001225 dhcp_spare = dhcp_spare->next;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001226 else /* need new one */
Simon Kelley5aabfc72007-08-29 11:24:47 +01001227 crec = whine_malloc(sizeof(struct crec));
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001228
1229 if (crec) /* malloc may fail */
1230 {
Simon Kelleybce6e1b2014-01-23 22:02:19 +00001231 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001232 if (ttd == 0)
1233 crec->flags |= F_IMMORTAL;
1234 else
1235 crec->ttd = ttd;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001236 crec->addr.addr = *host_address;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001237 crec->name.namep = host_name;
Simon Kelley9009d742008-11-14 20:04:27 +00001238 crec->uid = uid++;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001239 cache_hash(crec);
Simon Kelley9009d742008-11-14 20:04:27 +00001240
Simon Kelley611ebc52012-07-16 16:23:46 +01001241 add_dhcp_cname(crec, ttd);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001242 }
1243}
Simon Kelley7622fc02009-06-04 20:32:05 +01001244#endif
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001245
Simon Kelley9009d742008-11-14 20:04:27 +00001246
Simon Kelley5aabfc72007-08-29 11:24:47 +01001247void dump_cache(time_t now)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001248{
Simon Kelley824af852008-02-12 20:43:05 +00001249 struct server *serv, *serv1;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001250 char *t = "";
Simon Kelley824af852008-02-12 20:43:05 +00001251
1252 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1253 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1254 daemon->cachesize, cache_live_freed, cache_inserted);
1255 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1256 daemon->queries_forwarded, daemon->local_answer);
Simon Kelleyb485ed92013-10-18 22:00:39 +01001257#ifdef HAVE_AUTH
1258 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
1259#endif
Simon Kelleyc2207682014-01-08 18:04:20 +00001260#ifdef HAVE_DNSSEC
1261 blockdata_report();
1262#endif
Simon Kelley824af852008-02-12 20:43:05 +00001263
Simon Kelley824af852008-02-12 20:43:05 +00001264 /* sum counts from different records for same server */
1265 for (serv = daemon->servers; serv; serv = serv->next)
1266 serv->flags &= ~SERV_COUNTED;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001267
Simon Kelley824af852008-02-12 20:43:05 +00001268 for (serv = daemon->servers; serv; serv = serv->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001269 if (!(serv->flags &
1270 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
Simon Kelley824af852008-02-12 20:43:05 +00001271 {
1272 int port;
1273 unsigned int queries = 0, failed_queries = 0;
1274 for (serv1 = serv; serv1; serv1 = serv1->next)
Simon Kelley28866e92011-02-14 20:19:14 +00001275 if (!(serv1->flags &
1276 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1277 sockaddr_isequal(&serv->addr, &serv1->addr))
Simon Kelley824af852008-02-12 20:43:05 +00001278 {
1279 serv1->flags |= SERV_COUNTED;
1280 queries += serv1->queries;
1281 failed_queries += serv1->failed_queries;
1282 }
Simon Kelleyc72daea2012-01-05 21:33:27 +00001283 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1284 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 +00001285 }
1286
Simon Kelley28866e92011-02-14 20:19:14 +00001287 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001288 {
1289 struct crec *cache ;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001290 int i;
Simon Kelleye7829ae2014-01-22 22:21:51 +00001291 my_syslog(LOG_INFO, "Host Address Flags Expires");
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001292
1293 for (i=0; i<hash_size; i++)
1294 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1295 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001296 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1297 *a = 0;
Simon Kelley2d33bda2014-01-24 22:37:25 +00001298 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
Simon Kelley0fc2f312014-01-08 10:26:58 +00001299 n = "<Root>";
1300 p += sprintf(p, "%-40.40s ", n);
1301 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
1302 a = cache_get_cname_target(cache);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001303#ifdef HAVE_DNSSEC
Simon Kelleycdbee9a2012-04-04 21:55:59 +01001304 else if (cache->flags & F_DS)
1305 {
Simon Kelleye7829ae2014-01-22 22:21:51 +00001306 if (cache->flags & F_DNSKEY)
1307 {
Simon Kelleye7829ae2014-01-22 22:21:51 +00001308 /* RRSIG */
Simon Kelleye7829ae2014-01-22 22:21:51 +00001309 a = daemon->addrbuff;
1310 sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
Simon Kelley610e7822014-02-06 14:45:17 +00001311 cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
Simon Kelleye7829ae2014-01-22 22:21:51 +00001312 }
1313 else
1314 {
1315 a = daemon->addrbuff;
1316 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1317 cache->addr.ds.algo, cache->addr.ds.digest);
1318 }
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001319 }
1320 else if (cache->flags & F_DNSKEY)
1321 {
1322 a = daemon->addrbuff;
Simon Kelley0fc2f312014-01-08 10:26:58 +00001323 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
Simon Kelley51ea3ca2014-01-22 19:31:38 +00001324 cache->addr.key.algo, cache->addr.key.flags);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001325 }
1326#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001327 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
Simon Kelleyf2621c72007-04-29 19:47:21 +01001328 {
Simon Kelleyc72daea2012-01-05 21:33:27 +00001329 a = daemon->addrbuff;
Simon Kelleyf2621c72007-04-29 19:47:21 +01001330 if (cache->flags & F_IPV4)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001331 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001332#ifdef HAVE_IPV6
Simon Kelleyf2621c72007-04-29 19:47:21 +01001333 else if (cache->flags & F_IPV6)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001334 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001335#endif
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001336 }
1337
Simon Kelleye7829ae2014-01-22 22:21:51 +00001338 if (cache->flags & F_IPV4)
1339 t = "4";
1340 else if (cache->flags & F_IPV6)
1341 t = "6";
1342 else if (cache->flags & F_CNAME)
1343 t = "C";
1344#ifdef HAVE_DNSSEC
1345 else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
1346 t = "G"; /* DNSKEY and DS set -> RRISG */
1347 else if (cache->flags & F_DS)
1348 t = "S";
1349 else if (cache->flags & F_DNSKEY)
1350 t = "K";
1351#endif
1352 p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s ", a, t,
Simon Kelleyf2621c72007-04-29 19:47:21 +01001353 cache->flags & F_FORWARD ? "F" : " ",
1354 cache->flags & F_REVERSE ? "R" : " ",
1355 cache->flags & F_IMMORTAL ? "I" : " ",
1356 cache->flags & F_DHCP ? "D" : " ",
1357 cache->flags & F_NEG ? "N" : " ",
1358 cache->flags & F_NXDOMAIN ? "X" : " ",
Simon Kelley7b4ad2e2012-04-04 14:05:35 +01001359 cache->flags & F_HOSTS ? "H" : " ",
1360 cache->flags & F_DNSSECOK ? "V" : " ");
Simon Kelley44a2a312004-03-10 20:04:35 +00001361#ifdef HAVE_BROKEN_RTC
Simon Kelleyf2621c72007-04-29 19:47:21 +01001362 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
Simon Kelley44a2a312004-03-10 20:04:35 +00001363#else
Simon Kelleyf2621c72007-04-29 19:47:21 +01001364 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1365 /* ctime includes trailing \n - eat it */
1366 *(p-1) = 0;
Simon Kelley44a2a312004-03-10 20:04:35 +00001367#endif
Simon Kelley28866e92011-02-14 20:19:14 +00001368 my_syslog(LOG_INFO, daemon->namebuff);
Simon Kelleyf2621c72007-04-29 19:47:21 +01001369 }
1370 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001371}
1372
Simon Kelley7622fc02009-06-04 20:32:05 +01001373char *record_source(int index)
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001374{
Simon Kelley7622fc02009-06-04 20:32:05 +01001375 struct hostsfile *ah;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001376
Simon Kelley7622fc02009-06-04 20:32:05 +01001377 if (index == 0)
1378 return HOSTSFILE;
1379
1380 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1381 if (ah->index == index)
1382 return ah->fname;
1383
1384 return "<unknown>";
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001385}
Simon Kelleyc1bb8502004-08-11 18:40:17 +01001386
Simon Kelley610e7822014-02-06 14:45:17 +00001387char *querystr(char *desc, unsigned short type)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001388{
1389 unsigned int i;
Simon Kelley610e7822014-02-06 14:45:17 +00001390 int len = 10; /* strlen("type=xxxxx") */
1391 const char *types = NULL;
1392 static char *buff = NULL;
1393 static int bufflen = 0;
1394
Simon Kelley1a6bca82008-07-11 11:11:42 +01001395 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1396 if (typestr[i].type == type)
Simon Kelley610e7822014-02-06 14:45:17 +00001397 {
1398 types = typestr[i].name;
1399 len = strlen(types);
1400 break;
1401 }
1402
1403 len += 3; /* braces, terminator */
1404 len += strlen(desc);
1405
1406 if (!buff || bufflen < len)
1407 {
1408 if (buff)
1409 free(buff);
1410 else if (len < 20)
1411 len = 20;
1412
1413 buff = whine_malloc(len);
1414 bufflen = len;
1415 }
1416
1417 if (buff)
1418 {
1419 if (types)
1420 sprintf(buff, "%s[%s]", desc, types);
1421 else
1422 sprintf(buff, "%s[type=%d]", desc, type);
1423 }
1424
1425 return buff ? buff : "";
Simon Kelley1a6bca82008-07-11 11:11:42 +01001426}
1427
Simon Kelley28866e92011-02-14 20:19:14 +00001428void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001429{
Simon Kelleyc72daea2012-01-05 21:33:27 +00001430 char *source, *dest = daemon->addrbuff;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001431 char *verb = "is";
Simon Kelley5e9e0ef2006-04-17 14:24:29 +01001432
Simon Kelley28866e92011-02-14 20:19:14 +00001433 if (!option_bool(OPT_LOG))
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001434 return;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001435
1436 if (addr)
1437 {
Simon Kelley0fc2f312014-01-08 10:26:58 +00001438 if (flags & F_KEYTAG)
1439 sprintf(daemon->addrbuff, arg, addr->addr.keytag);
1440 else
1441 {
Simon Kelley5aabfc72007-08-29 11:24:47 +01001442#ifdef HAVE_IPV6
Simon Kelley0fc2f312014-01-08 10:26:58 +00001443 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1444 addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001445#else
Simon Kelley0fc2f312014-01-08 10:26:58 +00001446 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
Simon Kelley5aabfc72007-08-29 11:24:47 +01001447#endif
Simon Kelley0fc2f312014-01-08 10:26:58 +00001448 }
Simon Kelley5aabfc72007-08-29 11:24:47 +01001449 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001450 else
1451 dest = arg;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001452
1453 if (flags & F_REVERSE)
1454 {
1455 dest = name;
Simon Kelleyc72daea2012-01-05 21:33:27 +00001456 name = daemon->addrbuff;
Simon Kelley5aabfc72007-08-29 11:24:47 +01001457 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001458
1459 if (flags & F_NEG)
1460 {
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001461 if (flags & F_NXDOMAIN)
Simon Kelley40b695c2014-02-03 17:07:51 +00001462 dest = "NXDOMAIN";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001463 else
Simon Kelley5aabfc72007-08-29 11:24:47 +01001464 {
1465 if (flags & F_IPV4)
1466 dest = "NODATA-IPv4";
Simon Kelley824af852008-02-12 20:43:05 +00001467 else if (flags & F_IPV6)
Simon Kelley5aabfc72007-08-29 11:24:47 +01001468 dest = "NODATA-IPv6";
Simon Kelley824af852008-02-12 20:43:05 +00001469 else
1470 dest = "NODATA";
Simon Kelley5aabfc72007-08-29 11:24:47 +01001471 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001472 }
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001473 else if (flags & F_CNAME)
Simon Kelley28866e92011-02-14 20:19:14 +00001474 dest = "<CNAME>";
1475 else if (flags & F_RRNAME)
1476 dest = arg;
Simon Kelleyfd9fa482004-10-21 20:24:00 +01001477
Simon Kelley1f15b812009-10-13 17:49:32 +01001478 if (flags & F_CONFIG)
1479 source = "config";
1480 else if (flags & F_DHCP)
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001481 source = "DHCP";
1482 else if (flags & F_HOSTS)
Simon Kelley1a6bca82008-07-11 11:11:42 +01001483 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001484 else if (flags & F_UPSTREAM)
1485 source = "reply";
Simon Kelley0fc2f312014-01-08 10:26:58 +00001486 else if (flags & F_SECSTAT)
1487 source = "validation";
Simon Kelley4f7b3042012-11-28 21:27:02 +00001488 else if (flags & F_AUTH)
1489 source = "auth";
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001490 else if (flags & F_SERVER)
1491 {
1492 source = "forwarded";
1493 verb = "to";
1494 }
1495 else if (flags & F_QUERY)
1496 {
Simon Kelley1a6bca82008-07-11 11:11:42 +01001497 source = arg;
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001498 verb = "from";
1499 }
Simon Kelley0fc2f312014-01-08 10:26:58 +00001500 else if (flags & F_DNSSEC)
1501 {
1502 source = arg;
1503 verb = "to";
1504 }
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001505 else
1506 source = "cached";
1507
Simon Kelley3d8df262005-08-29 12:19:27 +01001508 if (strlen(name) == 0)
1509 name = ".";
1510
Simon Kelley28866e92011-02-14 20:19:14 +00001511 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
Simon Kelley9e4abcb2004-01-22 19:47:41 +00001512}
1513
Simon Kelley98c098b2014-01-08 17:31:16 +00001514