]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/cache.c
import of dnsmasq-2.38.tar.gz
[people/ms/dnsmasq.git] / src / cache.c
1 /* dnsmasq is Copyright (c) 2000-2007 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.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11 */
12
13 #include "dnsmasq.h"
14
15 static struct crec *cache_head, *cache_tail, **hash_table;
16 static struct crec *dhcp_spare, *new_chain;
17 static int cache_inserted, cache_live_freed, insert_error;
18 static union bigname *big_free;
19 static int bignames_left, log_queries, cache_size, hash_size;
20 static int uid;
21 static char *addrbuff;
22
23 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
24 static const struct {
25 unsigned int type;
26 const char * const name;
27 } typestr[] = {
28 { 1, "A" },
29 { 2, "NS" },
30 { 5, "CNAME" },
31 { 6, "SOA" },
32 { 10, "NULL" },
33 { 11, "WKS" },
34 { 12, "PTR" },
35 { 13, "HINFO" },
36 { 15, "MX" },
37 { 16, "TXT" },
38 { 22, "NSAP" },
39 { 23, "NSAP_PTR" },
40 { 24, "SIG" },
41 { 25, "KEY" },
42 { 28, "AAAA" },
43 { 33, "SRV" },
44 { 36, "KX" },
45 { 37, "CERT" },
46 { 38, "A6" },
47 { 39, "DNAME" },
48 { 41, "OPT" },
49 { 48, "DNSKEY" },
50 { 249, "TKEY" },
51 { 250, "TSIG" },
52 { 251, "IXFR" },
53 { 252, "AXFR" },
54 { 253, "MAILB" },
55 { 254, "MAILA" },
56 { 255, "ANY" }
57 };
58
59 static void cache_free(struct crec *crecp);
60 static void cache_unlink(struct crec *crecp);
61 static void cache_link(struct crec *crecp);
62 static char *record_source(struct hostsfile *add_hosts, int index);
63 static void rehash(int size);
64 static void cache_hash(struct crec *crecp);
65
66 void cache_init(int size, int logq)
67 {
68 struct crec *crecp;
69 int i;
70
71 if ((log_queries = logq))
72 addrbuff = safe_malloc(ADDRSTRLEN);
73 else
74 addrbuff = NULL;
75
76 cache_head = cache_tail = NULL;
77 dhcp_spare = NULL;
78 new_chain = NULL;
79 hash_table = NULL;
80 cache_size = size;
81 big_free = NULL;
82 bignames_left = size/10;
83 uid = 0;
84
85 cache_inserted = cache_live_freed = 0;
86
87 if (cache_size > 0)
88 {
89 crecp = safe_malloc(size*sizeof(struct crec));
90
91 for (i=0; i<size; i++, crecp++)
92 {
93 cache_link(crecp);
94 crecp->flags = 0;
95 crecp->uid = uid++;
96 }
97 }
98
99 /* create initial hash table*/
100 rehash(cache_size);
101 }
102
103 /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
104 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
105 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
106 expand the table. */
107 static void rehash(int size)
108 {
109 struct crec **new, **old, *p, *tmp;
110 int i, new_size, old_size;
111
112 /* hash_size is a power of two. */
113 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
114
115 /* must succeed in getting first instance, failure later is non-fatal */
116 if (!hash_table)
117 new = safe_malloc(new_size * sizeof(struct crec *));
118 else if (new_size <= hash_size || !(new = malloc(new_size * sizeof(struct crec *))))
119 return;
120
121 for(i = 0; i < new_size; i++)
122 new[i] = NULL;
123
124 old = hash_table;
125 old_size = hash_size;
126 hash_table = new;
127 hash_size = new_size;
128
129 if (old)
130 {
131 for (i = 0; i < old_size; i++)
132 for (p = old[i]; p ; p = tmp)
133 {
134 tmp = p->hash_next;
135 cache_hash(p);
136 }
137 free(old);
138 }
139 }
140
141 static struct crec **hash_bucket(char *name)
142 {
143 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
144 const unsigned char *mix_tab = (const unsigned char*)typestr;
145
146 while((c = (unsigned char) *name++))
147 {
148 /* don't use tolower and friends here - they may be messed up by LOCALE */
149 if (c >= 'A' && c <= 'Z')
150 c += 'a' - 'A';
151 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
152 }
153
154 /* hash_size is a power of two */
155 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
156 }
157
158 static void cache_hash(struct crec *crecp)
159 {
160 /* maintain an invariant that all entries with F_REVERSE set
161 are at the start of the hash-chain and all non-reverse
162 immortal entries are at the end of the hash-chain.
163 This allows reverse searches and garbage collection to be optimised */
164
165 struct crec **up = hash_bucket(cache_get_name(crecp));
166
167 if (!(crecp->flags & F_REVERSE))
168 {
169 while (*up && ((*up)->flags & F_REVERSE))
170 up = &((*up)->hash_next);
171
172 if (crecp->flags & F_IMMORTAL)
173 while (*up && !((*up)->flags & F_IMMORTAL))
174 up = &((*up)->hash_next);
175 }
176 crecp->hash_next = *up;
177 *up = crecp;
178 }
179
180 static void cache_free(struct crec *crecp)
181 {
182 crecp->flags &= ~F_FORWARD;
183 crecp->flags &= ~F_REVERSE;
184 crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
185
186 if (cache_tail)
187 cache_tail->next = crecp;
188 else
189 cache_head = crecp;
190 crecp->prev = cache_tail;
191 crecp->next = NULL;
192 cache_tail = crecp;
193
194 /* retrieve big name for further use. */
195 if (crecp->flags & F_BIGNAME)
196 {
197 crecp->name.bname->next = big_free;
198 big_free = crecp->name.bname;
199 crecp->flags &= ~F_BIGNAME;
200 }
201 }
202
203 /* insert a new cache entry at the head of the list (youngest entry) */
204 static void cache_link(struct crec *crecp)
205 {
206 if (cache_head) /* check needed for init code */
207 cache_head->prev = crecp;
208 crecp->next = cache_head;
209 crecp->prev = NULL;
210 cache_head = crecp;
211 if (!cache_tail)
212 cache_tail = crecp;
213 }
214
215 /* remove an arbitrary cache entry for promotion */
216 static void cache_unlink (struct crec *crecp)
217 {
218 if (crecp->prev)
219 crecp->prev->next = crecp->next;
220 else
221 cache_head = crecp->next;
222
223 if (crecp->next)
224 crecp->next->prev = crecp->prev;
225 else
226 cache_tail = crecp->prev;
227 }
228
229 char *cache_get_name(struct crec *crecp)
230 {
231 if (crecp->flags & F_BIGNAME)
232 return crecp->name.bname->name;
233 else if (crecp->flags & F_DHCP)
234 return crecp->name.namep;
235
236 return crecp->name.sname;
237 }
238
239 static int is_outdated_cname_pointer(struct crec *crecp)
240 {
241 struct crec *target = crecp->addr.cname.cache;
242
243 if (!(crecp->flags & F_CNAME))
244 return 0;
245
246 if (!target)
247 return 1;
248
249 if (crecp->addr.cname.uid == target->uid)
250 return 0;
251
252 return 1;
253 }
254
255 static int is_expired(time_t now, struct crec *crecp)
256 {
257 if (crecp->flags & F_IMMORTAL)
258 return 0;
259
260 if (difftime(now, crecp->ttd) < 0)
261 return 0;
262
263 return 1;
264 }
265
266 static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
267 {
268 /* Scan and remove old entries.
269 If (flags & F_FORWARD) then remove any forward entries for name and any expired
270 entries but only in the same hash bucket as name.
271 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
272 entries in the whole cache.
273 If (flags == 0) remove any expired entries in the whole cache.
274
275 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
276 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
277
278 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
279 so that when we hit an entry which isn't reverse and is immortal, we're done. */
280
281 struct crec *crecp, **up;
282
283 if (flags & F_FORWARD)
284 {
285 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
286 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
287 {
288 *up = crecp->hash_next;
289 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
290 {
291 cache_unlink(crecp);
292 cache_free(crecp);
293 }
294 }
295 else if ((crecp->flags & F_FORWARD) &&
296 ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || ((crecp->flags | flags) & F_CNAME)) &&
297 hostname_isequal(cache_get_name(crecp), name))
298 {
299 if (crecp->flags & (F_HOSTS | F_DHCP))
300 return 0;
301 *up = crecp->hash_next;
302 cache_unlink(crecp);
303 cache_free(crecp);
304 }
305 else
306 up = &crecp->hash_next;
307 }
308 else
309 {
310 int i;
311 #ifdef HAVE_IPV6
312 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
313 #else
314 int addrlen = INADDRSZ;
315 #endif
316 for (i = 0; i < hash_size; i++)
317 for (crecp = hash_table[i], up = &hash_table[i];
318 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
319 crecp = crecp->hash_next)
320 if (is_expired(now, crecp))
321 {
322 *up = crecp->hash_next;
323 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
324 {
325 cache_unlink(crecp);
326 cache_free(crecp);
327 }
328 }
329 else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
330 (flags & crecp->flags & F_REVERSE) &&
331 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
332 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
333 {
334 *up = crecp->hash_next;
335 cache_unlink(crecp);
336 cache_free(crecp);
337 }
338 else
339 up = &crecp->hash_next;
340 }
341
342 return 1;
343 }
344
345 /* Note: The normal calling sequence is
346 cache_start_insert
347 cache_insert * n
348 cache_end_insert
349
350 but an abort can cause the cache_end_insert to be missed
351 in which can the next cache_start_insert cleans things up. */
352
353 void cache_start_insert(void)
354 {
355 /* Free any entries which didn't get committed during the last
356 insert due to error.
357 */
358 while (new_chain)
359 {
360 struct crec *tmp = new_chain->next;
361 cache_free(new_chain);
362 new_chain = tmp;
363 }
364 new_chain = NULL;
365 insert_error = 0;
366 }
367
368 struct crec *cache_insert(char *name, struct all_addr *addr,
369 time_t now, unsigned long ttl, unsigned short flags)
370 {
371 #ifdef HAVE_IPV6
372 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
373 #else
374 int addrlen = INADDRSZ;
375 #endif
376 struct crec *new;
377 union bigname *big_name = NULL;
378 int freed_all = flags & F_REVERSE;
379
380 log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
381
382 /* name is needed as workspace by log_query in this case */
383 if ((flags & F_NEG) && (flags & F_REVERSE))
384 name = NULL;
385
386 /* CONFIG bit no needed except for logging */
387 flags &= ~F_CONFIG;
388
389 /* if previous insertion failed give up now. */
390 if (insert_error)
391 return NULL;
392
393 /* First remove any expired entries and entries for the name/address we
394 are currently inserting. Fail is we attempt to delete a name from
395 /etc/hosts or DHCP. */
396 if (!cache_scan_free(name, addr, now, flags))
397 {
398 insert_error = 1;
399 return NULL;
400 }
401
402 /* Now get a cache entry from the end of the LRU list */
403 while (1) {
404 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
405 {
406 insert_error = 1;
407 return NULL;
408 }
409
410 /* End of LRU list is still in use: if we didn't scan all the hash
411 chains for expired entries do that now. If we already tried that
412 then it's time to start spilling things. */
413
414 if (new->flags & (F_FORWARD | F_REVERSE))
415 {
416 if (freed_all)
417 {
418 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
419 cache_live_freed++;
420 }
421 else
422 {
423 cache_scan_free(NULL, NULL, now, 0);
424 freed_all = 1;
425 }
426 continue;
427 }
428
429 /* Check if we need to and can allocate extra memory for a long name.
430 If that fails, give up now. */
431 if (name && (strlen(name) > SMALLDNAME-1))
432 {
433 if (big_free)
434 {
435 big_name = big_free;
436 big_free = big_free->next;
437 }
438 else if (!bignames_left ||
439 !(big_name = (union bigname *)malloc(sizeof(union bigname))))
440 {
441 insert_error = 1;
442 return NULL;
443 }
444 else
445 bignames_left--;
446
447 }
448
449 /* Got the rest: finally grab entry. */
450 cache_unlink(new);
451 break;
452 }
453
454 new->flags = flags;
455 if (big_name)
456 {
457 new->name.bname = big_name;
458 new->flags |= F_BIGNAME;
459 }
460 if (name)
461 strcpy(cache_get_name(new), name);
462 else
463 *cache_get_name(new) = 0;
464 if (addr)
465 memcpy(&new->addr.addr, addr, addrlen);
466 else
467 new->addr.cname.cache = NULL;
468
469 new->ttd = now + (time_t)ttl;
470 new->next = new_chain;
471 new_chain = new;
472
473 return new;
474 }
475
476 /* after end of insertion, commit the new entries */
477 void cache_end_insert(void)
478 {
479 if (insert_error)
480 return;
481
482 while (new_chain)
483 {
484 struct crec *tmp = new_chain->next;
485 /* drop CNAMEs which didn't find a target. */
486 if (is_outdated_cname_pointer(new_chain))
487 cache_free(new_chain);
488 else
489 {
490 cache_hash(new_chain);
491 cache_link(new_chain);
492 cache_inserted++;
493 }
494 new_chain = tmp;
495 }
496 new_chain = NULL;
497 }
498
499 struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
500 {
501 struct crec *ans;
502
503 if (crecp) /* iterating */
504 ans = crecp->next;
505 else
506 {
507 /* first search, look for relevant entries and push to top of list
508 also free anything which has expired */
509 struct crec *next, **up, **insert = NULL, **chainp = &ans;
510
511 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
512 {
513 next = crecp->hash_next;
514
515 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
516 {
517 if ((crecp->flags & F_FORWARD) &&
518 (crecp->flags & prot) &&
519 hostname_isequal(cache_get_name(crecp), name))
520 {
521 if (crecp->flags & (F_HOSTS | F_DHCP))
522 {
523 *chainp = crecp;
524 chainp = &crecp->next;
525 }
526 else
527 {
528 cache_unlink(crecp);
529 cache_link(crecp);
530 }
531
532 /* move all but the first entry up the hash chain
533 this implements round-robin */
534 if (!insert)
535 {
536 insert = up;
537 up = &crecp->hash_next;
538 }
539 else
540 {
541 *up = crecp->hash_next;
542 crecp->hash_next = *insert;
543 *insert = crecp;
544 insert = &crecp->hash_next;
545 }
546 }
547 else
548 /* case : not expired, incorrect entry. */
549 up = &crecp->hash_next;
550 }
551 else
552 {
553 /* expired entry, free it */
554 *up = crecp->hash_next;
555 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
556 {
557 cache_unlink(crecp);
558 cache_free(crecp);
559 }
560 }
561 }
562
563 *chainp = cache_head;
564 }
565
566 if (ans &&
567 (ans->flags & F_FORWARD) &&
568 (ans->flags & prot) &&
569 hostname_isequal(cache_get_name(ans), name))
570 return ans;
571
572 return NULL;
573 }
574
575 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
576 time_t now, unsigned short prot)
577 {
578 struct crec *ans;
579 #ifdef HAVE_IPV6
580 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
581 #else
582 int addrlen = INADDRSZ;
583 #endif
584
585 if (crecp) /* iterating */
586 ans = crecp->next;
587 else
588 {
589 /* first search, look for relevant entries and push to top of list
590 also free anything which has expired. All the reverse entries are at the
591 start of the hash chain, so we can give up when we find the first
592 non-REVERSE one. */
593 int i;
594 struct crec **up, **chainp = &ans;
595
596 for (i=0; i<hash_size; i++)
597 for (crecp = hash_table[i], up = &hash_table[i];
598 crecp && (crecp->flags & F_REVERSE);
599 crecp = crecp->hash_next)
600 if (!is_expired(now, crecp))
601 {
602 if ((crecp->flags & prot) &&
603 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
604 {
605 if (crecp->flags & (F_HOSTS | F_DHCP))
606 {
607 *chainp = crecp;
608 chainp = &crecp->next;
609 }
610 else
611 {
612 cache_unlink(crecp);
613 cache_link(crecp);
614 }
615 }
616 up = &crecp->hash_next;
617 }
618 else
619 {
620 *up = crecp->hash_next;
621 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
622 {
623 cache_unlink(crecp);
624 cache_free(crecp);
625 }
626 }
627
628 *chainp = cache_head;
629 }
630
631 if (ans &&
632 (ans->flags & F_REVERSE) &&
633 (ans->flags & prot) &&
634 memcmp(&ans->addr.addr, addr, addrlen) == 0)
635 return ans;
636
637 return NULL;
638 }
639
640 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
641 unsigned short flags, int index, int addr_dup)
642 {
643 struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
644 int i;
645
646 /* Remove duplicates in hosts files. */
647 if (lookup && (lookup->flags & F_HOSTS) &&
648 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
649 free(cache);
650 else
651 {
652 /* Ensure there is only one address -> name mapping (first one trumps)
653 We do this by steam here, first we see if the address is the same as
654 the last one we saw, which eliminates most in the case of an ad-block
655 file with thousands of entries for the same address.
656 Then we search and bail at the first matching address that came from
657 a HOSTS file. Since the first host entry gets reverse, we know
658 then that it must exist without searching exhaustively for it. */
659
660 if (addr_dup)
661 flags &= ~F_REVERSE;
662 else
663 for (i=0; i<hash_size; i++)
664 {
665 for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
666 if ((lookup->flags & F_HOSTS) &&
667 (lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
668 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
669 {
670 flags &= ~F_REVERSE;
671 break;
672 }
673 if (lookup)
674 break;
675 }
676
677 cache->flags = flags;
678 cache->uid = index;
679 memcpy(&cache->addr.addr, addr, addrlen);
680 cache_hash(cache);
681 }
682 }
683
684 static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index, int cache_size)
685 {
686 FILE *f = fopen(filename, "r");
687 char *line;
688 int addr_count = 0, name_count = cache_size, lineno = 0;
689 unsigned short flags, saved_flags = 0;
690 struct all_addr addr, saved_addr;
691
692 if (!f)
693 {
694 syslog(LOG_ERR, _("failed to load names from %s: %m"), filename);
695 return 0;
696 }
697
698 while ((line = fgets(buff, MAXDNAME, f)))
699 {
700 char *token = strtok(line, " \t\n\r");
701 int addrlen, addr_dup = 0;
702
703 lineno++;
704
705 if (!token || (*token == '#'))
706 continue;
707
708 #ifdef HAVE_IPV6
709 if (inet_pton(AF_INET, token, &addr) > 0)
710 {
711 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
712 addrlen = INADDRSZ;
713 }
714 else if (inet_pton(AF_INET6, token, &addr) > 0)
715 {
716 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
717 addrlen = IN6ADDRSZ;
718 }
719 #else
720 if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
721 {
722 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
723 addrlen = INADDRSZ;
724 }
725 #endif
726 else
727 {
728 syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
729 continue;
730 }
731
732 if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
733 addr_dup = 1;
734 else
735 {
736 saved_flags = flags;
737 saved_addr = addr;
738 }
739
740 addr_count++;
741
742 /* rehash every 1000 names. */
743 if ((name_count - cache_size) > 1000)
744 {
745 rehash(name_count);
746 cache_size = name_count;
747 }
748
749 while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
750 {
751 struct crec *cache;
752 if (canonicalise(token))
753 {
754 /* If set, add a version of the name with a default domain appended */
755 if ((opts & OPT_EXPAND) && domain_suffix && !strchr(token, '.') &&
756 (cache = malloc(sizeof(struct crec) +
757 strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
758 {
759 strcpy(cache->name.sname, token);
760 strcat(cache->name.sname, ".");
761 strcat(cache->name.sname, domain_suffix);
762 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
763 addr_dup = 1;
764 name_count++;
765 }
766 if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
767 {
768 strcpy(cache->name.sname, token);
769 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
770 name_count++;
771 }
772 }
773 else
774 syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
775 }
776 }
777
778 fclose(f);
779 rehash(name_count);
780
781 syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
782
783 return name_count;
784 }
785
786 void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts)
787 {
788 struct crec *cache, **up, *tmp;
789 int i, total_size = cache_size;
790
791 cache_inserted = cache_live_freed = 0;
792
793 for (i=0; i<hash_size; i++)
794 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
795 {
796 tmp = cache->hash_next;
797 if (cache->flags & F_HOSTS)
798 {
799 *up = cache->hash_next;
800 free(cache);
801 }
802 else if (!(cache->flags & F_DHCP))
803 {
804 *up = cache->hash_next;
805 if (cache->flags & F_BIGNAME)
806 {
807 cache->name.bname->next = big_free;
808 big_free = cache->name.bname;
809 }
810 cache->flags = 0;
811 }
812 else
813 up = &cache->hash_next;
814 }
815
816 if ((opts & OPT_NO_HOSTS) && !addn_hosts)
817 {
818 if (cache_size > 0)
819 syslog(LOG_INFO, _("cleared cache"));
820 return;
821 }
822
823 if (!(opts & OPT_NO_HOSTS))
824 total_size = read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0, total_size);
825 while (addn_hosts)
826 {
827 total_size = read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index, total_size);
828 addn_hosts = addn_hosts->next;
829 }
830 }
831
832 void cache_unhash_dhcp(void)
833 {
834 struct crec *cache, **up;
835 int i;
836
837 for (i=0; i<hash_size; i++)
838 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
839 if (cache->flags & F_DHCP)
840 {
841 *up = cache->hash_next;
842 cache->next = dhcp_spare;
843 dhcp_spare = cache;
844 }
845 else
846 up = &cache->hash_next;
847 }
848
849 void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
850 struct in_addr *host_address, time_t ttd)
851 {
852 struct crec *crec;
853 unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
854
855 if (!host_name)
856 return;
857
858 if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME)))
859 {
860 if (crec->flags & F_HOSTS)
861 {
862 if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
863 {
864 strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
865 syslog(LOG_WARNING,
866 _("not giving name %s to the DHCP lease of %s because "
867 "the name exists in %s with address %s"),
868 host_name, inet_ntoa(*host_address),
869 record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
870 }
871 return;
872 }
873 else if (!(crec->flags & F_DHCP))
874 cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
875 }
876
877 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
878 {
879 if (crec->flags & F_NEG)
880 cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
881 else
882 /* avoid multiple reverse mappings */
883 flags &= ~F_REVERSE;
884 }
885
886 if ((crec = dhcp_spare))
887 dhcp_spare = dhcp_spare->next;
888 else /* need new one */
889 crec = malloc(sizeof(struct crec));
890
891 if (crec) /* malloc may fail */
892 {
893 crec->flags = flags;
894 if (ttd == 0)
895 crec->flags |= F_IMMORTAL;
896 else
897 crec->ttd = ttd;
898 crec->addr.addr.addr.addr4 = *host_address;
899 crec->name.namep = host_name;
900 cache_hash(crec);
901 }
902 }
903
904 void dump_cache(struct daemon *daemon, time_t now)
905 {
906 syslog(LOG_INFO, _("time %lu, cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
907 (unsigned long)now, daemon->cachesize, cache_live_freed, cache_inserted);
908
909 if ((daemon->options & (OPT_DEBUG | OPT_LOG)) &&
910 (addrbuff || (addrbuff = malloc(ADDRSTRLEN))))
911 {
912 struct crec *cache ;
913 int i;
914 syslog(LOG_DEBUG, "Host Address Flags Expires");
915
916 for (i=0; i<hash_size; i++)
917 for (cache = hash_table[i]; cache; cache = cache->hash_next)
918 {
919 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
920 addrbuff[0] = 0;
921 else if (cache->flags & F_CNAME)
922 {
923 addrbuff[0] = 0;
924 addrbuff[ADDRSTRLEN-1] = 0;
925 if (!is_outdated_cname_pointer(cache))
926 strncpy(addrbuff, cache_get_name(cache->addr.cname.cache), ADDRSTRLEN);
927 }
928 #ifdef HAVE_IPV6
929 else if (cache->flags & F_IPV4)
930 inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
931 else if (cache->flags & F_IPV6)
932 inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
933 #else
934 else
935 strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr.addr4));
936 #endif
937 syslog(LOG_DEBUG,
938 #ifdef HAVE_BROKEN_RTC
939 "%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %lu",
940 #else
941 "%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %s",
942 #endif
943 cache_get_name(cache), addrbuff,
944 cache->flags & F_IPV4 ? "4" : "",
945 cache->flags & F_IPV6 ? "6" : "",
946 cache->flags & F_CNAME ? "C" : "",
947 cache->flags & F_FORWARD ? "F" : " ",
948 cache->flags & F_REVERSE ? "R" : " ",
949 cache->flags & F_IMMORTAL ? "I" : " ",
950 cache->flags & F_DHCP ? "D" : " ",
951 cache->flags & F_NEG ? "N" : " ",
952 cache->flags & F_NXDOMAIN ? "X" : " ",
953 cache->flags & F_HOSTS ? "H" : " ",
954 #ifdef HAVE_BROKEN_RTC
955 cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)
956 #else
957 cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))
958 #endif
959 );
960 }
961 }
962 }
963
964 static char *record_source(struct hostsfile *addn_hosts, int index)
965 {
966 char *source = HOSTSFILE;
967 while (addn_hosts)
968 {
969 if (addn_hosts->index == index)
970 {
971 source = addn_hosts->fname;
972 break;
973 }
974 addn_hosts = addn_hosts->next;
975 }
976
977 return source;
978 }
979
980 void log_query(unsigned short flags, char *name, struct all_addr *addr,
981 unsigned short type, struct hostsfile *addn_hosts, int index)
982 {
983 char *source;
984 char *verb = "is";
985 char types[20];
986
987 if (!log_queries)
988 return;
989
990 if (flags & F_NEG)
991 {
992 if (flags & F_REVERSE)
993 #ifdef HAVE_IPV6
994 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
995 addr, name, MAXDNAME);
996 #else
997 strcpy(name, inet_ntoa(addr->addr.addr4));
998 #endif
999
1000 if (flags & F_NXDOMAIN)
1001 strcpy(addrbuff, "<NXDOMAIN>");
1002 else
1003 strcpy(addrbuff, "<NODATA>");
1004
1005 if (flags & F_IPV4)
1006 strcat(addrbuff, "-IPv4");
1007 else if (flags & F_IPV6)
1008 strcat(addrbuff, "-IPv6");
1009 }
1010 else if (flags & F_CNAME)
1011 {
1012 /* nasty abuse of IPV4 and IPV6 flags */
1013 if (flags & F_IPV4)
1014 strcpy(addrbuff, "<MX>");
1015 else if (flags & F_IPV6)
1016 strcpy(addrbuff, "<SRV>");
1017 else if (flags & F_NXDOMAIN)
1018 strcpy(addrbuff, "<TXT>");
1019 else if (flags & F_BIGNAME)
1020 strcpy(addrbuff, "<PTR>");
1021 else
1022 strcpy(addrbuff, "<CNAME>");
1023 }
1024 else
1025 #ifdef HAVE_IPV6
1026 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1027 addr, addrbuff, ADDRSTRLEN);
1028 #else
1029 strcpy(addrbuff, inet_ntoa(addr->addr.addr4));
1030 #endif
1031
1032 if (flags & F_DHCP)
1033 source = "DHCP";
1034 else if (flags & F_HOSTS)
1035 source = record_source(addn_hosts, index);
1036 else if (flags & F_CONFIG)
1037 source = "config";
1038 else if (flags & F_UPSTREAM)
1039 source = "reply";
1040 else if (flags & F_SERVER)
1041 {
1042 source = "forwarded";
1043 verb = "to";
1044 }
1045 else if (flags & F_QUERY)
1046 {
1047 unsigned int i;
1048
1049 if (type != 0)
1050 {
1051 sprintf(types, "query[type=%d]", type);
1052 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1053 if (typestr[i].type == type)
1054 sprintf(types,"query[%s]", typestr[i].name);
1055 }
1056 source = types;
1057 verb = "from";
1058 }
1059 else
1060 source = "cached";
1061
1062 if (strlen(name) == 0)
1063 name = ".";
1064
1065 if ((flags & F_FORWARD) | (flags & F_NEG))
1066 syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff);
1067 else if (flags & F_REVERSE)
1068 syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name);
1069 }
1070