⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcap-linux.c

📁 Ubuntu packages of security software。 相当不错的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  pcap-linux.c: Packet capture interface to the Linux kernel * *  Copyright (c) 2000 Torsten Landschoff <torsten@debian.org> *  		       Sebastian Krahmer  <krahmer@cs.uni-potsdam.de> * *  License: BSD * *  Redistribution and use in source and binary forms, with or without *  modification, are permitted provided that the following conditions *  are met: * *  1. Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. *  2. Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in *     the documentation and/or other materials provided with the *     distribution. *  3. The names of the authors may not be used to endorse or promote *     products derived from this software without specific prior *     written permission. * *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic const char rcsid[] _U_ =    "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.110.2.14 2006/10/12 17:26:58 guy Exp $ (LBL)";#endif/* * 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 catch "pcap_close()" and, for *     interfaces we put into promiscuous mode, take them out of *     promiscuous mode - which isn't necessarily the right thing to *     do, if another socket also requested promiscuous mode between *     the time when we opened the socket and the time when we close *     the socket. * *   - MSG_TRUNC isn't supported, so you can't specify that "recvfrom()" *     return the amount of data that you could have read, rather than *     the amount that was returned, so we can't just allocate a buffer *     whose size is the snapshot length and pass the snapshot length *     as the byte count, and also pass MSG_TRUNC, so that the return *     value tells us how long the packet was on the wire. * *     This means that, if we want to get the actual size of the packet, *     so we can return it in the "len" field of the packet header, *     we have to read the entire packet, not just the part that fits *     within the snapshot length, and thus waste CPU time copying data *     from the kernel that our caller won't see. * *     We have to get the actual size, and supply it in "len", because *     otherwise, the IP dissector in tcpdump, for example, will complain *     about "truncated-ip", as the packet will appear to have been *     shorter, on the wire, than the IP header said it should have been. */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "pcap-int.h"#include "sll.h"#ifdef HAVE_DAG_API#include "pcap-dag.h"#endif /* HAVE_DAG_API */#ifdef HAVE_SEPTEL_API#include "pcap-septel.h"#endif /* HAVE_SEPTEL_API */	  #include <errno.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/utsname.h>#include <net/if.h>#include <netinet/in.h>#include <linux/if_ether.h>#include <net/if_arp.h>/* * If PF_PACKET is defined, we can use {SOCK_RAW,SOCK_DGRAM}/PF_PACKET * sockets rather than SOCK_PACKET sockets. * * To use them, we include <linux/if_packet.h> rather than * <netpacket/packet.h>; we do so because * *	some Linux distributions (e.g., Slackware 4.0) have 2.2 or *	later kernels and libc5, and don't provide a <netpacket/packet.h> *	file; * *	not all versions of glibc2 have a <netpacket/packet.h> file *	that defines stuff needed for some of the 2.4-or-later-kernel *	features, so if the system has a 2.4 or later kernel, we *	still can't use those features. * * We're already including a number of other <linux/XXX.h> headers, and * this code is Linux-specific (no other OS has PF_PACKET sockets as * a raw packet capture mechanism), so it's not as if you gain any * useful portability by using <netpacket/packet.h> * * XXX - should we just include <linux/if_packet.h> even if PF_PACKET * isn't defined?  It only defines one data structure in 2.0.x, so * it shouldn't cause any problems. */#ifdef PF_PACKET# include <linux/if_packet.h> /*  * On at least some Linux distributions (for example, Red Hat 5.2),  * there's no <netpacket/packet.h> file, but PF_PACKET is defined if  * you include <sys/socket.h>, but <linux/if_packet.h> doesn't define  * any of the PF_PACKET stuff such as "struct sockaddr_ll" or any of  * the PACKET_xxx stuff.  *  * So we check whether PACKET_HOST is defined, and assume that we have  * PF_PACKET sockets only if it is defined.  */# ifdef PACKET_HOST#  define HAVE_PF_PACKET_SOCKETS# endif /* PACKET_HOST */#endif /* PF_PACKET */#ifdef SO_ATTACH_FILTER#include <linux/types.h>#include <linux/filter.h>#endif#ifndef __GLIBC__typedef int		socklen_t;#endif#ifndef MSG_TRUNC/* * This is being compiled on a system that lacks MSG_TRUNC; define it * with the value it has in the 2.2 and later kernels, so that, on * those kernels, when we pass it in the flags argument to "recvfrom()" * we're passing the right value and thus get the MSG_TRUNC behavior * we want.  (We don't get that behavior on 2.0[.x] kernels, because * they didn't support MSG_TRUNC.) */#define MSG_TRUNC	0x20#endif#ifndef SOL_PACKET/* * This is being compiled on a system that lacks SOL_PACKET; define it * with the value it has in the 2.2 and later kernels, so that we can * set promiscuous mode in the good modern way rather than the old * 2.0-kernel crappy way. */#define SOL_PACKET	263#endif#define MAX_LINKHEADER_SIZE	256/* * When capturing on all interfaces we use this as the buffer size. * Should be bigger then all MTUs that occur in real life. * 64kB should be enough for now. */#define BIGGER_THAN_ALL_MTUS	(64*1024)/* * Prototypes for internal functions */static void map_arphrd_to_dlt(pcap_t *, int, int);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 int pcap_setdirection_linux(pcap_t *, pcap_direction_t);static void pcap_close_linux(pcap_t *);/* * Wrap some ioctl calls */#ifdef HAVE_PF_PACKET_SOCKETSstatic int	iface_get_id(int fd, const char *device, char *ebuf);#endifstatic int	iface_get_mtu(int fd, const char *device, char *ebuf);static int 	iface_get_arptype(int fd, const char *device, char *ebuf);#ifdef HAVE_PF_PACKET_SOCKETSstatic int 	iface_bind(int fd, int ifindex, char *ebuf);#endifstatic int 	iface_bind_old(int fd, const char *device, char *ebuf);#ifdef SO_ATTACH_FILTERstatic int	fix_program(pcap_t *handle, struct sock_fprog *fcode);static int	fix_offset(struct bpf_insn *p);static int	set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode);static int	reset_kernel_filter(pcap_t *handle);static struct sock_filter	total_insn	= BPF_STMT(BPF_RET | BPF_K, 0);static struct sock_fprog	total_fcode	= { 1, &total_insn };#endif/* *  Get a handle for a live capture from the given device. You can *  pass NULL as device to get all packages (without link level *  information of course). If you pass 1 as promisc the interface *  will be set to promiscous mode (XXX: I think this usage should *  be deprecated and functions be added to select that later allow *  modification of that values -- Torsten). * *  See also pcap(3). */pcap_t *pcap_open_live(const 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;#ifdef HAVE_DAG_API	if (strstr(device, "dag")) {		return dag_open_live(device, snaplen, promisc, to_ms, ebuf);	}#endif /* HAVE_DAG_API */#ifdef HAVE_SEPTEL_API	if (strstr(device, "septel")) {		return septel_open_live(device, snaplen, promisc, to_ms, ebuf);	}#endif /* HAVE_SEPTEL_API */	/* Allocate a handle for this session. */	handle = malloc(sizeof(*handle));	if (handle == NULL) {		snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",			 pcap_strerror(errno));		return NULL;	}	/* Initialize some components of the pcap structure. */	memset(handle, 0, sizeof(*handle));	handle->snapshot	= snaplen;	handle->md.timeout	= to_ms;	/*	 * NULL and "any" are special devices which give us the hint to	 * monitor all devices.	 */	if (!device || strcmp(device, "any") == 0) {		device			= NULL;		handle->md.device	= strdup("any");		if (promisc) {			promisc = 0;			/* Just a warning. */			snprintf(ebuf, PCAP_ERRBUF_SIZE,			    "Promiscuous mode not supported on the \"any\" device");		}	} else		handle->md.device	= strdup(device);	if (handle->md.device == NULL) {		snprintf(ebuf, PCAP_ERRBUF_SIZE, "strdup: %s",			 pcap_strerror(errno) );		free(handle);		return NULL;	}	/*	 * Current Linux kernels use the protocol family PF_PACKET to	 * allow direct access to all packets on the network while	 * older kernels had a special socket type SOCK_PACKET to	 * implement this feature.	 * While this old implementation is kind of obsolete we need	 * to be compatible with older kernels for a while so we are	 * trying both methods with the newer method preferred.	 */	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).		 */		if (handle->md.device != NULL)			free(handle->md.device);		free(handle);		return NULL;	}	/*	 * Compute the buffer size.	 *	 * If we're using SOCK_PACKET, this might be a 2.0[.x] kernel,	 * and might require special handling - check.	 */	if (handle->md.sock_packet && (uname(&utsname) < 0 ||	    strncmp(utsname.release, "2.0", 3) == 0)) {		/*		 * We're using a SOCK_PACKET structure, and either		 * we couldn't find out what kernel release this is,		 * or it's a 2.0[.x] kernel.		 *		 * In the 2.0[.x] kernel, a "recvfrom()" on		 * a SOCK_PACKET socket, with MSG_TRUNC set, will		 * return the number of bytes read, so if we pass		 * a length based on the snapshot length, it'll		 * return the number of bytes from the packet		 * copied to userland, not the actual length		 * of the packet.		 *		 * This means that, for example, the IP dissector		 * in tcpdump will get handed a packet length less		 * than the length in the IP header, and will		 * complain about "truncated-ip".		 *		 * So we don't bother trying to copy from the		 * kernel only the bytes in which we're interested,		 * but instead copy them all, just as the older		 * versions of libpcap for Linux did.		 *		 * The buffer therefore needs to be big enough to		 * hold the largest packet we can get from this		 * device.  Unfortunately, we can't get the MRU		 * of the network; we can only get the MTU.  The		 * MTU may be too small, in which case a packet larger		 * than the buffer size will be truncated *and* we		 * won't get the actual packet size.		 *		 * However, if the snapshot length is larger than		 * the buffer size based on the MTU, we use the		 * snapshot length as the buffer size, instead;		 * this means that with a sufficiently large snapshot		 * length we won't artificially truncate packets		 * to the MTU-based size.		 *		 * This mess just one of many problems with packet		 * capture on 2.0[.x] kernels; you really want a		 * 2.2[.x] or later kernel if you want packet capture		 * to work well.		 */		mtu = iface_get_mtu(handle->fd, device, ebuf);		if (mtu == -1) {			pcap_close_linux(handle);			free(handle);			return NULL;		}		handle->bufsize = MAX_LINKHEADER_SIZE + mtu;		if (handle->bufsize < handle->snapshot)			handle->bufsize = handle->snapshot;	} else {		/*		 * This is a 2.2[.x] or later kernel (we know that		 * either because we're not using a SOCK_PACKET		 * socket - PF_PACKET is supported only in 2.2		 * and later kernels - or because we checked the		 * kernel version).		 *		 * We can safely pass "recvfrom()" a byte count		 * based on the snapshot length.		 *		 * If we're in cooked mode, make the snapshot length		 * large enough to hold a "cooked mode" header plus		 * 1 byte of packet data (so we don't pass a byte		 * count of 0 to "recvfrom()").		 */		if (handle->md.cooked) {			if (handle->snapshot < SLL_HDR_LEN + 1)				handle->snapshot = SLL_HDR_LEN + 1;		}		handle->bufsize = handle->snapshot;	}	/* Allocate the buffer */	handle->buffer	 = malloc(handle->bufsize + handle->offset);	if (!handle->buffer) {	        snprintf(ebuf, PCAP_ERRBUF_SIZE,			 "malloc: %s", pcap_strerror(errno));		pcap_close_linux(handle);		free(handle);		return NULL;	}	/*	 * "handle->fd" is a socket, so "select()" and "poll()"	 * should work on it.	 */	handle->selectable_fd = handle->fd;	handle->read_op = pcap_read_linux;	handle->inject_op = pcap_inject_linux;	handle->setfilter_op = pcap_setfilter_linux;	handle->setdirection_op = pcap_setdirection_linux;	handle->set_datalink_op = NULL;	/* can't change data link type */	handle->getnonblock_op = pcap_getnonblock_fd;	handle->setnonblock_op = pcap_setnonblock_fd;	handle->stats_op = pcap_stats_linux;	handle->close_op = pcap_close_linux;	return handle;}/* *  Read at most max_packets from the capture stream and call the callback *  for each of them. Returns the number of packets handled or -1 if an *  error occured. */static int

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -