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

version 1.1.1.1, 2016/11/02 09:57:01 version 1.1.1.2, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2016 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 144  size_t add_pseudoheader(struct dns_header *header, siz Line 144  size_t add_pseudoheader(struct dns_header *header, siz
           GETSHORT(len, p);            GETSHORT(len, p);
                       
           /* malformed option, delete the whole OPT RR and start again. */            /* malformed option, delete the whole OPT RR and start again. */
          if (i + len > rdlen)          if (i + 4 + len > rdlen)
             {              {
               rdlen = 0;                rdlen = 0;
               is_last = 0;                is_last = 0;
Line 159  size_t add_pseudoheader(struct dns_header *header, siz Line 159  size_t add_pseudoheader(struct dns_header *header, siz
               /* delete option if we're to replace it. */                /* delete option if we're to replace it. */
               p -= 4;                p -= 4;
               rdlen -= len + 4;                rdlen -= len + 4;
              memcpy(p, p+len+4, rdlen - i);              memmove(p, p+len+4, rdlen - i);
               PUTSHORT(rdlen, lenp);                PUTSHORT(rdlen, lenp);
               lenp -= 2;                lenp -= 2;
             }              }
Line 192  size_t add_pseudoheader(struct dns_header *header, siz Line 192  size_t add_pseudoheader(struct dns_header *header, siz
           !(p = skip_section(p,             !(p = skip_section(p, 
                              ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),                                ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), 
                              header, plen)))                               header, plen)))
         {
           free(buff);
         return plen;          return plen;
         }
         if (p + 11 > limit)
         {
           free(buff);
           return plen; /* Too big */
         }
       *p++ = 0; /* empty name */        *p++ = 0; /* empty name */
       PUTSHORT(T_OPT, p);        PUTSHORT(T_OPT, p);
       PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */        PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
Line 204  size_t add_pseudoheader(struct dns_header *header, siz Line 212  size_t add_pseudoheader(struct dns_header *header, siz
       /* Copy back any options */        /* Copy back any options */
       if (buff)        if (buff)
         {          {
             if (p + rdlen > limit)
             {
               free(buff);
               return plen; /* Too big */
             }
           memcpy(p, buff, rdlen);            memcpy(p, buff, rdlen);
           free(buff);            free(buff);
           p += rdlen;            p += rdlen;
         }          }
      header->arcount = htons(ntohs(header->arcount) + 1);      
       /* Only bump arcount if RR is going to fit */ 
       if (((ssize_t)optlen) <= (limit - (p + 4)))
         header->arcount = htons(ntohs(header->arcount) + 1);
     }      }
       
   if (((ssize_t)optlen) > (limit - (p + 4)))    if (((ssize_t)optlen) > (limit - (p + 4)))
Line 217  size_t add_pseudoheader(struct dns_header *header, siz Line 233  size_t add_pseudoheader(struct dns_header *header, siz
   /* Add new option */    /* Add new option */
   if (optno != 0 && replace != 2)    if (optno != 0 && replace != 2)
     {      {
         if (p + 4 > limit)
          return plen; /* Too big */
       PUTSHORT(optno, p);        PUTSHORT(optno, p);
       PUTSHORT(optlen, p);        PUTSHORT(optlen, p);
         if (p + optlen > limit)
          return plen; /* Too big */
       memcpy(p, opt, optlen);        memcpy(p, opt, optlen);
       p += optlen;          p += optlen;  
       PUTSHORT(p - datap, lenp);        PUTSHORT(p - datap, lenp);
Line 244  static void encoder(unsigned char *in, char *out) Line 264  static void encoder(unsigned char *in, char *out)
   out[3] = char64(in[2]);    out[3] = char64(in[2]);
 }  }
   
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
                              union mysockaddr *l3, time_t now, int *cacheablep)
 {  {
   int maclen, replace = 2; /* can't get mac address, just delete any incoming. */    int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
   unsigned char mac[DHCP_CHADDR_MAX];    unsigned char mac[DHCP_CHADDR_MAX];
Line 253  static size_t add_dns_client(struct dns_header *header Line 274  static size_t add_dns_client(struct dns_header *header
   if ((maclen = find_mac(l3, mac, 1, now)) == 6)    if ((maclen = find_mac(l3, mac, 1, now)) == 6)
     {      {
       replace = 1;        replace = 1;
         *cacheablep = 0;
   
       if (option_bool(OPT_MAC_HEX))        if (option_bool(OPT_MAC_HEX))
         print_mac(encode, mac, maclen);          print_mac(encode, mac, maclen);
Line 268  static size_t add_dns_client(struct dns_header *header Line 290  static size_t add_dns_client(struct dns_header *header
 }  }
   
   
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
                       union mysockaddr *l3, time_t now, int *cacheablep)
 {  {
   int maclen;    int maclen;
   unsigned char mac[DHCP_CHADDR_MAX];    unsigned char mac[DHCP_CHADDR_MAX];
   
   if ((maclen = find_mac(l3, mac, 1, now)) != 0)    if ((maclen = find_mac(l3, mac, 1, now)) != 0)
    plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);     {
          *cacheablep = 0;
       plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0); 
     }
   
   return plen;     return plen; 
 }  }
   
 struct subnet_opt {  struct subnet_opt {
   u16 family;    u16 family;
  u8 source_netmask, scope_netmask;  u8 source_netmask, scope_netmask; 
#ifdef HAVE_IPV6  
   u8 addr[IN6ADDRSZ];    u8 addr[IN6ADDRSZ];
 #else  
   u8 addr[INADDRSZ];  
 #endif  
 };  };
   
 static void *get_addrp(union mysockaddr *addr, const short family)   static void *get_addrp(union mysockaddr *addr, const short family) 
 {  {
 #ifdef HAVE_IPV6  
   if (family == AF_INET6)    if (family == AF_INET6)
     return &addr->in6.sin6_addr;      return &addr->in6.sin6_addr;
 #endif  
   
   return &addr->in.sin_addr;    return &addr->in.sin_addr;
 }  }
   
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
 {  {
   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */    /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
       
   int len;    int len;
  void *addrp;  void *addrp = NULL;
   int sa_family = source->sa.sa_family;    int sa_family = source->sa.sa_family;
  int cacheable = 0;
   
   opt->source_netmask = 0;    opt->source_netmask = 0;
   opt->scope_netmask = 0;    opt->scope_netmask = 0;
    
#ifdef HAVE_IPV6 
   if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)    if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
     {      {
       opt->source_netmask = daemon->add_subnet6->mask;        opt->source_netmask = daemon->add_subnet6->mask;
Line 318  static size_t calc_subnet_opt(struct subnet_opt *opt,  Line 338  static size_t calc_subnet_opt(struct subnet_opt *opt, 
         {          {
           sa_family = daemon->add_subnet6->addr.sa.sa_family;            sa_family = daemon->add_subnet6->addr.sa.sa_family;
           addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);            addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
             cacheable = 1;
         }           } 
       else         else 
         addrp = &source->in6.sin6_addr;          addrp = &source->in6.sin6_addr;
     }      }
 #endif  
   
   if (source->sa.sa_family == AF_INET && daemon->add_subnet4)    if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
     {      {
Line 331  static size_t calc_subnet_opt(struct subnet_opt *opt,  Line 351  static size_t calc_subnet_opt(struct subnet_opt *opt, 
         {          {
           sa_family = daemon->add_subnet4->addr.sa.sa_family;            sa_family = daemon->add_subnet4->addr.sa.sa_family;
           addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);            addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
             cacheable = 1; /* Address is constant */
         }           } 
         else           else 
           addrp = &source->in.sin_addr;            addrp = &source->in.sin_addr;
     }      }
       
 #ifdef HAVE_IPV6  
   opt->family = htons(sa_family == AF_INET6 ? 2 : 1);    opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
 #else  
   opt->family = htons(1);  
 #endif  
       
  len = 0;  if (addrp && opt->source_netmask != 0)
   
  if (opt->source_netmask != 0) 
     {      {
       len = ((opt->source_netmask - 1) >> 3) + 1;        len = ((opt->source_netmask - 1) >> 3) + 1;
       memcpy(opt->addr, addrp, len);        memcpy(opt->addr, addrp, len);
       if (opt->source_netmask & 7)        if (opt->source_netmask & 7)
         opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));          opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
     }      }
     else
       {
         cacheable = 1; /* No address ever supplied. */
         len = 0;
       }
   
     if (cacheablep)
       *cacheablep = cacheable;
       
   return len + 4;    return len + 4;
 }  }
     
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
 {  {
   /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */    /* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
       
   int len;    int len;
   struct subnet_opt opt;    struct subnet_opt opt;
       
  len = calc_subnet_opt(&opt, source);  len = calc_subnet_opt(&opt, source, cacheable);
   return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);    return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
 }  }
   
Line 375  int check_source(struct dns_header *header, size_t ple Line 398  int check_source(struct dns_header *header, size_t ple
   unsigned char *p;    unsigned char *p;
   int code, i, rdlen;    int code, i, rdlen;
       
   calc_len = calc_subnet_opt(&opt, peer);  calc_len = calc_subnet_opt(&opt, peer, NULL);
         
   if (!(p = skip_name(pseudoheader, header, plen, 10)))  if (!(p = skip_name(pseudoheader, header, plen, 10)))
     return 1;    return 1;
     
   p += 8; /* skip UDP length and RCODE */  p += 8; /* skip UDP length and RCODE */
     
   GETSHORT(rdlen, p);  GETSHORT(rdlen, p);
   if (!CHECK_LEN(header, p, plen, rdlen))  if (!CHECK_LEN(header, p, plen, rdlen))
     return 1; /* bad packet */    return 1; /* bad packet */
     
   /* check if option there */  /* check if option there */
    for (i = 0; i + 4 < rdlen; i += len + 4)     for (i = 0; i + 4 < rdlen; i += len + 4)
      {       {
        GETSHORT(code, p);         GETSHORT(code, p);
Line 404  int check_source(struct dns_header *header, size_t ple Line 427  int check_source(struct dns_header *header, size_t ple
    return 1;     return 1;
 }  }
   
   /* Set *check_subnet if we add a client subnet option, which needs to checked 
      in the reply. Set *cacheable to zero if we add an option which the answer
      may depend on. */
 size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,   size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit, 
                        union mysockaddr *source, time_t now, int *check_subnet)                            union mysockaddr *source, time_t now, int *check_subnet, int *cacheable)    
 {  {
   *check_subnet = 0;    *check_subnet = 0;
  *cacheable = 1;
   
   if (option_bool(OPT_ADD_MAC))    if (option_bool(OPT_ADD_MAC))
    plen  = add_mac(header, plen, limit, source, now);    plen  = add_mac(header, plen, limit, source, now, cacheable);
       
   if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))    if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
    plen = add_dns_client(header, plen, limit, source, now);    plen = add_dns_client(header, plen, limit, source, now, cacheable);
  
   if (daemon->dns_client_id)    if (daemon->dns_client_id)
     plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,       plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID, 
                             (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);                              (unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
       
   if (option_bool(OPT_CLIENT_SUBNET))    if (option_bool(OPT_CLIENT_SUBNET))
     {      {
      plen = add_source_addr(header, plen, limit, source);       plen = add_source_addr(header, plen, limit, source, cacheable); 
       *check_subnet = 1;        *check_subnet = 1;
     }      }
                       

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


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