"@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
The Regents of the University of California. All rights reserved.\n";
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.250 2004-11-07 22:05:20 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.269 2006-05-05 23:13:01 guy Exp $ (LBL)";
#endif
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
#ifndef WIN32
#include <pwd.h>
#include <grp.h>
#include "gmt2local.h"
#include "pcap-missing.h"
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
netdissect_options Gndo;
netdissect_options *gndo = &Gndo;
-/*
- * Define the maximum number of files for the -C flag, and how many
- * characters can be added to a filename for the -C flag (which
- * should be enough to handle MAX_CFLAG - 1).
- */
-#define MAX_CFLAG 1000000
-#define MAX_CFLAG_CHARS 6
-
int dflag; /* print filter code */
int Lflag; /* list available data link types and exit */
+char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */
static int infodelay;
static int infoprint;
/* Forwards */
static RETSIGTYPE cleanup(int);
+static RETSIGTYPE child_cleanup(int);
static void usage(void) __attribute__((noreturn));
static void show_dlts_and_exit(pcap_t *pd) __attribute__((noreturn));
static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
+static void ndo_default_print(netdissect_options *, const u_char *, u_int);
static void dump_packet_and_trunc(u_char *, const struct pcap_pkthdr *, const u_char *);
static void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
static void droproot(const char *, const char *);
#endif
#ifdef DLT_JUNIPER_ATM2
{ juniper_atm2_print, DLT_JUNIPER_ATM2 },
+#endif
+#ifdef DLT_JUNIPER_MFR
+ { juniper_mfr_print, DLT_JUNIPER_MFR },
+#endif
+#ifdef DLT_JUNIPER_MLFR
+ { juniper_mlfr_print, DLT_JUNIPER_MLFR },
+#endif
+#ifdef DLT_JUNIPER_MLPPP
+ { juniper_mlppp_print, DLT_JUNIPER_MLPPP },
+#endif
+#ifdef DLT_JUNIPER_PPPOE
+ { juniper_pppoe_print, DLT_JUNIPER_PPPOE },
+#endif
+#ifdef DLT_JUNIPER_PPPOE_ATM
+ { juniper_pppoe_atm_print, DLT_JUNIPER_PPPOE_ATM },
+#endif
+#ifdef DLT_JUNIPER_GGSN
+ { juniper_ggsn_print, DLT_JUNIPER_GGSN },
+#endif
+#ifdef DLT_JUNIPER_ES
+ { juniper_es_print, DLT_JUNIPER_ES },
+#endif
+#ifdef DLT_JUNIPER_MONITOR
+ { juniper_monitor_print, DLT_JUNIPER_MONITOR },
+#endif
+#ifdef DLT_JUNIPER_SERVICES
+ { juniper_services_print, DLT_JUNIPER_SERVICES },
+#endif
+#ifdef DLT_JUNIPER_ETHER
+ { juniper_ether_print, DLT_JUNIPER_ETHER },
+#endif
+#ifdef DLT_JUNIPER_PPP
+ { juniper_ppp_print, DLT_JUNIPER_PPP },
+#endif
+#ifdef DLT_JUNIPER_FRELAY
+ { juniper_frelay_print, DLT_JUNIPER_FRELAY },
+#endif
+#ifdef DLT_JUNIPER_CHDLC
+ { juniper_chdlc_print, DLT_JUNIPER_CHDLC },
+#endif
+#ifdef DLT_MFR
+ { mfr_if_print, DLT_MFR },
#endif
{ NULL, 0 },
};
struct dump_info {
char *WFileName;
+ char *CurrentFileName;
pcap_t *pd;
pcap_dumper_t *p;
};
static void
MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
{
+ char *filename = malloc(NAME_MAX + 1);
+
+ /* Process with strftime if Gflag is set. */
+ if (Gflag != 0) {
+ struct tm *local_tm;
+
+ /* Convert Gflag_time to a usable format */
+ if ((local_tm = localtime(&Gflag_time)) == NULL) {
+ error("MakeTimedFilename: localtime");
+ }
+
+ /* There's no good way to detect an error in strftime since a return
+ * value of 0 isn't necessarily failure.
+ */
+ strftime(filename, NAME_MAX, orig_name, local_tm);
+ } else {
+ strncpy(filename, orig_name, NAME_MAX);
+ }
+
if (cnt == 0 && max_chars == 0)
- strcpy(buffer, orig_name);
+ strncpy(buffer, filename, NAME_MAX + 1);
else
- sprintf(buffer, "%s%0*d", orig_name, max_chars, cnt);
+ if (snprintf(buffer, NAME_MAX + 1, "%s%0*d", filename, max_chars, cnt) > NAME_MAX)
+ /* Report an error if the filename is too large */
+ error("too many output files or filename is too long (> %d)", NAME_MAX);
+ free(filename);
}
static int tcpdump_printf(netdissect_options *ndo _U_,
{
register int cnt, op, i;
bpf_u_int32 localnet, netmask;
- register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName, *WFileNameAlt;
+ register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName;
pcap_handler callback;
int type;
struct bpf_program fcode;
gndo->ndo_Oflag=1;
gndo->ndo_Rflag=1;
gndo->ndo_dlt=-1;
+ gndo->ndo_default_print=ndo_default_print;
gndo->ndo_printf=tcpdump_printf;
gndo->ndo_error=ndo_error;
gndo->ndo_warning=ndo_warning;
opterr = 0;
while (
- (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:i:lLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:YZ:")) != -1)
+ (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:G:i:KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:Yz:Z:")) != -1)
switch (op) {
case 'a':
break;
case 'A':
- ++xflag;
- ++Xflag;
++Aflag;
break;
infile = optarg;
break;
+ case 'G':
+ Gflag = atoi(optarg);
+ if (Gflag < 0)
+ error("invalid number of seconds %s", optarg);
+
+ /* We will create one file initially. */
+ Gflag_count = 0;
+
+ /* Grab the current time for rotation use. */
+ if ((Gflag_time = time(NULL)) == (time_t)-1) {
+ error("main: can't get current time: %s",
+ pcap_strerror(errno));
+ }
+ break;
+
case 'i':
if (optarg[0] == '0' && optarg[1] == 0)
error("Invalid adapter index");
#endif /* WIN32 */
break;
- case 'n':
- ++nflag;
- break;
-
- case 'N':
- ++Nflag;
+ case 'K':
+ ++Kflag;
break;
case 'm':
#ifdef LIBSMI
- if (smiLoadModule(optarg) == 0) {
+ if (smiLoadModule(optarg) == 0) {
error("could not load MIB module %s", optarg);
- }
+ }
sflag = 1;
#else
(void)fprintf(stderr, "%s: ignoring option `-m %s' ",
tcpmd5secret = optarg;
break;
+ case 'n':
+ ++nflag;
+ break;
+
+ case 'N':
+ ++Nflag;
+ break;
+
case 'O':
Oflag = 0;
break;
case 'q':
++qflag;
+ ++suppress_default_print;
break;
case 'r':
case 'x':
++xflag;
+ ++suppress_default_print;
break;
case 'X':
++Xflag;
+ ++suppress_default_print;
break;
case 'y':
}
break;
#endif
+ case 'z':
+ if (optarg) {
+ zflag = strdup(optarg);
+ } else {
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+
case 'Z':
if (optarg) {
username = strdup(optarg);
case 1: /* No time stamp */
case 2: /* Unix timeval style */
case 3: /* Microseconds since previous packet */
+ case 5: /* Microseconds since first packet */
break;
default: /* Not supported */
- error("only -t, -tt, -ttt, and -tttt are supported");
+ error("only -t, -tt, -ttt, -tttt and -ttttt are supported");
break;
}
}
#endif
(void)fprintf(stderr, "%s: data link type %s\n",
- program_name, gndo->ndo_dltname);
+ program_name, gndo->ndo_dltname);
(void)fflush(stderr);
}
i = pcap_snapshot(pd);
exit(0);
}
init_addrtoname(localnet, netmask);
+ init_checksum();
#ifndef WIN32
(void)setsignal(SIGPIPE, cleanup);
#endif /* WIN32 */
(void)setsignal(SIGTERM, cleanup);
(void)setsignal(SIGINT, cleanup);
+ (void)setsignal(SIGCHLD, child_cleanup);
/* Cooperate with nohup(1) */
#ifndef WIN32
if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
error("%s", pcap_geterr(pd));
if (WFileName) {
pcap_dumper_t *p;
+ /* Do not exceed the default NAME_MAX for files. */
+ dumpinfo.CurrentFileName = (char *)malloc(NAME_MAX + 1);
+
+ if (dumpinfo.CurrentFileName == NULL)
+ error("malloc of dumpinfo.CurrentFileName");
- WFileNameAlt = (char *)malloc(strlen(WFileName) + MAX_CFLAG_CHARS + 1);
- if (WFileNameAlt == NULL)
- error("malloc of WFileNameAlt");
- MakeFilename(WFileNameAlt, WFileName, 0, WflagChars);
- p = pcap_dump_open(pd, WFileNameAlt);
+ /* We do not need numbering for dumpfiles if Cflag isn't set. */
+ if (Cflag != 0)
+ MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, WflagChars);
+ else
+ MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0);
+
+ p = pcap_dump_open(pd, dumpinfo.CurrentFileName);
if (p == NULL)
error("%s", pcap_geterr(pd));
- if (Cflag != 0) {
+ if (Cflag != 0 || Gflag != 0) {
callback = dump_packet_and_trunc;
dumpinfo.WFileName = WFileName;
dumpinfo.pd = pd;
#endif
}
+static RETSIGTYPE
+child_cleanup(int signo _U_)
+{
+ wait(NULL);
+}
+
static void
info(register int verbose)
{
infoprint = 0;
}
+static void
+compress_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));
+}
+
static void
dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
{
struct dump_info *dump_info;
- char *name;
++packets_captured;
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 (ftell((FILE *)dump_info->p) > 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;
- } else {
- if (Cflag_count >= MAX_CFLAG)
- error("too many output files");
}
- name = (char *)malloc(strlen(dump_info->WFileName) + MAX_CFLAG_CHARS + 1);
- if (name == NULL)
+ 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(name, dump_info->WFileName, Cflag_count, WflagChars);
- dump_info->p = pcap_dump_open(dump_info->pd, name);
- free(name);
+ 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));
}
snapend = sp + h->caplen;
hdrlen = (*print_info->printer)(h, sp);
- if (xflag) {
+ if (Xflag) {
/*
- * Print the raw packet data.
+ * 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) {
/*
hex_print("\n\t", sp + hdrlen,
h->caplen - hdrlen);
}
- } else if (Xflag) {
+ } else if (Aflag) {
/*
- * Print the raw packet data.
+ * Print the raw packet data in ASCII.
*/
- if (Xflag > 1) {
+ if (Aflag > 1) {
/*
* Include the link-layer header.
*/
- ascii_print("\n\t", sp, h->caplen);
+ ascii_print(sp, h->caplen);
} else {
/*
* Don't include the link-layer header - and if
* print nothing.
*/
if (h->caplen > hdrlen)
- ascii_print("\n\t", sp + hdrlen,
- h->caplen - hdrlen);
+ ascii_print(sp + hdrlen, h->caplen - hdrlen);
}
}
#endif
/*
- * By default, print the specified data out in hex.
+ * By default, print the specified data out in hex and ASCII.
*/
+static void
+ndo_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 */
+}
+
void
-default_print(register const u_char *bp, register u_int length)
+default_print(const u_char *bp, u_int length)
{
- ascii_print("\n\t", bp, length); /* pass on lf and identation string */
+ ndo_default_print(gndo, bp, length);
}
#ifdef SIGINFO
*/
#ifdef USE_WIN32_MM_TIMER
void CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_,
- DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_)
+ DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_)
{
struct pcap_stat stat;
#endif /* WIN32 */
#endif /* HAVE_PCAP_LIB_VERSION */
(void)fprintf(stderr,
-"Usage: %s [-aAd" D_FLAG "eflLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [-c count] [ -C file_size ]\n", program_name);
+"Usage: %s [-aAd" D_FLAG "efKlLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [-c count] [ -C file_size ]\n", program_name);
(void)fprintf(stderr,
-"\t\t[ -E algo:secret ] [ -F file ] [ -i interface ] [ -M secret ]\n");
+"\t\t[ -E algo:secret ] [ -F file ] [ -G seconds ] [ -i interface ]\n");
(void)fprintf(stderr,
-"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n");
+"\t\t[ -M secret ] [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n");
(void)fprintf(stderr,
-"\t\t[ -W filecount ] [ -y datalinktype ] [ -Z user ]\n");
+"\t\t[ -W filecount ] [ -y datalinktype ] [ -z command ] [ -Z user ]\n");
(void)fprintf(stderr,
"\t\t[ expression ]\n");
exit(1);