]> The Tcpdump Group git mirrors - tcpdump/blobdiff - tcpdump.c
It is once per second, not every 10 seconds.
[tcpdump] / tcpdump.c
index 6752c674fd47cc4a1e8cfeb07c3b09295bee0788..520d69f7d5f17c346787f030ce767a63519c1ba1 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -114,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"
@@ -136,7 +140,11 @@ 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 */
+#ifdef HAVE_PCAP_FTELL64
+static int64_t Cflag;                  /* rotate dump files after this many bytes */
+#else
+static long Cflag;                     /* rotate dump files after this many bytes */
+#endif
 static int Cflag_count;                        /* Keep track of which file number we're writing */
 static int Dflag;                      /* list available devices and exit */
 /*
@@ -181,26 +189,17 @@ 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(pcap_t *, const char *device) __attribute__((noreturn));
-static void show_dlts_and_exit(pcap_t *, 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 *);
@@ -249,6 +248,7 @@ struct dump_info {
        char    *CurrentFileName;
        pcap_t  *pd;
        pcap_dumper_t *p;
+       netdissect_options *ndo;
 #ifdef HAVE_CAPSICUM
        int     dirfd;
 #endif
@@ -558,6 +558,7 @@ show_devices_and_exit (void)
 #define OPTION_VERSION         128
 #define OPTION_TSTAMP_PRECISION        129
 #define OPTION_IMMEDIATE_MODE  130
+#define OPTION_PRINT           131
 
 static const struct option longopts[] = {
 #if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
@@ -597,6 +598,7 @@ static const struct option longopts[] = {
 #endif
        { "relinquish-privileges", required_argument, NULL, 'Z' },
        { "number", no_argument, NULL, '#' },
+       { "print", no_argument, NULL, OPTION_PRINT },
        { "version", no_argument, NULL, OPTION_VERSION },
        { NULL, 0, NULL, 0 }
 };
@@ -1041,10 +1043,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",
@@ -1092,6 +1100,30 @@ open_interface(const char *device, netdissect_options *ndo, char *ebuf)
                } 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));
@@ -1121,6 +1153,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) {
                /*
@@ -1144,9 +1182,10 @@ int
 main(int argc, char **argv)
 {
        register int cnt, op, i;
-       bpf_u_int32 localnet =, netmask = 0;
+       bpf_u_int32 localnet = 0, netmask = 0;
        int timezone_offset = 0;
        register char *cp, *infile, *cmdbuf, *device, *RFileName, *VFileName, *WFileName;
+       char *endp;
        pcap_handler callback;
        int dlt;
        const char *dlt_name;
@@ -1175,6 +1214,7 @@ main(int argc, char **argv)
        int Oflag = 1;                  /* run filter code optimizer */
        int yflag_dlt = -1;
        const char *yflag_dlt_name = NULL;
+       int print = 0;
 
        netdissect_options Ndo;
        netdissect_options *ndo = &Ndo;
@@ -1187,7 +1227,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;
@@ -1248,9 +1287,25 @@ main(int argc, char **argv)
                        break;
 
                case 'C':
-                       Cflag = atoi(optarg) * 1000000;
-                       if (Cflag <= 0)
+                       errno = 0;
+#ifdef HAVE_PCAP_FTELL64
+                       Cflag = strtoint64_t(optarg, &endp, 10);
+#else
+                       Cflag = strtol(optarg, &endp, 10);
+#endif
+                       if (endp == optarg || *endp != '\0' || errno != 0
+                           || Cflag <= 0)
                                error("invalid file size %s", optarg);
+                       /*
+                        * Will multiplying it by 1000000 overflow?
+                        */
+#ifdef HAVE_PCAP_FTELL64
+                       if (Cflag > INT64_T_CONSTANT(0x7fffffffffffffffU) / 1000000)
+#else
+                       if (Cflag > LONG_MAX / 1000000)
+#endif
+                               error("file size %s is too large", optarg);
+                       Cflag *= 1000000;
                        break;
 
                case 'd':
@@ -1417,8 +1472,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':
@@ -1554,6 +1607,10 @@ main(int argc, char **argv)
                        break;
 #endif
 
+               case OPTION_PRINT:
+                       print = 1;
+                       break;
+
                default:
                        print_usage();
                        exit_tcpdump(1);
@@ -1592,11 +1649,14 @@ main(int argc, char **argv)
 #ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
        /*
         * If we're printing dissected packets to the standard output
-        * rather than saving raw packets to a file, and the standard
-        * output is a terminal, use immediate mode, as the user's
-        * probably expecting to see packets pop up immediately.
+        * and the standard output is a terminal, use immediate mode,
+        * as the user's probably expecting to see packets pop up
+        * immediately.
+        *
+        * XXX - set the timeout to a lower value, instead?  If so,
+        * what value would be appropriate?
         */
-       if (WFileName == NULL && isatty(1))
+       if ((WFileName == NULL || print) && isatty(1))
                immediate_mode = 1;
 #endif
 
@@ -1696,20 +1756,21 @@ main(int argc, char **argv)
                         * Find the list of interfaces, and pick
                         * the first interface.
                         */
-                       if (pcap_findalldevs(&devlist, ebuf) >= 0 &&
-                           devlist != NULL) {
-                               device = strdup(devlist->name);
-                               pcap_freealldevs(devlist);
-                       }
+                       if (pcap_findalldevs(&devlist, ebuf) == -1)
+                               error("%s", ebuf);
+                       if (devlist == NULL)
+                               error("no interfaces available for capture");
+                       device = strdup(devlist->name);
+                       pcap_freealldevs(devlist);
 #else /* HAVE_PCAP_FINDALLDEVS */
                        /*
                         * Use whatever interface pcap_lookupdev()
                         * chooses.
                         */
                        device = pcap_lookupdev(ebuf);
-#endif
                        if (device == NULL)
                                error("%s", ebuf);
+#endif
                }
 
                /*
@@ -1756,7 +1817,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)
@@ -1791,7 +1853,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) {
@@ -1981,8 +2047,18 @@ main(int argc, char **argv)
                        pcap_userdata = (u_char *)&dumpinfo;
                } else {
                        callback = dump_packet;
-                       pcap_userdata = (u_char *)p;
+                       dumpinfo.WFileName = WFileName;
+                       dumpinfo.pd = pd;
+                       dumpinfo.p = p;
+                       pcap_userdata = (u_char *)&dumpinfo;
                }
+               if (print) {
+                       dlt = pcap_datalink(pd);
+                       ndo->ndo_if_printer = get_if_printer(ndo, dlt);
+                       dumpinfo.ndo = ndo;
+               } else
+                       dumpinfo.ndo = NULL;
+
 #ifdef HAVE_PCAP_DUMP_FLUSH
                if (Uflag)
                        pcap_dump_flush(p);
@@ -2003,11 +2079,11 @@ main(int argc, char **argv)
                (void)setsignal(SIGNAL_REQ_INFO, requestinfo);
 #endif
 
-       if (ndo->ndo_vflag > 0 && WFileName) {
+       if (ndo->ndo_vflag > 0 && WFileName && !print) {
                /*
-                * When capturing to a file, "-v" means tcpdump should,
-                * every 10 seconds, "v"erbosely report the number of
-                * packets captured.
+                * When capturing to a file, if "--print" wasn't specified,
+                *"-v" means tcpdump should, once per second,
+                * "v"erbosely report the number of packets captured.
                 */
 #ifdef USE_WIN32_MM_TIMER
                /* call verbose_stats_dump() each 1000 +/-100msec */
@@ -2452,7 +2528,17 @@ 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) {
+#ifdef HAVE_PCAP_FTELL64
+               int64_t size = pcap_dump_ftell64(dump_info->p);
+#else
+               /*
+                * XXX - this only handles a Cflag value > 2^31-1 on
+                * LP64 platforms; to handle ILP32 (32-bit UN*X and
+                * Windows) or LLP64 (64-bit Windows) would require
+                * a version of libpcap with pcap_dump_ftell64().
+                */
                long size = pcap_dump_ftell(dump_info->p);
+#endif
 
                if (size == -1)
                        error("ftell fails on output file");
@@ -2523,6 +2609,9 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
                pcap_dump_flush(dump_info->p);
 #endif
 
+       if (dump_info->ndo != NULL)
+               pretty_print_packet(dump_info->ndo, h, sp, packets_captured);
+
        --infodelay;
        if (infoprint)
                info(0);
@@ -2531,16 +2620,23 @@ dump_packet_and_trunc(u_char *user, const struct pcap_pkthdr *h, const u_char *s
 static void
 dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 {
+       struct dump_info *dump_info;
+
        ++packets_captured;
 
        ++infodelay;
 
-       pcap_dump(user, h, sp);
+       dump_info = (struct dump_info *)user;
+
+       pcap_dump((u_char *)dump_info->p, h, sp);
 #ifdef HAVE_PCAP_DUMP_FLUSH
        if (Uflag)
-               pcap_dump_flush((pcap_dumper_t *)user);
+               pcap_dump_flush(dump_info->p);
 #endif
 
+       if (dump_info->ndo != NULL)
+               pretty_print_packet(dump_info->ndo, h, sp, packets_captured);
+
        --infodelay;
        if (infoprint)
                info(0);
@@ -2597,6 +2693,18 @@ RETSIGTYPE requestinfo(int signo _U_)
 }
 #endif
 
+static void
+print_packets_captured (void)
+{
+       static u_int prev_packets_captured, first = 1;
+
+       if (infodelay == 0 && (first || packets_captured != prev_packets_captured)) {
+               fprintf(stderr, "Got %u\r", packets_captured);
+               first = 0;
+               prev_packets_captured = packets_captured;
+       }
+}
+
 /*
  * Called once each second in verbose mode while dumping to file
  */
@@ -2604,14 +2712,12 @@ RETSIGTYPE requestinfo(int signo _U_)
 void CALLBACK verbose_stats_dump (UINT timer_id _U_, UINT msg _U_, DWORD_PTR arg _U_,
                                  DWORD_PTR dw1 _U_, DWORD_PTR dw2 _U_)
 {
-       if (infodelay == 0)
-               fprintf(stderr, "Got %u\r", packets_captured);
+       print_packets_captured();
 }
 #elif defined(HAVE_ALARM)
 static void verbose_stats_dump(int sig _U_)
 {
-       if (infodelay == 0)
-               fprintf(stderr, "Got %u\r", packets_captured);
+       print_packets_captured();
        alarm(1);
 }
 #endif
@@ -2675,14 +2781,17 @@ print_usage(void)
 "\t\t[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]\n");
        (void)fprintf(stderr,
 "\t\t[ -i interface ]" j_FLAG_USAGE " [ -M secret ] [ --number ]\n");
+       (void)fprintf(stderr,
+"\t\t[ --print ]");
 #ifdef HAVE_PCAP_SETDIRECTION
        (void)fprintf(stderr,
-"\t\t[ -Q in|out|inout ]\n");
+" [ -Q in|out|inout ]");
 #endif
        (void)fprintf(stderr,
-"\t\t[ -r file ] [ -s snaplen ] ");
+" [ -r file ] [ -s snaplen ]\n");
 #ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
-       (void)fprintf(stderr, "[ --time-stamp-precision precision ]\n");
+       (void)fprintf(stderr,
+"\t\t[ --time-stamp-precision precision ]\n");
        (void)fprintf(stderr,
 "\t\t");
 #endif