File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / lpf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* lpf.c
    2: 
    3:    Linux packet filter code, contributed by Brian Murrel at Interlinx
    4:    Support Services in Vancouver, B.C. */
    5: 
    6: /*
    7:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
    8:  * Copyright (c) 1996-2003 by Internet Software Consortium
    9:  *
   10:  * Permission to use, copy, modify, and distribute this software for any
   11:  * purpose with or without fee is hereby granted, provided that the above
   12:  * copyright notice and this permission notice appear in all copies.
   13:  *
   14:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
   15:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   16:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
   17:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   18:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   19:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   20:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   21:  *
   22:  *   Internet Systems Consortium, Inc.
   23:  *   950 Charter Street
   24:  *   Redwood City, CA 94063
   25:  *   <info@isc.org>
   26:  *   https://www.isc.org/
   27:  */
   28: 
   29: #include "dhcpd.h"
   30: #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
   31: #include <sys/ioctl.h>
   32: #include <sys/uio.h>
   33: #include <errno.h>
   34: 
   35: #include <asm/types.h>
   36: #include <linux/filter.h>
   37: #include <linux/if_ether.h>
   38: #include <netinet/in_systm.h>
   39: #include <net/if_packet.h>
   40: #include "includes/netinet/ip.h"
   41: #include "includes/netinet/udp.h"
   42: #include "includes/netinet/if_ether.h"
   43: #include <net/if.h>
   44: 
   45: /* Reinitializes the specified interface after an address change.   This
   46:    is not required for packet-filter APIs. */
   47: 
   48: #ifdef USE_LPF_SEND
   49: void if_reinitialize_send (info)
   50: 	struct interface_info *info;
   51: {
   52: }
   53: #endif
   54: 
   55: #ifdef USE_LPF_RECEIVE
   56: void if_reinitialize_receive (info)
   57: 	struct interface_info *info;
   58: {
   59: }
   60: #endif
   61: 
   62: /* Called by get_interface_list for each interface that's discovered.
   63:    Opens a packet filter for each interface and adds it to the select
   64:    mask. */
   65: 
   66: int if_register_lpf (info)
   67: 	struct interface_info *info;
   68: {
   69: 	int sock;
   70: 	struct sockaddr sa;
   71: 
   72: 	/* Make an LPF socket. */
   73: 	if ((sock = socket(PF_PACKET, SOCK_PACKET,
   74: 			   htons((short)ETH_P_ALL))) < 0) {
   75: 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
   76: 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
   77: 		    errno == EAFNOSUPPORT || errno == EINVAL) {
   78: 			log_error ("socket: %m - make sure");
   79: 			log_error ("CONFIG_PACKET (Packet socket) %s",
   80: 				   "and CONFIG_FILTER");
   81: 			log_error ("(Socket Filtering) are enabled %s",
   82: 				   "in your kernel");
   83: 			log_fatal ("configuration!");
   84: 		}
   85: 		log_fatal ("Open a socket for LPF: %m");
   86: 	}
   87: 
   88: 	/* Bind to the interface name */
   89: 	memset (&sa, 0, sizeof sa);
   90: 	sa.sa_family = AF_PACKET;
   91: 	strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
   92: 	if (bind (sock, &sa, sizeof sa)) {
   93: 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
   94: 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
   95: 		    errno == EAFNOSUPPORT || errno == EINVAL) {
   96: 			log_error ("socket: %m - make sure");
   97: 			log_error ("CONFIG_PACKET (Packet socket) %s",
   98: 				   "and CONFIG_FILTER");
   99: 			log_error ("(Socket Filtering) are enabled %s",
  100: 				   "in your kernel");
  101: 			log_fatal ("configuration!");
  102: 		}
  103: 		log_fatal ("Bind socket to interface: %m");
  104: 	}
  105: 
  106: 	get_hw_addr(info->name, &info->hw_address);
  107: 
  108: 	return sock;
  109: }
  110: #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
  111: 
  112: #ifdef USE_LPF_SEND
  113: void if_register_send (info)
  114: 	struct interface_info *info;
  115: {
  116: 	/* If we're using the lpf API for sending and receiving,
  117: 	   we don't need to register this interface twice. */
  118: #ifndef USE_LPF_RECEIVE
  119: 	info -> wfdesc = if_register_lpf (info);
  120: #else
  121: 	info -> wfdesc = info -> rfdesc;
  122: #endif
  123: 	if (!quiet_interface_discovery)
  124: 		log_info ("Sending on   LPF/%s/%s%s%s",
  125: 		      info -> name,
  126: 		      print_hw_addr (info -> hw_address.hbuf [0],
  127: 				     info -> hw_address.hlen - 1,
  128: 				     &info -> hw_address.hbuf [1]),
  129: 		      (info -> shared_network ? "/" : ""),
  130: 		      (info -> shared_network ?
  131: 		       info -> shared_network -> name : ""));
  132: }
  133: 
  134: void if_deregister_send (info)
  135: 	struct interface_info *info;
  136: {
  137: 	/* don't need to close twice if we are using lpf for sending and
  138: 	   receiving */
  139: #ifndef USE_LPF_RECEIVE
  140: 	/* for LPF this is simple, packet filters are removed when sockets
  141: 	   are closed */
  142: 	close (info -> wfdesc);
  143: #endif
  144: 	info -> wfdesc = -1;
  145: 	if (!quiet_interface_discovery)
  146: 		log_info ("Disabling output on LPF/%s/%s%s%s",
  147: 		      info -> name,
  148: 		      print_hw_addr (info -> hw_address.hbuf [0],
  149: 				     info -> hw_address.hlen - 1,
  150: 				     &info -> hw_address.hbuf [1]),
  151: 		      (info -> shared_network ? "/" : ""),
  152: 		      (info -> shared_network ?
  153: 		       info -> shared_network -> name : ""));
  154: }
  155: #endif /* USE_LPF_SEND */
  156: 
  157: #ifdef USE_LPF_RECEIVE
  158: /* Defined in bpf.c.   We can't extern these in dhcpd.h without pulling
  159:    in bpf includes... */
  160: extern struct sock_filter dhcp_bpf_filter [];
  161: extern int dhcp_bpf_filter_len;
  162: 
  163: #if defined (HAVE_TR_SUPPORT)
  164: extern struct sock_filter dhcp_bpf_tr_filter [];
  165: extern int dhcp_bpf_tr_filter_len;
  166: static void lpf_tr_filter_setup (struct interface_info *);
  167: #endif
  168: 
  169: static void lpf_gen_filter_setup (struct interface_info *);
  170: 
  171: void if_register_receive (info)
  172: 	struct interface_info *info;
  173: {
  174: 	/* Open a LPF device and hang it on this interface... */
  175: 	info -> rfdesc = if_register_lpf (info);
  176: 
  177: #if defined (HAVE_TR_SUPPORT)
  178: 	if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
  179: 		lpf_tr_filter_setup (info);
  180: 	else
  181: #endif
  182: 		lpf_gen_filter_setup (info);
  183: 
  184: 	if (!quiet_interface_discovery)
  185: 		log_info ("Listening on LPF/%s/%s%s%s",
  186: 			  info -> name,
  187: 			  print_hw_addr (info -> hw_address.hbuf [0],
  188: 					 info -> hw_address.hlen - 1,
  189: 					 &info -> hw_address.hbuf [1]),
  190: 			  (info -> shared_network ? "/" : ""),
  191: 			  (info -> shared_network ?
  192: 			   info -> shared_network -> name : ""));
  193: }
  194: 
  195: void if_deregister_receive (info)
  196: 	struct interface_info *info;
  197: {
  198: 	/* for LPF this is simple, packet filters are removed when sockets
  199: 	   are closed */
  200: 	close (info -> rfdesc);
  201: 	info -> rfdesc = -1;
  202: 	if (!quiet_interface_discovery)
  203: 		log_info ("Disabling input on LPF/%s/%s%s%s",
  204: 			  info -> name,
  205: 			  print_hw_addr (info -> hw_address.hbuf [0],
  206: 					 info -> hw_address.hlen - 1,
  207: 					 &info -> hw_address.hbuf [1]),
  208: 			  (info -> shared_network ? "/" : ""),
  209: 			  (info -> shared_network ?
  210: 			   info -> shared_network -> name : ""));
  211: }
  212: 
  213: static void lpf_gen_filter_setup (info)
  214: 	struct interface_info *info;
  215: {
  216: 	struct sock_fprog p;
  217: 
  218: 	memset(&p, 0, sizeof(p));
  219: 
  220: 	/* Set up the bpf filter program structure.    This is defined in
  221: 	   bpf.c */
  222: 	p.len = dhcp_bpf_filter_len;
  223: 	p.filter = dhcp_bpf_filter;
  224: 
  225:         /* Patch the server port into the LPF  program...
  226: 	   XXX changes to filter program may require changes
  227: 	   to the insn number(s) used below! XXX */
  228: 	dhcp_bpf_filter [8].k = ntohs ((short)local_port);
  229: 
  230: 	if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
  231: 			sizeof p) < 0) {
  232: 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
  233: 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
  234: 		    errno == EAFNOSUPPORT) {
  235: 			log_error ("socket: %m - make sure");
  236: 			log_error ("CONFIG_PACKET (Packet socket) %s",
  237: 				   "and CONFIG_FILTER");
  238: 			log_error ("(Socket Filtering) are enabled %s",
  239: 				   "in your kernel");
  240: 			log_fatal ("configuration!");
  241: 		}
  242: 		log_fatal ("Can't install packet filter program: %m");
  243: 	}
  244: }
  245: 
  246: #if defined (HAVE_TR_SUPPORT)
  247: static void lpf_tr_filter_setup (info)
  248: 	struct interface_info *info;
  249: {
  250: 	struct sock_fprog p;
  251: 
  252: 	memset(&p, 0, sizeof(p));
  253: 
  254: 	/* Set up the bpf filter program structure.    This is defined in
  255: 	   bpf.c */
  256: 	p.len = dhcp_bpf_tr_filter_len;
  257: 	p.filter = dhcp_bpf_tr_filter;
  258: 
  259:         /* Patch the server port into the LPF  program...
  260: 	   XXX changes to filter program may require changes
  261: 	   XXX to the insn number(s) used below!
  262: 	   XXX Token ring filter is null - when/if we have a filter 
  263: 	   XXX that's not, we'll need this code.
  264: 	   XXX dhcp_bpf_filter [?].k = ntohs (local_port); */
  265: 
  266: 	if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
  267: 			sizeof p) < 0) {
  268: 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
  269: 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
  270: 		    errno == EAFNOSUPPORT) {
  271: 			log_error ("socket: %m - make sure");
  272: 			log_error ("CONFIG_PACKET (Packet socket) %s",
  273: 				   "and CONFIG_FILTER");
  274: 			log_error ("(Socket Filtering) are enabled %s",
  275: 				   "in your kernel");
  276: 			log_fatal ("configuration!");
  277: 		}
  278: 		log_fatal ("Can't install packet filter program: %m");
  279: 	}
  280: }
  281: #endif /* HAVE_TR_SUPPORT */
  282: #endif /* USE_LPF_RECEIVE */
  283: 
  284: #ifdef USE_LPF_SEND
  285: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
  286: 	struct interface_info *interface;
  287: 	struct packet *packet;
  288: 	struct dhcp_packet *raw;
  289: 	size_t len;
  290: 	struct in_addr from;
  291: 	struct sockaddr_in *to;
  292: 	struct hardware *hto;
  293: {
  294: 	unsigned hbufp = 0, ibufp = 0;
  295: 	double hh [16];
  296: 	double ih [1536 / sizeof (double)];
  297: 	unsigned char *buf = (unsigned char *)ih;
  298: 	struct sockaddr_pkt sa;
  299: 	int result;
  300: 	int fudge;
  301: 
  302: 	if (!strcmp (interface -> name, "fallback"))
  303: 		return send_fallback (interface, packet, raw,
  304: 				      len, from, to, hto);
  305: 
  306: 	/* Assemble the headers... */
  307: 	assemble_hw_header (interface, (unsigned char *)hh, &hbufp, hto);
  308: 	fudge = hbufp % 4;	/* IP header must be word-aligned. */
  309: 	memcpy (buf + fudge, (unsigned char *)hh, hbufp);
  310: 	ibufp = hbufp + fudge;
  311: 	assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
  312: 				to -> sin_addr.s_addr, to -> sin_port,
  313: 				(unsigned char *)raw, len);
  314: 	memcpy (buf + ibufp, raw, len);
  315: 
  316: 	/* For some reason, SOCK_PACKET sockets can't be connected,
  317: 	   so we have to do a sentdo every time. */
  318: 	memset (&sa, 0, sizeof sa);
  319: 	sa.spkt_family = AF_PACKET;
  320: 	strncpy ((char *)sa.spkt_device,
  321: 		 (const char *)interface -> ifp, sizeof sa.spkt_device);
  322: 	sa.spkt_protocol = htons(ETH_P_IP);
  323: 
  324: 	result = sendto (interface -> wfdesc,
  325: 			 buf + fudge, ibufp + len - fudge, 0, 
  326: 			 (const struct sockaddr *)&sa, sizeof sa);
  327: 	if (result < 0)
  328: 		log_error ("send_packet: %m");
  329: 	return result;
  330: }
  331: #endif /* USE_LPF_SEND */
  332: 
  333: #ifdef USE_LPF_RECEIVE
  334: ssize_t receive_packet (interface, buf, len, from, hfrom)
  335: 	struct interface_info *interface;
  336: 	unsigned char *buf;
  337: 	size_t len;
  338: 	struct sockaddr_in *from;
  339: 	struct hardware *hfrom;
  340: {
  341: 	int length = 0;
  342: 	int offset = 0;
  343: 	unsigned char ibuf [1536];
  344: 	unsigned bufix = 0;
  345: 	unsigned paylen;
  346: 
  347: 	length = read (interface -> rfdesc, ibuf, sizeof ibuf);
  348: 	if (length <= 0)
  349: 		return length;
  350: 
  351: 	bufix = 0;
  352: 	/* Decode the physical header... */
  353: 	offset = decode_hw_header (interface, ibuf, bufix, hfrom);
  354: 
  355: 	/* If a physical layer checksum failed (dunno of any
  356: 	   physical layer that supports this, but WTH), skip this
  357: 	   packet. */
  358: 	if (offset < 0) {
  359: 		return 0;
  360: 	}
  361: 
  362: 	bufix += offset;
  363: 	length -= offset;
  364: 
  365: 	/* Decode the IP and UDP headers... */
  366: 	offset = decode_udp_ip_header (interface, ibuf, bufix, from,
  367: 				       (unsigned)length, &paylen);
  368: 
  369: 	/* If the IP or UDP checksum was bad, skip the packet... */
  370: 	if (offset < 0)
  371: 		return 0;
  372: 
  373: 	bufix += offset;
  374: 	length -= offset;
  375: 
  376: 	if (length < paylen)
  377: 		log_fatal("Internal inconsistency at %s:%d.", MDL);
  378: 
  379: 	/* Copy out the data in the packet... */
  380: 	memcpy(buf, &ibuf[bufix], paylen);
  381: 	return paylen;
  382: }
  383: 
  384: int can_unicast_without_arp (ip)
  385: 	struct interface_info *ip;
  386: {
  387: 	return 1;
  388: }
  389: 
  390: int can_receive_unicast_unconfigured (ip)
  391: 	struct interface_info *ip;
  392: {
  393: 	return 1;
  394: }
  395: 
  396: int supports_multiple_interfaces (ip)
  397: 	struct interface_info *ip;
  398: {
  399: 	return 1;
  400: }
  401: 
  402: void maybe_setup_fallback ()
  403: {
  404: 	isc_result_t status;
  405: 	struct interface_info *fbi = (struct interface_info *)0;
  406: 	if (setup_fallback (&fbi, MDL)) {
  407: 		if_register_fallback (fbi);
  408: 		status = omapi_register_io_object ((omapi_object_t *)fbi,
  409: 						   if_readsocket, 0,
  410: 						   fallback_discard, 0, 0);
  411: 		if (status != ISC_R_SUCCESS)
  412: 			log_fatal ("Can't register I/O handle for \"%s\": %s",
  413: 				   fbi -> name, isc_result_totext (status));
  414: 		interface_dereference (&fbi, MDL);
  415: 	}
  416: }
  417: 
  418: void
  419: get_hw_addr(const char *name, struct hardware *hw) {
  420: 	int sock;
  421: 	struct ifreq tmp;
  422: 	struct sockaddr *sa;
  423: 
  424: 	if (strlen(name) >= sizeof(tmp.ifr_name)) {
  425: 		log_fatal("Device name too long: \"%s\"", name);
  426: 	}
  427: 
  428: 	sock = socket(AF_INET, SOCK_DGRAM, 0);
  429: 	if (sock < 0) {
  430: 		log_fatal("Can't create socket for \"%s\": %m", name);
  431: 	}
  432: 
  433: 	memset(&tmp, 0, sizeof(tmp));
  434: 	strcpy(tmp.ifr_name, name);
  435: 	if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
  436: 		log_fatal("Error getting hardware address for \"%s\": %m", 
  437: 			  name);
  438: 	}
  439: 
  440: 	sa = &tmp.ifr_hwaddr;
  441: 	switch (sa->sa_family) {
  442: 		case ARPHRD_ETHER:
  443: 			hw->hlen = 7;
  444: 			hw->hbuf[0] = HTYPE_ETHER;
  445: 			memcpy(&hw->hbuf[1], sa->sa_data, 6);
  446: 			break;
  447: 		case ARPHRD_IEEE802:
  448: #ifdef ARPHRD_IEEE802_TR
  449: 		case ARPHRD_IEEE802_TR:
  450: #endif /* ARPHRD_IEEE802_TR */
  451: 			hw->hlen = 7;
  452: 			hw->hbuf[0] = HTYPE_IEEE802;
  453: 			memcpy(&hw->hbuf[1], sa->sa_data, 6);
  454: 			break;
  455: 		case ARPHRD_FDDI:
  456: 			hw->hlen = 17;
  457: 			hw->hbuf[0] = HTYPE_FDDI;
  458: 			memcpy(&hw->hbuf[1], sa->sa_data, 16);
  459: 			break;
  460: 		default:
  461: 			log_fatal("Unsupported device type %ld for \"%s\"",
  462: 				  (long int)sa->sa_family, name);
  463: 	}
  464: 
  465: 	close(sock);
  466: }
  467: #endif

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