Diff for /embedaddon/dnsmasq/src/rfc1035.c between versions 1.1.1.1 and 1.1.1.3

version 1.1.1.1, 2013/07/29 19:37:40 version 1.1.1.3, 2016/11/02 09:57:01
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley/* dnsmasq is Copyright (c) 2000-2016 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 16 Line 16
   
 #include "dnsmasq.h"  #include "dnsmasq.h"
   
   
 #define CHECK_LEN(header, pp, plen, len) \  
     ((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))  
   
 #define ADD_RDLEN(header, pp, plen, len) \  
   (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))  
   
 int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,   int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, 
                  char *name, int isExtract, int extrabytes)                   char *name, int isExtract, int extrabytes)
 {  {
   unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;    unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
  unsigned int j, l, hops = 0;  unsigned int j, l, namelen = 0, hops = 0;
   int retvalue = 1;    int retvalue = 1;
       
   if (isExtract)    if (isExtract)
Line 84  int extract_name(struct dns_header *header, size_t ple Line 77  int extract_name(struct dns_header *header, size_t ple
                       
           p = l + (unsigned char *)header;            p = l + (unsigned char *)header;
         }          }
      else if (label_type == 0x80)      else if (label_type == 0x00)
        return 0; /* reserved */ 
      else if (label_type == 0x40) 
        { /* ELT */ 
          unsigned int count, digs; 
           
          if ((l & 0x3f) != 1) 
            return 0; /* we only understand bitstrings */ 
 
          if (!isExtract) 
            return 0; /* Cannot compare bitsrings */ 
           
          count = *p++; 
          if (count == 0) 
            count = 256; 
          digs = ((count-1)>>2)+1; 
           
          /* output is \[x<hex>/siz]. which is digs+9 chars */ 
          if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME) 
            return 0; 
          if (!CHECK_LEN(header, p, plen, (count-1)>>3)) 
            return 0; 
 
          *cp++ = '\\'; 
          *cp++ = '['; 
          *cp++ = 'x'; 
          for (j=0; j<digs; j++) 
            { 
              unsigned int dig; 
              if (j%2 == 0) 
                dig = *p >> 4; 
              else 
                dig = *p++ & 0x0f; 
               
              *cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10; 
            }  
          cp += sprintf((char *)cp, "/%d]", count); 
          /* do this here to overwrite the zero char from sprintf */ 
          *cp++ = '.'; 
        } 
      else  
         { /* label_type = 0 -> label. */          { /* label_type = 0 -> label. */
          if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)          namelen += l + 1; /* include period */
           if (namelen >= MAXDNAME)
             return 0;              return 0;
           if (!CHECK_LEN(header, p, plen, l))            if (!CHECK_LEN(header, p, plen, l))
             return 0;              return 0;
Line 135  int extract_name(struct dns_header *header, size_t ple Line 89  int extract_name(struct dns_header *header, size_t ple
             if (isExtract)              if (isExtract)
               {                {
                 unsigned char c = *p;                  unsigned char c = *p;
                if (isascii(c) && !iscntrl(c) && c != '.')#ifdef HAVE_DNSSEC
                  *cp++ = *p;                if (option_bool(OPT_DNSSEC_VALID))
                   {
                     if (c == 0 || c == '.' || c == NAME_ESCAPE)
                       {
                         *cp++ = NAME_ESCAPE;
                         *cp++ = c+1;
                       }
                     else
                       *cp++ = c; 
                   }
                 else                  else
   #endif
                   if (c != 0 && c != '.')
                     *cp++ = c;
                   else
                   return 0;                    return 0;
               }                }
             else               else 
Line 151  int extract_name(struct dns_header *header, size_t ple Line 118  int extract_name(struct dns_header *header, size_t ple
                     cp++;                      cp++;
                     if (c1 >= 'A' && c1 <= 'Z')                      if (c1 >= 'A' && c1 <= 'Z')
                       c1 += 'a' - 'A';                        c1 += 'a' - 'A';
   #ifdef HAVE_DNSSEC
                       if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
                         c1 = (*cp++)-1;
   #endif
                       
                     if (c2 >= 'A' && c2 <= 'Z')                      if (c2 >= 'A' && c2 <= 'Z')
                       c2 += 'a' - 'A';                        c2 += 'a' - 'A';
                                         
                     if (c1 != c2)                      if (c1 != c2)
                       retvalue =  2;                        retvalue =  2;
                   }                    }
               }                }
                      
           if (isExtract)            if (isExtract)
             *cp++ = '.';              *cp++ = '.';
           else if (*cp != 0 && *cp++ != '.')            else if (*cp != 0 && *cp++ != '.')
             retvalue = 2;              retvalue = 2;
         }          }
         else
           return 0; /* label types 0x40 and 0x80 not supported */
     }      }
 }  }
     
Line 274  int in_arpa_name_2_addr(char *namein, struct all_addr  Line 248  int in_arpa_name_2_addr(char *namein, struct all_addr 
   return 0;    return 0;
 }  }
   
static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
 {  {
   while(1)    while(1)
     {      {
Line 344  unsigned char *skip_questions(struct dns_header *heade Line 318  unsigned char *skip_questions(struct dns_header *heade
   return ansp;    return ansp;
 }  }
   
static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
 {  {
   int i, rdlen;    int i, rdlen;
       
Line 367  static unsigned char *skip_section(unsigned char *ansp Line 341  static unsigned char *skip_section(unsigned char *ansp
    than CRC the raw bytes, since replies might be compressed differently.      than CRC the raw bytes, since replies might be compressed differently. 
    We ignore case in the names for the same reason. Return all-ones     We ignore case in the names for the same reason. Return all-ones
    if there is not question section. */     if there is not question section. */
   #ifndef HAVE_DNSSEC
 unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)  unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
 {  {
   int q;    int q;
Line 407  unsigned int questions_crc(struct dns_header *header,  Line 382  unsigned int questions_crc(struct dns_header *header, 
   
   return crc;    return crc;
 }  }
   #endif
   
   
 size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)  size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
 {  {
   unsigned char *ansp = skip_questions(header, plen);    unsigned char *ansp = skip_questions(header, plen);
Line 433  size_t resize_packet(struct dns_header *header, size_t Line 408  size_t resize_packet(struct dns_header *header, size_t
   return ansp - (unsigned char *)header;    return ansp - (unsigned char *)header;
 }  }
   
 unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t  *len, unsigned char **p, int *is_sign)  
 {  
   /* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.   
      also return length of pseudoheader in *len and pointer to the UDP size in *p  
      Finally, check to see if a packet is signed. If it is we cannot change a single bit before  
      forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */  
     
   int i, arcount = ntohs(header->arcount);  
   unsigned char *ansp = (unsigned char *)(header+1);  
   unsigned short rdlen, type, class;  
   unsigned char *ret = NULL;  
   
   if (is_sign)  
     {  
       *is_sign = 0;  
   
       if (OPCODE(header) == QUERY)  
         {  
           for (i = ntohs(header->qdcount); i != 0; i--)  
             {  
               if (!(ansp = skip_name(ansp, header, plen, 4)))  
                 return NULL;  
                 
               GETSHORT(type, ansp);   
               GETSHORT(class, ansp);  
                 
               if (class == C_IN && type == T_TKEY)  
                 *is_sign = 1;  
             }  
         }  
     }  
   else  
     {  
       if (!(ansp = skip_questions(header, plen)))  
         return NULL;  
     }  
       
   if (arcount == 0)  
     return NULL;  
     
   if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))  
     return NULL;   
     
   for (i = 0; i < arcount; i++)  
     {  
       unsigned char *save, *start = ansp;  
       if (!(ansp = skip_name(ansp, header, plen, 10)))  
         return NULL;   
   
       GETSHORT(type, ansp);  
       save = ansp;  
       GETSHORT(class, ansp);  
       ansp += 4; /* TTL */  
       GETSHORT(rdlen, ansp);  
       if (!ADD_RDLEN(header, ansp, plen, rdlen))  
         return NULL;  
       if (type == T_OPT)  
         {  
           if (len)  
             *len = ansp - start;  
           if (p)  
             *p = save;  
           ret = start;  
         }  
       else if (is_sign &&   
                i == arcount - 1 &&   
                class == C_ANY &&   
                (type == T_SIG || type == T_TSIG))  
         *is_sign = 1;  
     }  
     
   return ret;  
 }  
   
 struct macparm {  
   unsigned char *limit;  
   struct dns_header *header;  
   size_t plen;  
   union mysockaddr *l3;  
 };  
   
 static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)  
 {  
   struct macparm *parm = parmv;  
   int match = 0;  
   unsigned short rdlen;  
   struct dns_header *header = parm->header;  
   unsigned char *lenp, *datap, *p;  
     
   if (family == parm->l3->sa.sa_family)  
     {  
       if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)  
         match = 1;  
 #ifdef HAVE_IPV6  
       else  
         if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)  
           match = 1;  
 #endif  
     }  
    
   if (!match)  
     return 1; /* continue */  
     
   if (ntohs(header->arcount) == 0)  
     {  
       /* We are adding the pseudoheader */  
       if (!(p = skip_questions(header, parm->plen)) ||  
           !(p = skip_section(p,   
                              ntohs(header->ancount) + ntohs(header->nscount),   
                              header, parm->plen)))  
         return 0;  
       *p++ = 0; /* empty name */  
       PUTSHORT(T_OPT, p);  
       PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */  
       PUTLONG(0, p);    /* extended RCODE */  
       lenp = p;  
       PUTSHORT(0, p);    /* RDLEN */  
       rdlen = 0;  
       if (((ssize_t)maclen) > (parm->limit - (p + 4)))  
         return 0; /* Too big */  
       header->arcount = htons(1);  
       datap = p;  
     }  
   else  
     {  
       int i, is_sign;  
       unsigned short code, len;  
         
       if (ntohs(header->arcount) != 1 ||  
           !(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) ||  
           is_sign ||  
           (!(p = skip_name(p, header, parm->plen, 10))))  
         return 0;  
         
       p += 8; /* skip UDP length and RCODE */  
         
       lenp = p;  
       GETSHORT(rdlen, p);  
       if (!CHECK_LEN(header, p, parm->plen, rdlen))  
         return 0; /* bad packet */  
       datap = p;  
   
       /* check if option already there */  
       for (i = 0; i + 4 < rdlen; i += len + 4)  
         {  
           GETSHORT(code, p);  
           GETSHORT(len, p);  
           if (code == EDNS0_OPTION_MAC)  
             return 0;  
           p += len;  
         }  
         
       if (((ssize_t)maclen) > (parm->limit - (p + 4)))  
         return 0; /* Too big */  
     }  
     
   PUTSHORT(EDNS0_OPTION_MAC, p);  
   PUTSHORT(maclen, p);  
   memcpy(p, mac, maclen);  
   p += maclen;    
   
   PUTSHORT(p - datap, lenp);  
   parm->plen = p - (unsigned char *)header;  
     
   return 0; /* done */  
 }               
        
   
 size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)  
 {  
   struct macparm parm;  
        
 /* Must have an existing pseudoheader as the only ar-record,   
    or have no ar-records. Must also not be signed */  
      
   if (ntohs(header->arcount) > 1)  
     return plen;  
   
   parm.header = header;  
   parm.limit = (unsigned char *)limit;  
   parm.plen = plen;  
   parm.l3 = l3;  
   
   iface_enumerate(AF_UNSPEC, &parm, filter_mac);  
     
   return parm.plen;   
 }  
   
       
 /* is addr in the non-globally-routed IP space? */   /* is addr in the non-globally-routed IP space? */ 
static int private_net(struct in_addr addr, int ban_localhost) int private_net(struct in_addr addr, int ban_localhost) 
 {  {
   in_addr_t ip_addr = ntohl(addr.s_addr);    in_addr_t ip_addr = ntohl(addr.s_addr);
   
   return    return
    (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ ||     (((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost)  /* 127.0.0.0/8    (loopback) */ ||
    ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||    ((ip_addr & 0xFF000000) == 0x00000000)  /* RFC 5735 section 3. "here" network */ ||
     ((ip_addr & 0xFF000000) == 0x0A000000)  /* 10.0.0.0/8     (private)  */ ||      ((ip_addr & 0xFF000000) == 0x0A000000)  /* 10.0.0.0/8     (private)  */ ||
     ((ip_addr & 0xFFF00000) == 0xAC100000)  /* 172.16.0.0/12  (private)  */ ||      ((ip_addr & 0xFFF00000) == 0xAC100000)  /* 172.16.0.0/12  (private)  */ ||
    ((ip_addr & 0xFFFF0000) == 0xA9FE0000)  /* 169.254.0.0/16 (zeroconf) */ ;    ((ip_addr & 0xFFFF0000) == 0xC0A80000)  /* 192.168.0.0/16 (private)  */ ||
     ((ip_addr & 0xFFFF0000) == 0xA9FE0000)  /* 169.254.0.0/16 (zeroconf) */ ||
     ((ip_addr & 0xFFFFFF00) == 0xC0000200)  /* 192.0.2.0/24   (test-net) */ ||
     ((ip_addr & 0xFFFFFF00) == 0xC6336400)  /* 198.51.100.0/24(test-net) */ ||
     ((ip_addr & 0xFFFFFF00) == 0xCB007100)  /* 203.0.113.0/24 (test-net) */ ||
     ((ip_addr & 0xFFFFFFFF) == 0xFFFFFFFF)  /* 255.255.255.255/32 (broadcast)*/ ;
 }  }
   
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name, int *doctored)
 {  {
   int i, qtype, qclass, rdlen;    int i, qtype, qclass, rdlen;
   
Line 680  static unsigned char *do_doctor(unsigned char *p, int  Line 471  static unsigned char *do_doctor(unsigned char *p, int 
               addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);                addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
               /* Since we munged the data, the server it came from is no longer authoritative */                /* Since we munged the data, the server it came from is no longer authoritative */
               header->hb3 &= ~HB3_AA;                header->hb3 &= ~HB3_AA;
                 *doctored = 1;
               memcpy(p, &addr, INADDRSZ);                memcpy(p, &addr, INADDRSZ);
               break;                break;
             }              }
Line 718  static unsigned char *do_doctor(unsigned char *p, int  Line 510  static unsigned char *do_doctor(unsigned char *p, int 
   return p;     return p; 
 }  }
   
static int find_soa(struct dns_header *header, size_t qlen, char *name)static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doctored)
 {  {
   unsigned char *p;    unsigned char *p;
   int qtype, qclass, rdlen;    int qtype, qclass, rdlen;
Line 727  static int find_soa(struct dns_header *header, size_t  Line 519  static int find_soa(struct dns_header *header, size_t 
       
   /* first move to NS section and find TTL from any SOA section */    /* first move to NS section and find TTL from any SOA section */
   if (!(p = skip_questions(header, qlen)) ||    if (!(p = skip_questions(header, qlen)) ||
      !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name)))      !(p = do_doctor(p, ntohs(header->ancount), header, qlen, name, doctored)))
     return 0;  /* bad packet */      return 0;  /* bad packet */
       
   for (i = ntohs(header->nscount); i != 0; i--)    for (i = ntohs(header->nscount); i != 0; i--)
Line 762  static int find_soa(struct dns_header *header, size_t  Line 554  static int find_soa(struct dns_header *header, size_t 
         return 0; /* bad packet */          return 0; /* bad packet */
     }      }
       
  /* rewrite addresses in additioal section too */  /* rewrite addresses in additional section too */
  if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL))  if (!do_doctor(p, ntohs(header->arcount), header, qlen, NULL, doctored))
     return 0;      return 0;
       
   if (!found_soa)    if (!found_soa)
Line 777  static int find_soa(struct dns_header *header, size_t  Line 569  static int find_soa(struct dns_header *header, size_t 
    expired and cleaned out that way.      expired and cleaned out that way. 
    Return 1 if we reject an address because it look like part of dns-rebinding attack. */     Return 1 if we reject an address because it look like part of dns-rebinding attack. */
 int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,   int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now, 
                      char **ipsets, int is_sign, int check_rebind, int checking_disabled)                      char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
 {  {
   unsigned char *p, *p1, *endrr, *namep;    unsigned char *p, *p1, *endrr, *namep;
   int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;    int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
Line 792  int extract_addresses(struct dns_header *header, size_ Line 584  int extract_addresses(struct dns_header *header, size_
   cache_start_insert();    cache_start_insert();
   
   /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */    /* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
  if (daemon->doctors || option_bool(OPT_LOG))  if (daemon->doctors || option_bool(OPT_LOG) || option_bool(OPT_DNSSEC_VALID))
     {      {
       searched_soa = 1;        searched_soa = 1;
      ttl = find_soa(header, qlen, name);      ttl = find_soa(header, qlen, name, doctored);
 #ifdef HAVE_DNSSEC
       if (*doctored && secure)
         return 0;
 #endif
     }      }
       
   /* go through the questions. */    /* go through the questions. */
Line 803  int extract_addresses(struct dns_header *header, size_ Line 599  int extract_addresses(struct dns_header *header, size_
       
   for (i = ntohs(header->qdcount); i != 0; i--)    for (i = ntohs(header->qdcount); i != 0; i--)
     {      {
      int found = 0, cname_count = 5;      int found = 0, cname_count = CNAME_CHAIN;
       struct crec *cpp = NULL;        struct crec *cpp = NULL;
       int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;        int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
         int secflag = secure ?  F_DNSSECOK : 0;
       unsigned long cttl = ULONG_MAX, attl;        unsigned long cttl = ULONG_MAX, attl;
      
       namep = p;        namep = p;
       if (!extract_name(header, qlen, &p, name, 1, 4))        if (!extract_name(header, qlen, &p, name, 1, 4))
         return 0; /* bad packet */          return 0; /* bad packet */
Line 863  int extract_addresses(struct dns_header *header, size_ Line 660  int extract_addresses(struct dns_header *header, size_
                                               
                       if (aqtype == T_CNAME)                        if (aqtype == T_CNAME)
                         {                          {
                          if (!cname_count--)                          if (!cname_count-- || secure)
                            return 0; /* looped CNAMES */                            return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
                           goto cname_loop;                            goto cname_loop;
                         }                          }
                                               
                      cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);                      cache_insert(name, &addr, now, cttl, name_encoding | secflag | F_REVERSE);
                       found = 1;                         found = 1; 
                     }                      }
                                       
Line 883  int extract_addresses(struct dns_header *header, size_ Line 680  int extract_addresses(struct dns_header *header, size_
               if (!searched_soa)                if (!searched_soa)
                 {                  {
                   searched_soa = 1;                    searched_soa = 1;
                  ttl = find_soa(header, qlen, NULL);                  ttl = find_soa(header, qlen, NULL, doctored);
                 }                  }
               if (ttl)                if (ttl)
                cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);                      cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);     
             }              }
         }          }
       else        else
Line 910  int extract_addresses(struct dns_header *header, size_ Line 707  int extract_addresses(struct dns_header *header, size_
           else             else 
             continue;              continue;
                           
          if (!(flags & F_NXDOMAIN))        cname_loop1:
           if (!(p1 = skip_questions(header, qlen)))
             return 0;
           
           for (j = ntohs(header->ancount); j != 0; j--) 
             {              {
            cname_loop1:              if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
              if (!(p1 = skip_questions(header, qlen)))                return 0; /* bad packet */
                return 0; 
                               
              for (j = ntohs(header->ancount); j != 0; j--)               GETSHORT(aqtype, p1); 
               GETSHORT(aqclass, p1);
               GETLONG(attl, p1);
               if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
                 {                  {
                  if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))                  (p1) -= 4;
                    return 0; /* bad packet */                  PUTLONG(daemon->max_ttl, p1);
                                  }
                  GETSHORT(aqtype, p1);               GETSHORT(ardlen, p1);
                  GETSHORT(aqclass, p1);              endrr = p1+ardlen;
                  GETLONG(attl, p1);              
                  if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)              if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
                 {
                   if (aqtype == T_CNAME)
                     {                      {
                      (p1) -= 4;                      if (!cname_count--)
                      PUTLONG(daemon->max_ttl, p1);                        return 0; /* looped CNAMES */
                    }                      newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD | secflag);
                  GETSHORT(ardlen, p1);                      if (newc)
                  endrr = p1+ardlen; 
                   
                  if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype)) 
                    { 
                      if (aqtype == T_CNAME) 
                         {                          {
                          if (!cname_count--)                          newc->addr.cname.target.cache = NULL;
                            return 0; /* looped CNAMES */                          /* anything other than zero, to avoid being mistaken for CNAME to interface-name */ 
                          newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);                          newc->addr.cname.uid = 1
                          if (newc)                          if (cpp)
                             {                              {
                              newc->addr.cname.cache = NULL;                              cpp->addr.cname.target.cache = newc;
                              if (cpp)                              cpp->addr.cname.uid = newc->uid;
                                { 
                                  cpp->addr.cname.cache = newc; 
                                  cpp->addr.cname.uid = newc->uid; 
                                } 
                             }                              }
   
                           cpp = newc;  
                           if (attl < cttl)  
                             cttl = attl;  
                             
                           if (!extract_name(header, qlen, &p1, name, 1, 0))  
                             return 0;  
                           goto cname_loop1;  
                         }                          }
                      else                      
                       cpp = newc;
                       if (attl < cttl)
                         cttl = attl;
                       
                       if (!extract_name(header, qlen, &p1, name, 1, 0))
                         return 0;
                       goto cname_loop1;
                     }
                   else if (!(flags & F_NXDOMAIN))
                     {
                       found = 1;
                       
                       /* copy address into aligned storage */
                       if (!CHECK_LEN(header, p1, qlen, addrlen))
                         return 0; /* bad packet */
                       memcpy(&addr, p1, addrlen);
                       
                       /* check for returned address in private space */
                       if (check_rebind)
                         {                          {
                          found = 1;                          if ((flags & F_IPV4) &&
                           
                          /* copy address into aligned storage */ 
                          if (!CHECK_LEN(header, p1, qlen, addrlen)) 
                            return 0; /* bad packet */ 
                          memcpy(&addr, p1, addrlen); 
                           
                          /* check for returned address in private space */ 
                          if (check_rebind && 
                              (flags & F_IPV4) && 
                               private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))                                private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
                             return 1;                              return 1;
                          
#ifdef HAVE_IPSET#ifdef HAVE_IPV6
                          if (ipsets && (flags & (F_IPV4 | F_IPV6)))                          if ((flags & F_IPV6) &&
                               IN6_IS_ADDR_V4MAPPED(&addr.addr.addr6))
                             {                              {
                              ipsets_cur = ipsets;                              struct in_addr v4;
                              while (*ipsets_cur)                              v4.s_addr = ((const uint32_t *) (&addr.addr.addr6))[3];
                                add_to_ipset(*ipsets_cur++, &addr, flags, 0);                              if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
                                 return 1;
                             }                              }
 #endif  #endif
                                                  }
                          newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);                      
                          if (newc && cpp)#ifdef HAVE_IPSET
                       if (ipsets && (flags & (F_IPV4 | F_IPV6)))
                         {
                           ipsets_cur = ipsets;
                           while (*ipsets_cur)
                             {                              {
                              cpp->addr.cname.cache = newc;                              log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
                              cpp->addr.cname.uid = newc->uid;                              add_to_ipset(*ipsets_cur++, &addr, flags, 0);
                             }                              }
                           cpp = NULL;  
                         }                          }
   #endif
                         
                         newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
                         if (newc && cpp)
                           {
                             cpp->addr.cname.target.cache = newc;
                             cpp->addr.cname.uid = newc->uid;
                           }
                         cpp = NULL;
                     }                      }
                     
                   p1 = endrr;  
                   if (!CHECK_LEN(header, p1, qlen, 0))  
                     return 0; /* bad packet */  
                 }                  }
                 
                 p1 = endrr;
                 if (!CHECK_LEN(header, p1, qlen, 0))
                   return 0; /* bad packet */
             }              }
                       
           if (!found && !option_bool(OPT_NO_NEG))            if (!found && !option_bool(OPT_NO_NEG))
Line 1002  int extract_addresses(struct dns_header *header, size_ Line 814  int extract_addresses(struct dns_header *header, size_
               if (!searched_soa)                if (!searched_soa)
                 {                  {
                   searched_soa = 1;                    searched_soa = 1;
                  ttl = find_soa(header, qlen, NULL);                  ttl = find_soa(header, qlen, NULL, doctored);
                 }                  }
               /* If there's no SOA to get the TTL from, but there is a CNAME                 /* If there's no SOA to get the TTL from, but there is a CNAME 
                  pointing at this, inherit its TTL */                   pointing at this, inherit its TTL */
               if (ttl || cpp)                if (ttl || cpp)
                 {                  {
                  newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);                        newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);     
                   if (newc && cpp)                    if (newc && cpp)
                     {                      {
                      cpp->addr.cname.cache = newc;                      cpp->addr.cname.target.cache = newc;
                       cpp->addr.cname.uid = newc->uid;                        cpp->addr.cname.uid = newc->uid;
                     }                      }
                 }                  }
Line 1020  int extract_addresses(struct dns_header *header, size_ Line 832  int extract_addresses(struct dns_header *header, size_
     }      }
       
   /* Don't put stuff from a truncated packet into the cache.    /* Don't put stuff from a truncated packet into the cache.
      Don't cache replies where DNSSEC validation was turned off, either  
      the upstream server told us so, or the original query specified it.   
      Don't cache replies from non-recursive nameservers, since we may get a        Don't cache replies from non-recursive nameservers, since we may get a 
      reply containing a CNAME but not its target, even though the target        reply containing a CNAME but not its target, even though the target 
      does exist. */       does exist. */
   if (!(header->hb3 & HB3_TC) &&     if (!(header->hb3 & HB3_TC) && 
       !(header->hb4 & HB4_CD) &&        !(header->hb4 & HB4_CD) &&
       (header->hb4 & HB4_RA) &&        (header->hb4 & HB4_RA) &&
      !checking_disabled)      !no_cache_dnssec)
     cache_end_insert();      cache_end_insert();
   
   return 0;    return 0;
Line 1036  int extract_addresses(struct dns_header *header, size_ Line 846  int extract_addresses(struct dns_header *header, size_
   
 /* If the packet holds exactly one query  /* If the packet holds exactly one query
    return F_IPV4 or F_IPV6  and leave the name from the query in name */     return F_IPV4 or F_IPV6  and leave the name from the query in name */
   
 unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)  unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
 {  {
   unsigned char *p = (unsigned char *)(header+1);    unsigned char *p = (unsigned char *)(header+1);
Line 1074  unsigned int extract_request(struct dns_header *header Line 883  unsigned int extract_request(struct dns_header *header
 size_t setup_reply(struct dns_header *header, size_t qlen,  size_t setup_reply(struct dns_header *header, size_t qlen,
                 struct all_addr *addrp, unsigned int flags, unsigned long ttl)                  struct all_addr *addrp, unsigned int flags, unsigned long ttl)
 {  {
  unsigned char *p = skip_questions(header, qlen);  unsigned char *p;
 
   if (!(p = skip_questions(header, qlen)))
     return 0;
       
   /* clear authoritative and truncated flags, set QR flag */    /* clear authoritative and truncated flags, set QR flag */
   header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;    header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
Line 1084  size_t setup_reply(struct dns_header *header, size_t q Line 896  size_t setup_reply(struct dns_header *header, size_t q
   header->nscount = htons(0);    header->nscount = htons(0);
   header->arcount = htons(0);    header->arcount = htons(0);
   header->ancount = htons(0); /* no answers unless changed below */    header->ancount = htons(0); /* no answers unless changed below */
  if (flags == F_NEG)  if (flags == F_NOERR)
    SET_RCODE(header, SERVFAIL); /* couldn't get memory */ 
  else if (flags == F_NOERR) 
     SET_RCODE(header, NOERROR); /* empty domain */      SET_RCODE(header, NOERROR); /* empty domain */
   else if (flags == F_NXDOMAIN)    else if (flags == F_NXDOMAIN)
     SET_RCODE(header, NXDOMAIN);      SET_RCODE(header, NXDOMAIN);
  else if (p && flags == F_IPV4)  else if (flags == F_IPV4)
     { /* we know the address */      { /* we know the address */
       SET_RCODE(header, NOERROR);        SET_RCODE(header, NOERROR);
       header->ancount = htons(1);        header->ancount = htons(1);
Line 1098  size_t setup_reply(struct dns_header *header, size_t q Line 908  size_t setup_reply(struct dns_header *header, size_t q
       add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);        add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
     }      }
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
  else if (p && flags == F_IPV6)  else if (flags == F_IPV6)
     {      {
       SET_RCODE(header, NOERROR);        SET_RCODE(header, NOERROR);
       header->ancount = htons(1);        header->ancount = htons(1);
Line 1122  int check_for_local_domain(char *name, time_t now) Line 932  int check_for_local_domain(char *name, time_t now)
   struct ptr_record *ptr;    struct ptr_record *ptr;
   struct naptr *naptr;    struct naptr *naptr;
   
  if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&  /* Note: the call to cache_find_by_name is intended to find any record which matches
      (crecp->flags & (F_HOSTS | F_DHCP)))     ie A, AAAA, CNAME. */
 
   if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
       (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
     return 1;      return 1;
       
   for (naptr = daemon->naptr; naptr; naptr = naptr->next)    for (naptr = daemon->naptr; naptr; naptr = naptr->next)
Line 1185  int check_for_bogus_wildcard(struct dns_header *header Line 998  int check_for_bogus_wildcard(struct dns_header *header
                 /* Found a bogus address. Insert that info here, since there no SOA record                  /* Found a bogus address. Insert that info here, since there no SOA record
                    to get the ttl from in the normal processing */                     to get the ttl from in the normal processing */
                 cache_start_insert();                  cache_start_insert();
                cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);                cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
                 cache_end_insert();                  cache_end_insert();
                                   
                 return 1;                  return 1;
Line 1199  int check_for_bogus_wildcard(struct dns_header *header Line 1012  int check_for_bogus_wildcard(struct dns_header *header
   return 0;    return 0;
 }  }
   
   int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
   {
     unsigned char *p;
     int i, qtype, qclass, rdlen;
     struct bogus_addr *baddrp;
   
     /* skip over questions */
     if (!(p = skip_questions(header, qlen)))
       return 0; /* bad packet */
   
     for (i = ntohs(header->ancount); i != 0; i--)
       {
         if (!(p = skip_name(p, header, qlen, 10)))
           return 0; /* bad packet */
         
         GETSHORT(qtype, p); 
         GETSHORT(qclass, p);
         p += 4; /* TTL */
         GETSHORT(rdlen, p);
         
         if (qclass == C_IN && qtype == T_A)
           {
             if (!CHECK_LEN(header, p, qlen, INADDRSZ))
               return 0;
             
             for (baddrp = baddr; baddrp; baddrp = baddrp->next)
               if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
                 return 1;
           }
         
         if (!ADD_RDLEN(header, p, qlen, rdlen))
           return 0;
       }
     
     return 0;
   }
   
 int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,   int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp, 
                         unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)                          unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
 {  {
Line 1255  int add_resource_record(struct dns_header *header, cha Line 1105  int add_resource_record(struct dns_header *header, cha
         p += INADDRSZ;          p += INADDRSZ;
         break;          break;
                   
         case 'b':
           usval = va_arg(ap, int);
           *p++ = usval;
           break;
           
       case 's':        case 's':
         usval = va_arg(ap, int);          usval = va_arg(ap, int);
         PUTSHORT(usval, p);          PUTSHORT(usval, p);
Line 1312  int add_resource_record(struct dns_header *header, cha Line 1167  int add_resource_record(struct dns_header *header, cha
 static unsigned long crec_ttl(struct crec *crecp, time_t now)  static unsigned long crec_ttl(struct crec *crecp, time_t now)
 {  {
   /* Return 0 ttl for DHCP entries, which might change    /* Return 0 ttl for DHCP entries, which might change
     before the lease expires. */     before the lease expires, unless configured otherwise. */
   
  if  (crecp->flags & (F_IMMORTAL | F_DHCP))  if (crecp->flags & F_DHCP)
    return daemon->local_ttl;    {
       int conf_ttl = daemon->use_dhcp_ttl ? daemon->dhcp_ttl : daemon->local_ttl;
       
       /* Apply ceiling of actual lease length to configured TTL. */
       if (!(crecp->flags & F_IMMORTAL) && (crecp->ttd - now) < conf_ttl)
         return crecp->ttd - now;
       
       return conf_ttl;
     }     
       
     /* Immortal entries other than DHCP are local, and hold TTL in TTD field. */
     if (crecp->flags & F_IMMORTAL)
       return crecp->ttd;
   
   /* Return the Max TTL value if it is lower then the actual TTL */    /* Return the Max TTL value if it is lower then the actual TTL */
   if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))    if (daemon->max_ttl == 0 || ((unsigned)(crecp->ttd - now) < daemon->max_ttl))
     return crecp->ttd - now;      return crecp->ttd - now;
Line 1327  static unsigned long crec_ttl(struct crec *crecp, time Line 1194  static unsigned long crec_ttl(struct crec *crecp, time
   
 /* return zero if we can't answer from cache, or packet size if we can */  /* return zero if we can't answer from cache, or packet size if we can */
 size_t answer_request(struct dns_header *header, char *limit, size_t qlen,    size_t answer_request(struct dns_header *header, char *limit, size_t qlen,  
                      struct in_addr local_addr, struct in_addr local_netmask, time_t now                      struct in_addr local_addr, struct in_addr local_netmask, 
                       time_t now, int ad_reqd, int do_bit, int have_pseudoheader) 
 {  {
   char *name = daemon->namebuff;    char *name = daemon->namebuff;
  unsigned char *p, *ansp, *pheader;  unsigned char *p, *ansp;
  int qtype, qclass;  unsigned int qtype, qclass;
   struct all_addr addr;    struct all_addr addr;
   int nameoffset;    int nameoffset;
   unsigned short flag;    unsigned short flag;
   int q, ans, anscount = 0, addncount = 0;    int q, ans, anscount = 0, addncount = 0;
  int dryrun = 0, sec_reqd = 0;  int dryrun = 0;
  int is_sign; 
   struct crec *crecp;    struct crec *crecp;
  int nxdomain = 0, auth = 1, trunc = 0;  int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
   struct mx_srv_record *rec;    struct mx_srv_record *rec;
   size_t len;
  /* If there is an RFC2671 pseudoheader then it will be overwritten by  
     partial replies, so we have to do a dry run to see if we can answer  if (ntohs(header->ancount) != 0 ||
     the query. We check to see if the do bit is set, if so we always      ntohs(header->nscount) != 0 ||
     forward rather than answering from the cache, which doesn't include      ntohs(header->qdcount) == 0 || 
     security information. */      OPCODE(header) != QUERY )
 
  if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign)) 
    {  
      unsigned short udpsz, flags; 
      unsigned char *psave = pheader; 
 
      GETSHORT(udpsz, pheader); 
      pheader += 2; /* ext_rcode */ 
      GETSHORT(flags, pheader); 
       
      sec_reqd = flags & 0x8000; /* do bit */  
 
      /* If our client is advertising a larger UDP packet size 
         than we allow, trim it so that we don't get an overlarge 
         response from upstream */ 
 
      if (!is_sign && (udpsz > daemon->edns_pktsz)) 
        PUTSHORT(daemon->edns_pktsz, psave);  
 
      dryrun = 1; 
    } 
 
  if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) 
     return 0;      return 0;
       
     /* Don't return AD set if checking disabled. */
     if (header->hb4 & HB4_CD)
       sec_data = 0;
     
     /* If there is an  additional data section then it will be overwritten by
        partial replies, so we have to do a dry run to see if we can answer
        the query. */
     if (ntohs(header->arcount) != 0)
       dryrun = 1;
   
   for (rec = daemon->mxnames; rec; rec = rec->next)    for (rec = daemon->mxnames; rec; rec = rec->next)
     rec->offset = 0;      rec->offset = 0;
       
Line 1407  size_t answer_request(struct dns_header *header, char  Line 1261  size_t answer_request(struct dns_header *header, char 
                   ans = 1;                    ans = 1;
                   if (!dryrun)                    if (!dryrun)
                     {                      {
                         unsigned long ttl = daemon->local_ttl;
                         int ok = 1;
                       log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");                        log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
                      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                       /* Dynamically generate stat record */
                                              daemon->local_ttl, NULL,                      if (t->stat != 0)
                                              T_TXT, t->class, "t", t->len, t->txt))                        {
                           ttl = 0;
                           if (!cache_make_stat(t))
                             ok = 0;
                         }
                       
                       if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                                     ttl, NULL,
                                                     T_TXT, t->class, "t", t->len, t->txt))
                         anscount++;                          anscount++;
   
                     }                      }
Line 1426  size_t answer_request(struct dns_header *header, char  Line 1290  size_t answer_request(struct dns_header *header, char 
             if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))              if ((t->class == qtype || qtype == T_ANY) && hostname_isequal(name, t->name))
               {                {
                 ans = 1;                  ans = 1;
                   sec_data = 0;
                 if (!dryrun)                  if (!dryrun)
                   {                    {
                     log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");                      log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
Line 1450  size_t answer_request(struct dns_header *header, char  Line 1315  size_t answer_request(struct dns_header *header, char 
               if (is_arpa == F_IPV4)                if (is_arpa == F_IPV4)
                 for (intr = daemon->int_names; intr; intr = intr->next)                  for (intr = daemon->int_names; intr; intr = intr->next)
                   {                    {
                    if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)                    struct addrlist *addrlist;
                     
                     for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
                       if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
                         break;
                     
                     if (addrlist)
                       break;                        break;
                     else                      else
                       while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)                        while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
                         intr = intr->next;                          intr = intr->next;
                   }                    }
   #ifdef HAVE_IPV6
                 else if (is_arpa == F_IPV6)
                   for (intr = daemon->int_names; intr; intr = intr->next)
                     {
                       struct addrlist *addrlist;
                       
                       for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
                         if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
                           break;
                       
                       if (addrlist)
                         break;
                       else
                         while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
                           intr = intr->next;
                     }
   #endif
                               
               if (intr)                if (intr)
                 {                  {
                     sec_data = 0;
                   ans = 1;                    ans = 1;
                   if (!dryrun)                    if (!dryrun)
                     {                      {
                      log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);                      log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
                       if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                         if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                               daemon->local_ttl, NULL,                                                daemon->local_ttl, NULL,
                                               T_PTR, C_IN, "d", intr->name))                                                T_PTR, C_IN, "d", intr->name))
Line 1472  size_t answer_request(struct dns_header *header, char  Line 1361  size_t answer_request(struct dns_header *header, char 
               else if (ptr)                else if (ptr)
                 {                  {
                   ans = 1;                    ans = 1;
                     sec_data = 0;
                   if (!dryrun)                    if (!dryrun)
                     {                      {
                       log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");                        log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
Line 1485  size_t answer_request(struct dns_header *header, char  Line 1375  size_t answer_request(struct dns_header *header, char 
                     }                      }
                 }                  }
               else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))                else if ((crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
                do                 {
                  {                   /* Don't use cache when DNSSEC data required, unless we know that
                    /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */                     the zone is unsigned, which implies that we're doing
                    if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))                     validation. */
                      continue;                  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || 
                                          !do_bit || 
                    if (crecp->flags & F_NEG)                      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
                      {                    {
                        ans = 1;                      do 
                        auth = 0;                        { 
                        if (crecp->flags & F_NXDOMAIN)                          /* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
                          nxdomain = 1;                          if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
                        if (!dryrun)                            continue;
                          log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);                          
                      }                          if (!(crecp->flags & F_DNSSECOK))
                    else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)                            sec_data = 0;
                      {                           
                        ans = 1;                          ans = 1;
                        if (!(crecp->flags & (F_HOSTS | F_DHCP)))                           
                          auth = 0;                          if (crecp->flags & F_NEG)
                        if (!dryrun)                            {
                          {                              auth = 0;
                            log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,                               if (crecp->flags & F_NXDOMAIN)
                                      record_source(crecp->uid));                                nxdomain = 1;
                                                          if (!dryrun)
                            if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                                 log_query(crecp->flags & ~F_FORWARD, name, &addr, NULL);
                                                    crec_ttl(crecp, now), NULL,                            }
                                                    T_PTR, C_IN, "d", cache_get_name(crecp)))                          else
                             {
                               if (!(crecp->flags & (F_HOSTS | F_DHCP)))
                                 auth = 0;
                               if (!dryrun)
                                 {
                                   log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr, 
                                             record_source(crecp->uid));
                                   
                                   if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                                           crec_ttl(crecp, now), NULL,
                                                           T_PTR, C_IN, "d", cache_get_name(crecp)))
                                     anscount++;
                                 }
                             }
                         } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
                     }
                 }
               else if (is_rev_synth(is_arpa, &addr, name))
                 {
                   ans = 1;
                   sec_data = 0;
                   if (!dryrun)
                     {
                       log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL); 
                       
                       if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                               daemon->local_ttl, NULL,
                                               T_PTR, C_IN, "d", name))
                               anscount++;                                anscount++;
                          }                    }
                      }                }
                  } while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa))); 
               else if (is_arpa == F_IPV4 &&                 else if (is_arpa == F_IPV4 && 
                        option_bool(OPT_BOGUSPRIV) &&                          option_bool(OPT_BOGUSPRIV) && 
                        private_net(addr.addr.addr4, 1))                         private_net(addr.addr.addr4, 1))
                 {                  {
                   /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */                    /* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
                   ans = 1;                    ans = 1;
                     sec_data = 0;
                   nxdomain = 1;                    nxdomain = 1;
                   if (!dryrun)                    if (!dryrun)
                     log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN,                       log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, 
Line 1533  size_t answer_request(struct dns_header *header, char  Line 1451  size_t answer_request(struct dns_header *header, char 
           for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)            for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
             {              {
               unsigned short type = T_A;                unsigned short type = T_A;
                            struct interface_name *intr;
 
               if (flag == F_IPV6)                if (flag == F_IPV6)
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
                 type = T_AAAA;                  type = T_AAAA;
Line 1569  size_t answer_request(struct dns_header *header, char  Line 1488  size_t answer_request(struct dns_header *header, char 
                   if (i == 4)                    if (i == 4)
                     {                      {
                       ans = 1;                        ans = 1;
                         sec_data = 0;
                       if (!dryrun)                        if (!dryrun)
                         {                          {
                           addr.addr.addr4.s_addr = htonl(a);                            addr.addr.addr4.s_addr = htonl(a);
Line 1582  size_t answer_request(struct dns_header *header, char  Line 1502  size_t answer_request(struct dns_header *header, char 
                 }                  }
   
               /* interface name stuff */                /* interface name stuff */
              if (qtype == T_A)            intname_restart:
               for (intr = daemon->int_names; intr; intr = intr->next)
                 if (hostname_isequal(name, intr->name))
                   break;
               
               if (intr)
                 {                  {
                  struct interface_name *intr;                  struct addrlist *addrlist;
                   int gotit = 0;
   
                     enumerate_interfaces(0);
                     
                   for (intr = daemon->int_names; intr; intr = intr->next)                    for (intr = daemon->int_names; intr; intr = intr->next)
                     if (hostname_isequal(name, intr->name))                      if (hostname_isequal(name, intr->name))
                      break;                      {
                                          for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
                  if (intr)#ifdef HAVE_IPV6
                    {                          if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
                      ans = 1;#endif
                      if (!dryrun) 
                        { 
                          if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1) 
                            log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL); 
                          else 
                             {                              {
                              log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);#ifdef HAVE_IPV6
                              if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                               if (addrlist->flags & ADDRLIST_REVONLY)
                                                      daemon->local_ttl, NULL, type, C_IN, "4", &addr))                                continue;
                                anscount++;#endif  
                               ans = 1;  
                               sec_data = 0;
                               if (!dryrun)
                                 {
                                   gotit = 1;
                                   log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
                                   if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                                           daemon->local_ttl, NULL, type, C_IN, 
                                                           type == T_A ? "4" : "6", &addrlist->addr))
                                     anscount++;
                                 }
                             }                              }
                        }                      }
                      continue;                  
                    }                  if (!dryrun && !gotit)
                     log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
                      
                   continue;
                 }                  }
   
             cname_restart:              cname_restart:
              if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))              if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
                 {                  {
                   int localise = 0;                    int localise = 0;
                                       
Line 1629  size_t answer_request(struct dns_header *header, char  Line 1566  size_t answer_request(struct dns_header *header, char 
                         } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));                          } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
                       crecp = save;                        crecp = save;
                     }                      }
                          
                  do                  /* If the client asked for DNSSEC  don't use cached data. */
                    {                   if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
                      /* don't answer wildcard queries with data not from /etc/hosts                    do
                         or DHCP leases */                      { 
                      if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))                        /* don't answer wildcard queries with data not from /etc/hosts
                        break;                           or DHCP leases */
                                              if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
                      if (crecp->flags & F_CNAME)                          break;
                        {                        
                          if (!dryrun)                        if (!(crecp->flags & F_DNSSECOK))
                            {                          sec_data = 0;
                              log_query(crecp->flags, name, NULL, record_source(crecp->uid));                        
                              if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                         if (crecp->flags & F_CNAME)
                                                      crec_ttl(crecp, now), &nameoffset,                          {
                                                      T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))                            char *cname_target = cache_get_cname_target(crecp);
                                anscount++;                            
                            }                            if (!dryrun)
                                                        {
                          strcpy(name, cache_get_name(crecp->addr.cname.cache));                                log_query(crecp->flags, name, NULL, record_source(crecp->uid));
                          goto cname_restart;                                if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                        }                                                        crec_ttl(crecp, now), &nameoffset,
                                                                              T_CNAME, C_IN, "d", cname_target))
                      if (crecp->flags & F_NEG)                                  anscount++;
                        {                              }
                          ans = 1;                            
                          auth = 0;                            strcpy(name, cname_target);
                          if (crecp->flags & F_NXDOMAIN)                            /* check if target interface_name */
                            nxdomain = 1;                            if (crecp->addr.cname.uid == SRC_INTERFACE)
                          if (!dryrun)                              goto intname_restart;
                            log_query(crecp->flags, name, NULL, NULL);                            else
                        }                              goto cname_restart;
                      else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)                          }
                        {                        
                          /* If we are returning local answers depending on network,                        if (crecp->flags & F_NEG)
                             filter here. */                          {
                          if (localise &&                             ans = 1;
                              (crecp->flags & F_HOSTS) && 
                              !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask)) 
                            continue; 
        
                          if (!(crecp->flags & (F_HOSTS | F_DHCP))) 
                             auth = 0;                              auth = 0;
                                                      if (crecp->flags & F_NXDOMAIN)
                          ans = 1;                              nxdomain = 1;
                          if (!dryrun)                            if (!dryrun)
                            {                              log_query(crecp->flags, name, NULL, NULL);
                              log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,                          }
                                        record_source(crecp->uid));                        else 
                                                        {
                              if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                             /* If we are returning local answers depending on network,
                                                      crec_ttl(crecp, now), NULL, type, C_IN,                                filter here. */
                                                      type == T_A ? "4" : "6", &crecp->addr))                            if (localise && 
                                anscount++;                                (crecp->flags & F_HOSTS) &&
                            }                                !is_same_net(*((struct in_addr *)&crecp->addr), local_addr, local_netmask))
                        }                              continue;
                    } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));                            
                             if (!(crecp->flags & (F_HOSTS | F_DHCP)))
                               auth = 0;
                             
                             ans = 1;
                             if (!dryrun)
                               {
                                 log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
                                           record_source(crecp->uid));
                                 
                                 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                                         crec_ttl(crecp, now), NULL, type, C_IN, 
                                                         type == T_A ? "4" : "6", &crecp->addr))
                                   anscount++;
                               }
                           }
                       } while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
                 }                  }
                 else if (is_name_synthetic(flag, name, &addr))
                   {
                     ans = 1;
                     if (!dryrun)
                       {
                         log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
                         if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                                 daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
                           anscount++;
                       }
                   }
             }              }
   
           if (qtype == T_CNAME || qtype == T_ANY)            if (qtype == T_CNAME || qtype == T_ANY)
             {              {
               if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&                if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
                  (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP))))                  (qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG  | (dryrun ? F_NO_RR : 0)))))
                 {                  {
                     if (!(crecp->flags & F_DNSSECOK))
                       sec_data = 0;
                     
                   ans = 1;                    ans = 1;
                   if (!dryrun)                    if (!dryrun)
                     {                      {
                       log_query(crecp->flags, name, NULL, record_source(crecp->uid));                        log_query(crecp->flags, name, NULL, record_source(crecp->uid));
                       if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                         if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                               crec_ttl(crecp, now), &nameoffset,                                                crec_ttl(crecp, now), &nameoffset,
                                              T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))                                              T_CNAME, C_IN, "d", cache_get_cname_target(crecp)))
                         anscount++;                          anscount++;
                     }                      }
                 }                  }
             }              }
          
           if (qtype == T_MX || qtype == T_ANY)            if (qtype == T_MX || qtype == T_ANY)
             {              {
               int found = 0;                int found = 0;
Line 1728  size_t answer_request(struct dns_header *header, char  Line 1690  size_t answer_request(struct dns_header *header, char 
                   }                    }
                               
               if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&                 if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) && 
                  cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))                  cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
                 {                   { 
                   ans = 1;                    ans = 1;
                   if (!dryrun)                    if (!dryrun)
Line 1872  size_t answer_request(struct dns_header *header, char  Line 1834  size_t answer_request(struct dns_header *header, char 
   /* truncation */    /* truncation */
   if (trunc)    if (trunc)
     header->hb3 |= HB3_TC;      header->hb3 |= HB3_TC;
  
  if (anscount == 0 && nxdomain)  if (nxdomain)
     SET_RCODE(header, NXDOMAIN);      SET_RCODE(header, NXDOMAIN);
   else    else
     SET_RCODE(header, NOERROR); /* no error */      SET_RCODE(header, NOERROR); /* no error */
   header->ancount = htons(anscount);    header->ancount = htons(anscount);
   header->nscount = htons(0);    header->nscount = htons(0);
   header->arcount = htons(addncount);    header->arcount = htons(addncount);
   return ansp - (unsigned char *)header;  
 }  
   
     len = ansp - (unsigned char *)header;
     
     /* Advertise our packet size limit in our reply */
     if (have_pseudoheader)
       len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
     
     if (ad_reqd && sec_data)
       header->hb4 |= HB4_AD;
     else
       header->hb4 &= ~HB4_AD;
     
     return len;
   }

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


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