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

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

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