File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / cache.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 09:57:01 2016 UTC (7 years, 8 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_76p1, HEAD
dnsmasq 2.76

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>