]> git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/cache.c
Cache stats availble in CHAOS .bind domain.
[people/ms/dnsmasq.git] / src / cache.c
1 /* dnsmasq is Copyright (c) 2000-2014 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
28 /* type->string mapping: this is also used by the name-hash function as a mixing table. */
29 static const struct {
30 unsigned int type;
31 const char * const name;
32 } typestr[] = {
33 { 1, "A" },
34 { 2, "NS" },
35 { 5, "CNAME" },
36 { 6, "SOA" },
37 { 10, "NULL" },
38 { 11, "WKS" },
39 { 12, "PTR" },
40 { 13, "HINFO" },
41 { 15, "MX" },
42 { 16, "TXT" },
43 { 22, "NSAP" },
44 { 23, "NSAP_PTR" },
45 { 24, "SIG" },
46 { 25, "KEY" },
47 { 28, "AAAA" },
48 { 33, "SRV" },
49 { 35, "NAPTR" },
50 { 36, "KX" },
51 { 37, "CERT" },
52 { 38, "A6" },
53 { 39, "DNAME" },
54 { 41, "OPT" },
55 { 43, "DS" },
56 { 46, "RRSIG" },
57 { 47, "NSEC" },
58 { 48, "DNSKEY" },
59 { 50, "NSEC3" },
60 { 249, "TKEY" },
61 { 250, "TSIG" },
62 { 251, "IXFR" },
63 { 252, "AXFR" },
64 { 253, "MAILB" },
65 { 254, "MAILA" },
66 { 255, "ANY" }
67 };
68
69 static void cache_free(struct crec *crecp);
70 static void cache_unlink(struct crec *crecp);
71 static void cache_link(struct crec *crecp);
72 static void rehash(int size);
73 static void cache_hash(struct crec *crecp);
74
75 static unsigned int next_uid(void)
76 {
77 static unsigned int uid = 0;
78
79 uid++;
80
81 /* uid == 0 used to indicate CNAME to interface name. */
82 if (uid == SRC_INTERFACE)
83 uid++;
84
85 return uid;
86 }
87
88 void cache_init(void)
89 {
90 struct crec *crecp;
91 int i;
92
93 bignames_left = daemon->cachesize/10;
94
95 if (daemon->cachesize > 0)
96 {
97 crecp = safe_malloc(daemon->cachesize*sizeof(struct crec));
98
99 for (i=0; i < daemon->cachesize; i++, crecp++)
100 {
101 cache_link(crecp);
102 crecp->flags = 0;
103 crecp->uid = next_uid();
104 }
105 }
106
107 /* create initial hash table*/
108 rehash(daemon->cachesize);
109 }
110
111 /* In most cases, we create the hash table once here by calling this with (hash_table == NULL)
112 but if the hosts file(s) are big (some people have 50000 ad-block entries), the table
113 will be much too small, so the hosts reading code calls rehash every 1000 addresses, to
114 expand the table. */
115 static void rehash(int size)
116 {
117 struct crec **new, **old, *p, *tmp;
118 int i, new_size, old_size;
119
120 /* hash_size is a power of two. */
121 for (new_size = 64; new_size < size/10; new_size = new_size << 1);
122
123 /* must succeed in getting first instance, failure later is non-fatal */
124 if (!hash_table)
125 new = safe_malloc(new_size * sizeof(struct crec *));
126 else if (new_size <= hash_size || !(new = whine_malloc(new_size * sizeof(struct crec *))))
127 return;
128
129 for(i = 0; i < new_size; i++)
130 new[i] = NULL;
131
132 old = hash_table;
133 old_size = hash_size;
134 hash_table = new;
135 hash_size = new_size;
136
137 if (old)
138 {
139 for (i = 0; i < old_size; i++)
140 for (p = old[i]; p ; p = tmp)
141 {
142 tmp = p->hash_next;
143 cache_hash(p);
144 }
145 free(old);
146 }
147 }
148
149 static struct crec **hash_bucket(char *name)
150 {
151 unsigned int c, val = 017465; /* Barker code - minimum self-correlation in cyclic shift */
152 const unsigned char *mix_tab = (const unsigned char*)typestr;
153
154 while((c = (unsigned char) *name++))
155 {
156 /* don't use tolower and friends here - they may be messed up by LOCALE */
157 if (c >= 'A' && c <= 'Z')
158 c += 'a' - 'A';
159 val = ((val << 7) | (val >> (32 - 7))) + (mix_tab[(val + c) & 0x3F] ^ c);
160 }
161
162 /* hash_size is a power of two */
163 return hash_table + ((val ^ (val >> 16)) & (hash_size - 1));
164 }
165
166 static void cache_hash(struct crec *crecp)
167 {
168 /* maintain an invariant that all entries with F_REVERSE set
169 are at the start of the hash-chain and all non-reverse
170 immortal entries are at the end of the hash-chain.
171 This allows reverse searches and garbage collection to be optimised */
172
173 struct crec **up = hash_bucket(cache_get_name(crecp));
174
175 if (!(crecp->flags & F_REVERSE))
176 {
177 while (*up && ((*up)->flags & F_REVERSE))
178 up = &((*up)->hash_next);
179
180 if (crecp->flags & F_IMMORTAL)
181 while (*up && !((*up)->flags & F_IMMORTAL))
182 up = &((*up)->hash_next);
183 }
184 crecp->hash_next = *up;
185 *up = crecp;
186 }
187
188 #ifdef HAVE_DNSSEC
189 static void cache_blockdata_free(struct crec *crecp)
190 {
191 if (crecp->flags & F_DNSKEY)
192 {
193 if (crecp->flags & F_DS)
194 blockdata_free(crecp->addr.sig.keydata);
195 else
196 blockdata_free(crecp->addr.key.keydata);
197 }
198 else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
199 blockdata_free(crecp->addr.ds.keydata);
200 }
201 #endif
202
203 static void cache_free(struct crec *crecp)
204 {
205 crecp->flags &= ~F_FORWARD;
206 crecp->flags &= ~F_REVERSE;
207 crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
208
209 if (cache_tail)
210 cache_tail->next = crecp;
211 else
212 cache_head = crecp;
213 crecp->prev = cache_tail;
214 crecp->next = NULL;
215 cache_tail = crecp;
216
217 /* retrieve big name for further use. */
218 if (crecp->flags & F_BIGNAME)
219 {
220 crecp->name.bname->next = big_free;
221 big_free = crecp->name.bname;
222 crecp->flags &= ~F_BIGNAME;
223 }
224
225 #ifdef HAVE_DNSSEC
226 cache_blockdata_free(crecp);
227 #endif
228 }
229
230 /* insert a new cache entry at the head of the list (youngest entry) */
231 static void cache_link(struct crec *crecp)
232 {
233 if (cache_head) /* check needed for init code */
234 cache_head->prev = crecp;
235 crecp->next = cache_head;
236 crecp->prev = NULL;
237 cache_head = crecp;
238 if (!cache_tail)
239 cache_tail = crecp;
240 }
241
242 /* remove an arbitrary cache entry for promotion */
243 static void cache_unlink (struct crec *crecp)
244 {
245 if (crecp->prev)
246 crecp->prev->next = crecp->next;
247 else
248 cache_head = crecp->next;
249
250 if (crecp->next)
251 crecp->next->prev = crecp->prev;
252 else
253 cache_tail = crecp->prev;
254 }
255
256 char *cache_get_name(struct crec *crecp)
257 {
258 if (crecp->flags & F_BIGNAME)
259 return crecp->name.bname->name;
260 else if (crecp->flags & F_NAMEP)
261 return crecp->name.namep;
262
263 return crecp->name.sname;
264 }
265
266 char *cache_get_cname_target(struct crec *crecp)
267 {
268 if (crecp->addr.cname.uid != SRC_INTERFACE)
269 return cache_get_name(crecp->addr.cname.target.cache);
270
271 return crecp->addr.cname.target.int_name->name;
272 }
273
274
275
276 struct crec *cache_enumerate(int init)
277 {
278 static int bucket;
279 static struct crec *cache;
280
281 if (init)
282 {
283 bucket = 0;
284 cache = NULL;
285 }
286 else if (cache && cache->hash_next)
287 cache = cache->hash_next;
288 else
289 {
290 cache = NULL;
291 while (bucket < hash_size)
292 if ((cache = hash_table[bucket++]))
293 break;
294 }
295
296 return cache;
297 }
298
299 static int is_outdated_cname_pointer(struct crec *crecp)
300 {
301 if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
302 return 0;
303
304 /* NB. record may be reused as DS or DNSKEY, where uid is
305 overloaded for something completely different */
306 if (crecp->addr.cname.target.cache &&
307 (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
308 crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
309 return 0;
310
311 return 1;
312 }
313
314 static int is_expired(time_t now, struct crec *crecp)
315 {
316 if (crecp->flags & F_IMMORTAL)
317 return 0;
318
319 if (difftime(now, crecp->ttd) < 0)
320 return 0;
321
322 return 1;
323 }
324
325 static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
326 {
327 /* Scan and remove old entries.
328 If (flags & F_FORWARD) then remove any forward entries for name and any expired
329 entries but only in the same hash bucket as name.
330 If (flags & F_REVERSE) then remove any reverse entries for addr and any expired
331 entries in the whole cache.
332 If (flags == 0) remove any expired entries in the whole cache.
333
334 In the flags & F_FORWARD case, the return code is valid, and returns zero if the
335 name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
336
337 We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
338 so that when we hit an entry which isn't reverse and is immortal, we're done. */
339
340 struct crec *crecp, **up;
341
342 if (flags & F_FORWARD)
343 {
344 for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
345 {
346 if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
347 {
348 *up = crecp->hash_next;
349 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
350 {
351 cache_unlink(crecp);
352 cache_free(crecp);
353 }
354 continue;
355 }
356
357 if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
358 {
359 /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
360 if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) ||
361 (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
362 {
363 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
364 return 0;
365 *up = crecp->hash_next;
366 cache_unlink(crecp);
367 cache_free(crecp);
368 continue;
369 }
370
371 #ifdef HAVE_DNSSEC
372 /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also
373 type-covered sensitive for RRSIG */
374 if ((flags & (F_DNSKEY | F_DS)) &&
375 (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
376 crecp->uid == addr->addr.dnssec.class &&
377 (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) ||
378 crecp->addr.sig.type_covered == addr->addr.dnssec.type))
379 {
380 if (crecp->flags & F_CONFIG)
381 return 0;
382 *up = crecp->hash_next;
383 cache_unlink(crecp);
384 cache_free(crecp);
385 continue;
386 }
387 #endif
388 }
389 up = &crecp->hash_next;
390 }
391 }
392 else
393 {
394 int i;
395 #ifdef HAVE_IPV6
396 int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
397 #else
398 int addrlen = INADDRSZ;
399 #endif
400 for (i = 0; i < hash_size; i++)
401 for (crecp = hash_table[i], up = &hash_table[i];
402 crecp && ((crecp->flags & F_REVERSE) || !(crecp->flags & F_IMMORTAL));
403 crecp = crecp->hash_next)
404 if (is_expired(now, crecp))
405 {
406 *up = crecp->hash_next;
407 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
408 {
409 cache_unlink(crecp);
410 cache_free(crecp);
411 }
412 }
413 else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
414 (flags & crecp->flags & F_REVERSE) &&
415 (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
416 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
417 {
418 *up = crecp->hash_next;
419 cache_unlink(crecp);
420 cache_free(crecp);
421 }
422 else
423 up = &crecp->hash_next;
424 }
425
426 return 1;
427 }
428
429 /* Note: The normal calling sequence is
430 cache_start_insert
431 cache_insert * n
432 cache_end_insert
433
434 but an abort can cause the cache_end_insert to be missed
435 in which can the next cache_start_insert cleans things up. */
436
437 void cache_start_insert(void)
438 {
439 /* Free any entries which didn't get committed during the last
440 insert due to error.
441 */
442 while (new_chain)
443 {
444 struct crec *tmp = new_chain->next;
445 cache_free(new_chain);
446 new_chain = tmp;
447 }
448 new_chain = NULL;
449 insert_error = 0;
450 }
451
452 struct crec *cache_insert(char *name, struct all_addr *addr,
453 time_t now, unsigned long ttl, unsigned short flags)
454 {
455 struct crec *new;
456 union bigname *big_name = NULL;
457 int freed_all = flags & F_REVERSE;
458 int free_avail = 0;
459
460 /* Don't log DNSSEC records here, done elsewhere */
461 if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
462 {
463 log_query(flags | F_UPSTREAM, name, addr, NULL);
464 /* Don;t mess with TTL for DNSSEC records. */
465 if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
466 ttl = daemon->max_cache_ttl;
467 }
468
469 /* if previous insertion failed give up now. */
470 if (insert_error)
471 return NULL;
472
473 /* First remove any expired entries and entries for the name/address we
474 are currently inserting. Fail if we attempt to delete a name from
475 /etc/hosts or DHCP. */
476 if (!cache_scan_free(name, addr, now, flags))
477 {
478 insert_error = 1;
479 return NULL;
480 }
481
482 /* Now get a cache entry from the end of the LRU list */
483 while (1) {
484 if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
485 {
486 insert_error = 1;
487 return NULL;
488 }
489
490 /* End of LRU list is still in use: if we didn't scan all the hash
491 chains for expired entries do that now. If we already tried that
492 then it's time to start spilling things. */
493
494 if (new->flags & (F_FORWARD | F_REVERSE))
495 {
496 /* If free_avail set, we believe that an entry has been freed.
497 Bugs have been known to make this not true, resulting in
498 a tight loop here. If that happens, abandon the
499 insert. Once in this state, all inserts will probably fail. */
500 if (free_avail)
501 {
502 static int warned = 0;
503 if (!warned)
504 {
505 my_syslog(LOG_ERR, _("Internal error in cache."));
506 warned = 1;
507 }
508 insert_error = 1;
509 return NULL;
510 }
511
512 if (freed_all)
513 {
514 struct all_addr free_addr = new->addr.addr;;
515
516 #ifdef HAVE_DNSSEC
517 /* For DNSSEC records, addr holds class and type_covered for RRSIG */
518 if (new->flags & (F_DS | F_DNSKEY))
519 {
520 free_addr.addr.dnssec.class = new->uid;
521 if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
522 free_addr.addr.dnssec.type = new->addr.sig.type_covered;
523 }
524 #endif
525
526 free_avail = 1; /* Must be free space now. */
527 cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
528 cache_live_freed++;
529 }
530 else
531 {
532 cache_scan_free(NULL, NULL, now, 0);
533 freed_all = 1;
534 }
535 continue;
536 }
537
538 /* Check if we need to and can allocate extra memory for a long name.
539 If that fails, give up now, always succeed for DNSSEC records. */
540 if (name && (strlen(name) > SMALLDNAME-1))
541 {
542 if (big_free)
543 {
544 big_name = big_free;
545 big_free = big_free->next;
546 }
547 else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
548 !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
549 {
550 insert_error = 1;
551 return NULL;
552 }
553 else if (bignames_left != 0)
554 bignames_left--;
555
556 }
557
558 /* Got the rest: finally grab entry. */
559 cache_unlink(new);
560 break;
561 }
562
563 new->flags = flags;
564 if (big_name)
565 {
566 new->name.bname = big_name;
567 new->flags |= F_BIGNAME;
568 }
569
570 if (name)
571 strcpy(cache_get_name(new), name);
572 else
573 *cache_get_name(new) = 0;
574
575 if (addr)
576 {
577 #ifdef HAVE_DNSSEC
578 if (flags & (F_DS | F_DNSKEY))
579 new->uid = addr->addr.dnssec.class;
580 else
581 #endif
582 new->addr.addr = *addr;
583 }
584
585 new->ttd = now + (time_t)ttl;
586 new->next = new_chain;
587 new_chain = new;
588
589 return new;
590 }
591
592 /* after end of insertion, commit the new entries */
593 void cache_end_insert(void)
594 {
595 if (insert_error)
596 return;
597
598 while (new_chain)
599 {
600 struct crec *tmp = new_chain->next;
601 /* drop CNAMEs which didn't find a target. */
602 if (is_outdated_cname_pointer(new_chain))
603 cache_free(new_chain);
604 else
605 {
606 cache_hash(new_chain);
607 cache_link(new_chain);
608 cache_inserted++;
609 }
610 new_chain = tmp;
611 }
612 new_chain = NULL;
613 }
614
615 struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
616 {
617 struct crec *ans;
618 int no_rr = prot & F_NO_RR;
619
620 prot &= ~F_NO_RR;
621
622 if (crecp) /* iterating */
623 ans = crecp->next;
624 else
625 {
626 /* first search, look for relevant entries and push to top of list
627 also free anything which has expired */
628 struct crec *next, **up, **insert = NULL, **chainp = &ans;
629 unsigned short ins_flags = 0;
630
631 for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
632 {
633 next = crecp->hash_next;
634
635 if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
636 {
637 if ((crecp->flags & F_FORWARD) &&
638 #ifdef HAVE_DNSSEC
639 ((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
640 #endif
641 (crecp->flags & prot) &&
642 hostname_isequal(cache_get_name(crecp), name))
643 {
644 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
645 {
646 *chainp = crecp;
647 chainp = &crecp->next;
648 }
649 else
650 {
651 cache_unlink(crecp);
652 cache_link(crecp);
653 }
654
655 /* Move all but the first entry up the hash chain
656 this implements round-robin.
657 Make sure that re-ordering doesn't break the hash-chain
658 order invariants.
659 */
660 if (insert && (crecp->flags & (F_REVERSE | F_IMMORTAL)) == ins_flags)
661 {
662 *up = crecp->hash_next;
663 crecp->hash_next = *insert;
664 *insert = crecp;
665 insert = &crecp->hash_next;
666 }
667 else
668 {
669 if (!insert && !no_rr)
670 {
671 insert = up;
672 ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
673 }
674 up = &crecp->hash_next;
675 }
676 }
677 else
678 /* case : not expired, incorrect entry. */
679 up = &crecp->hash_next;
680 }
681 else
682 {
683 /* expired entry, free it */
684 *up = crecp->hash_next;
685 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
686 {
687 cache_unlink(crecp);
688 cache_free(crecp);
689 }
690 }
691 }
692
693 *chainp = cache_head;
694 }
695
696 if (ans &&
697 (ans->flags & F_FORWARD) &&
698 #ifdef HAVE_DNSSEC
699 ((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
700 #endif
701 (ans->flags & prot) &&
702 hostname_isequal(cache_get_name(ans), name))
703 return ans;
704
705 return NULL;
706 }
707
708 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
709 time_t now, unsigned int prot)
710 {
711 struct crec *ans;
712 #ifdef HAVE_IPV6
713 int addrlen = (prot == F_IPV6) ? IN6ADDRSZ : INADDRSZ;
714 #else
715 int addrlen = INADDRSZ;
716 #endif
717
718 if (crecp) /* iterating */
719 ans = crecp->next;
720 else
721 {
722 /* first search, look for relevant entries and push to top of list
723 also free anything which has expired. All the reverse entries are at the
724 start of the hash chain, so we can give up when we find the first
725 non-REVERSE one. */
726 int i;
727 struct crec **up, **chainp = &ans;
728
729 for (i=0; i<hash_size; i++)
730 for (crecp = hash_table[i], up = &hash_table[i];
731 crecp && (crecp->flags & F_REVERSE);
732 crecp = crecp->hash_next)
733 if (!is_expired(now, crecp))
734 {
735 if ((crecp->flags & prot) &&
736 memcmp(&crecp->addr.addr, addr, addrlen) == 0)
737 {
738 if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
739 {
740 *chainp = crecp;
741 chainp = &crecp->next;
742 }
743 else
744 {
745 cache_unlink(crecp);
746 cache_link(crecp);
747 }
748 }
749 up = &crecp->hash_next;
750 }
751 else
752 {
753 *up = crecp->hash_next;
754 if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
755 {
756 cache_unlink(crecp);
757 cache_free(crecp);
758 }
759 }
760
761 *chainp = cache_head;
762 }
763
764 if (ans &&
765 (ans->flags & F_REVERSE) &&
766 (ans->flags & prot) &&
767 memcmp(&ans->addr.addr, addr, addrlen) == 0)
768 return ans;
769
770 return NULL;
771 }
772
773 static void add_hosts_cname(struct crec *target)
774 {
775 struct crec *crec;
776 struct cname *a;
777
778 for (a = daemon->cnames; a; a = a->next)
779 if (hostname_isequal(cache_get_name(target), a->target) &&
780 (crec = whine_malloc(sizeof(struct crec))))
781 {
782 crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
783 crec->name.namep = a->alias;
784 crec->addr.cname.target.cache = target;
785 crec->addr.cname.uid = target->uid;
786 crec->uid = next_uid();
787 cache_hash(crec);
788 add_hosts_cname(crec); /* handle chains */
789 }
790 }
791
792 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
793 unsigned int index, struct crec **rhash, int hashsz)
794 {
795 struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
796 int i, nameexists = 0;
797 unsigned int j;
798
799 /* Remove duplicates in hosts files. */
800 if (lookup && (lookup->flags & F_HOSTS))
801 {
802 nameexists = 1;
803 if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
804 {
805 free(cache);
806 return;
807 }
808 }
809
810 /* Ensure there is only one address -> name mapping (first one trumps)
811 We do this by steam here, The entries are kept in hash chains, linked
812 by ->next (which is unused at this point) held in hash buckets in
813 the array rhash, hashed on address. Note that rhash and the values
814 in ->next are only valid whilst reading hosts files: the buckets are
815 then freed, and the ->next pointer used for other things.
816
817 Only insert each unique address once into this hashing structure.
818
819 This complexity avoids O(n^2) divergent CPU use whilst reading
820 large (10000 entry) hosts files. */
821
822 /* hash address */
823 for (j = 0, i = 0; i < addrlen; i++)
824 j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
825
826 for (lookup = rhash[j]; lookup; lookup = lookup->next)
827 if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
828 memcmp(&lookup->addr.addr, addr, addrlen) == 0)
829 {
830 cache->flags &= ~F_REVERSE;
831 break;
832 }
833
834 /* maintain address hash chain, insert new unique address */
835 if (!lookup)
836 {
837 cache->next = rhash[j];
838 rhash[j] = cache;
839 }
840
841 cache->uid = index;
842 memcpy(&cache->addr.addr, addr, addrlen);
843 cache_hash(cache);
844
845 /* don't need to do alias stuff for second and subsequent addresses. */
846 if (!nameexists)
847 add_hosts_cname(cache);
848 }
849
850 static int eatspace(FILE *f)
851 {
852 int c, nl = 0;
853
854 while (1)
855 {
856 if ((c = getc(f)) == '#')
857 while (c != '\n' && c != EOF)
858 c = getc(f);
859
860 if (c == EOF)
861 return 1;
862
863 if (!isspace(c))
864 {
865 ungetc(c, f);
866 return nl;
867 }
868
869 if (c == '\n')
870 nl = 1;
871 }
872 }
873
874 static int gettok(FILE *f, char *token)
875 {
876 int c, count = 0;
877
878 while (1)
879 {
880 if ((c = getc(f)) == EOF)
881 return (count == 0) ? EOF : 1;
882
883 if (isspace(c) || c == '#')
884 {
885 ungetc(c, f);
886 return eatspace(f);
887 }
888
889 if (count < (MAXDNAME - 1))
890 {
891 token[count++] = c;
892 token[count] = 0;
893 }
894 }
895 }
896
897 static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
898 {
899 FILE *f = fopen(filename, "r");
900 char *token = daemon->namebuff, *domain_suffix = NULL;
901 int addr_count = 0, name_count = cache_size, lineno = 0;
902 unsigned short flags = 0;
903 struct all_addr addr;
904 int atnl, addrlen = 0;
905
906 if (!f)
907 {
908 my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
909 return 0;
910 }
911
912 eatspace(f);
913
914 while ((atnl = gettok(f, token)) != EOF)
915 {
916 lineno++;
917
918 if (inet_pton(AF_INET, token, &addr) > 0)
919 {
920 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
921 addrlen = INADDRSZ;
922 domain_suffix = get_domain(addr.addr.addr4);
923 }
924 #ifdef HAVE_IPV6
925 else if (inet_pton(AF_INET6, token, &addr) > 0)
926 {
927 flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
928 addrlen = IN6ADDRSZ;
929 domain_suffix = get_domain6(&addr.addr.addr6);
930 }
931 #endif
932 else
933 {
934 my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
935 while (atnl == 0)
936 atnl = gettok(f, token);
937 continue;
938 }
939
940 addr_count++;
941
942 /* rehash every 1000 names. */
943 if ((name_count - cache_size) > 1000)
944 {
945 rehash(name_count);
946 cache_size = name_count;
947 }
948
949 while (atnl == 0)
950 {
951 struct crec *cache;
952 int fqdn, nomem;
953 char *canon;
954
955 if ((atnl = gettok(f, token)) == EOF)
956 break;
957
958 fqdn = !!strchr(token, '.');
959
960 if ((canon = canonicalise(token, &nomem)))
961 {
962 /* If set, add a version of the name with a default domain appended */
963 if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
964 (cache = whine_malloc(sizeof(struct crec) +
965 strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
966 {
967 strcpy(cache->name.sname, canon);
968 strcat(cache->name.sname, ".");
969 strcat(cache->name.sname, domain_suffix);
970 cache->flags = flags;
971 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
972 name_count++;
973 }
974 if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
975 {
976 strcpy(cache->name.sname, canon);
977 cache->flags = flags;
978 add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
979 name_count++;
980 }
981 free(canon);
982
983 }
984 else if (!nomem)
985 my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
986 }
987 }
988
989 fclose(f);
990 rehash(name_count);
991
992 my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
993
994 return name_count;
995 }
996
997 void cache_reload(void)
998 {
999 struct crec *cache, **up, *tmp;
1000 int revhashsz, i, total_size = daemon->cachesize;
1001 struct hostsfile *ah;
1002 struct host_record *hr;
1003 struct name_list *nl;
1004 struct cname *a;
1005 struct interface_name *intr;
1006 #ifdef HAVE_DNSSEC
1007 struct ds_config *ds;
1008 #endif
1009
1010 cache_inserted = cache_live_freed = 0;
1011
1012 for (i=0; i<hash_size; i++)
1013 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
1014 {
1015 #ifdef HAVE_DNSSEC
1016 cache_blockdata_free(cache);
1017 #endif
1018 tmp = cache->hash_next;
1019 if (cache->flags & (F_HOSTS | F_CONFIG))
1020 {
1021 *up = cache->hash_next;
1022 free(cache);
1023 }
1024 else if (!(cache->flags & F_DHCP))
1025 {
1026 *up = cache->hash_next;
1027 if (cache->flags & F_BIGNAME)
1028 {
1029 cache->name.bname->next = big_free;
1030 big_free = cache->name.bname;
1031 }
1032 cache->flags = 0;
1033 }
1034 else
1035 up = &cache->hash_next;
1036 }
1037
1038 /* Add CNAMEs to interface_names to the cache */
1039 for (a = daemon->cnames; a; a = a->next)
1040 for (intr = daemon->int_names; intr; intr = intr->next)
1041 if (hostname_isequal(a->target, intr->name) &&
1042 ((cache = whine_malloc(sizeof(struct crec)))))
1043 {
1044 cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
1045 cache->name.namep = a->alias;
1046 cache->addr.cname.target.int_name = intr;
1047 cache->addr.cname.uid = SRC_INTERFACE;
1048 cache->uid = next_uid();
1049 cache_hash(cache);
1050 add_hosts_cname(cache); /* handle chains */
1051 }
1052
1053 #ifdef HAVE_DNSSEC
1054 for (ds = daemon->ds; ds; ds = ds->next)
1055 if ((cache = whine_malloc(sizeof(struct crec))) &&
1056 (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
1057 {
1058 cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
1059 cache->name.namep = ds->name;
1060 cache->addr.ds.keylen = ds->digestlen;
1061 cache->addr.ds.algo = ds->algo;
1062 cache->addr.ds.keytag = ds->keytag;
1063 cache->addr.ds.digest = ds->digest_type;
1064 cache->uid = ds->class;
1065 cache_hash(cache);
1066 }
1067 #endif
1068
1069 /* borrow the packet buffer for a temporary by-address hash */
1070 memset(daemon->packet, 0, daemon->packet_buff_sz);
1071 revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
1072 /* we overwrote the buffer... */
1073 daemon->srv_save = NULL;
1074
1075 /* Do host_records in config. */
1076 for (hr = daemon->host_records; hr; hr = hr->next)
1077 for (nl = hr->names; nl; nl = nl->next)
1078 {
1079 if (hr->addr.s_addr != 0 &&
1080 (cache = whine_malloc(sizeof(struct crec))))
1081 {
1082 cache->name.namep = nl->name;
1083 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
1084 add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1085 }
1086 #ifdef HAVE_IPV6
1087 if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
1088 (cache = whine_malloc(sizeof(struct crec))))
1089 {
1090 cache->name.namep = nl->name;
1091 cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
1092 add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
1093 }
1094 #endif
1095 }
1096
1097 if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
1098 {
1099 if (daemon->cachesize > 0)
1100 my_syslog(LOG_INFO, _("cleared cache"));
1101 return;
1102 }
1103
1104 if (!option_bool(OPT_NO_HOSTS))
1105 total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
1106
1107 daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
1108 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1109 if (!(ah->flags & AH_INACTIVE))
1110 total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
1111 }
1112
1113 #ifdef HAVE_DHCP
1114 struct in_addr a_record_from_hosts(char *name, time_t now)
1115 {
1116 struct crec *crecp = NULL;
1117 struct in_addr ret;
1118
1119 while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
1120 if (crecp->flags & F_HOSTS)
1121 return *(struct in_addr *)&crecp->addr;
1122
1123 my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
1124
1125 ret.s_addr = 0;
1126 return ret;
1127 }
1128
1129 void cache_unhash_dhcp(void)
1130 {
1131 struct crec *cache, **up;
1132 int i;
1133
1134 for (i=0; i<hash_size; i++)
1135 for (cache = hash_table[i], up = &hash_table[i]; cache; cache = cache->hash_next)
1136 if (cache->flags & F_DHCP)
1137 {
1138 *up = cache->hash_next;
1139 cache->next = dhcp_spare;
1140 dhcp_spare = cache;
1141 }
1142 else
1143 up = &cache->hash_next;
1144 }
1145
1146 static void add_dhcp_cname(struct crec *target, time_t ttd)
1147 {
1148 struct crec *aliasc;
1149 struct cname *a;
1150
1151 for (a = daemon->cnames; a; a = a->next)
1152 if (hostname_isequal(cache_get_name(target), a->target))
1153 {
1154 if ((aliasc = dhcp_spare))
1155 dhcp_spare = dhcp_spare->next;
1156 else /* need new one */
1157 aliasc = whine_malloc(sizeof(struct crec));
1158
1159 if (aliasc)
1160 {
1161 aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
1162 if (ttd == 0)
1163 aliasc->flags |= F_IMMORTAL;
1164 else
1165 aliasc->ttd = ttd;
1166 aliasc->name.namep = a->alias;
1167 aliasc->addr.cname.target.cache = target;
1168 aliasc->addr.cname.uid = target->uid;
1169 aliasc->uid = next_uid();
1170 cache_hash(aliasc);
1171 add_dhcp_cname(aliasc, ttd);
1172 }
1173 }
1174 }
1175
1176 void cache_add_dhcp_entry(char *host_name, int prot,
1177 struct all_addr *host_address, time_t ttd)
1178 {
1179 struct crec *crec = NULL, *fail_crec = NULL;
1180 unsigned short flags = F_IPV4;
1181 int in_hosts = 0;
1182 size_t addrlen = sizeof(struct in_addr);
1183
1184 #ifdef HAVE_IPV6
1185 if (prot == AF_INET6)
1186 {
1187 flags = F_IPV6;
1188 addrlen = sizeof(struct in6_addr);
1189 }
1190 #endif
1191
1192 inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
1193
1194 while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
1195 {
1196 /* check all addresses associated with name */
1197 if (crec->flags & (F_HOSTS | F_CONFIG))
1198 {
1199 if (crec->flags & F_CNAME)
1200 my_syslog(MS_DHCP | LOG_WARNING,
1201 _("%s is a CNAME, not giving it to the DHCP lease of %s"),
1202 host_name, daemon->addrbuff);
1203 else if (memcmp(&crec->addr.addr, host_address, addrlen) == 0)
1204 in_hosts = 1;
1205 else
1206 fail_crec = crec;
1207 }
1208 else if (!(crec->flags & F_DHCP))
1209 {
1210 cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
1211 /* scan_free deletes all addresses associated with name */
1212 break;
1213 }
1214 }
1215
1216 /* if in hosts, don't need DHCP record */
1217 if (in_hosts)
1218 return;
1219
1220 /* Name in hosts, address doesn't match */
1221 if (fail_crec)
1222 {
1223 inet_ntop(prot, &fail_crec->addr.addr, daemon->namebuff, MAXDNAME);
1224 my_syslog(MS_DHCP | LOG_WARNING,
1225 _("not giving name %s to the DHCP lease of %s because "
1226 "the name exists in %s with address %s"),
1227 host_name, daemon->addrbuff,
1228 record_source(fail_crec->uid), daemon->namebuff);
1229 return;
1230 }
1231
1232 if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
1233 {
1234 if (crec->flags & F_NEG)
1235 {
1236 flags |= F_REVERSE;
1237 cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
1238 }
1239 }
1240 else
1241 flags |= F_REVERSE;
1242
1243 if ((crec = dhcp_spare))
1244 dhcp_spare = dhcp_spare->next;
1245 else /* need new one */
1246 crec = whine_malloc(sizeof(struct crec));
1247
1248 if (crec) /* malloc may fail */
1249 {
1250 crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
1251 if (ttd == 0)
1252 crec->flags |= F_IMMORTAL;
1253 else
1254 crec->ttd = ttd;
1255 crec->addr.addr = *host_address;
1256 crec->name.namep = host_name;
1257 crec->uid = next_uid();
1258 cache_hash(crec);
1259
1260 add_dhcp_cname(crec, ttd);
1261 }
1262 }
1263 #endif
1264
1265 int cache_make_stat(struct txt_record *t)
1266 {
1267 static char *buff = NULL;
1268 static int bufflen = 60;
1269 int len;
1270 struct server *serv, *serv1;
1271 char *p;
1272
1273 if (!buff && !(buff = whine_malloc(60)))
1274 return 0;
1275
1276 p = buff;
1277
1278 switch (t->stat)
1279 {
1280 case TXT_STAT_CACHESIZE:
1281 sprintf(buff+1, "%d", daemon->cachesize);
1282 break;
1283
1284 case TXT_STAT_INSERTS:
1285 sprintf(buff+1, "%d", cache_inserted);
1286 break;
1287
1288 case TXT_STAT_EVICTIONS:
1289 sprintf(buff+1, "%d", cache_live_freed);
1290 break;
1291
1292 case TXT_STAT_MISSES:
1293 sprintf(buff+1, "%u", daemon->queries_forwarded);
1294 break;
1295
1296 case TXT_STAT_HITS:
1297 sprintf(buff+1, "%u", daemon->local_answer);
1298 break;
1299
1300 #ifdef HAVE_AUTH
1301 case TXT_STAT_AUTH:
1302 sprintf(buff+1, "%u", daemon->auth_answer);
1303 break;
1304 #endif
1305
1306 case TXT_STAT_SERVERS:
1307 /* sum counts from different records for same server */
1308 for (serv = daemon->servers; serv; serv = serv->next)
1309 serv->flags &= ~SERV_COUNTED;
1310
1311 for (serv = daemon->servers; serv; serv = serv->next)
1312 if (!(serv->flags &
1313 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1314 {
1315 char *new, *lenp;
1316 int port, newlen, bytes_avail, bytes_needed;
1317 unsigned int queries = 0, failed_queries = 0;
1318 for (serv1 = serv; serv1; serv1 = serv1->next)
1319 if (!(serv1->flags &
1320 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1321 sockaddr_isequal(&serv->addr, &serv1->addr))
1322 {
1323 serv1->flags |= SERV_COUNTED;
1324 queries += serv1->queries;
1325 failed_queries += serv1->failed_queries;
1326 }
1327 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1328 lenp = p++; /* length */
1329 bytes_avail = (p - buff) + bufflen;
1330 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1331 if (bytes_needed >= bytes_avail)
1332 {
1333 /* expand buffer if necessary */
1334 newlen = bytes_needed + 1 + bufflen - bytes_avail;
1335 if (!(new = whine_malloc(newlen)))
1336 return 0;
1337 memcpy(new, buff, bufflen);
1338 free(buff);
1339 p = new + (p - buff);
1340 lenp = p - 1;
1341 buff = new;
1342 bufflen = newlen;
1343 bytes_avail = (p - buff) + bufflen;
1344 bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
1345 }
1346 *lenp = bytes_needed;
1347 p += bytes_needed;
1348 }
1349 t->txt = (unsigned char *)buff;
1350 t->len = p - buff;
1351 return 1;
1352 }
1353
1354 len = strlen(buff+1);
1355 t->txt = (unsigned char *)buff;
1356 t->len = len + 1;
1357 *buff = len;
1358 return 1;
1359 }
1360
1361 void dump_cache(time_t now)
1362 {
1363 struct server *serv, *serv1;
1364 char *t = "";
1365
1366 my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
1367 my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
1368 daemon->cachesize, cache_live_freed, cache_inserted);
1369 my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
1370 daemon->queries_forwarded, daemon->local_answer);
1371 #ifdef HAVE_AUTH
1372 my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
1373 #endif
1374 #ifdef HAVE_DNSSEC
1375 blockdata_report();
1376 #endif
1377
1378 /* sum counts from different records for same server */
1379 for (serv = daemon->servers; serv; serv = serv->next)
1380 serv->flags &= ~SERV_COUNTED;
1381
1382 for (serv = daemon->servers; serv; serv = serv->next)
1383 if (!(serv->flags &
1384 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
1385 {
1386 int port;
1387 unsigned int queries = 0, failed_queries = 0;
1388 for (serv1 = serv; serv1; serv1 = serv1->next)
1389 if (!(serv1->flags &
1390 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
1391 sockaddr_isequal(&serv->addr, &serv1->addr))
1392 {
1393 serv1->flags |= SERV_COUNTED;
1394 queries += serv1->queries;
1395 failed_queries += serv1->failed_queries;
1396 }
1397 port = prettyprint_addr(&serv->addr, daemon->addrbuff);
1398 my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
1399 }
1400
1401 if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
1402 {
1403 struct crec *cache ;
1404 int i;
1405 my_syslog(LOG_INFO, "Host Address Flags Expires");
1406
1407 for (i=0; i<hash_size; i++)
1408 for (cache = hash_table[i]; cache; cache = cache->hash_next)
1409 {
1410 char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
1411 *a = 0;
1412 if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
1413 n = "<Root>";
1414 p += sprintf(p, "%-40.40s ", n);
1415 if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
1416 a = cache_get_cname_target(cache);
1417 #ifdef HAVE_DNSSEC
1418 else if (cache->flags & F_DS)
1419 {
1420 if (cache->flags & F_DNSKEY)
1421 /* RRSIG */
1422 sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
1423 cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
1424 else if (!(cache->flags & F_NEG))
1425 sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
1426 cache->addr.ds.algo, cache->addr.ds.digest);
1427 }
1428 else if (cache->flags & F_DNSKEY)
1429 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
1430 cache->addr.key.algo, cache->addr.key.flags);
1431 #endif
1432 else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
1433 {
1434 a = daemon->addrbuff;
1435 if (cache->flags & F_IPV4)
1436 inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
1437 #ifdef HAVE_IPV6
1438 else if (cache->flags & F_IPV6)
1439 inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
1440 #endif
1441 }
1442
1443 if (cache->flags & F_IPV4)
1444 t = "4";
1445 else if (cache->flags & F_IPV6)
1446 t = "6";
1447 else if (cache->flags & F_CNAME)
1448 t = "C";
1449 #ifdef HAVE_DNSSEC
1450 else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
1451 t = "G"; /* DNSKEY and DS set -> RRISG */
1452 else if (cache->flags & F_DS)
1453 t = "S";
1454 else if (cache->flags & F_DNSKEY)
1455 t = "K";
1456 #endif
1457 p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s ", a, t,
1458 cache->flags & F_FORWARD ? "F" : " ",
1459 cache->flags & F_REVERSE ? "R" : " ",
1460 cache->flags & F_IMMORTAL ? "I" : " ",
1461 cache->flags & F_DHCP ? "D" : " ",
1462 cache->flags & F_NEG ? "N" : " ",
1463 cache->flags & F_NXDOMAIN ? "X" : " ",
1464 cache->flags & F_HOSTS ? "H" : " ",
1465 cache->flags & F_DNSSECOK ? "V" : " ");
1466 #ifdef HAVE_BROKEN_RTC
1467 p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
1468 #else
1469 p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
1470 /* ctime includes trailing \n - eat it */
1471 *(p-1) = 0;
1472 #endif
1473 my_syslog(LOG_INFO, daemon->namebuff);
1474 }
1475 }
1476 }
1477
1478 char *record_source(unsigned int index)
1479 {
1480 struct hostsfile *ah;
1481
1482 if (index == SRC_CONFIG)
1483 return "config";
1484 else if (index == SRC_HOSTS)
1485 return HOSTSFILE;
1486
1487 for (ah = daemon->addn_hosts; ah; ah = ah->next)
1488 if (ah->index == index)
1489 return ah->fname;
1490
1491 return "<unknown>";
1492 }
1493
1494 char *querystr(char *desc, unsigned short type)
1495 {
1496 unsigned int i;
1497 int len = 10; /* strlen("type=xxxxx") */
1498 const char *types = NULL;
1499 static char *buff = NULL;
1500 static int bufflen = 0;
1501
1502 for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
1503 if (typestr[i].type == type)
1504 {
1505 types = typestr[i].name;
1506 len = strlen(types);
1507 break;
1508 }
1509
1510 len += 3; /* braces, terminator */
1511 len += strlen(desc);
1512
1513 if (!buff || bufflen < len)
1514 {
1515 if (buff)
1516 free(buff);
1517 else if (len < 20)
1518 len = 20;
1519
1520 buff = whine_malloc(len);
1521 bufflen = len;
1522 }
1523
1524 if (buff)
1525 {
1526 if (types)
1527 sprintf(buff, "%s[%s]", desc, types);
1528 else
1529 sprintf(buff, "%s[type=%d]", desc, type);
1530 }
1531
1532 return buff ? buff : "";
1533 }
1534
1535 void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
1536 {
1537 char *source, *dest = daemon->addrbuff;
1538 char *verb = "is";
1539
1540 if (!option_bool(OPT_LOG))
1541 return;
1542
1543 if (addr)
1544 {
1545 if (flags & F_KEYTAG)
1546 sprintf(daemon->addrbuff, arg, addr->addr.keytag);
1547 else
1548 {
1549 #ifdef HAVE_IPV6
1550 inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1551 addr, daemon->addrbuff, ADDRSTRLEN);
1552 #else
1553 strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1554 #endif
1555 }
1556 }
1557 else
1558 dest = arg;
1559
1560 if (flags & F_REVERSE)
1561 {
1562 dest = name;
1563 name = daemon->addrbuff;
1564 }
1565
1566 if (flags & F_NEG)
1567 {
1568 if (flags & F_NXDOMAIN)
1569 dest = "NXDOMAIN";
1570 else
1571 {
1572 if (flags & F_IPV4)
1573 dest = "NODATA-IPv4";
1574 else if (flags & F_IPV6)
1575 dest = "NODATA-IPv6";
1576 else
1577 dest = "NODATA";
1578 }
1579 }
1580 else if (flags & F_CNAME)
1581 dest = "<CNAME>";
1582 else if (flags & F_RRNAME)
1583 dest = arg;
1584
1585 if (flags & F_CONFIG)
1586 source = "config";
1587 else if (flags & F_DHCP)
1588 source = "DHCP";
1589 else if (flags & F_HOSTS)
1590 source = arg;
1591 else if (flags & F_UPSTREAM)
1592 source = "reply";
1593 else if (flags & F_SECSTAT)
1594 source = "validation";
1595 else if (flags & F_AUTH)
1596 source = "auth";
1597 else if (flags & F_SERVER)
1598 {
1599 source = "forwarded";
1600 verb = "to";
1601 }
1602 else if (flags & F_QUERY)
1603 {
1604 source = arg;
1605 verb = "from";
1606 }
1607 else if (flags & F_DNSSEC)
1608 {
1609 source = arg;
1610 verb = "to";
1611 }
1612 else
1613 source = "cached";
1614
1615 if (strlen(name) == 0)
1616 name = ".";
1617
1618 my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
1619 }
1620
1621