summaryrefslogtreecommitdiff
path: root/libnet/src/libnet_link_bpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnet/src/libnet_link_bpf.c')
-rw-r--r--libnet/src/libnet_link_bpf.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/libnet/src/libnet_link_bpf.c b/libnet/src/libnet_link_bpf.c
new file mode 100644
index 0000000..569ae9c
--- /dev/null
+++ b/libnet/src/libnet_link_bpf.c
@@ -0,0 +1,333 @@
+/*
+ * $Id: libnet_link_bpf.c,v 1.6 2004/01/28 19:45:00 mike Exp $
+ *
+ * libnet
+ * libnet_link_bpf.c - low-level bpf routines
+ *
+ * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
+ * All rights reserved.
+ *
+ * Copyright (c) 1993, 1994, 1995, 1996, 1998
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/param.h> /* optionally get BSD define */
+#include <sys/timeb.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#if (HAVE_CONFIG_H)
+#include "../include/config.h"
+#endif
+#include "../include/libnet.h"
+#include <sys/sysctl.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include "../include/gnuc.h"
+#include "../include/bpf.h"
+
+#ifdef HAVE_OS_PROTO_H
+#include "../include/os-proto.h"
+#endif
+
+int
+libnet_bpf_open(int8_t *err_buf)
+{
+ int i, fd;
+ int8_t device[sizeof "/dev/bpf000"];
+
+ /*
+ * Go through all the minors and find one that isn't in use.
+ */
+ for (i = 0;;i++)
+ {
+ sprintf(device, "/dev/bpf%d", i);
+
+ fd = open(device, O_RDWR);
+ if (fd == -1 && errno == EBUSY)
+ {
+ /*
+ * Device is busy.
+ */
+ continue;
+ }
+ else
+ {
+ /*
+ * Either we've got a valid file descriptor, or errno is not
+ * EBUSY meaning we've probably run out of devices.
+ */
+ break;
+ }
+ }
+
+ if (fd == -1)
+ {
+ snprintf(err_buf, LIBNET_ERRBUF_SIZE, "%s(): open(): (%s): %s\n",
+ __func__, device, strerror(errno));
+ }
+ return (fd);
+}
+
+
+int
+libnet_open_link(libnet_t *l)
+{
+ struct ifreq ifr;
+ struct bpf_version bv;
+ u_int v;
+
+#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
+ u_int spoof_eth_src = 1;
+#endif
+
+ if (l == NULL)
+ {
+ return (-1);
+ }
+
+ if (l->device == NULL)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): NULL device\n",
+ __func__);
+ goto bad;
+ }
+
+ l->fd = libnet_bpf_open(l->err_buf);
+ if (l->fd == -1)
+ {
+ goto bad;
+ }
+
+ /*
+ * Get bpf version.
+ */
+ if (ioctl(l->fd, BIOCVERSION, (caddr_t)&bv) < 0)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCVERSION: %s\n",
+ __func__, strerror(errno));
+ goto bad;
+ }
+
+ if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+ "%s(): kernel bpf filter out of date\n", __func__);
+ goto bad;
+ }
+
+ /*
+ * Attach network interface to bpf device.
+ */
+ strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) - 1);
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+
+ if (ioctl(l->fd, BIOCSETIF, (caddr_t)&ifr) == -1)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSETIF: (%s): %s\n",
+ __func__, l->device, strerror(errno));
+ goto bad;
+ }
+
+ /*
+ * Get the data link-layer type.
+ */
+ if (ioctl(l->fd, BIOCGDLT, (caddr_t)&v) == -1)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCGDLT: %s\n",
+ __func__, strerror(errno));
+ goto bad;
+ }
+
+ /*
+ * NetBSD and FreeBSD BPF have an ioctl for enabling/disabling
+ * automatic filling of the link level source address.
+ */
+#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
+ if (ioctl(l->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSHDRCMPLT: %s\n",
+ __func__, strerror(errno));
+ goto bad;
+ }
+#endif
+
+ /*
+ * Assign link type and offset.
+ */
+ switch (v)
+ {
+ case DLT_SLIP:
+ l->link_offset = 0x10;
+ break;
+ case DLT_RAW:
+ l->link_offset = 0x0;
+ break;
+ case DLT_PPP:
+ l->link_offset = 0x04;
+ break;
+ case DLT_EN10MB:
+ default:
+ l->link_offset = 0xe; /* default to ethernet */
+ break;
+ }
+#if _BSDI_VERSION - 0 >= 199510
+ switch (v)
+ {
+ case DLT_SLIP:
+ v = DLT_SLIP_BSDOS;
+ l->link_offset = 0x10;
+ break;
+ case DLT_PPP:
+ v = DLT_PPP_BSDOS;
+ l->link_offset = 0x04;
+ break;
+ }
+#endif
+ l->link_type = v;
+
+ return (1);
+
+bad:
+ if (l->fd > 0)
+ {
+ close(l->fd); /* this can fail ok */
+ }
+ return (-1);
+}
+
+
+int
+libnet_close_link(libnet_t *l)
+{
+ if (close(l->fd) == 0)
+ {
+ return (1);
+ }
+ else
+ {
+ return (-1);
+ }
+}
+
+
+int
+libnet_write_link(libnet_t *l, u_int8_t *packet, u_int32_t size)
+{
+ int c;
+
+ if (l == NULL)
+ {
+ return (-1);
+ }
+
+ c = write(l->fd, packet, size);
+ if (c != size)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+ "%s(): %d bytes written (%s)\n", __func__, c, strerror(errno));
+ }
+ return (c);
+}
+
+
+struct libnet_ether_addr *
+libnet_get_hwaddr(libnet_t *l)
+{
+ int mib[6];
+ size_t len;
+ int8_t *buf, *next, *end;
+ struct if_msghdr *ifm;
+ struct sockaddr_dl *sdl;
+ struct libnet_ether_addr *ea = NULL;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_LINK;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+
+ if (l == NULL)
+ {
+ return (NULL);
+ }
+
+ if (l->device == NULL)
+ {
+ if (libnet_select_device(l) == -1)
+ {
+ /* err msg set in libnet_select_device */
+ return (NULL);
+ }
+ }
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): sysctl(): %s\n",
+ __func__, strerror(errno));
+ return (NULL);
+ }
+
+ buf = (int8_t *)malloc(len);
+ if (buf == NULL)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n",
+ __func__, strerror(errno));
+ return (NULL);
+ }
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): sysctl(): %s\n",
+ __func__, strerror(errno));
+ free(buf);
+ return (NULL);
+ }
+ end = buf + len;
+
+ for (next = buf ; next < end ; next += ifm->ifm_msglen)
+ {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO)
+ {
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ if (strncmp(&sdl->sdl_data[0], l->device, sdl->sdl_nlen) == 0)
+ {
+ if (!(ea = malloc(sizeof(struct libnet_ether_addr))))
+ {
+ snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
+ "%s(): malloc(): %s", __func__, strerror(errno));
+ free(buf);
+ return (NULL);
+ }
+ memcpy(ea->ether_addr_octet, LLADDR(sdl), ETHER_ADDR_LEN);
+ break;
+ }
+ }
+ }
+ free(buf);
+ return (ea);
+}
+
+
+/* EOF */