]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add support for sending packets; includes contributions from Mark
authorguy <guy>
Tue, 23 Mar 2004 19:18:04 +0000 (19:18 +0000)
committerguy <guy>
Tue, 23 Mar 2004 19:18:04 +0000 (19:18 +0000)
Pizzolato <[email protected]>.

15 files changed:
CREDITS
pcap-bpf.c
pcap-dag.c
pcap-dlpi.c
pcap-int.h
pcap-linux.c
pcap-nit.c
pcap-pf.c
pcap-snit.c
pcap-snoop.c
pcap-win32.c
pcap.3
pcap.c
pcap.h
savefile.c

diff --git a/CREDITS b/CREDITS
index 97a90c71f56aa2c7bd31ce5a0ecc29399d486d94..96fb48530aba37f7fe33275c91ec6ebaa4ffc0e8 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -55,6 +55,7 @@ Additional people who have contributed patches:
        Love Hörnquist-Ã…strand          <[email protected]>
        Maciej W. Rozycki               <[email protected]>
        Marcus Felipe Pereira           <[email protected]>
+       Mark Pizzolato                  <[email protected]>
        Martin Husemann                 <[email protected]>
        Mike Wiacek                     <[email protected]>
        Monroe Williams                 <[email protected]>
index 8585db190c8a395e85853bc951b23320b56cd417..5da81b141df9eee821feab655010e9d174c5a9b3 100644 (file)
@@ -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;
index b466fc7803c5918291a2a843dd102038a7f2bd42..c918b3e10df0108333367b67a6113d567346cdbf 100644 (file)
@@ -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;
index 20c1fbb0dae3ccc3369b55064f7652e4ca4cffcc..722b36014606de98e3f516b6568a09246d988137 100644 (file)
@@ -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)
index 9e2dc0b28da66adca84aa69f5e9fb9c9429a1bca..636d1026aef66663706bee4fadb9643af02fe8fb 100644 (file)
@@ -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 *);
index 12c37f52b68ea5692744bd3feb3e490a6ba05d97..9710c36df2210d9414905bc8ef72173011112081 100644 (file)
@@ -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)
index ae4c40cb7867bbb526a3c968c055d470c971728b..7517f9e98c52021fc7ef31206d03b6c85947de8e 100644 (file)
@@ -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;
index 3fa1c842faee2eba09e6991dc78533a235dbb084..3a59083f4d3829ad105921191ef8e3a0ff02c7e4 100644 (file)
--- 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
@@ -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;
index 209878b57494289706b1e398a4688a094f2c6c52..3b0801edb3ceb94af7457f1455014eb722056ae4 100644 (file)
@@ -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;
index d847444fbab8315b9a4dbdf94489679435f3c12a..288ae709b5b57e33c2aa7864d839665dcab568cd 100644 (file)
@@ -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;
index da01f2868ac360e32c995c2b70e2ada946aab778..dcd4dc170a719576b1c9d6589e51710e03dcfa5d 100644 (file)
@@ -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 9f19df3b0376881f0f8a309d40c9afc106b7f6db..d5725dd55b932fd026ec6e125f49396948682e50 100644 (file)
--- 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 a32dc3f86aa547bf91dd3e4392c457ec4af0f200..01a3140e258f06b73d5cdef83c246748aa4acf78 100644 (file)
--- 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 b2cc62f36bdd7ca7a01fb068b911aaa682a01b61..55bca95d9b9c417c28bfec9116e062b3676bbac8 100644 (file)
--- 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
index dc4f3413cd2285e664af5eb8aa7aab81fd4aa7e0..d98178c9486854a29bd44b9b33251b3a5f32fbe3 100644 (file)
@@ -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;