Diff for /embedaddon/dnsmasq/src/network.c between versions 1.1.1.1 and 1.1.1.5

version 1.1.1.1, 2013/07/29 19:37:40 version 1.1.1.5, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley/* dnsmasq is Copyright (c) 2000-2022 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 29  int indextoname(int fd, int index, char *name) Line 29  int indextoname(int fd, int index, char *name)
   if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)    if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
     return 0;      return 0;
   
  strncpy(name, ifr.ifr_name, IF_NAMESIZE);  safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);
   
  return 1; return 1;
 }  }
   
   
Line 82  int indextoname(int fd, int index, char *name) Line 82  int indextoname(int fd, int index, char *name)
   for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++)     for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++) 
     {      {
       struct lifreq lifr;        struct lifreq lifr;
      strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);      safe_strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
       if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)         if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0) 
         return 0;          return 0;
               
       if (lifr.lifr_index == index) {        if (lifr.lifr_index == index) {
        strncpy(name, lifr.lifr_name, IF_NAMESIZE);        safe_strncpy(name, lifr.lifr_name, IF_NAMESIZE);
         return 1;          return 1;
       }        }
     }      }
Line 99  int indextoname(int fd, int index, char *name) Line 99  int indextoname(int fd, int index, char *name)
   
 int indextoname(int fd, int index, char *name)  int indextoname(int fd, int index, char *name)
 {   { 
     (void)fd;
   
   if (index == 0 || !if_indextoname(index, name))    if (index == 0 || !if_indextoname(index, name))
     return 0;      return 0;
   
Line 107  int indextoname(int fd, int index, char *name) Line 109  int indextoname(int fd, int index, char *name)
   
 #endif  #endif
   
int iface_check(int family, struct all_addr *addr, char *name, int *auth)int iface_check(int family, union all_addr *addr, char *name, int *auth)
 {  {
   struct iname *tmp;    struct iname *tmp;
  int ret = 1;  int ret = 1, match_addr = 0;
   
  /* Note: have to check all and not bail out early, so that we set the  /* Note: have to check all and not bail out early, so that we set the "used" flags.
     "used" flags. */     May be called with family == AF_LOCAL to check interface by name only. */
       
   if (auth)  
     *auth = 0;  
     
   if (daemon->if_names || daemon->if_addrs)    if (daemon->if_names || daemon->if_addrs)
     {      {
       ret = 0;        ret = 0;
Line 131  int iface_check(int family, struct all_addr *addr, cha Line 130  int iface_check(int family, struct all_addr *addr, cha
           if (tmp->addr.sa.sa_family == family)            if (tmp->addr.sa.sa_family == family)
             {              {
               if (family == AF_INET &&                if (family == AF_INET &&
                  tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)                  tmp->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
                ret = tmp->used = 1;                ret = match_addr = tmp->used = 1;
#ifdef HAVE_IPV6 
               else if (family == AF_INET6 &&                else if (family == AF_INET6 &&
                        IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,                          IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, 
                                          &addr->addr.addr6))                                          &addr->addr6))
                ret = tmp->used = 1;                ret = match_addr = tmp->used = 1;
#endif 
             }                        }          
     }      }
       
  for (tmp = daemon->if_except; tmp; tmp = tmp->next)  if (!match_addr)
    if (tmp->name && wildcard_match(tmp->name, name))    for (tmp = daemon->if_except; tmp; tmp = tmp->next)
      ret = 0;      if (tmp->name && wildcard_match(tmp->name, name))
         ret = 0;
           
     if (auth)
       {
         *auth = 0;
   
  for (tmp = daemon->authinterface; tmp; tmp = tmp->next)      for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
    if (tmp->name)        if (tmp->name)
      {          {
        if (strcmp(tmp->name, name) == 0)            if (strcmp(tmp->name, name) == 0 &&
                 (tmp->addr.sa.sa_family == 0 || tmp->addr.sa.sa_family == family))
               break;
           }
         else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
                  tmp->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
           break;            break;
      }        else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&
    else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&                 IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr6))
             tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)          break;
      break;      
#ifdef HAVE_IPV6      if (tmp
    else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&        {
             IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr.addr6))          *auth = 1;
      break;          ret = 1;
#endif              }
 
  if (tmp && auth 
    { 
      *auth = 1; 
      ret = 1; 
     }      }
   
   return ret;     return ret; 
 }  }
   
   
/* Fix for problem that the kernel sometimes reports the loopback inerface as the/* Fix for problem that the kernel sometimes reports the loopback interface as the
    arrival interface when a packet originates locally, even when sent to address of      arrival interface when a packet originates locally, even when sent to address of 
    an interface other than the loopback. Accept packet if it arrived via a loopback      an interface other than the loopback. Accept packet if it arrived via a loopback 
    interface, even when we're not accepting packets that way, as long as the destination     interface, even when we're not accepting packets that way, as long as the destination
    address is one we're believing. Interface list must be up-to-date before calling. */     address is one we're believing. Interface list must be up-to-date before calling. */
int loopback_exception(int fd, int family, struct all_addr *addr, char *name)    int loopback_exception(int fd, int family, union all_addr *addr, char *name)    
 {  {
   struct ifreq ifr;    struct ifreq ifr;
   struct irec *iface;    struct irec *iface;
   
  strncpy(ifr.ifr_name, name, IF_NAMESIZE);  safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
   if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&    if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
       ifr.ifr_flags & IFF_LOOPBACK)        ifr.ifr_flags & IFF_LOOPBACK)
     {      {
Line 191  int loopback_exception(int fd, int family, struct all_ Line 192  int loopback_exception(int fd, int family, struct all_
           {            {
             if (family == AF_INET)              if (family == AF_INET)
               {                {
                if (iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)                if (iface->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
                   return 1;                    return 1;
               }                }
#ifdef HAVE_IPV6            else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr6))
            else if (IN6_ARE_ADDR_EQUAL(&iface->addr.in6.sin6_addr, &addr->addr.addr6)) 
               return 1;                return 1;
 #endif  
               
           }            }
     }      }
   return 0;    return 0;
 }  }
   
static int iface_allowed(struct irec **irecp, int if_index, /* If we're configured with something like --interface=eth0:0 then we'll listen correctly
                         union mysockaddr *addr, struct in_addr netmask, int dad)    on the relevant address, but the name of the arrival interface, derived from the
    index won't match the config. Check that we found an interface address for the arrival 
    interface: daemon->interfaces must be up-to-date. */
 int label_exception(int index, int family, union all_addr *addr)
 {  {
   struct irec *iface;    struct irec *iface;
  int fd, mtu = 0, loopback;
   /* labels only supported on IPv4 addresses. */
   if (family != AF_INET)
     return 0;
 
   for (iface = daemon->interfaces; iface; iface = iface->next)
     if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
         iface->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
       return 1;
 
   return 0;
 }
 
 struct iface_param {
   struct addrlist *spare;
   int fd;
 };
 
 static int iface_allowed(struct iface_param *param, int if_index, char *label,
                          union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags) 
 {
   struct irec *iface;
   struct cond_domain *cond;
   int loopback;
   struct ifreq ifr;    struct ifreq ifr;
   int tftp_ok = !!option_bool(OPT_TFTP);    int tftp_ok = !!option_bool(OPT_TFTP);
   int dhcp_ok = 1;    int dhcp_ok = 1;
   int auth_dns = 0;    int auth_dns = 0;
#ifdef HAVE_DHCP  int is_label = 0;
 #if defined(HAVE_DHCP) || defined(HAVE_TFTP)
   struct iname *tmp;    struct iname *tmp;
 #endif  #endif
   
  /* check whether the interface IP has been added already   (void)prefixlen;
     we call this routine multiple times. */ 
  for (iface = *irecp; iface; iface = iface->next)  
    if (sockaddr_isequal(&iface->addr, addr)) 
      { 
        iface->dad = dad; 
        return 1; 
      } 
   
  if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||  if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
      !indextoname(fd, if_index, ifr.ifr_name) ||      ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
      ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)    return 0;
    
   loopback = ifr.ifr_flags & IFF_LOOPBACK;
   
   if (loopback)
     dhcp_ok = 0;
   
   if (!label)
     label = ifr.ifr_name;
   else
     is_label = strcmp(label, ifr.ifr_name);
  
   /* maintain a list of all addresses on all interfaces for --local-service option */
   if (option_bool(OPT_LOCAL_SERVICE))
     {      {
      if (fd != -1)      struct addrlist *al;
 
       if (param->spare)
         {          {
          int errsave = errno;          al = param->spare;
          close(fd);          param->spare = al->next;
          errno = errsave; 
         }          }
      return 0;      else
         al = whine_malloc(sizeof(struct addrlist));
       
       if (al)
         {
           al->next = daemon->interface_addrs;
           daemon->interface_addrs = al;
           al->prefixlen = prefixlen;
           
           if (addr->sa.sa_family == AF_INET)
             {
               al->addr.addr4 = addr->in.sin_addr;
               al->flags = 0;
             }
           else
             {
               al->addr.addr6 = addr->in6.sin6_addr;
               al->flags = ADDRLIST_IPV6;
             } 
         }
     }      }
      
   loopback = ifr.ifr_flags & IFF_LOOPBACK;  
       
  if (loopback)  if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
     dhcp_ok = 0;    {
       struct interface_name *int_name;
       struct addrlist *al;
 #ifdef HAVE_AUTH
       struct auth_zone *zone;
       struct auth_name_list *name;
   
  if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)      /* Find subnets in auth_zones */
    mtu = ifr.ifr_mtu;      for (zone = daemon->auth_zones; zone; zone = zone->next)
         for (name = zone->interface_names; name; name = name->next)
           if (wildcard_match(name->name, label))
             {
               if (addr->sa.sa_family == AF_INET && (name->flags & AUTH4))
                 {
                   if (param->spare)
                     {
                       al = param->spare;
                       param->spare = al->next;
                     }
                   else
                     al = whine_malloc(sizeof(struct addrlist));
                   
                   if (al)
                     {
                       al->next = zone->subnet;
                       zone->subnet = al;
                       al->prefixlen = prefixlen;
                       al->addr.addr4 = addr->in.sin_addr;
                       al->flags = 0;
                     }
                 }
               
               if (addr->sa.sa_family == AF_INET6 && (name->flags & AUTH6))
                 {
                   if (param->spare)
                     {
                       al = param->spare;
                       param->spare = al->next;
                     }
                   else
                     al = whine_malloc(sizeof(struct addrlist));
                   
                   if (al)
                     {
                       al->next = zone->subnet;
                       zone->subnet = al;
                       al->prefixlen = prefixlen;
                       al->addr.addr6 = addr->in6.sin6_addr;
                       al->flags = ADDRLIST_IPV6;
                     }
                 } 
             }
 #endif
        
       /* Update addresses from interface_names. These are a set independent
          of the set we're listening on. */  
       for (int_name = daemon->int_names; int_name; int_name = int_name->next)
         if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
           {
             struct addrlist *lp;
 
             al = NULL;
             
             if (addr->sa.sa_family == AF_INET && (int_name->flags & (IN4 | INP4)))
               {
                 struct in_addr newaddr = addr->in.sin_addr;
                 
                 if (int_name->flags & INP4)
                   {
                     if (netmask.s_addr == 0xffffffff)
                       continue;
 
                     newaddr.s_addr = (addr->in.sin_addr.s_addr & netmask.s_addr) |
                       (int_name->proto4.s_addr & ~netmask.s_addr);
                   }
                 
                 /* check for duplicates. */
                 for (lp = int_name->addr; lp; lp = lp->next)
                   if (lp->flags == 0 && lp->addr.addr4.s_addr == newaddr.s_addr)
                     break;
                 
                 if (!lp)
                   {
                     if (param->spare)
                       {
                         al = param->spare;
                         param->spare = al->next;
                       }
                     else
                       al = whine_malloc(sizeof(struct addrlist));
 
                     if (al)
                       {
                         al->flags = 0;
                         al->addr.addr4 = newaddr;
                       }
                   }
               }
 
             if (addr->sa.sa_family == AF_INET6 && (int_name->flags & (IN6 | INP6)))
               {
                 struct in6_addr newaddr = addr->in6.sin6_addr;
                 
                 if (int_name->flags & INP6)
                   {
                     int i;
 
                     /* No sense in doing /128. */
                     if (prefixlen == 128)
                       continue;
                     
                     for (i = 0; i < 16; i++)
                       {
                         int bits = ((i+1)*8) - prefixlen;
                        
                         if (bits >= 8)
                           newaddr.s6_addr[i] = int_name->proto6.s6_addr[i];
                         else if (bits >= 0)
                           {
                             unsigned char mask = 0xff << bits;
                             newaddr.s6_addr[i] =
                               (addr->in6.sin6_addr.s6_addr[i] & mask) |
                               (int_name->proto6.s6_addr[i] & ~mask);
                           }
                       }
                   }
                 
                 /* check for duplicates. */
                 for (lp = int_name->addr; lp; lp = lp->next)
                   if ((lp->flags & ADDRLIST_IPV6) &&
                       IN6_ARE_ADDR_EQUAL(&lp->addr.addr6, &newaddr))
                     break;
                                         
                 if (!lp)
                   {
                     if (param->spare)
                       {
                         al = param->spare;
                         param->spare = al->next;
                       }
                     else
                       al = whine_malloc(sizeof(struct addrlist));
                     
                     if (al)
                       {
                         al->flags = ADDRLIST_IPV6;
                         al->addr.addr6 = newaddr;
 
                         /* Privacy addresses and addresses still undergoing DAD and deprecated addresses
                            don't appear in forward queries, but will in reverse ones. */
                         if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
                           al->flags |= ADDRLIST_REVONLY;
                       }
                   }
               }
             
             if (al)
               {
                 al->next = int_name->addr;
                 int_name->addr = al;
               }
           }
     }
 
   /* Update addresses for domain=<domain>,<interface> */
   for (cond = daemon->cond_domain; cond; cond = cond->next)
     if (cond->interface && strncmp(label, cond->interface, IF_NAMESIZE) == 0)
       {
         struct addrlist *al;
 
         if (param->spare)
           {
             al = param->spare;
             param->spare = al->next;
           }
         else
           al = whine_malloc(sizeof(struct addrlist));
 
         if (addr->sa.sa_family == AF_INET)
           {
             al->addr.addr4 = addr->in.sin_addr;
             al->flags = 0;
           }
         else
           {
             al->addr.addr6 =  addr->in6.sin6_addr;
             al->flags = ADDRLIST_IPV6;
           }
 
         al->prefixlen = prefixlen;
         al->next = cond->al;
         cond->al = al;
       }
       
  close(fd);  /* check whether the interface IP has been added already 
       we call this routine multiple times. */
  /* If we are restricting the set of interfaces to use, make  for (iface = daemon->interfaces; iface; iface = iface->next) 
     if (sockaddr_isequal(&iface->addr, addr) && iface->index == if_index)
       {
         iface->dad = !!(iface_flags & IFACE_TENTATIVE);
         iface->found = 1; /* for garbage collection */
         iface->netmask = netmask;
         return 1;
       }
 
  /* If we are restricting the set of interfaces to use, make
      sure that loopback interfaces are in that set. */       sure that loopback interfaces are in that set. */
   if (daemon->if_names && loopback)    if (daemon->if_names && loopback)
     {      {
Line 273  static int iface_allowed(struct irec **irecp, int if_i Line 520  static int iface_allowed(struct irec **irecp, int if_i
     }      }
       
   if (addr->sa.sa_family == AF_INET &&    if (addr->sa.sa_family == AF_INET &&
      !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))      !iface_check(AF_INET, (union all_addr *)&addr->in.sin_addr, label, &auth_dns))
     return 1;      return 1;
   
 #ifdef HAVE_IPV6  
   if (addr->sa.sa_family == AF_INET6 &&    if (addr->sa.sa_family == AF_INET6 &&
      !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))      !iface_check(AF_INET6, (union all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
     return 1;      return 1;
 #endif  
           
 #ifdef HAVE_DHCP  #ifdef HAVE_DHCP
   /* No DHCP where we're doing auth DNS. */    /* No DHCP where we're doing auth DNS. */
Line 298  static int iface_allowed(struct irec **irecp, int if_i Line 543  static int iface_allowed(struct irec **irecp, int if_i
         }          }
 #endif  #endif
     
     
   #ifdef HAVE_TFTP
     if (daemon->tftp_interfaces)
       {
         /* dedicated tftp interface list */
         tftp_ok = 0;
         for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
           if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
             tftp_ok = 1;
       }
   #endif
     
   /* add to list */    /* add to list */
   if ((iface = whine_malloc(sizeof(struct irec))))    if ((iface = whine_malloc(sizeof(struct irec))))
     {      {
         int mtu = 0;
   
         if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
           mtu = ifr.ifr_mtu;
   
       iface->addr = *addr;        iface->addr = *addr;
       iface->netmask = netmask;        iface->netmask = netmask;
       iface->tftp_ok = tftp_ok;        iface->tftp_ok = tftp_ok;
       iface->dhcp_ok = dhcp_ok;        iface->dhcp_ok = dhcp_ok;
       iface->dns_auth = auth_dns;        iface->dns_auth = auth_dns;
       iface->mtu = mtu;        iface->mtu = mtu;
      iface->dad = dad;      iface->dad = !!(iface_flags & IFACE_TENTATIVE);
      iface->done = iface->multicast_done = 0;      iface->found = 1;
       iface->done = iface->multicast_done = iface->warned = 0;
       iface->index = if_index;        iface->index = if_index;
         iface->label = is_label;
       if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))        if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
         {          {
           strcpy(iface->name, ifr.ifr_name);            strcpy(iface->name, ifr.ifr_name);
          iface->next = *irecp;          iface->next = daemon->interfaces;
          *irecp = iface;          daemon->interfaces = iface;
           return 1;            return 1;
         }          }
       free(iface);        free(iface);
Line 325  static int iface_allowed(struct irec **irecp, int if_i Line 589  static int iface_allowed(struct irec **irecp, int if_i
   return 0;    return 0;
 }  }
   
 #ifdef HAVE_IPV6  
 static int iface_allowed_v6(struct in6_addr *local, int prefix,   static int iface_allowed_v6(struct in6_addr *local, int prefix, 
                             int scope, int if_index, int flags,                               int scope, int if_index, int flags, 
                             int preferred, int valid, void *vparam)                              int preferred, int valid, void *vparam)
Line 334  static int iface_allowed_v6(struct in6_addr *local, in Line 597  static int iface_allowed_v6(struct in6_addr *local, in
   struct in_addr netmask; /* dummy */    struct in_addr netmask; /* dummy */
   netmask.s_addr = 0;    netmask.s_addr = 0;
   
   (void)prefix; /* warning */  
   (void)scope; /* warning */    (void)scope; /* warning */
   (void)preferred;    (void)preferred;
   (void)valid;    (void)valid;
Line 346  static int iface_allowed_v6(struct in6_addr *local, in Line 608  static int iface_allowed_v6(struct in6_addr *local, in
   addr.in6.sin6_family = AF_INET6;    addr.in6.sin6_family = AF_INET6;
   addr.in6.sin6_addr = *local;    addr.in6.sin6_addr = *local;
   addr.in6.sin6_port = htons(daemon->port);    addr.in6.sin6_port = htons(daemon->port);
  addr.in6.sin6_scope_id = if_index;  /* FreeBSD insists this is zero for non-linklocal addresses */
   if (IN6_IS_ADDR_LINKLOCAL(local))
     addr.in6.sin6_scope_id = if_index;
   else
     addr.in6.sin6_scope_id = 0;
       
  return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));  return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, flags);
 }  }
 #endif  
   
static int iface_allowed_v4(struct in_addr local, int if_index, static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
                             struct in_addr netmask, struct in_addr broadcast, void *vparam)                              struct in_addr netmask, struct in_addr broadcast, void *vparam)
 {  {
   union mysockaddr addr;    union mysockaddr addr;
     int prefix, bit;
    
     (void)broadcast; /* warning */
   
   memset(&addr, 0, sizeof(addr));    memset(&addr, 0, sizeof(addr));
 #ifdef HAVE_SOCKADDR_SA_LEN  #ifdef HAVE_SOCKADDR_SA_LEN
   addr.in.sin_len = sizeof(addr.in);    addr.in.sin_len = sizeof(addr.in);
 #endif  #endif
   addr.in.sin_family = AF_INET;    addr.in.sin_family = AF_INET;
   addr.in.sin_addr = broadcast; /* warning */  
   addr.in.sin_addr = local;    addr.in.sin_addr = local;
   addr.in.sin_port = htons(daemon->port);    addr.in.sin_port = htons(daemon->port);
   
  return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);  /* determine prefix length from netmask */
   for (prefix = 32, bit = 1; (bit & ntohl(netmask.s_addr)) == 0 && prefix != 0; bit = bit << 1, prefix--);
 
   return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
 }  }
   
int enumerate_interfaces(void)/*
  * Clean old interfaces no longer found.
  */
 static void clean_interfaces()
 {  {
#ifdef HAVE_IPV6  struct irec *iface;
  if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))  struct irec **up = &daemon->interfaces;
    return 0; 
   for (iface = *up; iface; iface = *up)
   {
     if (!iface->found && !iface->done)
       {
         *up = iface->next;
         free(iface->name);
         free(iface);
       }
     else
       {
         up = &iface->next;
       }
   }
 }
 
 /** Release listener if no other interface needs it.
  *
  * @return 1 if released, 0 if still required
  */
 static int release_listener(struct listener *l)
 {
   if (l->used > 1)
     {
       struct irec *iface;
       for (iface = daemon->interfaces; iface; iface = iface->next)
         if (iface->done && sockaddr_isequal(&l->addr, &iface->addr))
           {
             if (iface->found)
               {
                 /* update listener to point to active interface instead */
                 if (!l->iface->found)
                   l->iface = iface;
               }
             else
               {
                 l->used--;
                 iface->done = 0;
               }
           }
 
       /* Someone is still using this listener, skip its deletion */
       if (l->used > 0)
         return 0;
     }
 
   if (l->iface->done)
     {
       int port;
 
       port = prettyprint_addr(&l->iface->addr, daemon->addrbuff);
       my_syslog(LOG_DEBUG|MS_DEBUG, _("stopped listening on %s(#%d): %s port %d"),
                 l->iface->name, l->iface->index, daemon->addrbuff, port);
       /* In case it ever returns */
       l->iface->done = 0;
     }
 
   if (l->fd != -1)
     close(l->fd);
   if (l->tcpfd != -1)
     close(l->tcpfd);
   if (l->tftpfd != -1)
     close(l->tftpfd);
 
   free(l);
   return 1;
 }
 
 int enumerate_interfaces(int reset)
 {
   static struct addrlist *spare = NULL;
   static int done = 0;
   struct iface_param param;
   int errsave, ret = 1;
   struct addrlist *addr, *tmp;
   struct interface_name *intname;
   struct cond_domain *cond;
   struct irec *iface;
 #ifdef HAVE_AUTH
   struct auth_zone *zone;
 #endif  #endif
     struct server *serv;
     
     /* Do this max once per select cycle  - also inhibits netlink socket use
      in TCP child processes. */
   
  return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);   if (reset)
     {
       done = 0;
       return 1;
     }
 
   if (done)
     return 1;
 
   done = 1;
 
   if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
     return 0;
 
   /* iface indexes can change when interfaces are created/destroyed. 
      We use them in the main forwarding control path, when the path
      to a server is specified by an interface, so cache them.
      Update the cache here. */
   for (serv = daemon->servers; serv; serv = serv->next)
     if (serv->interface[0] != 0)
       {
 #ifdef HAVE_LINUX_NETWORK
         struct ifreq ifr;
         
         safe_strncpy(ifr.ifr_name, serv->interface, IF_NAMESIZE);
         if (ioctl(param.fd, SIOCGIFINDEX, &ifr) != -1) 
           serv->ifindex = ifr.ifr_ifindex;
 #else
         serv->ifindex = if_nametoindex(serv->interface);
 #endif
       }
     
 again:
   /* Mark interfaces for garbage collection */
   for (iface = daemon->interfaces; iface; iface = iface->next) 
     iface->found = 0;
 
   /* remove addresses stored against interface_names */
   for (intname = daemon->int_names; intname; intname = intname->next)
     {
       for (addr = intname->addr; addr; addr = tmp)
         {
           tmp = addr->next;
           addr->next = spare;
           spare = addr;
         }
       
       intname->addr = NULL;
     }
 
   /* remove addresses stored against cond-domains. */
   for (cond = daemon->cond_domain; cond; cond = cond->next)
     {
       for (addr = cond->al; addr; addr = tmp)
         {
           tmp = addr->next;
           addr->next = spare;
           spare = addr;
       }
       
       cond->al = NULL;
     }
   
   /* Remove list of addresses of local interfaces */
   for (addr = daemon->interface_addrs; addr; addr = tmp)
     {
       tmp = addr->next;
       addr->next = spare;
       spare = addr;
     }
   daemon->interface_addrs = NULL;
   
 #ifdef HAVE_AUTH
   /* remove addresses stored against auth_zone subnets, but not 
    ones configured as address literals */
   for (zone = daemon->auth_zones; zone; zone = zone->next)
     if (zone->interface_names)
       {
         struct addrlist **up;
         for (up = &zone->subnet, addr = zone->subnet; addr; addr = tmp)
           {
             tmp = addr->next;
             if (addr->flags & ADDRLIST_LITERAL)
               up = &addr->next;
             else
               {
                 *up = addr->next;
                 addr->next = spare;
                 spare = addr;
               }
           }
       }
 #endif
 
   param.spare = spare;
   
   ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
   if (ret < 0)
     goto again;
   else if (ret)
     {
       ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
       if (ret < 0)
         goto again;
     }
  
   errsave = errno;
   close(param.fd);
   
   if (option_bool(OPT_CLEVERBIND))
     { 
       /* Garbage-collect listeners listening on addresses that no longer exist.
          Does nothing when not binding interfaces or for listeners on localhost, 
          since the ->iface field is NULL. Note that this needs the protections
          against reentrancy, hence it's here.  It also means there's a possibility,
          in OPT_CLEVERBIND mode, that at listener will just disappear after
          a call to enumerate_interfaces, this is checked OK on all calls. */
       struct listener *l, *tmp, **up;
       int freed = 0;
       
       for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
         {
           tmp = l->next;
           
           if (!l->iface || l->iface->found)
             up = &l->next;
           else if (release_listener(l))
             {
               *up = tmp;
               freed = 1;
             }
         }
 
       if (freed)
         clean_interfaces();
     }
 
   errno = errsave;
   spare = param.spare;
   
   return ret;
 }  }
   
 /* set NONBLOCK bit on fd: See Stevens 16.6 */  /* set NONBLOCK bit on fd: See Stevens 16.6 */
Line 398  static int make_sock(union mysockaddr *addr, int type, Line 894  static int make_sock(union mysockaddr *addr, int type,
       
   if ((fd = socket(family, type, 0)) == -1)    if ((fd = socket(family, type, 0)) == -1)
     {      {
      int port;      int port, errsave;
       char *s;        char *s;
   
       /* No error if the kernel just doesn't support this IP flavour */        /* No error if the kernel just doesn't support this IP flavour */
Line 408  static int make_sock(union mysockaddr *addr, int type, Line 904  static int make_sock(union mysockaddr *addr, int type,
         return -1;          return -1;
               
     err:      err:
         errsave = errno;
       port = prettyprint_addr(addr, daemon->addrbuff);        port = prettyprint_addr(addr, daemon->addrbuff);
       if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))        if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
         sprintf(daemon->addrbuff, "port %d", port);          sprintf(daemon->addrbuff, "port %d", port);
Line 415  static int make_sock(union mysockaddr *addr, int type, Line 912  static int make_sock(union mysockaddr *addr, int type,
               
       if (fd != -1)        if (fd != -1)
         close (fd);          close (fd);
              
       errno = errsave;
 
       if (dienow)        if (dienow)
         {          {
           /* failure to bind addresses given by --listen-address at this point            /* failure to bind addresses given by --listen-address at this point
Line 432  static int make_sock(union mysockaddr *addr, int type, Line 931  static int make_sock(union mysockaddr *addr, int type,
   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
     goto err;      goto err;
       
 #ifdef HAVE_IPV6  
   if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)    if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
     goto err;      goto err;
 #endif  
       
   if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)    if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
     goto err;      goto err;
       
   if (type == SOCK_STREAM)    if (type == SOCK_STREAM)
     {      {
      if (listen(fd, 5) == -1)#ifdef TCP_FASTOPEN
       int qlen = 5;                           
       setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen));
 #endif
       
       if (listen(fd, TCP_BACKLOG) == -1)
         goto err;          goto err;
     }      }
  else if (!option_bool(OPT_NOWILD))  else if (family == AF_INET)
     {      {
      if (family == AF_INET)      if (!option_bool(OPT_NOWILD))
         {          {
 #if defined(HAVE_LINUX_NETWORK)   #if defined(HAVE_LINUX_NETWORK) 
           if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)            if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
Line 458  static int make_sock(union mysockaddr *addr, int type, Line 960  static int make_sock(union mysockaddr *addr, int type,
             goto err;              goto err;
 #endif  #endif
         }          }
 #ifdef HAVE_IPV6  
       else if (!set_ipv6pktinfo(fd))  
         goto err;  
 #endif  
     }      }
     else if (!set_ipv6pktinfo(fd))
       goto err;
       
   return fd;    return fd;
 }  }
   
 #ifdef HAVE_IPV6    
 int set_ipv6pktinfo(int fd)  int set_ipv6pktinfo(int fd)
 {  {
   int opt = 1;    int opt = 1;
Line 494  int set_ipv6pktinfo(int fd) Line 993  int set_ipv6pktinfo(int fd)
   
   return 0;    return 0;
 }  }
 #endif  
   
   
 /* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */  /* Find the interface on which a TCP connection arrived, if possible, or zero otherwise. */
 int tcp_interface(int fd, int af)  int tcp_interface(int fd, int af)
 {   { 
     (void)fd; /* suppress potential unused warning */
     (void)af; /* suppress potential unused warning */
   int if_index = 0;    int if_index = 0;
   
 #ifdef HAVE_LINUX_NETWORK  #ifdef HAVE_LINUX_NETWORK
   int opt = 1;    int opt = 1;
   struct cmsghdr *cmptr;    struct cmsghdr *cmptr;
   struct msghdr msg;    struct msghdr msg;
     socklen_t len;
       
  /* use mshdr do that the CMSDG_* macros are available */  /* use mshdr so that the CMSDG_* macros are available */
   msg.msg_control = daemon->packet;    msg.msg_control = daemon->packet;
  msg.msg_controllen = daemon->packet_buff_sz;  msg.msg_controllen = len = daemon->packet_buff_sz;
  
   /* we overwrote the buffer... */    /* we overwrote the buffer... */
  daemon->srv_save = NULL;  daemon->srv_save = NULL; 
  
   if (af == AF_INET)    if (af == AF_INET)
     {      {
       if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&        if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) != -1 &&
          getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)          getsockopt(fd, IPPROTO_IP, IP_PKTOPTIONS, msg.msg_control, &len) != -1)
        for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))        {
          if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)          msg.msg_controllen = len;
            {          for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
              union {            if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
                unsigned char *c;              {
                struct in_pktinfo *p;                union {
              } p;                  unsigned char *c;
                                struct in_pktinfo *p;
              p.c = CMSG_DATA(cmptr);                } p;
              if_index = p.p->ipi_ifindex;                
            }                p.c = CMSG_DATA(cmptr);
                 if_index = p.p->ipi_ifindex;
               }
         }
     }      }
 #ifdef HAVE_IPV6  
   else    else
     {      {
       /* Only the RFC-2292 API has the ability to find the interface for TCP connections,        /* Only the RFC-2292 API has the ability to find the interface for TCP connections,
Line 546  int tcp_interface(int fd, int af) Line 1049  int tcp_interface(int fd, int af)
 #endif  #endif
   
       if (set_ipv6pktinfo(fd) &&        if (set_ipv6pktinfo(fd) &&
          getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, (socklen_t *)&msg.msg_controllen) != -1)          getsockopt(fd, IPPROTO_IPV6, PKTOPTIONS, msg.msg_control, &len) != -1)
         {          {
          for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))          msg.msg_controllen = len;
           for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
             if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)              if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
               {                {
                 union {                  union {
Line 561  int tcp_interface(int fd, int af) Line 1065  int tcp_interface(int fd, int af)
               }                }
         }          }
     }      }
 #endif /* IPV6 */  
 #endif /* Linux */  #endif /* Linux */
     
   return if_index;    return if_index;
Line 572  static struct listener *create_listeners(union mysocka Line 1075  static struct listener *create_listeners(union mysocka
   struct listener *l = NULL;    struct listener *l = NULL;
   int fd = -1, tcpfd = -1, tftpfd = -1;    int fd = -1, tcpfd = -1, tftpfd = -1;
   
     (void)do_tftp;
   
   if (daemon->port != 0)    if (daemon->port != 0)
     {      {
       fd = make_sock(addr, SOCK_DGRAM, dienow);        fd = make_sock(addr, SOCK_DGRAM, dienow);
Line 589  static struct listener *create_listeners(union mysocka Line 1094  static struct listener *create_listeners(union mysocka
           tftpfd = make_sock(addr, SOCK_DGRAM, dienow);            tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
           addr->in.sin_port = save;            addr->in.sin_port = save;
         }          }
 #  ifdef HAVE_IPV6  
       else        else
         {          {
           short save = addr->in6.sin6_port;            short save = addr->in6.sin6_port;
Line 597  static struct listener *create_listeners(union mysocka Line 1101  static struct listener *create_listeners(union mysocka
           tftpfd = make_sock(addr, SOCK_DGRAM, dienow);            tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
           addr->in6.sin6_port = save;            addr->in6.sin6_port = save;
         }            }  
 #  endif  
     }      }
 #endif  #endif
   
Line 605  static struct listener *create_listeners(union mysocka Line 1108  static struct listener *create_listeners(union mysocka
     {      {
       l = safe_malloc(sizeof(struct listener));        l = safe_malloc(sizeof(struct listener));
       l->next = NULL;        l->next = NULL;
       l->family = addr->sa.sa_family;  
       l->fd = fd;        l->fd = fd;
       l->tcpfd = tcpfd;        l->tcpfd = tcpfd;
       l->tftpfd = tftpfd;        l->tftpfd = tftpfd;
         l->addr = *addr;
         l->used = 1;
         l->iface = NULL;
     }      }
   
   return l;    return l;
Line 629  void create_wildcard_listeners(void) Line 1134  void create_wildcard_listeners(void)
   
   l = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);    l = create_listeners(&addr, !!option_bool(OPT_TFTP), 1);
   
 #ifdef HAVE_IPV6  
   memset(&addr, 0, sizeof(addr));    memset(&addr, 0, sizeof(addr));
#  ifdef HAVE_SOCKADDR_SA_LEN#ifdef HAVE_SOCKADDR_SA_LEN
   addr.in6.sin6_len = sizeof(addr.in6);    addr.in6.sin6_len = sizeof(addr.in6);
#  endif#endif
   addr.in6.sin6_family = AF_INET6;    addr.in6.sin6_family = AF_INET6;
   addr.in6.sin6_addr = in6addr_any;    addr.in6.sin6_addr = in6addr_any;
   addr.in6.sin6_port = htons(daemon->port);    addr.in6.sin6_port = htons(daemon->port);
Line 643  void create_wildcard_listeners(void) Line 1147  void create_wildcard_listeners(void)
     l->next = l6;      l->next = l6;
   else     else 
     l = l6;      l = l6;
 #endif  
   
   daemon->listeners = l;    daemon->listeners = l;
 }  }
   
   static struct listener *find_listener(union mysockaddr *addr)
   {
     struct listener *l;
     for (l = daemon->listeners; l; l = l->next)
       if (sockaddr_isequal(&l->addr, addr))
         return l;
     return NULL;
   }
   
 void create_bound_listeners(int dienow)  void create_bound_listeners(int dienow)
 {  {
   struct listener *new;    struct listener *new;
   struct irec *iface;    struct irec *iface;
   struct iname *if_tmp;    struct iname *if_tmp;
     struct listener *existing;
   
   for (iface = daemon->interfaces; iface; iface = iface->next)    for (iface = daemon->interfaces; iface; iface = iface->next)
    if (!iface->done && !iface->dad &&     if (!iface->done && !iface->dad && iface->found)
        (new = create_listeners(&iface->addr, iface->tftp_ok, dienow))) 
       {        {
        new->iface = iface;        existing = find_listener(&iface->addr);
        new->next = daemon->listeners;        if (existing)
        daemon->listeners = new;          {
        iface->done = 1;            iface->done = 1;
             existing->used++; /* increase usage counter */
           }
         else if ((new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
           {
             new->iface = iface;
             new->next = daemon->listeners;
             daemon->listeners = new;
             iface->done = 1;
 
             /* Don't log the initial set of listen addresses created
                at startup, since this is happening before the logging
                system is initialised and the sign-on printed. */
             if (!dienow)
               {
                 int port = prettyprint_addr(&iface->addr, daemon->addrbuff);
                 my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s(#%d): %s port %d"),
                           iface->name, iface->index, daemon->addrbuff, port);
               }
           }
       }        }
   
   /* Check for --listen-address options that haven't been used because there's    /* Check for --listen-address options that haven't been used because there's
Line 679  void create_bound_listeners(int dienow) Line 1210  void create_bound_listeners(int dienow)
     if (!if_tmp->used &&       if (!if_tmp->used && 
         (new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))          (new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))
       {        {
         new->iface = NULL;  
         new->next = daemon->listeners;          new->next = daemon->listeners;
         daemon->listeners = new;          daemon->listeners = new;
   
           if (!dienow)
             {
               int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
               my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);
             }
       }        }
 }  }
   
   /* In --bind-interfaces, the only access control is the addresses we're listening on. 
      There's nothing to avoid a query to the address of an internal interface arriving via
      an external interface where we don't want to accept queries, except that in the usual 
      case the addresses of internal interfaces are RFC1918. When bind-interfaces in use, 
      and we listen on an address that looks like it's probably globally routeable, shout.
   
      The fix is to use --bind-dynamic, which actually checks the arrival interface too.
      Tough if your platform doesn't support this.
   
      Note that checking the arrival interface is supported in the standard IPv6 API and
      always done, so we don't warn about any IPv6 addresses here.
   */
   
   void warn_bound_listeners(void)
   {
     struct irec *iface;   
     int advice = 0;
   
     for (iface = daemon->interfaces; iface; iface = iface->next)
       if (!iface->dns_auth)
         {
           if (iface->addr.sa.sa_family == AF_INET)
             {
               if (!private_net(iface->addr.in.sin_addr, 1))
                 {
                   inet_ntop(AF_INET, &iface->addr.in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
                   iface->warned = advice = 1;
                   my_syslog(LOG_WARNING, 
                             _("LOUD WARNING: listening on %s may accept requests via interfaces other than %s"),
                             daemon->addrbuff, iface->name);
                 }
             }
         }
     
     if (advice)
       my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)")); 
   }
   
   void warn_wild_labels(void)
   {
     struct irec *iface;
   
     for (iface = daemon->interfaces; iface; iface = iface->next)
       if (iface->found && iface->name && iface->label)
         my_syslog(LOG_WARNING, _("warning: using interface %s instead"), iface->name);
   }
   
   void warn_int_names(void)
   {
     struct interface_name *intname;
    
     for (intname = daemon->int_names; intname; intname = intname->next)
       if (!intname->addr)
         my_syslog(LOG_WARNING, _("warning: no addresses found for interface %s"), intname->intr);
   }
    
 int is_dad_listeners(void)  int is_dad_listeners(void)
 {  {
   struct irec *iface;    struct irec *iface;
Line 722  void join_multicast(int dienow)       Line 1314  void join_multicast(int dienow)      
                           
             inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);              inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
                           
            if (daemon->doing_dhcp6 &&            if ((daemon->doing_dhcp6 || daemon->relay6) &&
                 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)                  setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
              err = 1;              err = errno;
                           
             inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);              inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
                           
             if (daemon->doing_dhcp6 &&               if (daemon->doing_dhcp6 && 
                 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)                  setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
              err = 1;              err = errno;
                           
             inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);              inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
                           
             if (daemon->doing_ra &&              if (daemon->doing_ra &&
                 setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)                  setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
              err = 1;              err = errno;
                           
             if (err)              if (err)
               {                {
                 char *s = _("interface %s failed to join DHCPv6 multicast group: %s");                  char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
                   errno = err;
   
   #ifdef HAVE_LINUX_NETWORK
                   if (errno == ENOMEM)
                     my_syslog(LOG_ERR, _("try increasing /proc/sys/net/core/optmem_max"));
   #endif
   
                 if (dienow)                  if (dienow)
                   die(s, iface->name, EC_BADNET);                    die(s, iface->name, EC_BADNET);
                 else                  else
Line 751  void join_multicast(int dienow)       Line 1350  void join_multicast(int dienow)      
 }  }
 #endif  #endif
   
/* return a UDP socket bound to a random port, have to cope with straying intoint local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
   occupied port nos and reserved ones. */ 
int random_sock(int family) 
 {  {
  int fd;  union mysockaddr addr_copy = *addr;
   unsigned short port;
   int tries = 1;
   unsigned short ports_avail = 1;
   
  if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)  if (addr_copy.sa.sa_family == AF_INET)
    {    port = addr_copy.in.sin_port;
      union mysockaddr addr;  else
      unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;    port = addr_copy.in6.sin6_port;
      int tries = ports_avail < 30 ? 3 * ports_avail : 100; 
   
      memset(&addr, 0, sizeof(addr));  /* cannot set source _port_ for TCP connections. */
      addr.sa.sa_family = family;  if (is_tcp)
    port = 0;
      /* don't loop forever if all ports in use. */  else if (port == 0 && daemon->max_port != 0)
    {
      if (fix_fd(fd))      /* Bind a random port within the range given by min-port and max-port if either
        while(tries--)         or both are set. Otherwise use the OS's random ephemeral port allocation by
          {         leaving port == 0 and tries == 1 */
            unsigned short port = rand16();      ports_avail = daemon->max_port - daemon->min_port + 1;
                  tries =  (ports_avail < SMALL_PORT_RANGE) ? ports_avail : 100;
            if (daemon->min_port != 0)      port = htons(daemon->min_port + (rand16() % ports_avail));
              port = htons(daemon->min_port + (port % ((unsigned short)ports_avail))); 
             
            if (family == AF_INET)  
              { 
                addr.in.sin_addr.s_addr = INADDR_ANY; 
                addr.in.sin_port = port; 
#ifdef HAVE_SOCKADDR_SA_LEN 
                addr.in.sin_len = sizeof(struct sockaddr_in); 
#endif 
              } 
#ifdef HAVE_IPV6 
            else 
              { 
                addr.in6.sin6_addr = in6addr_any;  
                addr.in6.sin6_port = port; 
#ifdef HAVE_SOCKADDR_SA_LEN 
                addr.in6.sin6_len = sizeof(struct sockaddr_in6); 
#endif 
              } 
#endif 
             
            if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0) 
              return fd; 
             
            if (errno != EADDRINUSE && errno != EACCES) 
              break; 
          } 
 
      close(fd); 
     }      }
   
   return -1;   
 }  
       
     while (1)
       {
         /* elide bind() call if it's to port 0, address 0 */
         if (addr_copy.sa.sa_family == AF_INET)
           {
             if (port == 0 && addr_copy.in.sin_addr.s_addr == 0)
               break;
             addr_copy.in.sin_port = port;
           }
         else
           {
             if (port == 0 && IN6_IS_ADDR_UNSPECIFIED(&addr_copy.in6.sin6_addr))
               break;
             addr_copy.in6.sin6_port = port;
           }
         
         if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) != -1)
           break;
         
          if (errno != EADDRINUSE && errno != EACCES) 
            return 0;
   
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)      if (--tries == 0)
{        return 0;
  union mysockaddr addr_copy = *addr; 
   
  /* cannot set source _port_ for TCP connections. */      /* For small ranges, do a systematic search, not a random one. */
  if (is_tcp)      if (ports_avail < SMALL_PORT_RANGE)
         {
           unsigned short hport = ntohs(port);
           if (hport++ == daemon->max_port)
             hport = daemon->min_port;
           port = htons(hport);
         }
       else
         port = htons(daemon->min_port + (rand16() % ports_avail));
     }
 
   if (!is_tcp && ifindex > 0)
     {      {
   #if defined(IP_UNICAST_IF)
       if (addr_copy.sa.sa_family == AF_INET)        if (addr_copy.sa.sa_family == AF_INET)
        addr_copy.in.sin_port = 0;        {
#ifdef HAVE_IPV6          uint32_t ifindex_opt = htonl(ifindex);
      else          return setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
        addr_copy.in6.sin6_port = 0;        }
 #endif  #endif
   #if defined (IPV6_UNICAST_IF)
         if (addr_copy.sa.sa_family == AF_INET6)
           {
             uint32_t ifindex_opt = htonl(ifindex);
             return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
           }
   #endif
     }      }
  
  if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)  (void)intname; /* suppress potential unused warning */
    return 0; 
     
 #if defined(SO_BINDTODEVICE)  #if defined(SO_BINDTODEVICE)
   if (intname[0] != 0 &&    if (intname[0] != 0 &&
       setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)        setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
Line 836  int local_bind(int fd, union mysockaddr *addr, char *i Line 1440  int local_bind(int fd, union mysockaddr *addr, char *i
   return 1;    return 1;
 }  }
   
static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsigned int ifindex)
 {  {
   struct serverfd *sfd;    struct serverfd *sfd;
   int errsave;    int errsave;
  int opt = 1;
   
   /* when using random ports, servers which would otherwise use    /* when using random ports, servers which would otherwise use
     the INADDR_ANY/port0 socket have sfd set to NULL */     the INADDR_ANY/port0 socket have sfd set to NULL, this is 
  if (!daemon->osport && intname[0] == 0)     anything without an explictly set source port. */
   if (!daemon->osport)
     {      {
       errno = 0;        errno = 0;
               
       if (addr->sa.sa_family == AF_INET &&        if (addr->sa.sa_family == AF_INET &&
           addr->in.sin_addr.s_addr == INADDR_ANY &&  
           addr->in.sin_port == htons(0)            addr->in.sin_port == htons(0)
         return NULL;          return NULL;
   
 #ifdef HAVE_IPV6  
       if (addr->sa.sa_family == AF_INET6 &&        if (addr->sa.sa_family == AF_INET6 &&
           memcmp(&addr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 &&  
           addr->in6.sin6_port == htons(0)            addr->in6.sin6_port == htons(0)
         return NULL;          return NULL;
 #endif  
     }      }
      
   /* may have a suitable one already */    /* may have a suitable one already */
   for (sfd = daemon->sfds; sfd; sfd = sfd->next )    for (sfd = daemon->sfds; sfd; sfd = sfd->next )
    if (sockaddr_isequal(&sfd->source_addr, addr) &&    if (ifindex == sfd->ifindex &&
         sockaddr_isequal(&sfd->source_addr, addr) &&
         strcmp(intname, sfd->interface) == 0)          strcmp(intname, sfd->interface) == 0)
       return sfd;        return sfd;
       
Line 876  static struct serverfd *allocate_sfd(union mysockaddr  Line 1479  static struct serverfd *allocate_sfd(union mysockaddr 
       free(sfd);        free(sfd);
       return NULL;        return NULL;
     }      }
  
  if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))  if ((addr->sa.sa_family == AF_INET6 && setsockopt(sfd->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) ||
       !local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd))
     {       { 
      errsave = errno; /* save error from bind. */      errsave = errno; /* save error from bind/setsockopt. */
       close(sfd->fd);        close(sfd->fd);
       free(sfd);        free(sfd);
       errno = errsave;        errno = errsave;
       return NULL;        return NULL;
     }      }
    
  strcpy(sfd->interface, intname);   safe_strncpy(sfd->interface, intname, sizeof(sfd->interface)); 
   sfd->source_addr = *addr;    sfd->source_addr = *addr;
   sfd->next = daemon->sfds;    sfd->next = daemon->sfds;
     sfd->ifindex = ifindex;
     sfd->preallocated = 0;
   daemon->sfds = sfd;    daemon->sfds = sfd;
   
   return sfd;     return sfd; 
 }  }
   
Line 898  static struct serverfd *allocate_sfd(union mysockaddr  Line 1505  static struct serverfd *allocate_sfd(union mysockaddr 
 void pre_allocate_sfds(void)  void pre_allocate_sfds(void)
 {  {
   struct server *srv;    struct server *srv;
     struct serverfd *sfd;
       
   if (daemon->query_port != 0)    if (daemon->query_port != 0)
     {      {
Line 909  void pre_allocate_sfds(void) Line 1517  void pre_allocate_sfds(void)
 #ifdef HAVE_SOCKADDR_SA_LEN  #ifdef HAVE_SOCKADDR_SA_LEN
       addr.in.sin_len = sizeof(struct sockaddr_in);        addr.in.sin_len = sizeof(struct sockaddr_in);
 #endif  #endif
      allocate_sfd(&addr, "");      if ((sfd = allocate_sfd(&addr, "", 0)))
#ifdef HAVE_IPV6        sfd->preallocated = 1;
 
       memset(&addr, 0, sizeof(addr));        memset(&addr, 0, sizeof(addr));
       addr.in6.sin6_family = AF_INET6;        addr.in6.sin6_family = AF_INET6;
       addr.in6.sin6_addr = in6addr_any;        addr.in6.sin6_addr = in6addr_any;
Line 918  void pre_allocate_sfds(void) Line 1527  void pre_allocate_sfds(void)
 #ifdef HAVE_SOCKADDR_SA_LEN  #ifdef HAVE_SOCKADDR_SA_LEN
       addr.in6.sin6_len = sizeof(struct sockaddr_in6);        addr.in6.sin6_len = sizeof(struct sockaddr_in6);
 #endif  #endif
      allocate_sfd(&addr, "");      if ((sfd = allocate_sfd(&addr, "", 0)))
#endif        sfd->preallocated = 1;
     }      }
       
   for (srv = daemon->servers; srv; srv = srv->next)    for (srv = daemon->servers; srv; srv = srv->next)
    if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&    if (!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
        !allocate_sfd(&srv->source_addr, srv->interface) && 
         errno != 0 &&          errno != 0 &&
         option_bool(OPT_NOWILD))          option_bool(OPT_NOWILD))
       {        {
        prettyprint_addr(&srv->source_addr, daemon->namebuff);        (void)prettyprint_addr(&srv->source_addr, daemon->namebuff);
         if (srv->interface[0] != 0)          if (srv->interface[0] != 0)
           {            {
             strcat(daemon->namebuff, " ");              strcat(daemon->namebuff, " ");
Line 939  void pre_allocate_sfds(void) Line 1547  void pre_allocate_sfds(void)
       }          }  
 }  }
   
void check_servers(int no_loop_check)
void check_servers(void) 
 {  {
   struct irec *iface;    struct irec *iface;
  struct server *new, *tmp, *ret = NULL;  struct server *serv;
  int port = 0;  struct serverfd *sfd, *tmp, **up;
   int port = 0, count;
   int locals = 0;
   
 #ifdef HAVE_LOOP
   if (!no_loop_check)
     loop_send_probes();
 #endif
   
  /* interface may be new since startup */  /* clear all marks. */
  if (!option_bool(OPT_NOWILD))  mark_servers(0);
    enumerate_interfaces(); 
       
  for (new = daemon->servers; new; new = tmp) /* interface may be new since startup */
    {  if (!option_bool(OPT_NOWILD))
      tmp = new->next;    enumerate_interfaces(0);
       
      if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) 
        { 
          port = prettyprint_addr(&new->addr, daemon->namebuff); 
   
          /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */  /* don't garbage collect pre-allocated sfds. */
          if (new->addr.sa.sa_family == AF_INET &&  for (sfd = daemon->sfds; sfd; sfd = sfd->next)
              new->addr.in.sin_addr.s_addr == 0)    sfd->used = sfd->preallocated;
            { 
              free(new); 
              continue; 
            } 
   
          for (iface = daemon->interfaces; iface; iface = iface->next)  for (count = 0, serv = daemon->servers; serv; serv = serv->next)
            if (sockaddr_isequal(&new->addr, &iface->addr))    {
              break;      /* Init edns_pktsz for newly created server records. */
          if (iface)      if (serv->edns_pktsz == 0)
            {        serv->edns_pktsz = daemon->edns_pktsz;
              my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);      
              free(new);#ifdef HAVE_DNSSEC
              continue;      if (option_bool(OPT_DNSSEC_VALID))
            }        { 
           if (!(serv->flags & SERV_FOR_NODOTS))
             serv->flags |= SERV_DO_DNSSEC;
                       
          /* Do we need a socket set? */          /* Disable DNSSEC validation when using server=/domain/.... servers
          if (!new->sfd &&              unless there's a configured trust anchor. */
              !(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&          if (strlen(serv->domain) != 0)
              errno != 0) 
             {              {
              my_syslog(LOG_WARNING,               struct ds_config *ds;
                        _("ignoring nameserver %s - cannot make/bind socket: %s"),              char *domain = serv->domain;
                        daemon->namebuff, strerror(errno));              
              free(new);              /* .example.com is valid */
              continue;              while (*domain == '.')
                 domain++;
               
               for (ds = daemon->ds; ds; ds = ds->next)
                 if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
                   break;
               
               if (!ds)
                 serv->flags &= ~SERV_DO_DNSSEC;
             }              }
         }          }
   #endif
               
      /* reverse order - gets it right. */      port = prettyprint_addr(&serv->addr, daemon->namebuff);
      new->next = ret; 
      ret = new; 
               
      if (!(new->flags & SERV_NO_REBIND))      /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
       if (serv->addr.sa.sa_family == AF_INET &&
           serv->addr.in.sin_addr.s_addr == 0)
         {          {
          if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))          serv->flags |= SERV_MARK;
            {          continue;
              char *s1, *s2;        }
              if (!(new->flags & SERV_HAS_DOMAIN))      
                s1 = _("unqualified"), s2 = _("names");      for (iface = daemon->interfaces; iface; iface = iface->next)
              else if (strlen(new->domain) == 0)        if (sockaddr_isequal(&serv->addr, &iface->addr))
                s1 = _("default"), s2 = "";          break;
              else      if (iface)
                s1 = _("domain"), s2 = new->domain;        {
                        my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
              if (new->flags & SERV_NO_ADDR)          serv->flags |= SERV_MARK;
                my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);          continue;
              else if (new->flags & SERV_USE_RESOLV)        }
                my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);      
              else if (!(new->flags & SERV_LITERAL_ADDRESS))      /* Do we need a socket set? */
                my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);      if (!serv->sfd && 
            }          !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
          else if (new->interface[0] != 0)          errno != 0)
            my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);         {
           my_syslog(LOG_WARNING, 
                     _("ignoring nameserver %s - cannot make/bind socket: %s"),
                     daemon->namebuff, strerror(errno));
           serv->flags |= SERV_MARK;
           continue;
         }
       
       if (serv->sfd)
         serv->sfd->used = 1;
       
       if (count == SERVERS_LOGGED)
         my_syslog(LOG_INFO, _("more servers are defined but not logged"));
       
       if (++count > SERVERS_LOGGED)
         continue;
       
       if (strlen(serv->domain) != 0 || (serv->flags & SERV_FOR_NODOTS))
         {
           char *s1, *s2, *s3 = "", *s4 = "";
 
 #ifdef HAVE_DNSSEC
           if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
             s3 = _("(no DNSSEC)");
 #endif
           if (serv->flags & SERV_FOR_NODOTS)
             s1 = _("unqualified"), s2 = _("names");
           else if (strlen(serv->domain) == 0)
             s1 = _("default"), s2 = "";
           else            else
            my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);             s1 = _("domain"), s2 = serv->domain, s4 = (serv->flags & SERV_WILDCARD) ? "*" : "";
           
           my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s%s %s"), daemon->namebuff, port, s1, s4, s2, s3);
         }          }
   #ifdef HAVE_LOOP
         else if (serv->flags & SERV_LOOP)
           my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port); 
   #endif
         else if (serv->interface[0] != 0)
           my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface); 
         else
           my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port); 
   
     }      }
       
  daemon->servers = ret;  for (count = 0, serv = daemon->local_domains; serv; serv = serv->next)
     {
        if (++count > SERVERS_LOGGED)
          continue;
        
        if ((serv->flags & SERV_LITERAL_ADDRESS) &&
            !(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)) &&
            strlen(serv->domain))
          {
            count--;
            if (++locals <= LOCALS_LOGGED)
              my_syslog(LOG_INFO, _("using only locally-known addresses for %s"), serv->domain);
          }
        else if (serv->flags & SERV_USE_RESOLV)
          my_syslog(LOG_INFO, _("using standard nameservers for %s"), serv->domain);
     }
   
   if (locals > LOCALS_LOGGED)
     my_syslog(LOG_INFO, _("using %d more local addresses"), locals - LOCALS_LOGGED);
   if (count - 1 > SERVERS_LOGGED)
     my_syslog(LOG_INFO, _("using %d more nameservers"), count - SERVERS_LOGGED - 1);
 
   /* Remove unused sfds */
   for (sfd = daemon->sfds, up = &daemon->sfds; sfd; sfd = tmp)
     {
        tmp = sfd->next;
        if (!sfd->used) 
         {
           *up = sfd->next;
           close(sfd->fd);
           free(sfd);
         } 
       else
         up = &sfd->next;
     }
   
   cleanup_servers(); /* remove servers we just deleted. */
   build_server_array(); 
 }  }
   
 /* Return zero if no servers found, in that case we keep polling.  /* Return zero if no servers found, in that case we keep polling.
Line 1028  int reload_servers(char *fname) Line 1719  int reload_servers(char *fname)
 {  {
   FILE *f;    FILE *f;
   char *line;    char *line;
   struct server *old_servers = NULL;  
   struct server *new_servers = NULL;  
   struct server *serv;  
   int gotone = 0;    int gotone = 0;
   
   /* buff happens to be MAXDNAME long... */    /* buff happens to be MAXDNAME long... */
Line 1039  int reload_servers(char *fname) Line 1727  int reload_servers(char *fname)
       my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));        my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
       return 0;        return 0;
     }      }
     
  /* move old servers to free list - we can reuse the memory   mark_servers(SERV_FROM_RESOLV);
     and not risk malloc if there are the same or fewer new servers.     
     Servers which were specced on the command line go to the new list. */ 
  for (serv = daemon->servers; serv;) 
    { 
      struct server *tmp = serv->next; 
      if (serv->flags & SERV_FROM_RESOLV) 
        { 
          serv->next = old_servers; 
          old_servers = serv;  
          /* forward table rules reference servers, so have to blow them away */ 
          server_gone(serv); 
        } 
      else 
        { 
          serv->next = new_servers; 
          new_servers = serv; 
        } 
      serv = tmp; 
    } 
   
   while ((line = fgets(daemon->namebuff, MAXDNAME, f)))    while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
     {      {
       union mysockaddr addr, source_addr;        union mysockaddr addr, source_addr;
Line 1076  int reload_servers(char *fname) Line 1745  int reload_servers(char *fname)
       memset(&addr, 0, sizeof(addr));        memset(&addr, 0, sizeof(addr));
       memset(&source_addr, 0, sizeof(source_addr));        memset(&source_addr, 0, sizeof(source_addr));
               
      if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)      if (inet_pton(AF_INET, token, &addr.in.sin_addr) > 0)
         {          {
 #ifdef HAVE_SOCKADDR_SA_LEN  #ifdef HAVE_SOCKADDR_SA_LEN
           source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);            source_addr.in.sin_len = addr.in.sin_len = sizeof(source_addr.in);
Line 1086  int reload_servers(char *fname) Line 1755  int reload_servers(char *fname)
           source_addr.in.sin_addr.s_addr = INADDR_ANY;            source_addr.in.sin_addr.s_addr = INADDR_ANY;
           source_addr.in.sin_port = htons(daemon->query_port);            source_addr.in.sin_port = htons(daemon->query_port);
         }          }
 #ifdef HAVE_IPV6  
       else         else 
         {                 {       
           int scope_index = 0;            int scope_index = 0;
Line 1114  int reload_servers(char *fname) Line 1782  int reload_servers(char *fname)
           else            else
             continue;              continue;
         }          }
 #else /* IPV6 */  
       else  
         continue;  
 #endif   
   
      if (old_servers)      add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL, NULL);
        { 
          serv = old_servers; 
          old_servers = old_servers->next; 
        } 
      else if (!(serv = whine_malloc(sizeof (struct server)))) 
        continue; 
       
      /* this list is reverse ordered:  
         it gets reversed again in check_servers */ 
      serv->next = new_servers; 
      new_servers = serv; 
      serv->addr = addr; 
      serv->source_addr = source_addr; 
      serv->domain = NULL; 
      serv->interface[0] = 0; 
      serv->sfd = NULL; 
      serv->flags = SERV_FROM_RESOLV; 
      serv->queries = serv->failed_queries = 0; 
       gotone = 1;        gotone = 1;
     }      }
       
   /* Free any memory not used. */  
   while (old_servers)  
     {  
       struct server *tmp = old_servers->next;  
       free(old_servers);  
       old_servers = tmp;  
     }  
   
   daemon->servers = new_servers;  
   fclose(f);    fclose(f);
     cleanup_servers();
   
   return gotone;    return gotone;
 }  }
   
/* Called when addresses are added or deleted from an interface */
/* Use an IPv4 listener socket for ioctling */void newaddress(time_t now)
struct in_addr get_ifaddr(char *intr) 
 {  {
  struct listener *l;  struct dhcp_relay *relay;
  struct ifreq ifr;
  struct sockaddr_in ret;  (void)now;
       
  ret.sin_addr.s_addr = -1;  if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
       daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
     enumerate_interfaces(0);
   
   if (option_bool(OPT_CLEVERBIND))
     create_bound_listeners(0);
   
  for (l = daemon->listeners; #ifdef HAVE_DHCP
       l && (l->family != AF_INET || l->fd == -1);  /* clear cache of subnet->relay index */
       l = l->next);  for (relay = daemon->relay4; relay; relay = relay->next)
     relay->iface_index = 0;
 #endif
       
  strncpy(ifr.ifr_name, intr, IF_NAMESIZE);#ifdef HAVE_DHCP6
  ifr.ifr_addr.sa_family = AF_INET;  if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
     join_multicast(0);
       
  if (l &&  ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)  if (daemon->doing_dhcp6 || daemon->doing_ra)
    memcpy(&ret, &ifr.ifr_addr, sizeof(ret));     dhcp_construct_contexts(now);
       
  return ret.sin_addr;  if (daemon->doing_dhcp6)
}    lease_find_interfaces(now);
   
  for (relay = daemon->relay6; relay; relay = relay->next)
    relay->iface_index = 0;
 #endif
 }

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


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