Tomato 1.28
[tomato.git] / release / src / router / dnsmasq / src / cache.c
blob6cb95c2f3f2540e28fe7e20cb66cd6f835afab4d
1 /* dnsmasq is Copyright (c) 2000-2010 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;
27 static int uid = 0;
28 static char *addrbuff = NULL;
30 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
31 static const struct {
32 unsigned int type;
33 const char * const name;
34 } typestr[] = {
35 { 1, "A" },
36 { 2, "NS" },
37 { 5, "CNAME" },
38 { 6, "SOA" },
39 { 10, "NULL" },
40 { 11, "WKS" },
41 { 12, "PTR" },
42 { 13, "HINFO" },
43 { 15, "MX" },
44 { 16, "TXT" },
45 { 22, "NSAP" },
46 { 23, "NSAP_PTR" },
47 { 24, "SIG" },
48 { 25, "KEY" },
49 { 28, "AAAA" },
50 { 33, "SRV" },
51 { 35, "NAPTR" },
52 { 36, "KX" },
53 { 37, "CERT" },
54 { 38, "A6" },
55 { 39, "DNAME" },
56 { 41, "OPT" },
57 { 48, "DNSKEY" },
58 { 249, "TKEY" },
59 { 250, "TSIG" },
60 { 251, "IXFR" },
61 { 252, "AXFR" },
62 { 253, "MAILB" },
63 { 254, "MAILA" },
64 { 255, "ANY" }
67 static void cache_free(struct crec *crecp);
68 static void cache_unlink(struct crec *crecp);
69 static void cache_link(struct crec *crecp);
70 static void rehash(int size);
71 static void cache_hash(struct crec *crecp);
73 void cache_init(void)
75 struct crec *crecp;
76 int i;
78 if (daemon->options & OPT_LOG)
79 addrbuff = safe_malloc(ADDRSTRLEN);
81 bignames_left = daemon->cachesize/10;
83 if (daemon->cachesize > 0)
85 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
87 for (i=0; i < daemon->cachesize; i++, crecp++)
89 cache_link(crecp);
90 crecp->flags = 0;
91 crecp->uid = uid++;
95 /* create initial hash table*/
96 rehash(daemon->cachesize);
99 /* 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. */
103 static void rehash(int size)
105 struct crec **new, **old, *p, *tmp;
106 int i, new_size, old_size;
108 /* hash_size is a power of two. */
109 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
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 *));
114 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
115 return;
117 for(i = 0; i < new_size; i++)
118 new[i] = NULL;
120 old = hash_table;
121 old_size = hash_size;
122 hash_table = new;
123 hash_size = new_size;
125 if (old)
127 for (i = 0; i < old_size; i++)
128 for (p = old[i]; p ; p = tmp)
130 tmp = p->hash_next;
131 cache_hash(p);
133 free(old);
137 static struct crec **hash_bucket(char *name)
139 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
140 const unsigned char *mix_tab = (const unsigned char*)typestr;
142 while((c = (unsigned char) *name++))
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';
147 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
150 /* hash_size is a power of two */
151 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
154 static void cache_hash(struct crec *crecp)
156 /* 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 */
161 struct crec **up = hash_bucket(cache_get_name(crecp));
163 if (!(crecp->flags & F_REVERSE))
165 while (*up && ((*up)->flags & F_REVERSE))
166 up = &((*up)->hash_next);
168 if (crecp->flags & F_IMMORTAL)
169 while (*up && !((*up)->flags & F_IMMORTAL))
170 up = &((*up)->hash_next);
172 crecp->hash_next = *up;
173 *up = crecp;
176 static void cache_free(struct crec *crecp)
178 crecp->flags &= ~F_FORWARD;
179 crecp->flags &= ~F_REVERSE;
180 crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
182 if (cache_tail)
183 cache_tail->next = crecp;
184 else
185 cache_head = crecp;
186 crecp->prev = cache_tail;
187 crecp->next = NULL;
188 cache_tail = crecp;
190 /* retrieve big name for further use. */
191 if (crecp->flags & F_BIGNAME)
193 crecp->name.bname->next = big_free;
194 big_free = crecp->name.bname;
195 crecp->flags &= ~F_BIGNAME;
199 /* insert a new cache entry at the head of the list (youngest entry) */
200 static void cache_link(struct crec *crecp)
202 if (cache_head) /* check needed for init code */
203 cache_head->prev = crecp;
204 crecp->next = cache_head;
205 crecp->prev = NULL;
206 cache_head = crecp;
207 if (!cache_tail)
208 cache_tail = crecp;
211 /* remove an arbitrary cache entry for promotion */
212 static void cache_unlink (struct crec *crecp)
214 if (crecp->prev)
215 crecp->prev->next = crecp->next;
216 else
217 cache_head = crecp->next;
219 if (crecp->next)
220 crecp->next->prev = crecp->prev;
221 else
222 cache_tail = crecp->prev;
225 char *cache_get_name(struct crec *crecp)
227 if (crecp->flags & F_BIGNAME)
228 return crecp->name.bname->name;
229 else if (crecp->flags & (F_DHCP | F_CONFIG))
230 return crecp->name.namep;
232 return crecp->name.sname;
235 static int is_outdated_cname_pointer(struct crec *crecp)
237 if (!(crecp->flags & F_CNAME))
238 return 0;
240 if (crecp->addr.cname.cache && crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
241 return 0;
243 return 1;
246 static int is_expired(time_t now, struct crec *crecp)
248 if (crecp->flags & F_IMMORTAL)
249 return 0;
251 if (difftime(now, crecp->ttd) < 0)
252 return 0;
254 return 1;
257 static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
259 /* Scan and remove old entries.
260 If (flags & F_FORWARD) then remove any forward entries for name and any expired
261 entries but only in the same hash bucket as name.
262 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
263 entries in the whole cache.
264 If (flags == 0) remove any expired entries in the whole cache.
266 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
267 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
269 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
270 so that when we hit an entry which isn't reverse and is immortal, we're done. */
272 struct crec *crecp, **up;
274 if (flags & F_FORWARD)
276 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
277 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
279 *up = crecp->hash_next;
280 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
282 cache_unlink(crecp);
283 cache_free(crecp);
286 else if ((crecp->flags & F_FORWARD) &&
287 ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || ((crecp->flags | flags) & F_CNAME)) &&
288 hostname_isequal(cache_get_name(crecp), name))
290 if (crecp->flags & (F_HOSTS | F_DHCP))
291 return 0;
292 *up = crecp->hash_next;
293 cache_unlink(crecp);
294 cache_free(crecp);
296 else
297 up = &crecp->hash_next;
299 else
301 int i;
302 #ifdef HAVE_IPV6
303 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
304 #else
305 int addrlen = INADDRSZ;
306 #endif
307 for (i = 0; i < hash_size; i++)
308 for (crecp = hash_table[i], up = &hash_table[i];
309 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
310 crecp = crecp->hash_next)
311 if (is_expired(now, crecp))
313 *up = crecp->hash_next;
314 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
316 cache_unlink(crecp);
317 cache_free(crecp);
320 else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
321 (flags & crecp->flags & F_REVERSE) &&
322 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
323 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
325 *up = crecp->hash_next;
326 cache_unlink(crecp);
327 cache_free(crecp);
329 else
330 up = &crecp->hash_next;
333 return 1;
336 /* Note: The normal calling sequence is
337 cache_start_insert
338 cache_insert * n
339 cache_end_insert
341 but an abort can cause the cache_end_insert to be missed
342 in which can the next cache_start_insert cleans things up. */
344 void cache_start_insert(void)
346 /* Free any entries which didn't get committed during the last
347 insert due to error.
349 while (new_chain)
351 struct crec *tmp = new_chain->next;
352 cache_free(new_chain);
353 new_chain = tmp;
355 new_chain = NULL;
356 insert_error = 0;
359 struct crec *cache_insert(char *name, struct all_addr *addr,
360 time_t now, unsigned long ttl, unsigned short flags)
362 struct crec *new;
363 union bigname *big_name = NULL;
364 int freed_all = flags & F_REVERSE;
365 int free_avail = 0;
367 log_query(flags | F_UPSTREAM, name, addr, NULL);
369 /* CONFIG bit means something else when stored in cache entries */
370 flags &= ~F_CONFIG;
372 /* if previous insertion failed give up now. */
373 if (insert_error)
374 return NULL;
376 /* First remove any expired entries and entries for the name/address we
377 are currently inserting. Fail is we attempt to delete a name from
378 /etc/hosts or DHCP. */
379 if (!cache_scan_free(name, addr, now, flags))
381 insert_error = 1;
382 return NULL;
385 /* Now get a cache entry from the end of the LRU list */
386 while (1) {
387 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
389 insert_error = 1;
390 return NULL;
393 /* End of LRU list is still in use: if we didn't scan all the hash
394 chains for expired entries do that now. If we already tried that
395 then it's time to start spilling things. */
397 if (new->flags & (F_FORWARD | F_REVERSE))
399 /* If free_avail set, we believe that an entry has been freed.
400 Bugs have been known to make this not true, resulting in
401 a tight loop here. If that happens, abandon the
402 insert. Once in this state, all inserts will probably fail. */
403 if (free_avail)
405 insert_error = 1;
406 return NULL;
409 if (freed_all)
411 free_avail = 1; /* Must be free space now. */
412 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
413 cache_live_freed++;
415 else
417 cache_scan_free(NULL, NULL, now, 0);
418 freed_all = 1;
420 continue;
423 /* Check if we need to and can allocate extra memory for a long name.
424 If that fails, give up now. */
425 if (name && (strlen(name) > SMALLDNAME-1))
427 if (big_free)
429 big_name = big_free;
430 big_free = big_free->next;
432 else if (!bignames_left ||
433 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
435 insert_error = 1;
436 return NULL;
438 else
439 bignames_left--;
443 /* Got the rest: finally grab entry. */
444 cache_unlink(new);
445 break;
448 new->flags = flags;
449 if (big_name)
451 new->name.bname = big_name;
452 new->flags |= F_BIGNAME;
455 if (name)
456 strcpy(cache_get_name(new), name);
457 else
458 *cache_get_name(new) = 0;
460 if (addr)
461 new->addr.addr = *addr;
462 else
463 new->addr.cname.cache = NULL;
465 new->ttd = now + (time_t)ttl;
466 new->next = new_chain;
467 new_chain = new;
469 return new;
472 /* after end of insertion, commit the new entries */
473 void cache_end_insert(void)
475 if (insert_error)
476 return;
478 while (new_chain)
480 struct crec *tmp = new_chain->next;
481 /* drop CNAMEs which didn't find a target. */
482 if (is_outdated_cname_pointer(new_chain))
483 cache_free(new_chain);
484 else
486 cache_hash(new_chain);
487 cache_link(new_chain);
488 cache_inserted++;
490 new_chain = tmp;
492 new_chain = NULL;
495 struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
497 struct crec *ans;
499 if (crecp) /* iterating */
500 ans = crecp->next;
501 else
503 /* first search, look for relevant entries and push to top of list
504 also free anything which has expired */
505 struct crec *next, **up, **insert = NULL, **chainp = &ans;
506 int ins_flags = 0;
508 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
510 next = crecp->hash_next;
512 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
514 if ((crecp->flags & F_FORWARD) &&
515 (crecp->flags & prot) &&
516 hostname_isequal(cache_get_name(crecp), name))
518 if (crecp->flags & (F_HOSTS | F_DHCP))
520 *chainp = crecp;
521 chainp = &crecp->next;
523 else
525 cache_unlink(crecp);
526 cache_link(crecp);
529 /* Move all but the first entry up the hash chain
530 this implements round-robin.
531 Make sure that re-ordering doesn't break the hash-chain
532 order invariants.
534 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
536 *up = crecp->hash_next;
537 crecp->hash_next = *insert;
538 *insert = crecp;
539 insert = &crecp->hash_next;
541 else
543 if (!insert)
545 insert = up;
546 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
548 up = &crecp->hash_next;
551 else
552 /* case : not expired, incorrect entry. */
553 up = &crecp->hash_next;
555 else
557 /* expired entry, free it */
558 *up = crecp->hash_next;
559 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
561 cache_unlink(crecp);
562 cache_free(crecp);
567 *chainp = cache_head;
570 if (ans &&
571 (ans->flags & F_FORWARD) &&
572 (ans->flags & prot) &&
573 hostname_isequal(cache_get_name(ans), name))
574 return ans;
576 return NULL;
579 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
580 time_t now, unsigned short prot)
582 struct crec *ans;
583 #ifdef HAVE_IPV6
584 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
585 #else
586 int addrlen = INADDRSZ;
587 #endif
589 if (crecp) /* iterating */
590 ans = crecp->next;
591 else
593 /* first search, look for relevant entries and push to top of list
594 also free anything which has expired. All the reverse entries are at the
595 start of the hash chain, so we can give up when we find the first
596 non-REVERSE one. */
597 int i;
598 struct crec **up, **chainp = &ans;
600 for (i=0; i<hash_size; i++)
601 for (crecp = hash_table[i], up = &hash_table[i];
602 crecp && (crecp->flags & F_REVERSE);
603 crecp = crecp->hash_next)
604 if (!is_expired(now, crecp))
606 if ((crecp->flags & prot) &&
607 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
609 if (crecp->flags & (F_HOSTS | F_DHCP))
611 *chainp = crecp;
612 chainp = &crecp->next;
614 else
616 cache_unlink(crecp);
617 cache_link(crecp);
620 up = &crecp->hash_next;
622 else
624 *up = crecp->hash_next;
625 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
627 cache_unlink(crecp);
628 cache_free(crecp);
632 *chainp = cache_head;
635 if (ans &&
636 (ans->flags & F_REVERSE) &&
637 (ans->flags & prot) &&
638 memcmp(&ans->addr.addr, addr, addrlen) == 0)
639 return ans;
641 return NULL;
644 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
645 unsigned short flags, int index, int addr_dup)
647 struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
648 int i, nameexists = 0;
649 struct cname *a;
651 /* Remove duplicates in hosts files. */
652 if (lookup && (lookup->flags & F_HOSTS))
654 nameexists = 1;
655 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
657 free(cache);
658 return;
662 /* Ensure there is only one address -> name mapping (first one trumps)
663 We do this by steam here, first we see if the address is the same as
664 the last one we saw, which eliminates most in the case of an ad-block
665 file with thousands of entries for the same address.
666 Then we search and bail at the first matching address that came from
667 a HOSTS file. Since the first host entry gets reverse, we know
668 then that it must exist without searching exhaustively for it. */
670 if (addr_dup)
671 flags &= ~F_REVERSE;
672 else
673 for (i=0; i<hash_size; i++)
675 for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
676 if ((lookup->flags & F_HOSTS) &&
677 (lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
678 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
680 flags &= ~F_REVERSE;
681 break;
683 if (lookup)
684 break;
687 cache->flags = flags;
688 cache->uid = index;
689 memcpy(&cache->addr.addr, addr, addrlen);
690 cache_hash(cache);
692 /* don't need to do alias stuff for second and subsequent addresses. */
693 if (!nameexists)
694 for (a = daemon->cnames; a; a = a->next)
695 if (hostname_isequal(cache->name.sname, a->target) &&
696 (lookup = whine_malloc(sizeof(struct crec))))
698 lookup->flags = F_FORWARD | F_IMMORTAL | F_CONFIG | F_HOSTS | F_CNAME;
699 lookup->name.namep = a->alias;
700 lookup->addr.cname.cache = cache;
701 lookup->addr.cname.uid = index;
702 cache_hash(lookup);
706 static int eatspace(FILE *f)
708 int c, nl = 0;
710 while (1)
712 if ((c = getc(f)) == '#')
713 while (c != '\n' && c != EOF)
714 c = getc(f);
716 if (c == EOF)
717 return 1;
719 if (!isspace(c))
721 ungetc(c, f);
722 return nl;
725 if (c == '\n')
726 nl = 1;
730 static int gettok(FILE *f, char *token)
732 int c, count = 0;
734 while (1)
736 if ((c = getc(f)) == EOF)
737 return (count == 0) ? EOF : 1;
739 if (isspace(c) || c == '#')
741 ungetc(c, f);
742 return eatspace(f);
745 if (count < (MAXDNAME - 1))
747 token[count++] = c;
748 token[count] = 0;
753 static int read_hostsfile(char *filename, int index, int cache_size)
755 FILE *f = fopen(filename, "r");
756 char *token = daemon->namebuff, *domain_suffix = NULL;
757 int addr_count = 0, name_count = cache_size, lineno = 0;
758 unsigned short flags = 0, saved_flags = 0;
759 struct all_addr addr, saved_addr;
760 int atnl, addrlen = 0, addr_dup;
762 if (!f)
764 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
765 return 0;
768 eatspace(f);
770 while ((atnl = gettok(f, token)) != EOF)
772 addr_dup = 0;
773 lineno++;
775 #ifdef HAVE_IPV6
776 if (inet_pton(AF_INET, token, &addr) > 0)
778 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
779 addrlen = INADDRSZ;
780 domain_suffix = get_domain(addr.addr.addr4);
782 else if (inet_pton(AF_INET6, token, &addr) > 0)
784 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
785 addrlen = IN6ADDRSZ;
786 domain_suffix = daemon->domain_suffix;
788 #else
789 if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
791 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
792 addrlen = INADDRSZ;
793 domain_suffix = get_domain(addr.addr.addr4);
795 #endif
796 else
798 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
799 while (atnl == 0)
800 atnl = gettok(f, token);
801 continue;
804 if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
805 addr_dup = 1;
806 else
808 saved_flags = flags;
809 saved_addr = addr;
812 addr_count++;
814 /* rehash every 1000 names. */
815 if ((name_count - cache_size) > 1000)
817 rehash(name_count);
818 cache_size = name_count;
821 while (atnl == 0)
823 struct crec *cache;
824 int fqdn, nomem;
825 char *canon;
827 if ((atnl = gettok(f, token)) == EOF)
828 break;
830 fqdn = !!strchr(token, '.');
832 if ((canon = canonicalise(token, &nomem)))
834 /* If set, add a version of the name with a default domain appended */
835 if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
836 (cache = whine_malloc(sizeof(struct crec) +
837 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
839 strcpy(cache->name.sname, canon);
840 strcat(cache->name.sname, ".");
841 strcat(cache->name.sname, domain_suffix);
842 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
843 addr_dup = 1;
844 name_count++;
846 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
848 strcpy(cache->name.sname, canon);
849 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
850 name_count++;
852 free(canon);
855 else if (!nomem)
856 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
860 fclose(f);
861 rehash(name_count);
863 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
865 return name_count;
868 void cache_reload(void)
870 struct crec *cache, **up, *tmp;
871 int i, total_size = daemon->cachesize;
872 struct hostsfile *ah;
874 cache_inserted = cache_live_freed = 0;
876 for (i=0; i<hash_size; i++)
877 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
879 tmp = cache->hash_next;
880 if (cache->flags & F_HOSTS)
882 *up = cache->hash_next;
883 free(cache);
885 else if (!(cache->flags & F_DHCP))
887 *up = cache->hash_next;
888 if (cache->flags & F_BIGNAME)
890 cache->name.bname->next = big_free;
891 big_free = cache->name.bname;
893 cache->flags = 0;
895 else
896 up = &cache->hash_next;
899 if ((daemon->options & OPT_NO_HOSTS) && !daemon->addn_hosts)
901 if (daemon->cachesize > 0)
902 my_syslog(LOG_INFO, _("cleared cache"));
903 return;
906 if (!(daemon->options & OPT_NO_HOSTS))
907 total_size = read_hostsfile(HOSTSFILE, 0, total_size);
909 for (i = 0, ah = daemon->addn_hosts; ah; ah = ah->next)
911 if (i <= ah->index)
912 i = ah->index + 1;
914 if (ah->flags & AH_DIR)
915 ah->flags |= AH_INACTIVE;
916 else
917 ah->flags &= ~AH_INACTIVE;
920 for (ah = daemon->addn_hosts; ah; ah = ah->next)
921 if (!(ah->flags & AH_INACTIVE))
923 struct stat buf;
924 if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
926 DIR *dir_stream;
927 struct dirent *ent;
929 /* don't read this as a file */
930 ah->flags |= AH_INACTIVE;
932 if (!(dir_stream = opendir(ah->fname)))
933 my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
934 ah->fname, strerror(errno));
935 else
937 while ((ent = readdir(dir_stream)))
939 size_t lendir = strlen(ah->fname);
940 size_t lenfile = strlen(ent->d_name);
941 struct hostsfile *ah1;
942 char *path;
944 /* ignore emacs backups and dotfiles */
945 if (lenfile == 0 ||
946 ent->d_name[lenfile - 1] == '~' ||
947 (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
948 ent->d_name[0] == '.')
949 continue;
951 /* see if we have an existing record.
952 dir is ah->fname
953 file is ent->d_name
954 path to match is ah1->fname */
956 for (ah1 = daemon->addn_hosts; ah1; ah1 = ah1->next)
958 if (lendir < strlen(ah1->fname) &&
959 strstr(ah1->fname, ah->fname) == ah1->fname &&
960 ah1->fname[lendir] == '/' &&
961 strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
963 ah1->flags &= ~AH_INACTIVE;
964 break;
968 /* make new record */
969 if (!ah1)
971 if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
972 continue;
974 if (!(path = whine_malloc(lendir + lenfile + 2)))
976 free(ah1);
977 continue;
980 strcpy(path, ah->fname);
981 strcat(path, "/");
982 strcat(path, ent->d_name);
983 ah1->fname = path;
984 ah1->index = i++;
985 ah1->flags = AH_DIR;
986 ah1->next = daemon->addn_hosts;
987 daemon->addn_hosts = ah1;
990 /* inactivate record if not regular file */
991 if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
992 ah1->flags |= AH_INACTIVE;
995 closedir(dir_stream);
1000 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1001 if (!(ah->flags & AH_INACTIVE))
1002 total_size = read_hostsfile(ah->fname, ah->index, total_size);
1005 char *get_domain(struct in_addr addr)
1007 struct cond_domain *c;
1009 for (c = daemon->cond_domain; c; c = c->next)
1010 if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
1011 ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
1012 return c->domain;
1014 return daemon->domain_suffix;
1017 #ifdef HAVE_DHCP
1018 void cache_unhash_dhcp(void)
1020 struct crec *cache, **up;
1021 int i;
1023 for (i=0; i<hash_size; i++)
1024 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1025 if (cache->flags & F_DHCP)
1027 *up = cache->hash_next;
1028 cache->next = dhcp_spare;
1029 dhcp_spare = cache;
1031 else
1032 up = &cache->hash_next;
1035 void cache_add_dhcp_entry(char *host_name,
1036 struct in_addr *host_address, time_t ttd)
1038 struct crec *crec = NULL, *aliasc;
1039 unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
1040 int in_hosts = 0;
1041 struct cname *a;
1043 while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
1045 /* check all addresses associated with name */
1046 if (crec->flags & F_HOSTS)
1048 /* if in hosts, don't need DHCP record */
1049 in_hosts = 1;
1051 if (crec->flags & F_CNAME)
1052 my_syslog(LOG_WARNING,
1053 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1054 host_name, inet_ntoa(*host_address));
1055 else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
1057 strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
1058 my_syslog(LOG_WARNING,
1059 _("not giving name %s to the DHCP lease of %s because "
1060 "the name exists in %s with address %s"),
1061 host_name, inet_ntoa(*host_address),
1062 record_source(crec->uid), daemon->namebuff);
1065 else if (!(crec->flags & F_DHCP))
1067 cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
1068 /* scan_free deletes all addresses associated with name */
1069 break;
1073 if (in_hosts)
1074 return;
1076 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
1078 if (crec->flags & F_NEG)
1079 cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
1080 else
1081 /* avoid multiple reverse mappings */
1082 flags &= ~F_REVERSE;
1085 if ((crec = dhcp_spare))
1086 dhcp_spare = dhcp_spare->next;
1087 else /* need new one */
1088 crec = whine_malloc(sizeof(struct crec));
1090 if (crec) /* malloc may fail */
1092 crec->flags = flags;
1093 if (ttd == 0)
1094 crec->flags |= F_IMMORTAL;
1095 else
1096 crec->ttd = ttd;
1097 crec->addr.addr.addr.addr4 = *host_address;
1098 crec->name.namep = host_name;
1099 crec->uid = uid++;
1100 cache_hash(crec);
1102 for (a = daemon->cnames; a; a = a->next)
1103 if (hostname_isequal(host_name, a->target))
1105 if ((aliasc = dhcp_spare))
1106 dhcp_spare = dhcp_spare->next;
1107 else /* need new one */
1108 aliasc = whine_malloc(sizeof(struct crec));
1110 if (aliasc)
1112 aliasc->flags = F_FORWARD | F_CONFIG | F_DHCP | F_CNAME;
1113 if (ttd == 0)
1114 aliasc->flags |= F_IMMORTAL;
1115 else
1116 aliasc->ttd = ttd;
1117 aliasc->name.namep = a->alias;
1118 aliasc->addr.cname.cache = crec;
1119 aliasc->addr.cname.uid = crec->uid;
1120 cache_hash(aliasc);
1125 #endif
1128 void dump_cache(time_t now)
1130 struct server *serv, *serv1;
1132 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1133 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1134 daemon->cachesize, cache_live_freed, cache_inserted);
1135 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1136 daemon->queries_forwarded, daemon->local_answer);
1138 if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN)))
1139 return;
1141 /* sum counts from different records for same server */
1142 for (serv = daemon->servers; serv; serv = serv->next)
1143 serv->flags &= ~SERV_COUNTED;
1145 for (serv = daemon->servers; serv; serv = serv->next)
1146 if (!(serv->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)))
1148 int port;
1149 unsigned int queries = 0, failed_queries = 0;
1150 for (serv1 = serv; serv1; serv1 = serv1->next)
1151 if (!(serv1->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)) && sockaddr_isequal(&serv->addr, &serv1->addr))
1153 serv1->flags |= SERV_COUNTED;
1154 queries += serv1->queries;
1155 failed_queries += serv1->failed_queries;
1157 port = prettyprint_addr(&serv->addr, addrbuff);
1158 my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
1161 if ((daemon->options & (OPT_DEBUG | OPT_LOG)))
1163 struct crec *cache ;
1164 int i;
1165 my_syslog(LOG_DEBUG, "Host Address Flags Expires");
1167 for (i=0; i<hash_size; i++)
1168 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1170 char *a, *p = daemon->namebuff;
1171 p += sprintf(p, "%-40.40s ", cache_get_name(cache));
1172 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
1173 a = "";
1174 else if (cache->flags & F_CNAME)
1176 a = "";
1177 if (!is_outdated_cname_pointer(cache))
1178 a = cache_get_name(cache->addr.cname.cache);
1180 #ifdef HAVE_IPV6
1181 else
1183 a = addrbuff;
1184 if (cache->flags & F_IPV4)
1185 inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
1186 else if (cache->flags & F_IPV6)
1187 inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
1189 #else
1190 else
1191 a = inet_ntoa(cache->addr.addr.addr.addr4);
1192 #endif
1193 p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s ", a,
1194 cache->flags & F_IPV4 ? "4" : "",
1195 cache->flags & F_IPV6 ? "6" : "",
1196 cache->flags & F_CNAME ? "C" : "",
1197 cache->flags & F_FORWARD ? "F" : " ",
1198 cache->flags & F_REVERSE ? "R" : " ",
1199 cache->flags & F_IMMORTAL ? "I" : " ",
1200 cache->flags & F_DHCP ? "D" : " ",
1201 cache->flags & F_NEG ? "N" : " ",
1202 cache->flags & F_NXDOMAIN ? "X" : " ",
1203 cache->flags & F_HOSTS ? "H" : " ");
1204 #ifdef HAVE_BROKEN_RTC
1205 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
1206 #else
1207 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1208 /* ctime includes trailing \n - eat it */
1209 *(p-1) = 0;
1210 #endif
1211 my_syslog(LOG_DEBUG, daemon->namebuff);
1216 char *record_source(int index)
1218 struct hostsfile *ah;
1220 if (index == 0)
1221 return HOSTSFILE;
1223 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1224 if (ah->index == index)
1225 return ah->fname;
1227 return "<unknown>";
1230 void querystr(char *str, unsigned short type)
1232 unsigned int i;
1234 sprintf(str, "query[type=%d]", type);
1235 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1236 if (typestr[i].type == type)
1237 sprintf(str,"query[%s]", typestr[i].name);
1240 void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg)
1242 char *source, *dest = addrbuff;
1243 char *verb = "is";
1245 if (!(daemon->options & OPT_LOG))
1246 return;
1248 if (addr)
1250 #ifdef HAVE_IPV6
1251 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1252 addr, addrbuff, ADDRSTRLEN);
1253 #else
1254 strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1255 #endif
1258 if (flags & F_REVERSE)
1260 dest = name;
1261 name = addrbuff;
1264 if (flags & F_NEG)
1266 if (flags & F_NXDOMAIN)
1268 if (flags & F_IPV4)
1269 dest = "NXDOMAIN-IPv4";
1270 else if (flags & F_IPV6)
1271 dest = "NXDOMAIN-IPv6";
1272 else
1273 dest = "NXDOMAIN";
1275 else
1277 if (flags & F_IPV4)
1278 dest = "NODATA-IPv4";
1279 else if (flags & F_IPV6)
1280 dest = "NODATA-IPv6";
1281 else
1282 dest = "NODATA";
1285 else if (flags & F_CNAME)
1287 /* nasty abuse of NXDOMAIN and CNAME flags */
1288 if (flags & F_NXDOMAIN)
1289 dest = arg;
1290 else
1291 dest = "<CNAME>";
1294 if (flags & F_CONFIG)
1295 source = "config";
1296 else if (flags & F_DHCP)
1297 source = "DHCP";
1298 else if (flags & F_HOSTS)
1299 source = arg;
1300 else if (flags & F_UPSTREAM)
1301 source = "reply";
1302 else if (flags & F_SERVER)
1304 source = "forwarded";
1305 verb = "to";
1307 else if (flags & F_QUERY)
1309 source = arg;
1310 verb = "from";
1312 else
1313 source = "cached";
1315 if (strlen(name) == 0)
1316 name = ".";
1318 my_syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, dest);