File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / cache.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:31:38 2014 UTC (10 years ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_71, HEAD
dnsmasq 2.71

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

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