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

📄 pcap-bpf.c

📁 Windows XP下的抓包程序实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		u_int i;		int is_ethernet;		bdl.bfl_list = (u_int *) malloc(sizeof(u_int) * (bdl.bfl_len + 1));		if (bdl.bfl_list == NULL) {			(void)snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",			    pcap_strerror(errno));			goto bad;		}		if (ioctl(fd, BIOCGDLTLIST, (caddr_t)&bdl) < 0) {			(void)snprintf(ebuf, PCAP_ERRBUF_SIZE,			    "BIOCGDLTLIST: %s", pcap_strerror(errno));			free(bdl.bfl_list);			goto bad;		}		/*		 * OK, for real Ethernet devices, add DLT_DOCSIS to the		 * list, 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).		 *		 * A "real Ethernet device" is defined here as a device		 * that has a link-layer type of DLT_EN10MB and that has		 * no alternate link-layer types; that's done to exclude		 * 802.11 interfaces (which might or might not be the		 * right thing to do, but I suspect it is - Ethernet <->		 * 802.11 bridges would probably badly mishandle frames		 * that don't have Ethernet headers).		 */		if (p->linktype == DLT_EN10MB) {			is_ethernet = 1;			for (i = 0; i < bdl.bfl_len; i++) {				if (bdl.bfl_list[i] != DLT_EN10MB) {					is_ethernet = 0;					break;				}			}			if (is_ethernet) {				/*				 * We reserved one more slot at the end of				 * the list.				 */				bdl.bfl_list[bdl.bfl_len] = DLT_DOCSIS;				bdl.bfl_len++;			}		}		p->dlt_count = bdl.bfl_len;		p->dlt_list = bdl.bfl_list;	} else {		if (errno != EINVAL) {			(void)snprintf(ebuf, PCAP_ERRBUF_SIZE,			    "BIOCGDLTLIST: %s", pcap_strerror(errno));			goto bad;		}	}#endif	/*	 * If this is an Ethernet device, and we don't have a DLT_ list,	 * give it a list with DLT_EN10MB and DLT_DOCSIS.  (That'd give	 * 802.11 interfaces DLT_DOCSIS, which isn't the right thing to	 * do, but there's not much we can do about that without finding	 * some other way of determining whether it's an Ethernet or 802.11	 * device.)	 */	if (p->linktype == DLT_EN10MB && p->dlt_count == 0) {		p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);		/*		 * If that fails, just leave the list empty.		 */		if (p->dlt_list != NULL) {			p->dlt_list[0] = DLT_EN10MB;			p->dlt_list[1] = DLT_DOCSIS;			p->dlt_count = 2;		}	}		#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT)	/*	 * Do a BIOCSHDRCMPLT, if defined, to turn that flag on, so	 * the link-layer source address isn't forcibly overwritten.	 * (Should we ignore errors?  Should we do this only if	 * we're open for writing?)	 *	 * XXX - I seem to remember some packet-sending bug in some	 * BSDs - check CVS log for "bpf.c"?	 */	if (ioctl(fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1) {		(void)snprintf(ebuf, PCAP_ERRBUF_SIZE,		    "BIOCSHDRCMPLT: %s", pcap_strerror(errno));		goto bad;	}#endif	/* set timeout */	if (to_ms != 0) {		/*		 * XXX - is this seconds/nanoseconds in AIX?		 * (Treating it as such doesn't fix the timeout		 * problem described below.)		 */		struct timeval to;		to.tv_sec = to_ms / 1000;		to.tv_usec = (to_ms * 1000) % 1000000;		if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {			snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",			    pcap_strerror(errno));			goto bad;		}	}#ifdef _AIX#ifdef	BIOCIMMEDIATE	/*	 * Darren Reed notes that	 *	 *	On AIX (4.2 at least), if BIOCIMMEDIATE is not set, the	 *	timeout appears to be ignored and it waits until the buffer	 *	is filled before returning.  The result of not having it	 *	set is almost worse than useless if your BPF filter	 *	is reducing things to only a few packets (i.e. one every	 *	second or so).	 *	 * so we turn BIOCIMMEDIATE mode on if this is AIX.	 *	 * We don't turn it on for other platforms, as that means we	 * get woken up for every packet, which may not be what we want;	 * in the Winter 1993 USENIX paper on BPF, they say:	 *	 *	Since a process might want to look at every packet on a	 *	network and the time between packets can be only a few	 *	microseconds, it is not possible to do a read system call	 *	per packet and BPF must collect the data from several	 *	packets and return it as a unit when the monitoring	 *	application does a read.	 *	 * which I infer is the reason for the timeout - it means we	 * wait that amount of time, in the hopes that more packets	 * will arrive and we'll get them all with one read.	 *	 * Setting BIOCIMMEDIATE mode on FreeBSD (and probably other	 * BSDs) causes the timeout to be ignored.	 *	 * On the other hand, some platforms (e.g., Linux) don't support	 * timeouts, they just hand stuff to you as soon as it arrives;	 * if that doesn't cause a problem on those platforms, it may	 * be OK to have BIOCIMMEDIATE mode on BSD as well.	 *	 * (Note, though, that applications may depend on the read	 * completing, even if no packets have arrived, when the timeout	 * expires, e.g. GUI applications that have to check for input	 * while waiting for packets to arrive; a non-zero timeout	 * prevents "select()" from working right on FreeBSD and	 * possibly other BSDs, as the timer doesn't start until a	 * "read()" is done, so the timer isn't in effect if the	 * application is blocked on a "select()", and the "select()"	 * doesn't get woken up for a BPF device until the buffer	 * fills up.)	 */	v = 1;	if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) {		snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",		    pcap_strerror(errno));		goto bad;	}#endif	/* BIOCIMMEDIATE */#endif	/* _AIX */	if (promisc) {		/* set promiscuous mode, okay if it fails */		if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) {			snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s",			    pcap_strerror(errno));		}	}	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {		snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",		    pcap_strerror(errno));		goto bad;	}	p->bufsize = v;	p->buffer = (u_char *)malloc(p->bufsize);	if (p->buffer == NULL) {		snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",		    pcap_strerror(errno));		goto bad;	}#ifdef _AIX	/* For some strange reason this seems to prevent the EFAULT 	 * problems we have experienced from AIX BPF. */	memset(p->buffer, 0x0, p->bufsize);#endif	/*	 * If there's no filter program installed, there's	 * no indication to the kernel of what the snapshot	 * length should be, so no snapshotting is done.	 *	 * Therefore, when we open the device, we install	 * an "accept everything" filter with the specified	 * snapshot length.	 */	total_insn.code = (u_short)(BPF_RET | BPF_K);	total_insn.jt = 0;	total_insn.jf = 0;	total_insn.k = snaplen;	total_prog.bf_len = 1;	total_prog.bf_insns = &total_insn;	if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) {		snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",		    pcap_strerror(errno));		goto bad;	}	/*	 * On most BPF platforms, either you can do a "select()" or	 * "poll()" on a BPF file descriptor and it works correctly,	 * or you can do it and it will return "readable" if the	 * hold buffer is full but not if the timeout expires *and*	 * a non-blocking read will, if the hold buffer is empty	 * but the store buffer isn't empty, rotate the buffers	 * and return what packets are available.	 *	 * In the latter case, the fact that a non-blocking read	 * will give you the available packets means you can work	 * around the failure of "select()" and "poll()" to wake up	 * and return "readable" when the timeout expires by using	 * the timeout as the "select()" or "poll()" timeout, putting	 * the BPF descriptor into non-blocking mode, and read from	 * it regardless of whether "select()" reports it as readable	 * or not.	 *	 * However, in FreeBSD 4.3 and 4.4, "select()" and "poll()"	 * won't wake up and return "readable" if the timer expires	 * and non-blocking reads return EWOULDBLOCK if the hold	 * buffer is empty, even if the store buffer is non-empty.	 *	 * This means the workaround in question won't work.	 *	 * Therefore, on FreeBSD 4.3 and 4.4, we set "p->selectable_fd"	 * to -1, which means "sorry, you can't use 'select()' or 'poll()'	 * here".  On all other BPF platforms, we set it to the FD for	 * the BPF device; in NetBSD, OpenBSD, and Darwin, a non-blocking	 * read will, if the hold buffer is empty and the store buffer	 * isn't empty, rotate the buffers and return what packets are	 * there (and in sufficiently recent versions of OpenBSD	 * "select()" and "poll()" should work correctly).	 *	 * XXX - what about AIX?	 */	p->selectable_fd = p->fd;	/* assume select() works until we know otherwise */	if (uname(&osinfo) == 0) {		/*		 * We can check what OS this is.		 */		if (strcmp(osinfo.sysname, "FreeBSD") == 0) {			if (strncmp(osinfo.release, "4.3-", 4) == 0 ||			     strncmp(osinfo.release, "4.4-", 4) == 0)				p->selectable_fd = -1;		}	}	p->read_op = pcap_read_bpf;	p->inject_op = pcap_inject_bpf;	p->setfilter_op = pcap_setfilter_bpf;	p->setdirection_op = pcap_setdirection_bpf;	p->set_datalink_op = pcap_set_datalink_bpf;	p->getnonblock_op = pcap_getnonblock_fd;	p->setnonblock_op = pcap_setnonblock_fd;	p->stats_op = pcap_stats_bpf;	p->close_op = pcap_close_common;	return (p); bad:	(void)close(fd);	if (p->dlt_list != NULL)		free(p->dlt_list);	free(p);	return (NULL);}intpcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf){#ifdef HAVE_DAG_API	if (dag_platform_finddevs(alldevsp, errbuf) < 0)		return (-1);#endif /* HAVE_DAG_API */	return (0);}static intpcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp){	/*	 * It looks that BPF code generated by gen_protochain() is not	 * compatible with some of kernel BPF code (for example BSD/OS 3.1).	 * Take a safer side for now.	 */	if (no_optimize) {		/*		 * XXX - what if we already have a filter in the kernel?		 */		if (install_bpf_program(p, fp) < 0)			return (-1);		p->md.use_bpf = 0;	/* filtering in userland */		return (0);	}	/*	 * Free any user-mode filter we might happen to have installed.	 */	pcap_freecode(&p->fcode);	/*	 * Try to install the kernel filter.	 */	if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",		    pcap_strerror(errno));		return (-1);	}	p->md.use_bpf = 1;	/* filtering in the kernel */	/*	 * Discard any previously-received packets, as they might have	 * passed whatever filter was formerly in effect, but might	 * not pass this filter (BIOCSETF discards packets buffered	 * in the kernel, so you can lose packets in any case).	 */	p->cc = 0;	return (0);}/* * Set direction flag: Which packets do we accept on a forwarding * single device? IN, OUT or both? */static intpcap_setdirection_bpf(pcap_t *p, pcap_direction_t d){#ifdef BIOCSSEESENT	u_int seesent;#endif	/*	 * We don't support PCAP_D_OUT.	 */	if (d == PCAP_D_OUT) {		snprintf(p->errbuf, sizeof(p->errbuf),		    "Setting direction to PCAP_D_OUT is not supported on BPF");		return -1;	}#ifdef BIOCSSEESENT	seesent = (d == PCAP_D_INOUT);	if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) {		(void) snprintf(p->errbuf, sizeof(p->errbuf),		    "Cannot set direction to %s: %s",		        (d == PCAP_D_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_IN",			strerror(errno));		return (-1);	}	return (0);#else	(void) snprintf(p->errbuf, sizeof(p->errbuf),	    "This system doesn't support BIOCSSEESENT, so the direction can't be set");	return (-1);#endif}static intpcap_set_datalink_bpf(pcap_t *p, int dlt){#ifdef BIOCSDLT	if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) {		(void) snprintf(p->errbuf, sizeof(p->errbuf),		    "Cannot set DLT %d: %s", dlt, strerror(errno));		return (-1);	}#endif	return (0);}

⌨️ 快捷键说明

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