Annotation of embedaddon/dhcp/common/lpf.c, revision 1.1
1.1 ! misho 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>