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

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

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