"@(#) 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.265 2005-12-13 08:37:22 hannes Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.283 2008-09-25 21:45:50 guy Exp $ (LBL)";
#endif
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#ifndef WIN32
+#include <sys/wait.h>
+#include <sys/resource.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#endif /* WIN32 */
+
#include "netdissect.h"
#include "interface.h"
#include "addrtoname.h"
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));
#ifdef DLT_LTALK
{ ltalk_if_print, DLT_LTALK },
#endif
-#ifdef DLT_PFLOG
+#if defined(DLT_PFLOG) && defined(HAVE_NET_PFVAR_H)
{ pflog_if_print, DLT_PFLOG },
#endif
#ifdef DLT_FR
#ifdef DLT_APPLE_IP_OVER_IEEE1394
{ ap1394_if_print, DLT_APPLE_IP_OVER_IEEE1394 },
#endif
+#ifdef DLT_IEEE802_11_RADIO_AVS
+ { ieee802_11_radio_avs_if_print, DLT_IEEE802_11_RADIO_AVS },
+#endif
#ifdef DLT_JUNIPER_ATM1
{ juniper_atm1_print, DLT_JUNIPER_ATM1 },
#endif
#endif
#ifdef DLT_JUNIPER_CHDLC
{ juniper_chdlc_print, DLT_JUNIPER_CHDLC },
+#endif
+#ifdef DLT_MFR
+ { mfr_if_print, DLT_MFR },
+#endif
+#if defined(DLT_BLUETOOTH_HCI_H4_WITH_PHDR) && defined(HAVE_PCAP_BLUETOOTH_H)
+ { bt_if_print, DLT_BLUETOOTH_HCI_H4_WITH_PHDR},
+#endif
+#if defined(HAVE_PCAP_USB_H) && defined(DLT_USB_LINUX)
+ { usb_linux_print, DLT_USB_LINUX},
+#endif
+#if defined(HAVE_PCAP_USB_H) && defined(DLT_USB_LINUX_MMAPPED)
+ { usb_linux_print, DLT_USB_LINUX_MMAPPED},
#endif
{ NULL, 0 },
};
struct dump_info {
char *WFileName;
+ char *CurrentFileName;
pcap_t *pd;
pcap_dumper_t *p;
};
* OK, does tcpdump handle that type?
*/
if (lookup_printer(dlts[n_dlts]) == NULL)
- (void) fprintf(stderr, " (not supported)");
+ (void) fprintf(stderr, " (printing not supported)");
putchar('\n');
} else {
- (void) fprintf(stderr, " DLT %d (not supported)\n",
+ (void) fprintf(stderr, " DLT %d (printing not supported)\n",
dlts[n_dlts]);
}
}
* Set up flags that might or might not be supported depending on the
* version of libpcap we're using.
*/
-#ifdef WIN32
+#if defined(HAVE_PCAP_CREATE) || defined(WIN32)
#define B_FLAG "B:"
#define B_FLAG_USAGE " [ -B size ]"
-#else /* WIN32 */
+#else /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */
#define B_FLAG
#define B_FLAG_USAGE
-#endif /* WIN32 */
+#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */
+
+#ifdef HAVE_PCAP_CREATE
+#define I_FLAG "I"
+#else /* HAVE_PCAP_CREATE */
+#define I_FLAG
+#endif /* HAVE_PCAP_CREATE */
#ifdef HAVE_PCAP_FINDALLDEVS
#ifndef HAVE_PCAP_IF_T
{
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;
#endif
int status;
#ifdef WIN32
- u_int UserBufferSize = 1000000;
if(wsockinit() != 0) return 1;
#endif /* WIN32 */
opterr = 0;
while (
- (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)
+ (op = getopt(argc, argv, "aA" B_FLAG "c:C:d" D_FLAG "eE:fF:G:i:" I_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:Yz:Z:")) != -1)
switch (op) {
case 'a':
case 'A':
++Aflag;
break;
+ case 'b':
+ ++bflag;
+ break;
-#ifdef WIN32
+#if defined(HAVE_PCAP_CREATE) || defined(WIN32)
case 'B':
- UserBufferSize = atoi(optarg)*1024;
- if (UserBufferSize < 0)
+ Bflag = atoi(optarg)*1024;
+ if (Bflag <= 0)
error("invalid packet buffer size %s", optarg);
break;
-#endif /* WIN32 */
+#endif /* defined(HAVE_PCAP_CREATE) || defined(WIN32) */
case 'c':
cnt = atoi(optarg);
device = optarg;
break;
+#ifdef HAVE_PCAP_CREATE
+ case 'I':
+ ++Iflag;
+ break;
+#endif /* HAVE_PCAP_CREATE */
+
case 'l':
#ifdef WIN32
/*
#endif /* WIN32 */
break;
- case 'n':
- ++nflag;
- break;
-
- case 'N':
- ++Nflag;
+ case 'K':
+ ++Kflag;
break;
case 'm':
#ifndef HAVE_LIBCRYPTO
warning("crypto code not compiled in");
#endif
- tcpmd5secret = optarg;
+ sigsecret = optarg;
+ break;
+
+ case 'n':
+ ++nflag;
+ break;
+
+ case 'N':
+ ++Nflag;
break;
case 'O':
snaplen = strtol(optarg, &end, 0);
if (optarg == end || *end != '\0'
- || snaplen < 0 || snaplen > 65535)
+ || snaplen < 0 || snaplen > MAXIMUM_SNAPLEN)
error("invalid snaplen %s", optarg);
else if (snaplen == 0)
- snaplen = 65535;
+ snaplen = MAXIMUM_SNAPLEN;
break;
}
}
break;
#endif
+ case 'z':
+ if (optarg) {
+ zflag = strdup(optarg);
+ } else {
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+
case 'Z':
if (optarg) {
username = strdup(optarg);
fflush(stderr);
#endif /* WIN32 */
+#ifdef HAVE_PCAP_CREATE
+ pd = pcap_create(device, ebuf);
+ if (pd == NULL)
+ error("%s", ebuf);
+ status = pcap_set_snaplen(pd, snaplen);
+ if (status != 0)
+ error("%s: pcap_set_snaplen failed: %s",
+ device, pcap_statustostr(status));
+ status = pcap_set_promisc(pd, !pflag);
+ if (status != 0)
+ error("%s: pcap_set_promisc failed: %s",
+ device, pcap_statustostr(status));
+ if (Iflag) {
+ status = pcap_set_rfmon(pd, 1);
+ if (status != 0)
+ error("%s: pcap_set_rfmon failed: %s",
+ device, pcap_statustostr(status));
+ }
+ status = pcap_set_timeout(pd, 1000);
+ if (status != 0)
+ error("%s: pcap_set_timeout failed: %s",
+ device, pcap_statustostr(status));
+ if (Bflag != 0) {
+ status = pcap_set_buffer_size(pd, Bflag);
+ if (status != 0)
+ error("%s: pcap_set_buffer_size failed: %s",
+ device, pcap_statustostr(status));
+ }
+ status = pcap_activate(pd);
+ if (status < 0) {
+ /*
+ * pcap_activate() failed.
+ */
+ cp = pcap_geterr(pd);
+ if (status == PCAP_ERROR)
+ error("%s", cp);
+ else if ((status == PCAP_ERROR_NO_SUCH_DEVICE ||
+ status == PCAP_ERROR_PERM_DENIED) &&
+ *cp != '\0')
+ error("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+ else
+ error("%s: %s", device,
+ pcap_statustostr(status));
+ } else if (status > 0) {
+ /*
+ * pcap_activate() succeeded, but it's warning us
+ * of a problem it had.
+ */
+ cp = pcap_geterr(pd);
+ if (status == PCAP_WARNING)
+ warning("%s", cp);
+ else if (status == PCAP_WARNING_PROMISC_NOTSUP &&
+ *cp != '\0')
+ warning("%s: %s\n(%s)", device,
+ pcap_statustostr(status), cp);
+ else
+ warning("%s: %s", device,
+ pcap_statustostr(status));
+ }
+#else
*ebuf = '\0';
pd = pcap_open_live(device, snaplen, !pflag, 1000, ebuf);
if (pd == NULL)
error("%s", ebuf);
else if (*ebuf)
warning("%s", ebuf);
+#endif /* HAVE_PCAP_CREATE */
/*
* Let user own process after socket has been opened.
*/
if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
fprintf(stderr, "Warning: setgid/setuid failed !\n");
#endif /* WIN32 */
-#ifdef WIN32
- if(UserBufferSize != 1000000)
- if(pcap_setbuff(pd, UserBufferSize)==-1){
+#if !defined(HAVE_PCAP_CREATE) && defined(WIN32)
+ if(Bflag != 0)
+ if(pcap_setbuff(pd, Bflag)==-1){
error("%s", pcap_geterr(pd));
}
-#endif /* WIN32 */
+#endif /* !defined(HAVE_PCAP_CREATE) && defined(WIN32) */
if (Lflag)
show_dlts_and_exit(pd);
if (gndo->ndo_dlt >= 0) {
if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
error("%s", pcap_geterr(pd));
+ free(cmdbuf);
if (dflag) {
bpf_dump(&fcode, dflag);
pcap_close(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);
+#endif /* WIN32 */
/* Cooperate with nohup(1) */
#ifndef WIN32
if ((oldhandler = setsignal(SIGHUP, cleanup)) != SIG_DFL)
if (WFileName) {
pcap_dumper_t *p;
/* Do not exceed the default NAME_MAX for files. */
- WFileNameAlt = (char *)malloc(NAME_MAX + 1);
+ dumpinfo.CurrentFileName = (char *)malloc(NAME_MAX + 1);
- if (WFileNameAlt == NULL)
- error("malloc of WFileNameAlt");
+ if (dumpinfo.CurrentFileName == NULL)
+ error("malloc of dumpinfo.CurrentFileName");
/* We do not need numbering for dumpfiles if Cflag isn't set. */
if (Cflag != 0)
- MakeFilename(WFileNameAlt, WFileName, 0, WflagChars);
+ MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, WflagChars);
else
- MakeFilename(WFileNameAlt, WFileName, 0, 0);
+ MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0);
- p = pcap_dump_open(pd, WFileNameAlt);
- free(WFileNameAlt);
+ p = pcap_dump_open(pd, dumpinfo.CurrentFileName);
if (p == NULL)
error("%s", pcap_geterr(pd));
if (Cflag != 0 || Gflag != 0) {
if (printinfo.printer == NULL) {
gndo->ndo_dltname = pcap_datalink_val_to_name(type);
if (gndo->ndo_dltname != NULL)
- error("unsupported data link type %s",
+ error("packet printing is not supported for link type %s: use -w",
gndo->ndo_dltname);
else
- error("unsupported data link type %d", type);
+ error("packet printing is not supported for link type %d: use -w", type);
}
callback = print_packet;
pcap_userdata = (u_char *)&printinfo;
}
#endif /* WIN32 */
#ifdef SIGINFO
- (void)setsignal(SIGINFO, requestinfo);
+ /*
+ * We can't get statistics when reading from a file rather
+ * than capturing from a device.
+ */
+ if (RFileName == NULL)
+ (void)setsignal(SIGINFO, requestinfo);
#endif
if (vflag > 0 && WFileName) {
#endif
}
+/*
+ On windows, we do not use a fork, so we do not care less about
+ waiting a child processes to die
+ */
+#ifndef WIN32
+static RETSIGTYPE
+child_cleanup(int signo _U_)
+{
+ wait(NULL);
+}
+#endif /* WIN32 */
+
static void
info(register int verbose)
{
if (pcap_stats(pd, &stat) < 0) {
(void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pd));
+ infoprint = 0;
return;
}
infoprint = 0;
}
+#ifndef WIN32
+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));
+}
+#else /* WIN32 */
+static void
+compress_savefile(const char *filename)
+{
+ fprintf(stderr,
+ "compress_savefile failed. Functionality not implemented under windows\n");
+}
+#endif /* WIN32 */
+
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;
*/
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).
exit(0);
/* NOTREACHED */
}
+ if (dump_info->CurrentFileName != NULL)
+ free(dump_info->CurrentFileName);
/* Allocate space for max filename + \0. */
- name = (char *)malloc(NAME_MAX + 1);
- if (name == NULL)
+ 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
* We also don't need numbering if Cflag is not set.
*/
if (Cflag != 0)
- MakeFilename(name, dump_info->WFileName, 0,
+ MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0,
WflagChars);
else
- MakeFilename(name, dump_info->WFileName, 0, 0);
+ MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0);
- dump_info->p = pcap_dump_open(dump_info->pd, name);
- free(name);
+ dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
if (dump_info->p == NULL)
error("%s", pcap_geterr(pd));
}
* 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;
}
- name = (char *)malloc(NAME_MAX + 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));
}
#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 "ef" I_FLAG "KlLnNOpqRStu" U_FLAG "vxX]" B_FLAG_USAGE " [ -c count ]\n", program_name);
(void)fprintf(stderr,
-"\t\t[ -E algo:secret ] [ -F file ] [ -G seconds ] [ -i interface ]\n");
+"\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");
(void)fprintf(stderr,
-"\t\t[ -M secret ] [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n");
+"\t\t[ -i interface ] [ -M secret ] [ -r file ]\n");
(void)fprintf(stderr,
-"\t\t[ -W filecount ] [ -y datalinktype ] [ -Z user ]\n");
+"\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);
(void)fputc('\n', stderr);
}
}
-