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

version 1.1.1.2, 2014/06/15 16:31:38 version 1.1.1.5, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2014 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 16 Line 16
   
 #include "dnsmasq.h"  #include "dnsmasq.h"
   
 #ifndef IN6_IS_ADDR_ULA  
 #define IN6_IS_ADDR_ULA(a) ((((__const uint32_t *) (a))[0] & htonl (0xfe00000)) == htonl (0xfc000000))  
 #endif  
   
 #ifdef HAVE_LINUX_NETWORK  #ifdef HAVE_LINUX_NETWORK
   
 int indextoname(int fd, int index, char *name)  int indextoname(int fd, int index, char *name)
Line 33  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 86  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 113  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, match_addr = 0;    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. */
 
     May be called with family == AF_LOCALto 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 139  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 = match_addr = 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 = match_addr = tmp->used = 1;                  ret = match_addr = tmp->used = 1;
 #endif  
             }                        }          
     }      }
       
Line 155  int iface_check(int family, struct all_addr *addr, cha Line 144  int iface_check(int family, struct all_addr *addr, cha
       if (tmp->name && wildcard_match(tmp->name, name))        if (tmp->name && wildcard_match(tmp->name, name))
         ret = 0;          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))                (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 201  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;
Line 218  int loopback_exception(int fd, int family, struct all_ Line 206  int loopback_exception(int fd, int family, struct all_
    on the relevant address, but the name of the arrival interface, derived from the     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      index won't match the config. Check that we found an interface address for the arrival 
    interface: daemon->interfaces must be up-to-date. */     interface: daemon->interfaces must be up-to-date. */
int label_exception(int index, int family, struct all_addr *addr)int label_exception(int index, int family, union all_addr *addr)
 {  {
   struct irec *iface;    struct irec *iface;
   
Line 228  int label_exception(int index, int family, struct all_ Line 216  int label_exception(int index, int family, struct all_
   
   for (iface = daemon->interfaces; iface; iface = iface->next)    for (iface = daemon->interfaces; iface; iface = iface->next)
     if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&      if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
        iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)        iface->addr.in.sin_addr.s_addr == addr->addr4.s_addr)
       return 1;        return 1;
   
   return 0;    return 0;
Line 240  struct iface_param { Line 228  struct iface_param {
 };  };
   
 static int iface_allowed(struct iface_param *param, int if_index, char *label,  static int iface_allowed(struct iface_param *param, int if_index, char *label,
                         union mysockaddr *addr, struct in_addr netmask, int prefixlen, int dad)                          union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags) 
 {  {
   struct irec *iface;    struct irec *iface;
  int mtu = 0, loopback;  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;
     int is_label = 0;
 #if defined(HAVE_DHCP) || defined(HAVE_TFTP)  #if defined(HAVE_DHCP) || defined(HAVE_TFTP)
   struct iname *tmp;    struct iname *tmp;
 #endif  #endif
Line 263  static int iface_allowed(struct iface_param *param, in Line 253  static int iface_allowed(struct iface_param *param, in
   if (loopback)    if (loopback)
     dhcp_ok = 0;      dhcp_ok = 0;
       
   if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)  
     mtu = ifr.ifr_mtu;  
     
   if (!label)    if (!label)
     label = ifr.ifr_name;      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 */    /* maintain a list of all addresses on all interfaces for --local-service option */
   if (option_bool(OPT_LOCAL_SERVICE))    if (option_bool(OPT_LOCAL_SERVICE))
Line 290  static int iface_allowed(struct iface_param *param, in Line 279  static int iface_allowed(struct iface_param *param, in
                       
           if (addr->sa.sa_family == AF_INET)            if (addr->sa.sa_family == AF_INET)
             {              {
              al->addr.addr.addr4 = addr->in.sin_addr;              al->addr.addr4 = addr->in.sin_addr;
               al->flags = 0;                al->flags = 0;
             }              }
 #ifdef HAVE_IPV6  
           else            else
             {              {
              al->addr.addr.addr6 = addr->in6.sin6_addr;              al->addr.addr6 = addr->in6.sin6_addr;
               al->flags = ADDRLIST_IPV6;                al->flags = ADDRLIST_IPV6;
             }               } 
 #endif  
         }          }
     }      }
       
 #ifdef HAVE_IPV6  
   if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))    if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
 #endif  
     {      {
       struct interface_name *int_name;        struct interface_name *int_name;
       struct addrlist *al;        struct addrlist *al;
Line 333  static int iface_allowed(struct iface_param *param, in Line 318  static int iface_allowed(struct iface_param *param, in
                       al->next = zone->subnet;                        al->next = zone->subnet;
                       zone->subnet = al;                        zone->subnet = al;
                       al->prefixlen = prefixlen;                        al->prefixlen = prefixlen;
                      al->addr.addr.addr4 = addr->in.sin_addr;                      al->addr.addr4 = addr->in.sin_addr;
                       al->flags = 0;                        al->flags = 0;
                     }                      }
                 }                  }
                               
 #ifdef HAVE_IPV6  
               if (addr->sa.sa_family == AF_INET6 && (name->flags & AUTH6))                if (addr->sa.sa_family == AF_INET6 && (name->flags & AUTH6))
                 {                  {
                   if (param->spare)                    if (param->spare)
Line 354  static int iface_allowed(struct iface_param *param, in Line 338  static int iface_allowed(struct iface_param *param, in
                       al->next = zone->subnet;                        al->next = zone->subnet;
                       zone->subnet = al;                        zone->subnet = al;
                       al->prefixlen = prefixlen;                        al->prefixlen = prefixlen;
                      al->addr.addr.addr6 = addr->in6.sin6_addr;                      al->addr.addr6 = addr->in6.sin6_addr;
                       al->flags = ADDRLIST_IPV6;                        al->flags = ADDRLIST_IPV6;
                     }                      }
                 }                   } 
 #endif  
                 
             }              }
 #endif  #endif
                 
       /* Update addresses from interface_names. These are a set independent        /* Update addresses from interface_names. These are a set independent
          of the set we're listening on. */             of the set we're listening on. */  
       for (int_name = daemon->int_names; int_name; int_name = int_name->next)        for (int_name = daemon->int_names; int_name; int_name = int_name->next)
        if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0 &&         if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
            (addr->sa.sa_family == int_name->family || int_name->family == 0)) 
           {            {
            if (param->spare)            struct addrlist *lp;
 
             al = NULL;
             
             if (addr->sa.sa_family == AF_INET && (int_name->flags & (IN4 | INP4)))
               {                {
                al = param->spare;                struct in_addr newaddr = addr->in.sin_addr;
                param->spare = al->next;                
                 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;
                       }
                   }
               }                }
            else
              al = whine_malloc(sizeof(struct addrlist));            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)              if (al)
               {                {
                 al->next = int_name->addr;                  al->next = int_name->addr;
                 int_name->addr = al;                  int_name->addr = al;
                   
                 if (addr->sa.sa_family == AF_INET)  
                   {  
                     al->addr.addr.addr4 = addr->in.sin_addr;  
                     al->flags = 0;  
                   }  
 #ifdef HAVE_IPV6  
                 else  
                  {  
                     al->addr.addr.addr6 = addr->in6.sin6_addr;  
                     al->flags = ADDRLIST_IPV6;  
                  }   
 #endif  
               }                }
           }            }
     }      }
 
   /* 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;
       }
   
   /* check whether the interface IP has been added already     /* check whether the interface IP has been added already 
      we call this routine multiple times. */       we call this routine multiple times. */
   for (iface = daemon->interfaces; iface; iface = iface->next)     for (iface = daemon->interfaces; iface; iface = iface->next) 
    if (sockaddr_isequal(&iface->addr, addr))    if (sockaddr_isequal(&iface->addr, addr) && iface->index == if_index)
       {        {
        iface->dad = dad;        iface->dad = !!(iface_flags & IFACE_TENTATIVE);
         iface->found = 1; /* for garbage collection */          iface->found = 1; /* for garbage collection */
           iface->netmask = netmask;
         return 1;          return 1;
       }        }
   
Line 432  static int iface_allowed(struct iface_param *param, in Line 520  static int iface_allowed(struct iface_param *param, in
     }      }
       
   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, label, &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, label, &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 472  static int iface_allowed(struct iface_param *param, in Line 558  static int iface_allowed(struct iface_param *param, in
   /* 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->found = 1;        iface->found = 1;
       iface->done = iface->multicast_done = iface->warned = 0;        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);
Line 497  static int iface_allowed(struct iface_param *param, in Line 589  static int iface_allowed(struct iface_param *param, in
   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 523  static int iface_allowed_v6(struct in6_addr *local, in Line 614  static int iface_allowed_v6(struct in6_addr *local, in
   else    else
     addr.in6.sin6_scope_id = 0;      addr.in6.sin6_scope_id = 0;
       
  return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, !!(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, char *label,  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;    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);
   
Line 547  static int iface_allowed_v4(struct in_addr local, int  Line 638  static int iface_allowed_v4(struct in_addr local, int 
   
   return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);    return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
 }  }
   
 /*
  * Clean old interfaces no longer found.
  */
 static void clean_interfaces()
 {
   struct irec *iface;
   struct irec **up = &daemon->interfaces;
 
   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)  int enumerate_interfaces(int reset)
 {  {
   static struct addrlist *spare = NULL;    static struct addrlist *spare = NULL;
  static int done = 0, active = 0;  static int done = 0;
   struct iface_param param;    struct iface_param param;
   int errsave, ret = 1;    int errsave, ret = 1;
   struct addrlist *addr, *tmp;    struct addrlist *addr, *tmp;
   struct interface_name *intname;    struct interface_name *intname;
     struct cond_domain *cond;
   struct irec *iface;    struct irec *iface;
 #ifdef HAVE_AUTH  #ifdef HAVE_AUTH
   struct auth_zone *zone;    struct auth_zone *zone;
 #endif  #endif
  struct server *serv;
   
   /* Do this max once per select cycle  - also inhibits netlink socket use    /* Do this max once per select cycle  - also inhibits netlink socket use
    in TCP child processes. */     in TCP child processes. */
   
Line 570  int enumerate_interfaces(int reset) Line 738  int enumerate_interfaces(int reset)
       return 1;        return 1;
     }      }
   
  if (done || active)  if (done)
     return 1;      return 1;
   
   done = 1;    done = 1;
   
   /* protect against recusive calls from iface_enumerate(); */  
   active = 1;  
   
   if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)    if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
     return 0;      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 */    /* Mark interfaces for garbage collection */
   for (iface = daemon->interfaces; iface; iface = iface->next)     for (iface = daemon->interfaces; iface; iface = iface->next) 
     iface->found = 0;      iface->found = 0;
Line 598  int enumerate_interfaces(int reset) Line 782  int enumerate_interfaces(int reset)
       intname->addr = NULL;        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 */    /* Remove list of addresses of local interfaces */
   for (addr = daemon->interface_addrs; addr; addr = tmp)    for (addr = daemon->interface_addrs; addr; addr = tmp)
     {      {
Line 631  int enumerate_interfaces(int reset) Line 828  int enumerate_interfaces(int reset)
   
   param.spare = spare;    param.spare = spare;
       
 #ifdef HAVE_IPV6  
   ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);    ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
#endif  if (ret < 0)
    goto again;
  if (ret)  else if (ret)
    ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);     {
       ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
       if (ret < 0)
         goto again;
     }
     
   errsave = errno;    errsave = errno;
   close(param.fd);    close(param.fd);
Line 646  int enumerate_interfaces(int reset) Line 846  int enumerate_interfaces(int reset)
       /* Garbage-collect listeners listening on addresses that no longer exist.        /* Garbage-collect listeners listening on addresses that no longer exist.
          Does nothing when not binding interfaces or for listeners on localhost,            Does nothing when not binding interfaces or for listeners on localhost, 
          since the ->iface field is NULL. Note that this needs the protections           since the ->iface field is NULL. Note that this needs the protections
         against re-entrancy, hence it's here.  It also means there's a possibility,         against reentrancy, hence it's here.  It also means there's a possibility,
          in OPT_CLEVERBIND mode, that at listener will just disappear after           in OPT_CLEVERBIND mode, that at listener will just disappear after
          a call to enumerate_interfaces, this is checked OK on all calls. */           a call to enumerate_interfaces, this is checked OK on all calls. */
       struct listener *l, *tmp, **up;        struct listener *l, *tmp, **up;
         int freed = 0;
               
       for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)        for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
         {          {
Line 657  int enumerate_interfaces(int reset) Line 858  int enumerate_interfaces(int reset)
                       
           if (!l->iface || l->iface->found)            if (!l->iface || l->iface->found)
             up = &l->next;              up = &l->next;
          else          else if (release_listener(l))
             {              {
              *up = l->next;              *up = tmp;
                            freed = 1;
              /* 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); 
             }              }
         }          }
   
         if (freed)
           clean_interfaces();
     }      }
  
   errno = errsave;    errno = errsave;
     
   spare = param.spare;    spare = param.spare;
   active = 0;  
       
   return ret;    return ret;
 }  }
Line 703  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, errsav;      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 713  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:
      errsav = errno;      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 722  static int make_sock(union mysockaddr *addr, int type, Line 913  static int make_sock(union mysockaddr *addr, int type,
       if (fd != -1)        if (fd != -1)
         close (fd);          close (fd);
                   
      errno = errsav;      errno = errsave;
   
       if (dienow)        if (dienow)
         {          {
Line 740  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 (family == AF_INET)    else if (family == AF_INET)
Line 767  static int make_sock(union mysockaddr *addr, int type, Line 961  static int make_sock(union mysockaddr *addr, int type,
 #endif  #endif
         }          }
     }      }
 #ifdef HAVE_IPV6  
   else if (!set_ipv6pktinfo(fd))    else if (!set_ipv6pktinfo(fd))
     goto err;      goto err;
 #endif  
       
   return fd;    return fd;
 }  }
   
 #ifdef HAVE_IPV6    
 int set_ipv6pktinfo(int fd)  int set_ipv6pktinfo(int fd)
 {  {
   int opt = 1;    int opt = 1;
Line 802  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 854  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 869  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 899  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 907  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 915  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;        l->iface = NULL;
     }      }
   
Line 940  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 954  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 && iface->found &&    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 992  void create_bound_listeners(int dienow) Line 1212  void create_bound_listeners(int dienow)
       {        {
         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);
             }
       }        }
 }  }
   
Line 1033  void warn_bound_listeners(void) Line 1259  void warn_bound_listeners(void)
     my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"));       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)  void warn_int_names(void)
 {  {
   struct interface_name *intname;    struct interface_name *intname;
Line 1081  void join_multicast(int dienow)       Line 1316  void join_multicast(int dienow)      
                           
             if ((daemon->doing_dhcp6 || daemon->relay6) &&              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 1108  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 1193  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 1233  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 1255  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 1266  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 1275  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 1296  void pre_allocate_sfds(void) Line 1547  void pre_allocate_sfds(void)
       }          }  
 }  }
   
void mark_servers(int flag)void check_servers(int no_loop_check)
 {  {
     struct irec *iface;
   struct server *serv;    struct server *serv;
  struct serverfd *sfd, *tmp, **up;
  /* mark everything with argument flag */  int port = 0, count;
  for (serv = daemon->servers; serv; serv = serv->next)  int locals = 0;
    if (serv->flags & flag) 
      serv->flags |= SERV_MARK; 
} 
 
void cleanup_servers(void) 
{ 
  struct server *serv, *tmp, **up; 
 
  /* unlink and free anything still marked. */ 
  for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)  
    { 
      tmp = serv->next; 
      if (serv->flags & SERV_MARK) 
       { 
         server_gone(serv); 
         *up = serv->next; 
         if (serv->domain) 
           free(serv->domain); 
         free(serv); 
       } 
      else  
       up = &serv->next; 
    } 
} 
 
void add_update_server(int flags, 
                       union mysockaddr *addr, 
                       union mysockaddr *source_addr, 
                       const char *interface, 
                       const char *domain) 
{ 
  struct server *serv, *next = NULL; 
  char *domain_str = NULL; 
       
  /* See if there is a suitable candidate, and unmark */#ifdef HAVE_LOOP
  for (serv = daemon->servers; serv; serv = serv->next)  if (!no_loop_check)
    if (serv->flags & SERV_MARK)    loop_send_probes();
      {#endif
        if (domain) 
          { 
            if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain)) 
              continue; 
          } 
        else 
          { 
            if (serv->flags & SERV_HAS_DOMAIN) 
              continue; 
          } 
         
        break; 
      } 
   
  if (serv)  /* clear all marks. */
    {  mark_servers(0);
      domain_str = serv->domain; 
      next = serv->next; 
    } 
  else if ((serv = whine_malloc(sizeof (struct server)))) 
    { 
      /* Not found, create a new one. */ 
      if (domain && !(domain_str = whine_malloc(strlen(domain)+1))) 
        { 
          free(serv); 
          serv = NULL; 
        } 
      else 
        { 
          struct server *s; 
          /* Add to the end of the chain, for order */ 
          if (!daemon->servers) 
            daemon->servers = serv; 
          else 
            { 
              for (s = daemon->servers; s->next; s = s->next); 
              s->next = serv; 
            } 
          if (domain) 
            strcpy(domain_str, domain); 
        } 
    } 
       
  if (serv) /* interface may be new since startup */
    { 
      memset(serv, 0, sizeof(struct server)); 
      serv->flags = flags; 
      serv->domain = domain_str; 
      serv->next = next; 
      serv->queries = serv->failed_queries = 0; 
       
      if (domain) 
        serv->flags |= SERV_HAS_DOMAIN; 
       
      if (interface) 
        strcpy(serv->interface, interface);       
      if (addr) 
        serv->addr = *addr; 
      if (source_addr) 
        serv->source_addr = *source_addr; 
    } 
} 
 
void check_servers(void) 
{ 
  struct irec *iface; 
  struct server *serv; 
  int port = 0; 
 
  /* interface may be new since startup */ 
   if (!option_bool(OPT_NOWILD))    if (!option_bool(OPT_NOWILD))
     enumerate_interfaces(0);      enumerate_interfaces(0);
     
   for (serv = daemon->servers; serv; serv = serv->next)  
     {  
        if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))  
         {  
           port = prettyprint_addr(&serv->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 (serv->addr.sa.sa_family == AF_INET &&  for (sfd = daemon->sfds; sfd; sfd = sfd->next)
              serv->addr.in.sin_addr.s_addr == 0)    sfd->used = sfd->preallocated;
            { 
              serv->flags |= SERV_MARK; 
              continue; 
            } 
   
          for (iface = daemon->interfaces; iface; iface = iface->next)  for (count = 0, serv = daemon->servers; serv; serv = serv->next)
            if (sockaddr_isequal(&serv->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);      
              serv->flags |= SERV_MARK;#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 (!serv->sfd &&              unless there's a configured trust anchor. */
              !(serv->sfd = allocate_sfd(&serv->source_addr, serv->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));              
              serv->flags |= SERV_MARK;              /* .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
               
      if (!(serv->flags & SERV_NO_REBIND))      port = prettyprint_addr(&serv->addr, daemon->namebuff);
       
       /* 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 (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))          serv->flags |= SERV_MARK;
            {          continue;
              char *s1, *s2;        }
              if (!(serv->flags & SERV_HAS_DOMAIN))      
                s1 = _("unqualified"), s2 = _("names");      for (iface = daemon->interfaces; iface; iface = iface->next)
              else if (strlen(serv->domain) == 0)        if (sockaddr_isequal(&serv->addr, &iface->addr))
                s1 = _("default"), s2 = "";          break;
              else      if (iface)
                s1 = _("domain"), s2 = serv->domain;        {
                        my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
              if (serv->flags & SERV_NO_ADDR)          serv->flags |= SERV_MARK;
                my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);          continue;
              else if (serv->flags & SERV_USE_RESOLV)        }
                my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);      
              else if (!(serv->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 (serv->interface[0] != 0)          errno != 0)
            my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->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); 
   
     }      }
     
     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);
   
  cleanup_servers();  /* 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 1511  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 1521  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 1549  int reload_servers(char *fname) Line 1782  int reload_servers(char *fname)
           else            else
             continue;              continue;
         }          }
 #else /* IPV6 */  
       else  
         continue;  
 #endif   
   
      add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL);      add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL, NULL);
       gotone = 1;        gotone = 1;
     }      }
       
Line 1564  int reload_servers(char *fname) Line 1793  int reload_servers(char *fname)
   return gotone;    return gotone;
 }  }
   
 #if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)  
 /* Called when addresses are added or deleted from an interface */  /* Called when addresses are added or deleted from an interface */
 void newaddress(time_t now)  void newaddress(time_t now)
 {  {
     struct dhcp_relay *relay;
   
   (void)now;    (void)now;
       
   if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||    if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
Line 1576  void newaddress(time_t now) Line 1806  void newaddress(time_t now)
       
   if (option_bool(OPT_CLEVERBIND))    if (option_bool(OPT_CLEVERBIND))
     create_bound_listeners(0);      create_bound_listeners(0);
   
   #ifdef HAVE_DHCP
     /* clear cache of subnet->relay index */
     for (relay = daemon->relay4; relay; relay = relay->next)
       relay->iface_index = 0;
   #endif
       
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
   if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)    if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
Line 1586  void newaddress(time_t now) Line 1822  void newaddress(time_t now)
       
   if (daemon->doing_dhcp6)    if (daemon->doing_dhcp6)
     lease_find_interfaces(now);      lease_find_interfaces(now);
 #endif  
 }  
   
     for (relay = daemon->relay6; relay; relay = relay->next)
       relay->iface_index = 0;
 #endif  #endif
}
 
 
 

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


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