Diff for /embedaddon/dnsmasq/src/cache.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2013/07/29 19:37:40 version 1.1.1.2, 2014/06/15 16:31:38
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 24  static struct crec *new_chain = NULL; Line 24  static struct crec *new_chain = NULL;
 static int cache_inserted = 0, cache_live_freed = 0, insert_error;  static int cache_inserted = 0, cache_live_freed = 0, insert_error;
 static union bigname *big_free = NULL;  static union bigname *big_free = NULL;
 static int bignames_left, hash_size;  static int bignames_left, hash_size;
 static int uid = 0;  
 #ifdef HAVE_DNSSEC  
 static struct keydata *keyblock_free = NULL;  
 #endif  
   
 /* type->string mapping: this is also used by the name-hash function as a mixing table. */  /* type->string mapping: this is also used by the name-hash function as a mixing table. */
 static const struct {  static const struct {
Line 56  static const struct { Line 52  static const struct {
   { 38,  "A6" },    { 38,  "A6" },
   { 39,  "DNAME" },    { 39,  "DNAME" },
   { 41,  "OPT" },    { 41,  "OPT" },
     { 43,  "DS" },
     { 46,  "RRSIG" },
     { 47,  "NSEC" },
   { 48,  "DNSKEY" },    { 48,  "DNSKEY" },
     { 50,  "NSEC3" },
   { 249, "TKEY" },    { 249, "TKEY" },
   { 250, "TSIG" },    { 250, "TSIG" },
   { 251, "IXFR" },    { 251, "IXFR" },
Line 72  static void cache_link(struct crec *crecp); Line 72  static void cache_link(struct crec *crecp);
 static void rehash(int size);  static void rehash(int size);
 static void cache_hash(struct crec *crecp);  static void cache_hash(struct crec *crecp);
   
   static unsigned int next_uid(void)
   {
     static unsigned int uid = 0;
   
     uid++;
     
     /* uid == 0 used to indicate CNAME to interface name. */
     if (uid == SRC_INTERFACE)
       uid++;
     
     return uid;
   }
   
 void cache_init(void)  void cache_init(void)
 {  {
   struct crec *crecp;    struct crec *crecp;
   int i;    int i;
 
   bignames_left = daemon->cachesize/10;    bignames_left = daemon->cachesize/10;
       
   if (daemon->cachesize > 0)    if (daemon->cachesize > 0)
Line 87  void cache_init(void) Line 100  void cache_init(void)
         {          {
           cache_link(crecp);            cache_link(crecp);
           crecp->flags = 0;            crecp->flags = 0;
          crecp->uid = uid++;          crecp->uid = next_uid();
         }          }
     }      }
       
Line 171  static void cache_hash(struct crec *crecp) Line 184  static void cache_hash(struct crec *crecp)
   crecp->hash_next = *up;    crecp->hash_next = *up;
   *up = crecp;    *up = crecp;
 }  }
 
 #ifdef HAVE_DNSSEC
 static void cache_blockdata_free(struct crec *crecp)
 {
   if (crecp->flags & F_DNSKEY)
     {
       if (crecp->flags & F_DS)
         blockdata_free(crecp->addr.sig.keydata);
       else
         blockdata_free(crecp->addr.key.keydata);
     }
   else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
     blockdata_free(crecp->addr.ds.keydata);
 }
 #endif
 
 static void cache_free(struct crec *crecp)  static void cache_free(struct crec *crecp)
 {  {
   crecp->flags &= ~F_FORWARD;    crecp->flags &= ~F_FORWARD;
   crecp->flags &= ~F_REVERSE;    crecp->flags &= ~F_REVERSE;
  crecp->uid = uid++; /* invalidate CNAMES pointing to this. */  crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
  
   if (cache_tail)    if (cache_tail)
     cache_tail->next = crecp;      cache_tail->next = crecp;
   else    else
Line 193  static void cache_free(struct crec *crecp) Line 221  static void cache_free(struct crec *crecp)
       big_free = crecp->name.bname;        big_free = crecp->name.bname;
       crecp->flags &= ~F_BIGNAME;        crecp->flags &= ~F_BIGNAME;
     }      }
   
 #ifdef HAVE_DNSSEC  #ifdef HAVE_DNSSEC
  else if (crecp->flags & (F_DNSKEY | F_DS))  cache_blockdata_free(crecp);
    keydata_free(crecp->addr.key.keydata); 
 #endif  #endif
 }      }    
   
Line 235  char *cache_get_name(struct crec *crecp) Line 263  char *cache_get_name(struct crec *crecp)
   return crecp->name.sname;    return crecp->name.sname;
 }  }
   
   char *cache_get_cname_target(struct crec *crecp)
   {
     if (crecp->addr.cname.uid != SRC_INTERFACE)
       return cache_get_name(crecp->addr.cname.target.cache);
   
     return crecp->addr.cname.target.int_name->name;
   }
   
   
   
 struct crec *cache_enumerate(int init)  struct crec *cache_enumerate(int init)
 {  {
   static int bucket;    static int bucket;
Line 260  struct crec *cache_enumerate(int init) Line 298  struct crec *cache_enumerate(int init)
   
 static int is_outdated_cname_pointer(struct crec *crecp)  static int is_outdated_cname_pointer(struct crec *crecp)
 {  {
  if (!(crecp->flags & F_CNAME))  if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
     return 0;      return 0;
       
   /* NB. record may be reused as DS or DNSKEY, where uid is     /* NB. record may be reused as DS or DNSKEY, where uid is 
      overloaded for something completely different */       overloaded for something completely different */
  if (crecp->addr.cname.cache &&   if (crecp->addr.cname.target.cache && 
      (crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&      (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
      crecp->addr.cname.uid == crecp->addr.cname.cache->uid)      crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
     return 0;      return 0;
       
   return 1;    return 1;
Line 304  static int cache_scan_free(char *name, struct all_addr Line 342  static int cache_scan_free(char *name, struct all_addr
   if (flags & F_FORWARD)    if (flags & F_FORWARD)
     {      {
       for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)        for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
        if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))        {
          {           if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
            *up = crecp->hash_next;            { 
            if (!(crecp->flags & (F_HOSTS | F_DHCP)))              *up = crecp->hash_next;
              {              if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
                cache_unlink(crecp);                {
                cache_free(crecp);                  cache_unlink(crecp);
              }                  cache_free(crecp);
                          }
        else if ((crecp->flags & F_FORWARD) &&               continue;
                 ((flags & crecp->flags & F_TYPE) || ((crecp->flags | flags) & F_CNAME)) &&            } 
                 hostname_isequal(cache_get_name(crecp), name))        
          {          if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
            if (crecp->flags & (F_HOSTS | F_DHCP))            {
              return 0;              /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
            *up = crecp->hash_next;              if ((flags & crecp->flags & (F_IPV4 | F_IPV6)) || 
            cache_unlink(crecp);                  (((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
            cache_free(crecp);                {
          }                  if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
        else                    return 0;
                   *up = crecp->hash_next;
                   cache_unlink(crecp);
                   cache_free(crecp);
                   continue;
                 }
               
 #ifdef HAVE_DNSSEC
               /* Deletion has to be class-sensitive for DS, DNSKEY, RRSIG, also 
                  type-covered sensitive for  RRSIG */
               if ((flags & (F_DNSKEY | F_DS)) &&
                   (flags & (F_DNSKEY | F_DS)) == (crecp->flags & (F_DNSKEY | F_DS)) &&
                   crecp->uid == addr->addr.dnssec.class &&
                   (!((flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY)) || 
                    crecp->addr.sig.type_covered == addr->addr.dnssec.type))
                 {
                   if (crecp->flags & F_CONFIG)
                     return 0;
                   *up = crecp->hash_next;
                   cache_unlink(crecp);
                   cache_free(crecp);
                   continue;
                 }
 #endif
             }
           up = &crecp->hash_next;            up = &crecp->hash_next;
           }
     }      }
   else    else
     {      {
Line 341  static int cache_scan_free(char *name, struct all_addr Line 404  static int cache_scan_free(char *name, struct all_addr
           if (is_expired(now, crecp))            if (is_expired(now, crecp))
             {              {
               *up = crecp->hash_next;                *up = crecp->hash_next;
              if (!(crecp->flags & (F_HOSTS | F_DHCP)))              if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
                 {                   { 
                   cache_unlink(crecp);                    cache_unlink(crecp);
                   cache_free(crecp);                    cache_free(crecp);
                 }                  }
             }              }
          else if (!(crecp->flags & (F_HOSTS | F_DHCP)) &&          else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
                    (flags & crecp->flags & F_REVERSE) &&                      (flags & crecp->flags & F_REVERSE) && 
                    (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&                     (flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
                    memcmp(&crecp->addr.addr, addr, addrlen) == 0)                     memcmp(&crecp->addr.addr, addr, addrlen) == 0)
Line 394  struct crec *cache_insert(char *name, struct all_addr  Line 457  struct crec *cache_insert(char *name, struct all_addr 
   int freed_all = flags & F_REVERSE;    int freed_all = flags & F_REVERSE;
   int free_avail = 0;    int free_avail = 0;
   
  if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)  /* Don't log DNSSEC records here, done elsewhere */
    ttl = daemon->max_cache_ttl;  if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
     {
       log_query(flags | F_UPSTREAM, name, addr, NULL);
       /* Don;t mess with TTL for DNSSEC records. */
       if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
         ttl = daemon->max_cache_ttl;
     }
   
   /* Don't log keys */  
   if (flags & (F_IPV4 | F_IPV6))  
     log_query(flags | F_UPSTREAM, name, addr, NULL);  
   
   /* if previous insertion failed give up now. */    /* if previous insertion failed give up now. */
   if (insert_error)    if (insert_error)
     return NULL;      return NULL;
  
   /* First remove any expired entries and entries for the name/address we    /* First remove any expired entries and entries for the name/address we
     are currently inserting. Fail is we attempt to delete a name from     are currently inserting. Fail if we attempt to delete a name from
      /etc/hosts or DHCP. */       /etc/hosts or DHCP. */
   if (!cache_scan_free(name, addr, now, flags))    if (!cache_scan_free(name, addr, now, flags))
     {      {
Line 434  struct crec *cache_insert(char *name, struct all_addr  Line 499  struct crec *cache_insert(char *name, struct all_addr 
            insert. Once in this state, all inserts will probably fail. */             insert. Once in this state, all inserts will probably fail. */
         if (free_avail)          if (free_avail)
           {            {
               static int warned = 0;
               if (!warned)
                 {
                   my_syslog(LOG_ERR, _("Internal error in cache."));
                   warned = 1;
                 }
             insert_error = 1;              insert_error = 1;
             return NULL;              return NULL;
           }            }
                                   
         if (freed_all)          if (freed_all)
           {            {
               struct all_addr free_addr = new->addr.addr;;
   
   #ifdef HAVE_DNSSEC
               /* For DNSSEC records, addr holds class and type_covered for RRSIG */
               if (new->flags & (F_DS | F_DNSKEY))
                 {
                   free_addr.addr.dnssec.class = new->uid;
                   if ((new->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
                     free_addr.addr.dnssec.type = new->addr.sig.type_covered;
                 }
   #endif
               
             free_avail = 1; /* Must be free space now. */              free_avail = 1; /* Must be free space now. */
            cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);            cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
             cache_live_freed++;              cache_live_freed++;
           }            }
         else          else
Line 453  struct crec *cache_insert(char *name, struct all_addr  Line 536  struct crec *cache_insert(char *name, struct all_addr 
       }        }
     
     /* Check if we need to and can allocate extra memory for a long name.      /* Check if we need to and can allocate extra memory for a long name.
       If that fails, give up now. */       If that fails, give up now, always succeed for DNSSEC records. */
     if (name && (strlen(name) > SMALLDNAME-1))      if (name && (strlen(name) > SMALLDNAME-1))
       {        {
         if (big_free)          if (big_free)
Line 461  struct crec *cache_insert(char *name, struct all_addr  Line 544  struct crec *cache_insert(char *name, struct all_addr 
             big_name = big_free;              big_name = big_free;
             big_free = big_free->next;              big_free = big_free->next;
           }            }
        else if (!bignames_left ||        else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
                  !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))                   !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
           {            {
             insert_error = 1;              insert_error = 1;
             return NULL;              return NULL;
           }            }
        else        else if (bignames_left != 0)
           bignames_left--;            bignames_left--;
                   
       }        }
Line 490  struct crec *cache_insert(char *name, struct all_addr  Line 573  struct crec *cache_insert(char *name, struct all_addr 
     *cache_get_name(new) = 0;      *cache_get_name(new) = 0;
   
   if (addr)    if (addr)
    new->addr.addr = *addr;    {
 #ifdef HAVE_DNSSEC
       if (flags & (F_DS | F_DNSKEY))
         new->uid = addr->addr.dnssec.class;
       else
 #endif
         new->addr.addr = *addr; 
     }
   
   new->ttd = now + (time_t)ttl;    new->ttd = now + (time_t)ttl;
   new->next = new_chain;    new->next = new_chain;
Line 522  void cache_end_insert(void) Line 612  void cache_end_insert(void)
   new_chain = NULL;    new_chain = NULL;
 }  }
   
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
 {  {
   struct crec *ans;    struct crec *ans;
     int no_rr = prot & F_NO_RR;
   
     prot &= ~F_NO_RR;
     
   if (crecp) /* iterating */    if (crecp) /* iterating */
     ans = crecp->next;      ans = crecp->next;
   else    else
Line 542  struct crec *cache_find_by_name(struct crec *crecp, ch Line 635  struct crec *cache_find_by_name(struct crec *crecp, ch
           if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))            if (!is_expired(now, crecp) && !is_outdated_cname_pointer(crecp))
             {              {
               if ((crecp->flags & F_FORWARD) &&                 if ((crecp->flags & F_FORWARD) && 
   #ifdef HAVE_DNSSEC
                     ((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
   #endif
                   (crecp->flags & prot) &&                    (crecp->flags & prot) &&
                   hostname_isequal(cache_get_name(crecp), name))                    hostname_isequal(cache_get_name(crecp), name))
                 {                  {
                  if (crecp->flags & (F_HOSTS | F_DHCP))                  if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
                     {                      {
                       *chainp = crecp;                        *chainp = crecp;
                       chainp = &crecp->next;                        chainp = &crecp->next;
Line 570  struct crec *cache_find_by_name(struct crec *crecp, ch Line 666  struct crec *cache_find_by_name(struct crec *crecp, ch
                     }                      }
                   else                    else
                     {                      {
                      if (!insert)                      if (!insert && !no_rr)
                         {                          {
                           insert = up;                            insert = up;
                           ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);                            ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
Line 586  struct crec *cache_find_by_name(struct crec *crecp, ch Line 682  struct crec *cache_find_by_name(struct crec *crecp, ch
             {              {
               /* expired entry, free it */                /* expired entry, free it */
               *up = crecp->hash_next;                *up = crecp->hash_next;
              if (!(crecp->flags & (F_HOSTS | F_DHCP)))              if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
                 {                   { 
                   cache_unlink(crecp);                    cache_unlink(crecp);
                   cache_free(crecp);                    cache_free(crecp);
Line 599  struct crec *cache_find_by_name(struct crec *crecp, ch Line 695  struct crec *cache_find_by_name(struct crec *crecp, ch
   
   if (ans &&     if (ans && 
       (ans->flags & F_FORWARD) &&        (ans->flags & F_FORWARD) &&
      (ans->flags & prot) &&#ifdef HAVE_DNSSEC
       ((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
 #endif
       (ans->flags & prot) &&     
       hostname_isequal(cache_get_name(ans), name))        hostname_isequal(cache_get_name(ans), name))
     return ans;      return ans;
       
Line 607  struct crec *cache_find_by_name(struct crec *crecp, ch Line 706  struct crec *cache_find_by_name(struct crec *crecp, ch
 }  }
   
 struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,   struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, 
                                time_t now, unsigned short prot)                                time_t now, unsigned int prot)
 {  {
   struct crec *ans;    struct crec *ans;
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
Line 636  struct crec *cache_find_by_addr(struct crec *crecp, st Line 735  struct crec *cache_find_by_addr(struct crec *crecp, st
                if ((crecp->flags & prot) &&                 if ((crecp->flags & prot) &&
                    memcmp(&crecp->addr.addr, addr, addrlen) == 0)                     memcmp(&crecp->addr.addr, addr, addrlen) == 0)
                  {                             {          
                   if (crecp->flags & (F_HOSTS | F_DHCP))                   if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
                      {                       {
                        *chainp = crecp;                         *chainp = crecp;
                        chainp = &crecp->next;                         chainp = &crecp->next;
Line 652  struct crec *cache_find_by_addr(struct crec *crecp, st Line 751  struct crec *cache_find_by_addr(struct crec *crecp, st
            else             else
              {               {
                *up = crecp->hash_next;                 *up = crecp->hash_next;
               if (!(crecp->flags & (F_HOSTS | F_DHCP)))               if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
                  {                   {
                    cache_unlink(crecp);                     cache_unlink(crecp);
                    cache_free(crecp);                     cache_free(crecp);
Line 680  static void add_hosts_cname(struct crec *target) Line 779  static void add_hosts_cname(struct crec *target)
     if (hostname_isequal(cache_get_name(target), a->target) &&      if (hostname_isequal(cache_get_name(target), a->target) &&
         (crec = whine_malloc(sizeof(struct crec))))          (crec = whine_malloc(sizeof(struct crec))))
       {        {
        crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;        crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
         crec->name.namep = a->alias;          crec->name.namep = a->alias;
        crec->addr.cname.cache = target;        crec->addr.cname.target.cache = target;
         crec->addr.cname.uid = target->uid;          crec->addr.cname.uid = target->uid;
           crec->uid = next_uid();
         cache_hash(crec);          cache_hash(crec);
         add_hosts_cname(crec); /* handle chains */          add_hosts_cname(crec); /* handle chains */
       }        }
 }  }
       
 static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,   static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, 
                            int index, struct crec **rhash, int hashsz)                            unsigned int index, struct crec **rhash, int hashsz)
 {  {
   struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));    struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
   int i, nameexists = 0;    int i, nameexists = 0;
Line 794  static int gettok(FILE *f, char *token) Line 894  static int gettok(FILE *f, char *token)
     }      }
 }  }
   
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
 {    {  
   FILE *f = fopen(filename, "r");    FILE *f = fopen(filename, "r");
   char *token = daemon->namebuff, *domain_suffix = NULL;    char *token = daemon->namebuff, *domain_suffix = NULL;
Line 901  void cache_reload(void) Line 1001  void cache_reload(void)
   struct hostsfile *ah;    struct hostsfile *ah;
   struct host_record *hr;    struct host_record *hr;
   struct name_list *nl;    struct name_list *nl;
     struct cname *a;
     struct interface_name *intr;
   #ifdef HAVE_DNSSEC
     struct ds_config *ds;
   #endif
   
   cache_inserted = cache_live_freed = 0;    cache_inserted = cache_live_freed = 0;
       
   for (i=0; i<hash_size; i++)    for (i=0; i<hash_size; i++)
     for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)      for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
       {        {
   #ifdef HAVE_DNSSEC
           cache_blockdata_free(cache);
   #endif
         tmp = cache->hash_next;          tmp = cache->hash_next;
        if (cache->flags & F_HOSTS)        if (cache->flags & (F_HOSTS | F_CONFIG))
           {            {
             *up = cache->hash_next;              *up = cache->hash_next;
             free(cache);              free(cache);
Line 927  void cache_reload(void) Line 1035  void cache_reload(void)
           up = &cache->hash_next;            up = &cache->hash_next;
       }        }
       
     /* Add CNAMEs to interface_names to the cache */
     for (a = daemon->cnames; a; a = a->next)
       for (intr = daemon->int_names; intr; intr = intr->next)
         if (hostname_isequal(a->target, intr->name) &&
             ((cache = whine_malloc(sizeof(struct crec)))))
           {
             cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
             cache->name.namep = a->alias;
             cache->addr.cname.target.int_name = intr;
             cache->addr.cname.uid = SRC_INTERFACE;
             cache->uid = next_uid();
             cache_hash(cache);
             add_hosts_cname(cache); /* handle chains */
           }
   
   #ifdef HAVE_DNSSEC
     for (ds = daemon->ds; ds; ds = ds->next)
       if ((cache = whine_malloc(sizeof(struct crec))) &&
           (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
         {
           cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
           cache->name.namep = ds->name;
           cache->addr.ds.keylen = ds->digestlen;
           cache->addr.ds.algo = ds->algo;
           cache->addr.ds.keytag = ds->keytag;
           cache->addr.ds.digest = ds->digest_type;
           cache->uid = ds->class;
           cache_hash(cache);
         }
   #endif
     
   /* borrow the packet buffer for a temporary by-address hash */    /* borrow the packet buffer for a temporary by-address hash */
   memset(daemon->packet, 0, daemon->packet_buff_sz);    memset(daemon->packet, 0, daemon->packet_buff_sz);
   revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);    revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
Line 942  void cache_reload(void) Line 1081  void cache_reload(void)
           {            {
             cache->name.namep = nl->name;              cache->name.namep = nl->name;
             cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;              cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
            add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);            add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
           }            }
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
         if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&          if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
Line 950  void cache_reload(void) Line 1089  void cache_reload(void)
           {            {
             cache->name.namep = nl->name;              cache->name.namep = nl->name;
             cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;              cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
            add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);            add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
           }            }
 #endif  #endif
       }        }
Line 963  void cache_reload(void) Line 1102  void cache_reload(void)
     }      }
           
   if (!option_bool(OPT_NO_HOSTS))    if (!option_bool(OPT_NO_HOSTS))
    total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);    total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
                         
   daemon->addn_hosts = expand_filelist(daemon->addn_hosts);    daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
   for (ah = daemon->addn_hosts; ah; ah = ah->next)    for (ah = daemon->addn_hosts; ah; ah = ah->next)
Line 971  void cache_reload(void) Line 1110  void cache_reload(void)
       total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);        total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
 }   } 
   
 char *get_domain(struct in_addr addr)  
 {  
   struct cond_domain *c;  
   
   for (c = daemon->cond_domain; c; c = c->next)  
     if (!c->is6 &&  
         ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&  
         ntohl(addr.s_addr) <= ntohl(c->end.s_addr))  
       return c->domain;  
   
   return daemon->domain_suffix;  
 }  
   
   
 #ifdef HAVE_IPV6  
 char *get_domain6(struct in6_addr *addr)  
 {  
   struct cond_domain *c;  
   
   u64 addrpart = addr6part(addr);  
     
   for (c = daemon->cond_domain; c; c = c->next)  
     if (c->is6 &&  
         is_same_net6(addr, &c->start6, 64) &&  
         addrpart >= addr6part(&c->start6) &&  
         addrpart <= addr6part(&c->end6))  
       return c->domain;  
     
   return daemon->domain_suffix;  
 }  
 #endif  
   
 #ifdef HAVE_DHCP  #ifdef HAVE_DHCP
 struct in_addr a_record_from_hosts(char *name, time_t now)  struct in_addr a_record_from_hosts(char *name, time_t now)
 {  {
Line 1051  static void add_dhcp_cname(struct crec *target, time_t Line 1158  static void add_dhcp_cname(struct crec *target, time_t
                   
         if (aliasc)          if (aliasc)
           {            {
            aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;            aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG;
             if (ttd == 0)              if (ttd == 0)
               aliasc->flags |= F_IMMORTAL;                aliasc->flags |= F_IMMORTAL;
             else              else
               aliasc->ttd = ttd;                aliasc->ttd = ttd;
             aliasc->name.namep = a->alias;              aliasc->name.namep = a->alias;
            aliasc->addr.cname.cache = target;            aliasc->addr.cname.target.cache = target;
             aliasc->addr.cname.uid = target->uid;              aliasc->addr.cname.uid = target->uid;
               aliasc->uid = next_uid();
             cache_hash(aliasc);              cache_hash(aliasc);
             add_dhcp_cname(aliasc, ttd);              add_dhcp_cname(aliasc, ttd);
           }            }
Line 1086  void cache_add_dhcp_entry(char *host_name, int prot, Line 1194  void cache_add_dhcp_entry(char *host_name, int prot,
   while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))    while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
     {      {
       /* check all addresses associated with name */        /* check all addresses associated with name */
      if (crec->flags & F_HOSTS)      if (crec->flags & (F_HOSTS | F_CONFIG))
         {          {
           if (crec->flags & F_CNAME)            if (crec->flags & F_CNAME)
             my_syslog(MS_DHCP | LOG_WARNING,               my_syslog(MS_DHCP | LOG_WARNING, 
Line 1146  void cache_add_dhcp_entry(char *host_name, int prot, Line 1254  void cache_add_dhcp_entry(char *host_name, int prot,
         crec->ttd = ttd;          crec->ttd = ttd;
       crec->addr.addr = *host_address;        crec->addr.addr = *host_address;
       crec->name.namep = host_name;        crec->name.namep = host_name;
      crec->uid = uid++;      crec->uid = next_uid();
       cache_hash(crec);        cache_hash(crec);
   
       add_dhcp_cname(crec, ttd);        add_dhcp_cname(crec, ttd);
Line 1154  void cache_add_dhcp_entry(char *host_name, int prot, Line 1262  void cache_add_dhcp_entry(char *host_name, int prot,
 }  }
 #endif  #endif
   
   int cache_make_stat(struct txt_record *t)
   { 
     static char *buff = NULL;
     static int bufflen = 60;
     int len;
     struct server *serv, *serv1;
     char *p;
   
     if (!buff && !(buff = whine_malloc(60)))
       return 0;
   
     p = buff;
     
     switch (t->stat)
       {
       case TXT_STAT_CACHESIZE:
         sprintf(buff+1, "%d", daemon->cachesize);
         break;
   
       case TXT_STAT_INSERTS:
         sprintf(buff+1, "%d", cache_inserted);
         break;
   
       case TXT_STAT_EVICTIONS:
         sprintf(buff+1, "%d", cache_live_freed);
         break;
   
       case TXT_STAT_MISSES:
         sprintf(buff+1, "%u", daemon->queries_forwarded);
         break;
   
       case TXT_STAT_HITS:
         sprintf(buff+1, "%u", daemon->local_answer);
         break;
   
   #ifdef HAVE_AUTH
       case TXT_STAT_AUTH:
         sprintf(buff+1, "%u", daemon->auth_answer);
         break;
   #endif
   
       case TXT_STAT_SERVERS:
         /* sum counts from different records for same server */
         for (serv = daemon->servers; serv; serv = serv->next)
           serv->flags &= ~SERV_COUNTED;
         
         for (serv = daemon->servers; serv; serv = serv->next)
           if (!(serv->flags & 
                 (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
             {
               char *new, *lenp;
               int port, newlen, bytes_avail, bytes_needed;
               unsigned int queries = 0, failed_queries = 0;
               for (serv1 = serv; serv1; serv1 = serv1->next)
                 if (!(serv1->flags & 
                       (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) && 
                     sockaddr_isequal(&serv->addr, &serv1->addr))
                   {
                     serv1->flags |= SERV_COUNTED;
                     queries += serv1->queries;
                     failed_queries += serv1->failed_queries;
                   }
               port = prettyprint_addr(&serv->addr, daemon->addrbuff);
               lenp = p++; /* length */
               bytes_avail = (p - buff) + bufflen;
               bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
               if (bytes_needed >= bytes_avail)
                 {
                   /* expand buffer if necessary */
                   newlen = bytes_needed + 1 + bufflen - bytes_avail;
                   if (!(new = whine_malloc(newlen)))
                     return 0;
                   memcpy(new, buff, bufflen);
                   free(buff);
                   p = new + (p - buff);
                   lenp = p - 1;
                   buff = new;
                   bufflen = newlen;
                   bytes_avail = (p - buff) + bufflen;
                   bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
                 }
               *lenp = bytes_needed;
               p += bytes_needed;
             }
         t->txt = (unsigned char *)buff;
         t->len = p - buff;
         return 1;
       }
     
     len = strlen(buff+1);
     t->txt = (unsigned char *)buff;
     t->len = len + 1;
     *buff = len;
     return 1;
   }
   
 void dump_cache(time_t now)  void dump_cache(time_t now)
 {  {
   struct server *serv, *serv1;    struct server *serv, *serv1;
     char *t = "";
   
   my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);    my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
   my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),     my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."), 
             daemon->cachesize, cache_live_freed, cache_inserted);              daemon->cachesize, cache_live_freed, cache_inserted);
   my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),     my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), 
             daemon->queries_forwarded, daemon->local_answer);              daemon->queries_forwarded, daemon->local_answer);
   #ifdef HAVE_AUTH
     my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
   #endif
   #ifdef HAVE_DNSSEC
     blockdata_report();
   #endif
   
   /* sum counts from different records for same server */    /* sum counts from different records for same server */
   for (serv = daemon->servers; serv; serv = serv->next)    for (serv = daemon->servers; serv; serv = serv->next)
Line 1192  void dump_cache(time_t now) Line 1402  void dump_cache(time_t now)
     {      {
       struct crec *cache ;        struct crec *cache ;
       int i;        int i;
      my_syslog(LOG_INFO, "Host                                     Address                        Flags     Expires");      my_syslog(LOG_INFO, "Host                                     Address                        Flags      Expires");
           
       for (i=0; i<hash_size; i++)        for (i=0; i<hash_size; i++)
         for (cache = hash_table[i]; cache; cache = cache->hash_next)          for (cache = hash_table[i]; cache; cache = cache->hash_next)
           {            {
            char *a, *p = daemon->namebuff;            char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
            p += sprintf(p, "%-40.40s ", cache_get_name(cache));            *a = 0;
            if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))            if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
              a = "";               n = "<Root>";
            else if (cache->flags & F_CNAME)             p += sprintf(p, "%-40.40s ", n);
              {            if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
                a = "";              a = cache_get_cname_target(cache);
                if (!is_outdated_cname_pointer(cache)) 
                  a = cache_get_name(cache->addr.cname.cache); 
              } 
 #ifdef HAVE_DNSSEC  #ifdef HAVE_DNSSEC
             else if (cache->flags & F_DNSKEY)  
               {  
                 a = daemon->addrbuff;  
                 sprintf(a, "%3u %u", cache->addr.key.algo, cache->uid);  
               }  
             else if (cache->flags & F_DS)              else if (cache->flags & F_DS)
               {                {
                a = daemon->addrbuff;                if (cache->flags & F_DNSKEY)
                sprintf(a, "%5u %3u %3u %u", cache->addr.key.flags_or_keyid,                  /* RRSIG */
                        cache->addr.key.algo, cache->addr.key.digest, cache->uid);                  sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
                           cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
                 else if (!(cache->flags & F_NEG))
                   sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
                           cache->addr.ds.algo, cache->addr.ds.digest);
               }                }
               else if (cache->flags & F_DNSKEY)
                 sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
                         cache->addr.key.algo, cache->addr.key.flags);
 #endif  #endif
            else             else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
               {                 { 
                 a = daemon->addrbuff;                  a = daemon->addrbuff;
                 if (cache->flags & F_IPV4)                  if (cache->flags & F_IPV4)
Line 1231  void dump_cache(time_t now) Line 1440  void dump_cache(time_t now)
 #endif  #endif
               }                }
   
            p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s%s%s%s%s  ", a,             if (cache->flags & F_IPV4)
                         cache->flags & F_IPV4 ? "4" : "",              t = "4";
                         cache->flags & F_IPV6 ? "6" : "",            else if (cache->flags & F_IPV6)
                         cache->flags & F_DNSKEY ? "K" : "",              t = "6";
                         cache->flags & F_DS ? "S" : "",            else if (cache->flags & F_CNAME)
                         cache->flags & F_CNAME ? "C" : "",              t = "C";
 #ifdef HAVE_DNSSEC
             else if ((cache->flags & (F_DS | F_DNSKEY)) == (F_DS | F_DNSKEY))
               t = "G"; /* DNSKEY and DS set -> RRISG */
             else if (cache->flags & F_DS)
               t = "S";
             else if (cache->flags & F_DNSKEY)
               t = "K";
 #endif
             p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s  ", a, t,
                          cache->flags & F_FORWARD ? "F" : " ",                           cache->flags & F_FORWARD ? "F" : " ",
                          cache->flags & F_REVERSE ? "R" : " ",                           cache->flags & F_REVERSE ? "R" : " ",
                          cache->flags & F_IMMORTAL ? "I" : " ",                           cache->flags & F_IMMORTAL ? "I" : " ",
Line 1257  void dump_cache(time_t now) Line 1475  void dump_cache(time_t now)
     }      }
 }  }
   
char *record_source(int index)char *record_source(unsigned int index)
 {  {
   struct hostsfile *ah;    struct hostsfile *ah;
   
  if (index == 0)  if (index == SRC_CONFIG)
     return "config";
   else if (index == SRC_HOSTS)
     return HOSTSFILE;      return HOSTSFILE;
   
   for (ah = daemon->addn_hosts; ah; ah = ah->next)    for (ah = daemon->addn_hosts; ah; ah = ah->next)
Line 1271  char *record_source(int index) Line 1491  char *record_source(int index)
   return "<unknown>";    return "<unknown>";
 }  }
   
void querystr(char *desc, char *str, unsigned short type)char *querystr(char *desc, unsigned short type)
 {  {
   unsigned int i;    unsigned int i;
    int len = 10; /* strlen("type=xxxxx") */
  sprintf(str, "%s[type=%d]", desc, type);   const char *types = NULL;
   static char *buff = NULL;
   static int bufflen = 0;
 
   for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)    for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
     if (typestr[i].type == type)      if (typestr[i].type == type)
      sprintf(str,"%s[%s]", desc, typestr[i].name);      {
         types = typestr[i].name;
         len = strlen(types);
         break;
       }
 
   len += 3; /* braces, terminator */
   len += strlen(desc);
 
   if (!buff || bufflen < len)
     {
       if (buff)
         free(buff);
       else if (len < 20)
         len = 20;
       
       buff = whine_malloc(len);
       bufflen = len;
     }
 
   if (buff)
     {
       if (types)
         sprintf(buff, "%s[%s]", desc, types);
       else
         sprintf(buff, "%s[type=%d]", desc, type);
     }
 
   return buff ? buff : "";
 }  }
   
 void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)  void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
Line 1291  void log_query(unsigned int flags, char *name, struct  Line 1542  void log_query(unsigned int flags, char *name, struct 
   
   if (addr)    if (addr)
     {      {
         if (flags & F_KEYTAG)
           sprintf(daemon->addrbuff, arg, addr->addr.keytag);
         else
           {
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
      inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,          inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
                addr, daemon->addrbuff, ADDRSTRLEN);                    addr, daemon->addrbuff, ADDRSTRLEN);
 #else  #else
      strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);            strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);  
 #endif  #endif
           }
     }      }
     else
       dest = arg;
   
   if (flags & F_REVERSE)    if (flags & F_REVERSE)
     {      {
Line 1308  void log_query(unsigned int flags, char *name, struct  Line 1566  void log_query(unsigned int flags, char *name, struct 
   if (flags & F_NEG)    if (flags & F_NEG)
     {      {
       if (flags & F_NXDOMAIN)        if (flags & F_NXDOMAIN)
        {        dest = "NXDOMAIN";
          if (flags & F_IPV4) 
            dest = "NXDOMAIN-IPv4"; 
          else if (flags & F_IPV6) 
            dest = "NXDOMAIN-IPv6"; 
          else 
            dest = "NXDOMAIN"; 
        } 
       else        else
         {                {      
           if (flags & F_IPV4)            if (flags & F_IPV4)
Line 1339  void log_query(unsigned int flags, char *name, struct  Line 1590  void log_query(unsigned int flags, char *name, struct 
     source = arg;      source = arg;
   else if (flags & F_UPSTREAM)    else if (flags & F_UPSTREAM)
     source = "reply";      source = "reply";
     else if (flags & F_SECSTAT)
       source = "validation";
   else if (flags & F_AUTH)    else if (flags & F_AUTH)
     source = "auth";      source = "auth";
   else if (flags & F_SERVER)    else if (flags & F_SERVER)
Line 1351  void log_query(unsigned int flags, char *name, struct  Line 1604  void log_query(unsigned int flags, char *name, struct 
       source = arg;        source = arg;
       verb = "from";        verb = "from";
     }      }
     else if (flags & F_DNSSEC)
       {
         source = arg;
         verb = "to";
       }
     else if (flags & F_IPSET)
       {
         source = "ipset add";
         dest = name;
         name = arg;
         verb = daemon->addrbuff;
       }
   else    else
     source = "cached";      source = "cached";
       
Line 1360  void log_query(unsigned int flags, char *name, struct  Line 1625  void log_query(unsigned int flags, char *name, struct 
   my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);    my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
 }  }
   
#ifdef HAVE_DNSSEC 
struct keydata *keydata_alloc(char *data, size_t len) 
{ 
  struct keydata *block, *ret = NULL; 
  struct keydata **prev = &ret; 
  while (len > 0) 
    { 
      if (keyblock_free) 
        { 
          block = keyblock_free; 
          keyblock_free = block->next; 
        } 
      else 
        block = whine_malloc(sizeof(struct keydata)); 
 
      if (!block) 
        { 
          /* failed to alloc, free partial chain */ 
          keydata_free(ret); 
          return NULL; 
        } 
       
      memcpy(block->key, data, len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len); 
      data += KEYBLOCK_LEN; 
      len -= KEYBLOCK_LEN; 
      *prev = block; 
      prev = &block->next; 
      block->next = NULL; 
    } 
   
  return ret; 
} 
 
void keydata_free(struct keydata *blocks) 
{ 
  struct keydata *tmp; 
 
  if (blocks) 
    { 
      for (tmp = blocks; tmp->next; tmp = tmp->next); 
      tmp->next = keyblock_free; 
      keyblock_free = blocks; 
    } 
} 
#endif 
 
       

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


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