]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/cache.c
import of dnsmasq-2.36.tar.gz
[people/ms/dnsmasq.git] / src / cache.c
1 /* dnsmasq is Copyright (c) 2000-2005 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_inuse, *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_inuse = 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 struct crec **bucket = hash_bucket(cache_get_name(crecp));
161 crecp->hash_next = *bucket;
162 *bucket = crecp;
163 }
164
165 static void cache_free(struct crec *crecp)
166 {
167 crecp->flags &= ~F_FORWARD;
168 crecp->flags &= ~F_REVERSE;
169 crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
170
171 if (cache_tail)
172 cache_tail->next = crecp;
173 else
174 cache_head = crecp;
175 crecp->prev = cache_tail;
176 crecp->next = NULL;
177 cache_tail = crecp;
178
179 /* retrieve big name for further use. */
180 if (crecp->flags & F_BIGNAME)
181 {
182 crecp->name.bname->next = big_free;
183 big_free = crecp->name.bname;
184 crecp->flags &= ~F_BIGNAME;
185 }
186 }
187
188 /* insert a new cache entry at the head of the list (youngest entry) */
189 static void cache_link(struct crec *crecp)
190 {
191 if (cache_head) /* check needed for init code */
192 cache_head->prev = crecp;
193 crecp->next = cache_head;
194 crecp->prev = NULL;
195 cache_head = crecp;
196 if (!cache_tail)
197 cache_tail = crecp;
198 }
199
200 /* remove an arbitrary cache entry for promotion */
201 static void cache_unlink (struct crec *crecp)
202 {
203 if (crecp->prev)
204 crecp->prev->next = crecp->next;
205 else
206 cache_head = crecp->next;
207
208 if (crecp->next)
209 crecp->next->prev = crecp->prev;
210 else
211 cache_tail = crecp->prev;
212 }
213
214 char *cache_get_name(struct crec *crecp)
215 {
216 if (crecp->flags & F_BIGNAME)
217 return crecp->name.bname->name;
218 else if (crecp->flags & F_DHCP)
219 return crecp->name.namep;
220
221 return crecp->name.sname;
222 }
223
224 static int is_outdated_cname_pointer(struct crec *crecp)
225 {
226 struct crec *target = crecp->addr.cname.cache;
227
228 if (!(crecp->flags & F_CNAME))
229 return 0;
230
231 if (!target)
232 return 1;
233
234 if (crecp->addr.cname.uid == target->uid)
235 return 0;
236
237 return 1;
238 }
239
240 static int is_expired(time_t now, struct crec *crecp)
241 {
242 if (crecp->flags & F_IMMORTAL)
243 return 0;
244
245 if (difftime(now, crecp->ttd) < 0)
246 return 0;
247
248 return 1;
249 }
250
251 static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
252 {
253 /* Scan and remove old entries.
254 If (flags & F_FORWARD) then remove any forward entries for name and any expired
255 entries but only in the same hash bucket as name.
256 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
257 entries in the whole cache.
258 If (flags == 0) remove any expired entries in the whole cache.
259
260 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
261 name exists in the cache as a HOSTS or DHCP entry (these are never deleted) */
262
263 struct crec *crecp, **up;
264
265 if (flags & F_FORWARD)
266 {
267 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
268 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
269 {
270 *up = crecp->hash_next;
271 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
272 {
273 cache_unlink(crecp);
274 cache_free(crecp);
275 }
276 }
277 else if ((crecp->flags & F_FORWARD) &&
278 ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || ((crecp->flags | flags) & F_CNAME)) &&
279 hostname_isequal(cache_get_name(crecp), name))
280 {
281 if (crecp->flags & (F_HOSTS | F_DHCP))
282 return 0;
283 *up = crecp->hash_next;
284 cache_unlink(crecp);
285 cache_free(crecp);
286 }
287 else
288 up = &crecp->hash_next;
289 }
290 else
291 {
292 int i;
293 #ifdef HAVE_IPV6
294 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
295 #else
296 int addrlen = INADDRSZ;
297 #endif
298 for (i = 0; i < hash_size; i++)
299 for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
300 if (is_expired(now, crecp))
301 {
302 *up = crecp->hash_next;
303 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
304 {
305 cache_unlink(crecp);
306 cache_free(crecp);
307 }
308 }
309 else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&
310 (flags & crecp->flags & F_REVERSE) &&
311 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
312 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
313 {
314 *up = crecp->hash_next;
315 cache_unlink(crecp);
316 cache_free(crecp);
317 }
318 else
319 up = &crecp->hash_next;
320 }
321
322 return 1;
323 }
324
325 /* Note: The normal calling sequence is
326 cache_start_insert
327 cache_insert * n
328 cache_end_insert
329
330 but an abort can cause the cache_end_insert to be missed
331 in which can the next cache_start_insert cleans things up. */
332
333 void cache_start_insert(void)
334 {
335 /* Free any entries which didn't get committed during the last
336 insert due to error.
337 */
338 while (new_chain)
339 {
340 struct crec *tmp = new_chain->next;
341 cache_free(new_chain);
342 new_chain = tmp;
343 }
344 new_chain = NULL;
345 insert_error = 0;
346 }
347
348 struct crec *cache_insert(char *name, struct all_addr *addr,
349 time_t now, unsigned long ttl, unsigned short flags)
350 {
351 #ifdef HAVE_IPV6
352 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
353 #else
354 int addrlen = INADDRSZ;
355 #endif
356 struct crec *new;
357 union bigname *big_name = NULL;
358 int freed_all = flags & F_REVERSE;
359
360 log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
361
362 /* name is needed as workspace by log_query in this case */
363 if ((flags & F_NEG) && (flags & F_REVERSE))
364 name = NULL;
365
366 /* CONFIG bit no needed except for logging */
367 flags &= ~F_CONFIG;
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 (freed_all)
397 {
398 cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
399 cache_live_freed++;
400 }
401 else
402 {
403 cache_scan_free(NULL, NULL, now, 0);
404 freed_all = 1;
405 }
406 continue;
407 }
408
409 /* Check if we need to and can allocate extra memory for a long name.
410 If that fails, give up now. */
411 if (name && (strlen(name) > SMALLDNAME-1))
412 {
413 if (big_free)
414 {
415 big_name = big_free;
416 big_free = big_free->next;
417 }
418 else if (!bignames_left ||
419 !(big_name = (union bigname *)malloc(sizeof(union bigname))))
420 {
421 insert_error = 1;
422 return NULL;
423 }
424 else
425 bignames_left--;
426
427 }
428
429 /* Got the rest: finally grab entry. */
430 cache_unlink(new);
431 break;
432 }
433
434 new->flags = flags;
435 if (big_name)
436 {
437 new->name.bname = big_name;
438 new->flags |= F_BIGNAME;
439 }
440 if (name)
441 strcpy(cache_get_name(new), name);
442 else
443 *cache_get_name(new) = 0;
444 if (addr)
445 memcpy(&new->addr.addr, addr, addrlen);
446 else
447 new->addr.cname.cache = NULL;
448
449 new->ttd = now + (time_t)ttl;
450 new->next = new_chain;
451 new_chain = new;
452
453 return new;
454 }
455
456 /* after end of insertion, commit the new entries */
457 void cache_end_insert(void)
458 {
459 if (insert_error)
460 return;
461
462 while (new_chain)
463 {
464 struct crec *tmp = new_chain->next;
465 /* drop CNAMEs which didn't find a target. */
466 if (is_outdated_cname_pointer(new_chain))
467 cache_free(new_chain);
468 else
469 {
470 cache_hash(new_chain);
471 cache_link(new_chain);
472 cache_inserted++;
473 }
474 new_chain = tmp;
475 }
476 new_chain = NULL;
477 }
478
479 struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
480 {
481 struct crec *ans;
482
483 if (crecp) /* iterating */
484 ans = crecp->next;
485 else
486 {
487 /* first search, look for relevant entries and push to top of list
488 also free anything which has expired */
489 struct crec *next, **up, **insert = NULL, **chainp = &ans;
490
491 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
492 {
493 next = crecp->hash_next;
494
495 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
496 {
497 if ((crecp->flags & F_FORWARD) &&
498 (crecp->flags & prot) &&
499 hostname_isequal(cache_get_name(crecp), name))
500 {
501 if (crecp->flags & (F_HOSTS | F_DHCP))
502 {
503 *chainp = crecp;
504 chainp = &crecp->next;
505 }
506 else
507 {
508 cache_unlink(crecp);
509 cache_link(crecp);
510 }
511
512 /* move all but the first entry up the hash chain
513 this implements round-robin */
514 if (!insert)
515 {
516 insert = up;
517 up = &crecp->hash_next;
518 }
519 else
520 {
521 *up = crecp->hash_next;
522 crecp->hash_next = *insert;
523 *insert = crecp;
524 insert = &crecp->hash_next;
525 }
526 }
527 else
528 /* case : not expired, incorrect entry. */
529 up = &crecp->hash_next;
530 }
531 else
532 {
533 /* expired entry, free it */
534 *up = crecp->hash_next;
535 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
536 {
537 cache_unlink(crecp);
538 cache_free(crecp);
539 }
540 }
541 }
542
543 *chainp = cache_head;
544 }
545
546 if (ans &&
547 (ans->flags & F_FORWARD) &&
548 (ans->flags & prot) &&
549 hostname_isequal(cache_get_name(ans), name))
550 return ans;
551
552 return NULL;
553 }
554
555 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
556 time_t now, unsigned short prot)
557 {
558 struct crec *ans;
559 #ifdef HAVE_IPV6
560 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
561 #else
562 int addrlen = INADDRSZ;
563 #endif
564
565 if (crecp) /* iterating */
566 ans = crecp->next;
567 else
568 {
569 /* first search, look for relevant entries and push to top of list
570 also free anything which has expired */
571 int i;
572 struct crec **up, **chainp = &ans;
573
574 for(i=0; i<hash_size; i++)
575 for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
576 if (!is_expired(now, crecp))
577 {
578 if ((crecp->flags & F_REVERSE) &&
579 (crecp->flags & prot) &&
580 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
581 {
582 if (crecp->flags & (F_HOSTS | F_DHCP))
583 {
584 *chainp = crecp;
585 chainp = &crecp->next;
586 }
587 else
588 {
589 cache_unlink(crecp);
590 cache_link(crecp);
591 }
592 }
593 up = &crecp->hash_next;
594 }
595 else
596 {
597 *up = crecp->hash_next;
598 if (!(crecp->flags & (F_HOSTS | F_DHCP)))
599 {
600 cache_unlink(crecp);
601 cache_free(crecp);
602 }
603 }
604
605 *chainp = cache_head;
606 }
607
608 if (ans &&
609 (ans->flags & F_REVERSE) &&
610 (ans->flags & prot) &&
611 memcmp(&ans->addr.addr, addr, addrlen) == 0)
612 return ans;
613
614 return NULL;
615 }
616
617 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
618 unsigned short flags, int index, int addr_dup)
619 {
620 struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
621 int i;
622
623 /* Remove duplicates in hosts files. */
624 if (lookup && (lookup->flags & F_HOSTS) &&
625 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
626 free(cache);
627 else
628 {
629 /* Ensure there is only one address -> name mapping (first one trumps)
630 We do this by steam here, first we see if the address is the same as
631 the last one we saw, which eliminates most in the case of an ad-block
632 file with thousands of entries for the same address.
633 Then we search and bail at the first matching address that came from
634 a HOSTS file. Since the first host entry gets reverse, we know
635 then that it must exist without searching exhaustively for it. */
636
637 if (addr_dup)
638 flags &= ~F_REVERSE;
639 else
640 for (i=0; i<hash_size; i++)
641 {
642 for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
643 if ((lookup->flags & F_HOSTS) &&
644 (lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
645 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
646 {
647 flags &= ~F_REVERSE;
648 break;
649 }
650 if (lookup)
651 break;
652 }
653
654 cache->flags = flags;
655 cache->uid = index;
656 memcpy(&cache->addr.addr, addr, addrlen);
657 cache_hash(cache);
658 }
659 }
660
661 static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index, int cache_size)
662 {
663 FILE *f = fopen(filename, "r");
664 char *line;
665 int addr_count = 0, name_count = cache_size, lineno = 0;
666 unsigned short flags, saved_flags = 0;
667 struct all_addr addr, saved_addr;
668
669 if (!f)
670 {
671 syslog(LOG_ERR, _("failed to load names from %s: %m"), filename);
672 return 0;
673 }
674
675 while ((line = fgets(buff, MAXDNAME, f)))
676 {
677 char *token = strtok(line, " \t\n\r");
678 int addrlen, addr_dup = 0;
679
680 lineno++;
681
682 if (!token || (*token == '#'))
683 continue;
684
685 #ifdef HAVE_IPV6
686 if (inet_pton(AF_INET, token, &addr) > 0)
687 {
688 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
689 addrlen = INADDRSZ;
690 }
691 else if (inet_pton(AF_INET6, token, &addr) > 0)
692 {
693 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
694 addrlen = IN6ADDRSZ;
695 }
696 #else
697 if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
698 {
699 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
700 addrlen = INADDRSZ;
701 }
702 #endif
703 else
704 {
705 syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
706 continue;
707 }
708
709 if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
710 addr_dup = 1;
711 else
712 {
713 saved_flags = flags;
714 saved_addr = addr;
715 }
716
717 addr_count++;
718
719 /* rehash every 1000 names. */
720 if ((name_count - cache_size) > 1000)
721 {
722 rehash(name_count);
723 cache_size = name_count;
724 }
725
726 while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
727 {
728 struct crec *cache;
729 if (canonicalise(token))
730 {
731 /* If set, add a version of the name with a default domain appended */
732 if ((opts & OPT_EXPAND) && domain_suffix && !strchr(token, '.') &&
733 (cache = malloc(sizeof(struct crec) +
734 strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
735 {
736 strcpy(cache->name.sname, token);
737 strcat(cache->name.sname, ".");
738 strcat(cache->name.sname, domain_suffix);
739 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
740 addr_dup = 1;
741 name_count++;
742 }
743 if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
744 {
745 strcpy(cache->name.sname, token);
746 add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
747 name_count++;
748 }
749 }
750 else
751 syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
752 }
753 }
754
755 fclose(f);
756 rehash(name_count);
757
758 syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
759
760 return name_count;
761 }
762
763 void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts)
764 {
765 struct crec *cache, **up, *tmp;
766 int i, total_size = cache_size;
767
768 cache_inserted = cache_live_freed = 0;
769
770 for (i=0; i<hash_size; i++)
771 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
772 {
773 tmp = cache->hash_next;
774 if (cache->flags & F_HOSTS)
775 {
776 *up = cache->hash_next;
777 free(cache);
778 }
779 else if (!(cache->flags & F_DHCP))
780 {
781 *up = cache->hash_next;
782 if (cache->flags & F_BIGNAME)
783 {
784 cache->name.bname->next = big_free;
785 big_free = cache->name.bname;
786 }
787 cache->flags = 0;
788 }
789 else
790 up = &cache->hash_next;
791 }
792
793 if ((opts & OPT_NO_HOSTS) && !addn_hosts)
794 {
795 if (cache_size > 0)
796 syslog(LOG_INFO, _("cleared cache"));
797 return;
798 }
799
800 if (!(opts & OPT_NO_HOSTS))
801 total_size = read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0, total_size);
802 while (addn_hosts)
803 {
804 total_size = read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index, total_size);
805 addn_hosts = addn_hosts->next;
806 }
807 }
808
809 void cache_unhash_dhcp(void)
810 {
811 struct crec *tmp, *cache, **up;
812 int i;
813
814 for (i=0; i<hash_size; i++)
815 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
816 if (cache->flags & F_DHCP)
817 *up = cache->hash_next;
818 else
819 up = &cache->hash_next;
820
821 /* prev field links all dhcp entries */
822 for (cache = dhcp_inuse; cache; cache = tmp)
823 {
824 tmp = cache->prev;
825 cache->prev = dhcp_spare;
826 dhcp_spare = cache;
827 }
828
829 dhcp_inuse = NULL;
830 }
831
832 void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
833 struct in_addr *host_address, time_t ttd)
834 {
835 struct crec *crec;
836 unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
837
838 if (!host_name)
839 return;
840
841 if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME)))
842 {
843 if (crec->flags & F_HOSTS)
844 {
845 if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
846 {
847 strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
848 syslog(LOG_WARNING,
849 _("not giving name %s to the DHCP lease of %s because "
850 "the name exists in %s with address %s"),
851 host_name, inet_ntoa(*host_address),
852 record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
853 }
854 return;
855 }
856 else if (!(crec->flags & F_DHCP))
857 cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
858 }
859
860 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
861 {
862 if (crec->flags & F_NEG)
863 cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
864 else
865 /* avoid multiple reverse mappings */
866 flags &= ~F_REVERSE;
867 }
868
869 if ((crec = dhcp_spare))
870 dhcp_spare = dhcp_spare->prev;
871 else /* need new one */
872 crec = malloc(sizeof(struct crec));
873
874 if (crec) /* malloc may fail */
875 {
876 crec->flags = flags;
877 if (ttd == 0)
878 crec->flags |= F_IMMORTAL;
879 else
880 crec->ttd = ttd;
881 crec->addr.addr.addr.addr4 = *host_address;
882 crec->name.namep = host_name;
883 crec->prev = dhcp_inuse;
884 dhcp_inuse = crec;
885 cache_hash(crec);
886 }
887 }
888
889
890
891 void dump_cache(struct daemon *daemon, time_t now)
892 {
893 syslog(LOG_INFO, _("time %lu, cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
894 (unsigned long)now, daemon->cachesize, cache_live_freed, cache_inserted);
895
896 if ((daemon->options & (OPT_DEBUG | OPT_LOG)) &&
897 (addrbuff || (addrbuff = malloc(ADDRSTRLEN))))
898 {
899 struct crec *cache ;
900 int i;
901 syslog(LOG_DEBUG, "Host Address Flags Expires");
902
903 for (i=0; i<hash_size; i++)
904 for (cache = hash_table[i]; cache; cache = cache->hash_next)
905 {
906 if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
907 addrbuff[0] = 0;
908 else if (cache->flags & F_CNAME)
909 {
910 addrbuff[0] = 0;
911 addrbuff[ADDRSTRLEN-1] = 0;
912 if (!is_outdated_cname_pointer(cache))
913 strncpy(addrbuff, cache_get_name(cache->addr.cname.cache), ADDRSTRLEN);
914 }
915 #ifdef HAVE_IPV6
916 else if (cache->flags & F_IPV4)
917 inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
918 else if (cache->flags & F_IPV6)
919 inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
920 #else
921 else
922 strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr.addr4));
923 #endif
924 syslog(LOG_DEBUG,
925 #ifdef HAVE_BROKEN_RTC
926 "%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %lu",
927 #else
928 "%-40.40s %-30.30s %s%s%s%s%s%s%s%s%s%s %s",
929 #endif
930 cache_get_name(cache), addrbuff,
931 cache->flags & F_IPV4 ? "4" : "",
932 cache->flags & F_IPV6 ? "6" : "",
933 cache->flags & F_CNAME ? "C" : "",
934 cache->flags & F_FORWARD ? "F" : " ",
935 cache->flags & F_REVERSE ? "R" : " ",
936 cache->flags & F_IMMORTAL ? "I" : " ",
937 cache->flags & F_DHCP ? "D" : " ",
938 cache->flags & F_NEG ? "N" : " ",
939 cache->flags & F_NXDOMAIN ? "X" : " ",
940 cache->flags & F_HOSTS ? "H" : " ",
941 #ifdef HAVE_BROKEN_RTC
942 cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now)
943 #else
944 cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))
945 #endif
946 );
947 }
948 }
949 }
950
951 static char *record_source(struct hostsfile *addn_hosts, int index)
952 {
953 char *source = HOSTSFILE;
954 while (addn_hosts)
955 {
956 if (addn_hosts->index == index)
957 {
958 source = addn_hosts->fname;
959 break;
960 }
961 addn_hosts = addn_hosts->next;
962 }
963
964 return source;
965 }
966
967 void log_query(unsigned short flags, char *name, struct all_addr *addr,
968 unsigned short type, struct hostsfile *addn_hosts, int index)
969 {
970 char *source;
971 char *verb = "is";
972 char types[20];
973
974 if (!log_queries)
975 return;
976
977 if (flags & F_NEG)
978 {
979 if (flags & F_REVERSE)
980 #ifdef HAVE_IPV6
981 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
982 addr, name, MAXDNAME);
983 #else
984 strcpy(name, inet_ntoa(addr->addr.addr4));
985 #endif
986
987 if (flags & F_NXDOMAIN)
988 strcpy(addrbuff, "<NXDOMAIN>");
989 else
990 strcpy(addrbuff, "<NODATA>");
991
992 if (flags & F_IPV4)
993 strcat(addrbuff, "-IPv4");
994 else if (flags & F_IPV6)
995 strcat(addrbuff, "-IPv6");
996 }
997 else if (flags & F_CNAME)
998 {
999 /* nasty abuse of IPV4 and IPV6 flags */
1000 if (flags & F_IPV4)
1001 strcpy(addrbuff, "<MX>");
1002 else if (flags & F_IPV6)
1003 strcpy(addrbuff, "<SRV>");
1004 else if (flags & F_NXDOMAIN)
1005 strcpy(addrbuff, "<TXT>");
1006 else if (flags & F_BIGNAME)
1007 strcpy(addrbuff, "<PTR>");
1008 else
1009 strcpy(addrbuff, "<CNAME>");
1010 }
1011 else
1012 #ifdef HAVE_IPV6
1013 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1014 addr, addrbuff, ADDRSTRLEN);
1015 #else
1016 strcpy(addrbuff, inet_ntoa(addr->addr.addr4));
1017 #endif
1018
1019 if (flags & F_DHCP)
1020 source = "DHCP";
1021 else if (flags & F_HOSTS)
1022 source = record_source(addn_hosts, index);
1023 else if (flags & F_CONFIG)
1024 source = "config";
1025 else if (flags & F_UPSTREAM)
1026 source = "reply";
1027 else if (flags & F_SERVER)
1028 {
1029 source = "forwarded";
1030 verb = "to";
1031 }
1032 else if (flags & F_QUERY)
1033 {
1034 unsigned int i;
1035
1036 if (type != 0)
1037 {
1038 sprintf(types, "query[type=%d]", type);
1039 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1040 if (typestr[i].type == type)
1041 sprintf(types,"query[%s]", typestr[i].name);
1042 }
1043 source = types;
1044 verb = "from";
1045 }
1046 else
1047 source = "cached";
1048
1049 if (strlen(name) == 0)
1050 name = ".";
1051
1052 if ((flags & F_FORWARD) | (flags & F_NEG))
1053 syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff);
1054 else if (flags & F_REVERSE)
1055 syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name);
1056 }
1057