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