summaryrefslogtreecommitdiff
path: root/external/bsd/libpcap
diff options
context:
space:
mode:
authorchristos <christos@NetBSD.org>2020-03-29 19:49:26 +0000
committerchristos <christos@NetBSD.org>2020-03-29 19:49:26 +0000
commitbfc5861a0e1ff4e3c4b34e301f8a5eb5deb252e2 (patch)
treebc8e3580fadf4b0a4bc8930f83b4af91b7a91222 /external/bsd/libpcap
parenta46bbbf6d0af42d754b16575a5ba0ff4ae04cbc2 (diff)
Use http://sourceforge.net/p/libpcap/patches/_discuss/thread/fc8f43a0/ad35/\
attachment/rpcap3.patch to provide rpcap support.
Diffstat (limited to 'external/bsd/libpcap')
-rw-r--r--external/bsd/libpcap/dist/pcap-rpcap-unix.c766
-rw-r--r--external/bsd/libpcap/dist/pcap-rpcap-unix.h1
-rw-r--r--external/bsd/libpcap/dist/pcap.c11
3 files changed, 776 insertions, 2 deletions
diff --git a/external/bsd/libpcap/dist/pcap-rpcap-unix.c b/external/bsd/libpcap/dist/pcap-rpcap-unix.c
new file mode 100644
index 00000000000..48a55bc277b
--- /dev/null
+++ b/external/bsd/libpcap/dist/pcap-rpcap-unix.c
@@ -0,0 +1,766 @@
+/*
+ * Reimplementation of winpcap pcap-remote.c
+ * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
+ * 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. Neither the name of the Politecnico di Torino, CACE Technologies
+ * 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 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcap-int.h"
+
+#ifdef NEED_STRERROR_H
+#include "strerror.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <linux/types.h>
+
+#include "pcap-rpcap-unix.h"
+
+#define RPCAP_IFACE "rpcap://"
+
+/* default */
+#define RPCAP_DEFAULT_NETPORT 2002
+
+/* version */
+#define RPCAP_VERSION_EXPERIMENTAL 0
+
+/* packets */
+#define RPCAP_MSG_ERROR 1 /*!< Message that keeps an error notification */
+#define RPCAP_MSG_OPEN_REQ 3 /*!< Request to open a remote device */
+#define RPCAP_MSG_STARTCAP_REQ 4 /*!< Request to start a capture on a remote device */
+#define RPCAP_MSG_UPDATEFILTER_REQ 5 /*!< Send a compiled filter into the remote device */
+#define RPCAP_MSG_PACKET 7 /*!< This is a 'data' message, which carries a network packet */
+#define RPCAP_MSG_AUTH_REQ 8 /*!< Message that keeps the authentication parameters */
+#define RPCAP_MSG_STATS_REQ 9 /*!< It requires to have network statistics */
+
+#define RPCAP_UPDATEFILTER_BPF 1 /*!< This code tells us that the filter is encoded with the BPF/NPF syntax */
+
+static unsigned short
+get16(const unsigned char *buf)
+{
+ unsigned short val;
+
+ val = buf[0];
+ val = val << 8 | buf[1];
+ return val;
+}
+
+static void
+put16(unsigned char *buf, unsigned int val)
+{
+ buf[0] = val >> 8;
+ buf[1] = val >> 0;
+}
+
+static unsigned int
+get32(const unsigned char *buf)
+{
+ unsigned int val;
+
+ val = buf[0];
+ val = val << 8 | buf[1];
+ val = val << 8 | buf[2];
+ val = val << 8 | buf[3];
+ return val;
+}
+
+static void
+put32(unsigned char *buf, unsigned int val)
+{
+ buf[0] = val >> 24;
+ buf[1] = val >> 16;
+ buf[2] = val >> 8;
+ buf[3] = val >> 0;
+}
+
+static int
+rpcap_recv_pkt(pcap_t *p, int fd, char *recv_buf, unsigned int buflen)
+{
+ static char discard[1024];
+
+ size_t mlen;
+ int ret;
+ char *buf;
+ unsigned int len;
+ unsigned int pkt_len;
+
+ char hdr[8];
+ int pkt_type;
+
+/* read header loop */
+ buf = hdr;
+ len = 8;
+
+ ret = 0;
+ do {
+ buf += ret;
+ len -= ret;
+
+ do {
+ ret = read(fd, buf, len);
+ if (p->break_loop) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "break-loop");
+ p->break_loop = 0;
+ return -2;
+ }
+ } while (ret == -1 && errno == EINTR);
+ } while (ret > 0 && len-ret);
+
+ if (ret <= 0) {
+ if (!ret)
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: connection closed");
+ else
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: connection error (%s)", strerror(errno));
+ return -1;
+ }
+
+ if (hdr[0] != RPCAP_VERSION_EXPERIMENTAL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: incorrect reply version (%.2x)", hdr[0]);
+ return -1;
+ }
+
+ pkt_type = (unsigned char) hdr[1];
+ pkt_len = get32(&hdr[4]);
+
+ if (pkt_type == RPCAP_MSG_ERROR) {
+ recv_buf = p->errbuf;
+ buflen = PCAP_ERRBUF_SIZE-1;
+ }
+
+ buf = recv_buf;
+
+/* read payload loop */
+ if (pkt_len) {
+ ret = 0;
+ len = pkt_len;
+ do {
+ buf += ret;
+ buflen -= ret;
+ len -= ret;
+
+ if (!buflen) {
+ buf = discard;
+ buflen = sizeof(discard);
+ }
+
+ mlen = (len < 0x7fff) ? len : 0x7fff;
+
+ if (mlen > buflen)
+ mlen = buflen;
+
+ do {
+ ret = read(fd, buf, mlen);
+ if (p->break_loop) {
+ p->break_loop = 0;
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "break-loop");
+ return -2;
+ }
+ } while (ret == -1 && errno == EINTR);
+ } while (ret > 0 && len-ret);
+
+ if (ret <= 0) {
+ if (!ret)
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: connection closed");
+ else
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: connection error (%s)", strerror(errno));
+ return -1;
+ }
+ buf += ret;
+ }
+
+ /* always NUL terminate errbuf, and signal error */
+ if (pkt_type == RPCAP_MSG_ERROR) {
+ *buf = '\0';
+ return -1;
+ }
+ return pkt_len;
+}
+
+static int
+rpcap_send_pkt(pcap_t *p, const char *send_buf, unsigned int len)
+{
+ char *buf;
+
+ size_t mlen;
+ int ret;
+
+/* send loop */
+ ret = 0;
+ do {
+ send_buf += ret;
+ len -= ret;
+
+ mlen = (len < 0x7fff) ? len : 0x7fff;
+
+ do {
+ ret = write(p->fd, send_buf, mlen);
+ if (p->break_loop) {
+ p->break_loop = 0;
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "break-loop");
+ return -2;
+ }
+ } while (ret == -1 && errno == EINTR);
+ } while (ret > 0 && len-ret);
+
+ if (ret <= 0) {
+ if (!ret)
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: connection closed");
+ else
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: connection error (%s)", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+rpcap_send_request(pcap_t *p, char type, char *buf, unsigned int payload_len)
+{
+ buf[0] = RPCAP_VERSION_EXPERIMENTAL;
+ buf[1] = type;
+ buf[2] = buf[3] = 0;
+ put32(&buf[4], payload_len);
+
+ return rpcap_send_pkt(p, buf, 8+payload_len);
+}
+
+static int
+rpcap_send_request_auth(pcap_t *p, const char *username, const char *password)
+{
+ int res;
+
+ if (username || password) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: auth not supported (yet!)");
+ return -1;
+
+ } else {
+ static const char login_null_pkt[16] = {
+ RPCAP_VERSION_EXPERIMENTAL,
+ RPCAP_MSG_AUTH_REQ,
+ 0, 0,
+ 0, 0, 0, 8,
+
+ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ if (rpcap_send_pkt(p, login_null_pkt, sizeof(login_null_pkt)))
+ return -1;
+ }
+
+ return rpcap_recv_pkt(p, p->fd, NULL, 0);
+}
+
+static int
+rpcap_send_request_open(pcap_t *p, const char *interface)
+{
+ const size_t interface_len = strlen(interface);
+
+ char buf_open[8+255] = {
+ RPCAP_VERSION_EXPERIMENTAL,
+ RPCAP_MSG_OPEN_REQ,
+ 0, 0,
+ 0, 0, 0, interface_len
+ };
+
+ char reply_buf[8];
+ int reply_len;
+
+ if (interface_len > 255) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "rpcap: maximum interface length: 255");
+ return -1;
+ }
+
+ memcpy(buf_open + 8, interface, interface_len);
+ if (rpcap_send_pkt(p, buf_open, 8 + interface_len))
+ return -1;
+
+ reply_len = rpcap_recv_pkt(p, p->fd, reply_buf, sizeof(reply_buf));
+ if (reply_len != sizeof(reply_buf)) {
+ if (reply_len >= 0)
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Bad protocol (openreply: %u)", reply_len);
+ return -1;
+ }
+
+ p->linktype = get32(&reply_buf[0]);
+ p->tzoff = get32(&reply_buf[4]);
+
+ return 0;
+}
+
+static int
+rpcap_send_request_start(pcap_t *p, struct in_addr *server_ip)
+{
+ char buf_start[8+12+8+8] = {
+ RPCAP_VERSION_EXPERIMENTAL,
+ RPCAP_MSG_STARTCAP_REQ,
+ 0, 0,
+ 0, 0, 0, 12+8+8,
+/* rpcap_startcapreq (12B) */
+ 0xff, 0xff, 0xff, 0xff, /* snaplen */
+ 0xff, 0xff, 0xff, 0xff, /* timeout */
+ 0x00, 0x00, /* flags */
+ 0x00, 0x00, /* portdata */
+/* rpcap_filter (8B+8B) */
+ 0x00, RPCAP_UPDATEFILTER_BPF, /* filtertype */
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+
+ 0x00, 0x06, /* ret */
+ 0x00,
+ 0x00,
+ 0x00, 0x00, 0xff, 0xff /* #65535 */
+ };
+
+ struct sockaddr_in sin;
+ char reply_buf[8];
+ int reply_len;
+ int fd;
+
+ unsigned int buf_size;
+ unsigned short portdata;
+
+ put32(&buf_start[8], p->snapshot); /* snaplen */
+ put32(&buf_start[12], p->md.timeout/2); /* read_timeout */
+
+ if (rpcap_send_pkt(p, buf_start, sizeof(buf_start)))
+ return -1;
+
+ reply_len = rpcap_recv_pkt(p, p->fd, reply_buf, sizeof(reply_buf));
+ if (reply_len != sizeof(reply_buf)) {
+ if (reply_len >= 0)
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Bad protocol (startreply: %u)", reply_len);
+ return -1;
+ }
+
+ buf_size = get32(&reply_buf[0]);
+ portdata = get16(&reply_buf[4]);
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't create data socket %d:%s",
+ errno, pcap_strerror(errno));
+ return -1;
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_addr = *server_ip;
+ sin.sin_port = htons(portdata);
+
+ if (connect(fd, (struct sockaddr *) &sin, sizeof(sin))) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't connect to data socket (%d:%s)",
+ errno, pcap_strerror(errno));
+ return -1;
+ }
+ p->selectable_fd = fd;
+
+ return 0;
+}
+
+static int
+rpcap_inject_common(pcap_t *handle, const void *buf, size_t size)
+{
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported with remote capture");
+ return -1;
+}
+
+static int
+rpcap_stats_common(pcap_t *handle, struct pcap_stat *stats)
+{
+ static const char buf_stats[8] = {
+ RPCAP_VERSION_EXPERIMENTAL,
+ RPCAP_MSG_STATS_REQ,
+ 0, 0,
+ 0, 0, 0, 0
+ };
+
+ char reply_buf[16];
+ int reply_len;
+
+/* local */
+#if 0
+ stats->ps_recv = handle->md.packets_read;
+ stats->ps_drop = 0;
+ stats->ps_ifdrop = 0;
+#endif
+
+/* remote */
+ if (rpcap_send_pkt(handle, buf_stats, sizeof(buf_stats)))
+ return -1;
+
+ reply_len = rpcap_recv_pkt(handle, handle->fd, reply_buf, sizeof(reply_buf));
+ if (reply_len != sizeof(reply_buf)) {
+ if (reply_len >= 0)
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Bad protocol (statsreply: %u)", reply_len);
+ return -1;
+ }
+
+ stats->ps_recv = get32(&reply_buf[0]);
+ stats->ps_ifdrop = get32(&reply_buf[4]);
+ stats->ps_drop = get32(&reply_buf[8]);
+ return 0;
+}
+
+static int
+rpcap_setfilter_common(pcap_t *handle, struct bpf_program *prog)
+{
+ char *buf_setfilter;
+
+ /* update local filter */
+ if (install_bpf_program(handle, prog) == -1)
+ return -1;
+
+ /* update remote filter */
+ if (prog->bf_len < 0xfffff) {
+ unsigned int data_size = 8 + 8 * prog->bf_len;
+ char *buf_filter;
+ char *buf_insn;
+ int i;
+
+ buf_setfilter = malloc(8 + data_size);
+ if (!buf_setfilter) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "No memory for setfilter packet");
+ return -1;
+ }
+
+ buf_filter = &buf_setfilter[8];
+ buf_insn = &buf_filter[8];
+
+ put16(&buf_filter[0], RPCAP_UPDATEFILTER_BPF);
+ put16(&buf_filter[2], 0);
+ put32(&buf_filter[4], prog->bf_len);
+
+ for (i = 0; i < prog->bf_len; i++) {
+ char *data = &buf_insn[i * 8];
+
+ put16(&data[0], prog->bf_insns[i].code);
+ data[2] = prog->bf_insns[i].jt;
+ data[3] = prog->bf_insns[i].jf;
+ put32(&data[4], prog->bf_insns[i].k);
+ }
+
+ if (rpcap_send_request(handle, RPCAP_MSG_UPDATEFILTER_REQ, buf_setfilter, data_size)) {
+ free(buf_setfilter);
+ return -1;
+ }
+ free(buf_setfilter);
+
+ if (rpcap_recv_pkt(handle, handle->fd, NULL, 0) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static int
+rpcap_read_unix(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
+{
+ struct pcap_pkthdr pkth;
+ const char *pkt;
+ const char *buf;
+ int pkt_len;
+ int count = 0;
+
+ pkt_len = rpcap_recv_pkt(handle, handle->selectable_fd, handle->buffer, handle->bufsize);
+ if (pkt_len < 20) {
+ if (pkt_len >= 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pkt_len check failed (%u < 20)", pkt_len);
+ return -1;
+ }
+ return pkt_len;
+ }
+ buf = handle->buffer;
+
+/* local */
+#if 0
+ gettimeofday(&pkth.ts, NULL);
+ pkth.caplen = pkth.len = pkt_len - 20
+#endif
+/* remote */
+ pkth.ts.tv_sec = get32(&buf[0]);
+ pkth.ts.tv_usec = get32(&buf[4]);
+ pkth.caplen = get32(&buf[8]);
+ pkth.len = get32(&buf[12]);
+ /* pktnr */
+ pkt = &buf[20];
+
+ /* sanity caplen */
+ if (pkt_len - 20 < pkth.caplen) {
+ /* pkt.caplen = pkt_len - 20; */
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "pkth.caplen check failed (%u < %u)", pkt_len - 20, pkth.caplen);
+ return -1;
+ }
+
+ if (handle->fcode.bf_insns == NULL ||
+ bpf_filter(handle->fcode.bf_insns, pkt, pkth.len, pkth.caplen))
+ {
+ handle->md.packets_read++;
+ callback(user, &pkth, pkt);
+ count++;
+ }
+ return count;
+}
+
+static void
+rpcap_cleanup(pcap_t *handle)
+{
+ if (handle->selectable_fd != handle->fd) {
+ int fd = handle->selectable_fd;
+
+ if (fd != -1) {
+ handle->selectable_fd = -1;
+ close(fd);
+ }
+ }
+ pcap_cleanup_live_common(handle);
+}
+
+static int
+rpcap_activate(pcap_t *handle)
+{
+ const char *dev = handle->opt.source;
+ const char *tmp;
+
+ char *host;
+ char *username = NULL;
+ char *password = NULL;
+ const char *interface = NULL;
+ int port;
+
+ struct sockaddr_in sin;
+
+ /* rpcap[s]://login:password@host:port/interface */
+ if (strncmp(dev, RPCAP_IFACE, strlen(RPCAP_IFACE)) == 0) {
+ port = RPCAP_DEFAULT_NETPORT;
+ dev += strlen(RPCAP_IFACE);
+
+ } /* else if (strncmp(dev, "rpcaps://", strlen("rpcaps://")) == 0) {
+ port = RPCAP_DEFAULT_NETPORT_SSL;
+ dev += strlen("rpcaps://");
+
+ } */ else {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "rpcap: invalid protocol");
+ return PCAP_ERROR;
+ }
+
+ if ((tmp = strchr(dev, '@'))) {
+ char *ptmp;
+
+ if ((ptmp = strchr(dev, ':'))) {
+ username = strndup(dev, ptmp-dev);
+ password = strndup(ptmp+1, tmp-(ptmp+1));
+
+ } else {
+ username = strndup(dev, tmp-dev);
+
+ /* XXX, ask for password? */
+ }
+
+ dev = tmp + 1;
+ }
+
+ if (*dev == '[') {
+ tmp = strchr(dev, ']');
+ if (!tmp) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "rpcap: invalid host (missing ']')");
+ return PCAP_ERROR;
+ }
+
+ host = strndup(dev+1, tmp-(dev+1));
+
+ dev = tmp + 1;
+ } else {
+ tmp = strchr(dev, ':');
+ if (!tmp)
+ tmp = strchr(dev, '/');
+
+ if (tmp) {
+ host = strndup(dev, tmp-dev);
+ dev = tmp;
+ } else
+ host = strdup(dev);
+ }
+
+ if (*dev == ':') {
+ char *end;
+
+ if (dev[1] == '\0') {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "rpcap: missing port");
+ return PCAP_ERROR;
+ }
+
+ port = strtol(dev + 1, &end, 10);
+ if (port < 1 || port > 65535) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "rpcap: invalid port");
+ return PCAP_ERROR;
+ }
+
+ dev = end;
+ }
+
+ if (*dev == '/')
+ interface = dev+1;
+
+ if (!host) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "rpcap: couldn't parse host");
+ return PCAP_ERROR;
+ }
+
+ if (!interface) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "rpcap: couldn't parse interface");
+ return PCAP_ERROR;
+ }
+
+ /* XXX, gethostbyname, ipv6, etc... */
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(host);
+ sin.sin_port = htons(port);
+ if (sin.sin_addr.s_addr == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "rpcap: not ipv4 address");
+ goto free_fail;
+ }
+
+ /* Initialize some components of the pcap structure. */
+ handle->offset = 20;
+ handle->bufsize = handle->snapshot + handle->offset;
+ handle->linktype = -1; /* invalid for now */
+ handle->read_op = rpcap_read_unix;
+ handle->setfilter_op = rpcap_setfilter_common;
+ handle->inject_op = rpcap_inject_common;
+ handle->setdirection_op = NULL;
+ handle->set_datalink_op = NULL; /* not possible */
+ handle->getnonblock_op = pcap_getnonblock_fd;
+ handle->setnonblock_op = pcap_setnonblock_fd;
+ handle->stats_op = rpcap_stats_common;
+ handle->cleanup_op = rpcap_cleanup;
+
+ /* Create socket */
+ handle->fd = socket(AF_INET, SOCK_STREAM, 0);
+ handle->selectable_fd = -1;
+ if (handle->fd < 0) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't create socket %d:%s",
+ errno, pcap_strerror(errno));
+ goto close_fail;
+ }
+
+ if (connect(handle->fd, (struct sockaddr *) &sin, sizeof(sin))) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't connect to %s:%d (%d:%s)",
+ host, port, errno, pcap_strerror(errno));
+ goto free_fail;
+ }
+
+/* login */
+ if (rpcap_send_request_auth(handle, username, password) < 0)
+ goto close_fail;
+ if (rpcap_send_request_open(handle, interface) < 0)
+ goto close_fail;
+ if (rpcap_send_request_start(handle, &(sin.sin_addr)) < 0)
+ goto close_fail;
+
+ handle->buffer = malloc(handle->bufsize);
+ if (!handle->buffer) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't allocate dump buffer: %s",
+ pcap_strerror(errno));
+ goto close_fail;
+ }
+
+ if (handle->opt.rfmon) {
+ /*
+ * Monitor mode doesn't apply to rpcap.
+ */
+ rpcap_cleanup(handle);
+ return PCAP_ERROR_RFMON_NOTSUP;
+ }
+
+ if (handle->opt.buffer_size != 0) {
+ /*
+ * Set the socket buffer size to the specified value.
+ */
+ if (setsockopt(handle->selectable_fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) {
+ snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SO_RCVBUF: %s", pcap_strerror(errno));
+ goto close_fail;
+ }
+ }
+ free(username);
+ free(password);
+ free(host);
+
+ return 0;
+
+close_fail:
+ rpcap_cleanup(handle);
+free_fail:
+ free(username);
+ free(password);
+ free(host);
+ return PCAP_ERROR;
+}
+
+pcap_t *
+rpcap_create(const char *device, char *err_str, int *is_ours)
+{
+ const char *cp = device;
+ pcap_t *p;
+
+ if (strncmp(cp, RPCAP_IFACE, strlen(RPCAP_IFACE)) == 0)
+ cp += strlen(RPCAP_IFACE);
+ else {
+ *is_ours = 0;
+ return NULL;
+ }
+
+ if (*cp == '\0') {
+ *is_ours = 0;
+ return NULL;
+ }
+
+ *is_ours = 1;
+
+ p = pcap_create_common(device, err_str);
+ if (p == NULL)
+ return NULL;
+
+ p->activate_op = rpcap_activate;
+ return p;
+}
+
diff --git a/external/bsd/libpcap/dist/pcap-rpcap-unix.h b/external/bsd/libpcap/dist/pcap-rpcap-unix.h
new file mode 100644
index 00000000000..a9a3f834ff6
--- /dev/null
+++ b/external/bsd/libpcap/dist/pcap-rpcap-unix.h
@@ -0,0 +1 @@
+pcap_t *rpcap_create(const char *device, char *err_str, int *is_ours);
diff --git a/external/bsd/libpcap/dist/pcap.c b/external/bsd/libpcap/dist/pcap.c
index 1861f9abc1e..9f413364fb9 100644
--- a/external/bsd/libpcap/dist/pcap.c
+++ b/external/bsd/libpcap/dist/pcap.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pcap.c,v 1.9 2019/10/01 16:02:12 christos Exp $ */
+/* $NetBSD: pcap.c,v 1.10 2020/03/29 19:49:26 christos Exp $ */
/*
* Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: pcap.c,v 1.9 2019/10/01 16:02:12 christos Exp $");
+__RCSID("$NetBSD: pcap.c,v 1.10 2020/03/29 19:49:26 christos Exp $");
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -125,6 +125,10 @@ struct rtentry; /* declarations in <net/if.h> */
#include "pcap-dbus.h"
#endif
+#ifdef PCAP_SUPPORT_RPCAP
+#include "pcap-rpcap-unix.h"
+#endif
+
#ifdef PCAP_SUPPORT_RDMASNIFF
#include "pcap-rdmasniff.h"
#endif
@@ -554,6 +558,9 @@ static struct capture_source_type {
#ifdef PCAP_SUPPORT_RDMASNIFF
{ rdmasniff_findalldevs, rdmasniff_create },
#endif
+#ifdef PCAP_SUPPORT_RPCAP
+ { NULL, rpcap_create },
+#endif
{ NULL, NULL }
};