]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
NTP: Use tstr for truncation indicator.
[tcpdump] / tcpdump.c
index bde74864d9ecd7893cbba61063b73445a566d3d4..270f79b4b92658d2188727f8b475b8ecc395e1ca 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -44,9 +44,10 @@ The Regents of the University of California.  All rights reserved.\n";
 #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
- * define pcap_if_t, meaning that we can't actually *use* pcap_findalldevs().
+ * Some older versions of 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 define pcap_if_t, meaning that we can't actually *use*
+ * pcap_findalldevs().
  */
 #ifdef HAVE_PCAP_FINDALLDEVS
 #ifndef HAVE_PCAP_IF_T
@@ -80,6 +81,11 @@ The Regents of the University of California.  All rights reserved.\n";
 #include <sys/ioccom.h>
 #include <net/bpf.h>
 #include <libgen.h>
+#ifdef HAVE_CASPER
+#include <libcasper.h>
+#include <casper/cap_dns.h>
+#include <sys/nv.h>
+#endif /* HAVE_CASPER */
 #endif /* HAVE_CAPSICUM */
 #include <pcap.h>
 #include <signal.h>
@@ -108,6 +114,10 @@ The Regents of the University of California.  All rights reserved.\n";
 #endif /* HAVE_CAP_NG_H */
 #endif /* HAVE_LIBCAP_NG */
 
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif /* __FreeBSD__ */
+
 #include "netdissect.h"
 #include "interface.h"
 #include "addrtoname.h"
@@ -130,7 +140,7 @@ The Regents of the University of California.  All rights reserved.\n";
 #endif
 
 static int Bflag;                      /* buffer size */
-static int Cflag;                      /* rotate dump files after this many bytes */
+static long Cflag;                     /* rotate dump files after this many bytes */
 static int Cflag_count;                        /* Keep track of which file number we're writing */
 static int Dflag;                      /* list available devices and exit */
 /*
@@ -157,7 +167,7 @@ static int Jflag;                   /* list available time stamp types */
 static int jflag = -1;                 /* packet time stamp source */
 static int pflag;                      /* don't go promiscuous */
 #ifdef HAVE_PCAP_SETDIRECTION
-int Qflag = -1;                                /* restrict captured packet by send/receive direction */
+static int Qflag = -1;                 /* restrict captured packet by send/receive direction */
 #endif
 static int Uflag;                      /* "unbuffered" output of dump files */
 static int Wflag;                      /* recycle output files after this number of files */
@@ -170,27 +180,22 @@ static int infoprint;
 
 char *program_name;
 
+#ifdef HAVE_CASPER
+cap_channel_t *capdns;
+#endif
+
 /* Forwards */
-static void error(const char *, ...)
-     __attribute__((noreturn))
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 1, 2)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
-static void warning(const char *, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-     __attribute__((format (printf, 1, 2)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-     ;
-static void exit_tcpdump(int) __attribute__((noreturn));
+static NORETURN void error(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2);
+static void warning(FORMAT_STRING(const char *), ...) PRINTFLIKE(1, 2);
+static NORETURN void exit_tcpdump(int);
 static RETSIGTYPE cleanup(int);
 static RETSIGTYPE child_cleanup(int);
 static void print_version(void);
 static void print_usage(void);
-static void show_tstamp_types_and_exit(const char *device) __attribute__((noreturn));
-static void show_dlts_and_exit(const char *device) __attribute__((noreturn));
+static NORETURN void show_tstamp_types_and_exit(pcap_t *, const char *device);
+static NORETURN void show_dlts_and_exit(pcap_t *, const char *device);
 #ifdef HAVE_PCAP_FINDALLDEVS
-static void show_devices_and_exit (void) __attribute__((noreturn));
+static NORETURN void show_devices_and_exit(void);
 #endif
 
 static void print_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
@@ -340,16 +345,16 @@ exit_tcpdump(int status)
 
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
 static void
-show_tstamp_types_and_exit(const char *device)
+show_tstamp_types_and_exit(pcap_t *pc, const char *device)
 {
        int n_tstamp_types;
        int *tstamp_types = 0;
        const char *tstamp_type_name;
        int i;
 
-       n_tstamp_types = pcap_list_tstamp_types(pd, &tstamp_types);
+       n_tstamp_types = pcap_list_tstamp_types(pc, &tstamp_types);
        if (n_tstamp_types < 0)
-               error("%s", pcap_geterr(pd));
+               error("%s", pcap_geterr(pc));
 
        if (n_tstamp_types == 0) {
                fprintf(stderr, "Time stamp type cannot be set for %s\n",
@@ -373,15 +378,15 @@ show_tstamp_types_and_exit(const char *device)
 #endif
 
 static void
-show_dlts_and_exit(const char *device)
+show_dlts_and_exit(pcap_t *pc, const char *device)
 {
        int n_dlts, i;
        int *dlts = 0;
        const char *dlt_name;
 
-       n_dlts = pcap_list_datalinks(pd, &dlts);
+       n_dlts = pcap_list_datalinks(pc, &dlts);
        if (n_dlts < 0)
-               error("%s", pcap_geterr(pd));
+               error("%s", pcap_geterr(pc));
        else if (n_dlts == 0 || !dlts)
                error("No data link types.");
 
@@ -458,7 +463,7 @@ show_devices_and_exit (void)
  * OS X tcpdump uses -g to force non--v output for IP to be on one
  * line, making it more "g"repable;
  *
- * OS X tcpdump uses -k tospecify that packet comments in pcap-ng files
+ * OS X tcpdump uses -k to specify that packet comments in pcap-ng files
  * should be printed;
  *
  * OpenBSD tcpdump uses -o to indicate that OS fingerprinting should be done
@@ -643,12 +648,13 @@ droproot(const char *username, const char *chroot_dir)
                exit_tcpdump(1);
        }
 #ifdef HAVE_LIBCAP_NG
-       /* We don't need CAP_SETUID and CAP_SETGID any more. */
+       /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT any more. */
        capng_updatev(
                CAPNG_DROP,
                CAPNG_EFFECTIVE | CAPNG_PERMITTED,
                CAP_SETUID,
                CAP_SETGID,
+               CAP_SYS_CHROOT,
                -1);
        capng_apply(CAPNG_SELECT_BOTH);
 #endif /* HAVE_LIBCAP_NG */
@@ -719,6 +725,35 @@ get_next_file(FILE *VFile, char *ptr)
        return ret;
 }
 
+#ifdef HAVE_CASPER
+static cap_channel_t *
+capdns_setup(void)
+{
+       cap_channel_t *capcas, *capdnsloc;
+       const char *types[1];
+       int families[2];
+
+       capcas = cap_init();
+       if (capcas == NULL)
+               error("unable to create casper process");
+       capdnsloc = cap_service_open(capcas, "system.dns");
+       /* Casper capability no longer needed. */
+       cap_close(capcas);
+       if (capdnsloc == NULL)
+               error("unable to open system.dns service");
+       /* Limit system.dns to reverse DNS lookups. */
+       types[0] = "ADDR";
+       if (cap_dns_type_limit(capdnsloc, types, 1) < 0)
+               error("unable to limit access to system.dns service");
+       families[0] = AF_INET;
+       families[1] = AF_INET6;
+       if (cap_dns_family_limit(capdnsloc, families, 2) < 0)
+               error("unable to limit access to system.dns service");
+
+       return (capdnsloc);
+}
+#endif /* HAVE_CASPER */
+
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
 static int
 tstamp_precision_from_string(const char *precision)
@@ -974,7 +1009,7 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
        }
 #ifdef HAVE_PCAP_SET_TSTAMP_TYPE
        if (Jflag)
-               show_tstamp_types_and_exit(device);
+               show_tstamp_types_and_exit(pc, device);
 #endif
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
        status = pcap_set_tstamp_precision(pc, ndo->ndo_tstamp_precision);
@@ -1001,10 +1036,16 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                supports_monitor_mode = 1;
        else
                supports_monitor_mode = 0;
-       status = pcap_set_snaplen(pc, ndo->ndo_snaplen);
-       if (status != 0)
-               error("%s: Can't set snapshot length: %s",
-                   device, pcap_statustostr(status));
+       if (ndo->ndo_snaplen != 0) {
+               /*
+                * A snapshot length was explicitly specified;
+                * use it.
+                */
+               status = pcap_set_snaplen(pc, ndo->ndo_snaplen);
+               if (status != 0)
+                       error("%s: Can't set snapshot length: %s",
+                           device, pcap_statustostr(status));
+       }
        status = pcap_set_promisc(pc, !pflag);
        if (status != 0)
                error("%s: Can't set promiscuous mode: %s",
@@ -1045,13 +1086,37 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                        /*
                         * Return an error for our caller to handle.
                         */
-                       pcap_close(pc);
                        snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s\n(%s)",
                            device, pcap_statustostr(status), cp);
+                       pcap_close(pc);
                        return (NULL);
                } else if (status == PCAP_ERROR_PERM_DENIED && *cp != '\0')
                        error("%s: %s\n(%s)", device,
                            pcap_statustostr(status), cp);
+#ifdef __FreeBSD__
+               else if (status == PCAP_ERROR_RFMON_NOTSUP &&
+                   strncmp(device, "wlan", 4) == 0) {
+                       char parent[8], newdev[8];
+                       char sysctl[32];
+                       size_t s = sizeof(parent);
+
+                       snprintf(sysctl, sizeof(sysctl),
+                           "net.wlan.%d.%%parent", atoi(device + 4));
+                       sysctlbyname(sysctl, parent, &s, NULL, 0);
+                       strlcpy(newdev, device, sizeof(newdev));
+                       /* Suggest a new wlan device. */
+                       /* FIXME: incrementing the index this way is not going to work well
+                        * when the index is 9 or greater but the only consequence in this
+                        * specific case would be an error message that looks a bit odd.
+                        */
+                       newdev[strlen(newdev)-1]++;
+                       error("%s is not a monitor mode VAP\n"
+                           "To create a new monitor mode VAP use:\n"
+                           "  ifconfig %s create wlandev %s wlanmode monitor\n"
+                           "and use %s as the tcpdump interface",
+                           device, newdev, parent, newdev);
+               }
+#endif
                else
                        error("%s: %s", device,
                            pcap_statustostr(status));
@@ -1081,6 +1146,12 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
 #endif /* HAVE_PCAP_SETDIRECTION */
 #else /* HAVE_PCAP_CREATE */
        *ebuf = '\0';
+       /*
+        * If no snapshot length was specified, or a length of 0 was
+        * specified, default to 256KB.
+        */
+       if (ndo->ndo_snaplen == 0)
+               ndo->ndo_snaplen = 262144;
        pc = pcap_open_live(device, ndo->ndo_snaplen, !pflag, 1000, ebuf);
        if (pc == NULL) {
                /*
@@ -1147,7 +1218,6 @@ main(int argc, char **argv)
 
        memset(ndo, 0, sizeof(*ndo));
        ndo_set_function_pointers(ndo);
-       ndo->ndo_snaplen = DEFAULT_SNAPLEN;
 
        cnt = -1;
        device = NULL;
@@ -1377,8 +1447,6 @@ main(int argc, char **argv)
                        if (optarg == end || *end != '\0'
                            || ndo->ndo_snaplen < 0 || ndo->ndo_snaplen > MAXIMUM_SNAPLEN)
                                error("invalid snaplen %s", optarg);
-                       else if (ndo->ndo_snaplen == 0)
-                               ndo->ndo_snaplen = MAXIMUM_SNAPLEN;
                        break;
 
                case 'S':
@@ -1716,7 +1784,8 @@ main(int argc, char **argv)
                }
 
                /*
-                * Let user own process after socket has been opened.
+                * Let user own process after capture device has
+                * been opened.
                 */
 #ifndef _WIN32
                if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
@@ -1729,7 +1798,7 @@ main(int argc, char **argv)
                        }
 #endif /* !defined(HAVE_PCAP_CREATE) && defined(_WIN32) */
                if (Lflag)
-                       show_dlts_and_exit(device);
+                       show_dlts_and_exit(pd, device);
                if (yflag_dlt >= 0) {
 #ifdef HAVE_PCAP_SET_DATALINK
                        if (pcap_set_datalink(pd, yflag_dlt) < 0)
@@ -1751,7 +1820,11 @@ main(int argc, char **argv)
                }
                i = pcap_snapshot(pd);
                if (ndo->ndo_snaplen < i) {
-                       warning("snaplen raised from %d to %d", ndo->ndo_snaplen, i);
+                       if (ndo->ndo_snaplen != 0)
+                               warning("snaplen raised from %d to %d", ndo->ndo_snaplen, i);
+                       ndo->ndo_snaplen = i;
+               } else if (ndo->ndo_snaplen > i) {
+                       warning("snaplen lowered from %d to %d", ndo->ndo_snaplen, i);
                        ndo->ndo_snaplen = i;
                }
                 if(ndo->ndo_fflag != 0) {
@@ -1778,6 +1851,12 @@ main(int argc, char **argv)
                pcap_freecode(&fcode);
                exit_tcpdump(0);
        }
+
+#ifdef HAVE_CASPER
+       if (!ndo->ndo_nflag)
+               capdns = capdns_setup();
+#endif /* HAVE_CASPER */
+
        init_print(ndo, localnet, netmask, timezone_offset);
 
 #ifndef _WIN32
@@ -1825,6 +1904,13 @@ main(int argc, char **argv)
                                CAP_SETGID,
                                -1);
                }
+               if (chroot_dir) {
+                       capng_update(
+                               CAPNG_ADD,
+                               CAPNG_PERMITTED | CAPNG_EFFECTIVE,
+                               CAP_SYS_CHROOT
+                               );
+               }
 
                if (WFileName) {
                        capng_update(
@@ -1847,7 +1933,12 @@ main(int argc, char **argv)
        if (RFileName == NULL && VFileName == NULL) {
                static const unsigned long cmds[] = { BIOCGSTATS, BIOCROTZBUF };
 
-               cap_rights_init(&rights, CAP_IOCTL, CAP_READ);
+               /*
+                * The various libpcap devices use a combination of
+                * read (bpf), ioctl (bpf, netmap), poll (netmap)
+                * so we add the relevant access rights.
+                */
+               cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_EVENT);
                if (cap_rights_limit(pcap_fileno(pd), &rights) < 0 &&
                    errno != ENOSYS) {
                        error("unable to limit pcap descriptor");
@@ -1987,7 +2078,12 @@ main(int argc, char **argv)
        }
 
 #ifdef HAVE_CAPSICUM
-       cansandbox = (ndo->ndo_nflag && VFileName == NULL && zflag == NULL);
+       cansandbox = (VFileName == NULL && zflag == NULL);
+#ifdef HAVE_CASPER
+       cansandbox = (cansandbox && (ndo->ndo_nflag || capdns != NULL));
+#else
+       cansandbox = (cansandbox && ndo->ndo_nflag);
+#endif /* HAVE_CASPER */
        if (cansandbox && cap_enter() < 0 && errno != ENOSYS)
                error("unable to enter the capability mode");
 #endif /* HAVE_CAPSICUM */
@@ -2322,6 +2418,7 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                        if (Cflag == 0 && Wflag > 0 && Gflag_count >= Wflag) {
                                (void)fprintf(stderr, "Maximum file limit reached: %d\n",
                                    Wflag);
+                               info(1);
                                exit_tcpdump(0);
                                /* NOTREACHED */
                        }
@@ -2590,6 +2687,14 @@ print_version(void)
        smi_version_string = nd_smi_version_string();
        if (smi_version_string != NULL)
                (void)fprintf (stderr, "SMI-library: %s\n", smi_version_string);
+
+#if defined(__SANITIZE_ADDRESS__)
+       (void)fprintf (stderr, "Compiled with AddressSanitizer/GCC.\n");
+#elif defined(__has_feature)
+#  if __has_feature(address_sanitizer)
+       (void)fprintf (stderr, "Compiled with AddressSanitizer/CLang.\n");
+#  endif
+#endif /* __SANITIZE_ADDRESS__ or __has_feature */
 }
 USES_APPLE_RST