File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / bpf.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 09:57:01 2016 UTC (7 years, 8 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_76p1, HEAD
dnsmasq 2.76

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

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