Annotation of embedaddon/dnsmasq/src/cache.c, revision 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>