]> The Tcpdump Group git mirrors - libpcap/commitdiff
Bug fixes from Graeme Hewson <[email protected]>:
authorguy <guy>
Fri, 22 Feb 2002 09:20:11 +0000 (09:20 +0000)
committerguy <guy>
Fri, 22 Feb 2002 09:20:11 +0000 (09:20 +0000)
1. During termination processing set up by atexit() under a 2.0.x
   kernel, if a socket had been previously closed and the handle freed
   due to an error, pcap_close_all() and pcap_close_linux() would
   nevertheless try to work with these structures and then crash.
   pcap_close_linux() is now called directly when necessary during
   error processing.

2. atexit() could get called more than once because the did_atexit
   flag wasn't being set.

3. If iface_get_arptype() returns an error because the ioctl() call
   failed (probably due to "no such device"), live_open_new() now
   returns a fatal error to pcap_open_live() and the call to
   live_open_old() is short-circuited.

4. Applications using libpcap would appear to listen on an interface
   that was down.

   a. iface_bind() and iface_bind_old() now check for pending errors
      after bind().  In turn, pcap_open_live() now returns an error
      status if there was a pending error after bind().

   b. After draining the socket, set_kernel_filter() now checks to see
      if the error was the expected EAGAIN and returns a fatal error
      to pcap_setfilter() if not.  In turn, pcap_setfilter() now
      returns an error status if there was a network error.

5. pcap_setfilter() was putting an error message into errbuf after a
   failed call to install_bpf_program().  This was unnecessary since
   install_bpf_program() puts its own error message into errbuf.

CREDITS
pcap-linux.c

diff --git a/CREDITS b/CREDITS
index a604760a0391740e0d9a04c5a8441f6fc4cf89e4..60dfc579735f62011bee356ce28160eaa019bc13 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -20,6 +20,7 @@ Additional people who have contributed patches:
        Chris Pepper                    <[email protected]>
        Darren Reed                     <[email protected]>
        Franz Schaefer                  <[email protected]>
+       Graeme Hewson                   <[email protected]>
        Greg Troxel                     <[email protected]>
        Hyung Sik Yoon                  <[email protected]>
        Igor Khristophorov              <[email protected]>
index 56d1e0527cd4930031b84af7d182ec44fb00da96..b9e4e2aa876484f899d074bcdba9d7bb27ce1230 100644 (file)
@@ -26,7 +26,7 @@
  */
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.77 2002-02-10 00:05:14 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.78 2002-02-22 09:20:11 guy Exp $ (LBL)";
 #endif
 
 /*
@@ -213,6 +213,8 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
 {
        pcap_t          *handle;
        int             mtu;
+       int             err;
+       int             live_open_ok = 0;
        struct utsname  utsname;
 
         /* Allocate a handle for this session. */
@@ -264,16 +266,22 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
         * trying both methods with the newer method preferred.
         */
 
-       if (! (live_open_new(handle, device, promisc, to_ms, ebuf) ||
-              live_open_old(handle, device, promisc, to_ms, ebuf)) )
-       {
+       if ((err = live_open_new(handle, device, promisc, to_ms, ebuf)) == 1)
+               live_open_ok = 1;
+       else if (err == 0) {
+               /* Non-fatal error; try old way */
+               if (live_open_old(handle, device, promisc, to_ms, ebuf))
+                       live_open_ok = 1;
+       }
+       if (!live_open_ok) {
                /* 
                 * Both methods to open the packet socket failed. Tidy
                 * up and report our failure (ebuf is expected to be
                 * set by the functions above). 
                 */
 
-               free(handle->md.device);
+               if (handle->md.device != NULL)
+                       free(handle->md.device);
                free(handle);
                return NULL;
        }
@@ -331,8 +339,12 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
                 */
                mtu = iface_get_mtu(handle->fd, device, ebuf);
                if (mtu == -1) {
+                       if (handle->md.clear_promisc)
+                               /* 2.0.x kernel */
+                               pcap_close_linux(handle);
                        close(handle->fd);
-                       free(handle->md.device);
+                       if (handle->md.device != NULL)
+                               free(handle->md.device);
                        free(handle);
                        return NULL;
                }
@@ -359,8 +371,12 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
        if (!handle->buffer) {
                snprintf(ebuf, PCAP_ERRBUF_SIZE,
                         "malloc: %s", pcap_strerror(errno));
+               if (handle->md.clear_promisc)
+                       /* 2.0.x kernel */
+                       pcap_close_linux(handle);
                close(handle->fd);
-               free(handle->md.device);
+               if (handle->md.device != NULL)
+                       free(handle->md.device);
                free(handle);
                return NULL;
        }
@@ -719,6 +735,7 @@ pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
 #ifdef SO_ATTACH_FILTER
        struct sock_fprog       fcode;
        int                     can_filter_in_kernel;
+       int                     err = 0;
 #endif
 
        if (!handle)
@@ -731,11 +748,9 @@ pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
 
        /* Make our private copy of the filter */
 
-       if (install_bpf_program(handle, filter) < 0) {
-               snprintf(handle->errbuf, sizeof(handle->errbuf),
-                        "malloc: %s", pcap_strerror(errno));
+       if (install_bpf_program(handle, filter) < 0)
+               /* install_bpf_program() filled in errbuf */
                return -1;
-       }
 
        /* 
         * Run user level packet filter by default. Will be overriden if 
@@ -809,12 +824,12 @@ pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
        }
 
        if (can_filter_in_kernel) {
-               if (set_kernel_filter(handle, &fcode) == 0)
+               if ((err = set_kernel_filter(handle, &fcode)) == 0)
                {
                        /* Installation succeded - using kernel filter. */
                        handle->md.use_bpf = 1;
                }
-               else
+               else if (err == -1)     /* Non-fatal error */
                {
                        /* 
                         * Print a warning if we weren't able to install
@@ -845,6 +860,10 @@ pcap_setfilter(pcap_t *handle, struct bpf_program *filter)
         */
        if (fcode.filter != NULL)
                free(fcode.filter);
+
+       if (err == -2)
+               /* Fatal error */
+               return -1;
 #endif /* SO_ATTACH_FILTER */
 
        return 0;
@@ -1068,6 +1087,8 @@ live_open_new(pcap_t *handle, char *device, int promisc,
 {
 #ifdef HAVE_PF_PACKET_SOCKETS
        int                     sock_fd = -1, device_id, arptype;
+       int                     err;
+       int                     fatal_err = 0;
        struct packet_mreq      mr;
 
        /* One shot loop used for error handling - bail out with break */
@@ -1120,8 +1141,10 @@ live_open_new(pcap_t *handle, char *device, int promisc,
                        handle->md.cooked = 0;
 
                        arptype = iface_get_arptype(sock_fd, device, ebuf);
-                       if (arptype == -1) 
+                       if (arptype == -1) {
+                               fatal_err = 1;
                                break;
+                       }
                        map_arphrd_to_dlt(handle, arptype, 1);
                        if (handle->linktype == -1 ||
                            handle->linktype == DLT_LINUX_SLL ||
@@ -1172,8 +1195,11 @@ live_open_new(pcap_t *handle, char *device, int promisc,
                        if (device_id == -1)
                                break;
 
-                       if (iface_bind(sock_fd, device_id, ebuf) == -1)
+                       if ((err = iface_bind(sock_fd, device_id, ebuf)) < 0) {
+                               if (err == -2)
+                                       fatal_err = 1;
                                break;
+                       }
                } else {
                        /*
                         * This is cooked mode.
@@ -1225,7 +1251,11 @@ live_open_new(pcap_t *handle, char *device, int promisc,
 
        if (sock_fd != -1)
                close(sock_fd);
-       return 0;
+
+       if (fatal_err)
+               return -2;
+       else
+               return 0;
 #else
        strncpy(ebuf, 
                "New packet capturing interface not supported by build " 
@@ -1263,6 +1293,8 @@ static int
 iface_bind(int fd, int ifindex, char *ebuf)
 {
        struct sockaddr_ll      sll;
+       int                     err;
+       socklen_t               errlen = sizeof(err);
 
        memset(&sll, 0, sizeof(sll));
        sll.sll_family          = AF_PACKET;
@@ -1275,6 +1307,20 @@ iface_bind(int fd, int ifindex, char *ebuf)
                return -1;
        }
 
+       /* Any pending errors, e.g., network is down? */
+
+       if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
+               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       "getsockopt: %s", pcap_strerror(errno));
+               return -2;
+       }
+
+       if (err > 0) { 
+               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       "bind: %s", pcap_strerror(err)); 
+               return -2;
+       }
+
        return 0;
 }
 
@@ -1380,8 +1426,10 @@ void     pcap_close_linux( pcap_t *handle )
                        }
                }
        }
+
        if (handle->md.device != NULL)
                free(handle->md.device);
+               handle->md.device = NULL;
 }
 
 /*
@@ -1475,6 +1523,7 @@ live_open_old(pcap_t *handle, char *device, int promisc,
                                                        PCAP_ERRBUF_SIZE);
                                                break;
                                        }
+                                       did_atexit = 1;
                                }
 
                                ifr.ifr_flags |= IFF_PROMISC;
@@ -1509,6 +1558,8 @@ live_open_old(pcap_t *handle, char *device, int promisc,
 
        } while (0);
 
+       if (handle->md.clear_promisc)
+               pcap_close_linux(handle);
        if (sock_fd != -1)
                close(sock_fd);
        return 0;
@@ -1522,6 +1573,8 @@ static int
 iface_bind_old(int fd, const char *device, char *ebuf)
 {
        struct sockaddr saddr;
+       int             err;
+       socklen_t       errlen = sizeof(err);
 
        memset(&saddr, 0, sizeof(saddr));
        strncpy(saddr.sa_data, device, sizeof(saddr.sa_data));
@@ -1531,6 +1584,20 @@ iface_bind_old(int fd, const char *device, char *ebuf)
                return -1;
        }
 
+       /* Any pending errors, e.g., network is down? */
+
+       if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
+               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       "getsockopt: %s", pcap_strerror(errno));
+               return -1;
+       }
+
+       if (err > 0) { 
+               snprintf(ebuf, PCAP_ERRBUF_SIZE,
+                       "bind: %s", pcap_strerror(err)); 
+               return -1;
+       }
+
        return 0;
 }
 
@@ -1756,7 +1823,7 @@ set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode)
                /*
                 * Save the socket's current mode, and put it in
                 * non-blocking mode; we drain it by reading packets
-                * until we get an error (which we assume is a
+                * until we get an error (which is normally a
                 * "nothing more to be read" error).
                 */
                save_mode = fcntl(handle->fd, F_GETFL, 0);
@@ -1765,7 +1832,15 @@ set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode)
                        while (recv(handle->fd, &drain, sizeof drain,
                               MSG_TRUNC) >= 0)
                                ;
+                       save_errno = errno;
                        fcntl(handle->fd, F_SETFL, save_mode);
+                       if (save_errno != EAGAIN) {
+                               /* Fatal error */
+                               reset_kernel_filter(handle);
+                               snprintf(handle->errbuf, sizeof(handle->errbuf),
+                                "recv: %s", pcap_strerror(save_errno));
+                               return -2;
+                       }
                }
        }