"@(#) 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.239 2004-03-30 14:42:40 mcr Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.265 2005-12-13 08:37:22 hannes Exp $ (LBL)";
#endif
/*
#ifndef WIN32
#include <pwd.h>
#include <grp.h>
+#include <errno.h>
#endif /* WIN32 */
#include "netdissect.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 Lflag; /* list available data link types and exit */
+int dflag; /* print filter code */
+int Lflag; /* list available data link types and exit */
static int infodelay;
static int infoprint;
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 *);
+static void ndo_error(netdissect_options *ndo, const char *fmt, ...);
+static void ndo_warning(netdissect_options *ndo, const char *fmt, ...);
#ifdef SIGINFO
RETSIGTYPE requestinfo(int);
static void info(int);
static u_int packets_captured;
-/* Length of saved portion of packet. */
-int snaplen = DEFAULT_SNAPLEN;
-
typedef u_int (*if_printer)(const struct pcap_pkthdr *, const u_char *);
struct printer {
{ sl_bsdos_if_print, DLT_SLIP_BSDOS },
#endif
{ ppp_if_print, DLT_PPP },
+#ifdef DLT_PPP_WITHDIRECTION
+ { ppp_if_print, DLT_PPP_WITHDIRECTION },
+#endif
#ifdef DLT_PPP_BSDOS
{ ppp_bsdos_if_print, DLT_PPP_BSDOS },
#endif
#endif
#ifdef DLT_APPLE_IP_OVER_IEEE1394
{ ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 },
+#endif
+#ifdef DLT_JUNIPER_ATM1
+ { juniper_atm1_print, DLT_JUNIPER_ATM1 },
+#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
{ NULL, 0 },
};
struct passwd *pw = NULL;
if (chroot_dir && !username) {
- fprintf(stderr, "Chroot without dropping root is insecure\n");
+ fprintf(stderr, "tcpdump: Chroot without dropping root is insecure\n");
exit(1);
}
if (pw) {
if (chroot_dir) {
if (chroot(chroot_dir) != 0 || chdir ("/") != 0) {
- fprintf(stderr, "Couldn't chroot/chdir to '%.64s'\n", chroot_dir);
+ fprintf(stderr, "tcpdump: Couldn't chroot/chdir to '%.64s': %s\n",
+ chroot_dir, pcap_strerror(errno));
exit(1);
}
}
- if (initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 ||
- setuid(pw->pw_uid) != 0) {
- fprintf(stderr, "Couldn't change to '%.32s' uid=%d gid=%d\n", username,
- pw->pw_uid, pw->pw_gid);
+ if (initgroups(pw->pw_name, pw->pw_gid) != 0 ||
+ setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
+ fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n",
+ username,
+ (unsigned long)pw->pw_uid,
+ (unsigned long)pw->pw_gid,
+ pcap_strerror(errno));
exit(1);
}
}
else {
- fprintf(stderr, "Couldn't find user '%.32s'\n", username);
+ fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n",
+ username);
exit(1);
}
}
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_,
va_end(args);
return ret;
-};
+}
int
main(int argc, char **argv)
gndo->ndo_Oflag=1;
gndo->ndo_Rflag=1;
- gndo->ndo_tflag=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;
+ gndo->ndo_snaplen = DEFAULT_SNAPLEN;
cnt = -1;
device = NULL;
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:lLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:YZ:")) != -1)
switch (op) {
case 'a':
break;
case 'A':
- ++xflag;
- ++Xflag;
++Aflag;
break;
#ifndef HAVE_LIBCRYPTO
warning("crypto code not compiled in");
#endif
- espsecret = optarg;
+ gndo->ndo_espsecret = optarg;
break;
case 'f':
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");
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' ",
case 'q':
++qflag;
+ ++suppress_default_print;
break;
case 'r':
break;
case 't':
- --tflag;
+ ++tflag;
break;
case 'T':
case 'x':
++xflag;
+ ++suppress_default_print;
break;
case 'X':
- ++xflag;
++Xflag;
+ ++suppress_default_print;
break;
case 'y':
/* NOTREACHED */
}
- if (tflag > 0)
+ switch (tflag) {
+
+ case 0: /* Default */
+ case 4: /* Default + Date*/
thiszone = gmt2local(0);
+ break;
+
+ 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, -tttt and -ttttt are supported");
+ break;
+ }
#ifdef WITH_CHROOT
/* if run as root, prepare for chrooting */
error("%s", ebuf);
}
#ifdef WIN32
- if(IsTextUnicode(device,
- wcslen((short*)device), // Device always ends with a double \0, so this way to determine its
- // length should be always valid
- NULL))
- {
+ if(strlen(device) == 1) //we assume that an ASCII string is always longer than 1 char
+ { //a Unicode string has a \0 as second byte (so strlen() is 1)
fprintf(stderr, "%s: listening on %ws\n", program_name, device);
}
else
}
#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);
error("%s", pcap_geterr(pd));
if (WFileName) {
pcap_dumper_t *p;
+ /* Do not exceed the default NAME_MAX for files. */
+ WFileNameAlt = (char *)malloc(NAME_MAX + 1);
- WFileNameAlt = (char *)malloc(strlen(WFileName) + MAX_CFLAG_CHARS + 1);
if (WFileNameAlt == NULL)
error("malloc of WFileNameAlt");
- MakeFilename(WFileNameAlt, WFileName, 0, WflagChars);
+
+ /* We do not need numbering for dumpfiles if Cflag isn't set. */
+ if (Cflag != 0)
+ MakeFilename(WFileNameAlt, WFileName, 0, WflagChars);
+ else
+ MakeFilename(WFileNameAlt, WFileName, 0, 0);
+
p = pcap_dump_open(pd, WFileNameAlt);
+ free(WFileNameAlt);
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;
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);
+
+ /*
+ * 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 */
+ }
+ /* Allocate space for max filename + \0. */
+ name = (char *)malloc(NAME_MAX + 1);
+ if (name == 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(name, dump_info->WFileName, 0,
+ WflagChars);
+ else
+ MakeFilename(name, dump_info->WFileName, 0, 0);
+
+ dump_info->p = pcap_dump_open(dump_info->pd, name);
+ free(name);
+ 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.
*/
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);
+ name = (char *)malloc(NAME_MAX + 1);
if (name == NULL)
error("dump_packet_and_trunc: malloc");
MakeFilename(name, dump_info->WFileName, Cflag_count, WflagChars);
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) {
/*
* Include the link-layer header.
*/
- default_print(sp, h->caplen);
+ hex_print("\n\t", sp, h->caplen);
} else {
/*
* Don't include the link-layer header - and if
* print nothing.
*/
if (h->caplen > hdrlen)
- default_print(sp + 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');
char version[]="current-cvs.tcpdump.org";
#endif
char pcap_version[]="current-cvs.tcpdump.org";
- char Wpcap_version[]="3.0 alpha";
+ char Wpcap_version[]="3.1";
#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 /* 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);
- (void)fprintf(stderr, "%s\n", pcap_lib_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,
"Usage: %s [-aAd" D_FLAG "eflLnNOpqRStu" 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 ] [ -W filecount ]\n");
+"\t\t[ -M secret ] [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n");
(void)fprintf(stderr,
-"\t\t[ -y datalinktype ] [ -Z user ]\n");
+"\t\t[ -W filecount ] [ -y datalinktype ] [ -Z user ]\n");
(void)fprintf(stderr,
"\t\t[ expression ]\n");
exit(1);
}
+
+
+
+/* VARARGS */
+static void
+ndo_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 void
+ndo_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);
+ }
+}
+