aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorguy <guy>2000-10-25 07:46:49 +0000
committerguy <guy>2000-10-25 07:46:49 +0000
commit188fee53ccbbe6b11e84ae01b10955205be5ac62 (patch)
tree14a2efbcdd623ef403f55637ec99daf12b9bd220
parent5c4a9505073aa4221706ef489a7efdb68521edfd (diff)
If we're receiving packets from a PF_PACKET socket, check whether the
interface index of the interface for the packet is the interface index of the loopback interface and, if it is, check if the packet is an outgoing packet; if so, ignore it, as we'll also be seeing that packet as a received packet. If we don't handle the arphrd type of an interface, and fall back on cooked mode, report the arphrd type, so we know what type we should consider supporting (if that type can't be supported well, e.g. if you don't get any link-layer header, as happens with PPP, we'd be silent).
-rw-r--r--pcap-int.h3
-rw-r--r--pcap-linux.c117
2 files changed, 93 insertions, 27 deletions
diff --git a/pcap-int.h b/pcap-int.h
index 603bc1f..f5344d4 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.28 2000-09-19 03:28:10 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.29 2000-10-25 07:46:49 guy Exp $ (LBL)
*/
#ifndef pcap_int_h
@@ -67,6 +67,7 @@ struct pcap_md {
int sock_packet; /* using Linux 2.0 compatible interface */
int timeout; /* timeout specified to pcap_open_live */
int promisc; /* running in promiscuous mode */
+ int lo_ifindex; /* interface index of the loopback device */
char *device; /* device name */
#endif
};
diff --git a/pcap-linux.c b/pcap-linux.c
index 23dd816..d5e4f53 100644
--- a/pcap-linux.c
+++ b/pcap-linux.c
@@ -26,12 +26,32 @@
*/
#ifndef lint
static const char rcsid[] =
- "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.37 2000-10-25 06:59:10 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.38 2000-10-25 07:46:50 guy Exp $ (LBL)";
#endif
/*
- * Known bugs:
- * - setting promiscuous on loopback gives every packet twice
+ * Known problems with 2.0[.x] kernels:
+ *
+ * - The loopback device gives every packet twice; on 2.2[.x] kernels,
+ * if we use PF_PACKET, we can filter out the transmitted version
+ * of the packet by using data in the "sockaddr_ll" returned by
+ * "recvfrom()", but, on 2.0[.x] kernels, we have to use
+ * PF_INET/SOCK_PACKET, which means "recvfrom()" supplies a
+ * "sockaddr_pkt" which doesn't give us enough information to let
+ * us do that.
+ *
+ * - We have to set the interface's IFF_PROMISC flag ourselves, if
+ * we're to run in promiscuous mode, which means we have to turn
+ * it off ourselves when we're done; the kernel doesn't keep track
+ * of how many sockets are listening promiscuously, which means
+ * it won't get turned off automatically when no sockets are
+ * listening promiscuously. We'd have to catch "pcap_close()"
+ * and restore the value the promiscuous flag had when we opened
+ * the device - which may not be the value it should have, if
+ * another socket also requested promiscuous mode between the time
+ * when we opened the socket and the time when we close the socket.
+ * We currently just punt, printing a warning and hinting that the
+ * user should upgrade to a 2.2 or later kernel.
*/
@@ -271,7 +291,11 @@ pcap_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
static int
pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
{
+#ifdef HAVE_NETPACKET_PACKET_H
+ struct sockaddr_ll from;
+#else
struct sockaddr from;
+#endif
socklen_t fromlen;
int packet_len, caplen;
struct pcap_pkthdr pcap_header;
@@ -303,6 +327,22 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
}
}
+#ifdef HAVE_NETPACKET_PACKET_H
+ /*
+ * If this is from the loopback device, reject outgoing packets;
+ * we'll see the packet as an incoming packet as well, and
+ * we don't want to see it twice.
+ *
+ * We can only do this if we're using PF_PACKET; the address
+ * returned for SOCK_PACKET is a "sockaddr_pkt" which lacks
+ * the relevant packet type information.
+ */
+ if (!handle->md.sock_packet &&
+ from.sll_ifindex == handle->md.lo_ifindex &&
+ from.sll_pkttype == PACKET_OUTGOING)
+ return 0;
+#endif
+
/*
* XXX: According to the kernel source we should get the real
* packet len if calling recvfrom with MSG_TRUNC set. It does
@@ -541,6 +581,19 @@ live_open_new(pcap_t *handle, char *device, int promisc,
handle->md.sock_packet = 0;
/*
+ * Get the interface index of the loopback device.
+ * If the attempt fails, don't fail, just set the
+ * "md.lo_ifindex" to -1.
+ *
+ * XXX - can there be more than one device that loops
+ * packets back, i.e. devices other than "lo"? If so,
+ * we'd need to find them all, and have an array of
+ * indices for them, and check all of them in
+ * "pcap_read_packet()".
+ */
+ handle->md.lo_ifindex = iface_get_id(sock_fd, "lo", ebuf);
+
+ /*
* What kind of frames do we have to deal with? Fall back
* to cooked mode if we have an unknown interface type.
*/
@@ -550,38 +603,50 @@ live_open_new(pcap_t *handle, char *device, int promisc,
if (arptype == -1)
break;
handle->linktype = map_arphrd_to_dlt(arptype);
- } else
- handle->linktype = DLT_RAW;
-
- if (handle->linktype == -1) {
- /* Unknown interface type - reopen in cooked mode */
+ if (handle->linktype == -1) {
+ /*
+ * Unknown interface type - reopen in cooked
+ * mode.
+ */
+ if (close(sock_fd) == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "close: %s", pcap_strerror(errno));
+ break;
+ }
+ sock_fd = socket(PF_PACKET, SOCK_DGRAM,
+ htons(ETH_P_ALL));
+ if (sock_fd == -1) {
+ snprintf(ebuf, PCAP_ERRBUF_SIZE,
+ "socket: %s", pcap_strerror(errno));
+ break;
+ }
- if (close(sock_fd) == -1) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "close: %s", pcap_strerror(errno));
- break;
+ fprintf(stderr,
+ "Warning: arptype %d not supported by "
+ "libpcap - falling back to cooked "
+ "socket\n",
+ arptype);
+ handle->linktype = DLT_RAW;
}
- sock_fd = socket(PF_PACKET, SOCK_DGRAM,
- htons(ETH_P_ALL));
- if (sock_fd == -1) {
- snprintf(ebuf, PCAP_ERRBUF_SIZE,
- "socket: %s", pcap_strerror(errno));
- break;
- }
-
- fprintf(stderr,
- "Warning: Falling back to cooked socket\n");
- handle->linktype = DLT_RAW;
- }
-
- if (device) {
device_id = iface_get_id(sock_fd, device, ebuf);
if (device_id == -1)
break;
if (iface_bind(sock_fd, device_id, ebuf) == -1)
break;
+ } else {
+ handle->linktype = DLT_RAW;
+
+ /*
+ * 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.
+ */
+ device_id = -1;
}
/* Select promiscuous mode on/off */