Skip to content

Changes related to new option added: --pipeoutput. #458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
/* define if you have the dnet_htoa function */
#undef HAVE_DNET_HTOA

/* Define to 1 if you have the `dup2' function. */
#undef HAVE_DUP2

/* Define to 1 if you have the `ether_ntohost' function. */
#undef HAVE_ETHER_NTOHOST

Expand Down Expand Up @@ -166,6 +169,12 @@
/* Define to 1 if you have the `setlinebuf' function. */
#undef HAVE_SETLINEBUF

/* Define to 1 if you have the `setpgid' function. */
#undef HAVE_SETPGID

/* Define to 1 if you have the `setsockopt' function. */
#undef HAVE_SETSOCKOPT

/* Define to 1 if you have the `sigaction' function. */
#undef HAVE_SIGACTION

Expand All @@ -178,6 +187,9 @@
/* if struct sockaddr has the sa_len member */
#undef HAVE_SOCKADDR_SA_LEN

/* Define to 1 if you have the `socketpair' function. */
#undef HAVE_SOCKETPAIR

/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H

Expand Down
12 changes: 12 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -5188,6 +5188,18 @@ _ACEOF
fi
done

for ac_func in dup2 socketpair setsockopt setpgid
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF

fi
done


needsnprintf=no
for ac_func in vsnprintf snprintf
Expand Down
1 change: 1 addition & 0 deletions configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ fi
AC_REPLACE_FUNCS(vfprintf strlcat strlcpy strdup strsep getopt_long)
AC_CHECK_FUNCS(fork vfork strftime)
AC_CHECK_FUNCS(setlinebuf alarm)
AC_CHECK_FUNCS(dup2 socketpair setsockopt setpgid)

needsnprintf=no
AC_CHECK_FUNCS(vsnprintf snprintf,,
Expand Down
31 changes: 31 additions & 0 deletions tcpdump.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ tcpdump \- dump traffic on a network
]
.ti +8
[
.BI \-\-pipeoutput= pipe-command
]
.ti +8
[
.BI \-\-time\-stamp\-precision= tstamp_precision
]
.ti +8
Expand Down Expand Up @@ -846,6 +850,33 @@ different arguments, you can always write a shell script that will take the
savefile name as the only argument, make the flags & arguments arrangements
and execute the command that you want.
.TP
.BI \-\-pipeoutput " pipe-command"
Used in conjunction with the
.B \-w
option,
.I tcpdump
will pipe output through "
.I pipe-command
" before saving it to a file.
For example, specifying
.RS
.RS
.nf
\fB-w "pcap_%F-%T.gz" -G 3 -W 60 --pipeoutput gzip\fP
.fi
.RE
will compress each file with gzip
.I before
saving it to disk. Compared with post-processing equivalent of
.RS
.nf
\fB-w "pcap_%F-%T" -G 3 -W 60 -z gzip\fP
.fi
.RE
the former has the advantage of reducing disk bandwidth at the expense of
increased CPU usage. This option is not available on all platforms.
.RE
.TP
.BI \-Z " user"
.PD 0
.TP
Expand Down
149 changes: 143 additions & 6 deletions tcpdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ The Regents of the University of California. All rights reserved.\n";
#include "config.h"
#endif

#if defined(HAVE_DUP2) && defined(HAVE_SOCKETPAIR) && \
( defined(HAVE_FORK) || defined(HAVE_VFORK) )
#define WITH_PIPEOUTPUT 1
#endif

/*
* Mac OS X may ship pcap.h from libpcap 0.6 with a libpcap based on
* 0.8. That means it has pcap_findalldevs() but the header doesn't
Expand Down Expand Up @@ -146,7 +151,13 @@ static int Uflag; /* "unbuffered" output of dump files */
static int Wflag; /* recycle output files after this number of files */
static int WflagChars;
static char *zflag = NULL; /* compress each savefile using a specified command (like gzip or bzip2) */

#ifdef WITH_PIPEOUTPUT
static char *pipeoutput = NULL;
static char *compressor_arg[1024];
#define PIPEOUTPUT_FILE_HDRSZ sizeof(struct pcap_file_header)
#define PIPEOUTPUT_PCKT_HDRSZ 16 /* =sizeof(struct pcap_sf_pkthdr) */
static long file_bytesize = PIPEOUTPUT_FILE_HDRSZ;
#endif /* WITH_PIPEOUTPUT */
static int infodelay;
static int infoprint;

Expand Down Expand Up @@ -209,6 +220,71 @@ struct dump_info {
#endif
};

#ifdef WITH_PIPEOUTPUT
static void
remap_to_pipe(pcap_dumper_t *dumper)
{
int pipefd[2];
pid_t compressor_pid;
int i;
int maxfd = getdtablesize();
#define PIPEBUFSZ (8*1024*1024)
int dump_fd = fileno(pcap_dump_file(dumper));

if (!dumper) { return; }
if (0 != socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd)) {
error("Error creating pipe: '%s'\n", strerror(errno));
}
#ifdef HAVE_SETSOCKOPT
int bufsz;
bufsz = PIPEBUFSZ;
if (0!= setsockopt(pipefd[0], SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz))) {
warning("setsockopt SO_RCVBUF failed\n");
}
bufsz = PIPEBUFSZ;
if (0!= setsockopt(pipefd[1], SOL_SOCKET, SO_SNDBUF, &bufsz, sizeof(bufsz))) {
warning("setsockopt SO_SNDBUF failed\n");
}
#endif
compressor_pid =
# ifdef HAVE_FORK
fork()
# else
vfork()
# endif
;
if (compressor_pid == -1) {
error("Error forking compressor: '%s'\n", strerror(errno));
}
if (compressor_pid == 0) {
/* child */
#ifdef HAVE_SETPGID
setpgid(0,0);
#endif
if (-1 == dup2(pipefd[0], STDIN_FILENO)) {
error("Error DUP compressor stdin: '%s'\n", strerror(errno));
}
close(pipefd[0]);
if (-1 == dup2(dump_fd, STDOUT_FILENO)) {
error("Error DUP compressor stdout: '%s'\n", strerror(errno));
}
for (i=0; i<maxfd; ++i) {
if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
close(i);
}
execvp(compressor_arg[0], compressor_arg);
/* should not return */
error("Failed to execute --pipeout command %s: %s\n",
compressor_arg[0], strerror(errno));
} else {
/* parent */
close(pipefd[0]); /* read end of pipe */
dup2(pipefd[1], dump_fd);
close(pipefd[1]);
}
}
#endif /* WITH_PIPEOUTPUT */

#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
static void
show_tstamp_types_and_exit(const char *device)
Expand Down Expand Up @@ -419,8 +495,13 @@ show_devices_and_exit (void)
#define OPTION_VERSION 128
#define OPTION_TSTAMP_PRECISION 129
#define OPTION_IMMEDIATE_MODE 130

#ifdef WITH_PIPEOUTPUT
#define OPTION_PIPEOUTPUT 1190
#endif /* WITH_PIPEOUTPUT */
static const struct option longopts[] = {
#ifdef WITH_PIPEOUTPUT
{ "pipeoutput", required_argument, NULL, OPTION_PIPEOUTPUT },
#endif /* WITH_PIPEOUTPUT */
#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
{ "buffer-size", required_argument, NULL, 'B' },
#endif
Expand Down Expand Up @@ -1153,6 +1234,21 @@ main(int argc, char **argv)
break;
#endif

#ifdef WITH_PIPEOUTPUT
case OPTION_PIPEOUTPUT:
pipeoutput = optarg;
{
int ii=0, cc=0;
compressor_arg[cc] = pipeoutput;
for ( ; pipeoutput[ii] != '\0'; ++i) {
if (pipeoutput[ii] == ' ') {
pipeoutput[i] = '\0';
compressor_arg[++cc] = &pipeoutput[ii+1];
}
}
}
break;
#endif /* WITH_PIPEOUTPUT */
default:
print_usage();
exit(1);
Expand Down Expand Up @@ -1635,6 +1731,12 @@ main(int argc, char **argv)
callback = dump_packet;
pcap_userdata = (u_char *)p;
}
#ifdef WITH_PIPEOUTPUT
if (pipeoutput) {
remap_to_pipe(p);
}
#endif /* WITH_PIPEOUTPUT */

#ifdef HAVE_PCAP_DUMP_FLUSH
if (Uflag)
pcap_dump_flush(p);
Expand Down Expand Up @@ -1721,7 +1823,7 @@ main(int argc, char **argv)
}
(void)fflush(stdout);
}
if (status == -2) {
if (status == -2) {
/*
* We got interrupted. If we are reading multiple
* files (via -V) set these so that we stop.
Expand Down Expand Up @@ -1780,7 +1882,13 @@ main(int argc, char **argv)
}
}
while (ret != NULL);

#ifdef WITH_PIPEOUTPUT
if (pipeoutput && dumpinfo.p) {
pcap_dump_close(dumpinfo.p);
dumpinfo.p = NULL;
wait(NULL);
}
#endif /* WITH_PIPEOUTPUT */
free(cmdbuf);
exit(status == -1 ? 1 : 0);
}
Expand Down Expand Up @@ -2029,6 +2137,13 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
#else /* !HAVE_CAPSICUM */
dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
#endif

#ifdef WITH_PIPEOUTPUT
if (pipeoutput) {
remap_to_pipe(dump_info->p);
}
#endif /* WITH_PIPEOUTPUT */

#ifdef HAVE_LIBCAP_NG
capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
capng_apply(CAPNG_SELECT_BOTH);
Expand All @@ -2047,7 +2162,16 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
* file could put it over Cflag.
*/
if (Cflag != 0) {
long size = pcap_dump_ftell(dump_info->p);
long size = 0;
#ifdef WITH_PIPEOUTPUT
if (pipeoutput) {
size = file_bytesize;
} else {
size = pcap_dump_ftell(dump_info->p);
}
#else
size = pcap_dump_ftell(dump_info->p);
#endif /* WITH_PIPEOUTPUT */

if (size == -1)
error("ftell fails on output file");
Expand All @@ -2061,7 +2185,6 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
* 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.
Expand Down Expand Up @@ -2100,6 +2223,14 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
#else /* !HAVE_CAPSICUM */
dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
#endif
#ifdef WITH_PIPEOUTPUT
file_bytesize = PIPEOUTPUT_FILE_HDRSZ;

if (pipeoutput) {
remap_to_pipe(dump_info->p);
}
#endif /* WITH_PIPEOUTPUT */

#ifdef HAVE_LIBCAP_NG
capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
capng_apply(CAPNG_SELECT_BOTH);
Expand All @@ -2113,6 +2244,9 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
}

pcap_dump((u_char *)dump_info->p, h, sp);
#ifdef WITH_PIPEOUTPUT
file_bytesize += (h->caplen + PIPEOUTPUT_PCKT_HDRSZ);
#endif /* WITH_PIPEOUTPUT */
#ifdef HAVE_PCAP_DUMP_FLUSH
if (Uflag)
pcap_dump_flush(dump_info->p);
Expand Down Expand Up @@ -2278,6 +2412,9 @@ print_usage(void)
(void)fprintf(stderr, "[ -T type ] [ --version ] [ -V file ]\n");
(void)fprintf(stderr,
"\t\t[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z command ]\n");
#ifdef WITH_PIPEOUTPUT
(void)fprintf(stderr, "\t\t[ --pipeoutput command ]\n");
#endif /* WITH_PIPEOUTPUT */
(void)fprintf(stderr,
"\t\t[ -Z user ] [ expression ]\n");
}
Expand Down