tcpdump mailing list archives
Linux evdev capture support (draft patch)
From: David Gibson <david () gibson dropbear id au>
Date: Tue, 9 Dec 2008 19:40:29 +1100
I've implemented a first cut at adding support to libpcap to capture
from the Linux /dev/input/event* (evdev) devices. Draft patch is
included below.
However, I've realised there's a problem. Since it's an internal-only
protocol, the evdev devices return packets which are in native-endian
format. Obviously that's problematic once the packets go into pcap
files which could be moved to other machines.
As I see it, I have 3 options here:
1. Ask for a second DLT_ value, and use different DLT values
for the capture depending on the endianness of the capturing machine.
2. Covert the packets at capture time to either little or
big-endian (arbitrary choice).
3. Capture and record in native-endian, and rely on programs
reading the pcap file to deduce the endianness from other data. This
will generally be possible in practice because the 16-bit 'type' field
has no assigned values above 0xff.
I'm inclined towards option (2), but I don't know if there's a
pre-existing libpcap rule of thumb about this sort of thing.
Index: libpcap/Makefile.in
===================================================================
--- libpcap.orig/Makefile.in 2008-11-22 00:31:34.000000000 +1100
+++ libpcap/Makefile.in 2008-11-22 00:32:08.000000000 +1100
@@ -77,7 +77,7 @@ YACC = @V_YACC@
@rm -f $@
$(CC) $(CFLAGS) -c $(srcdir)/$*.c
-PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@
+PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @EVDEV_SRC@
FSRC = fad-@V_FINDALLDEVS@.c
SSRC = @SSRC@
CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c \
Index: libpcap/configure.in
===================================================================
--- libpcap.orig/configure.in 2008-11-22 00:32:01.000000000 +1100
+++ libpcap/configure.in 2008-11-22 00:32:08.000000000 +1100
@@ -1072,6 +1072,26 @@ if test "x$enable_bluetooth" != "xno" ;
AC_SUBST(BT_SRC)
fi
+dnl check for Linux evdev sniffing support
+AC_MSG_CHECKING(for Linux evdev sniffing support)
+case "$host_os" in
+linux*)
+ AC_CHECK_HEADER(linux/input.h,
+ [
+ AC_DEFINE(PCAP_SUPPORT_EVDEV, 1, [target host supports evdev sniffing])
+ EVDEV_SRC=pcap-evdev-linux.c
+ AC_MSG_RESULT(yes)
+ ],
+ AC_MSG_NOTICE(Need linux/input.h to support evdev sniffing)
+ )
+ ;;
+*)
+ AC_MSG_NOTICE(no Linux evdev sniffing support)
+ ;;
+esac
+AC_SUBST(PCAP_SUPPORT_EVDEV)
+AC_SUBST(EVDEV_SRC)
+
AC_PROG_INSTALL
AC_CONFIG_HEADER(config.h)
Index: libpcap/pcap-evdev-linux.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ libpcap/pcap-evdev-linux.c 2008-11-22 00:32:08.000000000 +1100
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2008 David Gibson.
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ *
+ * Sniffing support for the Linux evdev interface.
+ * By David Gibson <david () gibson dropbear id au>
+ *
+ */
+#ifndef lint
+static const char rcsid[] _U_ =
+ "@(#) $Header$ (LBL)";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcap-int.h"
+#include "pcap-evdev-linux.h"
+
+#ifdef NEED_STRERROR_H
+#include "strerror.h"
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <dirent.h>
+#include <byteswap.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <linux/input.h>
+
+#define EVDEV_IFACE "event"
+#define EVDEV_DEV_DIR "/dev/input"
+#define EVDEV_KNOWN_VERSION 0x010000
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define htols(s) s
+#define htoll(l) l
+#define htol64(ll) ll
+#else
+#define htols(s) bswap_16(s)
+#define htoll(l) bswap_32(l)
+#define htol64(ll) bswap_64(ll)
+#endif
+
+static int evdev_dev_add(pcap_if_t** alldevsp, const char *dev_name, char *err_str)
+{
+ char dev_descr[30];
+
+ snprintf(dev_descr, 30, "input layer evdev device %s", dev_name);
+
+ if (pcap_add_if(alldevsp, dev_name, 0, dev_descr, err_str) < 0)
+ return -1;
+ return 0;
+}
+
+int evdev_platform_finddevs(pcap_if_t **alldevsp, char *err_str)
+{
+ struct dirent *data;
+ int ret = 0;
+ DIR *dir;
+
+ /* scan udev directory */
+ dir = opendir(EVDEV_DEV_DIR);
+ if (!dir)
+ return 0;
+ while ((ret == 0) && ((data = readdir(dir)) != 0)) {
+ int n;
+ char *name = data->d_name;
+ int len = strlen(name);
+
+ /* Check if this is an event device */
+ if (strncmp(name, EVDEV_IFACE, strlen(EVDEV_IFACE)) != 0)
+ continue;
+
+ ret = evdev_dev_add(alldevsp, name, err_str);
+ }
+
+ closedir(dir);
+ return ret;
+}
+
+static int evdev_inject_linux(pcap_t *handle, const void *buf, size_t size)
+{
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on "
+ "evdev devices");
+ return (-1);
+}
+
+static int evdev_setfilter_linux(pcap_t *p, struct bpf_program *fp)
+{
+ return 0;
+}
+
+static int evdev_setdirection_linux(pcap_t *p, pcap_direction_t d)
+{
+ p->direction = d;
+ return 0;
+}
+
+static int evdev_stats_linux(pcap_t *handle, struct pcap_stat *stats)
+{
+ stats->ps_recv = handle->md.packets_read;
+ stats->ps_ifdrop = 0;
+ return 0;
+}
+
+static int evdev_read_linux(pcap_t *handle, int max_packets,
+ pcap_handler callback, u_char *user)
+{
+ int ret;
+ struct pcap_pkthdr pkth;
+ struct input_event *ie = (struct input_event *)handle->buffer;
+
+ ret = read(handle->fd, handle->buffer, sizeof(struct input_event));
+ if (ret < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't read from fd %d: %s", handle->fd, strerror(errno));
+ return -1;
+ }
+ if (ret < sizeof(struct input_event)) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Short read from fd %d: %d of %d bytes",
+ handle->fd, ret, sizeof(struct input_event));
+ return -1;
+ }
+
+ pkth.caplen = pkth.len = sizeof(struct input_event);
+ if (handle->snapshot < pkth.caplen)
+ pkth.caplen = handle->snapshot;
+ pkth.ts = ie->time;
+
+ handle->md.packets_read++;
+ callback(user, &pkth, handle->buffer);
+ return 1;
+}
+
+static int evdev_activate(pcap_t *handle)
+{
+ char evdev_path[PATH_MAX];
+ int evdev_version;
+ int err;
+
+ /* Initialize some components of the pcap structure. */
+ handle->bufsize = sizeof(struct input_event);
+ handle->offset = 0;
+ handle->linktype = DLT_LINUX_EVDEV;
+
+ handle->inject_op = evdev_inject_linux;
+ handle->setfilter_op = evdev_setfilter_linux;
+ handle->setdirection_op = evdev_setdirection_linux;
+ handle->set_datalink_op = NULL; /* can't change data link type */
+ handle->getnonblock_op = pcap_getnonblock_fd;
+ handle->setnonblock_op = pcap_setnonblock_fd;
+
+ /* get index from device name */
+ if (sscanf(handle->opt.source, EVDEV_IFACE"%d", &handle->md.ifindex) != 1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't get USB bus index from %s", handle->opt.source);
+ return PCAP_ERROR;
+ }
+
+ snprintf(evdev_path, PATH_MAX, EVDEV_DEV_DIR "/%s", handle->opt.source);
+ handle->fd = open(evdev_path, O_RDONLY, 0);
+ if (handle->fd < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't open evdev device %s: %s", evdev_path,
+ strerror(errno));
+ return PCAP_ERROR;
+ }
+
+ err = ioctl(handle->fd, EVIOCGVERSION, &evdev_version);
+ if (err < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "EVIOCGVERSION failed (%s), looks like %s isn't an evdev",
+ strerror(errno), evdev_path);
+ return PCAP_ERROR;
+ }
+
+ if (evdev_version != EVDEV_KNOWN_VERSION) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Don't understand evdev protocol version 0x%06x",
+ evdev_version);
+ return PCAP_ERROR;
+ }
+
+ if (handle->opt.rfmon)
+ /* Monitor mode doesn't apply to evdev devices. */
+ return PCAP_ERROR_RFMON_NOTSUP;
+
+ handle->stats_op = evdev_stats_linux;
+ handle->read_op = evdev_read_linux;
+
+ /*
+ * "handle->fd" is a real file, so "select()" and "poll()"
+ * work on it.
+ */
+ handle->selectable_fd = handle->fd;
+
+ handle->buffer = malloc(handle->bufsize);
+ if (!handle->buffer) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "malloc: %s", pcap_strerror(errno));
+ return PCAP_ERROR;
+ }
+ return 0;
+}
+
+pcap_t *evdev_create(const char *device, char *ebuf)
+{
+ pcap_t *p;
+
+ p = pcap_create_common(device, ebuf);
+ if (p == NULL)
+ return (NULL);
+
+ p->activate_op = evdev_activate;
+ return (p);
+}
Index: libpcap/pcap-linux.c
===================================================================
--- libpcap.orig/pcap-linux.c 2008-11-22 00:32:01.000000000 +1100
+++ libpcap/pcap-linux.c 2008-11-22 00:32:08.000000000 +1100
@@ -126,6 +126,10 @@ static const char rcsid[] _U_ =
#include "pcap-bt-linux.h"
#endif
+#ifdef PCAP_SUPPORT_EVDEV
+#include "pcap-evdev-linux.h"
+#endif
+
/*
* If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET
* sockets rather than SOCK_PACKET sockets.
@@ -315,6 +319,12 @@ pcap_create(const char *device, char *eb
}
#endif /* HAVE_SEPTEL_API */
+#ifdef PCAP_SUPPORT_EVDEV
+ if (strstr(device, "event")) {
+ return evdev_create(device, ebuf);
+ }
+#endif
+
#ifdef PCAP_SUPPORT_BT
if (strstr(device, "bluetooth")) {
return bt_create(device, ebuf);
@@ -1156,6 +1166,11 @@ pcap_platform_finddevs(pcap_if_t **allde
return (-1);
#endif /* HAVE_SEPTEL_API */
+#ifdef PCAP_SUPPORT_EVDEV
+ if (evdev_platform_finddevs(alldevsp, errbuf) < 0)
+ return (-1);
+#endif
+
#ifdef PCAP_SUPPORT_BT
if (bt_platform_finddevs(alldevsp, errbuf) < 0)
return (-1);
Index: libpcap/pcap-evdev-linux.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ libpcap/pcap-evdev-linux.h 2008-11-22 00:32:08.000000000 +1100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 David Gibson.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ *
+ * Sniffing support for the Linux evdev interface.
+ * By David Gibson <david () gibson dropbear id au>
+ *
+ * @(#) $Header$ (LBL)
+ */
+
+/*
+ * Prototypes for evdev-related functions
+ */
+int evdev_platform_finddevs(pcap_if_t **alldevsp, char *err_str);
+pcap_t *evdev_create(const char *device, char *ebuf);
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
Attachment:
signature.asc
Description: Digital signature
Current thread:
- Linux evdev capture support (draft patch) David Gibson (Dec 09)
- Re: Linux evdev capture support (draft patch) ronnie sahlberg (Dec 09)
- Re: Linux evdev capture support (draft patch) David Gibson (Dec 09)
- Re: Linux evdev capture support (draft patch) ronnie sahlberg (Dec 09)
