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

📄 pcap-linux.c

📁 Ubuntu packages of security software。 相当不错的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
pcap_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user){	/*	 * Currently, on Linux only one packet is delivered per read,	 * so we don't loop.	 */	return pcap_read_packet(handle, callback, user);}/* *  Read a packet from the socket calling the handler provided by *  the user. Returns the number of packets received or -1 if an *  error occured. */static intpcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata){	u_char			*bp;	int			offset;#ifdef HAVE_PF_PACKET_SOCKETS	struct sockaddr_ll	from;	struct sll_header	*hdrp;#else	struct sockaddr		from;#endif	socklen_t		fromlen;	int			packet_len, caplen;	struct pcap_pkthdr	pcap_header;#ifdef HAVE_PF_PACKET_SOCKETS	/*	 * If this is a cooked device, leave extra room for a	 * fake packet header.	 */	if (handle->md.cooked)		offset = SLL_HDR_LEN;	else		offset = 0;#else	/*	 * This system doesn't have PF_PACKET sockets, so it doesn't	 * support cooked devices.	 */	offset = 0;#endif	/* Receive a single packet from the kernel */	bp = handle->buffer + handle->offset;	do {		/*		 * Has "pcap_breakloop()" been called?		 */		if (handle->break_loop) {			/*			 * Yes - clear the flag that indicates that it			 * has, and return -2 as an indication that we			 * were told to break out of the loop.			 */			handle->break_loop = 0;			return -2;		}		fromlen = sizeof(from);		packet_len = recvfrom(			handle->fd, bp + offset,			handle->bufsize - offset, MSG_TRUNC,			(struct sockaddr *) &from, &fromlen);	} while (packet_len == -1 && errno == EINTR);	/* Check if an error occured */	if (packet_len == -1) {		if (errno == EAGAIN)			return 0;	/* no packet there */		else {			snprintf(handle->errbuf, sizeof(handle->errbuf),				 "recvfrom: %s", pcap_strerror(errno));			return -1;		}	}#ifdef HAVE_PF_PACKET_SOCKETS	if (!handle->md.sock_packet) {		/*		 * Unfortunately, there is a window between socket() and		 * bind() where the kernel may queue packets from any		 * interface.  If we're bound to a particular interface,		 * discard packets not from that interface.		 *		 * (If socket filters are supported, we could do the		 * same thing we do when changing the filter; however,		 * that won't handle packet sockets without socket		 * filter support, and it's a bit more complicated.		 * It would save some instructions per packet, however.)		 */		if (handle->md.ifindex != -1 &&		    from.sll_ifindex != handle->md.ifindex)			return 0;		/*		 * Do checks based on packet direction.		 * 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 (from.sll_pkttype == PACKET_OUTGOING) {			/*			 * Outgoing packet.			 * If this is from the loopback device, reject it;			 * we'll see the packet as an incoming packet as well,			 * and we don't want to see it twice.			 */			if (from.sll_ifindex == handle->md.lo_ifindex)				return 0;			/*			 * If the user only wants incoming packets, reject it.			 */			if (handle->direction == PCAP_D_IN)				return 0;		} else {			/*			 * Incoming packet.			 * If the user only wants outgoing packets, reject it.			 */			if (handle->direction == PCAP_D_OUT)				return 0;		}	}#endif#ifdef HAVE_PF_PACKET_SOCKETS	/*	 * If this is a cooked device, fill in the fake packet header.	 */	if (handle->md.cooked) {		/*		 * Add the length of the fake header to the length		 * of packet data we read.		 */		packet_len += SLL_HDR_LEN;		hdrp = (struct sll_header *)bp;		/*		 * Map the PACKET_ value to a LINUX_SLL_ value; we		 * want the same numerical value to be used in		 * the link-layer header even if the numerical values		 * for the PACKET_ #defines change, so that programs		 * that look at the packet type field will always be		 * able to handle DLT_LINUX_SLL captures.		 */		switch (from.sll_pkttype) {		case PACKET_HOST:			hdrp->sll_pkttype = htons(LINUX_SLL_HOST);			break;		case PACKET_BROADCAST:			hdrp->sll_pkttype = htons(LINUX_SLL_BROADCAST);			break;		case PACKET_MULTICAST:			hdrp->sll_pkttype = htons(LINUX_SLL_MULTICAST);			break;		case PACKET_OTHERHOST:			hdrp->sll_pkttype = htons(LINUX_SLL_OTHERHOST);			break;		case PACKET_OUTGOING:			hdrp->sll_pkttype = htons(LINUX_SLL_OUTGOING);			break;		default:			hdrp->sll_pkttype = -1;			break;		}		hdrp->sll_hatype = htons(from.sll_hatype);		hdrp->sll_halen = htons(from.sll_halen);		memcpy(hdrp->sll_addr, from.sll_addr,		    (from.sll_halen > SLL_ADDRLEN) ?		      SLL_ADDRLEN :		      from.sll_halen);		hdrp->sll_protocol = from.sll_protocol;	}#endif	/*	 * XXX: According to the kernel source we should get the real	 * packet len if calling recvfrom with MSG_TRUNC set. It does	 * not seem to work here :(, but it is supported by this code	 * anyway.	 * To be honest the code RELIES on that feature so this is really	 * broken with 2.2.x kernels.	 * I spend a day to figure out what's going on and I found out	 * that the following is happening:	 *	 * The packet comes from a random interface and the packet_rcv	 * hook is called with a clone of the packet. That code inserts	 * the packet into the receive queue of the packet socket.	 * If a filter is attached to that socket that filter is run	 * first - and there lies the problem. The default filter always	 * cuts the packet at the snaplen:	 *	 * # tcpdump -d	 * (000) ret      #68	 *	 * So the packet filter cuts down the packet. The recvfrom call	 * says "hey, it's only 68 bytes, it fits into the buffer" with	 * the result that we don't get the real packet length. This	 * is valid at least until kernel 2.2.17pre6.	 *	 * We currently handle this by making a copy of the filter	 * program, fixing all "ret" instructions with non-zero	 * operands to have an operand of 65535 so that the filter	 * doesn't truncate the packet, and supplying that modified	 * filter to the kernel.	 */	caplen = packet_len;	if (caplen > handle->snapshot)		caplen = handle->snapshot;	/* Run the packet filter if not using kernel filter */	if (!handle->md.use_bpf && handle->fcode.bf_insns) {		if (bpf_filter(handle->fcode.bf_insns, bp,		                packet_len, caplen) == 0)		{			/* rejected by filter */			return 0;		}	}	/* Fill in our own header data */	if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) {		snprintf(handle->errbuf, sizeof(handle->errbuf),			 "SIOCGSTAMP: %s", pcap_strerror(errno));		return -1;	}	pcap_header.caplen	= caplen;	pcap_header.len		= packet_len;	/*	 * Count the packet.	 *	 * Arguably, we should count them before we check the filter,	 * as on many other platforms "ps_recv" counts packets	 * handed to the filter rather than packets that passed	 * the filter, but if filtering is done in the kernel, we	 * can't get a count of packets that passed the filter,	 * and that would mean the meaning of "ps_recv" wouldn't	 * be the same on all Linux systems.	 *	 * XXX - it's not the same on all systems in any case;	 * ideally, we should have a "get the statistics" call	 * that supplies more counts and indicates which of them	 * it supplies, so that we supply a count of packets	 * handed to the filter only on platforms where that	 * information is available.	 *	 * We count them here even if we can get the packet count	 * from the kernel, as we can only determine at run time	 * whether we'll be able to get it from the kernel (if	 * HAVE_TPACKET_STATS isn't defined, we can't get it from	 * the kernel, but if it is defined, the library might	 * have been built with a 2.4 or later kernel, but we	 * might be running on a 2.2[.x] kernel without Alexey	 * Kuznetzov's turbopacket patches, and thus the kernel	 * might not be able to supply those statistics).  We	 * could, I guess, try, when opening the socket, to get	 * the statistics, and if we can not increment the count	 * here, but it's not clear that always incrementing	 * the count is more expensive than always testing a flag	 * in memory.	 *	 * We keep the count in "md.packets_read", and use that for	 * "ps_recv" if we can't get the statistics from the kernel.	 * We do that because, if we *can* get the statistics from	 * the kernel, we use "md.stat.ps_recv" and "md.stat.ps_drop"	 * as running counts, as reading the statistics from the	 * kernel resets the kernel statistics, and if we directly	 * increment "md.stat.ps_recv" here, that means it will	 * count packets *twice* on systems where we can get kernel	 * statistics - once here, and once in pcap_stats_linux().	 */	handle->md.packets_read++;	/* Call the user supplied callback function */	callback(userdata, &pcap_header, bp);	return 1;}static intpcap_inject_linux(pcap_t *handle, const void *buf, size_t size){	int ret;#ifdef HAVE_PF_PACKET_SOCKETS	if (!handle->md.sock_packet) {		/* PF_PACKET socket */		if (handle->md.ifindex == -1) {			/*			 * We don't support sending on the "any" device.			 */			strlcpy(handle->errbuf,			    "Sending packets isn't supported on the \"any\" device",			    PCAP_ERRBUF_SIZE);			return (-1);		}		if (handle->md.cooked) {			/*			 * We don't support sending on the "any" device.			 *			 * XXX - how do you send on a bound cooked-mode			 * socket?			 * Is a "sendto()" required there?			 */			strlcpy(handle->errbuf,			    "Sending packets isn't supported in cooked mode",			    PCAP_ERRBUF_SIZE);			return (-1);		}	}#endif	ret = send(handle->fd, buf, size, 0);	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 *  the PACKET_STATISTICS "getsockopt()" argument (2.4 and later *  kernels, and 2.2[.x] kernels with Alexey Kuznetzov's turbopacket *  patches); otherwise, that information isn't available, and we lie *  and report 0 as the count of dropped packets. */static intpcap_stats_linux(pcap_t *handle, struct pcap_stat *stats){#ifdef HAVE_TPACKET_STATS	struct tpacket_stats kstats;	socklen_t len = sizeof (struct tpacket_stats);#endif#ifdef HAVE_TPACKET_STATS	/*	 * Try to get the packet counts from the kernel.	 */	if (getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS,			&kstats, &len) > -1) {		/*		 * On systems where the PACKET_STATISTICS "getsockopt()"		 * argument is supported on PF_PACKET sockets:		 *		 *	"ps_recv" counts only packets that *passed* the		 *	filter, not packets that didn't pass the filter.		 *	This includes packets later dropped because we		 *	ran out of buffer space.		 *		 *	"ps_drop" counts packets dropped because we ran		 *	out of buffer space.  It doesn't count packets		 *	dropped by the interface driver.  It counts only		 *	packets that passed the filter.		 *		 *	Both statistics include packets not yet read from		 *	the kernel by libpcap, and thus not yet seen by		 *	the application.		 *		 * In "linux/net/packet/af_packet.c", at least in the		 * 2.4.9 kernel, "tp_packets" is incremented for every		 * packet that passes the packet filter *and* is		 * successfully queued on the socket; "tp_drops" is		 * incremented for every packet dropped because there's		 * not enough free space in the socket buffer.		 *		 * When the statistics are returned for a PACKET_STATISTICS		 * "getsockopt()" call, "tp_drops" is added to "tp_packets",		 * so that "tp_packets" counts all packets handed to		 * the PF_PACKET socket, including packets dropped because		 * there wasn't room on the socket buffer - but not		 * including packets that didn't pass the filter.		 *		 * In the BSD BPF, the count of received packets is		 * incremented for every packet handed to BPF, regardless		 * of whether it passed the filter.		 *		 * We can't make "pcap_stats()" work the same on both		 * platforms, but the best approximation is to return		 * "tp_packets" as the count of packets and "tp_drops"		 * as the count of drops.		 *		 * Keep a running total because each call to 		 *    getsockopt(handle->fd, SOL_PACKET, PACKET_STATISTICS, ....		 * resets the counters to zero.		 */		handle->md.stat.ps_recv += kstats.tp_packets;		handle->md.stat.ps_drop += kstats.tp_drops;		*stats = handle->md.stat;		return 0;	}	else	{		/*		 * If the error was EOPNOTSUPP, fall through, so that		 * if you build the library on a system with		 * "struct tpacket_stats" and run it on a system		 * that doesn't, it works as it does if the library		 * is built on a system without "struct tpacket_stats".		 */		if (errno != EOPNOTSUPP) {			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,			    "pcap_stats: %s", pcap_strerror(errno));			return -1;		}	}#endif	/*	 * On systems where the PACKET_STATISTICS "getsockopt()" argument	 * is not supported on PF_PACKET sockets:	 *	 *	"ps_recv" counts only packets that *passed* the filter,	 *	not packets that didn't pass the filter.  It does not	 *	count packets dropped because we ran out of buffer	 *	space.	 *	 *	"ps_drop" is not supported.	 *	 *	"ps_recv" doesn't include packets not yet read from	 *	the kernel by libpcap.	 *	 * We maintain the count of packets processed by libpcap in	 * "md.packets_read", for reasons described in the comment	 * at the end of pcap_read_packet().  We have no idea how many	 * packets were dropped.

⌨️ 快捷键说明

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