dnsmasq: update to 2.73 (23.06.2015)
[tomato.git] / release / src / router / dnsmasq / src / cache.c
blob9c5d4e5cfb534be9a9fca653aa4e7463c630a97e
1 /* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
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
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
8 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.
13 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/>.
17 #include "dnsmasq.h"
19 static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
20 #ifdef HAVE_DHCP
21 static struct crec *dhcp_spare = NULL;
22 #endif
23 static struct crec *new_chain = NULL;
24 static int cache_inserted = 0, cache_live_freed = 0, insert_error;
25 static union bigname *big_free = NULL;
26 static int bignames_left, hash_size;
28 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
29 static 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" },
49 { 35, "NAPTR" },
50 { 36, "KX" },
51 { 37, "CERT" },
52 { 38, "A6" },
53 { 39, "DNAME" },
54 { 41, "OPT" },
55 { 43, "DS" },
56 { 46, "RRSIG" },
57 { 47, "NSEC" },
58 { 48, "DNSKEY" },
59 { 50, "NSEC3" },
60 { 249, "TKEY" },
61 { 250, "TSIG" },
62 { 251, "IXFR" },
63 { 252, "AXFR" },
64 { 253, "MAILB" },
65 { 254, "MAILA" },
66 { 255, "ANY" }
69 static void cache_free(struct crec *crecp);
70 static void cache_unlink(struct crec *crecp);
71 static void cache_link(struct crec *crecp);
72 static void rehash(int size);
73 static void cache_hash(struct crec *crecp);
75 static unsigned int next_uid(void)
77 static unsigned int uid = 0;
79 uid++;
81 /* uid == 0 used to indicate CNAME to interface name. */
82 if (uid == SRC_INTERFACE)
83 uid++;
85 return uid;
88 void cache_init(void)
90 struct crec *crecp;
91 int i;
93 bignames_left = daemon->cachesize/10;
95 if (daemon->cachesize > 0)
97 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
99 for (i=0; i < daemon->cachesize; i++, crecp++)
101 cache_link(crecp);
102 crecp->flags = 0;
103 crecp->uid = next_uid();
107 /* create initial hash table*/
108 rehash(daemon->cachesize);
111 /* 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. */
115 static void rehash(int size)
117 struct crec **new, **old, *p, *tmp;
118 int i, new_size, old_size;
120 /* hash_size is a power of two. */
121 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
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 *));
126 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
127 return;
129 for(i = 0; i < new_size; i++)
130 new[i] = NULL;
132 old = hash_table;
133 old_size = hash_size;
134 hash_table = new;
135 hash_size = new_size;
137 if (old)
139 for (i = 0; i < old_size; i++)
140 for (p = old[i]; p ; p = tmp)
142 tmp = p->hash_next;
143 cache_hash(p);
145 free(old);
149 static struct crec **hash_bucket(char *name)
151 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
152 const unsigned char *mix_tab = (const unsigned char*)typestr;
154 while((c = (unsigned char) *name++))
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';
159 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
162 /* hash_size is a power of two */
163 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
166 static void cache_hash(struct crec *crecp)
168 /* 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 */
173 struct crec **up = hash_bucket(cache_get_name(crecp));
175 if (!(crecp->flags & F_REVERSE))
177 while (*up && ((*up)->flags & F_REVERSE))
178 up = &((*up)->hash_next);
180 if (crecp->flags & F_IMMORTAL)
181 while (*up && !((*up)->flags & F_IMMORTAL))
182 up = &((*up)->hash_next);
184 crecp->hash_next = *up;
185 *up = crecp;
188 #ifdef HAVE_DNSSEC
189 static void cache_blockdata_free(struct crec *crecp)
191 if (crecp->flags & F_DNSKEY)
193 if (crecp->flags & F_DS)
194 blockdata_free(crecp->addr.sig.keydata);
195 else
196 blockdata_free(crecp->addr.key.keydata);
198 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
199 blockdata_free(crecp->addr.ds.keydata);
201 #endif
203 static void cache_free(struct crec *crecp)
205 crecp->flags &= ~F_FORWARD;
206 crecp->flags &= ~F_REVERSE;
207 crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
209 if (cache_tail)
210 cache_tail->next = crecp;
211 else
212 cache_head = crecp;
213 crecp->prev = cache_tail;
214 crecp->next = NULL;
215 cache_tail = crecp;
217 /* retrieve big name for further use. */
218 if (crecp->flags & F_BIGNAME)
220 crecp->name.bname->next = big_free;
221 big_free = crecp->name.bname;
222 crecp->flags &= ~F_BIGNAME;
225 #ifdef HAVE_DNSSEC
226 cache_blockdata_free(crecp);
227 #endif
230 /* insert a new cache entry at the head of the list (youngest entry) */
231 static void cache_link(struct crec *crecp)
233 if (cache_head) /* check needed for init code */
234 cache_head->prev = crecp;
235 crecp->next = cache_head;
236 crecp->prev = NULL;
237 cache_head = crecp;
238 if (!cache_tail)
239 cache_tail = crecp;
242 /* remove an arbitrary cache entry for promotion */
243 static void cache_unlink (struct crec *crecp)
245 if (crecp->prev)
246 crecp->prev->next = crecp->next;
247 else
248 cache_head = crecp->next;
250 if (crecp->next)
251 crecp->next->prev = crecp->prev;
252 else
253 cache_tail = crecp->prev;
256 char *cache_get_name(struct crec *crecp)
258 if (crecp->flags & F_BIGNAME)
259 return crecp->name.bname->name;
260 else if (crecp->flags & F_NAMEP)
261 return crecp->name.namep;
263 return crecp->name.sname;
266 char *cache_get_cname_target(struct crec *crecp)
268 if (crecp->addr.cname.uid != SRC_INTERFACE)
269 return cache_get_name(crecp->addr.cname.target.cache);
271 return crecp->addr.cname.target.int_name->name;
276 struct crec *cache_enumerate(int init)
278 static int bucket;
279 static struct crec *cache;
281 if (init)
283 bucket = 0;
284 cache = NULL;
286 else if (cache && cache->hash_next)
287 cache = cache->hash_next;
288 else
290 cache = NULL;
291 while (bucket < hash_size)
292 if ((cache = hash_table[bucket++]))
293 break;
296 return cache;
299 static int is_outdated_cname_pointer(struct crec *crecp)
301 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
302 return 0;
304 /* NB. record may be reused as DS or DNSKEY, where uid is
305 overloaded for something completely different */
306 if (crecp->addr.cname.target.cache &&
307 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
308 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
309 return 0;
311 return 1;
314 static int is_expired(time_t now, struct crec *crecp)
316 if (crecp->flags & F_IMMORTAL)
317 return 0;
319 if (difftime(now, crecp->ttd) < 0)
320 return 0;
322 return 1;
325 static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
327 /* Scan and remove old entries.
328 If (flags & F_FORWARD) then remove any forward entries for name and any expired
329 entries but only in the same hash bucket as name.
330 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
331 entries in the whole cache.
332 If (flags == 0) remove any expired entries in the whole cache.
334 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
335 to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
337 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
338 so that when we hit an entry which isn't reverse and is immortal, we're done. */
340 struct crec *crecp, **up;
342 if (flags & F_FORWARD)
344 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
346 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
348 *up = crecp->hash_next;
349 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
351 cache_unlink(crecp);
352 cache_free(crecp);
354 continue;
357 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
359 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
360 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
361 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
363 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
364 return crecp;
365 *up = crecp->hash_next;
366 cache_unlink(crecp);
367 cache_free(crecp);
368 continue;
371 #ifdef HAVE_DNSSEC
372 /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
373 type-covered sensitive for RRSIG */
374 if ((flags & (F_DNSKEY | F_DS)) &&
375 (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
376 crecp->uid == addr->addr.dnssec.class &&
377 (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
378 crecp->addr.sig.type_covered == addr->addr.dnssec.type))
380 if (crecp->flags & F_CONFIG)
381 return crecp;
382 *up = crecp->hash_next;
383 cache_unlink(crecp);
384 cache_free(crecp);
385 continue;
387 #endif
389 up = &crecp->hash_next;
392 else
394 int i;
395 #ifdef HAVE_IPV6
396 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
397 #else
398 int addrlen = INADDRSZ;
399 #endif
400 for (i = 0; i < hash_size; i++)
401 for (crecp = hash_table[i], up = &hash_table[i];
402 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
403 crecp = crecp->hash_next)
404 if (is_expired(now, crecp))
406 *up = crecp->hash_next;
407 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
409 cache_unlink(crecp);
410 cache_free(crecp);
413 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
414 (flags & crecp->flags & F_REVERSE) &&
415 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
416 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
418 *up = crecp->hash_next;
419 cache_unlink(crecp);
420 cache_free(crecp);
422 else
423 up = &crecp->hash_next;
426 return NULL;
429 /* Note: The normal calling sequence is
430 cache_start_insert
431 cache_insert * n
432 cache_end_insert
434 but an abort can cause the cache_end_insert to be missed
435 in which can the next cache_start_insert cleans things up. */
437 void cache_start_insert(void)
439 /* Free any entries which didn't get committed during the last
440 insert due to error.
442 while (new_chain)
444 struct crec *tmp = new_chain->next;
445 cache_free(new_chain);
446 new_chain = tmp;
448 new_chain = NULL;
449 insert_error = 0;
452 struct crec *cache_insert(char *name, struct all_addr *addr,
453 time_t now, unsigned long ttl, unsigned short flags)
455 struct crec *new;
456 union bigname *big_name = NULL;
457 int freed_all = flags & F_REVERSE;
458 int free_avail = 0;
460 /* Don't log DNSSEC records here, done elsewhere */
461 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
463 log_query(flags | F_UPSTREAM, name, addr, NULL);
464 /* Don't mess with TTL for DNSSEC records. */
465 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
466 ttl = daemon->max_cache_ttl;
467 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
468 ttl = daemon->min_cache_ttl;
471 /* if previous insertion failed give up now. */
472 if (insert_error)
473 return NULL;
475 /* First remove any expired entries and entries for the name/address we
476 are currently inserting. */
477 if ((new = cache_scan_free(name, addr, now, flags)))
479 /* We're trying to insert a record over one from
480 /etc/hosts or DHCP, or other config. If the
481 existing record is for an A or AAAA and
482 the record we're trying to insert is the same,
483 just drop the insert, but don't error the whole process. */
484 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD))
486 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
487 new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
488 return new;
489 #ifdef HAVE_IPV6
490 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
491 IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
492 return new;
493 #endif
496 insert_error = 1;
497 return NULL;
500 /* Now get a cache entry from the end of the LRU list */
501 while (1) {
502 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
504 insert_error = 1;
505 return NULL;
508 /* End of LRU list is still in use: if we didn't scan all the hash
509 chains for expired entries do that now. If we already tried that
510 then it's time to start spilling things. */
512 if (new->flags & (F_FORWARD | F_REVERSE))
514 /* If free_avail set, we believe that an entry has been freed.
515 Bugs have been known to make this not true, resulting in
516 a tight loop here. If that happens, abandon the
517 insert. Once in this state, all inserts will probably fail. */
518 if (free_avail)
520 static int warned = 0;
521 if (!warned)
523 my_syslog(LOG_ERR, _("Internal error in cache."));
524 warned = 1;
526 insert_error = 1;
527 return NULL;
530 if (freed_all)
532 struct all_addr free_addr = new->addr.addr;;
534 #ifdef HAVE_DNSSEC
535 /* For DNSSEC records, addr holds class and type_covered for RRSIG */
536 if (new->flags & (F_DS | F_DNSKEY))
538 free_addr.addr.dnssec.class = new->uid;
539 if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
540 free_addr.addr.dnssec.type = new->addr.sig.type_covered;
542 #endif
544 free_avail = 1; /* Must be free space now. */
545 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
546 cache_live_freed++;
548 else
550 cache_scan_free(NULL, NULL, now, 0);
551 freed_all = 1;
553 continue;
556 /* Check if we need to and can allocate extra memory for a long name.
557 If that fails, give up now, always succeed for DNSSEC records. */
558 if (name && (strlen(name) > SMALLDNAME-1))
560 if (big_free)
562 big_name = big_free;
563 big_free = big_free->next;
565 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
566 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
568 insert_error = 1;
569 return NULL;
571 else if (bignames_left != 0)
572 bignames_left--;
576 /* Got the rest: finally grab entry. */
577 cache_unlink(new);
578 break;
581 new->flags = flags;
582 if (big_name)
584 new->name.bname = big_name;
585 new->flags |= F_BIGNAME;
588 if (name)
589 strcpy(cache_get_name(new), name);
590 else
591 *cache_get_name(new) = 0;
593 if (addr)
595 #ifdef HAVE_DNSSEC
596 if (flags & (F_DS | F_DNSKEY))
597 new->uid = addr->addr.dnssec.class;
598 else
599 #endif
600 new->addr.addr = *addr;
603 new->ttd = now + (time_t)ttl;
604 new->next = new_chain;
605 new_chain = new;
607 return new;
610 /* after end of insertion, commit the new entries */
611 void cache_end_insert(void)
613 if (insert_error)
614 return;
616 while (new_chain)
618 struct crec *tmp = new_chain->next;
619 /* drop CNAMEs which didn't find a target. */
620 if (is_outdated_cname_pointer(new_chain))
621 cache_free(new_chain);
622 else
624 cache_hash(new_chain);
625 cache_link(new_chain);
626 cache_inserted++;
628 new_chain = tmp;
630 new_chain = NULL;
633 struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
635 struct crec *ans;
636 int no_rr = prot & F_NO_RR;
638 prot &= ~F_NO_RR;
640 if (crecp) /* iterating */
641 ans = crecp->next;
642 else
644 /* first search, look for relevant entries and push to top of list
645 also free anything which has expired */
646 struct crec *next, **up, **insert = NULL, **chainp = &ans;
647 unsigned short ins_flags = 0;
649 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
651 next = crecp->hash_next;
653 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
655 if ((crecp->flags & F_FORWARD) &&
656 #ifdef HAVE_DNSSEC
657 (((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
658 #endif
659 (crecp->flags & prot) &&
660 hostname_isequal(cache_get_name(crecp), name))
662 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
664 *chainp = crecp;
665 chainp = &crecp->next;
667 else
669 cache_unlink(crecp);
670 cache_link(crecp);
673 /* Move all but the first entry up the hash chain
674 this implements round-robin.
675 Make sure that re-ordering doesn't break the hash-chain
676 order invariants.
678 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
680 *up = crecp->hash_next;
681 crecp->hash_next = *insert;
682 *insert = crecp;
683 insert = &crecp->hash_next;
685 else
687 if (!insert && !no_rr)
689 insert = up;
690 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
692 up = &crecp->hash_next;
695 else
696 /* case : not expired, incorrect entry. */
697 up = &crecp->hash_next;
699 else
701 /* expired entry, free it */
702 *up = crecp->hash_next;
703 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
705 cache_unlink(crecp);
706 cache_free(crecp);
711 *chainp = cache_head;
714 if (ans &&
715 (ans->flags & F_FORWARD) &&
716 #ifdef HAVE_DNSSEC
717 (((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
718 #endif
719 (ans->flags & prot) &&
720 hostname_isequal(cache_get_name(ans), name))
721 return ans;
723 return NULL;
726 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
727 time_t now, unsigned int prot)
729 struct crec *ans;
730 #ifdef HAVE_IPV6
731 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
732 #else
733 int addrlen = INADDRSZ;
734 #endif
736 if (crecp) /* iterating */
737 ans = crecp->next;
738 else
740 /* first search, look for relevant entries and push to top of list
741 also free anything which has expired. All the reverse entries are at the
742 start of the hash chain, so we can give up when we find the first
743 non-REVERSE one. */
744 int i;
745 struct crec **up, **chainp = &ans;
747 for (i=0; i<hash_size; i++)
748 for (crecp = hash_table[i], up = &hash_table[i];
749 crecp && (crecp->flags & F_REVERSE);
750 crecp = crecp->hash_next)
751 if (!is_expired(now, crecp))
753 if ((crecp->flags & prot) &&
754 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
756 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
758 *chainp = crecp;
759 chainp = &crecp->next;
761 else
763 cache_unlink(crecp);
764 cache_link(crecp);
767 up = &crecp->hash_next;
769 else
771 *up = crecp->hash_next;
772 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
774 cache_unlink(crecp);
775 cache_free(crecp);
779 *chainp = cache_head;
782 if (ans &&
783 (ans->flags & F_REVERSE) &&
784 (ans->flags & prot) &&
785 memcmp(&ans->addr.addr, addr, addrlen) == 0)
786 return ans;
788 return NULL;
791 static void add_hosts_cname(struct crec *target)
793 struct crec *crec;
794 struct cname *a;
796 for (a = daemon->cnames; a; a = a->next)
797 if (hostname_isequal(cache_get_name(target), a->target) &&
798 (crec = whine_malloc(sizeof(struct crec))))
800 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
801 crec->name.namep = a->alias;
802 crec->addr.cname.target.cache = target;
803 crec->addr.cname.uid = target->uid;
804 crec->uid = next_uid();
805 cache_hash(crec);
806 add_hosts_cname(crec); /* handle chains */
810 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
811 unsigned int index, struct crec **rhash, int hashsz)
813 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
814 int i, nameexists = 0;
815 unsigned int j;
817 /* Remove duplicates in hosts files. */
818 if (lookup && (lookup->flags & F_HOSTS))
820 nameexists = 1;
821 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
823 free(cache);
824 return;
828 /* Ensure there is only one address -> name mapping (first one trumps)
829 We do this by steam here, The entries are kept in hash chains, linked
830 by ->next (which is unused at this point) held in hash buckets in
831 the array rhash, hashed on address. Note that rhash and the values
832 in ->next are only valid whilst reading hosts files: the buckets are
833 then freed, and the ->next pointer used for other things.
835 Only insert each unique address once into this hashing structure.
837 This complexity avoids O(n^2) divergent CPU use whilst reading
838 large (10000 entry) hosts files.
840 Note that we only do this process when bulk-reading hosts files,
841 for incremental reads, rhash is NULL, and we use cache lookups
842 instead.
845 if (rhash)
847 /* hash address */
848 for (j = 0, i = 0; i < addrlen; i++)
849 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
851 for (lookup = rhash[j]; lookup; lookup = lookup->next)
852 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
853 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
855 cache->flags &= ~F_REVERSE;
856 break;
859 /* maintain address hash chain, insert new unique address */
860 if (!lookup)
862 cache->next = rhash[j];
863 rhash[j] = cache;
866 else
868 /* incremental read, lookup in cache */
869 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
870 if (lookup && lookup->flags & F_HOSTS)
871 cache->flags &= ~F_REVERSE;
874 cache->uid = index;
875 memcpy(&cache->addr.addr, addr, addrlen);
876 cache_hash(cache);
878 /* don't need to do alias stuff for second and subsequent addresses. */
879 if (!nameexists)
880 add_hosts_cname(cache);
883 static int eatspace(FILE *f)
885 int c, nl = 0;
887 while (1)
889 if ((c = getc(f)) == '#')
890 while (c != '\n' && c != EOF)
891 c = getc(f);
893 if (c == EOF)
894 return 1;
896 if (!isspace(c))
898 ungetc(c, f);
899 return nl;
902 if (c == '\n')
903 nl = 1;
907 static int gettok(FILE *f, char *token)
909 int c, count = 0;
911 while (1)
913 if ((c = getc(f)) == EOF)
914 return (count == 0) ? EOF : 1;
916 if (isspace(c) || c == '#')
918 ungetc(c, f);
919 return eatspace(f);
922 if (count < (MAXDNAME - 1))
924 token[count++] = c;
925 token[count] = 0;
930 int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
932 FILE *f = fopen(filename, "r");
933 char *token = daemon->namebuff, *domain_suffix = NULL;
934 int addr_count = 0, name_count = cache_size, lineno = 0;
935 unsigned short flags = 0;
936 struct all_addr addr;
937 int atnl, addrlen = 0;
939 if (!f)
941 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
942 return 0;
945 eatspace(f);
947 while ((atnl = gettok(f, token)) != EOF)
949 lineno++;
951 if (inet_pton(AF_INET, token, &addr) > 0)
953 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
954 addrlen = INADDRSZ;
955 domain_suffix = get_domain(addr.addr.addr4);
957 #ifdef HAVE_IPV6
958 else if (inet_pton(AF_INET6, token, &addr) > 0)
960 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
961 addrlen = IN6ADDRSZ;
962 domain_suffix = get_domain6(&addr.addr.addr6);
964 #endif
965 else
967 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
968 while (atnl == 0)
969 atnl = gettok(f, token);
970 continue;
973 addr_count++;
975 /* rehash every 1000 names. */
976 if (rhash && ((name_count - cache_size) > 1000))
978 rehash(name_count);
979 cache_size = name_count;
982 while (atnl == 0)
984 struct crec *cache;
985 int fqdn, nomem;
986 char *canon;
988 if ((atnl = gettok(f, token)) == EOF)
989 break;
991 fqdn = !!strchr(token, '.');
993 if ((canon = canonicalise(token, &nomem)))
995 /* If set, add a version of the name with a default domain appended */
996 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
997 (cache = whine_malloc(sizeof(struct crec) +
998 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
1000 strcpy(cache->name.sname, canon);
1001 strcat(cache->name.sname, ".");
1002 strcat(cache->name.sname, domain_suffix);
1003 cache->flags = flags;
1004 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
1005 name_count++;
1007 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
1009 strcpy(cache->name.sname, canon);
1010 cache->flags = flags;
1011 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
1012 name_count++;
1014 free(canon);
1017 else if (!nomem)
1018 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1022 fclose(f);
1024 if (rhash)
1025 rehash(name_count);
1027 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1029 return name_count;
1032 void cache_reload(void)
1034 struct crec *cache, **up, *tmp;
1035 int revhashsz, i, total_size = daemon->cachesize;
1036 struct hostsfile *ah;
1037 struct host_record *hr;
1038 struct name_list *nl;
1039 struct cname *a;
1040 struct interface_name *intr;
1041 #ifdef HAVE_DNSSEC
1042 struct ds_config *ds;
1043 #endif
1045 cache_inserted = cache_live_freed = 0;
1047 for (i=0; i<hash_size; i++)
1048 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1050 #ifdef HAVE_DNSSEC
1051 cache_blockdata_free(cache);
1052 #endif
1053 tmp = cache->hash_next;
1054 if (cache->flags & (F_HOSTS | F_CONFIG))
1056 *up = cache->hash_next;
1057 free(cache);
1059 else if (!(cache->flags & F_DHCP))
1061 *up = cache->hash_next;
1062 if (cache->flags & F_BIGNAME)
1064 cache->name.bname->next = big_free;
1065 big_free = cache->name.bname;
1067 cache->flags = 0;
1069 else
1070 up = &cache->hash_next;
1073 /* Add CNAMEs to interface_names to the cache */
1074 for (a = daemon->cnames; a; a = a->next)
1075 for (intr = daemon->int_names; intr; intr = intr->next)
1076 if (hostname_isequal(a->target, intr->name) &&
1077 ((cache = whine_malloc(sizeof(struct crec)))))
1079 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
1080 cache->name.namep = a->alias;
1081 cache->addr.cname.target.int_name = intr;
1082 cache->addr.cname.uid = SRC_INTERFACE;
1083 cache->uid = next_uid();
1084 cache_hash(cache);
1085 add_hosts_cname(cache); /* handle chains */
1088 #ifdef HAVE_DNSSEC
1089 for (ds = daemon->ds; ds; ds = ds->next)
1090 if ((cache = whine_malloc(sizeof(struct crec))) &&
1091 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
1093 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
1094 cache->name.namep = ds->name;
1095 cache->addr.ds.keylen = ds->digestlen;
1096 cache->addr.ds.algo = ds->algo;
1097 cache->addr.ds.keytag = ds->keytag;
1098 cache->addr.ds.digest = ds->digest_type;
1099 cache->uid = ds->class;
1100 cache_hash(cache);
1102 #endif
1104 /* borrow the packet buffer for a temporary by-address hash */
1105 memset(daemon->packet, 0, daemon->packet_buff_sz);
1106 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1107 /* we overwrote the buffer... */
1108 daemon->srv_save = NULL;
1110 /* Do host_records in config. */
1111 for (hr = daemon->host_records; hr; hr = hr->next)
1112 for (nl = hr->names; nl; nl = nl->next)
1114 if (hr->addr.s_addr != 0 &&
1115 (cache = whine_malloc(sizeof(struct crec))))
1117 cache->name.namep = nl->name;
1118 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
1119 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1121 #ifdef HAVE_IPV6
1122 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1123 (cache = whine_malloc(sizeof(struct crec))))
1125 cache->name.namep = nl->name;
1126 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
1127 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1129 #endif
1132 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
1134 if (daemon->cachesize > 0)
1135 my_syslog(LOG_INFO, _("cleared cache"));
1137 else
1139 if (!option_bool(OPT_NO_HOSTS))
1140 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1142 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1143 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1144 if (!(ah->flags & AH_INACTIVE))
1145 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1148 #ifdef HAVE_INOTIFY
1149 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1150 #endif
1154 #ifdef HAVE_DHCP
1155 struct in_addr a_record_from_hosts(char *name, time_t now)
1157 struct crec *crecp = NULL;
1158 struct in_addr ret;
1160 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1161 if (crecp->flags & F_HOSTS)
1162 return *(struct in_addr *)&crecp->addr;
1164 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1166 ret.s_addr = 0;
1167 return ret;
1170 void cache_unhash_dhcp(void)
1172 struct crec *cache, **up;
1173 int i;
1175 for (i=0; i<hash_size; i++)
1176 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1177 if (cache->flags & F_DHCP)
1179 *up = cache->hash_next;
1180 cache->next = dhcp_spare;
1181 dhcp_spare = cache;
1183 else
1184 up = &cache->hash_next;
1187 static void add_dhcp_cname(struct crec *target, time_t ttd)
1189 struct crec *aliasc;
1190 struct cname *a;
1192 for (a = daemon->cnames; a; a = a->next)
1193 if (hostname_isequal(cache_get_name(target), a->target))
1195 if ((aliasc = dhcp_spare))
1196 dhcp_spare = dhcp_spare->next;
1197 else /* need new one */
1198 aliasc = whine_malloc(sizeof(struct crec));
1200 if (aliasc)
1202 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
1203 if (ttd == 0)
1204 aliasc->flags |= F_IMMORTAL;
1205 else
1206 aliasc->ttd = ttd;
1207 aliasc->name.namep = a->alias;
1208 aliasc->addr.cname.target.cache = target;
1209 aliasc->addr.cname.uid = target->uid;
1210 aliasc->uid = next_uid();
1211 cache_hash(aliasc);
1212 add_dhcp_cname(aliasc, ttd);
1217 void cache_add_dhcp_entry(char *host_name, int prot,
1218 struct all_addr *host_address, time_t ttd)
1220 struct crec *crec = NULL, *fail_crec = NULL;
1221 unsigned short flags = F_IPV4;
1222 int in_hosts = 0;
1223 size_t addrlen = sizeof(struct in_addr);
1225 #ifdef HAVE_IPV6
1226 if (prot == AF_INET6)
1228 flags = F_IPV6;
1229 addrlen = sizeof(struct in6_addr);
1231 #endif
1233 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1235 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
1237 /* check all addresses associated with name */
1238 if (crec->flags & (F_HOSTS | F_CONFIG))
1240 if (crec->flags & F_CNAME)
1241 my_syslog(MS_DHCP | LOG_WARNING,
1242 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1243 host_name, daemon->addrbuff);
1244 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1245 in_hosts = 1;
1246 else
1247 fail_crec = crec;
1249 else if (!(crec->flags & F_DHCP))
1251 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
1252 /* scan_free deletes all addresses associated with name */
1253 break;
1257 /* if in hosts, don't need DHCP record */
1258 if (in_hosts)
1259 return;
1261 /* Name in hosts, address doesn't match */
1262 if (fail_crec)
1264 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1265 my_syslog(MS_DHCP | LOG_WARNING,
1266 _("not giving name %s to the DHCP lease of %s because "
1267 "the name exists in %s with address %s"),
1268 host_name, daemon->addrbuff,
1269 record_source(fail_crec->uid), daemon->namebuff);
1270 return;
1273 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1275 if (crec->flags & F_NEG)
1277 flags |= F_REVERSE;
1278 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1281 else
1282 flags |= F_REVERSE;
1284 if ((crec = dhcp_spare))
1285 dhcp_spare = dhcp_spare->next;
1286 else /* need new one */
1287 crec = whine_malloc(sizeof(struct crec));
1289 if (crec) /* malloc may fail */
1291 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
1292 if (ttd == 0)
1293 crec->flags |= F_IMMORTAL;
1294 else
1295 crec->ttd = ttd;
1296 crec->addr.addr = *host_address;
1297 crec->name.namep = host_name;
1298 crec->uid = next_uid();
1299 cache_hash(crec);
1301 add_dhcp_cname(crec, ttd);
1304 #endif
1306 int cache_make_stat(struct txt_record *t)
1308 static char *buff = NULL;
1309 static int bufflen = 60;
1310 int len;
1311 struct server *serv, *serv1;
1312 char *p;
1314 if (!buff && !(buff = whine_malloc(60)))
1315 return 0;
1317 p = buff;
1319 switch (t->stat)
1321 case TXT_STAT_CACHESIZE:
1322 sprintf(buff+1, "%d", daemon->cachesize);
1323 break;
1325 case TXT_STAT_INSERTS:
1326 sprintf(buff+1, "%d", cache_inserted);
1327 break;
1329 case TXT_STAT_EVICTIONS:
1330 sprintf(buff+1, "%d", cache_live_freed);
1331 break;
1333 case TXT_STAT_MISSES:
1334 sprintf(buff+1, "%u", daemon->queries_forwarded);
1335 break;
1337 case TXT_STAT_HITS:
1338 sprintf(buff+1, "%u", daemon->local_answer);
1339 break;
1341 #ifdef HAVE_AUTH
1342 case TXT_STAT_AUTH:
1343 sprintf(buff+1, "%u", daemon->auth_answer);
1344 break;
1345 #endif
1347 case TXT_STAT_SERVERS:
1348 /* sum counts from different records for same server */
1349 for (serv = daemon->servers; serv; serv = serv->next)
1350 serv->flags &= ~SERV_COUNTED;
1352 for (serv = daemon->servers; serv; serv = serv->next)
1353 if (!(serv->flags &
1354 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1356 char *new, *lenp;
1357 int port, newlen, bytes_avail, bytes_needed;
1358 unsigned int queries = 0, failed_queries = 0;
1359 for (serv1 = serv; serv1; serv1 = serv1->next)
1360 if (!(serv1->flags &
1361 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1362 sockaddr_isequal(&serv->addr, &serv1->addr))
1364 serv1->flags |= SERV_COUNTED;
1365 queries += serv1->queries;
1366 failed_queries += serv1->failed_queries;
1368 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1369 lenp = p++; /* length */
1370 bytes_avail = bufflen - (p - buff );
1371 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1372 if (bytes_needed >= bytes_avail)
1374 /* expand buffer if necessary */
1375 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1376 if (!(new = whine_malloc(newlen)))
1377 return 0;
1378 memcpy(new, buff, bufflen);
1379 free(buff);
1380 p = new + (p - buff);
1381 lenp = p - 1;
1382 buff = new;
1383 bufflen = newlen;
1384 bytes_avail = bufflen - (p - buff );
1385 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1387 *lenp = bytes_needed;
1388 p += bytes_needed;
1390 t->txt = (unsigned char *)buff;
1391 t->len = p - buff;
1392 return 1;
1395 len = strlen(buff+1);
1396 t->txt = (unsigned char *)buff;
1397 t->len = len + 1;
1398 *buff = len;
1399 return 1;
1402 /* There can be names in the cache containing control chars, don't
1403 mess up logging or open security holes. */
1404 static char *sanitise(char *name)
1406 unsigned char *r;
1407 if (name)
1408 for (r = (unsigned char *)name; *r; r++)
1409 if (!isprint((int)*r))
1410 return "<name unprintable>";
1412 return name;
1416 void dump_cache(time_t now)
1418 struct server *serv, *serv1;
1419 char *t = "";
1421 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1422 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1423 daemon->cachesize, cache_live_freed, cache_inserted);
1424 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1425 daemon->queries_forwarded, daemon->local_answer);
1426 #ifdef HAVE_AUTH
1427 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
1428 #endif
1429 #ifdef HAVE_DNSSEC
1430 blockdata_report();
1431 #endif
1433 /* sum counts from different records for same server */
1434 for (serv = daemon->servers; serv; serv = serv->next)
1435 serv->flags &= ~SERV_COUNTED;
1437 for (serv = daemon->servers; serv; serv = serv->next)
1438 if (!(serv->flags &
1439 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1441 int port;
1442 unsigned int queries = 0, failed_queries = 0;
1443 for (serv1 = serv; serv1; serv1 = serv1->next)
1444 if (!(serv1->flags &
1445 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1446 sockaddr_isequal(&serv->addr, &serv1->addr))
1448 serv1->flags |= SERV_COUNTED;
1449 queries += serv1->queries;
1450 failed_queries += serv1->failed_queries;
1452 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1453 my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
1456 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG) || daemon->hosts_cache != NULL)
1458 struct crec *cache ;
1459 int i;
1460 int dumping_hosts = daemon->hosts_cache != NULL;
1461 FILE *hosts_cache = NULL;
1462 if (dumping_hosts) {
1463 hosts_cache = fopen(daemon->hosts_cache, "w");
1464 if (hosts_cache == NULL) {
1465 dumping_hosts = 0;
1466 my_syslog(LOG_WARNING, "Failed to open hosts cache file: \"%s\"", daemon->hosts_cache);
1470 my_syslog(LOG_INFO, "Host Address Flags Expires");
1472 for (i=0; i<hash_size; i++)
1473 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1475 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1476 *a = 0;
1477 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
1478 n = "<Root>";
1479 p += sprintf(p, "%-30.30s ", sanitise(n));
1480 if ((cache->flags & F_CNAME))
1482 if (!is_outdated_cname_pointer(cache))
1483 a = cache_get_cname_target(cache);
1484 if (dumping_hosts)
1485 fprintf(hosts_cache, "#%s\t%s\n", cache_get_cname_target(cache), n);
1487 #ifdef HAVE_DNSSEC
1488 else if (cache->flags & F_DS)
1490 if (cache->flags & F_DNSKEY)
1491 /* RRSIG */
1492 sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
1493 cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
1494 else if (!(cache->flags & F_NEG))
1495 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1496 cache->addr.ds.algo, cache->addr.ds.digest);
1498 else if (cache->flags & F_DNSKEY)
1499 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1500 cache->addr.key.algo, cache->addr.key.flags);
1501 #endif
1502 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
1504 a = daemon->addrbuff;
1505 if (cache->flags & F_IPV4)
1506 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
1507 #ifdef HAVE_IPV6
1508 else if (cache->flags & F_IPV6)
1509 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
1510 #endif
1511 if (dumping_hosts)
1512 fprintf(hosts_cache, "%s\t%s\n", a, n);
1515 if (cache->flags & F_IPV4)
1516 t = "4";
1517 else if (cache->flags & F_IPV6)
1518 t = "6";
1519 else if (cache->flags & F_CNAME)
1520 t = "C";
1521 #ifdef HAVE_DNSSEC
1522 else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
1523 t = "G"; /* DNSKEY and DS set -> RRISG */
1524 else if (cache->flags & F_DS)
1525 t = "S";
1526 else if (cache->flags & F_DNSKEY)
1527 t = "K";
1528 #endif
1529 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
1530 cache->flags & F_FORWARD ? "F" : " ",
1531 cache->flags & F_REVERSE ? "R" : " ",
1532 cache->flags & F_IMMORTAL ? "I" : " ",
1533 cache->flags & F_DHCP ? "D" : " ",
1534 cache->flags & F_NEG ? "N" : " ",
1535 cache->flags & F_NXDOMAIN ? "X" : " ",
1536 cache->flags & F_HOSTS ? "H" : " ",
1537 cache->flags & F_DNSSECOK ? "V" : " ");
1538 #ifdef HAVE_BROKEN_RTC
1539 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
1540 #else
1541 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1542 /* ctime includes trailing \n - eat it */
1543 *(p-1) = 0;
1544 #endif
1545 my_syslog(LOG_INFO, daemon->namebuff);
1547 if (dumping_hosts)
1548 fclose(hosts_cache);
1552 char *record_source(unsigned int index)
1554 struct hostsfile *ah;
1556 if (index == SRC_CONFIG)
1557 return "config";
1558 else if (index == SRC_HOSTS)
1559 return HOSTSFILE;
1561 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1562 if (ah->index == index)
1563 return ah->fname;
1565 #ifdef HAVE_INOTIFY
1566 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1567 if (ah->index == index)
1568 return ah->fname;
1569 #endif
1571 return "<unknown>";
1574 char *querystr(char *desc, unsigned short type)
1576 unsigned int i;
1577 int len = 10; /* strlen("type=xxxxx") */
1578 const char *types = NULL;
1579 static char *buff = NULL;
1580 static int bufflen = 0;
1582 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1583 if (typestr[i].type == type)
1585 types = typestr[i].name;
1586 len = strlen(types);
1587 break;
1590 len += 3; /* braces, terminator */
1591 len += strlen(desc);
1593 if (!buff || bufflen < len)
1595 if (buff)
1596 free(buff);
1597 else if (len < 20)
1598 len = 20;
1600 buff = whine_malloc(len);
1601 bufflen = len;
1604 if (buff)
1606 if (types)
1607 sprintf(buff, "%s[%s]", desc, types);
1608 else
1609 sprintf(buff, "%s[type=%d]", desc, type);
1612 return buff ? buff : "";
1615 void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
1617 char *source, *dest = daemon->addrbuff;
1618 char *verb = "is";
1620 if (!option_bool(OPT_LOG))
1621 return;
1623 name = sanitise(name);
1625 if (addr)
1627 if (flags & F_KEYTAG)
1628 sprintf(daemon->addrbuff, arg, addr->addr.keytag);
1629 else
1631 #ifdef HAVE_IPV6
1632 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1633 addr, daemon->addrbuff, ADDRSTRLEN);
1634 #else
1635 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1636 #endif
1639 else
1640 dest = arg;
1642 if (flags & F_REVERSE)
1644 dest = name;
1645 name = daemon->addrbuff;
1648 if (flags & F_NEG)
1650 if (flags & F_NXDOMAIN)
1651 dest = "NXDOMAIN";
1652 else
1654 if (flags & F_IPV4)
1655 dest = "NODATA-IPv4";
1656 else if (flags & F_IPV6)
1657 dest = "NODATA-IPv6";
1658 else
1659 dest = "NODATA";
1662 else if (flags & F_CNAME)
1663 dest = "<CNAME>";
1664 else if (flags & F_RRNAME)
1665 dest = arg;
1667 if (flags & F_CONFIG)
1668 source = "config";
1669 else if (flags & F_DHCP)
1670 source = "DHCP";
1671 else if (flags & F_HOSTS)
1672 source = arg;
1673 else if (flags & F_UPSTREAM)
1674 source = "reply";
1675 else if (flags & F_SECSTAT)
1676 source = "validation";
1677 else if (flags & F_AUTH)
1678 source = "auth";
1679 else if (flags & F_SERVER)
1681 source = "forwarded";
1682 verb = "to";
1684 else if (flags & F_QUERY)
1686 source = arg;
1687 verb = "from";
1689 else if (flags & F_DNSSEC)
1691 source = arg;
1692 verb = "to";
1694 else if (flags & F_IPSET)
1696 source = "ipset add";
1697 dest = name;
1698 name = arg;
1699 verb = daemon->addrbuff;
1701 else
1702 source = "cached";
1704 if (strlen(name) == 0)
1705 name = ".";
1707 if (option_bool(OPT_EXTRALOG))
1709 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
1710 if (flags & F_NOEXTRA)
1711 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
1712 else
1713 my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
1715 else
1716 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);