Diff for /embedaddon/dnsmasq/src/auth.c between versions 1.1.1.1 and 1.1.1.4

version 1.1.1.1, 2013/07/29 19:37:40 version 1.1.1.4, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley/* dnsmasq is Copyright (c) 2000-2021 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 18 Line 18
   
 #ifdef HAVE_AUTH  #ifdef HAVE_AUTH
   
static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u)
 {  {
  struct subnet *subnet;  do {
     if (!(list->flags & ADDRLIST_IPV6))
       {
         struct in_addr netmask, addr = addr_u->addr4;
         
         if (!(flag & F_IPV4))
           continue;
         
         netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
         
         if  (is_same_net(addr, list->addr.addr4, netmask))
           return list;
       }
     else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen))
       return list;
     
   } while ((list = list->next));
   
   return NULL;
 }
   
  for (subnet = zone->subnet; subnet; subnet = subnet->next)static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union all_addr *addr_u)
    {{
      if (subnet->is6 && (flag & F_IPV4))  if (!zone->subnet)
        continue;    return NULL;
   
   return find_addrlist(zone->subnet, flag, addr_u);
 }
   
      if (!subnet->is6)static struct addrlist *find_exclude(struct auth_zone *zone, int flag, union all_addr *addr_u)
        {{
          struct in_addr addr = addr_u->addr.addr4;  if (!zone->exclude)
          struct in_addr mask;    return NULL;
            
          mask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));  return find_addrlist(zone->exclude, flag, addr_u);
           
          if  (is_same_net(addr, subnet->addr4, mask)) 
            return subnet; 
        } 
#ifdef HAVE_IPV6 
      else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr6, subnet->prefixlen)) 
        return subnet; 
#endif 
 
    } 
  return NULL; 
 }  }
   
static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_addr *addr_u)static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u)
 {  {
#ifdef HAVE_DHCP6  if (find_exclude(zone, flag, addr_u))
  struct dhcp_context *context;    return 0;
   
  if (flag & F_IPV6)  /* No subnets specified, no filter */
    for (context = daemon->dhcp6; context; context = context->next)  if (!zone->subnet)
      if ((context->flags & CONTEXT_CONSTRUCTED) &&    return 1;
          is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix)) 
        return 1; 
#endif 
       
  return filter_zone(zone, flag, addr_u) != NULL;  return find_subnet(zone, flag, addr_u) != NULL;
 }  }
   
static int in_zone(struct auth_zone *zone, char *name, char **cut)int in_zone(struct auth_zone *zone, char *name, char **cut)
 {  {
   size_t namelen = strlen(name);    size_t namelen = strlen(name);
   size_t domainlen = strlen(zone->domain);    size_t domainlen = strlen(zone->domain);
Line 88  static int in_zone(struct auth_zone *zone, char *name, Line 96  static int in_zone(struct auth_zone *zone, char *name,
 }  }
   
   
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addrsize_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr
                    int local_query, int do_bit, int have_pseudoheader) 
 {  {
   char *name = daemon->namebuff;    char *name = daemon->namebuff;
   unsigned char *p, *ansp;    unsigned char *p, *ansp;
  int qtype, qclass;  int qtype, qclass, rc;
   int nameoffset, axfroffset = 0;    int nameoffset, axfroffset = 0;
   int q, anscount = 0, authcount = 0;    int q, anscount = 0, authcount = 0;
   struct crec *crecp;    struct crec *crecp;
  int  auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;  int  auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
   struct auth_zone *zone = NULL;    struct auth_zone *zone = NULL;
  struct subnet *subnet = NULL;  struct addrlist *subnet = NULL;
   char *cut;    char *cut;
   struct mx_srv_record *rec, *move, **up;    struct mx_srv_record *rec, *move, **up;
   struct txt_record *txt;    struct txt_record *txt;
   struct interface_name *intr;    struct interface_name *intr;
   struct naptr *na;    struct naptr *na;
  struct all_addr addr;  union all_addr addr;
  struct cname *a;  struct cname *a, *candidate;
   unsigned int wclen;
       
   if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )    if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
     return 0;      return 0;
  
   /* determine end of question section (we put answers there) */    /* determine end of question section (we put answers there) */
   if (!(ansp = skip_questions(header, qlen)))    if (!(ansp = skip_questions(header, qlen)))
     return 0; /* bad packet */      return 0; /* bad packet */
Line 119  size_t answer_auth(struct dns_header *header, char *li Line 129  size_t answer_auth(struct dns_header *header, char *li
   
   for (q = ntohs(header->qdcount); q != 0; q--)    for (q = ntohs(header->qdcount); q != 0; q--)
     {      {
      unsigned short flag = 0;      unsigned int flag = 0;
       int found = 0;        int found = 0;
         int cname_wildcard = 0;
       
       /* save pointer to name for copying into answers */        /* save pointer to name for copying into answers */
       nameoffset = p - (unsigned char *)header;        nameoffset = p - (unsigned char *)header;
Line 138  size_t answer_auth(struct dns_header *header, char *li Line 149  size_t answer_auth(struct dns_header *header, char *li
           continue;            continue;
         }          }
   
      if (qtype == T_PTR)      if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
           (flag = in_arpa_name_2_addr(name, &addr)) &&
           !local_query)
         {          {
           if (!(flag = in_arpa_name_2_addr(name, &addr)))  
             continue;  
   
           for (zone = daemon->auth_zones; zone; zone = zone->next)            for (zone = daemon->auth_zones; zone; zone = zone->next)
            if ((subnet = filter_zone(zone, flag, &addr)))            if ((subnet = find_subnet(zone, flag, &addr)))
               break;                break;
          
           if (!zone)            if (!zone)
             {              {
               auth = 0;                auth = 0;
               continue;                continue;
             }              }
                    else if (qtype == T_SOA)
             soa = 1, found = 1;
           else if (qtype == T_NS)
             ns = 1, found = 1;
         }
 
       if (qtype == T_PTR && flag)
         {
           intr = NULL;
 
           if (flag == F_IPV4)            if (flag == F_IPV4)
            {            for (intr = daemon->int_names; intr; intr = intr->next)
              for (intr = daemon->int_names; intr; intr = intr->next)              {
                {                struct addrlist *addrlist;
                  if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)                
                 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
                   if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
                     break;                      break;
                  else                
                    while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)                if (addrlist)
                      intr = intr->next;                  break;
                 else
                   while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
                     intr = intr->next;
               }
           else if (flag == 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.addr6, &addrlist->addr.addr6))
                     break;
                 
                 if (addrlist)
                   break;
                 else
                   while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
                     intr = intr->next;
               }
           
           if (intr)
             {
               if (local_query || in_zone(zone, intr->name, NULL))
                 {       
                   found = 1;
                   log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
                   if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                           daemon->auth_ttl, NULL,
                                           T_PTR, C_IN, "d", intr->name))
                     anscount++;
                 }                  }
   
               if (intr)  
                 {  
                   if (in_zone(zone, intr->name, NULL))  
                     {     
                       found = 1;  
                       log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);  
                       if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,   
                                               daemon->auth_ttl, NULL,  
                                               T_PTR, C_IN, "d", intr->name))  
                         anscount++;  
                     }  
                 }  
             }              }
          
           if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))            if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
             do {               do { 
               strcpy(name, cache_get_name(crecp));                strcpy(name, cache_get_name(crecp));
Line 189  size_t answer_auth(struct dns_header *header, char *li Line 227  size_t answer_auth(struct dns_header *header, char *li
                     *p = 0; /* must be bare name */                      *p = 0; /* must be bare name */
                                       
                   /* add  external domain */                    /* add  external domain */
                  strcat(name, ".");                  if (zone)
                  strcat(name, zone->domain);                    {
                       strcat(name, ".");
                       strcat(name, zone->domain);
                     }
                   log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));                    log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
                   found = 1;                    found = 1;
                   if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                     if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
Line 198  size_t answer_auth(struct dns_header *header, char *li Line 239  size_t answer_auth(struct dns_header *header, char *li
                                           T_PTR, C_IN, "d", name))                                            T_PTR, C_IN, "d", name))
                     anscount++;                      anscount++;
                 }                  }
              else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))              else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
                 {                  {
                   log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));                    log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
                   found = 1;                    found = 1;
Line 212  size_t answer_auth(struct dns_header *header, char *li Line 253  size_t answer_auth(struct dns_header *header, char *li
                                           
             } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));              } while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
   
          if (!found)          if (found)
            log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);            nxdomain = 0;
           else
             log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
   
           continue;            continue;
         }          }
               
     cname_restart:      cname_restart:
      for (zone = daemon->auth_zones; zone; zone = zone->next)      if (found)
        if (in_zone(zone, name, &cut))        /* NS and SOA .arpa requests have set found above. */
          break;        cut = NULL;
            else
      if (!zone) 
         {          {
          auth = 0;          for (zone = daemon->auth_zones; zone; zone = zone->next)
          continue;            if (in_zone(zone, name, &cut))
               break;
           
           if (!zone)
             {
               auth = 0;
               continue;
             }
         }          }
   
       for (rec = daemon->mxnames; rec; rec = rec->next)        for (rec = daemon->mxnames; rec; rec = rec->next)
        if (!rec->issrv && hostname_isequal(name, rec->name))        if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
           {            {
             nxdomain = 0;              nxdomain = 0;
                                     
            if (qtype == T_MX)            if (rc == 2 && qtype == T_MX)
               {                {
                 found = 1;                  found = 1;
                 log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");                   log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); 
Line 245  size_t answer_auth(struct dns_header *header, char *li Line 294  size_t answer_auth(struct dns_header *header, char *li
           }            }
               
       for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)        for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
        if (rec->issrv && hostname_isequal(name, rec->name))        if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
           {            {
             nxdomain = 0;              nxdomain = 0;
                           
            if (qtype == T_SRV)            if (rc == 2 && qtype == T_SRV)
               {                {
                 found = 1;                  found = 1;
                 log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");                   log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>"); 
Line 280  size_t answer_auth(struct dns_header *header, char *li Line 329  size_t answer_auth(struct dns_header *header, char *li
         }          }
   
       for (txt = daemon->rr; txt; txt = txt->next)        for (txt = daemon->rr; txt; txt = txt->next)
        if (hostname_isequal(name, txt->name))        if ((rc = hostname_issubdomain(name, txt->name)))
           {            {
             nxdomain = 0;              nxdomain = 0;
            if (txt->class == qtype)            if (rc == 2 && txt->class == qtype)
               {                {
                 found = 1;                  found = 1;
                log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");                 log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class)); 
                 if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,                  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
                                         NULL, txt->class, C_IN, "t", txt->len, txt->txt))                                          NULL, txt->class, C_IN, "t", txt->len, txt->txt))
                   anscount++;                    anscount++;
Line 294  size_t answer_auth(struct dns_header *header, char *li Line 343  size_t answer_auth(struct dns_header *header, char *li
           }            }
               
       for (txt = daemon->txt; txt; txt = txt->next)        for (txt = daemon->txt; txt; txt = txt->next)
        if (txt->class == C_IN && hostname_isequal(name, txt->name))        if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
           {            {
             nxdomain = 0;              nxdomain = 0;
            if (qtype == T_TXT)            if (rc == 2 && qtype == T_TXT)
               {                {
                 found = 1;                  found = 1;
                 log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");                   log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); 
Line 308  size_t answer_auth(struct dns_header *header, char *li Line 357  size_t answer_auth(struct dns_header *header, char *li
           }            }
   
        for (na = daemon->naptr; na; na = na->next)         for (na = daemon->naptr; na; na = na->next)
         if (hostname_isequal(name, na->name))         if ((rc = hostname_issubdomain(name, na->name)))
            {             {
              nxdomain = 0;               nxdomain = 0;
             if (qtype == T_NAPTR)             if (rc == 2 && qtype == T_NAPTR)
                {                 {
                  found = 1;                   found = 1;
                  log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");                   log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
Line 321  size_t answer_auth(struct dns_header *header, char *li Line 370  size_t answer_auth(struct dns_header *header, char *li
                           anscount++;                            anscount++;
                }                 }
            }             }
    
       if (qtype == T_A)
          flag = F_IPV4;
        
        if (qtype == T_AAAA)
          flag = F_IPV6;
        
        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 ((rc = hostname_issubdomain(name, intr->name)))
            {             {
                struct addrlist *addrlist;
                
              nxdomain = 0;               nxdomain = 0;
              if (qtype == T_A && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)  
                {  
                  found = 1;  
                  log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);  
                  if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,   
                                          daemon->auth_ttl, NULL, T_A, C_IN, "4", &addr))  
                    anscount++;  
                }  
            }  
          
        for (a = daemon->cnames; a; a = a->next)  
          if (hostname_isequal(name, a->alias) )  
            {  
              log_query(F_CONFIG | F_CNAME, name, NULL, NULL);  
              strcpy(name, a->target);  
              if (!strchr(name, '.'))  
                {  
                  strcat(name, ".");  
                  strcat(name, zone->domain);  
                }  
              found = 1;  
              if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,   
                                      daemon->auth_ttl, NULL,  
                                      T_CNAME, C_IN, "d", name))  
                anscount++;  
                             
             goto cname_restart;             if (rc == 2 && flag)
           }               for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)  
                  if (((addrlist->flags & ADDRLIST_IPV6)  ? T_AAAA : T_A) == qtype &&
                      (local_query || filter_zone(zone, flag, &addrlist->addr)))
                    {
                      if (addrlist->flags & ADDRLIST_REVONLY)
                        continue;
   
      if (qtype == T_A)                     found = 1;
        flag = F_IPV4;                     log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
                     if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
#ifdef HAVE_IPV6                                             daemon->auth_ttl, NULL, qtype, C_IN, 
      if (qtype == T_AAAA)                                             qtype == T_A ? "4" : "6", &addrlist->addr))
        flag = F_IPV6;                       anscount++;
#endif                   }
             }
        
       if (!cut)        if (!cut)
         {          {
           nxdomain = 0;            nxdomain = 0;
                       
           if (qtype == T_SOA)            if (qtype == T_SOA)
             {              {
              soa = 1; /* inhibits auth section */              auth = soa = 1; /* inhibits auth section */
               found = 1;                found = 1;
               log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");                log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
             }              }
Line 380  size_t answer_auth(struct dns_header *header, char *li Line 417  size_t answer_auth(struct dns_header *header, char *li
                               
               if (peer_addr->sa.sa_family == AF_INET)                if (peer_addr->sa.sa_family == AF_INET)
                 peer_addr->in.sin_port = 0;                  peer_addr->in.sin_port = 0;
 #ifdef HAVE_IPV6  
               else                else
                peer_addr->in6.sin6_port = 0;                 {
#endif                  peer_addr->in6.sin6_port = 0; 
                   peer_addr->in6.sin6_scope_id = 0;
                 }
                               
               for (peers = daemon->auth_peers; peers; peers = peers->next)                for (peers = daemon->auth_peers; peers; peers = peers->next)
                 if (sockaddr_isequal(peer_addr, &peers->addr))                  if (sockaddr_isequal(peer_addr, &peers->addr))
                   break;                    break;
                               
              /* Refuse all AXFR unless --auth-sec-servers is set */              /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
              if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)              if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
                   (daemon->auth_peers && !peers)) 
                 {                  {
                   if (peer_addr->sa.sa_family == AF_INET)                    if (peer_addr->sa.sa_family == AF_INET)
                     inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);                      inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
 #ifdef HAVE_IPV6  
                   else                    else
                     inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);                       inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); 
 #endif  
                                       
                   my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);                    my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
                   return 0;                    return 0;
                 }                  }
                                               
                 auth = 1;
               soa = 1; /* inhibits auth section */                soa = 1; /* inhibits auth section */
               ns = 1; /* ensure we include NS records! */                ns = 1; /* ensure we include NS records! */
               axfr = 1;                axfr = 1;
Line 412  size_t answer_auth(struct dns_header *header, char *li Line 450  size_t answer_auth(struct dns_header *header, char *li
             }              }
           else if (qtype == T_NS)            else if (qtype == T_NS)
             {              {
                 auth = 1;
               ns = 1; /* inhibits auth section */                ns = 1; /* inhibits auth section */
               found = 1;                found = 1;
               log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");                 log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); 
Line 429  size_t answer_auth(struct dns_header *header, char *li Line 468  size_t answer_auth(struct dns_header *header, char *li
                   {                     { 
                     nxdomain = 0;                      nxdomain = 0;
                     if ((crecp->flags & flag) &&                       if ((crecp->flags & flag) && 
                        (filter_constructed_dhcp(zone, flag, &(crecp->addr.addr))))                        (local_query || filter_zone(zone, flag, &(crecp->addr))))
                       {                        {
                         *cut = '.'; /* restore domain part */                          *cut = '.'; /* restore domain part */
                        log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));                        log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
                         *cut  = 0; /* remove domain part */                          *cut  = 0; /* remove domain part */
                         found = 1;                          found = 1;
                         if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                           if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
Line 452  size_t answer_auth(struct dns_header *header, char *li Line 491  size_t answer_auth(struct dns_header *header, char *li
             do              do
               {                 { 
                  nxdomain = 0;                   nxdomain = 0;
                 if ((crecp->flags & flag) && filter_constructed_dhcp(zone, flag, &(crecp->addr.addr)))                 if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
                    {                     {
                     log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));                     log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
                      found = 1;                       found = 1;
                      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,                        if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                              daemon->auth_ttl, NULL, qtype, C_IN,                                                daemon->auth_ttl, NULL, qtype, C_IN, 
Line 464  size_t answer_auth(struct dns_header *header, char *li Line 503  size_t answer_auth(struct dns_header *header, char *li
               } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));                } while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
         }          }
               
      if (!found)      /* Only supply CNAME if no record for any type is known. */
        log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);      if (nxdomain)
         {
           /* Check for possible wildcard match against *.domain 
              return length of match, to get longest.
              Note that if return length of wildcard section, so
              we match b.simon to _both_ *.simon and b.simon
              but return a longer (better) match to b.simon.
           */  
           for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
             if (a->alias[0] == '*')
               {
                 char *test = name;
                 
                 while ((test = strchr(test+1, '.')))
                   {
                     if (hostname_isequal(test, &(a->alias[1])))
                       {
                         if (strlen(test) > wclen && !cname_wildcard)
                           {
                             wclen = strlen(test);
                             candidate = a;
                             cname_wildcard = 1;
                           }
                         break;
                       }
                   }
                 
               }
             else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
               {
                 /* Simple case, no wildcard */
                 wclen = strlen(a->alias);
                 candidate = a;
               }
           
           if (candidate)
             {
               log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
               strcpy(name, candidate->target);
               if (!strchr(name, '.'))
                 {
                   strcat(name, ".");
                   strcat(name, zone->domain);
                 }
               found = 1;
               if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
                                       daemon->auth_ttl, &nameoffset,
                                       T_CNAME, C_IN, "d", name))
                 anscount++;
               
               goto cname_restart;
             }
           else if (cache_find_non_terminal(name, now))
             nxdomain = 0;
 
           log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
         }
               
     }      }
       
Line 483  size_t answer_auth(struct dns_header *header, char *li Line 578  size_t answer_auth(struct dns_header *header, char *li
                       
           authname = name;            authname = name;
   
          if (!subnet->is6)          if (!(subnet->flags & ADDRLIST_IPV6))
             {              {
              in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;              in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
               char *p = name;                char *p = name;
                               
              if (subnet->prefixlen == 24)              if (subnet->prefixlen >= 24)
                p += sprintf(p, "%d.", a & 0xff);                p += sprintf(p, "%u.", a & 0xff);
               a = a >> 8;                a = a >> 8;
              if (subnet->prefixlen != 8)              if (subnet->prefixlen >= 16 )
                p += sprintf(p, "%d.", a & 0xff);                p += sprintf(p, "%u.", a & 0xff);
               a = a >> 8;                a = a >> 8;
              p += sprintf(p, "%d.in-addr.arpa", a & 0xff);              p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
                               
             }              }
 #ifdef HAVE_IPV6  
           else            else
             {              {
               char *p = name;                char *p = name;
Line 505  size_t answer_auth(struct dns_header *header, char *li Line 599  size_t answer_auth(struct dns_header *header, char *li
                               
               for (i = subnet->prefixlen-1; i >= 0; i -= 4)                for (i = subnet->prefixlen-1; i >= 0; i -= 4)
                 {                   { 
                  int dig = ((unsigned char *)&subnet->addr6)[i>>3];                  int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
                   p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);                    p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
                 }                  }
               p += sprintf(p, "ip6.arpa");                p += sprintf(p, "ip6.arpa");
                               
             }              }
 #endif  
         }          }
               
       /* handle NS and SOA in auth section or for explicit queries */        /* handle NS and SOA in auth section or for explicit queries */
Line 535  size_t answer_auth(struct dns_header *header, char *li Line 628  size_t answer_auth(struct dns_header *header, char *li
         {          {
           struct name_list *secondary;            struct name_list *secondary;
                       
          newoffset = ansp - (unsigned char *)header;          /* Only include the machine running dnsmasq if it's acting as an auth server */
          if (add_resource_record(header, limit, &trunc, -offset, &ansp,           if (daemon->authinterface)
                                  daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver)) 
             {              {
              if (offset == 0)               newoffset = ansp - (unsigned char *)header;
                offset = newoffset;              if (add_resource_record(header, limit, &trunc, -offset, &ansp, 
              if (ns)                                       daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
                anscount++;                {
              else                  if (offset == 0) 
                authcount++;                    offset = newoffset;
                   if (ns) 
                     anscount++;
                   else
                     authcount++;
                 }
             }              }
   
           if (!subnet)            if (!subnet)
Line 634  size_t answer_auth(struct dns_header *header, char *li Line 731  size_t answer_auth(struct dns_header *header, char *li
               }                }
                       
           for (intr = daemon->int_names; intr; intr = intr->next)            for (intr = daemon->int_names; intr; intr = intr->next)
            if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)            if (in_zone(zone, intr->name, &cut))
               {                {
                   struct addrlist *addrlist;
                   
                 if (cut)                  if (cut)
                   *cut = 0;                    *cut = 0;
                                   
                if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,                 for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 
                                        daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))                  if (!(addrlist->flags & ADDRLIST_IPV6) &&
                  anscount++;                      (local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) && 
                       add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
                                           daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
                     anscount++;
                                   
                   for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) 
                     if ((addrlist->flags & ADDRLIST_IPV6) && 
                         (local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
                         add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
                                             daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
                       anscount++;
                   
                 /* restore config data */                  /* restore config data */
                 if (cut)                  if (cut)
                   *cut = '.';                     *cut = '.'; 
               }                }
                       
           for (a = daemon->cnames; a; a = a->next)            for (a = daemon->cnames; a; a = a->next)
             if (in_zone(zone, a->alias, &cut))              if (in_zone(zone, a->alias, &cut))
               {                {
Line 677  size_t answer_auth(struct dns_header *header, char *li Line 786  size_t answer_auth(struct dns_header *header, char *li
                   if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))                    if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
                     {                      {
                       char *cache_name = cache_get_name(crecp);                        char *cache_name = cache_get_name(crecp);
                      if (!strchr(cache_name, '.') && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))                      if (!strchr(cache_name, '.') && 
                        {                          (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) &&
                          qtype = T_A;                          add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
#ifdef HAVE_IPV6                                              daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN, 
                          if (crecp->flags & F_IPV6)                                              (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
                            qtype = T_AAAA;                        anscount++;
#endif 
                          if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,  
                                                  daemon->auth_ttl, NULL, qtype, C_IN,  
                                                  (crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr)) 
                            anscount++; 
                        } 
                     }                      }
                                       
                   if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))                    if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
                     {                      {
                       strcpy(name, cache_get_name(crecp));                        strcpy(name, cache_get_name(crecp));
                      if (in_zone(zone, name, &cut) && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))                      if (in_zone(zone, name, &cut) && 
                           (local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
                         {                          {
                          qtype = T_A;                          if (cut)
#ifdef HAVE_IPV6                            *cut = 0;
                          if (crecp->flags & F_IPV6) 
                            qtype = T_AAAA; 
#endif 
                           if (cut) 
                             *cut = 0; 
   
                           if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,                           if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, 
                                                   daemon->auth_ttl, NULL, qtype, C_IN,                                                   daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN, 
                                                   (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))                                                  (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
                             anscount++;                            anscount++;
                         }                          }
                     }                      }
                 }                  }
Line 729  size_t answer_auth(struct dns_header *header, char *li Line 828  size_t answer_auth(struct dns_header *header, char *li
   /* done all questions, set up header and return length of result */    /* done all questions, set up header and return length of result */
   /* 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;
   /* clear RA flag */  
   header->hb4 &= ~HB4_RA;  
   
  /* authoritive */  if (local_query)
     {
       /* set RA flag */
       header->hb4 |= HB4_RA;
     }
   else
     {
       /* clear RA flag */
       header->hb4 &= ~HB4_RA;
     }
 
   /* data is never DNSSEC signed. */
   header->hb4 &= ~HB4_AD;
 
   /* authoritative */
   if (auth)    if (auth)
     header->hb3 |= HB3_AA;      header->hb3 |= HB3_AA;
       
Line 740  size_t answer_auth(struct dns_header *header, char *li Line 851  size_t answer_auth(struct dns_header *header, char *li
   if (trunc)    if (trunc)
     header->hb3 |= HB3_TC;      header->hb3 |= HB3_TC;
       
  if (anscount == 0 && auth && nxdomain)  if ((auth || local_query) && 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(authcount);    header->nscount = htons(authcount);
   header->arcount = htons(0);    header->arcount = htons(0);
   
     /* Advertise our packet size limit in our reply */
     if (have_pseudoheader)
       return add_pseudoheader(header,  ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
   
   return ansp - (unsigned char *)header;    return ansp - (unsigned char *)header;
 }  }
       

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


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