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

📄 pcap-linux.c

📁 Ubuntu packages of security software。 相当不错的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		} 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),			 "ioctl: %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.	 */	handle->md.stat.ps_recv++;	/* 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) {		/*		 * 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;	}	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 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.	 *	 * 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.	 */	*stats = handle->md.stat;	return 0;}/* * Description string for the "any" device. */static const char any_descr[] = "Pseudo-device that captures on all interfaces";intpcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf){	if (pcap_add_if(alldevsp, "any", 0, any_descr, errbuf) < 0)		return (-1);#ifdef HAVE_DAG_API	if (dag_platform_finddevs(alldevsp, errbuf) < 0)		return (-1);#endif /* HAVE_DAG_API */#ifdef HAVE_SEPTEL_API	if (septel_platform_finddevs(alldevsp, errbuf) < 0)		return (-1);#endif /* HAVE_SEPTEL_API */	return (0);}/* *  Attach the given BPF code to the packet capture device. */static intpcap_setfilter_linux(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)		return -1;	if (!filter) {	        strncpy(handle->errbuf, "setfilter: No filter specified",			sizeof(handle->errbuf));		return -1;	}	/* Make our private copy of the filter */	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	 * installing a kernel filter succeeds.	 */	handle->md.use_bpf = 0;	/* Install kernel level filter if possible */#ifdef SO_ATTACH_FILTER#ifdef USHRT_MAX	if (handle->fcode.bf_len > USHRT_MAX) {		/*		 * fcode.len is an unsigned short for current kernel.		 * I have yet to see BPF-Code with that much		 * instructions but still it is possible. So for the		 * sake of correctness I added this check.		 */		fprintf(stderr, "Warning: Filter too complex for kernel\n");		fcode.filter = NULL;		can_filter_in_kernel = 0;	} else#endif /* USHRT_MAX */	{		/*		 * Oh joy, the Linux kernel uses struct sock_fprog instead		 * of struct bpf_program and of course the length field is		 * of different size. Pointed out by Sebastian		 *		 * Oh, and we also need to fix it up so that all "ret"		 * instructions with non-zero operands have 65535 as the		 * operand, and so that, if we're in cooked mode, all		 * memory-reference instructions use special magic offsets		 * in references to the link-layer header and assume that		 * the link-layer payload begins at 0; "fix_program()"		 * will do that.		 */		switch (fix_program(handle, &fcode)) {		case -1:		default:			/*			 * Fatal error; just quit.			 * (The "default" case shouldn't happen; we			 * return -1 for that reason.)			 */			return -1;		case 0:			/*			 * The program performed checks that we can't make			 * work in the kernel.			 */			can_filter_in_kernel = 0;			break;		case 1:			/*			 * We have a filter that'll work in the kernel.			 */			can_filter_in_kernel = 1;			break;		}	}	if (can_filter_in_kernel) {		if ((err = set_kernel_filter(handle, &fcode)) == 0)		{			/* Installation succeded - using kernel filter. */			handle->md.use_bpf = 1;		}		else if (err == -1)	/* Non-fatal error */		{			/*			 * Print a warning if we weren't able to install			 * the filter for a reason other than "this kernel			 * isn't configured to support socket filters.			 */			if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {				fprintf(stderr,				    "Warning: Kernel filter failed: %s\n",					pcap_strerror(errno));			}		}	}	/*	 * If we're not using the kernel filter, get rid of any kernel	 * filter that might've been there before, e.g. because the	 * previous filter could work in the kernel, or because some other	 * code attached a filter to the socket by some means other than	 * calling "pcap_setfilter()".  Otherwise, the kernel filter may	 * filter out packets that would pass the new userland filter.	 */	if (!handle->md.use_bpf)		reset_kernel_filter(handle);	/*	 * Free up the copy of the filter that was made by "fix_program()".	 */	if (fcode.filter != NULL)		free(fcode.filter);	if (err == -2)		/* Fatal error */		return -1;#endif /* SO_ATTACH_FILTER */	return 0;}/* * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */static intpcap_setdirection_linux(pcap_t *handle, pcap_direction_t d){#ifdef HAVE_PF_PACKET_SOCKETS	if (!handle->md.sock_packet) {		handle->direction = d;		return 0;	}#endif	/*	 * We're not using PF_PACKET sockets, so we can't determine	 * the direction of the packet.	 */	snprintf(handle->errbuf, sizeof(handle->errbuf),	    "Setting direction is not supported on SOCK_PACKET sockets");	return -1;}/* *  Linux uses the ARP hardware type to identify the type of an *  interface. pcap uses the DLT_xxx constants for this. This *  function takes a pointer to a "pcap_t", and an ARPHRD_xxx *  constant, as arguments, and sets "handle->linktype" to the *  appropriate DLT_XXX constant and sets "handle->offset" to *  the appropriate value (to make "handle->offset" plus link-layer *  header length be a multiple of 4, so that the link-layer payload *  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) {	case ARPHRD_ETHER:		/*		 * This is (presumably) a real Ethernet capture; give it a		 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so		 * that an application can let you choose it, in case you're		 * capturing DOCSIS traffic that a Cisco Cable Modem		 * Termination System is putting out onto an Ethernet (it		 * doesn't put an Ethernet header onto the wire, it puts raw		 * DOCSIS frames out on the wire inside the low-level		 * Ethernet framing).		 *		 * XXX - are there any sorts of "fake Ethernet" that have		 * ARPHRD_ETHER but that *shouldn't offer DLT_DOCSIS as		 * a Cisco CMTS won't put traffic onto it or get traffic		 * bridged onto it?  ISDN is handled in "live_open_new()",		 * as we fall back on cooked mode there; are there any		 * others?		 */		handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);		/*		 * If that fails, just leave the list empty.		 */		if (handle->dlt_list != NULL) {			handle->dlt_list[0] = DLT_EN10MB;			handle->dlt_list[1] = DLT_DOCSIS;

⌨️ 快捷键说明

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