dnsmasq: re-apply original Tomato specific code
[tomato.git] / release / src / router / dnsmasq / src / cache.c
blob635e5089ea136cc6d2c3ebb86efd165ca581acc2
1 /* dnsmasq is Copyright (c) 2000-2016 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)
192 blockdata_free(crecp->addr.key.keydata);
193 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
194 blockdata_free(crecp->addr.ds.keydata);
196 #endif
198 static void cache_free(struct crec *crecp)
200 crecp->flags &= ~F_FORWARD;
201 crecp->flags &= ~F_REVERSE;
202 crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
204 if (cache_tail)
205 cache_tail->next = crecp;
206 else
207 cache_head = crecp;
208 crecp->prev = cache_tail;
209 crecp->next = NULL;
210 cache_tail = crecp;
212 /* retrieve big name for further use. */
213 if (crecp->flags & F_BIGNAME)
215 crecp->name.bname->next = big_free;
216 big_free = crecp->name.bname;
217 crecp->flags &= ~F_BIGNAME;
220 #ifdef HAVE_DNSSEC
221 cache_blockdata_free(crecp);
222 #endif
225 /* insert a new cache entry at the head of the list (youngest entry) */
226 static void cache_link(struct crec *crecp)
228 if (cache_head) /* check needed for init code */
229 cache_head->prev = crecp;
230 crecp->next = cache_head;
231 crecp->prev = NULL;
232 cache_head = crecp;
233 if (!cache_tail)
234 cache_tail = crecp;
237 /* remove an arbitrary cache entry for promotion */
238 static void cache_unlink (struct crec *crecp)
240 if (crecp->prev)
241 crecp->prev->next = crecp->next;
242 else
243 cache_head = crecp->next;
245 if (crecp->next)
246 crecp->next->prev = crecp->prev;
247 else
248 cache_tail = crecp->prev;
251 char *cache_get_name(struct crec *crecp)
253 if (crecp->flags & F_BIGNAME)
254 return crecp->name.bname->name;
255 else if (crecp->flags & F_NAMEP)
256 return crecp->name.namep;
258 return crecp->name.sname;
261 char *cache_get_cname_target(struct crec *crecp)
263 if (crecp->addr.cname.uid != SRC_INTERFACE)
264 return cache_get_name(crecp->addr.cname.target.cache);
266 return crecp->addr.cname.target.int_name->name;
271 struct crec *cache_enumerate(int init)
273 static int bucket;
274 static struct crec *cache;
276 if (init)
278 bucket = 0;
279 cache = NULL;
281 else if (cache && cache->hash_next)
282 cache = cache->hash_next;
283 else
285 cache = NULL;
286 while (bucket < hash_size)
287 if ((cache = hash_table[bucket++]))
288 break;
291 return cache;
294 static int is_outdated_cname_pointer(struct crec *crecp)
296 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
297 return 0;
299 /* NB. record may be reused as DS or DNSKEY, where uid is
300 overloaded for something completely different */
301 if (crecp->addr.cname.target.cache &&
302 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
303 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
304 return 0;
306 return 1;
309 static int is_expired(time_t now, struct crec *crecp)
311 if (crecp->flags & F_IMMORTAL)
312 return 0;
314 if (difftime(now, crecp->ttd) < 0)
315 return 0;
317 return 1;
320 static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
322 /* Scan and remove old entries.
323 If (flags & F_FORWARD) then remove any forward entries for name and any expired
324 entries but only in the same hash bucket as name.
325 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
326 entries in the whole cache.
327 If (flags == 0) remove any expired entries in the whole cache.
329 In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
330 to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
332 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
333 so that when we hit an entry which isn't reverse and is immortal, we're done. */
335 struct crec *crecp, **up;
337 if (flags & F_FORWARD)
339 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
341 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
343 *up = crecp->hash_next;
344 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
346 cache_unlink(crecp);
347 cache_free(crecp);
349 continue;
352 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
354 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
355 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
356 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
358 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
359 return crecp;
360 *up = crecp->hash_next;
361 cache_unlink(crecp);
362 cache_free(crecp);
363 continue;
366 #ifdef HAVE_DNSSEC
367 /* Deletion has to be class-sensitive for DS and DNSKEY */
368 if ((flags & crecp->flags & (F_DNSKEY | F_DS)) && crecp->uid == addr->addr.dnssec.class)
370 if (crecp->flags & F_CONFIG)
371 return crecp;
372 *up = crecp->hash_next;
373 cache_unlink(crecp);
374 cache_free(crecp);
375 continue;
377 #endif
379 up = &crecp->hash_next;
382 else
384 int i;
385 #ifdef HAVE_IPV6
386 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
387 #else
388 int addrlen = INADDRSZ;
389 #endif
390 for (i = 0; i < hash_size; i++)
391 for (crecp = hash_table[i], up = &hash_table[i];
392 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
393 crecp = crecp->hash_next)
394 if (is_expired(now, crecp))
396 *up = crecp->hash_next;
397 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
399 cache_unlink(crecp);
400 cache_free(crecp);
403 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
404 (flags & crecp->flags & F_REVERSE) &&
405 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
406 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
408 *up = crecp->hash_next;
409 cache_unlink(crecp);
410 cache_free(crecp);
412 else
413 up = &crecp->hash_next;
416 return NULL;
419 /* Note: The normal calling sequence is
420 cache_start_insert
421 cache_insert * n
422 cache_end_insert
424 but an abort can cause the cache_end_insert to be missed
425 in which can the next cache_start_insert cleans things up. */
427 void cache_start_insert(void)
429 /* Free any entries which didn't get committed during the last
430 insert due to error.
432 while (new_chain)
434 struct crec *tmp = new_chain->next;
435 cache_free(new_chain);
436 new_chain = tmp;
438 new_chain = NULL;
439 insert_error = 0;
442 struct crec *cache_insert(char *name, struct all_addr *addr,
443 time_t now, unsigned long ttl, unsigned short flags)
445 struct crec *new;
446 union bigname *big_name = NULL;
447 int freed_all = flags & F_REVERSE;
448 int free_avail = 0;
450 /* Don't log DNSSEC records here, done elsewhere */
451 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
453 log_query(flags | F_UPSTREAM, name, addr, NULL);
454 /* Don't mess with TTL for DNSSEC records. */
455 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
456 ttl = daemon->max_cache_ttl;
457 if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
458 ttl = daemon->min_cache_ttl;
461 /* if previous insertion failed give up now. */
462 if (insert_error)
463 return NULL;
465 /* First remove any expired entries and entries for the name/address we
466 are currently inserting. */
467 if ((new = cache_scan_free(name, addr, now, flags)))
469 /* We're trying to insert a record over one from
470 /etc/hosts or DHCP, or other config. If the
471 existing record is for an A or AAAA and
472 the record we're trying to insert is the same,
473 just drop the insert, but don't error the whole process. */
474 if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
476 if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
477 new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
478 return new;
479 #ifdef HAVE_IPV6
480 else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
481 IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
482 return new;
483 #endif
486 insert_error = 1;
487 return NULL;
490 /* Now get a cache entry from the end of the LRU list */
491 while (1) {
492 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
494 insert_error = 1;
495 return NULL;
498 /* End of LRU list is still in use: if we didn't scan all the hash
499 chains for expired entries do that now. If we already tried that
500 then it's time to start spilling things. */
502 if (new->flags & (F_FORWARD | F_REVERSE))
504 /* If free_avail set, we believe that an entry has been freed.
505 Bugs have been known to make this not true, resulting in
506 a tight loop here. If that happens, abandon the
507 insert. Once in this state, all inserts will probably fail. */
508 if (free_avail)
510 static int warned = 0;
511 if (!warned)
513 my_syslog(LOG_ERR, _("Internal error in cache."));
514 warned = 1;
516 insert_error = 1;
517 return NULL;
520 if (freed_all)
522 struct all_addr free_addr = new->addr.addr;;
524 #ifdef HAVE_DNSSEC
525 /* For DNSSEC records, addr holds class. */
526 if (new->flags & (F_DS | F_DNSKEY))
527 free_addr.addr.dnssec.class = new->uid;
528 #endif
530 free_avail = 1; /* Must be free space now. */
531 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
532 cache_live_freed++;
534 else
536 cache_scan_free(NULL, NULL, now, 0);
537 freed_all = 1;
539 continue;
542 /* Check if we need to and can allocate extra memory for a long name.
543 If that fails, give up now, always succeed for DNSSEC records. */
544 if (name && (strlen(name) > SMALLDNAME-1))
546 if (big_free)
548 big_name = big_free;
549 big_free = big_free->next;
551 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
552 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
554 insert_error = 1;
555 return NULL;
557 else if (bignames_left != 0)
558 bignames_left--;
562 /* Got the rest: finally grab entry. */
563 cache_unlink(new);
564 break;
567 new->flags = flags;
568 if (big_name)
570 new->name.bname = big_name;
571 new->flags |= F_BIGNAME;
574 if (name)
575 strcpy(cache_get_name(new), name);
576 else
577 *cache_get_name(new) = 0;
579 if (addr)
581 #ifdef HAVE_DNSSEC
582 if (flags & (F_DS | F_DNSKEY))
583 new->uid = addr->addr.dnssec.class;
584 else
585 #endif
586 new->addr.addr = *addr;
589 new->ttd = now + (time_t)ttl;
590 new->next = new_chain;
591 new_chain = new;
593 return new;
596 /* after end of insertion, commit the new entries */
597 void cache_end_insert(void)
599 if (insert_error)
600 return;
602 while (new_chain)
604 struct crec *tmp = new_chain->next;
605 /* drop CNAMEs which didn't find a target. */
606 if (is_outdated_cname_pointer(new_chain))
607 cache_free(new_chain);
608 else
610 cache_hash(new_chain);
611 cache_link(new_chain);
612 cache_inserted++;
614 new_chain = tmp;
616 new_chain = NULL;
619 struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
621 struct crec *ans;
622 int no_rr = prot & F_NO_RR;
624 prot &= ~F_NO_RR;
626 if (crecp) /* iterating */
627 ans = crecp->next;
628 else
630 /* first search, look for relevant entries and push to top of list
631 also free anything which has expired */
632 struct crec *next, **up, **insert = NULL, **chainp = &ans;
633 unsigned short ins_flags = 0;
635 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
637 next = crecp->hash_next;
639 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
641 if ((crecp->flags & F_FORWARD) &&
642 (crecp->flags & prot) &&
643 hostname_isequal(cache_get_name(crecp), name))
645 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
647 *chainp = crecp;
648 chainp = &crecp->next;
650 else
652 cache_unlink(crecp);
653 cache_link(crecp);
656 /* Move all but the first entry up the hash chain
657 this implements round-robin.
658 Make sure that re-ordering doesn't break the hash-chain
659 order invariants.
661 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
663 *up = crecp->hash_next;
664 crecp->hash_next = *insert;
665 *insert = crecp;
666 insert = &crecp->hash_next;
668 else
670 if (!insert && !no_rr)
672 insert = up;
673 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
675 up = &crecp->hash_next;
678 else
679 /* case : not expired, incorrect entry. */
680 up = &crecp->hash_next;
682 else
684 /* expired entry, free it */
685 *up = crecp->hash_next;
686 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
688 cache_unlink(crecp);
689 cache_free(crecp);
694 *chainp = cache_head;
697 if (ans &&
698 (ans->flags & F_FORWARD) &&
699 (ans->flags & prot) &&
700 hostname_isequal(cache_get_name(ans), name))
701 return ans;
703 return NULL;
706 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
707 time_t now, unsigned int prot)
709 struct crec *ans;
710 #ifdef HAVE_IPV6
711 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
712 #else
713 int addrlen = INADDRSZ;
714 #endif
716 if (crecp) /* iterating */
717 ans = crecp->next;
718 else
720 /* first search, look for relevant entries and push to top of list
721 also free anything which has expired. All the reverse entries are at the
722 start of the hash chain, so we can give up when we find the first
723 non-REVERSE one. */
724 int i;
725 struct crec **up, **chainp = &ans;
727 for (i=0; i<hash_size; i++)
728 for (crecp = hash_table[i], up = &hash_table[i];
729 crecp && (crecp->flags & F_REVERSE);
730 crecp = crecp->hash_next)
731 if (!is_expired(now, crecp))
733 if ((crecp->flags & prot) &&
734 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
736 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
738 *chainp = crecp;
739 chainp = &crecp->next;
741 else
743 cache_unlink(crecp);
744 cache_link(crecp);
747 up = &crecp->hash_next;
749 else
751 *up = crecp->hash_next;
752 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
754 cache_unlink(crecp);
755 cache_free(crecp);
759 *chainp = cache_head;
762 if (ans &&
763 (ans->flags & F_REVERSE) &&
764 (ans->flags & prot) &&
765 memcmp(&ans->addr.addr, addr, addrlen) == 0)
766 return ans;
768 return NULL;
771 static void add_hosts_cname(struct crec *target)
773 struct crec *crec;
774 struct cname *a;
776 for (a = daemon->cnames; a; a = a->next)
777 if (hostname_isequal(cache_get_name(target), a->target) &&
778 (crec = whine_malloc(sizeof(struct crec))))
780 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
781 crec->ttd = a->ttl;
782 crec->name.namep = a->alias;
783 crec->addr.cname.target.cache = target;
784 crec->addr.cname.uid = target->uid;
785 crec->uid = next_uid();
786 cache_hash(crec);
787 add_hosts_cname(crec); /* handle chains */
791 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
792 unsigned int index, struct crec **rhash, int hashsz)
794 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
795 int i, nameexists = 0;
796 unsigned int j;
798 /* Remove duplicates in hosts files. */
799 if (lookup && (lookup->flags & F_HOSTS))
801 nameexists = 1;
802 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
804 free(cache);
805 return;
809 /* Ensure there is only one address -> name mapping (first one trumps)
810 We do this by steam here, The entries are kept in hash chains, linked
811 by ->next (which is unused at this point) held in hash buckets in
812 the array rhash, hashed on address. Note that rhash and the values
813 in ->next are only valid whilst reading hosts files: the buckets are
814 then freed, and the ->next pointer used for other things.
816 Only insert each unique address once into this hashing structure.
818 This complexity avoids O(n^2) divergent CPU use whilst reading
819 large (10000 entry) hosts files.
821 Note that we only do this process when bulk-reading hosts files,
822 for incremental reads, rhash is NULL, and we use cache lookups
823 instead.
826 if (rhash)
828 /* hash address */
829 for (j = 0, i = 0; i < addrlen; i++)
830 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
832 for (lookup = rhash[j]; lookup; lookup = lookup->next)
833 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
834 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
836 cache->flags &= ~F_REVERSE;
837 break;
840 /* maintain address hash chain, insert new unique address */
841 if (!lookup)
843 cache->next = rhash[j];
844 rhash[j] = cache;
847 else
849 /* incremental read, lookup in cache */
850 lookup = cache_find_by_addr(NULL, addr, 0, cache->flags & (F_IPV4 | F_IPV6));
851 if (lookup && lookup->flags & F_HOSTS)
852 cache->flags &= ~F_REVERSE;
855 cache->uid = index;
856 memcpy(&cache->addr.addr, addr, addrlen);
857 cache_hash(cache);
859 /* don't need to do alias stuff for second and subsequent addresses. */
860 if (!nameexists)
861 add_hosts_cname(cache);
864 static int eatspace(FILE *f)
866 int c, nl = 0;
868 while (1)
870 if ((c = getc(f)) == '#')
871 while (c != '\n' && c != EOF)
872 c = getc(f);
874 if (c == EOF)
875 return 1;
877 if (!isspace(c))
879 ungetc(c, f);
880 return nl;
883 if (c == '\n')
884 nl = 1;
888 static int gettok(FILE *f, char *token)
890 int c, count = 0;
892 while (1)
894 if ((c = getc(f)) == EOF)
895 return (count == 0) ? EOF : 1;
897 if (isspace(c) || c == '#')
899 ungetc(c, f);
900 return eatspace(f);
903 if (count < (MAXDNAME - 1))
905 token[count++] = c;
906 token[count] = 0;
911 int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
913 FILE *f = fopen(filename, "r");
914 char *token = daemon->namebuff, *domain_suffix = NULL;
915 int addr_count = 0, name_count = cache_size, lineno = 0;
916 unsigned short flags = 0;
917 struct all_addr addr;
918 int atnl, addrlen = 0;
920 if (!f)
922 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
923 return cache_size;
926 eatspace(f);
928 while ((atnl = gettok(f, token)) != EOF)
930 lineno++;
932 if (inet_pton(AF_INET, token, &addr) > 0)
934 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
935 addrlen = INADDRSZ;
936 domain_suffix = get_domain(addr.addr.addr4);
938 #ifdef HAVE_IPV6
939 else if (inet_pton(AF_INET6, token, &addr) > 0)
941 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
942 addrlen = IN6ADDRSZ;
943 domain_suffix = get_domain6(&addr.addr.addr6);
945 #endif
946 else
948 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
949 while (atnl == 0)
950 atnl = gettok(f, token);
951 continue;
954 addr_count++;
956 /* rehash every 1000 names. */
957 if (rhash && ((name_count - cache_size) > 1000))
959 rehash(name_count);
960 cache_size = name_count;
963 while (atnl == 0)
965 struct crec *cache;
966 int fqdn, nomem;
967 char *canon;
969 if ((atnl = gettok(f, token)) == EOF)
970 break;
972 fqdn = !!strchr(token, '.');
974 if ((canon = canonicalise(token, &nomem)))
976 /* If set, add a version of the name with a default domain appended */
977 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
978 (cache = whine_malloc(sizeof(struct crec) +
979 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
981 strcpy(cache->name.sname, canon);
982 strcat(cache->name.sname, ".");
983 strcat(cache->name.sname, domain_suffix);
984 cache->flags = flags;
985 cache->ttd = daemon->local_ttl;
986 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
987 name_count++;
989 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
991 strcpy(cache->name.sname, canon);
992 cache->flags = flags;
993 cache->ttd = daemon->local_ttl;
994 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
995 name_count++;
997 free(canon);
1000 else if (!nomem)
1001 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
1005 fclose(f);
1007 if (rhash)
1008 rehash(name_count);
1010 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
1012 return name_count;
1015 void cache_reload(void)
1017 struct crec *cache, **up, *tmp;
1018 int revhashsz, i, total_size = daemon->cachesize;
1019 struct hostsfile *ah;
1020 struct host_record *hr;
1021 struct name_list *nl;
1022 struct cname *a;
1023 struct interface_name *intr;
1024 #ifdef HAVE_DNSSEC
1025 struct ds_config *ds;
1026 #endif
1028 cache_inserted = cache_live_freed = 0;
1030 for (i=0; i<hash_size; i++)
1031 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1033 #ifdef HAVE_DNSSEC
1034 cache_blockdata_free(cache);
1035 #endif
1036 tmp = cache->hash_next;
1037 if (cache->flags & (F_HOSTS | F_CONFIG))
1039 *up = cache->hash_next;
1040 free(cache);
1042 else if (!(cache->flags & F_DHCP))
1044 *up = cache->hash_next;
1045 if (cache->flags & F_BIGNAME)
1047 cache->name.bname->next = big_free;
1048 big_free = cache->name.bname;
1050 cache->flags = 0;
1052 else
1053 up = &cache->hash_next;
1056 /* Add CNAMEs to interface_names to the cache */
1057 for (a = daemon->cnames; a; a = a->next)
1058 for (intr = daemon->int_names; intr; intr = intr->next)
1059 if (hostname_isequal(a->target, intr->name) &&
1060 ((cache = whine_malloc(sizeof(struct crec)))))
1062 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
1063 cache->ttd = a->ttl;
1064 cache->name.namep = a->alias;
1065 cache->addr.cname.target.int_name = intr;
1066 cache->addr.cname.uid = SRC_INTERFACE;
1067 cache->uid = next_uid();
1068 cache_hash(cache);
1069 add_hosts_cname(cache); /* handle chains */
1072 #ifdef HAVE_DNSSEC
1073 for (ds = daemon->ds; ds; ds = ds->next)
1074 if ((cache = whine_malloc(sizeof(struct crec))) &&
1075 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
1077 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
1078 cache->ttd = daemon->local_ttl;
1079 cache->name.namep = ds->name;
1080 cache->addr.ds.keylen = ds->digestlen;
1081 cache->addr.ds.algo = ds->algo;
1082 cache->addr.ds.keytag = ds->keytag;
1083 cache->addr.ds.digest = ds->digest_type;
1084 cache->uid = ds->class;
1085 cache_hash(cache);
1087 #endif
1089 /* borrow the packet buffer for a temporary by-address hash */
1090 memset(daemon->packet, 0, daemon->packet_buff_sz);
1091 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1092 /* we overwrote the buffer... */
1093 daemon->srv_save = NULL;
1095 /* Do host_records in config. */
1096 for (hr = daemon->host_records; hr; hr = hr->next)
1097 for (nl = hr->names; nl; nl = nl->next)
1099 if (hr->addr.s_addr != 0 &&
1100 (cache = whine_malloc(sizeof(struct crec))))
1102 cache->name.namep = nl->name;
1103 cache->ttd = hr->ttl;
1104 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
1105 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1107 #ifdef HAVE_IPV6
1108 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1109 (cache = whine_malloc(sizeof(struct crec))))
1111 cache->name.namep = nl->name;
1112 cache->ttd = hr->ttl;
1113 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
1114 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1116 #endif
1119 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
1121 if (daemon->cachesize > 0)
1122 my_syslog(LOG_INFO, _("cleared cache"));
1124 else
1126 if (!option_bool(OPT_NO_HOSTS))
1127 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1129 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1130 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1131 if (!(ah->flags & AH_INACTIVE))
1132 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1135 #ifdef HAVE_INOTIFY
1136 set_dynamic_inotify(AH_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1137 #endif
1141 #ifdef HAVE_DHCP
1142 struct in_addr a_record_from_hosts(char *name, time_t now)
1144 struct crec *crecp = NULL;
1145 struct in_addr ret;
1147 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1148 if (crecp->flags & F_HOSTS)
1149 return *(struct in_addr *)&crecp->addr;
1151 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1153 ret.s_addr = 0;
1154 return ret;
1157 void cache_unhash_dhcp(void)
1159 struct crec *cache, **up;
1160 int i;
1162 for (i=0; i<hash_size; i++)
1163 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1164 if (cache->flags & F_DHCP)
1166 *up = cache->hash_next;
1167 cache->next = dhcp_spare;
1168 dhcp_spare = cache;
1170 else
1171 up = &cache->hash_next;
1174 static void add_dhcp_cname(struct crec *target, time_t ttd)
1176 struct crec *aliasc;
1177 struct cname *a;
1179 for (a = daemon->cnames; a; a = a->next)
1180 if (hostname_isequal(cache_get_name(target), a->target))
1182 if ((aliasc = dhcp_spare))
1183 dhcp_spare = dhcp_spare->next;
1184 else /* need new one */
1185 aliasc = whine_malloc(sizeof(struct crec));
1187 if (aliasc)
1189 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
1190 if (ttd == 0)
1191 aliasc->flags |= F_IMMORTAL;
1192 else
1193 aliasc->ttd = ttd;
1194 aliasc->name.namep = a->alias;
1195 aliasc->addr.cname.target.cache = target;
1196 aliasc->addr.cname.uid = target->uid;
1197 aliasc->uid = next_uid();
1198 cache_hash(aliasc);
1199 add_dhcp_cname(aliasc, ttd);
1204 void cache_add_dhcp_entry(char *host_name, int prot,
1205 struct all_addr *host_address, time_t ttd)
1207 struct crec *crec = NULL, *fail_crec = NULL;
1208 unsigned short flags = F_IPV4;
1209 int in_hosts = 0;
1210 size_t addrlen = sizeof(struct in_addr);
1212 #ifdef HAVE_IPV6
1213 if (prot == AF_INET6)
1215 flags = F_IPV6;
1216 addrlen = sizeof(struct in6_addr);
1218 #endif
1220 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1222 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
1224 /* check all addresses associated with name */
1225 if (crec->flags & (F_HOSTS | F_CONFIG))
1227 if (crec->flags & F_CNAME)
1228 my_syslog(MS_DHCP | LOG_WARNING,
1229 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1230 host_name, daemon->addrbuff);
1231 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1232 in_hosts = 1;
1233 else
1234 fail_crec = crec;
1236 else if (!(crec->flags & F_DHCP))
1238 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
1239 /* scan_free deletes all addresses associated with name */
1240 break;
1244 /* if in hosts, don't need DHCP record */
1245 if (in_hosts)
1246 return;
1248 /* Name in hosts, address doesn't match */
1249 if (fail_crec)
1251 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1252 my_syslog(MS_DHCP | LOG_WARNING,
1253 _("not giving name %s to the DHCP lease of %s because "
1254 "the name exists in %s with address %s"),
1255 host_name, daemon->addrbuff,
1256 record_source(fail_crec->uid), daemon->namebuff);
1257 return;
1260 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1262 if (crec->flags & F_NEG)
1264 flags |= F_REVERSE;
1265 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1268 else
1269 flags |= F_REVERSE;
1271 if ((crec = dhcp_spare))
1272 dhcp_spare = dhcp_spare->next;
1273 else /* need new one */
1274 crec = whine_malloc(sizeof(struct crec));
1276 if (crec) /* malloc may fail */
1278 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
1279 if (ttd == 0)
1280 crec->flags |= F_IMMORTAL;
1281 else
1282 crec->ttd = ttd;
1283 crec->addr.addr = *host_address;
1284 crec->name.namep = host_name;
1285 crec->uid = next_uid();
1286 cache_hash(crec);
1288 add_dhcp_cname(crec, ttd);
1291 #endif
1293 int cache_make_stat(struct txt_record *t)
1295 static char *buff = NULL;
1296 static int bufflen = 60;
1297 int len;
1298 struct server *serv, *serv1;
1299 char *p;
1301 if (!buff && !(buff = whine_malloc(60)))
1302 return 0;
1304 p = buff;
1306 switch (t->stat)
1308 case TXT_STAT_CACHESIZE:
1309 sprintf(buff+1, "%d", daemon->cachesize);
1310 break;
1312 case TXT_STAT_INSERTS:
1313 sprintf(buff+1, "%d", cache_inserted);
1314 break;
1316 case TXT_STAT_EVICTIONS:
1317 sprintf(buff+1, "%d", cache_live_freed);
1318 break;
1320 case TXT_STAT_MISSES:
1321 sprintf(buff+1, "%u", daemon->queries_forwarded);
1322 break;
1324 case TXT_STAT_HITS:
1325 sprintf(buff+1, "%u", daemon->local_answer);
1326 break;
1328 #ifdef HAVE_AUTH
1329 case TXT_STAT_AUTH:
1330 sprintf(buff+1, "%u", daemon->auth_answer);
1331 break;
1332 #endif
1334 case TXT_STAT_SERVERS:
1335 /* sum counts from different records for same server */
1336 for (serv = daemon->servers; serv; serv = serv->next)
1337 serv->flags &= ~SERV_COUNTED;
1339 for (serv = daemon->servers; serv; serv = serv->next)
1340 if (!(serv->flags &
1341 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1343 char *new, *lenp;
1344 int port, newlen, bytes_avail, bytes_needed;
1345 unsigned int queries = 0, failed_queries = 0;
1346 for (serv1 = serv; serv1; serv1 = serv1->next)
1347 if (!(serv1->flags &
1348 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1349 sockaddr_isequal(&serv->addr, &serv1->addr))
1351 serv1->flags |= SERV_COUNTED;
1352 queries += serv1->queries;
1353 failed_queries += serv1->failed_queries;
1355 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1356 lenp = p++; /* length */
1357 bytes_avail = bufflen - (p - buff );
1358 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1359 if (bytes_needed >= bytes_avail)
1361 /* expand buffer if necessary */
1362 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1363 if (!(new = whine_malloc(newlen)))
1364 return 0;
1365 memcpy(new, buff, bufflen);
1366 free(buff);
1367 p = new + (p - buff);
1368 lenp = p - 1;
1369 buff = new;
1370 bufflen = newlen;
1371 bytes_avail = bufflen - (p - buff );
1372 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1374 *lenp = bytes_needed;
1375 p += bytes_needed;
1377 t->txt = (unsigned char *)buff;
1378 t->len = p - buff;
1379 return 1;
1382 len = strlen(buff+1);
1383 t->txt = (unsigned char *)buff;
1384 t->len = len + 1;
1385 *buff = len;
1386 return 1;
1389 /* There can be names in the cache containing control chars, don't
1390 mess up logging or open security holes. */
1391 static char *sanitise(char *name)
1393 unsigned char *r;
1394 if (name)
1395 for (r = (unsigned char *)name; *r; r++)
1396 if (!isprint((int)*r))
1397 return "<name unprintable>";
1399 return name;
1403 void dump_cache(time_t now)
1405 struct server *serv, *serv1;
1406 char *t = "";
1408 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1409 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1410 daemon->cachesize, cache_live_freed, cache_inserted);
1411 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1412 daemon->queries_forwarded, daemon->local_answer);
1413 #ifdef HAVE_AUTH
1414 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
1415 #endif
1416 #ifdef HAVE_DNSSEC
1417 blockdata_report();
1418 #endif
1420 /* sum counts from different records for same server */
1421 for (serv = daemon->servers; serv; serv = serv->next)
1422 serv->flags &= ~SERV_COUNTED;
1424 for (serv = daemon->servers; serv; serv = serv->next)
1425 if (!(serv->flags &
1426 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1428 int port;
1429 unsigned int queries = 0, failed_queries = 0;
1430 for (serv1 = serv; serv1; serv1 = serv1->next)
1431 if (!(serv1->flags &
1432 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1433 sockaddr_isequal(&serv->addr, &serv1->addr))
1435 serv1->flags |= SERV_COUNTED;
1436 queries += serv1->queries;
1437 failed_queries += serv1->failed_queries;
1439 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1440 my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
1443 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG) || daemon->hosts_cache != NULL)
1445 struct crec *cache ;
1446 int i;
1447 int dumping_hosts = daemon->hosts_cache != NULL;
1448 FILE *hosts_cache = NULL;
1449 if (dumping_hosts) {
1450 hosts_cache = fopen(daemon->hosts_cache, "w");
1451 if (hosts_cache == NULL) {
1452 dumping_hosts = 0;
1453 my_syslog(LOG_WARNING, "Failed to open hosts cache file: \"%s\"", daemon->hosts_cache);
1457 my_syslog(LOG_INFO, "Host Address Flags Expires");
1459 for (i=0; i<hash_size; i++)
1460 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1462 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1463 *a = 0;
1464 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
1465 n = "<Root>";
1466 p += sprintf(p, "%-30.30s ", sanitise(n));
1467 if ((cache->flags & F_CNAME))
1469 if (!is_outdated_cname_pointer(cache))
1470 a = cache_get_cname_target(cache);
1471 if (dumping_hosts)
1472 fprintf(hosts_cache, "#%s\t%s\n", cache_get_cname_target(cache), n);
1474 #ifdef HAVE_DNSSEC
1475 else if (cache->flags & F_DS)
1477 if (!(cache->flags & F_NEG))
1478 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1479 cache->addr.ds.algo, cache->addr.ds.digest);
1481 else if (cache->flags & F_DNSKEY)
1482 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1483 cache->addr.key.algo, cache->addr.key.flags);
1484 #endif
1485 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
1487 a = daemon->addrbuff;
1488 if (cache->flags & F_IPV4)
1489 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
1490 #ifdef HAVE_IPV6
1491 else if (cache->flags & F_IPV6)
1492 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
1493 #endif
1494 if (dumping_hosts)
1495 fprintf(hosts_cache, "%s\t%s\n", a, n);
1498 if (cache->flags & F_IPV4)
1499 t = "4";
1500 else if (cache->flags & F_IPV6)
1501 t = "6";
1502 else if (cache->flags & F_CNAME)
1503 t = "C";
1504 #ifdef HAVE_DNSSEC
1505 else if (cache->flags & F_DS)
1506 t = "S";
1507 else if (cache->flags & F_DNSKEY)
1508 t = "K";
1509 #endif
1510 p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
1511 cache->flags & F_FORWARD ? "F" : " ",
1512 cache->flags & F_REVERSE ? "R" : " ",
1513 cache->flags & F_IMMORTAL ? "I" : " ",
1514 cache->flags & F_DHCP ? "D" : " ",
1515 cache->flags & F_NEG ? "N" : " ",
1516 cache->flags & F_NXDOMAIN ? "X" : " ",
1517 cache->flags & F_HOSTS ? "H" : " ",
1518 cache->flags & F_DNSSECOK ? "V" : " ");
1519 #ifdef HAVE_BROKEN_RTC
1520 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
1521 #else
1522 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1523 /* ctime includes trailing \n - eat it */
1524 *(p-1) = 0;
1525 #endif
1526 my_syslog(LOG_INFO, daemon->namebuff);
1528 if (dumping_hosts)
1529 fclose(hosts_cache);
1533 char *record_source(unsigned int index)
1535 struct hostsfile *ah;
1537 if (index == SRC_CONFIG)
1538 return "config";
1539 else if (index == SRC_HOSTS)
1540 return HOSTSFILE;
1542 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1543 if (ah->index == index)
1544 return ah->fname;
1546 #ifdef HAVE_INOTIFY
1547 for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
1548 if (ah->index == index)
1549 return ah->fname;
1550 #endif
1552 return "<unknown>";
1555 char *querystr(char *desc, unsigned short type)
1557 unsigned int i;
1558 int len = 10; /* strlen("type=xxxxx") */
1559 const char *types = NULL;
1560 static char *buff = NULL;
1561 static int bufflen = 0;
1563 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1564 if (typestr[i].type == type)
1566 types = typestr[i].name;
1567 len = strlen(types);
1568 break;
1571 len += 3; /* braces, terminator */
1572 len += strlen(desc);
1574 if (!buff || bufflen < len)
1576 if (buff)
1577 free(buff);
1578 else if (len < 20)
1579 len = 20;
1581 buff = whine_malloc(len);
1582 bufflen = len;
1585 if (buff)
1587 if (types)
1588 sprintf(buff, "%s[%s]", desc, types);
1589 else
1590 sprintf(buff, "%s[type=%d]", desc, type);
1593 return buff ? buff : "";
1596 void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
1598 char *source, *dest = daemon->addrbuff;
1599 char *verb = "is";
1601 if (!option_bool(OPT_LOG))
1602 return;
1604 name = sanitise(name);
1606 if (addr)
1608 if (flags & F_KEYTAG)
1609 sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
1610 else
1612 #ifdef HAVE_IPV6
1613 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1614 addr, daemon->addrbuff, ADDRSTRLEN);
1615 #else
1616 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1617 #endif
1620 else
1621 dest = arg;
1623 if (flags & F_REVERSE)
1625 dest = name;
1626 name = daemon->addrbuff;
1629 if (flags & F_NEG)
1631 if (flags & F_NXDOMAIN)
1632 dest = "NXDOMAIN";
1633 else
1635 if (flags & F_IPV4)
1636 dest = "NODATA-IPv4";
1637 else if (flags & F_IPV6)
1638 dest = "NODATA-IPv6";
1639 else
1640 dest = "NODATA";
1643 else if (flags & F_CNAME)
1644 dest = "<CNAME>";
1645 else if (flags & F_RRNAME)
1646 dest = arg;
1648 if (flags & F_CONFIG)
1649 source = "config";
1650 else if (flags & F_DHCP)
1651 source = "DHCP";
1652 else if (flags & F_HOSTS)
1653 source = arg;
1654 else if (flags & F_UPSTREAM)
1655 source = "reply";
1656 else if (flags & F_SECSTAT)
1657 source = "validation";
1658 else if (flags & F_AUTH)
1659 source = "auth";
1660 else if (flags & F_SERVER)
1662 source = "forwarded";
1663 verb = "to";
1665 else if (flags & F_QUERY)
1667 source = arg;
1668 verb = "from";
1670 else if (flags & F_DNSSEC)
1672 source = arg;
1673 verb = "to";
1675 else if (flags & F_IPSET)
1677 source = "ipset add";
1678 dest = name;
1679 name = arg;
1680 verb = daemon->addrbuff;
1682 else
1683 source = "cached";
1685 if (strlen(name) == 0)
1686 name = ".";
1688 if (option_bool(OPT_EXTRALOG))
1690 int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
1691 if (flags & F_NOEXTRA)
1692 my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
1693 else
1694 my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
1696 else
1697 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);