File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / bpf.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 1 week ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: #include "dnsmasq.h"
   18: 
   19: #if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
   20: #include <ifaddrs.h>
   21: 
   22: #include <sys/param.h>
   23: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
   24: #include <sys/sysctl.h>
   25: #endif
   26: #include <net/if.h>
   27: #include <net/route.h>
   28: #include <net/if_dl.h>
   29: #include <netinet/if_ether.h>
   30: #if defined(__FreeBSD__)
   31: #  include <net/if_var.h> 
   32: #endif
   33: #include <netinet/in_var.h>
   34: #include <netinet6/in6_var.h>
   35: 
   36: #ifndef SA_SIZE
   37: #define SA_SIZE(sa)                                             \
   38:     (  (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?      \
   39:         sizeof(long)            :                               \
   40:         1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
   41: #endif
   42: 
   43: #ifdef HAVE_BSD_NETWORK
   44: static int del_family = 0;
   45: static union all_addr del_addr;
   46: #endif
   47: 
   48: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
   49: 
   50: int arp_enumerate(void *parm, int (*callback)())
   51: {
   52:   int mib[6];
   53:   size_t needed;
   54:   char *next;
   55:   struct rt_msghdr *rtm;
   56:   struct sockaddr_inarp *sin2;
   57:   struct sockaddr_dl *sdl;
   58:   struct iovec buff;
   59:   int rc;
   60: 
   61:   buff.iov_base = NULL;
   62:   buff.iov_len = 0;
   63: 
   64:   mib[0] = CTL_NET;
   65:   mib[1] = PF_ROUTE;
   66:   mib[2] = 0;
   67:   mib[3] = AF_INET;
   68:   mib[4] = NET_RT_FLAGS;
   69: #ifdef RTF_LLINFO
   70:   mib[5] = RTF_LLINFO;
   71: #else
   72:   mib[5] = 0;
   73: #endif	
   74:   if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
   75:     return 0;
   76: 
   77:   while (1) 
   78:     {
   79:       if (!expand_buf(&buff, needed))
   80: 	return 0;
   81:       if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
   82: 	  errno != ENOMEM)
   83: 	break;
   84:       needed += needed / 8;
   85:     }
   86:   if (rc == -1)
   87:     return 0;
   88:   
   89:   for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
   90:     {
   91:       rtm = (struct rt_msghdr *)next;
   92:       sin2 = (struct sockaddr_inarp *)(rtm + 1);
   93:       sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
   94:       if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
   95: 	return 0;
   96:     }
   97: 
   98:   return 1;
   99: }
  100: #endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
  101: 
  102: 
  103: int iface_enumerate(int family, void *parm, int (*callback)())
  104: {
  105:   struct ifaddrs *head, *addrs;
  106:   int errsave, fd = -1, ret = 0;
  107: 
  108:   if (family == AF_UNSPEC)
  109: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
  110:     return  arp_enumerate(parm, callback);
  111: #else
  112:   return 0; /* need code for Solaris and MacOS*/
  113: #endif
  114: 
  115:   /* AF_LINK doesn't exist in Linux, so we can't use it in our API */
  116:   if (family == AF_LOCAL)
  117:     family = AF_LINK;
  118: 
  119:   if (getifaddrs(&head) == -1)
  120:     return 0;
  121: 
  122: #if defined(HAVE_BSD_NETWORK)
  123:   if (family == AF_INET6)
  124:     fd = socket(PF_INET6, SOCK_DGRAM, 0);
  125: #endif
  126:   
  127:   for (addrs = head; addrs; addrs = addrs->ifa_next)
  128:     {
  129:       if (addrs->ifa_addr->sa_family == family)
  130: 	{
  131: 	  int iface_index = if_nametoindex(addrs->ifa_name);
  132: 
  133: 	  if (iface_index == 0 || !addrs->ifa_addr || 
  134: 	      (!addrs->ifa_netmask && family != AF_LINK))
  135: 	    continue;
  136: 
  137: 	  if (family == AF_INET)
  138: 	    {
  139: 	      struct in_addr addr, netmask, broadcast;
  140: 	      addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
  141: #ifdef HAVE_BSD_NETWORK
  142: 	      if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr)
  143: 		continue;
  144: #endif
  145: 	      netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
  146: 	      if (addrs->ifa_broadaddr)
  147: 		broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr; 
  148: 	      else 
  149: 		broadcast.s_addr = 0;	      
  150: 	      if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
  151: 		goto err;
  152: 	    }
  153: 	  else if (family == AF_INET6)
  154: 	    {
  155: 	      struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
  156: 	      unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
  157: 	      int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
  158: 	      int i, j, prefix = 0;
  159: 	      u32 valid = 0xffffffff, preferred = 0xffffffff;
  160: 	      int flags = 0;
  161: #ifdef HAVE_BSD_NETWORK
  162: 	      if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr))
  163: 		continue;
  164: #endif
  165: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
  166: 	      struct in6_ifreq ifr6;
  167: 
  168: 	      memset(&ifr6, 0, sizeof(ifr6));
  169: 	      safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
  170: 	      
  171: 	      ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
  172: 	      if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
  173: 		{
  174: 		  if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
  175: 		    flags |= IFACE_TENTATIVE;
  176: 		  
  177: 		  if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
  178: 		    flags |= IFACE_DEPRECATED;
  179: 
  180: #ifdef IN6_IFF_TEMPORARY
  181: 		  if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
  182: 		    flags |= IFACE_PERMANENT;
  183: #endif
  184: 
  185: #ifdef IN6_IFF_PRIVACY
  186: 		  if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
  187: 		    flags |= IFACE_PERMANENT;
  188: #endif
  189: 		}
  190: 	      
  191: 	      ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
  192: 	      if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
  193: 		{
  194: 		  valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
  195: 		  preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
  196: 		}
  197: #endif
  198: 	      	      
  199: 	      for (i = 0; i < IN6ADDRSZ; i++, prefix += 8) 
  200:                 if (netmask[i] != 0xff)
  201: 		  break;
  202: 	      
  203: 	      if (i != IN6ADDRSZ && netmask[i]) 
  204:                 for (j = 7; j > 0; j--, prefix++) 
  205: 		  if ((netmask[i] & (1 << j)) == 0)
  206: 		    break;
  207: 	      
  208: 	      /* voodoo to clear interface field in address */
  209: 	      if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
  210: 		{
  211: 		  addr->s6_addr[2] = 0;
  212: 		  addr->s6_addr[3] = 0;
  213: 		} 
  214: 	     
  215: 	      if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
  216: 				(int) preferred, (int)valid, parm)))
  217: 		goto err;	      
  218: 	    }
  219: 
  220: #ifdef HAVE_DHCP6      
  221: 	  else if (family == AF_LINK)
  222: 	    { 
  223: 	      /* Assume ethernet again here */
  224: 	      struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
  225: 	      if (sdl->sdl_alen != 0 && 
  226: 		  !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
  227: 		goto err;
  228: 	    }
  229: #endif 
  230: 	}
  231:     }
  232:   
  233:   ret = 1;
  234: 
  235:  err:
  236:   errsave = errno;
  237:   freeifaddrs(head); 
  238:   if (fd != -1)
  239:     close(fd);
  240:   errno = errsave;
  241: 
  242:   return ret;
  243: }
  244: #endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
  245: 
  246: 
  247: #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
  248: #include <net/bpf.h>
  249: 
  250: void init_bpf(void)
  251: {
  252:   int i = 0;
  253: 
  254:   while (1) 
  255:     {
  256:       sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
  257:       if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
  258: 	return;
  259: 
  260:       if (errno != EBUSY)
  261: 	die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
  262:     }	     
  263: }
  264: 
  265: void send_via_bpf(struct dhcp_packet *mess, size_t len,
  266: 		  struct in_addr iface_addr, struct ifreq *ifr)
  267: {
  268:    /* Hairy stuff, packet either has to go to the
  269:       net broadcast or the destination can't reply to ARP yet,
  270:       but we do know the physical address. 
  271:       Build the packet by steam, and send directly, bypassing
  272:       the kernel IP stack */
  273:   
  274:   struct ether_header ether; 
  275:   struct ip ip;
  276:   struct udphdr {
  277:     u16 uh_sport;               /* source port */
  278:     u16 uh_dport;               /* destination port */
  279:     u16 uh_ulen;                /* udp length */
  280:     u16 uh_sum;                 /* udp checksum */
  281:   } udp;
  282:   
  283:   u32 i, sum;
  284:   struct iovec iov[4];
  285: 
  286:   /* Only know how to do ethernet on *BSD */
  287:   if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
  288:     {
  289:       my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"), 
  290: 		mess->htype, ifr->ifr_name);
  291:       return;
  292:     }
  293:    
  294:   ifr->ifr_addr.sa_family = AF_LINK;
  295:   if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
  296:     return;
  297:   
  298:   memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
  299:   ether.ether_type = htons(ETHERTYPE_IP);
  300:   
  301:   if (ntohs(mess->flags) & 0x8000)
  302:     {
  303:       memset(ether.ether_dhost, 255,  ETHER_ADDR_LEN);
  304:       ip.ip_dst.s_addr = INADDR_BROADCAST;
  305:     }
  306:   else
  307:     {
  308:       memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN); 
  309:       ip.ip_dst.s_addr = mess->yiaddr.s_addr;
  310:     }
  311:   
  312:   ip.ip_p = IPPROTO_UDP;
  313:   ip.ip_src.s_addr = iface_addr.s_addr;
  314:   ip.ip_len = htons(sizeof(struct ip) + 
  315: 		    sizeof(struct udphdr) +
  316: 		    len) ;
  317:   ip.ip_hl = sizeof(struct ip) / 4;
  318:   ip.ip_v = IPVERSION;
  319:   ip.ip_tos = 0;
  320:   ip.ip_id = htons(0);
  321:   ip.ip_off = htons(0x4000); /* don't fragment */
  322:   ip.ip_ttl = IPDEFTTL;
  323:   ip.ip_sum = 0;
  324:   for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
  325:     sum += ((u16 *)&ip)[i];
  326:   while (sum>>16)
  327:     sum = (sum & 0xffff) + (sum >> 16);  
  328:   ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
  329:   
  330:   udp.uh_sport = htons(daemon->dhcp_server_port);
  331:   udp.uh_dport = htons(daemon->dhcp_client_port);
  332:   if (len & 1)
  333:     ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
  334:   udp.uh_sum = 0;
  335:   udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
  336:   sum += htons(IPPROTO_UDP);
  337:   sum += ip.ip_src.s_addr & 0xffff;
  338:   sum += (ip.ip_src.s_addr >> 16) & 0xffff;
  339:   sum += ip.ip_dst.s_addr & 0xffff;
  340:   sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
  341:   for (i = 0; i < sizeof(struct udphdr)/2; i++)
  342:     sum += ((u16 *)&udp)[i];
  343:   for (i = 0; i < (len + 1) / 2; i++)
  344:     sum += ((u16 *)mess)[i];
  345:   while (sum>>16)
  346:     sum = (sum & 0xffff) + (sum >> 16);
  347:   udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
  348:   
  349:   ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
  350:   
  351:   iov[0].iov_base = &ether;
  352:   iov[0].iov_len = sizeof(ether);
  353:   iov[1].iov_base = &ip;
  354:   iov[1].iov_len = sizeof(ip);
  355:   iov[2].iov_base = &udp;
  356:   iov[2].iov_len = sizeof(udp);
  357:   iov[3].iov_base = mess;
  358:   iov[3].iov_len = len;
  359: 
  360:   while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
  361: }
  362: 
  363: #endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
  364:  
  365: 
  366: #ifdef HAVE_BSD_NETWORK
  367: 
  368: void route_init(void)
  369: {
  370:   /* AF_UNSPEC: all addr families */
  371:   daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
  372:   
  373:   if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
  374:     die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
  375: }
  376: 
  377: void route_sock(void)
  378: {
  379:   struct if_msghdr *msg;
  380:   int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
  381: 
  382:   if (rc < 4)
  383:     return;
  384: 
  385:   msg = (struct if_msghdr *)daemon->packet;
  386:   
  387:   if (rc < msg->ifm_msglen)
  388:     return;
  389: 
  390:    if (msg->ifm_version != RTM_VERSION)
  391:      {
  392:        static int warned = 0;
  393:        if (!warned)
  394: 	 {
  395: 	   my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
  396: 	   warned = 1;
  397: 	 }
  398:      }
  399:    else if (msg->ifm_type == RTM_NEWADDR)
  400:      {
  401:        del_family = 0;
  402:        queue_event(EVENT_NEWADDR);
  403:      }
  404:    else if (msg->ifm_type == RTM_DELADDR)
  405:      {
  406:        /* There's a race in the kernel, such that if we run iface_enumerate() immediately
  407: 	  we get a DELADDR event, the deleted address still appears. Here we store the deleted address
  408: 	  in a static variable, and omit it from the set returned by iface_enumerate() */
  409:        int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
  410:        int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
  411: 			 RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
  412:        int of;
  413:        unsigned int i;
  414:        
  415:        for (i = 0,  of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++) 
  416: 	 if (mask & maskvec[i]) 
  417: 	   {
  418: 	     struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
  419: 	     size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
  420: 	     
  421: 	     if (maskvec[i] == RTA_IFA)
  422: 	       {
  423: 		 del_family = sa->sa_family;
  424: 		 if (del_family == AF_INET)
  425: 		   del_addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
  426: 		 else if (del_family == AF_INET6)
  427: 		   del_addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
  428: 		 else
  429: 		   del_family = 0;
  430: 	       }
  431: 	     
  432: 	     of += diff;
  433: 	     /* round up as needed */
  434: 	     if (diff & (sizeof(long) - 1)) 
  435: 	       of += sizeof(long) - (diff & (sizeof(long) - 1));
  436: 	   }
  437:        
  438:        queue_event(EVENT_NEWADDR);
  439:      }
  440: }
  441: 
  442: #endif /* HAVE_BSD_NETWORK */

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