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