Diff for /embedaddon/dnsmasq/src/dhcp.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 20 Line 20
   
 struct iface_param {  struct iface_param {
   struct dhcp_context *current;    struct dhcp_context *current;
   struct dhcp_relay *relay;  
   struct in_addr relay_local;  
   int ind;    int ind;
 };  };
   
Line 34  static int complete_context(struct in_addr local, int  Line 32  static int complete_context(struct in_addr local, int 
                             struct in_addr netmask, struct in_addr broadcast, void *vparam);                              struct in_addr netmask, struct in_addr broadcast, void *vparam);
 static int check_listen_addrs(struct in_addr local, int if_index, char *label,  static int check_listen_addrs(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);
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz);
 static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);  static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
   
 static int make_fd(int port)  static int make_fd(int port)
Line 177  void dhcp_packet(time_t now, int pxe_fd) Line 175  void dhcp_packet(time_t now, int pxe_fd)
   if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||     if ((sz = recv_dhcp_packet(fd, &msg)) == -1 || 
       (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))         (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))) 
     return;      return;
      
  #if defined (HAVE_LINUX_NETWORK)#ifdef HAVE_DUMPFILE
   dump_packet_udp(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, NULL, fd);
 #endif
   
 #if defined (HAVE_LINUX_NETWORK)
   if (ioctl(fd, SIOCGSTAMP, &tv) == 0)    if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
     recvtime = tv.tv_sec;      recvtime = tv.tv_sec;
  
   if (msg.msg_controllen >= sizeof(struct cmsghdr))    if (msg.msg_controllen >= sizeof(struct cmsghdr))
     for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))      for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
       if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)        if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
Line 302  void dhcp_packet(time_t now, int pxe_fd) Line 304  void dhcp_packet(time_t now, int pxe_fd)
       for (context = daemon->dhcp; context; context = context->next)        for (context = daemon->dhcp; context; context = context->next)
         context->current = context;          context->current = context;
               
       for (relay = daemon->relay4; relay; relay = relay->next)  
         relay->current = relay;  
         
       parm.current = NULL;        parm.current = NULL;
       parm.relay = NULL;  
       parm.relay_local.s_addr = 0;  
       parm.ind = iface_index;        parm.ind = iface_index;
               
       if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NULL))        if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NULL))
Line 329  void dhcp_packet(time_t now, int pxe_fd) Line 326  void dhcp_packet(time_t now, int pxe_fd)
              there is more than one address on the interface in the same subnet */               there is more than one address on the interface in the same subnet */
           complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);            complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
         }              }    
               
         if (relay_upstream4(iface_index, mess, (size_t)sz))
           return;
               
       if (!iface_enumerate(AF_INET, &parm, complete_context))        if (!iface_enumerate(AF_INET, &parm, complete_context))
         return;          return;
   
      /* We're relaying this request */      /* Check for a relay again after iface_enumerate/complete_context has had
      if  (parm.relay_local.s_addr != 0 &&         chance to fill in relay->iface_index fields. This handles first time through
           relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))         and any changes in interface config. */
        if (relay_upstream4(iface_index, mess, (size_t)sz))
         return;          return;
       
       /* May have configured relay, but not DHCP server */        /* May have configured relay, but not DHCP server */
       if (!daemon->dhcp)        if (!daemon->dhcp)
         return;          return;
Line 455  void dhcp_packet(time_t now, int pxe_fd) Line 456  void dhcp_packet(time_t now, int pxe_fd)
 #elif defined(HAVE_BSD_NETWORK)  #elif defined(HAVE_BSD_NETWORK)
   else     else 
     {      {
   #ifdef HAVE_DUMPFILE
         if (ntohs(mess->flags) & 0x8000)
           dest.sin_addr.s_addr = INADDR_BROADCAST;
         else
           dest.sin_addr = mess->yiaddr;
         dest.sin_port = htons(daemon->dhcp_client_port);
         
         dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
                         (union mysockaddr *)&dest, fd);
   #endif
         
       send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);        send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
       return;        return;
     }      }
Line 463  void dhcp_packet(time_t now, int pxe_fd) Line 475  void dhcp_packet(time_t now, int pxe_fd)
 #ifdef HAVE_SOLARIS_NETWORK  #ifdef HAVE_SOLARIS_NETWORK
   setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));    setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
 #endif  #endif
   
   #ifdef HAVE_DUMPFILE
     dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
                     (union mysockaddr *)&dest, fd);
   #endif
       
   while(retry_send(sendmsg(fd, &msg, 0)));    while(retry_send(sendmsg(fd, &msg, 0)));
   
   /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */    /* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
   if (errno != 0)    if (errno != 0)
    my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),    {
              inet_ntoa(dest.sin_addr), strerror(errno));      inet_ntop(AF_INET, &dest.sin_addr, daemon->addrbuff, ADDRSTRLEN);
       my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
                 daemon->addrbuff, strerror(errno));
     }
 }  }
   
 /* check against secondary interface addresses */  /* check against secondary interface addresses */
Line 521  static void guess_range_netmask(struct in_addr addr, s Line 541  static void guess_range_netmask(struct in_addr addr, s
             !(is_same_net(addr, context->start, netmask) &&              !(is_same_net(addr, context->start, netmask) &&
               is_same_net(addr, context->end, netmask)))                is_same_net(addr, context->end, netmask)))
           {            {
            strcpy(daemon->dhcp_buff, inet_ntoa(context->start));            inet_ntop(AF_INET, &context->start, daemon->dhcp_buff, DHCP_BUFF_SZ);
            strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));            inet_ntop(AF_INET, &context->end, daemon->dhcp_buff2, DHCP_BUFF_SZ);
             inet_ntop(AF_INET, &netmask, daemon->addrbuff, ADDRSTRLEN);
             my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),              my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
                      daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));                      daemon->dhcp_buff, daemon->dhcp_buff2, daemon->addrbuff);
           }                 }     
         context->netmask = netmask;          context->netmask = netmask;
       }        }
Line 609  static int complete_context(struct in_addr local, int  Line 630  static int complete_context(struct in_addr local, int 
     }      }
   
   for (relay = daemon->relay4; relay; relay = relay->next)    for (relay = daemon->relay4; relay; relay = relay->next)
    if (if_index == param->ind && relay->local.addr4.s_addr == local.s_addr && relay->current == relay &&    if (relay->local.addr4.s_addr == local.s_addr)
        (param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))      relay->iface_index = if_index;
      {  
        relay->current = param->relay; 
        param->relay = relay; 
        param->relay_local = local;      
      } 
 
   return 1;    return 1;
 }  }
                       
Line 900  void dhcp_read_ethers(void) Line 916  void dhcp_read_ethers(void)
               
       lineno++;        lineno++;
               
      while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))      while (strlen(buff) > 0 && isspace((unsigned char)buff[strlen(buff)-1]))
         buff[strlen(buff)-1] = 0;          buff[strlen(buff)-1] = 0;
               
       if ((*buff == '#') || (*buff == '+') || (*buff == 0))        if ((*buff == '#') || (*buff == '+') || (*buff == 0))
         continue;          continue;
               
      for (ip = buff; *ip && !isspace((int)*ip); ip++);      for (ip = buff; *ip && !isspace((unsigned char)*ip); ip++);
      for(; *ip && isspace((int)*ip); ip++)      for(; *ip && isspace((unsigned char)*ip); ip++)
         *ip = 0;          *ip = 0;
       if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)        if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
         {          {
Line 922  void dhcp_read_ethers(void) Line 938  void dhcp_read_ethers(void)
               
       if (!*cp)        if (!*cp)
         {          {
          if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)          if (inet_pton(AF_INET, ip, &addr.s_addr) < 1)
             {              {
               my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);                 my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno); 
               continue;                continue;
Line 1057  char *host_from_dns(struct in_addr addr) Line 1073  char *host_from_dns(struct in_addr addr)
   return NULL;    return NULL;
 }  }
   
static int  relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz)
 {  {
  /* ->local is same value for all relays on ->current chain */  struct in_addr giaddr = mess->giaddr;
  union all_addr from;  u8 hops = mess->hops;
    struct dhcp_relay *relay;
 
   if (mess->op != BOOTREQUEST)    if (mess->op != BOOTREQUEST)
     return 0;      return 0;
   
  /* source address == relay address */  for (relay = daemon->relay4; relay; relay = relay->next)
  from.addr4 = relay->local.addr4;    if (relay->iface_index != 0 && relay->iface_index == iface_index)
       break;
 
   /* No relay config. */
   if (!relay)
     return 0;
       
  /* already gatewayed ? */  for (; relay; relay = relay->next)
  if (mess->giaddr.s_addr)    if (relay->iface_index != 0 && relay->iface_index == iface_index)
    {      {
      /* if so check if by us, to stomp on loops. */        union mysockaddr to;
      if (mess->giaddr.s_addr == relay->local.addr4.s_addr)        union all_addr from;
        return 1; 
    } 
  else 
    { 
      /* plug in our address */ 
      mess->giaddr.s_addr = relay->local.addr4.s_addr; 
    } 
   
  if ((mess->hops++) > 20)        mess->hops = hops;
    return 1;        mess->giaddr = giaddr;
         
         if ((mess->hops++) > 20)
           continue;
         
         /* source address == relay address */
         from.addr4 = relay->local.addr4;
   
  for (; relay; relay = relay->current)        /* already gatewayed ? */
    {        if (giaddr.s_addr)
      union mysockaddr to;          {
                  /* if so check if by us, to stomp on loops. */
      to.sa.sa_family = AF_INET;            if (giaddr.s_addr == relay->local.addr4.s_addr)
      to.in.sin_addr = relay->server.addr4;              continue;
      to.in.sin_port = htons(daemon->dhcp_server_port);          }
              else
      send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);          {
                  /* plug in our address */
      if (option_bool(OPT_LOG_OPTS))            mess->giaddr.s_addr = relay->local.addr4.s_addr;
           }
         
         to.sa.sa_family = AF_INET;
         to.in.sin_addr = relay->server.addr4;
         to.in.sin_port = htons(relay->port);
         
         /* Broadcasting to server. */
         if (relay->server.addr4.s_addr == 0)
           {
             struct ifreq ifr;
             
             if (relay->interface)
               safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
             
             if (!relay->interface || strchr(relay->interface, '*') ||
                 ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
               {
                 my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s"), relay->interface);
                 continue;
               }
             
             to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
           }
         
 #ifdef HAVE_DUMPFILE
         {          {
          inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);          union mysockaddr fromsock;
          my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr4));          fromsock.in.sin_port = htons(daemon->dhcp_server_port);
           fromsock.in.sin_addr = from.addr4;
           fromsock.sa.sa_family = AF_INET;
 
           dump_packet_udp(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, -1);
         }          }
      #endif
      /* Save this for replies */        
      relay->iface_index = iface_index;         send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
    }         
          if (option_bool(OPT_LOG_OPTS))
            {
              inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
              if (relay->server.addr4.s_addr == 0)
                snprintf(daemon->dhcp_buff2, DHCP_BUFF_SZ, _("broadcast via %s"), relay->interface);
              else
                inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
              my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
            }
       }
       
   return 1;    return 1;
 }  }

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


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