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

version 1.1.1.4, 2021/03/17 00:56:46 version 1.1.1.5, 2023/09/27 11:02:07
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2021 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 31  int indextoname(int fd, int index, char *name) Line 31  int indextoname(int fd, int index, char *name)
   
   safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);    safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);
   
  return 1; return 1;
 }  }
   
   
Line 114  int iface_check(int family, union all_addr *addr, char Line 114  int iface_check(int family, union all_addr *addr, char
   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 149  int iface_check(int family, union all_addr *addr, char Line 144  int iface_check(int family, union all_addr *addr, char
       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->addr4.s_addr)          break;
      break;      
    else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&      if (tmp
             IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr6))        {
      break;          *auth = 1;
          ret = 1;
  if (tmp && auth        }
    { 
      *auth = 1; 
      ret = 1; 
     }      }
   
   return ret;     return ret; 
Line 232  static int iface_allowed(struct iface_param *param, in Line 231  static int iface_allowed(struct iface_param *param, in
                          union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags)                            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;
Line 253  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    else
Line 351  static int iface_allowed(struct iface_param *param, in Line 348  static int iface_allowed(struct iface_param *param, in
       /* 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.addr4 = addr->in.sin_addr;  
                     al->flags = 0;  
                   }  
                 else  
                  {  
                     al->addr.addr6 = addr->in6.sin6_addr;  
                     al->flags = ADDRLIST_IPV6;  
                     /* 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;  
                  }   
               }                }
           }            }
     }      }
 
   /* 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) 
Line 458  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;
Line 592  static int release_listener(struct listener *l) Line 697  static int release_listener(struct listener *l)
       int port;        int port;
   
       port = prettyprint_addr(&l->iface->addr, daemon->addrbuff);        port = prettyprint_addr(&l->iface->addr, daemon->addrbuff);
      my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s port %d"),      my_syslog(LOG_DEBUG|MS_DEBUG, _("stopped listening on %s(#%d): %s port %d"),
                 l->iface->name, l->iface->index, daemon->addrbuff, port);                  l->iface->name, l->iface->index, daemon->addrbuff, port);
       /* In case it ever returns */        /* In case it ever returns */
       l->iface->done = 0;        l->iface->done = 0;
Line 617  int enumerate_interfaces(int reset) Line 722  int enumerate_interfaces(int reset)
   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 638  int enumerate_interfaces(int reset) Line 745  int enumerate_interfaces(int reset)
   
   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 656  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 690  int enumerate_interfaces(int reset) Line 829  int enumerate_interfaces(int reset)
   param.spare = spare;    param.spare = spare;
       
   ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);    ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
  if (ret < 0)
  if (ret)    goto again;
    ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);   else if (ret)
     {
       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 727  int enumerate_interfaces(int reset) Line 871  int enumerate_interfaces(int reset)
   
   errno = errsave;    errno = errsave;
   spare = param.spare;    spare = param.spare;
      
   return ret;    return ret;
 }  }
   
Line 867  int tcp_interface(int fd, int af) Line 1011  int tcp_interface(int fd, int af)
   /* use mshdr so 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 = len = 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 &&
Line 1045  void create_bound_listeners(int dienow) Line 1189  void create_bound_listeners(int dienow)
             if (!dienow)              if (!dienow)
               {                {
                 int port = prettyprint_addr(&iface->addr, daemon->addrbuff);                  int port = prettyprint_addr(&iface->addr, daemon->addrbuff);
                my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s port %d"),                my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s(#%d): %s port %d"),
                           iface->name, iface->index, daemon->addrbuff, port);                            iface->name, iface->index, daemon->addrbuff, port);
               }                }
           }            }
Line 1072  void create_bound_listeners(int dienow) Line 1216  void create_bound_listeners(int dienow)
         if (!dienow)          if (!dienow)
           {            {
             int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff);              int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
            my_syslog(LOG_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);            my_syslog(LOG_DEBUG|MS_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);
           }            }
       }        }
 }  }
Line 1206  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 into  
    occupied port nos and reserved ones. */  
 int random_sock(int family)  
 {  
   int fd;  
   
   if ((fd = socket(family, SOCK_DGRAM, 0)) != -1)  
     {  
       union mysockaddr addr;  
       unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;  
       int tries = ports_avail < 30 ? 3 * ports_avail : 100;  
   
       memset(&addr, 0, sizeof(addr));  
       addr.sa.sa_family = family;  
   
       /* don't loop forever if all ports in use. */  
   
       if (fix_fd(fd))  
         while(tries--)  
           {  
             unsigned short port = htons(daemon->min_port + (rand16() % ((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  
               }  
             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  
               }  
               
             if (bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == 0)  
               return fd;  
               
             if (errno != EADDRINUSE && errno != EACCES)  
               break;  
           }  
   
       close(fd);  
     }  
   
   return -1;   
 }  
     
   
 int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)  int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
 {  {
   union mysockaddr addr_copy = *addr;    union mysockaddr addr_copy = *addr;
   unsigned short port;    unsigned short port;
  int tries = 1, done = 0;  int tries = 1;
  unsigned int ports_avail = ((unsigned short)daemon->max_port - (unsigned short)daemon->min_port) + 1;  unsigned short ports_avail = 1;
 
   if (addr_copy.sa.sa_family == AF_INET)    if (addr_copy.sa.sa_family == AF_INET)
     port = addr_copy.in.sin_port;      port = addr_copy.in.sin_port;
   else    else
Line 1274  int local_bind(int fd, union mysockaddr *addr, char *i Line 1365  int local_bind(int fd, union mysockaddr *addr, char *i
   /* cannot set source _port_ for TCP connections. */    /* cannot set source _port_ for TCP connections. */
   if (is_tcp)    if (is_tcp)
     port = 0;      port = 0;
  else if (port == 0 && daemon->max_port != 0)
  /* Bind a random port within the range given by min-port and max-port */ 
  if (port == 0) 
     {      {
      tries = ports_avail < 30 ? 3 * ports_avail : 100;      /* Bind a random port within the range given by min-port and max-port if either
      port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));         or both are set. Otherwise use the OS's random ephemeral port allocation by
          leaving port == 0 and tries == 1 */
       ports_avail = daemon->max_port - daemon->min_port + 1;
       tries =  (ports_avail < SMALL_PORT_RANGE) ? ports_avail : 100;
       port = htons(daemon->min_port + (rand16() % ports_avail));
     }      }
       
  while (tries--)  while (1)
     {      {
         /* elide bind() call if it's to port 0, address 0 */
       if (addr_copy.sa.sa_family == AF_INET)        if (addr_copy.sa.sa_family == AF_INET)
        addr_copy.in.sin_port = port;        {
           if (port == 0 && addr_copy.in.sin_addr.s_addr == 0)
             break;
           addr_copy.in.sin_port = port;
         }
       else        else
         addr_copy.in6.sin6_port = port;  
   
       if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) != -1)  
         {          {
          done = 1;          if (port == 0 && IN6_IS_ADDR_UNSPECIFIED(&addr_copy.in6.sin6_addr))
          break;            break;
           addr_copy.in6.sin6_port = port;
         }          }
               
      if (errno != EADDRINUSE && errno != EACCES)      if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) != -1)
        return 0;        break;
               
      port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));       if (errno != EADDRINUSE && errno != EACCES) 
    }         return 0;
   
  if (!done)      if (--tries == 0)
    return 0;        return 0;
   
         /* For small ranges, do a systematic search, not a random one. */
         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 (!is_tcp && ifindex > 0)
     {      {
 #if defined(IP_UNICAST_IF)  #if defined(IP_UNICAST_IF)
Line 1332  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;
   unsigned int ifindex = 0;  
   int errsave;    int errsave;
   int opt = 1;    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;
   
       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;
     }      }
   
   if (intname && strlen(intname) != 0)  
     ifindex = if_nametoindex(intname); /* index == 0 when not binding to an interface */  
         
   /* 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 &&
        strcmp(intname, sfd->interface) == 0 &&        sockaddr_isequal(&sfd->source_addr, addr) &&
        ifindex == sfd->ifindex)         strcmp(intname, sfd->interface) == 0)
       return sfd;        return sfd;
       
   /* need to make a new one. */    /* need to make a new one. */
Line 1414  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
      if ((sfd = allocate_sfd(&addr, "")))      if ((sfd = allocate_sfd(&addr, "", 0)))
         sfd->preallocated = 1;          sfd->preallocated = 1;
   
       memset(&addr, 0, sizeof(addr));        memset(&addr, 0, sizeof(addr));
Line 1424  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
      if ((sfd = allocate_sfd(&addr, "")))      if ((sfd = allocate_sfd(&addr, "", 0)))
         sfd->preallocated = 1;          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))
       {        {
Line 1445  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 server *serv;  
   
   /* mark everything with argument flag */  
   for (serv = daemon->servers; serv; serv = serv->next)  
     {  
       if (serv->flags & flag)  
         serv->flags |= SERV_MARK;  
 #ifdef HAVE_LOOP  
       /* Give looped servers another chance */  
       serv->flags &= ~SERV_LOOP;  
 #endif  
     }  
 }  
   
 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;  
     }  
   
 #ifdef HAVE_LOOP  
   /* Now we have a new set of servers, test for loops. */  
   loop_send_probes();  
 #endif  
 }  
   
 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 */  
   for (serv = daemon->servers; serv; serv = serv->next)  
     if (serv->flags & SERV_MARK)  
       {  
         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)  
     {  
       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)  
     {  
       memset(serv, 0, sizeof(struct server));  
       serv->flags = flags;  
       serv->domain = domain_str;  
       serv->next = next;  
       serv->queries = serv->failed_queries = 0;  
 #ifdef HAVE_LOOP  
       serv->uid = rand32();  
 #endif        
   
       if (domain)  
         serv->flags |= SERV_HAS_DOMAIN;  
         
       if (interface)  
         safe_strncpy(serv->interface, interface, sizeof(serv->interface));  
       if (addr)  
         serv->addr = *addr;  
       if (source_addr)  
         serv->source_addr = *source_addr;  
     }  
 }  
   
 void check_servers(void)  
 {  
   struct irec *iface;    struct irec *iface;
   struct server *serv;    struct server *serv;
   struct serverfd *sfd, *tmp, **up;    struct serverfd *sfd, *tmp, **up;
   int port = 0, count;    int port = 0, count;
   int locals = 0;    int locals = 0;
     
   #ifdef HAVE_LOOP
     if (!no_loop_check)
       loop_send_probes();
   #endif
   
  /* interface may be new since startup */  /* clear all marks. */
   mark_servers(0);
   
  /* interface may be new since startup */
   if (!option_bool(OPT_NOWILD))    if (!option_bool(OPT_NOWILD))
     enumerate_interfaces(0);      enumerate_interfaces(0);
   
Line 1584  void check_servers(void) Line 1573  void check_servers(void)
   
   for (count = 0, serv = daemon->servers; serv; serv = serv->next)    for (count = 0, serv = daemon->servers; serv; serv = serv->next)
     {      {
      if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))      /* Init edns_pktsz for newly created server records. */
        {      if (serv->edns_pktsz == 0)
          /* Init edns_pktsz for newly created server records. */        serv->edns_pktsz = daemon->edns_pktsz;
          if (serv->edns_pktsz == 0)      
            serv->edns_pktsz = daemon->edns_pktsz; 
           
 #ifdef HAVE_DNSSEC  #ifdef HAVE_DNSSEC
          if (option_bool(OPT_DNSSEC_VALID))      if (option_bool(OPT_DNSSEC_VALID))
            {         { 
              if (!(serv->flags & SERV_FOR_NODOTS))          if (!(serv->flags & SERV_FOR_NODOTS))
                serv->flags |= SERV_DO_DNSSEC;            serv->flags |= SERV_DO_DNSSEC;
               
              /* Disable DNSSEC validation when using server=/domain/.... servers 
                 unless there's a configured trust anchor. */ 
              if (serv->flags & SERV_HAS_DOMAIN) 
                { 
                  struct ds_config *ds; 
                  char *domain = serv->domain; 
                   
                  /* .example.com is valid */ 
                  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 
 
          port = prettyprint_addr(&serv->addr, daemon->namebuff); 
                       
          /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */          /* Disable DNSSEC validation when using server=/domain/.... servers
          if (serv->addr.sa.sa_family == AF_INET &&             unless there's a configured trust anchor. */
              serv->addr.in.sin_addr.s_addr == 0)          if (strlen(serv->domain) != 0)
             {              {
              serv->flags |= SERV_MARK;              struct ds_config *ds;
              continue;              char *domain = serv->domain;
               
               /* .example.com is valid */
               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;
             }              }
   
           for (iface = daemon->interfaces; iface; iface = iface->next)  
             if (sockaddr_isequal(&serv->addr, &iface->addr))  
               break;  
           if (iface)  
             {  
               my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);  
               serv->flags |= SERV_MARK;  
               continue;  
             }  
             
           /* Do we need a socket set? */  
           if (!serv->sfd &&   
               !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface)) &&  
               errno != 0)  
             {  
               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;  
         }          }
   #endif
               
      if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))      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 (++count > SERVERS_LOGGED)          serv->flags |= SERV_MARK;
            continue;          continue;
                  }
          if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))      
            {      for (iface = daemon->interfaces; iface; iface = iface->next)
              char *s1, *s2, *s3 = "";        if (sockaddr_isequal(&serv->addr, &iface->addr))
           break;
       if (iface)
         {
           my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
           serv->flags |= SERV_MARK;
           continue;
         }
       
       /* Do we need a socket set? */
       if (!serv->sfd && 
           !(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
           errno != 0)
         {
           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  #ifdef HAVE_DNSSEC
              if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))          if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
                s3 = _("(no DNSSEC)");            s3 = _("(no DNSSEC)");
 #endif  #endif
              if (!(serv->flags & SERV_HAS_DOMAIN))          if (serv->flags & SERV_FOR_NODOTS)
                s1 = _("unqualified"), s2 = _("names");            s1 = _("unqualified"), s2 = _("names");
              else if (strlen(serv->domain) == 0)          else if (strlen(serv->domain) == 0)
                s1 = _("default"), s2 = "";            s1 = _("default"), s2 = "";
              else 
                s1 = _("domain"), s2 = serv->domain; 
               
              if (serv->flags & SERV_NO_ADDR) 
                { 
                  count--; 
                  if (++locals <= LOCALS_LOGGED) 
                        my_syslog(LOG_INFO, _("using only locally-known addresses for %s %s"), s1, s2); 
                } 
              else if (serv->flags & SERV_USE_RESOLV) 
                my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2); 
              else  
                my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, 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            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)    if (locals > LOCALS_LOGGED)
     my_syslog(LOG_INFO, _("using %d more local addresses"), locals - LOCALS_LOGGED);      my_syslog(LOG_INFO, _("using %d more local addresses"), locals - LOCALS_LOGGED);
   if (count - 1 > SERVERS_LOGGED)    if (count - 1 > SERVERS_LOGGED)
Line 1713  void check_servers(void) Line 1709  void check_servers(void)
         up = &sfd->next;          up = &sfd->next;
     }      }
       
  cleanup_servers();  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 1748  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 1786  int reload_servers(char *fname) Line 1783  int reload_servers(char *fname)
             continue;              continue;
         }          }
   
      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 1799  int reload_servers(char *fname) Line 1796  int reload_servers(char *fname)
 /* 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 1807  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 1817  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);
   
     for (relay = daemon->relay6; relay; relay = relay->next)
       relay->iface_index = 0;
 #endif  #endif
 }  }
   
   
   
   
   

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


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