]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/cache.c
import of dnsmasq-2.58.tar.gz
[people/ms/dnsmasq.git] / src / cache.c
1 /* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
2
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.
7
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.
12
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/>.
15 */
16
17 #include "dnsmasq.h"
18
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;
29
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" }
65 };
66
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);
72
73 void cache_init(void)
74 {
75 struct crec *crecp;
76 int i;
77
78 if (option_bool(OPT_LOG))
79 addrbuff = safe_malloc(ADDRSTRLEN);
80
81 bignames_left = daemon->cachesize/10;
82
83 if (daemon->cachesize > 0)
84 {
85 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
86
87 for (i=0; i < daemon->cachesize; i++, crecp++)
88 {
89 cache_link(crecp);
90 crecp->flags = 0;
91 crecp->uid = uid++;
92 }
93 }
94
95 /* create initial hash table*/
96 rehash(daemon->cachesize);
97 }
98
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)
104 {
105 struct crec **new, **old, *p, *tmp;
106 int i, new_size, old_size;
107
108 /* hash_size is a power of two. */
109 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
110
111 /* must succeed in getting first instance, failure later is non-fatal */
112 if (!hash_table)
113 new = safe_malloc(new_size * sizeof(struct crec *));
114 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
115 return;
116
117 for(i = 0; i < new_size; i++)
118 new[i] = NULL;
119
120 old = hash_table;
121 old_size = hash_size;
122 hash_table = new;
123 hash_size = new_size;
124
125 if (old)
126 {
127 for (i = 0; i < old_size; i++)
128 for (p = old[i]; p ; p = tmp)
129 {
130 tmp = p->hash_next;
131 cache_hash(p);
132 }
133 free(old);
134 }
135 }
136
137 static struct crec **hash_bucket(char *name)
138 {
139 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
140 const unsigned char *mix_tab = (const unsigned char*)typestr;
141
142 while((c = (unsigned char) *name++))
143 {
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);
148 }
149
150 /* hash_size is a power of two */
151 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
152 }
153
154 static void cache_hash(struct crec *crecp)
155 {
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 */
160
161 struct crec **up = hash_bucket(cache_get_name(crecp));
162
163 if (!(crecp->flags & F_REVERSE))
164 {
165 while (*up && ((*up)->flags & F_REVERSE))
166 up = &((*up)->hash_next);
167
168 if (crecp->flags & F_IMMORTAL)
169 while (*up && !((*up)->flags & F_IMMORTAL))
170 up = &((*up)->hash_next);
171 }
172 crecp->hash_next = *up;
173 *up = crecp;
174 }
175
176 static void cache_free(struct crec *crecp)
177 {
178 crecp->flags &= ~F_FORWARD;
179 crecp->flags &= ~F_REVERSE;
180 crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
181
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;
189
190 /* retrieve big name for further use. */
191 if (crecp->flags & F_BIGNAME)
192 {
193 crecp->name.bname->next = big_free;
194 big_free = crecp->name.bname;
195 crecp->flags &= ~F_BIGNAME;
196 }
197 }
198
199 /* insert a new cache entry at the head of the list (youngest entry) */
200 static void cache_link(struct crec *crecp)
201 {
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;
209 }
210
211 /* remove an arbitrary cache entry for promotion */
212 static void cache_unlink (struct crec *crecp)
213 {
214 if (crecp->prev)
215 crecp->prev->next = crecp->next;
216 else
217 cache_head = crecp->next;
218
219 if (crecp->next)
220 crecp->next->prev = crecp->prev;
221 else
222 cache_tail = crecp->prev;
223 }
224
225 char *cache_get_name(struct crec *crecp)
226 {
227 if (crecp->flags & F_BIGNAME)
228 return crecp->name.bname->name;
229 else if (crecp->flags & F_NAMEP)
230 return crecp->name.namep;
231
232 return crecp->name.sname;
233 }
234
235 static int is_outdated_cname_pointer(struct crec *crecp)
236 {
237 if (!(crecp->flags & F_CNAME))
238 return 0;
239
240 if (crecp->addr.cname.cache && crecp->addr.cname.uid == crecp->addr.cname.cache->uid)
241 return 0;
242
243 return 1;
244 }
245
246 static int is_expired(time_t now, struct crec *crecp)
247 {
248 if (crecp->flags & F_IMMORTAL)
249 return 0;
250
251 if (difftime(now, crecp->ttd) < 0)
252 return 0;
253
254 return 1;
255 }
256
257 static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
258 {
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.
265
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)
268
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. */
271
272 struct crec *crecp, **up;
273
274 if (flags & F_FORWARD)
275 {
276 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
277 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
278 {
279 *up = crecp->hash_next;
280 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
281 {
282 cache_unlink(crecp);
283 cache_free(crecp);
284 }
285 }
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))
289 {
290 if (crecp->flags & (F_HOSTS | F_DHCP))
291 return 0;
292 *up = crecp->hash_next;
293 cache_unlink(crecp);
294 cache_free(crecp);
295 }
296 else
297 up = &crecp->hash_next;
298 }
299 else
300 {
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))
312 {
313 *up = crecp->hash_next;
314 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
315 {
316 cache_unlink(crecp);
317 cache_free(crecp);
318 }
319 }
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)
324 {
325 *up = crecp->hash_next;
326 cache_unlink(crecp);
327 cache_free(crecp);
328 }
329 else
330 up = &crecp->hash_next;
331 }
332
333 return 1;
334 }
335
336 /* Note: The normal calling sequence is
337 cache_start_insert
338 cache_insert * n
339 cache_end_insert
340
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. */
343
344 void cache_start_insert(void)
345 {
346 /* Free any entries which didn't get committed during the last
347 insert due to error.
348 */
349 while (new_chain)
350 {
351 struct crec *tmp = new_chain->next;
352 cache_free(new_chain);
353 new_chain = tmp;
354 }
355 new_chain = NULL;
356 insert_error = 0;
357 }
358
359 struct crec *cache_insert(char *name, struct all_addr *addr,
360 time_t now, unsigned long ttl, unsigned short flags)
361 {
362 struct crec *new;
363 union bigname *big_name = NULL;
364 int freed_all = flags & F_REVERSE;
365 int free_avail = 0;
366
367 log_query(flags | F_UPSTREAM, name, addr, NULL);
368
369 /* if previous insertion failed give up now. */
370 if (insert_error)
371 return NULL;
372
373 /* First remove any expired entries and entries for the name/address we
374 are currently inserting. Fail is we attempt to delete a name from
375 /etc/hosts or DHCP. */
376 if (!cache_scan_free(name, addr, now, flags))
377 {
378 insert_error = 1;
379 return NULL;
380 }
381
382 /* Now get a cache entry from the end of the LRU list */
383 while (1) {
384 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
385 {
386 insert_error = 1;
387 return NULL;
388 }
389
390 /* End of LRU list is still in use: if we didn't scan all the hash
391 chains for expired entries do that now. If we already tried that
392 then it's time to start spilling things. */
393
394 if (new->flags & (F_FORWARD | F_REVERSE))
395 {
396 /* If free_avail set, we believe that an entry has been freed.
397 Bugs have been known to make this not true, resulting in
398 a tight loop here. If that happens, abandon the
399 insert. Once in this state, all inserts will probably fail. */
400 if (free_avail)
401 {
402 insert_error = 1;
403 return NULL;
404 }
405
406 if (freed_all)
407 {
408 free_avail = 1; /* Must be free space now. */
409 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
410 cache_live_freed++;
411 }
412 else
413 {
414 cache_scan_free(NULL, NULL, now, 0);
415 freed_all = 1;
416 }
417 continue;
418 }
419
420 /* Check if we need to and can allocate extra memory for a long name.
421 If that fails, give up now. */
422 if (name && (strlen(name) > SMALLDNAME-1))
423 {
424 if (big_free)
425 {
426 big_name = big_free;
427 big_free = big_free->next;
428 }
429 else if (!bignames_left ||
430 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
431 {
432 insert_error = 1;
433 return NULL;
434 }
435 else
436 bignames_left--;
437
438 }
439
440 /* Got the rest: finally grab entry. */
441 cache_unlink(new);
442 break;
443 }
444
445 new->flags = flags;
446 if (big_name)
447 {
448 new->name.bname = big_name;
449 new->flags |= F_BIGNAME;
450 }
451
452 if (name)
453 strcpy(cache_get_name(new), name);
454 else
455 *cache_get_name(new) = 0;
456
457 if (addr)
458 new->addr.addr = *addr;
459 else
460 new->addr.cname.cache = NULL;
461
462 new->ttd = now + (time_t)ttl;
463 new->next = new_chain;
464 new_chain = new;
465
466 return new;
467 }
468
469 /* after end of insertion, commit the new entries */
470 void cache_end_insert(void)
471 {
472 if (insert_error)
473 return;
474
475 while (new_chain)
476 {
477 struct crec *tmp = new_chain->next;
478 /* drop CNAMEs which didn't find a target. */
479 if (is_outdated_cname_pointer(new_chain))
480 cache_free(new_chain);
481 else
482 {
483 cache_hash(new_chain);
484 cache_link(new_chain);
485 cache_inserted++;
486 }
487 new_chain = tmp;
488 }
489 new_chain = NULL;
490 }
491
492 struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
493 {
494 struct crec *ans;
495
496 if (crecp) /* iterating */
497 ans = crecp->next;
498 else
499 {
500 /* first search, look for relevant entries and push to top of list
501 also free anything which has expired */
502 struct crec *next, **up, **insert = NULL, **chainp = &ans;
503 unsigned short ins_flags = 0;
504
505 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
506 {
507 next = crecp->hash_next;
508
509 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
510 {
511 if ((crecp->flags & F_FORWARD) &&
512 (crecp->flags & prot) &&
513 hostname_isequal(cache_get_name(crecp), name))
514 {
515 if (crecp->flags & (F_HOSTS | F_DHCP))
516 {
517 *chainp = crecp;
518 chainp = &crecp->next;
519 }
520 else
521 {
522 cache_unlink(crecp);
523 cache_link(crecp);
524 }
525
526 /* Move all but the first entry up the hash chain
527 this implements round-robin.
528 Make sure that re-ordering doesn't break the hash-chain
529 order invariants.
530 */
531 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
532 {
533 *up = crecp->hash_next;
534 crecp->hash_next = *insert;
535 *insert = crecp;
536 insert = &crecp->hash_next;
537 }
538 else
539 {
540 if (!insert)
541 {
542 insert = up;
543 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
544 }
545 up = &crecp->hash_next;
546 }
547 }
548 else
549 /* case : not expired, incorrect entry. */
550 up = &crecp->hash_next;
551 }
552 else
553 {
554 /* expired entry, free it */
555 *up = crecp->hash_next;
556 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
557 {
558 cache_unlink(crecp);
559 cache_free(crecp);
560 }
561 }
562 }
563
564 *chainp = cache_head;
565 }
566
567 if (ans &&
568 (ans->flags & F_FORWARD) &&
569 (ans->flags & prot) &&
570 hostname_isequal(cache_get_name(ans), name))
571 return ans;
572
573 return NULL;
574 }
575
576 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
577 time_t now, unsigned short prot)
578 {
579 struct crec *ans;
580 #ifdef HAVE_IPV6
581 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
582 #else
583 int addrlen = INADDRSZ;
584 #endif
585
586 if (crecp) /* iterating */
587 ans = crecp->next;
588 else
589 {
590 /* first search, look for relevant entries and push to top of list
591 also free anything which has expired. All the reverse entries are at the
592 start of the hash chain, so we can give up when we find the first
593 non-REVERSE one. */
594 int i;
595 struct crec **up, **chainp = &ans;
596
597 for (i=0; i<hash_size; i++)
598 for (crecp = hash_table[i], up = &hash_table[i];
599 crecp && (crecp->flags & F_REVERSE);
600 crecp = crecp->hash_next)
601 if (!is_expired(now, crecp))
602 {
603 if ((crecp->flags & prot) &&
604 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
605 {
606 if (crecp->flags & (F_HOSTS | F_DHCP))
607 {
608 *chainp = crecp;
609 chainp = &crecp->next;
610 }
611 else
612 {
613 cache_unlink(crecp);
614 cache_link(crecp);
615 }
616 }
617 up = &crecp->hash_next;
618 }
619 else
620 {
621 *up = crecp->hash_next;
622 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
623 {
624 cache_unlink(crecp);
625 cache_free(crecp);
626 }
627 }
628
629 *chainp = cache_head;
630 }
631
632 if (ans &&
633 (ans->flags & F_REVERSE) &&
634 (ans->flags & prot) &&
635 memcmp(&ans->addr.addr, addr, addrlen) == 0)
636 return ans;
637
638 return NULL;
639 }
640
641 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
642 unsigned short flags, int index, int addr_dup)
643 {
644 struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
645 int i, nameexists = 0;
646 struct cname *a;
647
648 /* Remove duplicates in hosts files. */
649 if (lookup && (lookup->flags & F_HOSTS))
650 {
651 nameexists = 1;
652 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
653 {
654 free(cache);
655 return;
656 }
657 }
658
659 /* Ensure there is only one address -> name mapping (first one trumps)
660 We do this by steam here, first we see if the address is the same as
661 the last one we saw, which eliminates most in the case of an ad-block
662 file with thousands of entries for the same address.
663 Then we search and bail at the first matching address that came from
664 a HOSTS file. Since the first host entry gets reverse, we know
665 then that it must exist without searching exhaustively for it. */
666
667 if (addr_dup)
668 flags &= ~F_REVERSE;
669 else
670 for (i=0; i<hash_size; i++)
671 {
672 for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
673 if ((lookup->flags & F_HOSTS) &&
674 (lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
675 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
676 {
677 flags &= ~F_REVERSE;
678 break;
679 }
680 if (lookup)
681 break;
682 }
683
684 cache->flags = flags;
685 cache->uid = index;
686 memcpy(&cache->addr.addr, addr, addrlen);
687 cache_hash(cache);
688
689 /* don't need to do alias stuff for second and subsequent addresses. */
690 if (!nameexists)
691 for (a = daemon->cnames; a; a = a->next)
692 if (hostname_isequal(cache->name.sname, a->target) &&
693 (lookup = whine_malloc(sizeof(struct crec))))
694 {
695 lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
696 lookup->name.namep = a->alias;
697 lookup->addr.cname.cache = cache;
698 lookup->addr.cname.uid = index;
699 cache_hash(lookup);
700 }
701 }
702
703 static int eatspace(FILE *f)
704 {
705 int c, nl = 0;
706
707 while (1)
708 {
709 if ((c = getc(f)) == '#')
710 while (c != '\n' && c != EOF)
711 c = getc(f);
712
713 if (c == EOF)
714 return 1;
715
716 if (!isspace(c))
717 {
718 ungetc(c, f);
719 return nl;
720 }
721
722 if (c == '\n')
723 nl = 1;
724 }
725 }
726
727 static int gettok(FILE *f, char *token)
728 {
729 int c, count = 0;
730
731 while (1)
732 {
733 if ((c = getc(f)) == EOF)
734 return (count == 0) ? EOF : 1;
735
736 if (isspace(c) || c == '#')
737 {
738 ungetc(c, f);
739 return eatspace(f);
740 }
741
742 if (count < (MAXDNAME - 1))
743 {
744 token[count++] = c;
745 token[count] = 0;
746 }
747 }
748 }
749
750 static int read_hostsfile(char *filename, int index, int cache_size)
751 {
752 FILE *f = fopen(filename, "r");
753 char *token = daemon->namebuff, *domain_suffix = NULL;
754 int addr_count = 0, name_count = cache_size, lineno = 0;
755 unsigned short flags = 0, saved_flags = 0;
756 struct all_addr addr, saved_addr;
757 int atnl, addrlen = 0, addr_dup;
758
759 if (!f)
760 {
761 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
762 return 0;
763 }
764
765 eatspace(f);
766
767 while ((atnl = gettok(f, token)) != EOF)
768 {
769 addr_dup = 0;
770 lineno++;
771
772 #ifdef HAVE_IPV6
773 if (inet_pton(AF_INET, token, &addr) > 0)
774 {
775 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
776 addrlen = INADDRSZ;
777 domain_suffix = get_domain(addr.addr.addr4);
778 }
779 else if (inet_pton(AF_INET6, token, &addr) > 0)
780 {
781 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
782 addrlen = IN6ADDRSZ;
783 domain_suffix = daemon->domain_suffix;
784 }
785 #else
786 if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
787 {
788 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
789 addrlen = INADDRSZ;
790 domain_suffix = get_domain(addr.addr.addr4);
791 }
792 #endif
793 else
794 {
795 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
796 while (atnl == 0)
797 atnl = gettok(f, token);
798 continue;
799 }
800
801 if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
802 addr_dup = 1;
803 else
804 {
805 saved_flags = flags;
806 saved_addr = addr;
807 }
808
809 addr_count++;
810
811 /* rehash every 1000 names. */
812 if ((name_count - cache_size) > 1000)
813 {
814 rehash(name_count);
815 cache_size = name_count;
816 }
817
818 while (atnl == 0)
819 {
820 struct crec *cache;
821 int fqdn, nomem;
822 char *canon;
823
824 if ((atnl = gettok(f, token)) == EOF)
825 break;
826
827 fqdn = !!strchr(token, '.');
828
829 if ((canon = canonicalise(token, &nomem)))
830 {
831 /* If set, add a version of the name with a default domain appended */
832 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
833 (cache = whine_malloc(sizeof(struct crec) +
834 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
835 {
836 strcpy(cache->name.sname, canon);
837 strcat(cache->name.sname, ".");
838 strcat(cache->name.sname, domain_suffix);
839 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
840 addr_dup = 1;
841 name_count++;
842 }
843 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
844 {
845 strcpy(cache->name.sname, canon);
846 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
847 name_count++;
848 }
849 free(canon);
850
851 }
852 else if (!nomem)
853 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
854 }
855 }
856
857 fclose(f);
858 rehash(name_count);
859
860 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
861
862 return name_count;
863 }
864
865 void cache_reload(void)
866 {
867 struct crec *cache, **up, *tmp;
868 int i, total_size = daemon->cachesize;
869 struct hostsfile *ah;
870
871 cache_inserted = cache_live_freed = 0;
872
873 for (i=0; i<hash_size; i++)
874 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
875 {
876 tmp = cache->hash_next;
877 if (cache->flags & F_HOSTS)
878 {
879 *up = cache->hash_next;
880 free(cache);
881 }
882 else if (!(cache->flags & F_DHCP))
883 {
884 *up = cache->hash_next;
885 if (cache->flags & F_BIGNAME)
886 {
887 cache->name.bname->next = big_free;
888 big_free = cache->name.bname;
889 }
890 cache->flags = 0;
891 }
892 else
893 up = &cache->hash_next;
894 }
895
896 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
897 {
898 if (daemon->cachesize > 0)
899 my_syslog(LOG_INFO, _("cleared cache"));
900 return;
901 }
902
903 if (!option_bool(OPT_NO_HOSTS))
904 total_size = read_hostsfile(HOSTSFILE, 0, total_size);
905
906 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
907 for (ah = daemon->addn_hosts; ah; ah = ah->next)
908 if (!(ah->flags & AH_INACTIVE))
909 total_size = read_hostsfile(ah->fname, ah->index, total_size);
910 }
911
912 char *get_domain(struct in_addr addr)
913 {
914 struct cond_domain *c;
915
916 for (c = daemon->cond_domain; c; c = c->next)
917 if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
918 ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
919 return c->domain;
920
921 return daemon->domain_suffix;
922 }
923
924 #ifdef HAVE_DHCP
925 struct in_addr a_record_from_hosts(char *name, time_t now)
926 {
927 struct crec *crecp = NULL;
928 struct in_addr ret;
929
930 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
931 if (crecp->flags & F_HOSTS)
932 return *(struct in_addr *)&crecp->addr;
933
934 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
935
936 ret.s_addr = 0;
937 return ret;
938 }
939
940 void cache_unhash_dhcp(void)
941 {
942 struct crec *cache, **up;
943 int i;
944
945 for (i=0; i<hash_size; i++)
946 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
947 if (cache->flags & F_DHCP)
948 {
949 *up = cache->hash_next;
950 cache->next = dhcp_spare;
951 dhcp_spare = cache;
952 }
953 else
954 up = &cache->hash_next;
955 }
956
957 void cache_add_dhcp_entry(char *host_name,
958 struct in_addr *host_address, time_t ttd)
959 {
960 struct crec *crec = NULL, *aliasc;
961 unsigned short flags = F_NAMEP | F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
962 int in_hosts = 0;
963 struct cname *a;
964
965 while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
966 {
967 /* check all addresses associated with name */
968 if (crec->flags & F_HOSTS)
969 {
970 /* if in hosts, don't need DHCP record */
971 in_hosts = 1;
972
973 if (crec->flags & F_CNAME)
974 my_syslog(MS_DHCP | LOG_WARNING,
975 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
976 host_name, inet_ntoa(*host_address));
977 else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
978 {
979 strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
980 my_syslog(MS_DHCP | LOG_WARNING,
981 _("not giving name %s to the DHCP lease of %s because "
982 "the name exists in %s with address %s"),
983 host_name, inet_ntoa(*host_address),
984 record_source(crec->uid), daemon->namebuff);
985 }
986 }
987 else if (!(crec->flags & F_DHCP))
988 {
989 cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
990 /* scan_free deletes all addresses associated with name */
991 break;
992 }
993 }
994
995 if (in_hosts)
996 return;
997
998 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
999 {
1000 if (crec->flags & F_NEG)
1001 cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
1002 else
1003 /* avoid multiple reverse mappings */
1004 flags &= ~F_REVERSE;
1005 }
1006
1007 if ((crec = dhcp_spare))
1008 dhcp_spare = dhcp_spare->next;
1009 else /* need new one */
1010 crec = whine_malloc(sizeof(struct crec));
1011
1012 if (crec) /* malloc may fail */
1013 {
1014 crec->flags = flags;
1015 if (ttd == 0)
1016 crec->flags |= F_IMMORTAL;
1017 else
1018 crec->ttd = ttd;
1019 crec->addr.addr.addr.addr4 = *host_address;
1020 crec->name.namep = host_name;
1021 crec->uid = uid++;
1022 cache_hash(crec);
1023
1024 for (a = daemon->cnames; a; a = a->next)
1025 if (hostname_isequal(host_name, a->target))
1026 {
1027 if ((aliasc = dhcp_spare))
1028 dhcp_spare = dhcp_spare->next;
1029 else /* need new one */
1030 aliasc = whine_malloc(sizeof(struct crec));
1031
1032 if (aliasc)
1033 {
1034 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
1035 if (ttd == 0)
1036 aliasc->flags |= F_IMMORTAL;
1037 else
1038 aliasc->ttd = ttd;
1039 aliasc->name.namep = a->alias;
1040 aliasc->addr.cname.cache = crec;
1041 aliasc->addr.cname.uid = crec->uid;
1042 cache_hash(aliasc);
1043 }
1044 }
1045 }
1046 }
1047 #endif
1048
1049
1050 void dump_cache(time_t now)
1051 {
1052 struct server *serv, *serv1;
1053
1054 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1055 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1056 daemon->cachesize, cache_live_freed, cache_inserted);
1057 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1058 daemon->queries_forwarded, daemon->local_answer);
1059
1060 if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN)))
1061 return;
1062
1063 /* sum counts from different records for same server */
1064 for (serv = daemon->servers; serv; serv = serv->next)
1065 serv->flags &= ~SERV_COUNTED;
1066
1067 for (serv = daemon->servers; serv; serv = serv->next)
1068 if (!(serv->flags &
1069 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1070 {
1071 int port;
1072 unsigned int queries = 0, failed_queries = 0;
1073 for (serv1 = serv; serv1; serv1 = serv1->next)
1074 if (!(serv1->flags &
1075 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1076 sockaddr_isequal(&serv->addr, &serv1->addr))
1077 {
1078 serv1->flags |= SERV_COUNTED;
1079 queries += serv1->queries;
1080 failed_queries += serv1->failed_queries;
1081 }
1082 port = prettyprint_addr(&serv->addr, addrbuff);
1083 my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
1084 }
1085
1086 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
1087 {
1088 struct crec *cache ;
1089 int i;
1090 my_syslog(LOG_INFO, "Host Address Flags Expires");
1091
1092 for (i=0; i<hash_size; i++)
1093 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1094 {
1095 char *a, *p = daemon->namebuff;
1096 p += sprintf(p, "%-40.40s ", cache_get_name(cache));
1097 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
1098 a = "";
1099 else if (cache->flags & F_CNAME)
1100 {
1101 a = "";
1102 if (!is_outdated_cname_pointer(cache))
1103 a = cache_get_name(cache->addr.cname.cache);
1104 }
1105 #ifdef HAVE_IPV6
1106 else
1107 {
1108 a = addrbuff;
1109 if (cache->flags & F_IPV4)
1110 inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
1111 else if (cache->flags & F_IPV6)
1112 inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
1113 }
1114 #else
1115 else
1116 a = inet_ntoa(cache->addr.addr.addr.addr4);
1117 #endif
1118 p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s ", a,
1119 cache->flags & F_IPV4 ? "4" : "",
1120 cache->flags & F_IPV6 ? "6" : "",
1121 cache->flags & F_CNAME ? "C" : "",
1122 cache->flags & F_FORWARD ? "F" : " ",
1123 cache->flags & F_REVERSE ? "R" : " ",
1124 cache->flags & F_IMMORTAL ? "I" : " ",
1125 cache->flags & F_DHCP ? "D" : " ",
1126 cache->flags & F_NEG ? "N" : " ",
1127 cache->flags & F_NXDOMAIN ? "X" : " ",
1128 cache->flags & F_HOSTS ? "H" : " ");
1129 #ifdef HAVE_BROKEN_RTC
1130 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
1131 #else
1132 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1133 /* ctime includes trailing \n - eat it */
1134 *(p-1) = 0;
1135 #endif
1136 my_syslog(LOG_INFO, daemon->namebuff);
1137 }
1138 }
1139 }
1140
1141 char *record_source(int index)
1142 {
1143 struct hostsfile *ah;
1144
1145 if (index == 0)
1146 return HOSTSFILE;
1147
1148 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1149 if (ah->index == index)
1150 return ah->fname;
1151
1152 return "<unknown>";
1153 }
1154
1155 void querystr(char *str, unsigned short type)
1156 {
1157 unsigned int i;
1158
1159 sprintf(str, "query[type=%d]", type);
1160 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1161 if (typestr[i].type == type)
1162 sprintf(str,"query[%s]", typestr[i].name);
1163 }
1164
1165 void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
1166 {
1167 char *source, *dest = addrbuff;
1168 char *verb = "is";
1169
1170 if (!option_bool(OPT_LOG))
1171 return;
1172
1173 if (addr)
1174 {
1175 #ifdef HAVE_IPV6
1176 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1177 addr, addrbuff, ADDRSTRLEN);
1178 #else
1179 strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1180 #endif
1181 }
1182
1183 if (flags & F_REVERSE)
1184 {
1185 dest = name;
1186 name = addrbuff;
1187 }
1188
1189 if (flags & F_NEG)
1190 {
1191 if (flags & F_NXDOMAIN)
1192 {
1193 if (flags & F_IPV4)
1194 dest = "NXDOMAIN-IPv4";
1195 else if (flags & F_IPV6)
1196 dest = "NXDOMAIN-IPv6";
1197 else
1198 dest = "NXDOMAIN";
1199 }
1200 else
1201 {
1202 if (flags & F_IPV4)
1203 dest = "NODATA-IPv4";
1204 else if (flags & F_IPV6)
1205 dest = "NODATA-IPv6";
1206 else
1207 dest = "NODATA";
1208 }
1209 }
1210 else if (flags & F_CNAME)
1211 dest = "<CNAME>";
1212 else if (flags & F_RRNAME)
1213 dest = arg;
1214
1215 if (flags & F_CONFIG)
1216 source = "config";
1217 else if (flags & F_DHCP)
1218 source = "DHCP";
1219 else if (flags & F_HOSTS)
1220 source = arg;
1221 else if (flags & F_UPSTREAM)
1222 source = "reply";
1223 else if (flags & F_SERVER)
1224 {
1225 source = "forwarded";
1226 verb = "to";
1227 }
1228 else if (flags & F_QUERY)
1229 {
1230 source = arg;
1231 verb = "from";
1232 }
1233 else
1234 source = "cached";
1235
1236 if (strlen(name) == 0)
1237 name = ".";
1238
1239 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
1240 }
1241