aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2017-05-31 12:45:20 -0700
committerGuy Harris <guy@alum.mit.edu>2017-05-31 12:45:20 -0700
commitf6685854a93e4ba9e0842001ccdc19410d4e424c (patch)
treee48d02f859a057a43643564cf362ee2c209d2b6c
parent89180a8f0d17af09abfe1b8f45bd4dad505db4a8 (diff)
Add netmap support.
Based on https://github.com/luigirizzo/netmap-libpcap.
-rw-r--r--Makefile.in10
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure35
-rw-r--r--configure.ac19
-rw-r--r--inet.c4
-rw-r--r--pcap-netmap.c254
-rw-r--r--pcap-netmap.h2
-rw-r--r--pcap.c7
8 files changed, 333 insertions, 1 deletions
diff --git a/Makefile.in b/Makefile.in
index 320ed043..bbe470c4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -83,7 +83,13 @@ YACC = @YACC@
@rm -f $@
$(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
-PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ @NETFILTER_SRC@ @DBUS_SRC@
+PSRC = pcap-@V_PCAP@.c \
+ @USB_SRC@ \
+ @BT_SRC@ \
+ @BT_MONITOR_SRC@ \
+ @NETFILTER_SRC@ \
+ @DBUS_SRC@ \
+ @NETMAP_SRC@
FSRC = @V_FINDALLDEVS@
SSRC = @SSRC@
CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c \
@@ -345,6 +351,8 @@ EXTRA_DIST = \
pcap-new.c \
pcap-netfilter-linux.c \
pcap-netfilter-linux.h \
+ pcap-netmap.c \
+ pcap-netmap.h \
pcap-nit.c \
pcap-null.c \
pcap-pf.c \
diff --git a/config.h.in b/config.h.in
index d901c750..51bdf13b 100644
--- a/config.h.in
+++ b/config.h.in
@@ -277,6 +277,9 @@
/* target host supports netfilter sniffing */
#undef PCAP_SUPPORT_NETFILTER
+/* target host supports netmap */
+#undef PCAP_SUPPORT_NETMAP
+
/* use Linux packet ring capture if available */
#undef PCAP_SUPPORT_PACKET_RING
diff --git a/configure b/configure
index a4904572..9b68b37b 100755
--- a/configure
+++ b/configure
@@ -630,6 +630,8 @@ PKGCONFIG
BT_MONITOR_SRC
BT_SRC
PCAP_SUPPORT_BT
+NETMAP_SRC
+PCAP_SUPPORT_NETMAP
NETFILTER_SRC
PCAP_SUPPORT_NETFILTER
USB_SRC
@@ -752,6 +754,7 @@ enable_remote
enable_universal
enable_shared
enable_usb
+enable_netmap
enable_bluetooth
enable_dbus
enable_packet_ring
@@ -1392,6 +1395,8 @@ Optional Features:
available]
--enable-usb enable nusb support [default=yes, if support
available]
+ --enable-netmap enable netmap support [default=yes, if support
+ available]
--enable-bluetooth enable Bluetooth support [default=yes, if support
available]
--enable-dbus enable D-Bus capture support [default=yes, if
@@ -8628,6 +8633,36 @@ fi
+# Check whether --enable-netmap was given.
+if test "${enable_netmap+set}" = set; then :
+ enableval=$enable_netmap;
+else
+ enable_netmap=yes
+fi
+
+
+if test "x$enable_netmap" != "xno" ; then
+ ac_fn_c_check_header_compile "$LINENO" "net/netmap_user.h" "ac_cv_header_net_netmap_user_h" "$ac_includes_default
+
+"
+if test "x$ac_cv_header_net_netmap_user_h" = xyes; then :
+
+$as_echo "#define PCAP_SUPPORT_NETMAP 1" >>confdefs.h
+
+ NETMAP_SRC=pcap-netmap.c
+ { $as_echo "$as_me:${as_lineno-$LINENO}: netmap is supported" >&5
+$as_echo "$as_me: netmap is supported" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: netmap is not supported" >&5
+$as_echo "$as_me: netmap is not supported" >&6;}
+fi
+
+
+
+
+fi
+
+
# Check whether --enable-bluetooth was given.
if test "${enable_bluetooth+set}" = set; then :
enableval=$enable_bluetooth;
diff --git a/configure.ac b/configure.ac
index 4ae1f0bb..af0e857b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1640,6 +1640,25 @@ fi
AC_SUBST(PCAP_SUPPORT_NETFILTER)
AC_SUBST(NETFILTER_SRC)
+AC_ARG_ENABLE([netmap],
+[AC_HELP_STRING([--enable-netmap],[enable netmap support @<:@default=yes, if support available@:>@])],
+ [],
+ [enable_netmap=yes])
+
+if test "x$enable_netmap" != "xno" ; then
+ dnl check for netmap support
+ AC_CHECK_HEADER(net/netmap_user.h,
+ [ AC_DEFINE(PCAP_SUPPORT_NETMAP, 1, [target host supports netmap])
+ NETMAP_SRC=pcap-netmap.c
+ AC_MSG_NOTICE(netmap is supported)],
+ AC_MSG_NOTICE(netmap is not supported),
+ AC_INCLUDES_DEFAULT
+ )
+ AC_SUBST(PCAP_SUPPORT_NETMAP)
+ AC_SUBST(NETMAP_SRC)
+fi
+
+
AC_ARG_ENABLE([bluetooth],
[AC_HELP_STRING([--enable-bluetooth],[enable Bluetooth support @<:@default=yes, if support available@:>@])],
[],
diff --git a/inet.c b/inet.c
index 76abcb8f..34da782f 100644
--- a/inet.c
+++ b/inet.c
@@ -151,6 +151,10 @@ pcap_lookupnet(device, netp, maskp, errbuf)
#ifdef HAVE_SNF_API
|| strstr(device, "snf") != NULL
#endif
+#ifdef PCAP_SUPPORT_NETMAP
+ || strncmp(device, "netmap:", 7) == 0
+ || strncmp(device, "vale", 4) == 0
+#endif
) {
*netp = *maskp = 0;
return 0;
diff --git a/pcap-netmap.c b/pcap-netmap.c
new file mode 100644
index 00000000..6dde821b
--- /dev/null
+++ b/pcap-netmap.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2014 Luigi Rizzo. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <poll.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NETMAP_WITH_LIBS
+#include <net/netmap_user.h>
+
+#include "pcap-int.h"
+#include "pcap-netmap.h"
+
+#if defined (linux)
+/* On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh.
+ * remap to IFF_PROMISC on linux
+ */
+#define IFF_PPROMISC IFF_PROMISC
+#endif /* linux */
+
+struct pcap_netmap {
+ struct nm_desc *d; /* pointer returned by nm_open() */
+ pcap_handler cb; /* callback and argument */
+ u_char *cb_arg;
+ int must_clear_promisc; /* flag */
+ uint64_t rx_pkts; /* # of pkts received before the filter */
+};
+
+
+static int
+pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ struct pcap_netmap *pn = p->priv;
+
+ ps->ps_recv = pn->rx_pkts;
+ ps->ps_drop = 0;
+ ps->ps_ifdrop = 0;
+ return 0;
+}
+
+
+static void
+pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf)
+{
+ pcap_t *p = (pcap_t *)arg;
+ struct pcap_netmap *pn = p->priv;
+ const struct bpf_insn *pc = p->fcode.bf_insns;
+
+ ++pn->rx_pkts;
+ if (pc == NULL || bpf_filter(pc, buf, h->len, h->caplen))
+ pn->cb(pn->cb_arg, h, buf);
+}
+
+
+static int
+pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user)
+{
+ int ret;
+ struct pcap_netmap *pn = p->priv;
+ struct nm_desc *d = pn->d;
+ struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 };
+
+ pn->cb = cb;
+ pn->cb_arg = user;
+
+ for (;;) {
+ if (p->break_loop) {
+ p->break_loop = 0;
+ return PCAP_ERROR_BREAK;
+ }
+ /* nm_dispatch won't run forever */
+
+ ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p);
+ if (ret != 0)
+ break;
+ errno = 0;
+ ret = poll(&pfd, 1, p->opt.timeout);
+ }
+ return ret;
+}
+
+
+/* XXX need to check the NIOCTXSYNC/poll */
+static int
+pcap_netmap_inject(pcap_t *p, const void *buf, size_t size)
+{
+ struct pcap_netmap *pn = p->priv;
+ struct nm_desc *d = pn->d;
+
+ return nm_inject(d, buf, size);
+}
+
+
+static int
+pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags)
+{
+ struct pcap_netmap *pn = p->priv;
+ struct nm_desc *d = pn->d;
+ struct ifreq ifr;
+ int error, fd = d->fd;
+
+#ifdef linux
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ fprintf(stderr, "Error: cannot get device control socket.\n");
+ return -1;
+ }
+#endif /* linux */
+ bzero(&ifr, sizeof(ifr));
+ strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name));
+ switch (what) {
+ case SIOCSIFFLAGS:
+ ifr.ifr_flags = *if_flags;
+#ifdef __FreeBSD__
+ ifr.ifr_flagshigh = *if_flags >> 16;
+#endif /* __FreeBSD__ */
+ break;
+ }
+ error = ioctl(fd, what, &ifr);
+ if (!error) {
+ switch (what) {
+ case SIOCGIFFLAGS:
+ *if_flags = ifr.ifr_flags;
+#ifdef __FreeBSD__
+ *if_flags |= (ifr.ifr_flagshigh << 16);
+#endif /* __FreeBSD__ */
+ }
+ }
+#ifdef linux
+ close(fd);
+#endif /* linux */
+ return error ? -1 : 0;
+}
+
+
+static void
+pcap_netmap_close(pcap_t *p)
+{
+ struct pcap_netmap *pn = p->priv;
+ struct nm_desc *d = pn->d;
+ uint32_t if_flags = 0;
+
+ if (pn->must_clear_promisc) {
+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
+ if (if_flags & IFF_PPROMISC) {
+ if_flags &= ~IFF_PPROMISC;
+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
+ }
+ }
+ nm_close(d);
+ pcap_cleanup_live_common(p);
+}
+
+
+static int
+pcap_netmap_activate(pcap_t *p)
+{
+ struct pcap_netmap *pn = p->priv;
+ struct nm_desc *d = nm_open(p->opt.source, NULL, 0, NULL);
+ uint32_t if_flags = 0;
+
+ if (d == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "netmap open: cannot access %s: %s\n",
+ p->opt.source, pcap_strerror(errno));
+ pcap_cleanup_live_common(p);
+ return (PCAP_ERROR);
+ }
+ if (0)
+ fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n",
+ __FUNCTION__, p->opt.source, d, d->fd,
+ d->first_rx_ring, d->last_rx_ring);
+ pn->d = d;
+ p->fd = d->fd;
+ if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) {
+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
+ if (!(if_flags & IFF_PPROMISC)) {
+ pn->must_clear_promisc = 1;
+ if_flags |= IFF_PPROMISC;
+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
+ }
+ }
+ p->linktype = DLT_EN10MB;
+ p->selectable_fd = p->fd;
+ p->read_op = pcap_netmap_dispatch;
+ p->inject_op = pcap_netmap_inject,
+ p->setfilter_op = install_bpf_program;
+ p->setdirection_op = NULL;
+ p->set_datalink_op = NULL;
+ p->getnonblock_op = pcap_getnonblock_fd;
+ p->setnonblock_op = pcap_setnonblock_fd;
+ p->stats_op = pcap_netmap_stats;
+ p->cleanup_op = pcap_netmap_close;
+
+ return (0);
+}
+
+
+pcap_t *
+pcap_netmap_create(const char *device, char *ebuf, int *is_ours)
+{
+ pcap_t *p;
+
+ *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4));
+ if (! *is_ours)
+ return NULL;
+ p = pcap_create_common(ebuf, sizeof (struct pcap_netmap));
+ if (p == NULL)
+ return (NULL);
+ p->activate_op = pcap_netmap_activate;
+ return (p);
+}
+
+/*
+ * XXX - is there a way to enumerate the netmap devices?
+ */
+int
+pcap_netmap_findalldevs(pcap_if_list_t *devlistp, char *err_str)
+{
+ return 0;
+}
+
diff --git a/pcap-netmap.h b/pcap-netmap.h
new file mode 100644
index 00000000..6a414fca
--- /dev/null
+++ b/pcap-netmap.h
@@ -0,0 +1,2 @@
+pcap_t *pcap_netmap_create(const char *, char *, int *);
+int pcap_netmap_findalldevs(pcap_if_list_t *devlistp, char *errbuf);
diff --git a/pcap.c b/pcap.c
index 488846d5..b12ce091 100644
--- a/pcap.c
+++ b/pcap.c
@@ -120,6 +120,10 @@ struct rtentry; /* declarations in <net/if.h> */
#include "pcap-netfilter-linux.h"
#endif
+#ifdef PCAP_SUPPORT_NETMAP
+#include "pcap-netmap.h"
+#endif
+
#ifdef PCAP_SUPPORT_DBUS
#include "pcap-dbus.h"
#endif
@@ -350,6 +354,9 @@ static struct capture_source_type {
#ifdef PCAP_SUPPORT_NETFILTER
{ netfilter_findalldevs, netfilter_create },
#endif
+#ifdef PCAP_SUPPORT_NETFILTER
+ { pcap_netmap_findalldevs, pcap_netmap_create },
+#endif
#ifdef PCAP_SUPPORT_DBUS
{ dbus_findalldevs, dbus_create },
#endif