Add support for sending packets; includes contributions from Mark
Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>.
This commit is contained in:
parent
3380fa10db
commit
2d2890dd37
1
CREDITS
1
CREDITS
|
@ -55,6 +55,7 @@ Additional people who have contributed patches:
|
|||
Love Hörnquist-Ĺstrand <lha@stacken.kth.se>
|
||||
Maciej W. Rozycki <macro@ds2.pg.gda.pl>
|
||||
Marcus Felipe Pereira <marcus@task.com.br>
|
||||
Mark Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>
|
||||
Martin Husemann <martin@netbsd.org>
|
||||
Mike Wiacek <mike@iroot.net>
|
||||
Monroe Williams <monroe@pobox.com>
|
||||
|
|
44
pcap-bpf.c
44
pcap-bpf.c
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.73 2003-12-24 08:26:24 itojun Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.74 2004-03-23 19:18:04 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -292,6 +292,29 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|||
return (n);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_inject_bpf(pcap_t *p, const void *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Do a BIOCSHDRCMPLT, if defined, to turn that flag on, so
|
||||
* the link-layer source address isn't forcibly overwritten?
|
||||
* (Ignore errors? Return errors if not "sorry, that ioctl
|
||||
* isn't supported?)
|
||||
*
|
||||
* XXX - I seem to remember some packet-sending bug in some
|
||||
* BSDs - check CVS log for "bpf.c"?
|
||||
*/
|
||||
ret = write(p->fd, buf, size);
|
||||
if (ret == -1) {
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef _AIX
|
||||
static int
|
||||
bpf_odminit(char *errbuf)
|
||||
|
@ -467,7 +490,23 @@ bpf_open(pcap_t *p, char *errbuf)
|
|||
*/
|
||||
do {
|
||||
(void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
|
||||
fd = open(device, O_RDONLY);
|
||||
/*
|
||||
* Initially try a read/write open (to allow the inject
|
||||
* method to work). If that fails due to permission
|
||||
* issues, fall back to read-only. This allows a
|
||||
* non-root user to be granted specific access to pcap
|
||||
* capabilities via file permissions.
|
||||
*
|
||||
* XXX - we should have an API that has a flag that
|
||||
* controls whether to open read-only or read-write,
|
||||
* so that denial of permission to send (or inability
|
||||
* to send, if sending packets isn't supported on
|
||||
* the device in question) can be indicated at open
|
||||
* time.
|
||||
*/
|
||||
fd = open(device, O_RDWR);
|
||||
if (fd == -1 && errno == EACCES)
|
||||
fd = open(device, O_RDONLY);
|
||||
} while (fd < 0 && errno == EBUSY);
|
||||
|
||||
/*
|
||||
|
@ -898,6 +937,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
}
|
||||
|
||||
p->read_op = pcap_read_bpf;
|
||||
p->inject_op = pcap_inject_bpf;
|
||||
p->setfilter_op = pcap_setfilter_bpf;
|
||||
p->set_datalink_op = pcap_set_datalink_bpf;
|
||||
p->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
|
11
pcap-dag.c
11
pcap-dag.c
|
@ -15,7 +15,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.17 2004-01-30 02:23:53 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.18 2004-03-23 19:18:04 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -377,6 +377,14 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|||
return processed;
|
||||
}
|
||||
|
||||
static int
|
||||
dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
|
||||
{
|
||||
strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards",
|
||||
PCAP_ERRBUF_SIZE);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a handle for a live capture from the given DAG device. Passing a NULL
|
||||
* device will result in a failure. The promisc flag is ignored because DAG
|
||||
|
@ -503,6 +511,7 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu
|
|||
#endif
|
||||
|
||||
handle->read_op = dag_read;
|
||||
handle->inject_op = dag_inject;
|
||||
handle->setfilter_op = dag_setfilter;
|
||||
handle->set_datalink_op = dag_set_datalink;
|
||||
handle->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
|
101
pcap-dlpi.c
101
pcap-dlpi.c
|
@ -38,7 +38,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.95 2003-12-18 23:32:32 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.96 2004-03-23 19:18:05 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -220,6 +220,11 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|||
p->break_loop = 0;
|
||||
return (-2);
|
||||
}
|
||||
/*
|
||||
* XXX - check for the DLPI primitive, which
|
||||
* would be DL_HP_RAWDATA_IND on HP-UX
|
||||
* if we're in raw mode?
|
||||
*/
|
||||
if (getmsg(p->fd, &ctl, &data, &flags) < 0) {
|
||||
/* Don't choke when we get ptraced */
|
||||
if (errno == EINTR) {
|
||||
|
@ -306,6 +311,23 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|||
return (n);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_inject_dlpi(pcap_t *p, const void *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* XXX - use "dlunitdatareq()" on HP-UX.
|
||||
*/
|
||||
ret = write(p->fd, buf, size);
|
||||
if (ret == -1) {
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifndef DL_IPATM
|
||||
#define DL_IPATM 0x12 /* ATM Classical IP interface */
|
||||
#endif
|
||||
|
@ -573,6 +595,8 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
|
||||
/*
|
||||
** Determine link type
|
||||
** XXX - get SAP length and address length as well, for use
|
||||
** when sending packets.
|
||||
*/
|
||||
if (dlinforeq(p->fd, ebuf) < 0 ||
|
||||
dlinfoack(p->fd, (char *)buf, ebuf) < 0)
|
||||
|
@ -612,6 +636,9 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
break;
|
||||
|
||||
case DL_TPR:
|
||||
/*
|
||||
* XXX - what about DL_TPB? Is that Token Bus?
|
||||
*/
|
||||
p->linktype = DLT_IEEE802;
|
||||
p->offset = 2;
|
||||
break;
|
||||
|
@ -730,6 +757,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
p->selectable_fd = p->fd;
|
||||
|
||||
p->read_op = pcap_read_dlpi;
|
||||
p->inject_op = pcap_inject_dlpi;
|
||||
p->setfilter_op = install_bpf_program; /* no kernel filtering */
|
||||
p->set_datalink_op = NULL; /* can't change data link type */
|
||||
p->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
@ -1194,6 +1222,77 @@ dlinfoack(int fd, char *bufp, char *ebuf)
|
|||
return (recv_ack(fd, DL_INFO_ACK_SIZE, "info", bufp, ebuf));
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* No ack?
|
||||
*
|
||||
* On HP-UX, use DL_HP_RAWDATA_REQ instead, *if* we're in RAW mode.
|
||||
* There is an ack *IF* there's an error.
|
||||
*
|
||||
* XXX - this is not needed on Solaris; we're running in raw mode so
|
||||
* we can just do a "write()".
|
||||
* What about, say, AIX?
|
||||
*/
|
||||
static int
|
||||
dlunitdatareq(int fd, u_char *addrp, int addrlen, u_char *datap, int datalen)
|
||||
{
|
||||
struct strbuf ctl, data;
|
||||
long buf[MAXDLBUF]; /* XXX - char? */
|
||||
union DL_primitives *dlp;
|
||||
|
||||
dlp = (union DL_primitives*) buf;
|
||||
|
||||
dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
|
||||
dlp->unitdata_req.dl_dest_addr_length = addrlen;
|
||||
dlp->unitdata_req.dl_dest_addr_offset = DL_UNITDATA_REQ_SIZE;
|
||||
dlp->unitdata_req.dl_priority.dl_min = 0;
|
||||
dlp->unitdata_req.dl_priority.dl_max = 0
|
||||
|
||||
/*
|
||||
* XXX - the "address", on Ethernet, is the destination address,
|
||||
* followed by the link-layer type. What is it for other
|
||||
* link layers?
|
||||
*
|
||||
* The address length "dl_addr_length" from the "info_ack"
|
||||
* structure is the total length of the link-layer address.
|
||||
*
|
||||
* The SAP length "dl_sap_length" is the length of the SAP part
|
||||
* of the address.
|
||||
* If positive, the SAP comes before the destination address;
|
||||
* if negative, the SAP comes after the destination address.
|
||||
*
|
||||
* XXX - what about Ethernet vs. 802.3? Is the SAP the Ethertype
|
||||
* or the DSAP? How can we send both? *Can* we send both on
|
||||
* the same device?
|
||||
*
|
||||
* Note that in raw mode, we send a raw link-layer packet.
|
||||
* In that mode, can we avoid worrying about this crap?
|
||||
*
|
||||
* For ATM (ha ha), we might not be able to send packets,
|
||||
* even in raw mode, without binding to a VC. (Presumably
|
||||
* going into SAP promiscuous mode lets us *see* all packets.)
|
||||
*
|
||||
* XXX - extract it from the packet to be sent.
|
||||
*/
|
||||
memcpy((char *)dlp + DL_UNITDATA_REQ_SIZE, addrp, addrlen);
|
||||
|
||||
ctl.maxlen = 0;
|
||||
ctl.len = DL_UNITDATA_REQ_SIZE + addrlen;
|
||||
ctl.buf = buf;
|
||||
|
||||
data.maxlen = 0;
|
||||
data.len = datalen;
|
||||
data.buf = datap;
|
||||
|
||||
if (putmsg(fd, &ctl, &data, 0) < 0) {
|
||||
snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
||||
"dlunitdatareq: putmsg: %s", pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_BUFMOD_H
|
||||
static int
|
||||
strioctl(int fd, int cmd, int len, char *dp)
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.61 2003-12-21 22:00:10 guy Exp $ (LBL)
|
||||
* @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.62 2004-03-23 19:18:05 guy Exp $ (LBL)
|
||||
*/
|
||||
|
||||
#ifndef pcap_int_h
|
||||
|
@ -74,13 +74,14 @@ struct pcap_md {
|
|||
u_long TotDrops; /* count of dropped packets */
|
||||
long TotMissed; /* missed by i/f during this run */
|
||||
long OrigMissed; /* missed by i/f before this run */
|
||||
char *device; /* device name */
|
||||
#ifdef linux
|
||||
int sock_packet; /* using Linux 2.0 compatible interface */
|
||||
int timeout; /* timeout specified to pcap_open_live */
|
||||
int clear_promisc; /* must clear promiscuous mode when we close */
|
||||
int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */
|
||||
int ifindex; /* interface index of device we're bound to */
|
||||
int lo_ifindex; /* interface index of the loopback device */
|
||||
char *device; /* device name */
|
||||
struct pcap *next; /* list of open promiscuous sock_packet pcaps */
|
||||
#endif
|
||||
|
||||
|
@ -130,6 +131,7 @@ struct pcap {
|
|||
* Methods.
|
||||
*/
|
||||
int (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);
|
||||
int (*inject_op)(pcap_t *, const void *, size_t);
|
||||
int (*setfilter_op)(pcap_t *, struct bpf_program *);
|
||||
int (*set_datalink_op)(pcap_t *, int);
|
||||
int (*getnonblock_op)(pcap_t *, char *);
|
||||
|
|
87
pcap-linux.c
87
pcap-linux.c
|
@ -27,7 +27,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.105 2004-01-14 01:56:10 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.106 2004-03-23 19:18:05 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -188,6 +188,7 @@ static int live_open_old(pcap_t *, const char *, int, int, char *);
|
|||
static int live_open_new(pcap_t *, const char *, int, int, char *);
|
||||
static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *);
|
||||
static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
|
||||
static int pcap_inject_linux(pcap_t *, const void *, size_t);
|
||||
static int pcap_stats_linux(pcap_t *, struct pcap_stat *);
|
||||
static int pcap_setfilter_linux(pcap_t *, struct bpf_program *);
|
||||
static void pcap_close_linux(pcap_t *);
|
||||
|
@ -404,6 +405,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
handle->selectable_fd = handle->fd;
|
||||
|
||||
handle->read_op = pcap_read_linux;
|
||||
handle->inject_op = pcap_inject_linux;
|
||||
handle->setfilter_op = pcap_setfilter_linux;
|
||||
handle->set_datalink_op = NULL; /* can't change data link type */
|
||||
handle->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
@ -672,6 +674,63 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_inject_linux(pcap_t *handle, const void *buf, size_t size)
|
||||
{
|
||||
#ifdef HAVE_PF_PACKET_SOCKETS
|
||||
struct sockaddr_ll sa_ll;
|
||||
#endif
|
||||
struct sockaddr_pkt sa_pkt;
|
||||
int ret;
|
||||
|
||||
#ifdef HAVE_PF_PACKET_SOCKETS
|
||||
if (!handle->md.sock_packet)) {
|
||||
/* PF_PACKET socket */
|
||||
if (handle->md.ifindex == -1) {
|
||||
/*
|
||||
* Cooked mode - can't send.
|
||||
* XXX - how do you send on a bound cooked-mode
|
||||
* socket?
|
||||
*/
|
||||
strlcpy(handle->errbuf,
|
||||
"Sending packets isn't supported in cooked mode",
|
||||
PCAP_ERRBUF_SIZE);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memset(&sa_ll, 0, sizeof(sa_ll));
|
||||
sa_ll.sll_family = AF_PACKET;
|
||||
sa_ll.sll_ifindex = handle->md.ifindex;
|
||||
/*
|
||||
* Do we have to set the hardware address?
|
||||
*/
|
||||
sa_ll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
ret = sendto(handle->fd, buf, size, 0, &sa_ll, sizeof(sa_ll));
|
||||
if (ret == -1) {
|
||||
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
memset(&sa_pkt, 0, sizeof(sa_pkt));
|
||||
sa_pkt.spkt_family = PF_INET;
|
||||
strcpy(sa_pkt.spkt_device, handle->md.device);
|
||||
/*
|
||||
* Do we have to set "spkt_protocol" to the Ethernet protocol?
|
||||
*/
|
||||
|
||||
ret = sendto(handle->fd, buf, size, 0, &sa, sizeof(sa)));
|
||||
if (ret == -1) {
|
||||
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the statistics for the given packet capture handle.
|
||||
* Reports the number of dropped packets iff the kernel supports
|
||||
|
@ -1221,7 +1280,7 @@ live_open_new(pcap_t *handle, const char *device, int promisc,
|
|||
int to_ms, char *ebuf)
|
||||
{
|
||||
#ifdef HAVE_PF_PACKET_SOCKETS
|
||||
int sock_fd = -1, device_id, arptype;
|
||||
int sock_fd = -1, arptype;
|
||||
int err;
|
||||
int fatal_err = 0;
|
||||
struct packet_mreq mr;
|
||||
|
@ -1341,11 +1400,12 @@ live_open_new(pcap_t *handle, const char *device, int promisc,
|
|||
handle->linktype = DLT_LINUX_SLL;
|
||||
}
|
||||
|
||||
device_id = iface_get_id(sock_fd, device, ebuf);
|
||||
if (device_id == -1)
|
||||
handle->md.ifindex = iface_get_id(sock_fd, device, ebuf);
|
||||
if (handle->md.ifindex == -1)
|
||||
break;
|
||||
|
||||
if ((err = iface_bind(sock_fd, device_id, ebuf)) < 0) {
|
||||
if ((err = iface_bind(sock_fd, handle->md.ifindex,
|
||||
ebuf)) < 0) {
|
||||
if (err == -2)
|
||||
fatal_err = 1;
|
||||
break;
|
||||
|
@ -1358,14 +1418,15 @@ live_open_new(pcap_t *handle, const char *device, int promisc,
|
|||
handle->linktype = DLT_LINUX_SLL;
|
||||
|
||||
/*
|
||||
* XXX - squelch GCC complaints about
|
||||
* uninitialized variables; if we can't
|
||||
* select promiscuous mode on all interfaces,
|
||||
* we should move the code below into the
|
||||
* "if (device)" branch of the "if" and
|
||||
* get rid of the next statement.
|
||||
* We're not bound to a device.
|
||||
* XXX - true? Or true only if we're using
|
||||
* the "any" device?
|
||||
* For now, we're using this as an indication
|
||||
* that we can't transmit; stop doing that only
|
||||
* if we figure out how to transmit in cooked
|
||||
* mode.
|
||||
*/
|
||||
device_id = -1;
|
||||
handle->md.ifindex = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1389,7 +1450,7 @@ live_open_new(pcap_t *handle, const char *device, int promisc,
|
|||
|
||||
if (device && promisc) {
|
||||
memset(&mr, 0, sizeof(mr));
|
||||
mr.mr_ifindex = device_id;
|
||||
mr.mr_ifindex = handle->md.ifindex;
|
||||
mr.mr_type = PACKET_MR_PROMISC;
|
||||
if (setsockopt(sock_fd, SOL_PACKET,
|
||||
PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1)
|
||||
|
|
32
pcap-nit.c
32
pcap-nit.c
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.55 2004-03-21 08:32:05 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.56 2004-03-23 19:18:06 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -192,6 +192,23 @@ pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|||
return (n);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_inject_nit(pcap_t *p, const void *buf, size_t size)
|
||||
{
|
||||
struct sockaddr sa;
|
||||
int ret;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
strncpy(sa.sa_data, device, sizeof(sa.sa_data));
|
||||
ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa));
|
||||
if (ret == -1) {
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
|
||||
{
|
||||
|
@ -226,6 +243,8 @@ pcap_close_nit(pcap_t *p)
|
|||
{
|
||||
if (p->buffer != NULL)
|
||||
free(p->buffer);
|
||||
if (p->device != NULL)
|
||||
free(p->device);
|
||||
if (p->fd >= 0)
|
||||
close(p->fd);
|
||||
}
|
||||
|
@ -280,6 +299,16 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need the device name in order to send packets.
|
||||
*/
|
||||
p->device = strdup(device);
|
||||
if (p->device == NULL) {
|
||||
strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
|
||||
free(p->buffer);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* "p->fd" is a socket, so "select()" should work on it.
|
||||
*/
|
||||
|
@ -306,6 +335,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
}
|
||||
|
||||
p->read_op = pcap_read_nit;
|
||||
p->inject_op = pcap_inject_nit;
|
||||
p->setfilter_op = install_bpf_program; /* no kernel filtering */
|
||||
p->set_datalink_op = NULL; /* can't change data link type */
|
||||
p->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
|
35
pcap-pf.c
35
pcap-pf.c
|
@ -24,7 +24,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.86 2004-02-09 06:24:42 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.87 2004-03-23 19:18:06 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -219,6 +219,20 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
|
|||
return (n);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_inject_pf(pcap_t *p, const void *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = write(p->fd, buf, size);
|
||||
if (ret == -1) {
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_stats_pf(pcap_t *p, struct pcap_stat *ps)
|
||||
{
|
||||
|
@ -299,14 +313,28 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
return (0);
|
||||
}
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
/*
|
||||
* Initially try a read/write open (to allow the inject
|
||||
* method to work). If that fails due to permission
|
||||
* issues, fall back to read-only. This allows a
|
||||
* non-root user to be granted specific access to pcap
|
||||
* capabilities via file permissions.
|
||||
*
|
||||
* XXX - we should have an API that has a flag that
|
||||
* controls whether to open read-only or read-write,
|
||||
* so that denial of permission to send (or inability
|
||||
* to send, if sending packets isn't supported on
|
||||
* the device in question) can be indicated at open
|
||||
* time.
|
||||
*
|
||||
* XXX - we assume here that "pfopen()" does not, in fact, modify
|
||||
* its argument, even though it takes a "char *" rather than a
|
||||
* "const char *" as its first argument. That appears to be
|
||||
* the case, at least on Digital UNIX 4.0.
|
||||
*/
|
||||
p->fd = pfopen(device, O_RDONLY);
|
||||
p->fd = pfopen(device, O_RDWR);
|
||||
if (p->fd == -1 && errno == EACCES)
|
||||
p->fd = pfopen(device, O_RDONLY);
|
||||
if (p->fd < 0) {
|
||||
snprintf(ebuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\
|
||||
your system may not be properly configured; see the packetfilter(4) man page\n",
|
||||
|
@ -467,6 +495,7 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
|
|||
p->selectable_fd = p->fd;
|
||||
|
||||
p->read_op = pcap_read_pf;
|
||||
p->inject_op = pcap_inject_pf;
|
||||
p->setfilter_op = pcap_setfilter_pf;
|
||||
p->set_datalink_op = NULL; /* can't change data link type */
|
||||
p->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
|
44
pcap-snit.c
44
pcap-snit.c
|
@ -25,7 +25,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.70 2003-12-18 23:32:33 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.71 2004-03-23 19:18:06 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -204,6 +204,29 @@ pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|||
return (n);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_inject_snit(pcap_t *p, const void *buf, size_t size)
|
||||
{
|
||||
struct strbuf ctl, data;
|
||||
|
||||
/*
|
||||
* XXX - can we just do
|
||||
*
|
||||
ret = write(pd->f, buf, size);
|
||||
*/
|
||||
ctl.len = sizeof(*sa); /* XXX - what was this? */
|
||||
ctl.buf = (char *)sa;
|
||||
data.buf = buf;
|
||||
data.len = size;
|
||||
ret = putmsg(p->fd, &ctl, &data);
|
||||
if (ret == -1) {
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
|
||||
{
|
||||
|
@ -271,7 +294,23 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
snaplen = 96;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->fd = fd = open(dev, O_RDONLY);
|
||||
/*
|
||||
* Initially try a read/write open (to allow the inject
|
||||
* method to work). If that fails due to permission
|
||||
* issues, fall back to read-only. This allows a
|
||||
* non-root user to be granted specific access to pcap
|
||||
* capabilities via file permissions.
|
||||
*
|
||||
* XXX - we should have an API that has a flag that
|
||||
* controls whether to open read-only or read-write,
|
||||
* so that denial of permission to send (or inability
|
||||
* to send, if sending packets isn't supported on
|
||||
* the device in question) can be indicated at open
|
||||
* time.
|
||||
*/
|
||||
p->fd = fd = open(dev, O_RDWR);
|
||||
if (fd < 0 && errno == EACCES)
|
||||
p->fd = fd = open(dev, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s", dev,
|
||||
pcap_strerror(errno));
|
||||
|
@ -365,6 +404,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
}
|
||||
|
||||
p->read_op = pcap_read_snit;
|
||||
p->inject_op = pcap_inject_snit;
|
||||
p->setfilter_op = install_bpf_program; /* no kernel filtering */
|
||||
p->set_datalink_op = NULL; /* can't change data link type */
|
||||
p->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
|
19
pcap-snoop.c
19
pcap-snoop.c
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.51 2004-03-21 08:32:06 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.52 2004-03-23 19:18:06 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -125,6 +125,22 @@ again:
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_inject_snoop(pcap_t *p, const void *buf, size_t size)
|
||||
{
|
||||
/*
|
||||
* XXX - libnet overwrites the source address with what I
|
||||
* presume is the interface's address; is that required?
|
||||
*/
|
||||
ret = write(p->fd, buf, size);
|
||||
if (ret == -1) {
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
|
||||
pcap_strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
pcap_stats_snoop(pcap_t *p, struct pcap_stat *ps)
|
||||
{
|
||||
|
@ -358,6 +374,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
p->selectable_fd = p->fd;
|
||||
|
||||
p->read_op = pcap_read_snoop;
|
||||
p->inject_op = pcap_inject_snoop;
|
||||
p->setfilter_op = install_bpf_program; /* no kernel filtering */
|
||||
p->set_datalink_op = NULL; /* can't change data link type */
|
||||
p->getnonblock_op = pcap_getnonblock_fd;
|
||||
|
|
48
pcap-win32.c
48
pcap-win32.c
|
@ -32,7 +32,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.20 2004-01-28 14:06:20 risso Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.21 2004-03-23 19:18:07 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#include <pcap-int.h>
|
||||
|
@ -344,6 +344,29 @@ pcap_read_win32_dag(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|||
}
|
||||
#endif /* HAVE_DAG_API */
|
||||
|
||||
/* Send a packet to the network */
|
||||
static int
|
||||
pcap_inject_win32(pcap_t *p, const void *buf, size_t size){
|
||||
LPPACKET PacketToSend;
|
||||
|
||||
PacketToSend=PacketAllocatePacket();
|
||||
PacketInitPacket(PacketToSend,buf,size);
|
||||
if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: PacketSendPacket failed");
|
||||
PacketFreePacket(PacketToSend);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PacketFreePacket(PacketToSend);
|
||||
|
||||
/*
|
||||
* We assume it all got sent if "PacketSendPacket()" succeeded.
|
||||
* "pcap_inject()" is expected to return the number of bytes
|
||||
* sent.
|
||||
*/
|
||||
return size;
|
||||
}
|
||||
|
||||
static void
|
||||
pcap_close_win32(pcap_t *p)
|
||||
{
|
||||
|
@ -569,6 +592,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
|
|||
#ifdef HAVE_DAG_API
|
||||
}
|
||||
#endif /* HAVE_DAG_API */
|
||||
p->inject_op = pcap_inject_win32;
|
||||
p->set_datalink_op = NULL; /* can't change data link type */
|
||||
p->getnonblock_op = pcap_getnonblock_win32;
|
||||
p->setnonblock_op = pcap_setnonblock_win32;
|
||||
|
@ -686,28 +710,6 @@ pcap_setmode(pcap_t *p, int mode){
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Send a packet to the network */
|
||||
int
|
||||
pcap_sendpacket(pcap_t *p, u_char *buf, int size){
|
||||
LPPACKET PacketToSend;
|
||||
|
||||
if (p->adapter==NULL)
|
||||
{
|
||||
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Writing a packet is allowed only on a physical adapter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PacketToSend=PacketAllocatePacket();
|
||||
PacketInitPacket(PacketToSend,buf,size);
|
||||
if(PacketSendPacket(p->adapter,PacketToSend,TRUE) == FALSE){
|
||||
PacketFreePacket(PacketToSend);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PacketFreePacket(PacketToSend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the dimension of the kernel-level capture buffer */
|
||||
int
|
||||
pcap_setbuff(pcap_t *p, int dim)
|
||||
|
|
37
pcap.3
37
pcap.3
|
@ -1,4 +1,4 @@
|
|||
.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.58 2004-02-28 02:51:26 guy Exp $
|
||||
.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.59 2004-03-23 19:18:07 guy Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1994, 1996, 1997
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
|
@ -88,6 +88,11 @@ void pcap_breakloop(pcap_t *)
|
|||
.ft
|
||||
.LP
|
||||
.ft B
|
||||
int pcap_inject(pcap_t *p, const void *buf, size_t size)
|
||||
int pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
|
||||
.ft
|
||||
.LP
|
||||
.ft B
|
||||
int pcap_datalink(pcap_t *p)
|
||||
int pcap_list_datalinks(pcap_t *p, int **dlt_buf);
|
||||
int pcap_set_datalink(pcap_t *p, int dlt);
|
||||
|
@ -628,6 +633,36 @@ the flag is cleared, so a subsequent call will resume reading packets.
|
|||
If a positive number is returned, the flag is not cleared, so a
|
||||
subsequent call will return \-2 and clear the flag.
|
||||
.PP
|
||||
.B pcap_inject()
|
||||
sends a raw packet through the network interface;
|
||||
.I buf
|
||||
points to the data of the packet, including the link-layer header, and
|
||||
.I size
|
||||
is the number of bytes in the packet.
|
||||
It returns the number of bytes written on success. A return of \-1
|
||||
indicates an error in which case
|
||||
.B pcap_perror()
|
||||
or
|
||||
.B pcap_geterr()
|
||||
may be used to display the error text.
|
||||
Note that, even if you successfully open the network interface, you
|
||||
might not have permission to send packets on it, or it might not support
|
||||
sending packets; as
|
||||
.I pcap_open_live()
|
||||
doesn't have a flag to indicate whether to open for capturing, sending,
|
||||
or capturing and sending, you cannot request an open that supports
|
||||
sending and be notified at open time whether sending will be possible.
|
||||
Note also that some devices might not support sending packets.
|
||||
.PP
|
||||
.B pcap_sendpacket()
|
||||
is like
|
||||
.BR pcap_inject() ,
|
||||
but it returns 0 on success and \-1 on failure.
|
||||
.RB ( pcap_inject()
|
||||
comes from OpenBSD;
|
||||
.B pcap_sendpacket()
|
||||
comes from WinPcap. Both are provided for compatibility.)
|
||||
.PP
|
||||
.B pcap_dump()
|
||||
outputs a packet to the ``savefile'' opened with
|
||||
.BR pcap_dump_open() .
|
||||
|
|
26
pcap.c
26
pcap.c
|
@ -33,7 +33,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.72 2004-03-17 19:03:29 guy Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.73 2004-03-23 19:18:07 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -700,6 +700,30 @@ pcap_open_dead(int linktype, int snaplen)
|
|||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* API compatible with WinPcap's "send a packet" routine - returns -1
|
||||
* on error, 0 otherwise.
|
||||
*
|
||||
* XXX - what if we get a short write?
|
||||
*/
|
||||
int
|
||||
pcap_sendpacket(pcap_t *p, const u_char *buf, int size)
|
||||
{
|
||||
if (p->inject_op(p, buf, size) == -1)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* API compatible with OpenBSD's "send a packet" routine - returns -1 on
|
||||
* error, number of bytes written otherwise.
|
||||
*/
|
||||
int
|
||||
pcap_inject(pcap_t *p, const void *buf, size_t size)
|
||||
{
|
||||
return (p->inject_op(p, buf, size));
|
||||
}
|
||||
|
||||
void
|
||||
pcap_close(pcap_t *p)
|
||||
{
|
||||
|
|
5
pcap.h
5
pcap.h
|
@ -31,7 +31,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.49 2004-01-27 09:44:14 risso Exp $ (LBL)
|
||||
* @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.50 2004-03-23 19:18:07 guy Exp $ (LBL)
|
||||
*/
|
||||
|
||||
#ifndef lib_pcap_h
|
||||
|
@ -184,6 +184,8 @@ int pcap_setfilter(pcap_t *, struct bpf_program *);
|
|||
int pcap_getnonblock(pcap_t *, char *);
|
||||
int pcap_setnonblock(pcap_t *, int, char *);
|
||||
void pcap_perror(pcap_t *, char *);
|
||||
int pcap_inject(pcap_t *, const void *, size_t);
|
||||
int pcap_sendpacket(pcap_t *, const u_char *, int);
|
||||
char *pcap_strerror(int);
|
||||
char *pcap_geterr(pcap_t *);
|
||||
int pcap_compile(pcap_t *, struct bpf_program *, char *, int,
|
||||
|
@ -230,7 +232,6 @@ void bpf_dump(struct bpf_program *, int);
|
|||
|
||||
int pcap_setbuff(pcap_t *p, int dim);
|
||||
int pcap_setmode(pcap_t *p, int mode);
|
||||
int pcap_sendpacket(pcap_t *p, u_char *buf, int size);
|
||||
int pcap_setmintocopy(pcap_t *p, int size);
|
||||
|
||||
#ifdef WPCAP
|
||||
|
|
11
savefile.c
11
savefile.c
|
@ -30,7 +30,7 @@
|
|||
|
||||
#ifndef lint
|
||||
static const char rcsid[] _U_ =
|
||||
"@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.105 2004-03-16 19:27:55 risso Exp $ (LBL)";
|
||||
"@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.106 2004-03-23 19:18:08 guy Exp $ (LBL)";
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -574,6 +574,14 @@ sf_stats(pcap_t *p, struct pcap_stat *ps)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
sf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
|
||||
{
|
||||
strlcpy(p->errbuf, "Sending packets isn't supported on savefiles",
|
||||
PCAP_ERRBUF_SIZE);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
sf_close(pcap_t *p)
|
||||
{
|
||||
|
@ -730,6 +738,7 @@ pcap_open_offline(const char *fname, char *errbuf)
|
|||
#endif
|
||||
|
||||
p->read_op = pcap_offline_read;
|
||||
p->inject_op = sf_inject;
|
||||
p->setfilter_op = install_bpf_program;
|
||||
p->set_datalink_op = NULL; /* we don't support munging link-layer headers */
|
||||
p->getnonblock_op = sf_getnonblock;
|
||||
|
|
Reference in New Issue