• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       /* TODO: support scoped addresses. struct all_addr doesn't store scope IDs. */
1249       inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
1250 		addr, addrbuff, ADDRSTRLEN);
1251 #else
1252       strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
1253 #endif
1254     }
1255 
1256   if (flags & F_REVERSE)
1257     {
1258       dest = name;
1259       name = addrbuff;
1260     }
1261 
1262   if (flags & F_NEG)
1263     {
1264       if (flags & F_NXDOMAIN)
1265 	{
1266 	  if (flags & F_IPV4)
1267 	    dest = "NXDOMAIN-IPv4";
1268 	  else if (flags & F_IPV6)
1269 	    dest = "NXDOMAIN-IPv6";
1270 	  else
1271 	    dest = "NXDOMAIN";
1272 	}
1273       else
1274 	{
1275 	  if (flags & F_IPV4)
1276 	    dest = "NODATA-IPv4";
1277 	  else if (flags & F_IPV6)
1278 	    dest = "NODATA-IPv6";
1279 	  else
1280 	    dest = "NODATA";
1281 	}
1282     }
1283   else if (flags & F_CNAME)
1284     {
1285       /* nasty abuse of NXDOMAIN and CNAME flags */
1286       if (flags & F_NXDOMAIN)
1287 	dest = arg;
1288       else
1289 	dest = "<CNAME>";
1290     }
1291 
1292   if (flags & F_CONFIG)
1293     source = "config";
1294   else if (flags & F_DHCP)
1295     source = "DHCP";
1296   else if (flags & F_HOSTS)
1297     source = arg;
1298   else if (flags & F_UPSTREAM)
1299     source = "reply";
1300   else if (flags & F_SERVER)
1301     {
1302       source = "forwarded";
1303       verb = "to";
1304     }
1305   else if (flags & F_QUERY)
1306     {
1307       source = arg;
1308       verb = "from";
1309     }
1310   else
1311     source = "cached";
1312 
1313   if (strlen(name) == 0)
1314     name = ".";
1315 
1316   my_syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, dest);
1317 }
1318 
1319