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