Annotation of embedaddon/dnsmasq/src/cache.c, revision 1.1.1.1

1.1       misho       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>