File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / bpf.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:31:38 2014 UTC (10 years, 1 month ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_71, HEAD
dnsmasq 2.71

    1: /* dnsmasq is Copyright (c) 2000-2014 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: #include <sys/sysctl.h>
   24: #include <net/if.h>
   25: #include <net/route.h>
   26: #include <net/if_dl.h>
   27: #include <netinet/if_ether.h>
   28: #if defined(__FreeBSD__)
   29: #  include <net/if_var.h> 
   30: #endif
   31: #include <netinet/in_var.h>
   32: #ifdef HAVE_IPV6
   33: #  include <netinet6/in6_var.h>
   34: #endif
   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 struct 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 errsav, 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) && defined(HAVE_IPV6)
  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.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: #ifdef HAVE_IPV6
  154: 	  else if (family == AF_INET6)
  155: 	    {
  156: 	      struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
  157: 	      unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
  158: 	      int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
  159: 	      int i, j, prefix = 0;
  160: 	      u32 valid = 0xffffffff, preferred = 0xffffffff;
  161: 	      int flags = 0;
  162: #ifdef HAVE_BSD_NETWORK
  163: 	      if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
  164: 		continue;
  165: #endif
  166: #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
  167: 	      struct in6_ifreq ifr6;
  168: 
  169: 	      memset(&ifr6, 0, sizeof(ifr6));
  170: 	      strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
  171: 	      
  172: 	      ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
  173: 	      if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
  174: 		{
  175: 		  if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
  176: 		    flags |= IFACE_TENTATIVE;
  177: 		  
  178: 		  if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
  179: 		    flags |= IFACE_DEPRECATED;
  180: 
  181: #ifdef IN6_IFF_TEMPORARY
  182: 		  if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
  183: 		    flags |= IFACE_PERMANENT;
  184: #endif
  185: 
  186: #ifdef IN6_IFF_PRIVACY
  187: 		  if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
  188: 		    flags |= IFACE_PERMANENT;
  189: #endif
  190: 		}
  191: 	      
  192: 	      ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
  193: 	      if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
  194: 		{
  195: 		  valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
  196: 		  preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
  197: 		}
  198: #endif
  199: 	      	      
  200: 	      for (i = 0; i < IN6ADDRSZ; i++, prefix += 8) 
  201:                 if (netmask[i] != 0xff)
  202: 		  break;
  203: 	      
  204: 	      if (i != IN6ADDRSZ && netmask[i]) 
  205:                 for (j = 7; j > 0; j--, prefix++) 
  206: 		  if ((netmask[i] & (1 << j)) == 0)
  207: 		    break;
  208: 	      
  209: 	      /* voodoo to clear interface field in address */
  210: 	      if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
  211: 		{
  212: 		  addr->s6_addr[2] = 0;
  213: 		  addr->s6_addr[3] = 0;
  214: 		} 
  215: 	     
  216: 	      if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
  217: 				(int) preferred, (int)valid, parm)))
  218: 		goto err;	      
  219: 	    }
  220: #endif /* HAVE_IPV6 */
  221: 
  222: #ifdef HAVE_DHCP6      
  223: 	  else if (family == AF_LINK)
  224: 	    { 
  225: 	      /* Assume ethernet again here */
  226: 	      struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
  227: 	      if (sdl->sdl_alen != 0 && 
  228: 		  !((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
  229: 		goto err;
  230: 	    }
  231: #endif 
  232: 	}
  233:     }
  234:   
  235:   ret = 1;
  236: 
  237:  err:
  238:   errsav = errno;
  239:   freeifaddrs(head); 
  240:   if (fd != -1)
  241:     close(fd);
  242:   errno = errsav;
  243: 
  244:   return ret;
  245: }
  246: #endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
  247: 
  248: 
  249: #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
  250: #include <net/bpf.h>
  251: 
  252: void init_bpf(void)
  253: {
  254:   int i = 0;
  255: 
  256:   while (1) 
  257:     {
  258:       sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
  259:       if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
  260: 	return;
  261: 
  262:       if (errno != EBUSY)
  263: 	die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
  264:     }	     
  265: }
  266: 
  267: void send_via_bpf(struct dhcp_packet *mess, size_t len,
  268: 		  struct in_addr iface_addr, struct ifreq *ifr)
  269: {
  270:    /* Hairy stuff, packet either has to go to the
  271:       net broadcast or the destination can't reply to ARP yet,
  272:       but we do know the physical address. 
  273:       Build the packet by steam, and send directly, bypassing
  274:       the kernel IP stack */
  275:   
  276:   struct ether_header ether; 
  277:   struct ip ip;
  278:   struct udphdr {
  279:     u16 uh_sport;               /* source port */
  280:     u16 uh_dport;               /* destination port */
  281:     u16 uh_ulen;                /* udp length */
  282:     u16 uh_sum;                 /* udp checksum */
  283:   } udp;
  284:   
  285:   u32 i, sum;
  286:   struct iovec iov[4];
  287: 
  288:   /* Only know how to do ethernet on *BSD */
  289:   if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
  290:     {
  291:       my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"), 
  292: 		mess->htype, ifr->ifr_name);
  293:       return;
  294:     }
  295:    
  296:   ifr->ifr_addr.sa_family = AF_LINK;
  297:   if (ioctl(daemon->dhcpfd, SIOCGIFADDR, ifr) < 0)
  298:     return;
  299:   
  300:   memcpy(ether.ether_shost, LLADDR((struct sockaddr_dl *)&ifr->ifr_addr), ETHER_ADDR_LEN);
  301:   ether.ether_type = htons(ETHERTYPE_IP);
  302:   
  303:   if (ntohs(mess->flags) & 0x8000)
  304:     {
  305:       memset(ether.ether_dhost, 255,  ETHER_ADDR_LEN);
  306:       ip.ip_dst.s_addr = INADDR_BROADCAST;
  307:     }
  308:   else
  309:     {
  310:       memcpy(ether.ether_dhost, mess->chaddr, ETHER_ADDR_LEN); 
  311:       ip.ip_dst.s_addr = mess->yiaddr.s_addr;
  312:     }
  313:   
  314:   ip.ip_p = IPPROTO_UDP;
  315:   ip.ip_src.s_addr = iface_addr.s_addr;
  316:   ip.ip_len = htons(sizeof(struct ip) + 
  317: 		    sizeof(struct udphdr) +
  318: 		    len) ;
  319:   ip.ip_hl = sizeof(struct ip) / 4;
  320:   ip.ip_v = IPVERSION;
  321:   ip.ip_tos = 0;
  322:   ip.ip_id = htons(0);
  323:   ip.ip_off = htons(0x4000); /* don't fragment */
  324:   ip.ip_ttl = IPDEFTTL;
  325:   ip.ip_sum = 0;
  326:   for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
  327:     sum += ((u16 *)&ip)[i];
  328:   while (sum>>16)
  329:     sum = (sum & 0xffff) + (sum >> 16);  
  330:   ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
  331:   
  332:   udp.uh_sport = htons(daemon->dhcp_server_port);
  333:   udp.uh_dport = htons(daemon->dhcp_client_port);
  334:   if (len & 1)
  335:     ((char *)mess)[len] = 0; /* for checksum, in case length is odd. */
  336:   udp.uh_sum = 0;
  337:   udp.uh_ulen = sum = htons(sizeof(struct udphdr) + len);
  338:   sum += htons(IPPROTO_UDP);
  339:   sum += ip.ip_src.s_addr & 0xffff;
  340:   sum += (ip.ip_src.s_addr >> 16) & 0xffff;
  341:   sum += ip.ip_dst.s_addr & 0xffff;
  342:   sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
  343:   for (i = 0; i < sizeof(struct udphdr)/2; i++)
  344:     sum += ((u16 *)&udp)[i];
  345:   for (i = 0; i < (len + 1) / 2; i++)
  346:     sum += ((u16 *)mess)[i];
  347:   while (sum>>16)
  348:     sum = (sum & 0xffff) + (sum >> 16);
  349:   udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
  350:   
  351:   ioctl(daemon->dhcp_raw_fd, BIOCSETIF, ifr);
  352:   
  353:   iov[0].iov_base = &ether;
  354:   iov[0].iov_len = sizeof(ether);
  355:   iov[1].iov_base = &ip;
  356:   iov[1].iov_len = sizeof(ip);
  357:   iov[2].iov_base = &udp;
  358:   iov[2].iov_len = sizeof(udp);
  359:   iov[3].iov_base = mess;
  360:   iov[3].iov_len = len;
  361: 
  362:   while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
  363: }
  364: 
  365: #endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
  366:  
  367: 
  368: #ifdef HAVE_BSD_NETWORK
  369: 
  370: void route_init(void)
  371: {
  372:   /* AF_UNSPEC: all addr families */
  373:   daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
  374:   
  375:   if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
  376:     die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
  377: }
  378: 
  379: void route_sock(time_t now)
  380: {
  381:   struct if_msghdr *msg;
  382:   int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
  383: 
  384:   if (rc < 4)
  385:     return;
  386: 
  387:   msg = (struct if_msghdr *)daemon->packet;
  388:   
  389:   if (rc < msg->ifm_msglen)
  390:     return;
  391: 
  392:    if (msg->ifm_version != RTM_VERSION)
  393:      {
  394:        static int warned = 0;
  395:        if (!warned)
  396: 	 {
  397: 	   my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
  398: 	   warned = 1;
  399: 	 }
  400:      }
  401:    else if (msg->ifm_type == RTM_NEWADDR)
  402:      {
  403:        del_family = 0;
  404:        newaddress(now);
  405:      }
  406:    else if (msg->ifm_type == RTM_DELADDR)
  407:      {
  408:        /* There's a race in the kernel, such that if we run iface_enumerate() immediately
  409: 	  we get a DELADDR event, the deleted address still appears. Here we store the deleted address
  410: 	  in a static variable, and omit it from the set returned by iface_enumerate() */
  411:        int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
  412:        int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
  413: 			 RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
  414:        int of;
  415:        unsigned int i;
  416:        
  417:        for (i = 0,  of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++) 
  418: 	 if (mask & maskvec[i]) 
  419: 	   {
  420: 	     struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
  421: 	     size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
  422: 	     
  423: 	     if (maskvec[i] == RTA_IFA)
  424: 	       {
  425: 		 del_family = sa->sa_family;
  426: 		 if (del_family == AF_INET)
  427: 		   del_addr.addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
  428: #ifdef HAVE_IPV6
  429: 		 else if (del_family == AF_INET6)
  430: 		   del_addr.addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
  431: #endif
  432: 		 else
  433: 		   del_family = 0;
  434: 	       }
  435: 	     
  436: 	     of += diff;
  437: 	     /* round up as needed */
  438: 	     if (diff & (sizeof(long) - 1)) 
  439: 	       of += sizeof(long) - (diff & (sizeof(long) - 1));
  440: 	   }
  441:        
  442:        newaddress(now);
  443:      }
  444: }
  445: 
  446: #endif /* HAVE_BSD_NETWORK */
  447: 
  448: 

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