summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorguy <guy>2004-03-23 19:18:04 +0000
committerguy <guy>2004-03-23 19:18:04 +0000
commit2d2890dd3774c9b1f90828f41d06e4998191d2f7 (patch)
treeff0fffc64592d13d9a4a364b9fb2ca051f28d686
parent3380fa10dbcb28d2c58ba852f1539ef67f3bbcca (diff)
downloadlibpcap-2d2890dd3774c9b1f90828f41d06e4998191d2f7.tar.gz
Add support for sending packets; includes contributions from Mark
Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>.
-rw-r--r--CREDITS1
-rw-r--r--pcap-bpf.c44
-rw-r--r--pcap-dag.c11
-rw-r--r--pcap-dlpi.c101
-rw-r--r--pcap-int.h6
-rw-r--r--pcap-linux.c87
-rw-r--r--pcap-nit.c32
-rw-r--r--pcap-pf.c35
-rw-r--r--pcap-snit.c44
-rw-r--r--pcap-snoop.c19
-rw-r--r--pcap-win32.c48
-rw-r--r--pcap.337
-rw-r--r--pcap.c26
-rw-r--r--pcap.h5
-rw-r--r--savefile.c11
15 files changed, 453 insertions, 54 deletions
diff --git a/CREDITS b/CREDITS
index 97a90c71..96fb4853 100644
--- a/CREDITS
+++ b/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>
diff --git a/pcap-bpf.c b/pcap-bpf.c
index 8585db19..5da81b14 100644
--- a/pcap-bpf.c
+++ b/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;
diff --git a/pcap-dag.c b/pcap-dag.c
index b466fc78..c918b3e1 100644
--- a/pcap-dag.c
+++ b/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;
diff --git a/pcap-dlpi.c b/pcap-dlpi.c
index 20c1fbb0..722b3601 100644
--- a/pcap-dlpi.c
+++ b/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)
diff --git a/pcap-int.h b/pcap-int.h
index 9e2dc0b2..636d1026 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -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 *);
diff --git a/pcap-linux.c b/pcap-linux.c
index 12c37f52..9710c36d 100644
--- a/pcap-linux.c
+++ b/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)
diff --git a/pcap-nit.c b/pcap-nit.c
index ae4c40cb..7517f9e9 100644
--- a/pcap-nit.c
+++ b/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
@@ -193,6 +193,23 @@ pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
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)
{
struct nit_ioc nioc;
@@ -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);
}
@@ -281,6 +300,16 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
}
/*
+ * 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.
*/
p->selectable_fd = p->fd;
@@ -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;
diff --git a/pcap-pf.c b/pcap-pf.c
index 3fa1c842..3a59083f 100644
--- a/pcap-pf.c
+++ b/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
@@ -220,6 +220,20 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
}
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;
diff --git a/pcap-snit.c b/pcap-snit.c
index 209878b5..3b0801ed 100644
--- a/pcap-snit.c
+++ b/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
@@ -205,6 +205,29 @@ pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
}
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)
{
bpf_u_int32 flags;
@@ -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;
diff --git a/pcap-snoop.c b/pcap-snoop.c
index d847444f..288ae709 100644
--- a/pcap-snoop.c
+++ b/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
@@ -126,6 +126,22 @@ again:
}
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)
{
register struct rawstats *rs;
@@ -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;
diff --git a/pcap-win32.c b/pcap-win32.c
index da01f286..dcd4dc17 100644
--- a/pcap-win32.c
+++ b/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)
diff --git a/pcap.3 b/pcap.3
index 9f19df3b..d5725dd5 100644
--- a/pcap.3
+++ b/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() .
diff --git a/pcap.c b/pcap.c
index a32dc3f8..01a3140e 100644
--- a/pcap.c
+++ b/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)
{
diff --git a/pcap.h b/pcap.h
index b2cc62f3..55bca95d 100644
--- a/pcap.h
+++ b/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
diff --git a/savefile.c b/savefile.c
index dc4f3413..d98178c9 100644
--- a/savefile.c
+++ b/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;