attachment/rpcap3.patch to provide rpcap support.
This commit is contained in:
parent
7d80d661b8
commit
e770cc2dd9
766
external/bsd/libpcap/dist/pcap-rpcap-unix.c
vendored
Normal file
766
external/bsd/libpcap/dist/pcap-rpcap-unix.c
vendored
Normal file
@ -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;
|
||||
}
|
||||
|
1
external/bsd/libpcap/dist/pcap-rpcap-unix.h
vendored
Normal file
1
external/bsd/libpcap/dist/pcap-rpcap-unix.h
vendored
Normal file
@ -0,0 +1 @@
|
||||
pcap_t *rpcap_create(const char *device, char *err_str, int *is_ours);
|
11
external/bsd/libpcap/dist/pcap.c
vendored
11
external/bsd/libpcap/dist/pcap.c
vendored
@ -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
|
||||
@ -553,6 +557,9 @@ static struct capture_source_type {
|
||||
#endif
|
||||
#ifdef PCAP_SUPPORT_RDMASNIFF
|
||||
{ rdmasniff_findalldevs, rdmasniff_create },
|
||||
#endif
|
||||
#ifdef PCAP_SUPPORT_RPCAP
|
||||
{ NULL, rpcap_create },
|
||||
#endif
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user