Annotation of embedaddon/dhcp/common/nit.c, revision 1.1
1.1 ! misho 1: /* nit.c
! 2:
! 3: Network Interface Tap (NIT) network interface code, by Ted Lemon
! 4: with one crucial tidbit of help from Stu Grossmen. */
! 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: * This software has been written for Internet Systems Consortium
! 29: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
! 30: * To learn more about Internet Systems Consortium, see
! 31: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
! 32: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
! 33: * ``http://www.nominum.com''.
! 34: */
! 35:
! 36: #include "dhcpd.h"
! 37: #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
! 38: #include <sys/ioctl.h>
! 39: #include <sys/uio.h>
! 40:
! 41: #include <sys/time.h>
! 42: #include <net/nit.h>
! 43: #include <net/nit_if.h>
! 44: #include <net/nit_pf.h>
! 45: #include <net/nit_buf.h>
! 46: #include <sys/stropts.h>
! 47: #include <net/packetfilt.h>
! 48:
! 49: #include <netinet/in_systm.h>
! 50: #include "includes/netinet/ip.h"
! 51: #include "includes/netinet/udp.h"
! 52: #include "includes/netinet/if_ether.h"
! 53:
! 54: /* Reinitializes the specified interface after an address change. This
! 55: is not required for packet-filter APIs. */
! 56:
! 57: #ifdef USE_NIT_SEND
! 58: void if_reinitialize_send (info)
! 59: struct interface_info *info;
! 60: {
! 61: }
! 62: #endif
! 63:
! 64: #ifdef USE_NIT_RECEIVE
! 65: void if_reinitialize_receive (info)
! 66: struct interface_info *info;
! 67: {
! 68: }
! 69: #endif
! 70:
! 71: /* Called by get_interface_list for each interface that's discovered.
! 72: Opens a packet filter for each interface and adds it to the select
! 73: mask. */
! 74:
! 75: int if_register_nit (info)
! 76: struct interface_info *info;
! 77: {
! 78: int sock;
! 79: char filename[50];
! 80: struct ifreq ifr;
! 81: struct strioctl sio;
! 82:
! 83: /* Open a NIT device */
! 84: sock = open ("/dev/nit", O_RDWR);
! 85: if (sock < 0)
! 86: log_fatal ("Can't open NIT device for %s: %m", info -> name);
! 87:
! 88: /* Set the NIT device to point at this interface. */
! 89: sio.ic_cmd = NIOCBIND;
! 90: sio.ic_len = sizeof *(info -> ifp);
! 91: sio.ic_dp = (char *)(info -> ifp);
! 92: sio.ic_timout = INFTIM;
! 93: if (ioctl (sock, I_STR, &sio) < 0)
! 94: log_fatal ("Can't attach interface %s to nit device: %m",
! 95: info -> name);
! 96:
! 97: /* Get the low-level address... */
! 98: sio.ic_cmd = SIOCGIFADDR;
! 99: sio.ic_len = sizeof ifr;
! 100: sio.ic_dp = (char *)𝔦
! 101: sio.ic_timout = INFTIM;
! 102: if (ioctl (sock, I_STR, &sio) < 0)
! 103: log_fatal ("Can't get physical layer address for %s: %m",
! 104: info -> name);
! 105:
! 106: /* XXX code below assumes ethernet interface! */
! 107: info -> hw_address.hlen = 7;
! 108: info -> hw_address.hbuf [0] = ARPHRD_ETHER;
! 109: memcpy (&info -> hw_address.hbuf [1],
! 110: ifr.ifr_ifru.ifru_addr.sa_data, 6);
! 111:
! 112: if (ioctl (sock, I_PUSH, "pf") < 0)
! 113: log_fatal ("Can't push packet filter onto NIT for %s: %m",
! 114: info -> name);
! 115:
! 116: return sock;
! 117: }
! 118: #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
! 119:
! 120: #ifdef USE_NIT_SEND
! 121: void if_register_send (info)
! 122: struct interface_info *info;
! 123: {
! 124: /* If we're using the nit API for sending and receiving,
! 125: we don't need to register this interface twice. */
! 126: #ifndef USE_NIT_RECEIVE
! 127: struct packetfilt pf;
! 128: struct strioctl sio;
! 129:
! 130: info -> wfdesc = if_register_nit (info);
! 131:
! 132: pf.Pf_Priority = 0;
! 133: pf.Pf_FilterLen = 1;
! 134: pf.Pf_Filter [0] = ENF_PUSHZERO;
! 135:
! 136: /* Set up an NIT filter that rejects everything... */
! 137: sio.ic_cmd = NIOCSETF;
! 138: sio.ic_len = sizeof pf;
! 139: sio.ic_dp = (char *)&pf;
! 140: sio.ic_timout = INFTIM;
! 141: if (ioctl (info -> wfdesc, I_STR, &sio) < 0)
! 142: log_fatal ("Can't set NIT filter: %m");
! 143: #else
! 144: info -> wfdesc = info -> rfdesc;
! 145: #endif
! 146: if (!quiet_interface_discovery)
! 147: log_info ("Sending on NIT/%s%s%s",
! 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:
! 156: void if_deregister_send (info)
! 157: struct interface_info *info;
! 158: {
! 159: /* If we're using the nit API for sending and receiving,
! 160: we don't need to register this interface twice. */
! 161: #ifndef USE_NIT_RECEIVE
! 162: close (info -> wfdesc);
! 163: #endif
! 164: info -> wfdesc = -1;
! 165: if (!quiet_interface_discovery)
! 166: log_info ("Disabling output on NIT/%s%s%s",
! 167: print_hw_addr (info -> hw_address.hbuf [0],
! 168: info -> hw_address.hlen - 1,
! 169: &info -> hw_address.hbuf [1]),
! 170: (info -> shared_network ? "/" : ""),
! 171: (info -> shared_network ?
! 172: info -> shared_network -> name : ""));
! 173: }
! 174: #endif /* USE_NIT_SEND */
! 175:
! 176: #ifdef USE_NIT_RECEIVE
! 177: /* Packet filter program...
! 178: XXX Changes to the filter program may require changes to the constant
! 179: offsets used in if_register_send to patch the NIT program! XXX */
! 180:
! 181: void if_register_receive (info)
! 182: struct interface_info *info;
! 183: {
! 184: int flag = 1;
! 185: u_int32_t x;
! 186: struct packetfilt pf;
! 187: struct strioctl sio;
! 188: u_int16_t addr [2];
! 189: struct timeval t;
! 190:
! 191: /* Open a NIT device and hang it on this interface... */
! 192: info -> rfdesc = if_register_nit (info);
! 193:
! 194: /* Set the snap length to 0, which means always take the whole
! 195: packet. */
! 196: x = 0;
! 197: if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0)
! 198: log_fatal ("Can't set NIT snap length on %s: %m", info -> name);
! 199:
! 200: /* Set the stream to byte stream mode */
! 201: if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0)
! 202: log_info ("I_SRDOPT failed on %s: %m", info -> name);
! 203:
! 204: #if 0
! 205: /* Push on the chunker... */
! 206: if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0)
! 207: log_fatal ("Can't push chunker onto NIT STREAM: %m");
! 208:
! 209: /* Set the timeout to zero. */
! 210: t.tv_sec = 0;
! 211: t.tv_usec = 0;
! 212: if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0)
! 213: log_fatal ("Can't set chunk timeout: %m");
! 214: #endif
! 215:
! 216: /* Ask for no header... */
! 217: x = 0;
! 218: if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0)
! 219: log_fatal ("Can't set NIT flags on %s: %m", info -> name);
! 220:
! 221: /* Set up the NIT filter program. */
! 222: /* XXX Unlike the BPF filter program, this one won't work if the
! 223: XXX IP packet is fragmented or if there are options on the IP
! 224: XXX header. */
! 225: pf.Pf_Priority = 0;
! 226: pf.Pf_FilterLen = 0;
! 227:
! 228: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6;
! 229: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
! 230: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP);
! 231: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT;
! 232: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP);
! 233: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11;
! 234: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
! 235: pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF);
! 236: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND;
! 237: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18;
! 238: pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
! 239: pf.Pf_Filter [pf.Pf_FilterLen++] = local_port;
! 240:
! 241: /* Install the filter... */
! 242: sio.ic_cmd = NIOCSETF;
! 243: sio.ic_len = sizeof pf;
! 244: sio.ic_dp = (char *)&pf;
! 245: sio.ic_timout = INFTIM;
! 246: if (ioctl (info -> rfdesc, I_STR, &sio) < 0)
! 247: log_fatal ("Can't set NIT filter on %s: %m", info -> name);
! 248:
! 249: if (!quiet_interface_discovery)
! 250: log_info ("Listening on NIT/%s%s%s",
! 251: print_hw_addr (info -> hw_address.hbuf [0],
! 252: info -> hw_address.hlen - 1,
! 253: &info -> hw_address.hbuf [1]),
! 254: (info -> shared_network ? "/" : ""),
! 255: (info -> shared_network ?
! 256: info -> shared_network -> name : ""));
! 257: }
! 258:
! 259: void if_deregister_receive (info)
! 260: struct interface_info *info;
! 261: {
! 262: /* If we're using the nit API for sending and receiving,
! 263: we don't need to register this interface twice. */
! 264: close (info -> rfdesc);
! 265: info -> rfdesc = -1;
! 266:
! 267: if (!quiet_interface_discovery)
! 268: log_info ("Disabling input on NIT/%s%s%s",
! 269: print_hw_addr (info -> hw_address.hbuf [0],
! 270: info -> hw_address.hlen - 1,
! 271: &info -> hw_address.hbuf [1]),
! 272: (info -> shared_network ? "/" : ""),
! 273: (info -> shared_network ?
! 274: info -> shared_network -> name : ""));
! 275: }
! 276: #endif /* USE_NIT_RECEIVE */
! 277:
! 278: #ifdef USE_NIT_SEND
! 279: ssize_t send_packet (interface, packet, raw, len, from, to, hto)
! 280: struct interface_info *interface;
! 281: struct packet *packet;
! 282: struct dhcp_packet *raw;
! 283: size_t len;
! 284: struct in_addr from;
! 285: struct sockaddr_in *to;
! 286: struct hardware *hto;
! 287: {
! 288: unsigned hbufp, ibufp;
! 289: double hh [16];
! 290: double ih [1536 / sizeof (double)];
! 291: unsigned char *buf = (unsigned char *)ih;
! 292: struct sockaddr *junk;
! 293: struct strbuf ctl, data;
! 294: struct sockaddr_in foo;
! 295: int result;
! 296:
! 297: if (!strcmp (interface -> name, "fallback"))
! 298: return send_fallback (interface, packet, raw,
! 299: len, from, to, hto);
! 300:
! 301: /* Start with the sockaddr struct... */
! 302: junk = (struct sockaddr *)&hh [0];
! 303: hbufp = (((unsigned char *)&junk -> sa_data [0]) -
! 304: (unsigned char *)&hh[0]);
! 305: ibufp = 0;
! 306:
! 307: /* Assemble the headers... */
! 308: assemble_hw_header (interface, (unsigned char *)junk, &hbufp, hto);
! 309: assemble_udp_ip_header (interface, buf, &ibufp,
! 310: from.s_addr, to -> sin_addr.s_addr,
! 311: to -> sin_port, (unsigned char *)raw, len);
! 312:
! 313: /* Copy the data into the buffer (yuk). */
! 314: memcpy (buf + ibufp, raw, len);
! 315:
! 316: /* Set up the sockaddr structure... */
! 317: #if USE_SIN_LEN
! 318: junk -> sa_len = hbufp - 2; /* XXX */
! 319: #endif
! 320: junk -> sa_family = AF_UNSPEC;
! 321:
! 322: /* Set up the msg_buf structure... */
! 323: ctl.buf = (char *)&hh [0];
! 324: ctl.maxlen = ctl.len = hbufp;
! 325: data.buf = (char *)&ih [0];
! 326: data.maxlen = data.len = ibufp + len;
! 327:
! 328: result = putmsg (interface -> wfdesc, &ctl, &data, 0);
! 329: if (result < 0)
! 330: log_error ("send_packet: %m");
! 331: return result;
! 332: }
! 333: #endif /* USE_NIT_SEND */
! 334:
! 335: #ifdef USE_NIT_RECEIVE
! 336: ssize_t receive_packet (interface, buf, len, from, hfrom)
! 337: struct interface_info *interface;
! 338: unsigned char *buf;
! 339: size_t len;
! 340: struct sockaddr_in *from;
! 341: struct hardware *hfrom;
! 342: {
! 343: int nread;
! 344: int length = 0;
! 345: int offset = 0;
! 346: unsigned char ibuf [1536];
! 347: int bufix = 0;
! 348: unsigned paylen;
! 349:
! 350: length = read (interface -> rfdesc, ibuf, sizeof ibuf);
! 351: if (length <= 0)
! 352: return length;
! 353:
! 354: /* Decode the physical header... */
! 355: offset = decode_hw_header (interface, ibuf, bufix, hfrom);
! 356:
! 357: /* If a physical layer checksum failed (dunno of any
! 358: physical layer that supports this, but WTH), skip this
! 359: packet. */
! 360: if (offset < 0) {
! 361: return 0;
! 362: }
! 363:
! 364: bufix += offset;
! 365: length -= offset;
! 366:
! 367: /* Decode the IP and UDP headers... */
! 368: offset = decode_udp_ip_header (interface, ibuf, bufix,
! 369: from, length, &paylen);
! 370:
! 371: /* If the IP or UDP checksum was bad, skip the packet... */
! 372: if (offset < 0)
! 373: return 0;
! 374:
! 375: bufix += offset;
! 376: length -= offset;
! 377:
! 378: if (length < paylen)
! 379: log_fatal("Internal inconsistency at %s:%d.", MDL);
! 380:
! 381: /* Copy out the data in the packet... */
! 382: memcpy(buf, &ibuf[bufix], paylen);
! 383: return paylen;
! 384: }
! 385:
! 386: int can_unicast_without_arp (ip)
! 387: struct interface_info *ip;
! 388: {
! 389: return 1;
! 390: }
! 391:
! 392: int can_receive_unicast_unconfigured (ip)
! 393: struct interface_info *ip;
! 394: {
! 395: return 1;
! 396: }
! 397:
! 398: int supports_multiple_interfaces (ip)
! 399: struct interface_info *ip;
! 400: {
! 401: return 1;
! 402: }
! 403:
! 404: void maybe_setup_fallback ()
! 405: {
! 406: isc_result_t status;
! 407: struct interface_info *fbi = (struct interface_info *)0;
! 408: if (setup_fallback (&fbi, MDL)) {
! 409: if_register_fallback (fbi);
! 410: status = omapi_register_io_object ((omapi_object_t *)fbi,
! 411: if_readsocket, 0,
! 412: fallback_discard, 0, 0);
! 413: if (status != ISC_R_SUCCESS)
! 414: log_fatal ("Can't register I/O handle for %s: %s",
! 415: fbi -> name, isc_result_totext (status));
! 416: interface_dereference (&fbi, MDL);
! 417: }
! 418: }
! 419: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>