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 + -
显示快捷键?