aboutsummaryrefslogtreecommitdiff
path: root/contrib/tcpdump/tcpdump.c
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2013-05-30 20:51:22 +0000
committerXin LI <delphij@FreeBSD.org>2013-05-30 20:51:22 +0000
commitd03c0883ad6dcda67e9281df01f1940292dee669 (patch)
treef1ffd0911b49d93d246ae1677dd73d297cd2d92d /contrib/tcpdump/tcpdump.c
parent7560005c4159f2ab5b497c5455a1e542400def4f (diff)
parentf3d019c7d20f9d0c07d397064fa7cef7711b2455 (diff)
downloadsrc-d03c0883ad6dcda67e9281df01f1940292dee669.tar.gz
src-d03c0883ad6dcda67e9281df01f1940292dee669.zip
MFV: tcpdump 4.4.0.
MFC after: 4 weeks
Notes
Notes: svn path=/head/; revision=251158
Diffstat (limited to 'contrib/tcpdump/tcpdump.c')
-rw-r--r--contrib/tcpdump/tcpdump.c308
1 files changed, 236 insertions, 72 deletions
diff --git a/contrib/tcpdump/tcpdump.c b/contrib/tcpdump/tcpdump.c
index 834833887d8c..c8f86db49c64 100644
--- a/contrib/tcpdump/tcpdump.c
+++ b/contrib/tcpdump/tcpdump.c
@@ -76,6 +76,10 @@ extern int SIZE_BUF;
#include <errno.h>
#endif /* WIN32 */
+/* capabilities convinience library */
+#ifdef HAVE_CAP_NG_H
+#include <cap-ng.h>
+#endif /* HAVE_CAP_NG_H */
#include "netdissect.h"
#include "interface.h"
@@ -85,8 +89,8 @@ extern int SIZE_BUF;
#include "gmt2local.h"
#include "pcap-missing.h"
-#ifndef NAME_MAX
-#define NAME_MAX 255
+#ifndef PATH_MAX
+#define PATH_MAX 1024
#endif
#ifdef SIGINFO
@@ -463,7 +467,9 @@ show_dlts_and_exit(const char *device, pcap_t *pd)
dlts[n_dlts]);
}
}
+#ifdef HAVE_PCAP_FREE_DATALINKS
pcap_free_datalinks(dlts);
+#endif
exit(0);
}
@@ -534,6 +540,19 @@ droproot(const char *username, const char *chroot_dir)
exit(1);
}
}
+#ifdef HAVE_CAP_NG_H
+ int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG);
+ if (ret < 0) {
+ printf("error : ret %d\n", ret);
+ }
+ /* We don't need CAP_SETUID and CAP_SETGID */
+ capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_SETUID);
+ capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_SETUID);
+ capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_SETUID);
+ capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_SETUID);
+ capng_apply(CAPNG_SELECT_BOTH);
+
+#else
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",
@@ -543,6 +562,7 @@ droproot(const char *username, const char *chroot_dir)
pcap_strerror(errno));
exit(1);
}
+#endif /* HAVE_CAP_NG_H */
}
else {
fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n",
@@ -570,7 +590,9 @@ getWflagChars(int x)
static void
MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
{
- char *filename = malloc(NAME_MAX + 1);
+ char *filename = malloc(PATH_MAX + 1);
+ if (filename == NULL)
+ error("Makefilename: malloc");
/* Process with strftime if Gflag is set. */
if (Gflag != 0) {
@@ -584,17 +606,17 @@ MakeFilename(char *buffer, char *orig_name, int cnt, int max_chars)
/* 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);
+ strftime(filename, PATH_MAX, orig_name, local_tm);
} else {
- strncpy(filename, orig_name, NAME_MAX);
+ strncpy(filename, orig_name, PATH_MAX);
}
if (cnt == 0 && max_chars == 0)
- strncpy(buffer, filename, NAME_MAX + 1);
+ strncpy(buffer, filename, PATH_MAX + 1);
else
- if (snprintf(buffer, NAME_MAX + 1, "%s%0*d", filename, max_chars, cnt) > NAME_MAX)
+ if (snprintf(buffer, PATH_MAX + 1, "%s%0*d", filename, max_chars, cnt) > PATH_MAX)
/* Report an error if the filename is too large */
- error("too many output files or filename is too long (> %d)", NAME_MAX);
+ error("too many output files or filename is too long (> %d)", PATH_MAX);
free(filename);
}
@@ -612,14 +634,55 @@ static int tcpdump_printf(netdissect_options *ndo _U_,
return ret;
}
+static struct print_info
+get_print_info(int type)
+{
+ struct print_info printinfo;
+
+ printinfo.ndo_type = 1;
+ printinfo.ndo = gndo;
+ printinfo.p.ndo_printer = lookup_ndo_printer(type);
+ if (printinfo.p.ndo_printer == NULL) {
+ printinfo.p.printer = lookup_printer(type);
+ printinfo.ndo_type = 0;
+ if (printinfo.p.printer == NULL) {
+ gndo->ndo_dltname = pcap_datalink_val_to_name(type);
+ if (gndo->ndo_dltname != NULL)
+ error("packet printing is not supported for link type %s: use -w",
+ gndo->ndo_dltname);
+ else
+ error("packet printing is not supported for link type %d: use -w", type);
+ }
+ }
+ return (printinfo);
+}
+
+static char *
+get_next_file(FILE *VFile, char *ptr)
+{
+ char *ret;
+
+ ret = fgets(ptr, PATH_MAX, VFile);
+ if (!ret)
+ return NULL;
+
+ if (ptr[strlen(ptr) - 1] == '\n')
+ ptr[strlen(ptr) - 1] = '\0';
+
+ return ret;
+}
+
int
main(int argc, char **argv)
{
register int cnt, op, i;
bpf_u_int32 localnet, netmask;
- register char *cp, *infile, *cmdbuf, *device, *RFileName, *WFileName;
+ register char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName;
pcap_handler callback;
int type;
+ int dlt;
+ int new_dlt;
+ const char *dlt_name;
struct bpf_program fcode;
#ifndef WIN32
RETSIGTYPE (*oldhandler)(int);
@@ -628,13 +691,17 @@ main(int argc, char **argv)
struct dump_info dumpinfo;
u_char *pcap_userdata;
char ebuf[PCAP_ERRBUF_SIZE];
+ char VFileLine[PATH_MAX + 1];
char *username = NULL;
char *chroot_dir = NULL;
+ char *ret = NULL;
+ char *end;
#ifdef HAVE_PCAP_FINDALLDEVS
pcap_if_t *devpointer;
int devnum;
#endif
int status;
+ FILE *VFile;
#ifdef WIN32
if(wsockinit() != 0) return 1;
#endif /* WIN32 */
@@ -653,7 +720,10 @@ main(int argc, char **argv)
device = NULL;
infile = NULL;
RFileName = NULL;
+ VFileName = NULL;
+ VFile = NULL;
WFileName = NULL;
+ dlt = -1;
if ((cp = strrchr(argv[0], '/')) != NULL)
program_name = cp + 1;
else
@@ -667,7 +737,7 @@ main(int argc, char **argv)
#endif
while (
- (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "vw:W:xXy:Yz:Z:")) != -1)
+ (op = getopt(argc, argv, "aAb" B_FLAG "c:C:d" D_FLAG "eE:fF:G:hHi:" I_FLAG j_FLAG J_FLAG "KlLm:M:nNOpqr:Rs:StT:u" U_FLAG "V:vw:W:xXy:Yz:Z:")) != -1)
switch (op) {
case 'a':
@@ -783,7 +853,8 @@ main(int argc, char **argv)
* It can be useful on Windows, where more than
* one interface can have the same name.
*/
- if ((devnum = atoi(optarg)) != 0) {
+ devnum = strtol(optarg, &end, 10);
+ if (optarg != end && *end == '\0') {
if (devnum < 0)
error("Invalid adapter index");
@@ -902,9 +973,7 @@ main(int argc, char **argv)
Rflag = 0;
break;
- case 's': {
- char *end;
-
+ case 's':
snaplen = strtol(optarg, &end, 0);
if (optarg == end || *end != '\0'
|| snaplen < 0 || snaplen > MAXIMUM_SNAPLEN)
@@ -912,7 +981,6 @@ main(int argc, char **argv)
else if (snaplen == 0)
snaplen = MAXIMUM_SNAPLEN;
break;
- }
case 'S':
++Sflag;
@@ -943,6 +1011,12 @@ main(int argc, char **argv)
packettype = PT_AODV;
else if (strcasecmp(optarg, "carp") == 0)
packettype = PT_CARP;
+ else if (strcasecmp(optarg, "radius") == 0)
+ packettype = PT_RADIUS;
+ else if (strcasecmp(optarg, "zmtp1") == 0)
+ packettype = PT_ZMTP1;
+ else if (strcasecmp(optarg, "vxlan") == 0)
+ packettype = PT_VXLAN;
else
error("unknown packet type `%s'", optarg);
break;
@@ -961,6 +1035,10 @@ main(int argc, char **argv)
++vflag;
break;
+ case 'V':
+ VFileName = optarg;
+ break;
+
case 'w':
WFileName = optarg;
break;
@@ -1046,6 +1124,12 @@ main(int argc, char **argv)
break;
}
+ if (fflag != 0 && (VFileName != NULL || RFileName != NULL))
+ error("-f can not be used with -V or -r");
+
+ if (VFileName != NULL && RFileName != NULL)
+ error("-V and -r are mutually exclusive.");
+
#ifdef WITH_CHROOT
/* if run as root, prepare for chrooting */
if (getuid() == 0 || geteuid() == 0) {
@@ -1064,10 +1148,16 @@ main(int argc, char **argv)
}
#endif
- if (RFileName != NULL) {
- int dlt;
- const char *dlt_name;
-
+ if (RFileName != NULL || VFileName != NULL) {
+ /*
+ * If RFileName is non-null, it's the pathname of a
+ * savefile to read. If VFileName is non-null, it's
+ * the pathname of a file containing a list of pathnames
+ * (one per line) of savefiles to read.
+ *
+ * In either case, we're reading a savefile, not doing
+ * a live capture.
+ */
#ifndef WIN32
/*
* We don't need network access, so relinquish any set-UID
@@ -1081,6 +1171,21 @@ main(int argc, char **argv)
if (setgid(getgid()) != 0 || setuid(getuid()) != 0 )
fprintf(stderr, "Warning: setgid/setuid failed !\n");
#endif /* WIN32 */
+ if (VFileName != NULL) {
+ if (VFileName[0] == '-' && VFileName[1] == '\0')
+ VFile = stdin;
+ else
+ VFile = fopen(VFileName, "r");
+
+ if (VFile == NULL)
+ error("Unable to open file: %s\n", strerror(errno));
+
+ ret = get_next_file(VFile, VFileLine);
+ if (!ret)
+ error("Nothing in %s\n", VFileName);
+ RFileName = VFileLine;
+ }
+
pd = pcap_open_offline(RFileName, ebuf);
if (pd == NULL)
error("%s", ebuf);
@@ -1097,15 +1202,20 @@ main(int argc, char **argv)
}
localnet = 0;
netmask = 0;
- if (fflag != 0)
- error("-f and -r options are incompatible");
} else {
+ /*
+ * We're doing a live capture.
+ */
if (device == NULL) {
device = pcap_lookupdev(ebuf);
if (device == NULL)
error("%s", ebuf);
}
#ifdef WIN32
+ /*
+ * Print a message to the standard error on Windows.
+ * XXX - why do it here, with a different message?
+ */
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);
@@ -1256,10 +1366,10 @@ main(int argc, char **argv)
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);
+ free(cmdbuf);
exit(0);
}
init_addrtoname(localnet, netmask);
@@ -1297,9 +1407,31 @@ main(int argc, char **argv)
* Switching to the -Z user ID only after opening the first
* savefile doesn't handle the general case.
*/
+
+#ifdef HAVE_CAP_NG_H
+ /* We are running as root and we will be writing to savefile */
+ if ((getuid() == 0 || geteuid() == 0) && WFileName) {
+ if (username) {
+ /* Drop all capabilities from effective set */
+ capng_clear(CAPNG_EFFECTIVE);
+ /* Add capabilities we will need*/
+ capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_SETUID);
+ capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_SETGID);
+ capng_update(CAPNG_ADD, CAPNG_PERMITTED, CAP_DAC_OVERRIDE);
+
+ capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_SETUID);
+ capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_SETGID);
+ capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
+
+ capng_apply(CAPNG_SELECT_BOTH);
+ }
+ }
+#endif /* HAVE_CAP_NG_H */
+
if (getuid() == 0 || geteuid() == 0) {
if (username || chroot_dir)
droproot(username, chroot_dir);
+
}
#endif /* WIN32 */
@@ -1307,8 +1439,8 @@ main(int argc, char **argv)
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);
+ /* Do not exceed the default PATH_MAX for files. */
+ dumpinfo.CurrentFileName = (char *)malloc(PATH_MAX + 1);
if (dumpinfo.CurrentFileName == NULL)
error("malloc of dumpinfo.CurrentFileName");
@@ -1320,6 +1452,10 @@ main(int argc, char **argv)
MakeFilename(dumpinfo.CurrentFileName, WFileName, 0, 0);
p = pcap_dump_open(pd, dumpinfo.CurrentFileName);
+#ifdef HAVE_CAP_NG_H
+ /* Give up capabilities, clear Effective set */
+ capng_clear(CAPNG_EFFECTIVE);
+#endif
if (p == NULL)
error("%s", pcap_geterr(pd));
if (Cflag != 0 || Gflag != 0) {
@@ -1338,21 +1474,7 @@ main(int argc, char **argv)
#endif
} else {
type = pcap_datalink(pd);
- printinfo.ndo_type = 1;
- printinfo.ndo = gndo;
- printinfo.p.ndo_printer = lookup_ndo_printer(type);
- if (printinfo.p.ndo_printer == NULL) {
- printinfo.p.printer = lookup_printer(type);
- printinfo.ndo_type = 0;
- if (printinfo.p.printer == NULL) {
- gndo->ndo_dltname = pcap_datalink_val_to_name(type);
- if (gndo->ndo_dltname != NULL)
- error("packet printing is not supported for link type %s: use -w",
- gndo->ndo_dltname);
- else
- error("packet printing is not supported for link type %d: use -w", type);
- }
- }
+ printinfo = get_print_info(type);
callback = print_packet;
pcap_userdata = (u_char *)&printinfo;
}
@@ -1384,9 +1506,11 @@ main(int argc, char **argv)
#ifndef WIN32
if (RFileName == NULL) {
- int dlt;
- const char *dlt_name;
-
+ /*
+ * Live capture (if -V was specified, we set RFileName
+ * to a file from the -V file). Print a message to
+ * the standard error on UN*X.
+ */
if (!vflag && !WFileName) {
(void)fprintf(stderr,
"%s: verbose output suppressed, use -v or -vv for full protocol decode\n",
@@ -1406,37 +1530,69 @@ main(int argc, char **argv)
(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) {
+ do {
+ status = pcap_loop(pd, cnt, callback, pcap_userdata);
+ if (WFileName == NULL) {
/*
- * We got interrupted, so perhaps we didn't
- * manage to finish a line we were printing.
- * Print an extra newline, just in case.
+ * We're printing packets. Flush the printed output,
+ * so it doesn't get intermingled with error output.
*/
- putchar('\n');
+ 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);
+ if (VFileName != NULL) {
+ ret = get_next_file(VFile, VFileLine);
+ if (ret) {
+ RFileName = VFileLine;
+ pd = pcap_open_offline(RFileName, ebuf);
+ if (pd == NULL)
+ error("%s", ebuf);
+ new_dlt = pcap_datalink(pd);
+ if (WFileName && new_dlt != dlt)
+ error("%s: new dlt does not match original", RFileName);
+ printinfo = get_print_info(new_dlt);
+ dlt_name = pcap_datalink_val_to_name(new_dlt);
+ if (dlt_name == NULL) {
+ fprintf(stderr, "reading from file %s, link-type %u\n",
+ RFileName, new_dlt);
+ } else {
+ fprintf(stderr,
+ "reading from file %s, link-type %s (%s)\n",
+ RFileName, dlt_name,
+ pcap_datalink_val_to_description(new_dlt));
+ }
+ if (pcap_compile(pd, &fcode, cmdbuf, Oflag, netmask) < 0)
+ error("%s", pcap_geterr(pd));
+ if (pcap_setfilter(pd, &fcode) < 0)
+ error("%s", pcap_geterr(pd));
+ }
}
- (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);
+ while (ret != NULL);
+
+ free(cmdbuf);
exit(status == -1 ? 1 : 0);
}
@@ -1637,7 +1793,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
if (dump_info->CurrentFileName != NULL)
free(dump_info->CurrentFileName);
/* Allocate space for max filename + \0. */
- dump_info->CurrentFileName = (char *)malloc(NAME_MAX + 1);
+ dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1);
if (dump_info->CurrentFileName == NULL)
error("dump_packet_and_trunc: malloc");
/*
@@ -1651,7 +1807,15 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
else
MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, 0, 0);
+#ifdef HAVE_CAP_NG_H
+ capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
+ capng_apply(CAPNG_EFFECTIVE);
+#endif /* HAVE_CAP_NG_H */
dump_info->p = pcap_dump_open(dump_info->pd, dump_info->CurrentFileName);
+#ifdef HAVE_CAP_NG_H
+ capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_DAC_OVERRIDE);
+ capng_apply(CAPNG_EFFECTIVE);
+#endif /* HAVE_CAP_NG_H */
if (dump_info->p == NULL)
error("%s", pcap_geterr(pd));
}
@@ -1681,7 +1845,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
}
if (dump_info->CurrentFileName != NULL)
free(dump_info->CurrentFileName);
- dump_info->CurrentFileName = (char *)malloc(NAME_MAX + 1);
+ dump_info->CurrentFileName = (char *)malloc(PATH_MAX + 1);
if (dump_info->CurrentFileName == NULL)
error("dump_packet_and_trunc: malloc");
MakeFilename(dump_info->CurrentFileName, dump_info->WFileName, Cflag_count, WflagChars);
@@ -1920,7 +2084,7 @@ usage(void)
(void)fprintf(stderr,
"\t\t[ -i interface ]" j_FLAG_USAGE " [ -M secret ]\n");
(void)fprintf(stderr,
-"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]\n");
+"\t\t[ -r file ] [ -s snaplen ] [ -T type ] [ -V file ] [ -w file ]\n");
(void)fprintf(stderr,
"\t\t[ -W filecount ] [ -y datalinktype ] [ -z command ]\n");
(void)fprintf(stderr,