tcpdump.c

来自「TCPDUMP的C语言源代码,是在数据链路层的应用」· C语言 代码 · 共 1,726 行 · 第 1/3 页

C
1,726
字号
	 */	if (RFileName == NULL)		(void)setsignal(SIGINFO, requestinfo);#endif	if (vflag > 0 && WFileName) {		/*		 * When capturing to a file, "-v" means tcpdump should,		 * every 10 secodns, "v"erbosely report the number of		 * packets captured.		 */#ifdef USE_WIN32_MM_TIMER		/* call verbose_stats_dump() each 1000 +/-100msec */		timer_id = timeSetEvent(1000, 100, verbose_stats_dump, 0, TIME_PERIODIC);		setvbuf(stderr, NULL, _IONBF, 0);#elif defined(HAVE_ALARM)		(void)setsignal(SIGALRM, verbose_stats_dump);		alarm(1);#endif	}#ifndef WIN32	if (RFileName == NULL) {		int dlt;		const char *dlt_name;		if (!vflag && !WFileName) {			(void)fprintf(stderr,			    "%s: verbose output suppressed, use -v or -vv for full protocol decode\n",			    program_name);		} else			(void)fprintf(stderr, "%s: ", program_name);		dlt = pcap_datalink(pd);		dlt_name = pcap_datalink_val_to_name(dlt);		if (dlt_name == NULL) {			(void)fprintf(stderr, "listening on %s, link-type %u, capture size %u bytes\n",			    device, dlt, snaplen);		} else {			(void)fprintf(stderr, "listening on %s, link-type %s (%s), capture size %u bytes\n",			    device, dlt_name,			    pcap_datalink_val_to_description(dlt), snaplen);		}		(void)fflush(stderr);	}#endif /* WIN32 */	status = pcap_loop(pd, cnt, callback, pcap_userdata);	if (WFileName == NULL) {		/*		 * We're printing packets.  Flush the printed output,		 * so it doesn't get intermingled with error output.		 */		if (status == -2) {			/*			 * We got interrupted, so perhaps we didn't			 * manage to finish a line we were printing.			 * Print an extra newline, just in case.			 */			putchar('\n');		}		(void)fflush(stdout);	}	if (status == -1) {		/*		 * Error.  Report it.		 */		(void)fprintf(stderr, "%s: pcap_loop: %s\n",		    program_name, pcap_geterr(pd));	}	if (RFileName == NULL) {		/*		 * We're doing a live capture.  Report the capture		 * statistics.		 */		info(1);	}	pcap_close(pd);	exit(status == -1 ? 1 : 0);}/* make a clean exit on interrupts */static RETSIGTYPEcleanup(int signo _U_){#ifdef USE_WIN32_MM_TIMER	if (timer_id)		timeKillEvent(timer_id);	timer_id = 0;#elif defined(HAVE_ALARM)	alarm(0);#endif#ifdef HAVE_PCAP_BREAKLOOP	/*	 * We have "pcap_breakloop()"; use it, so that we do as little	 * as possible in the signal handler (it's probably not safe	 * to do anything with standard I/O streams in a signal handler -	 * the ANSI C standard doesn't say it is).	 */	pcap_breakloop(pd);#else	/*	 * We don't have "pcap_breakloop()"; this isn't safe, but	 * it's the best we can do.  Print the summary if we're	 * not reading from a savefile - i.e., if we're doing a	 * live capture - and exit.	 */	if (pd != NULL && pcap_file(pd) == NULL) {		/*		 * We got interrupted, so perhaps we didn't		 * manage to finish a line we were printing.		 * Print an extra newline, just in case.		 */		putchar('\n');		(void)fflush(stdout);		info(1);	}	exit(0);#endif}/*  On windows, we do not use a fork, so we do not care less about  waiting a child processes to die */#ifndef WIN32static RETSIGTYPEchild_cleanup(int signo _U_){  wait(NULL);}#endif /* WIN32 */static voidinfo(register int verbose){	struct pcap_stat stat;	if (pcap_stats(pd, &stat) < 0) {		(void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd));		infoprint = 0;		return;	}	if (!verbose)		fprintf(stderr, "%s: ", program_name);	(void)fprintf(stderr, "%u packets captured", packets_captured);	if (!verbose)		fputs(", ", stderr);	else		putc('\n', stderr);	(void)fprintf(stderr, "%d packets received by filter", stat.ps_recv);	if (!verbose)		fputs(", ", stderr);	else		putc('\n', stderr);	(void)fprintf(stderr, "%d packets dropped by kernel\n", stat.ps_drop);	infoprint = 0;}#ifndef WIN32static voidcompress_savefile(const char *filename){	if (fork())		return;	/*	 * Set to lowest priority so that this doesn't disturb the capture	 */#ifdef NZERO	setpriority(PRIO_PROCESS, 0, NZERO - 1);#else	setpriority(PRIO_PROCESS, 0, 19);#endif	if (execlp(zflag, zflag, filename, NULL) == -1)		fprintf(stderr,			"compress_savefile:execlp(%s, %s): %s\n",			zflag,			filename,			strerror(errno));}#else  /* WIN32 */static voidcompress_savefile(const char *filename){	fprintf(stderr,		"compress_savefile failed. Functionality not implemented under windows\n");}#endif /* WIN32 */static voiddump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp){	struct dump_info *dump_info;	++packets_captured;	++infodelay;	dump_info = (struct dump_info *)user;	/*	 * XXX - this won't force the file to rotate on the specified time	 * boundary, but it will rotate on the first packet received after the	 * specified Gflag number of seconds. Note: if a Gflag time boundary	 * and a Cflag size boundary coincide, the time rotation will occur	 * first thereby cancelling the Cflag boundary (since the file should	 * be 0).	 */	if (Gflag != 0) {		/* Check if it is time to rotate */		time_t t;		/* Get the current time */		if ((t = time(NULL)) == (time_t)-1) {			error("dump_and_trunc_packet: can't get current_time: %s",			    pcap_strerror(errno));		}		/* If the time is greater than the specified window, rotate */		if (t - Gflag_time >= Gflag) {			/* Update the Gflag_time */			Gflag_time = t;			/* Update Gflag_count */			Gflag_count++;			/*			 * Close the current file and open a new one.			 */			pcap_dump_close(dump_info->p);			/*			 * Compress the file we just closed, if the user asked for it			 */			if (zflag != NULL)				compress_savefile(dump_info->CurrentFileName);			/*			 * Check to see if we've exceeded the Wflag (when			 * not using Cflag).			 */			if (Cflag == 0 && Wflag > 0 && Gflag_count >= Wflag) {				(void)fprintf(stderr, "Maximum file limit reached: %d\n",				    Wflag);				exit(0);				/* NOTREACHED */			}			if (dump_info->CurrentFileName != NULL)				free(dump_info->CurrentFileName);			/* Allocate space for max filename + \0. */			dump_info->CurrentFileName = (char *)malloc(NAME_MAX + 1);			if (dump_info->CurrentFileName == NULL)				error("dump_packet_and_trunc: malloc");			/*			 * This is always the first file in the Cflag			 * rotation: e.g. 0			 * We also don't need numbering if Cflag is not set.			 */			if (Cflag != 0)				MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0,				    WflagChars);			else				MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0);			dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);			if (dump_info->p == NULL)				error("%s", pcap_geterr(pd));		}	}	/*	 * XXX - this won't prevent capture files from getting	 * larger than Cflag - the last packet written to the	 * file could put it over Cflag.	 */	if (Cflag != 0 && pcap_dump_ftell(dump_info->p) > Cflag) {		/*		 * Close the current file and open a new one.		 */		pcap_dump_close(dump_info->p);		/*		 * Compress the file we just closed, if the user asked for it		 */		if (zflag != NULL)			compress_savefile(dump_info->CurrentFileName);		Cflag_count++;		if (Wflag > 0) {			if (Cflag_count >= Wflag)				Cflag_count = 0;		}		if (dump_info->CurrentFileName != NULL)			free(dump_info->CurrentFileName);		dump_info->CurrentFileName = (char *)malloc(NAME_MAX + 1);		if (dump_info->CurrentFileName == NULL)			error("dump_packet_and_trunc: malloc");		MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);		dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);		if (dump_info->p == NULL)			error("%s", pcap_geterr(pd));	}	pcap_dump((u_char *)dump_info->p, h, sp);#ifdef HAVE_PCAP_DUMP_FLUSH	if (Uflag)		pcap_dump_flush(dump_info->p);#endif	--infodelay;	if (infoprint)		info(0);}static voiddump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp){	++packets_captured;	++infodelay;	pcap_dump(user, h, sp);#ifdef HAVE_PCAP_DUMP_FLUSH	if (Uflag)		pcap_dump_flush((pcap_dumper_t *)user);#endif	--infodelay;	if (infoprint)		info(0);}static voidprint_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp){	struct print_info *print_info;	u_int hdrlen;	++packets_captured;	++infodelay;	ts_print(&h->ts);	print_info = (struct print_info *)user;	/*	 * Some printers want to check that they're not walking off the	 * end of the packet.	 * Rather than pass it all the way down, we set this global.	 */	snapend = sp + h->caplen;	hdrlen = (*print_info->printer)(h, sp);	if (Xflag) {		/*		 * Print the raw packet data in hex and ASCII.		 */		if (Xflag > 1) {			/*			 * Include the link-layer header.			 */			hex_and_ascii_print("\n\t", sp, h->caplen);		} else {			/*			 * Don't include the link-layer header - and if			 * we have nothing past the link-layer header,			 * print nothing.			 */			if (h->caplen > hdrlen)				hex_and_ascii_print("\n\t", sp + hdrlen,				    h->caplen - hdrlen);		}	} else if (xflag) {		/*		 * Print the raw packet data in hex.		 */		if (xflag > 1) {			/*			 * Include the link-layer header.			 */			hex_print("\n\t", sp, h->caplen);		} else {			/*			 * Don't include the link-layer header - and if			 * we have nothing past the link-layer header,			 * print nothing.			 */			if (h->caplen > hdrlen)				hex_print("\n\t", sp + hdrlen,				    h->caplen - hdrlen);		}	} else if (Aflag) {		/*		 * Print the raw packet data in ASCII.		 */		if (Aflag > 1) {			/*			 * Include the link-layer header.			 */			ascii_print(sp, h->caplen);		} else {			/*			 * Don't include the link-layer header - and if			 * we have nothing past the link-layer header,			 * print nothing.			 */			if (h->caplen > hdrlen)				ascii_print(sp + hdrlen, h->caplen - hdrlen);		}	}	putchar('\n');	--infodelay;	if (infoprint)		info(0);}#ifdef WIN32	/*	 * XXX - there should really be libpcap calls to get the version	 * number as a string (the string would be generated from #defines	 * at run time, so that it's not generated from string constants	 * in the library, as, on many UNIX systems, those constants would	 * be statically linked into the application executable image, and	 * would thus reflect the version of libpcap on the system on	 * which the application was *linked*, not the system on which it's	 * *running*.	 *	 * That routine should be documented, unlike the "version[]"	 * string, so that UNIX vendors providing their own libpcaps	 * don't omit it (as a couple of vendors have...).	 *	 * Packet.dll should perhaps also export a routine to return the	 * version number of the Packet.dll code, to supply the	 * "Wpcap_version" information on Windows.	 */	char WDversion[]="current-cvs.tcpdump.org";#if !defined(HAVE_GENERATED_VERSION)	char version[]="current-cvs.tcpdump.org";#endif	char pcap_version[]="current-cvs.tcpdump.org";	char Wpcap_version[]="3.1";#endif/* * By default, print the specified data out in hex and ASCII. */static voidndo_default_print(netdissect_options *ndo _U_, const u_char *bp, u_int length){	hex_and_ascii_print("\n\t", bp, length); /* pass on lf and identation string */}voiddefault_print(const u_char *bp, u_int length){	ndo_default_print(gndo, bp, length);}#ifdef SIGINFORETSIGTYPE requestinfo(int signo _U_){	if (infodelay)		++infoprint;	else		info(0);}#endif/* * Called once each second in verbose mode while dumping to file */#ifdef USE_WIN32_MM_TIMERvoid CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_,				  DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_){	struct pcap_stat stat;	if (infodelay == 0 && pcap_stats(pd, &stat) >= 0)		fprintf(stderr, "Got %u\r", packets_captured);}#elif defined(HAVE_ALARM)static void verbose_stats_dump(int sig _U_){	struct pcap_stat stat;	if (infodelay == 0 && pcap_stats(pd, &stat) >= 0)		fprintf(stderr, "Got %u\r", packets_captured);	alarm(1);}#endifstatic voidusage(void){	extern char version[];#ifndef HAVE_PCAP_LIB_VERSION#if defined(WIN32) || defined(HAVE_PCAP_VERSION)	extern char pcap_version[];#else /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */	static char pcap_version[] = "unknown";#endif /* defined(WIN32) || defined(HAVE_PCAP_VERSION) */#endif /* HAVE_PCAP_LIB_VERSION */#ifdef HAVE_PCAP_LIB_VERSION#ifdef WIN32	(void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version);#else /* WIN32 */	(void)fprintf(stderr, "%s version %s\n", program_name, version);#endif /* WIN32 */	(void)fprintf(stderr, "%s\n",pcap_lib_version());#else /* HAVE_PCAP_LIB_VERSION */#ifdef WIN32	(void)fprintf(stderr, "%s version %s, based on tcpdump version %s\n", program_name, WDversion, version);	(void)fprintf(stderr, "WinPcap version %s, based on libpcap version %s\n",Wpcap_version, pcap_version);#else /* WIN32 */	(void)fprintf(stderr, "%s version %s\n", program_name, version);	(void)fprintf(stderr, "libpcap version %s\n", pcap_version);#endif /* WIN32 */#endif /* HAVE_PCAP_LIB_VERSION */	(void)fprintf(stderr,"Usage: %s [-aAd" D_FLAG "ef" I_FLAG "KlLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name);	(void)fprintf(stderr,"\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");	(void)fprintf(stderr,"\t\t[ -i interface ] [ -M secret ] [ -r file ]\n");	(void)fprintf(stderr,"\t\t[ -s snaplen ] [ -T type ] [ -w file ] [ -W filecount ]\n");	(void)fprintf(stderr,"\t\t[ -y datalinktype ] [ -z command ] [ -Z user ]\n");	(void)fprintf(stderr,"\t\t[ expression ]\n");	exit(1);}/* VARARGS */static voidndo_error(netdissect_options *ndo _U_, const char *fmt, ...){	va_list ap;	(void)fprintf(stderr, "%s: ", program_name);	va_start(ap, fmt);	(void)vfprintf(stderr, fmt, ap);	va_end(ap);	if (*fmt) {		fmt += strlen(fmt);		if (fmt[-1] != '\n')			(void)fputc('\n', stderr);	}	exit(1);	/* NOTREACHED */}/* VARARGS */static voidndo_warning(netdissect_options *ndo _U_, const char *fmt, ...){	va_list ap;	(void)fprintf(stderr, "%s: WARNING: ", program_name);	va_start(ap, fmt);	(void)vfprintf(stderr, fmt, ap);	va_end(ap);	if (*fmt) {		fmt += strlen(fmt);		if (fmt[-1] != '\n')			(void)fputc('\n', stderr);	}}

⌨️ 快捷键说明

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