On Tue, Feb 05, 2002 at 12:19:16PM +0100, Jan-Philip Velders wrote:
> > Do you have a stack trace from the crash?
>
> Here it comes:
OK, it appears the problem is that, when using PF_INET/SOCK_PACKET
sockets (which is all you have on 2.0[.x]), we first try to put the
interface into promiscuous mode, and only after trying that check
whether we can support its link-layer type.
This causes the list of sockets on which we should turn promiscuous mode
off when we exit (2.0[.x] won't do that automatically when the socket is
closed) to include a socket that's already been closed, which causes an
error message ("Can't restore interface flags (SIOCGIFFLAGS failed: Bad
file number)."). (It also causes a crash; I'll look into why that
happens.)
> As far as I can tell, if ppp0 is already in promisc:
> tcpdump: interface type of ppp0 not supported
That's because we were only supporting PPP devices on PF_PACKET sockets.
> If it has to be set in promisc mode:
> tcpdump: interface type of ppp0 not supported
Same problem.
> Can't restore interface flags (SIOCGIFFLAGS failed: Bad file number).
As the interface wasn't in promiscuous mode before, we have to take it
out of promiscuous mode when we exit; that didn't happen in the previous
case, as the interface was already in promiscuous mode.
I've checked in a change to
1) use DLT_RAW with PPP devices if you don't have PF_PACKET
support - that will *not* work for all PPP devices, but it
will work for some (unfortunately, ippp devices may be among
those on which it doesn't work, but it didn't work in
previous versions of libpcap, either; it *might* be possible
to add some code to make it work with *some* ISDN devices);
2) get the link-layer type before turning promiscuous mode on.
That's both in the main CVS branch and the x.7 branch, so the fix should
show up in the next libpcap 0.7.x release.
I've attached the patch for the change I checked in.
Index: pcap-linux.c
===================================================================
RCS file: /tcpdump/master/libpcap/pcap-linux.c,v
retrieving revision 1.76
diff -c -r1.76 pcap-linux.c
*** pcap-linux.c 2002/02/05 05:47:14 1.76
--- pcap-linux.c 2002/02/10 00:01:22
***************
*** 168,174 ****
/*
* Prototypes for internal functions
*/
! static void map_arphrd_to_dlt(pcap_t *, int);
static int live_open_old(pcap_t *, char *, int, int, char *);
static int live_open_new(pcap_t *, char *, int, int, char *);
static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
--- 168,174 ----
/*
* Prototypes for internal functions
*/
! static void map_arphrd_to_dlt(pcap_t *, int, int);
static int live_open_old(pcap_t *, char *, int, int, char *);
static int live_open_new(pcap_t *, char *, int, int, char *);
static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
***************
*** 861,870 ****
* will be aligned on a 4-byte boundary when capturing packets).
* (If the offset isn't set here, it'll be 0; add code as appropriate
* for cases where it shouldn't be 0.)
*
* Sets the link type to -1 if unable to map the type.
*/
! static void map_arphrd_to_dlt(pcap_t *handle, int arptype)
{
switch (arptype) {
--- 861,874 ----
* will be aligned on a 4-byte boundary when capturing packets).
* (If the offset isn't set here, it'll be 0; add code as appropriate
* for cases where it shouldn't be 0.)
+ *
+ * If "cooked_ok" is non-zero, we can use DLT_LINUX_SLL and capture
+ * in cooked mode; otherwise, we can't use cooked mode, so we have
+ * to pick some type that works in raw mode, or fail.
*
* Sets the link type to -1 if unable to map the type.
*/
! static void map_arphrd_to_dlt(pcap_t *handle, int arptype, int cooked_ok)
{
switch (arptype) {
***************
*** 949,957 ****
* Both of those are a nuisance - and, at least on systems
* that support PF_PACKET sockets, we don't have to put
* up with those nuisances; instead, we can just capture
! * in cooked mode. That's what we'll do.
*/
! handle->linktype = DLT_LINUX_SLL;
break;
#ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */
--- 953,965 ----
* Both of those are a nuisance - and, at least on systems
* that support PF_PACKET sockets, we don't have to put
* up with those nuisances; instead, we can just capture
! * in cooked mode. That's what we'll do, if we can.
! * Otherwise, we'll just fail.
*/
! if (cooked_ok)
! handle->linktype = DLT_LINUX_SLL;
! else
! handle->linktype = -1;
break;
#ifndef ARPHRD_IEEE80211 /* From Linux 2.4.6 */
***************
*** 981,989 ****
* oddball link-layer headers particular packets have).
*
* As such, we just punt, and run all PPP interfaces
! * in cooked mode.
*/
! handle->linktype = DLT_LINUX_SLL;
break;
#ifndef ARPHRD_HDLC
--- 989,1022 ----
* oddball link-layer headers particular packets have).
*
* As such, we just punt, and run all PPP interfaces
! * in cooked mode, if we can; otherwise, we just treat
! * it as DLT_RAW, for now - if somebody needs to capture,
! * on a 2.0[.x] kernel, on PPP devices that supply a
! * link-layer header, they'll have to add code here to
! * map to the appropriate DLT_ type (possibly adding a
! * new DLT_ type, if necessary).
*/
! if (cooked_ok)
! handle->linktype = DLT_LINUX_SLL;
! else {
! /*
! * XXX - handle ISDN types here? We can't fall
! * back on cooked sockets, so we'd have to
! * figure out from the device name what type of
! * link-layer encapsulation it's using, and map
! * that to an appropriate DLT_ value, meaning
! * we'd map "isdnN" devices to DLT_RAW (they
! * supply raw IP packets with no link-layer
! * header) and "isdY" devices to a new DLT_I4L_IP
! * type that has only an Ethernet packet type as
! * a link-layer header.
! *
! * But sometimes we seem to get random crap
! * in the link-layer header when capturing on
! * ISDN devices....
! */
! handle->linktype = DLT_RAW;
! }
break;
#ifndef ARPHRD_HDLC
***************
*** 1089,1095 ****
arptype = iface_get_arptype(sock_fd, device, ebuf);
if (arptype == -1)
break;
! map_arphrd_to_dlt(handle, arptype);
if (handle->linktype == -1 ||
handle->linktype == DLT_LINUX_SLL ||
(handle->linktype == DLT_EN10MB &&
--- 1122,1128 ----
arptype = iface_get_arptype(sock_fd, device, ebuf);
if (arptype == -1)
break;
! map_arphrd_to_dlt(handle, arptype, 1);
if (handle->linktype == -1 ||
handle->linktype == DLT_LINUX_SLL ||
(handle->linktype == DLT_EN10MB &&
***************
*** 1388,1395 ****
}
if (iface_bind_old(sock_fd, device, ebuf) == -1)
break;
! /* Go to promisc mode */
if (promisc) {
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
--- 1421,1447 ----
}
if (iface_bind_old(sock_fd, device, ebuf) == -1)
break;
+
+ /*
+ * Try to get the link-layer type.
+ */
+ arptype = iface_get_arptype(sock_fd, device, ebuf);
+ if (arptype == -1)
+ break;
+
+ /*
+ * Try to find the DLT_ type corresponding to that
+ * link-layer type.
+ */
+ map_arphrd_to_dlt(handle, arptype, 0);
+ if (handle->linktype == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "unknown arptype %d", arptype);
+ break;
+ }
! /* Go to promisc mode if requested */
!
if (promisc) {
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
***************
*** 1443,1454 ****
}
}
- /* All done - fill in the pcap handle */
-
- arptype = iface_get_arptype(sock_fd, device, ebuf);
- if (arptype == -1)
- break;
-
/* Save the socket FD in the pcap structure */
handle->fd = sock_fd;
--- 1495,1500 ----
***************
*** 1458,1482 ****
* on a 4-byte boundary.
*/
handle->offset = 0;
-
- /*
- * XXX - handle ISDN types here? We can't fall back on
- * cooked sockets, so we'd have to figure out from the
- * device name what type of link-layer encapsulation
- * it's using, and map that to an appropriate DLT_
- * value, meaning we'd map "isdnN" devices to DLT_RAW
- * (they supply raw IP packets with no link-layer
- * header) and "isdY" devices to a new DLT_I4L_IP
- * type that has only an Ethernet packet type as
- * a link-layer header.
- */
- map_arphrd_to_dlt(handle, arptype);
- if (handle->linktype == -1 ||
- handle->linktype == DLT_LINUX_SLL) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "interface type of %s not supported", device);
- break;
- }
return 1;
--- 1504,1509 ----