File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / cache.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 29 19:37:40 2013 UTC (10 years, 11 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_66p0, v2_66, HEAD
dnsmasq

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

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