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