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