]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add pcap_set_protocol() to allow specifying a specific capture protocol. 595/head
authorLennert Buytenhek <[email protected]>
Thu, 29 Jun 2017 22:25:57 +0000 (01:25 +0300)
committerLennert Buytenhek <[email protected]>
Mon, 21 Aug 2017 12:24:22 +0000 (15:24 +0300)
This adds the Linux-specific pcap_set_protocol(), which allows you to
specify a specific protocol to be captured.  A protocol value specified
with this function will be used instead of ETH_P_ALL when creating and
binding a packet socket.

For ethernet packets, a similar result can be achieved by explicitly
creating a BPF filter that filters on ethertype and attaching that
filter to the packet socket, however, filtering using the packet socket
protocol field is slightly more efficient.

Also, in some cases, the packet socket protocol field and the
ethertype field have different values, and in those cases it is
impossible to achieve the same result by using a BPF filter.  An
example of this is on Arista platforms, where sFlow-sampled packets
are delivered, unmodified, to virtual interfaces on the management
CPU with their packet socket protocol value set to the magic value
0x002d, independently of their actual ethertype.

Makefile.in
pcap-int.h
pcap-linux.c
pcap.3pcap.in
pcap.c
pcap/pcap.h
pcap_set_protocol.3pcap [new file with mode: 0644]

index bbe470c4ed35893e024576fe4e0b0eda9b105a62..35f2ea4726e22b26e15ceb16a4408be9b0da3547 100644 (file)
@@ -231,6 +231,7 @@ MAN3PCAP_NOEXPAND = \
        pcap_set_datalink.3pcap \
        pcap_set_immediate_mode.3pcap \
        pcap_set_promisc.3pcap \
+       pcap_set_protocol.3pcap \
        pcap_set_rfmon.3pcap \
        pcap_set_snaplen.3pcap \
        pcap_set_timeout.3pcap \
index 66c3d0634c1e8247c43b851592fe9e64637636c1..acf386c02dabec8647738a6f62efe6f1814a0128 100644 (file)
@@ -112,6 +112,9 @@ struct pcap_opt {
        int     timeout;        /* timeout for buffering */
        u_int   buffer_size;
        int     promisc;
+#ifdef __linux__
+       int     protocol;
+#endif
        int     rfmon;          /* monitor mode */
        int     immediate;      /* immediate mode - deliver packets as soon as they arrive */
        int     nonblock;       /* non-blocking mode - don't wait for packets to be delivered, return "no packets available" */
index 179fd348acfc652db5dc9d462e608cebcb853d10..e4f0637df560c383490687b0104920eda2f7637b 100644 (file)
@@ -425,7 +425,7 @@ static int  iface_get_id(int fd, const char *device, char *ebuf);
 static int     iface_get_mtu(int fd, const char *device, char *ebuf);
 static int     iface_get_arptype(int fd, const char *device, char *ebuf);
 #ifdef HAVE_PF_PACKET_SOCKETS
-static int     iface_bind(int fd, int ifindex, char *ebuf);
+static int     iface_bind(int fd, int ifindex, char *ebuf, int protocol);
 #ifdef IW_MODE_MONITOR
 static int     has_wext(int sock_fd, const char *device, char *ebuf);
 #endif /* IW_MODE_MONITOR */
@@ -1008,6 +1008,17 @@ is_bonding_device(int fd, const char *device)
 }
 #endif /* IW_MODE_MONITOR */
 
+static int pcap_protocol(pcap_t *handle)
+{
+       int protocol;
+
+       protocol = handle->opt.protocol;
+       if (protocol == 0)
+               protocol = ETH_P_ALL;
+
+       return htons(protocol);
+}
+
 static int
 pcap_can_set_rfmon_linux(pcap_t *handle)
 {
@@ -1059,7 +1070,7 @@ pcap_can_set_rfmon_linux(pcap_t *handle)
         * (We assume that if we have Wireless Extensions support
         * we also have PF_PACKET support.)
         */
-       sock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       sock_fd = socket(PF_PACKET, SOCK_RAW, pcap_protocol(handle));
        if (sock_fd == -1) {
                (void)pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                    "socket: %s", pcap_strerror(errno));
@@ -3328,6 +3339,7 @@ activate_new(pcap_t *handle)
        struct pcap_linux *handlep = handle->priv;
        const char              *device = handle->opt.device;
        int                     is_any_device = (strcmp(device, "any") == 0);
+       int                     protocol = pcap_protocol(handle);
        int                     sock_fd = -1, arptype;
 #ifdef HAVE_PACKET_AUXDATA
        int                     val;
@@ -3346,8 +3358,8 @@ activate_new(pcap_t *handle)
         * try a SOCK_RAW socket for the raw interface.
         */
        sock_fd = is_any_device ?
-               socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)) :
-               socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+               socket(PF_PACKET, SOCK_DGRAM, protocol) :
+               socket(PF_PACKET, SOCK_RAW, protocol);
 
        if (sock_fd == -1) {
                if (errno == EINVAL || errno == EAFNOSUPPORT) {
@@ -3464,8 +3476,7 @@ activate_new(pcap_t *handle)
                                         "close: %s", pcap_strerror(errno));
                                return PCAP_ERROR;
                        }
-                       sock_fd = socket(PF_PACKET, SOCK_DGRAM,
-                           htons(ETH_P_ALL));
+                       sock_fd = socket(PF_PACKET, SOCK_DGRAM, protocol);
                        if (sock_fd == -1) {
                                pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                                    "socket: %s", pcap_strerror(errno));
@@ -3529,7 +3540,7 @@ activate_new(pcap_t *handle)
                }
 
                if ((err = iface_bind(sock_fd, handlep->ifindex,
-                   handle->errbuf)) != 1) {
+                   handle->errbuf, protocol)) != 1) {
                        close(sock_fd);
                        if (err < 0)
                                return err;
@@ -5310,7 +5321,7 @@ iface_get_id(int fd, const char *device, char *ebuf)
  *  or a PCAP_ERROR_ value on a hard error.
  */
 static int
-iface_bind(int fd, int ifindex, char *ebuf)
+iface_bind(int fd, int ifindex, char *ebuf, int protocol)
 {
        struct sockaddr_ll      sll;
        int                     err;
@@ -5319,7 +5330,7 @@ iface_bind(int fd, int ifindex, char *ebuf)
        memset(&sll, 0, sizeof(sll));
        sll.sll_family          = AF_PACKET;
        sll.sll_ifindex         = ifindex;
-       sll.sll_protocol        = htons(ETH_P_ALL);
+       sll.sll_protocol        = protocol;
 
        if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1) {
                if (errno == ENETDOWN) {
@@ -6946,3 +6957,12 @@ pcap_platform_lib_version(void)
        return ("without TPACKET");
 #endif
 }
+
+int
+pcap_set_protocol(pcap_t *p, int protocol)
+{
+       if (pcap_check_activated(p))
+               return (PCAP_ERROR_ACTIVATED);
+       p->opt.protocol = protocol;
+       return (0);
+}
index 544e79ccadb393fa9e6c1ea831c2ef40c449acc5..11c44837b99320f6ea8cd63314b69bedee56bdbe 100644 (file)
@@ -394,6 +394,11 @@ set promiscuous mode for a not-yet-activated
 .B pcap_t
 for live capture
 .TP
+.BR pcap_set_protocol (3PCAP)
+set capture protocol for a not-yet-activated
+.B pcap_t
+for live capture (Linux only)
+.TP
 .BR pcap_set_rfmon (3PCAP)
 set monitor mode for a not-yet-activated
 .B pcap_t
diff --git a/pcap.c b/pcap.c
index bb5e648b192822ddea439f26ce191896d5bca9e9..b24b89946a267f4b9f8f28a22b5ca90fb40441ef 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -1338,6 +1338,9 @@ pcap_create_common(char *ebuf, size_t size)
        p->opt.timeout = 0;             /* no timeout specified */
        p->opt.buffer_size = 0;         /* use the platform's default */
        p->opt.promisc = 0;
+#ifdef __linux__
+       p->opt.protocol = 0;
+#endif
        p->opt.rfmon = 0;
        p->opt.immediate = 0;
        p->opt.tstamp_type = -1;        /* default to not setting time stamp type */
index adff85333a894f3dfd445d40facc1b5495a3956a..613a5697c5e88a6b9b4bb3b9c44b267fe2e6fe21 100644 (file)
@@ -331,6 +331,10 @@ PCAP_API int       pcap_tstamp_type_name_to_val(const char *);
 PCAP_API const char *pcap_tstamp_type_val_to_name(int);
 PCAP_API const char *pcap_tstamp_type_val_to_description(int);
 
+#ifdef __linux__
+PCAP_API int   pcap_set_protocol(pcap_t *, int);
+#endif
+
 /*
  * Time stamp types.
  * Not all systems and interfaces will necessarily support all of these.
diff --git a/pcap_set_protocol.3pcap b/pcap_set_protocol.3pcap
new file mode 100644 (file)
index 0000000..4ed3e62
--- /dev/null
@@ -0,0 +1,48 @@
+.\" Copyright (c) 1994, 1996, 1997
+.\"    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.
+.\"
+.TH PCAP_SET_PROTOCOL 3PCAP "3 January 2014"
+.SH NAME
+pcap_set_protocol \- set capture protocol for a not-yet-activated
+capture handle
+.SH SYNOPSIS
+.nf
+.ft B
+#include <pcap/pcap.h>
+.LP
+.ft B
+int pcap_set_protocol(pcap_t *p, int protocol);
+.ft
+.fi
+.SH DESCRIPTION
+.B pcap_set_protocol()
+sets the capture protocol to use on a capture handle when the handle
+is activated.
+If
+.I protocol
+is non-zero, packets of that protocol will be captured when the
+handle is activated, otherwise, all packets will be captured.  This
+function is only provided on Linux.
+.SH RETURN VALUE
+.B pcap_set_protocol()
+returns 0 on success or
+.B PCAP_ERROR_ACTIVATED
+if called on a capture handle that has been activated.
+.SH SEE ALSO
+pcap(3PCAP), pcap_create(3PCAP), pcap_activate(3PCAP)