X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=dumpcap.c;h=6d2bcd3d9ef2ed93e6af8f8fa7d4e456ad1ec779;hb=b1fa4c19e643704927d09078780cb3b47815a231;hp=6eb12d717d9760ab3658f0d9cc0744fc6c1aa194;hpb=9be282951b1490764fc226296edb65c37ee1ea05;p=metze%2Fwireshark%2Fwip.git diff --git a/dumpcap.c b/dumpcap.c index 6eb12d717d..6d2bcd3d9e 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -59,9 +59,7 @@ #include #include -#ifdef HAVE_GETOPT_H -#include -#else +#ifndef HAVE_GETOPT #include "wsutil/wsgetopt.h" #endif @@ -81,11 +79,13 @@ #include "version_info.h" #include "capture-pcap-util.h" +#ifdef _WIN32 +#include "capture-wpcap.h" +#endif /* _WIN32 */ #include "pcapio.h" #ifdef _WIN32 -#include #include "capture-wpcap.h" #include #endif @@ -135,10 +135,6 @@ FILE *debug_log; /* for logging debug messages to */ /* is defined */ #endif -#ifdef _WIN32 -#define USE_THREADS -#endif - static GAsyncQueue *pcap_queue; static gint64 pcap_queue_bytes; static gint64 pcap_queue_packets; @@ -219,13 +215,9 @@ typedef enum { INITFILTER_OTHER_ERROR } initfilter_status_t; -typedef struct _pcap_queue_element { - guint interface_id; - struct pcap_pkthdr phdr; - u_char *pd; -} pcap_queue_element; - typedef struct _pcap_options { + guint32 received; + guint32 dropped; pcap_t *pcap_h; #ifdef MUST_DO_SELECT int pcap_fd; /* pcap file descriptor */ @@ -246,9 +238,9 @@ typedef struct _pcap_options { #endif gboolean cap_pipe_modified; /* TRUE if data in the pipe uses modified pcap headers */ gboolean cap_pipe_byte_swapped; /* TRUE if data in the pipe is byte swapped */ -#ifdef USE_THREADS +#if defined(_WIN32) char * cap_pipe_buf; /* Pointer to the data buffer we read into */ -#endif /* USE_THREADS */ +#endif int cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */ int cap_pipe_bytes_read; /* Used by cap_pipe_dispatch */ enum { @@ -258,7 +250,7 @@ typedef struct _pcap_options { STATE_READ_DATA } cap_pipe_state; enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err; -#ifdef USE_THREADS +#if defined(_WIN32) GMutex *cap_pipe_read_mtx; GAsyncQueue *cap_pipe_pending_q, *cap_pipe_done_q; #endif @@ -282,6 +274,12 @@ typedef struct _loop_data { guint32 autostop_files; } loop_data; +typedef struct _pcap_queue_element { + pcap_options *pcap_opts; + struct pcap_pkthdr phdr; + u_char *pd; +} pcap_queue_element; + /* * Standard secondary message for unexpected errors. */ @@ -323,12 +321,11 @@ static gboolean need_timeout_workaround; * WaitForSingleObject. If it's less than 1000 WaitForSingleObject * will return immediately. */ -#ifndef USE_THREADS -#define PIPE_READ_TIMEOUT 250000 -#else +#if defined(_WIN32) #define PIPE_READ_TIMEOUT 100000 +#else +#define PIPE_READ_TIMEOUT 250000 #endif -static const char *cap_pipe_err_str; #define WRITER_THREAD_TIMEOUT 100000 /* usecs */ @@ -341,9 +338,9 @@ static capture_options global_capture_opts; static gboolean quiet = FALSE; static gboolean use_threads = FALSE; -static void capture_loop_write_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, +static void capture_loop_write_packet_cb(u_char *pcap_opts_p, const struct pcap_pkthdr *phdr, const u_char *pd); -static void capture_loop_queue_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, +static void capture_loop_queue_packet_cb(u_char *pcap_opts_p, const struct pcap_pkthdr *phdr, const u_char *pd); static void capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fname, int err, gboolean is_close); @@ -354,7 +351,7 @@ static void report_new_capture_file(const char *filename); static void report_packet_count(int packet_count); static void report_packet_drops(guint32 received, guint32 drops, gchar *name); static void report_capture_error(const char *error_msg, const char *secondary_error_msg); -static void report_cfilter_error(const char *cfilter, const char *errmsg); +static void report_cfilter_error(capture_options *capture_opts, guint i, const char *errmsg); #define MSG_MAX_LENGTH 4096 @@ -367,7 +364,7 @@ print_usage(gboolean print_ver) output = stdout; fprintf(output, "Dumpcap " VERSION "%s\n" - "Capture network packets and dump them into a libpcap file.\n" + "Capture network packets and dump them into a pcapng file.\n" "See http://www.wireshark.org for more information.\n", wireshark_svnversion); } else { @@ -392,11 +389,11 @@ print_usage(gboolean print_ver) #ifdef HAVE_BPF_IMAGE fprintf(output, " -d print generated BPF code for capture filter\n"); #endif - fprintf(output, " -S print statistics for each interface once every second\n"); + fprintf(output, " -S print statistics for each interface once per second\n"); fprintf(output, " -M for -D, -L, and -S, produce machine-readable output\n"); fprintf(output, "\n"); #ifdef HAVE_PCAP_REMOTE - fprintf(output, "\nRPCAP options:\n"); + fprintf(output, "RPCAP options:\n"); fprintf(output, " -r don't ignore own RPCAP traffic in capture\n"); fprintf(output, " -u use UDP for RPCAP data transfer\n"); fprintf(output, " -A : use RPCAP password authentication\n"); @@ -418,16 +415,17 @@ print_usage(gboolean print_ver) fprintf(output, " -b ... duration:NUM - switch to next file after NUM secs\n"); fprintf(output, " filesize:NUM - switch to next file after NUM KB\n"); fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n"); - fprintf(output, " -n use pcapng format instead of pcap\n"); - /*fprintf(output, "\n");*/ + fprintf(output, " -n use pcapng format instead of pcap (default)\n"); + fprintf(output, " -P use libpcap format instead of pcapng\n"); + fprintf(output, "\n"); fprintf(output, "Miscellaneous:\n"); fprintf(output, " -t use a separate thread per interface\n"); fprintf(output, " -q don't report packet capture counts\n"); fprintf(output, " -v print version information and exit\n"); fprintf(output, " -h display this help and exit\n"); fprintf(output, "\n"); - fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n"); - fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcap\"\n"); + fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcapng\n"); + fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcapng\"\n"); fprintf(output, "\n"); fprintf(output, "Use Ctrl-C to stop capturing at any time.\n"); } @@ -539,7 +537,7 @@ relinquish_all_capabilities(void) cap_t caps = cap_init(); /* all capabilities initialized to off */ print_caps("Pre-clear"); if (cap_set_proc(caps)) { - cmdarg_err("cap_set_proc() fail return: %s", strerror(errno)); + cmdarg_err("cap_set_proc() fail return: %s", g_strerror(errno)); } print_caps("Post-clear"); cap_free(caps); @@ -562,6 +560,7 @@ open_capture_device(interface_options *interface_opts, Some versions of libpcap may put warnings into the error buffer if they succeed; to tell if that's happened, we have to clear the error buffer, and check if it's still a null string. */ + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Entering open_capture_device()."); (*open_err_str)[0] = '\0'; #if defined(HAVE_PCAP_OPEN) && defined(HAVE_PCAP_REMOTE) /* @@ -574,12 +573,18 @@ open_capture_device(interface_options *interface_opts, auth.username = interface_opts->auth_username; auth.password = interface_opts->auth_password; + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "Calling pcap_open() using name %s, snaplen %d, promisc_mode %d, datatx_udp %d, nocap_rpcap %d.", + interface_opts->name, interface_opts->snaplen, interface_opts->promisc_mode, + interface_opts->datatx_udp, interface_opts->nocap_rpcap); pcap_h = pcap_open(interface_opts->name, interface_opts->snaplen, /* flags */ (interface_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) | (interface_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) | (interface_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0), CAP_READ_TIMEOUT, &auth, *open_err_str); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "pcap_open() returned %p.", (void *)pcap_h); } else #endif { @@ -589,18 +594,32 @@ open_capture_device(interface_options *interface_opts, * size, otherwise use pcap_open_live(). */ #ifdef HAVE_PCAP_CREATE + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "Calling pcap_create() using %s.", interface_opts->name); pcap_h = pcap_create(interface_opts->name, *open_err_str); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "pcap_create() returned %p.", (void *)pcap_h); if (pcap_h != NULL) { + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "Calling pcap_set_snaplen() with snaplen %d.", interface_opts->snaplen); pcap_set_snaplen(pcap_h, interface_opts->snaplen); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "Calling pcap_set_snaplen() with promisc_mode %d.", interface_opts->promisc_mode); pcap_set_promisc(pcap_h, interface_opts->promisc_mode); pcap_set_timeout(pcap_h, CAP_READ_TIMEOUT); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "buffersize %d.", interface_opts->buffer_size); if (interface_opts->buffer_size > 1) { pcap_set_buffer_size(pcap_h, interface_opts->buffer_size * 1024 * 1024); } + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "monitor_mode %d.", interface_opts->monitor_mode); if (interface_opts->monitor_mode) pcap_set_rfmon(pcap_h, 1); err = pcap_activate(pcap_h); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "pcap_activate() returned %d.", err); if (err < 0) { /* Failed to activate, set to NULL */ if (err == PCAP_ERROR) @@ -612,11 +631,17 @@ open_capture_device(interface_options *interface_opts, } } #else + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "pcap_open_live() calling using name %s, snaplen %d, promisc_mode %d.", + interface_opts->name, interface_opts->snaplen, interface_opts->promisc_mode); pcap_h = pcap_open_live(interface_opts->name, interface_opts->snaplen, interface_opts->promisc_mode, CAP_READ_TIMEOUT, *open_err_str); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "pcap_open_live() returned %p.", (void *)pcap_h); #endif } + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "open_capture_device %s : %s", pcap_h ? "SUCCESS" : "FAILURE", interface_opts->name); return pcap_h; } @@ -655,21 +680,40 @@ get_capture_device_open_failure_messages(const char *open_err_str, libpcap_warn = ""; g_snprintf(errmsg, (gulong) errmsg_len, "The capture session could not be initiated (%s).", open_err_str); -#ifndef _WIN32 +#ifdef _WIN32 + if (!has_wpcap) { + g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, + "\n" + "In order to capture packets, WinPcap must be installed; see\n" + "\n" + " http://www.winpcap.org/\n" + "\n" + "or the mirror at\n" + "\n" + " http://www.mirrors.wiretapped.net/security/packet-capture/winpcap/\n" + "\n" + "or the mirror at\n" + "\n" + " http://winpcap.cs.pu.edu.tw/\n" + "\n" + "for a downloadable version of WinPcap and for instructions on how to install\n" + "WinPcap."); + } else { + g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, + "\n" + "Please check that \"%s\" is the proper interface.\n" + "\n" + "\n" + "Help can be found at:\n" + "\n" + " http://wiki.wireshark.org/WinPcap\n" + " http://wiki.wireshark.org/CaptureSetup\n", + iface); + } +#else g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, "Please check to make sure you have sufficient permissions, and that you have " "the proper interface or pipe specified.%s", libpcap_warn); -#else - g_snprintf(secondary_errmsg, (gulong) secondary_errmsg_len, - "\n" - "Please check that \"%s\" is the proper interface.\n" - "\n" - "\n" - "Help can be found at:\n" - "\n" - " http://wiki.wireshark.org/WinPcap\n" - " http://wiki.wireshark.org/CaptureSetup\n", - iface); #endif /* _WIN32 */ } @@ -714,7 +758,7 @@ set_pcap_linktype(pcap_t *pcap_h, int linktype, static gboolean compile_capture_filter(const char *iface, pcap_t *pcap_h, - struct bpf_program *fcode, char *cfilter) + struct bpf_program *fcode, const char *cfilter) { bpf_u_int32 netnum, netmask; gchar lookup_net_err_str[PCAP_ERRBUF_SIZE]; @@ -733,7 +777,13 @@ compile_capture_filter(const char *iface, pcap_t *pcap_h, "Warning: Couldn't obtain netmask info (%s).", lookup_net_err_str);*/ netmask = 0; } - if (pcap_compile(pcap_h, fcode, cfilter, 1, netmask) < 0) + + /* + * Sigh. Older versions of libpcap don't properly declare the + * third argument to pcap_compile() as a const pointer. Cast + * away the warning. + */ + if (pcap_compile(pcap_h, fcode, (char *)cfilter, 1, netmask) < 0) return FALSE; return TRUE; } @@ -780,7 +830,7 @@ show_filter_code(capture_options *capture_opts) if (!compile_capture_filter(interface_opts.name, pcap_h, &fcode, interface_opts.cfilter)) { pcap_close(pcap_h); - report_cfilter_error(interface_opts.cfilter, errmsg); + report_cfilter_error(capture_opts, j, errmsg); return FALSE; } pcap_close(pcap_h); @@ -1252,6 +1302,7 @@ print_statistics_loop(gboolean machine_readable) if (if_list == NULL) { switch (err) { case CANT_GET_INTERFACE_LIST: + case DONT_HAVE_PCAP: cmdarg_err("%s", err_str); g_free(err_str); break; @@ -1381,17 +1432,13 @@ capture_cleanup_handler(int signum _U_) static void -report_capture_count(void) +report_capture_count(gboolean reportit) { /* Don't print this if we're a capture child. */ - if (!capture_child) { - if (quiet) { - /* Report the count only if we aren't printing a packet count - as packets arrive. */ - fprintf(stderr, "Packets captured: %u\n", global_ld.packet_count); - /* stderr could be line buffered */ - fflush(stderr); - } + if (!capture_child && reportit) { + fprintf(stderr, "\rPackets captured: %u\n", global_ld.packet_count); + /* stderr could be line buffered */ + fflush(stderr); } } @@ -1400,7 +1447,7 @@ report_capture_count(void) static void report_counts_for_siginfo(void) { - report_capture_count(); + report_capture_count(quiet); infoprint = FALSE; /* we just reported it */ } @@ -1465,14 +1512,14 @@ relinquish_privs_except_capture(void) print_caps("Pre drop, pre set"); if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { - cmdarg_err("prctl() fail return: %s", strerror(errno)); + cmdarg_err("prctl() fail return: %s", g_strerror(errno)); } cap_set_flag(caps, CAP_PERMITTED, cl_len, cap_list, CAP_SET); cap_set_flag(caps, CAP_INHERITABLE, cl_len, cap_list, CAP_SET); if (cap_set_proc(caps)) { - cmdarg_err("cap_set_proc() fail return: %s", strerror(errno)); + cmdarg_err("cap_set_proc() fail return: %s", g_strerror(errno)); } print_caps("Pre drop, post set"); @@ -1481,7 +1528,7 @@ relinquish_privs_except_capture(void) print_caps("Post drop, pre set"); cap_set_flag(caps, CAP_EFFECTIVE, cl_len, cap_list, CAP_SET); if (cap_set_proc(caps)) { - cmdarg_err("cap_set_proc() fail return: %s", strerror(errno)); + cmdarg_err("cap_set_proc() fail return: %s", g_strerror(errno)); } print_caps("Post drop, post set"); @@ -1522,7 +1569,7 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr } } -#ifdef USE_THREADS +#if defined(_WIN32) /* * Thread function that reads from a pipe and pushes the data * to the main application thread. @@ -1541,7 +1588,7 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr */ static void *cap_pipe_read(void *arg) { - pcap_options *pcap_opts = (pcap_options *)arg; + pcap_options *pcap_opts; int bytes_read; #ifdef _WIN32 BOOL res; @@ -1550,6 +1597,7 @@ static void *cap_pipe_read(void *arg) int b; #endif /* _WIN32 */ + pcap_opts = (pcap_options *)arg; while (pcap_opts->cap_pipe_err == PIPOK) { g_async_queue_pop(pcap_opts->cap_pipe_pending_q); /* Wait for our cue (ahem) from the main thread */ g_mutex_lock(pcap_opts->cap_pipe_read_mtx); @@ -1607,22 +1655,19 @@ static void *cap_pipe_read(void *arg) } return NULL; } -#endif /* USE_THREADS */ +#endif +#if !defined(_WIN32) || defined(MUST_DO_SELECT) /* Provide select() functionality for a single file descriptor * on UNIX/POSIX. Windows uses cap_pipe_read via a thread. * - * Returns the same values as select. If an error is returned, - * the string cap_pipe_err_str should be used instead of errno. + * Returns the same values as select. */ static int cap_pipe_select(int pipe_fd) { fd_set rfds; struct timeval timeout; - int sel_ret; - - cap_pipe_err_str = "Unknown error"; FD_ZERO(&rfds); FD_SET(pipe_fd, &rfds); @@ -1630,11 +1675,9 @@ cap_pipe_select(int pipe_fd) timeout.tv_sec = PIPE_READ_TIMEOUT / 1000000; timeout.tv_usec = PIPE_READ_TIMEOUT % 1000000; - sel_ret = select(pipe_fd+1, &rfds, NULL, NULL, &timeout); - if (sel_ret < 0) - cap_pipe_err_str = strerror(errno); - return sel_ret; + return select(pipe_fd+1, &rfds, NULL, NULL, &timeout); } +#endif /* Mimic pcap_open_live() for pipe captures @@ -1661,7 +1704,7 @@ cap_pipe_open_live(char *pipename, wchar_t *err_str; #endif #endif -#ifndef USE_THREADS +#ifndef _WIN32 int sel_ret; unsigned int bytes_read; #endif @@ -1692,7 +1735,7 @@ cap_pipe_open_live(char *pipename, else { g_snprintf(errmsg, errmsgl, "The capture session could not be initiated " - "due to error getting information on pipe/socket: %s", strerror(errno)); + "due to error getting information on pipe/socket: %s", g_strerror(errno)); pcap_opts->cap_pipe_err = PIPERR; } return; @@ -1702,7 +1745,7 @@ cap_pipe_open_live(char *pipename, if (fd == -1) { g_snprintf(errmsg, errmsgl, "The capture session could not be initiated " - "due to error on pipe open: %s", strerror(errno)); + "due to error on pipe open: %s", g_strerror(errno)); pcap_opts->cap_pipe_err = PIPERR; return; } @@ -1711,7 +1754,7 @@ cap_pipe_open_live(char *pipename, if (fd == -1) { g_snprintf(errmsg, errmsgl, "The capture session could not be initiated " - "due to error on socket create: %s", strerror(errno)); + "due to error on socket create: %s", g_strerror(errno)); pcap_opts->cap_pipe_err = PIPERR; return; } @@ -1751,7 +1794,7 @@ cap_pipe_open_live(char *pipename, if (b == -1) { g_snprintf(errmsg, errmsgl, "The capture session coud not be initiated " - "due to error on socket connect: %s", strerror(errno)); + "due to error on socket connect: %s", g_strerror(errno)); pcap_opts->cap_pipe_err = PIPERR; return; } @@ -1830,14 +1873,14 @@ cap_pipe_open_live(char *pipename, pcap_opts->from_cap_pipe = TRUE; -#ifndef USE_THREADS +#ifndef _WIN32 /* read the pcap header */ bytes_read = 0; while (bytes_read < sizeof magic) { sel_ret = cap_pipe_select(fd); if (sel_ret < 0) { g_snprintf(errmsg, errmsgl, - "Unexpected error from select: %s", strerror(errno)); + "Unexpected error from select: %s", g_strerror(errno)); goto error; } else if (sel_ret > 0) { b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read); @@ -1846,13 +1889,13 @@ cap_pipe_open_live(char *pipename, g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open"); else g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s", - strerror(errno)); + g_strerror(errno)); goto error; } bytes_read += b; } } -#else /* USE_THREADS */ +#else g_thread_create(&cap_pipe_read, pcap_opts, FALSE, NULL); pcap_opts->cap_pipe_buf = (char *) &magic; @@ -1866,11 +1909,11 @@ cap_pipe_open_live(char *pipename, g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open"); else g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s", - strerror(errno)); + g_strerror(errno)); goto error; } -#endif /* USE_THREADS */ +#endif switch (magic) { case PCAP_MAGIC: @@ -1905,14 +1948,14 @@ cap_pipe_open_live(char *pipename, goto error; } -#ifndef USE_THREADS +#ifndef _WIN32 /* Read the rest of the header */ bytes_read = 0; while (bytes_read < sizeof(struct pcap_hdr)) { sel_ret = cap_pipe_select(fd); if (sel_ret < 0) { g_snprintf(errmsg, errmsgl, - "Unexpected error from select: %s", strerror(errno)); + "Unexpected error from select: %s", g_strerror(errno)); goto error; } else if (sel_ret > 0) { b = read(fd, ((char *)hdr)+bytes_read, @@ -1922,13 +1965,13 @@ cap_pipe_open_live(char *pipename, g_snprintf(errmsg, errmsgl, "End of file on pipe header during open"); else g_snprintf(errmsg, errmsgl, "Error on pipe header during open: %s", - strerror(errno)); + g_strerror(errno)); goto error; } bytes_read += b; } } -#else /* USE_THREADS */ +#else pcap_opts->cap_pipe_buf = (char *) hdr; pcap_opts->cap_pipe_bytes_read = 0; pcap_opts->cap_pipe_bytes_to_read = sizeof(struct pcap_hdr); @@ -1939,10 +1982,10 @@ cap_pipe_open_live(char *pipename, g_snprintf(errmsg, errmsgl, "End of file on pipe header during open"); else g_snprintf(errmsg, errmsgl, "Error on pipe header header during open: %s", - strerror(errno)); + g_strerror(errno)); goto error; } -#endif /* USE_THREADS */ +#endif if (pcap_opts->cap_pipe_byte_swapped) { /* Byte-swap the header fields about which we care. */ @@ -1985,7 +2028,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er struct pcap_pkthdr phdr; enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR, PD_ERR } result; -#ifdef USE_THREADS +#ifdef _WIN32 GTimeVal wait_time; gpointer q_status; #else @@ -2002,7 +2045,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er switch (pcap_opts->cap_pipe_state) { case STATE_EXPECT_REC_HDR: -#ifdef USE_THREADS +#ifdef _WIN32 if (g_mutex_trylock(pcap_opts->cap_pipe_read_mtx)) { #endif @@ -2011,7 +2054,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr); pcap_opts->cap_pipe_bytes_read = 0; -#ifdef USE_THREADS +#ifdef _WIN32 pcap_opts->cap_pipe_buf = (char *) &pcap_opts->cap_pipe_rechdr; g_async_queue_push(pcap_opts->cap_pipe_pending_q, pcap_opts->cap_pipe_buf); g_mutex_unlock(pcap_opts->cap_pipe_read_mtx); @@ -2020,7 +2063,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er /* Fall through */ case STATE_READ_REC_HDR: -#ifndef USE_THREADS +#ifndef _WIN32 b = read(pcap_opts->cap_pipe_fd, ((char *)&pcap_opts->cap_pipe_rechdr)+pcap_opts->cap_pipe_bytes_read, pcap_opts->cap_pipe_bytes_to_read - pcap_opts->cap_pipe_bytes_read); if (b <= 0) { @@ -2031,7 +2074,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er break; } pcap_opts->cap_pipe_bytes_read += b; -#else /* USE_THREADS */ +#else g_get_current_time(&wait_time); g_time_val_add(&wait_time, PIPE_READ_TIMEOUT); q_status = g_async_queue_timed_pop(pcap_opts->cap_pipe_done_q, &wait_time); @@ -2045,14 +2088,14 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er if (!q_status) { return 0; } -#endif /* USE_THREADS */ +#endif if ((pcap_opts->cap_pipe_bytes_read) < pcap_opts->cap_pipe_bytes_to_read) return 0; result = PD_REC_HDR_READ; break; case STATE_EXPECT_DATA: -#ifdef USE_THREADS +#ifdef _WIN32 if (g_mutex_trylock(pcap_opts->cap_pipe_read_mtx)) { #endif @@ -2060,7 +2103,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er pcap_opts->cap_pipe_bytes_to_read = pcap_opts->cap_pipe_rechdr.hdr.incl_len; pcap_opts->cap_pipe_bytes_read = 0; -#ifdef USE_THREADS +#ifdef _WIN32 pcap_opts->cap_pipe_buf = (char *) data; g_async_queue_push(pcap_opts->cap_pipe_pending_q, pcap_opts->cap_pipe_buf); g_mutex_unlock(pcap_opts->cap_pipe_read_mtx); @@ -2069,7 +2112,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er /* Fall through */ case STATE_READ_DATA: -#ifndef USE_THREADS +#ifndef _WIN32 b = read(pcap_opts->cap_pipe_fd, data+pcap_opts->cap_pipe_bytes_read, pcap_opts->cap_pipe_bytes_to_read - pcap_opts->cap_pipe_bytes_read); if (b <= 0) { @@ -2080,7 +2123,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er break; } pcap_opts->cap_pipe_bytes_read += b; -#else /* USE_THREADS */ +#else g_get_current_time(&wait_time); g_time_val_add(&wait_time, PIPE_READ_TIMEOUT); q_status = g_async_queue_timed_pop(pcap_opts->cap_pipe_done_q, &wait_time); @@ -2094,7 +2137,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er if (!q_status) { return 0; } -#endif /* USE_THREADS */ +#endif if ((pcap_opts->cap_pipe_bytes_read) < pcap_opts->cap_pipe_bytes_to_read) return 0; result = PD_DATA_READ; @@ -2120,8 +2163,12 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er ld->packet_count+1, pcap_opts->cap_pipe_rechdr.hdr.incl_len); break; } - pcap_opts->cap_pipe_state = STATE_EXPECT_DATA; - return 0; + + if (pcap_opts->cap_pipe_rechdr.hdr.incl_len) { + pcap_opts->cap_pipe_state = STATE_EXPECT_DATA; + return 0; + } + /* no data to read? fall through */ case PD_DATA_READ: /* Fill in a "struct pcap_pkthdr", and process the packet. */ @@ -2131,9 +2178,9 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er phdr.len = pcap_opts->cap_pipe_rechdr.hdr.orig_len; if (use_threads) { - capture_loop_queue_packet_cb((u_char *)&pcap_opts->interface_id, &phdr, data); + capture_loop_queue_packet_cb((u_char *)pcap_opts, &phdr, data); } else { - capture_loop_write_packet_cb((u_char *)&pcap_opts->interface_id, &phdr, data); + capture_loop_write_packet_cb((u_char *)pcap_opts, &phdr, data); } pcap_opts->cap_pipe_state = STATE_EXPECT_REC_HDR; return 1; @@ -2152,7 +2199,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er LocalFree(err_str); #else g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s", - strerror(errno)); + g_strerror(errno)); #endif /* Fall through */ case PD_ERR: @@ -2175,7 +2222,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, gchar open_err_str[PCAP_ERRBUF_SIZE]; gchar *sync_msg_str; interface_options interface_opts; - pcap_options pcap_opts; + pcap_options *pcap_opts; guint i; #ifdef _WIN32 int err; @@ -2234,53 +2281,67 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, if ((use_threads == FALSE) && (capture_opts->ifaces->len > 1)) { g_snprintf(errmsg, (gulong) errmsg_len, - "Using threads is required for capturing on mulitple interfaces! Use the -t option."); + "Using threads is required for capturing on mulitple interfaces!"); return FALSE; } for (i = 0; i < capture_opts->ifaces->len; i++) { interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); - pcap_opts.pcap_h = NULL; + pcap_opts = (pcap_options *)g_malloc(sizeof (pcap_options)); + if (pcap_opts == NULL) { + g_snprintf(errmsg, (gulong) errmsg_len, + "Could not allocate memory."); + return FALSE; + } + pcap_opts->received = 0; + pcap_opts->dropped = 0; + pcap_opts->pcap_h = NULL; #ifdef MUST_DO_SELECT - pcap_opts.pcap_fd = -1; -#endif - pcap_opts.pcap_err = FALSE; - pcap_opts.interface_id = i; - pcap_opts.tid = NULL; - pcap_opts.snaplen = 0; - pcap_opts.linktype = -1; - pcap_opts.from_cap_pipe = FALSE; - memset(&pcap_opts.cap_pipe_hdr, 0, sizeof(struct pcap_hdr)); - memset(&pcap_opts.cap_pipe_rechdr, 0, sizeof(struct pcaprec_modified_hdr)); + pcap_opts->pcap_fd = -1; +#endif + pcap_opts->pcap_err = FALSE; + pcap_opts->interface_id = i; + pcap_opts->tid = NULL; + pcap_opts->snaplen = 0; + pcap_opts->linktype = -1; + pcap_opts->from_cap_pipe = FALSE; + memset(&pcap_opts->cap_pipe_hdr, 0, sizeof(struct pcap_hdr)); + memset(&pcap_opts->cap_pipe_rechdr, 0, sizeof(struct pcaprec_modified_hdr)); +#ifdef _WIN32 + pcap_opts->cap_pipe_h = INVALID_HANDLE_VALUE; +#else + pcap_opts->cap_pipe_fd = -1; +#endif + pcap_opts->cap_pipe_modified = FALSE; + pcap_opts->cap_pipe_byte_swapped = FALSE; +#ifdef _WIN32 + pcap_opts->cap_pipe_buf = NULL; +#endif + pcap_opts->cap_pipe_bytes_to_read = 0; + pcap_opts->cap_pipe_bytes_read = 0; + pcap_opts->cap_pipe_state = 0; + pcap_opts->cap_pipe_err = PIPOK; #ifdef _WIN32 - pcap_opts.cap_pipe_h = INVALID_HANDLE_VALUE; +#if GLIB_CHECK_VERSION(2,31,0) + pcap_opts->cap_pipe_read_mtx = g_malloc(sizeof(GMutex)); + g_mutex_init(pcap_opts->cap_pipe_read_mtx); #else - pcap_opts.cap_pipe_fd = -1; -#endif - pcap_opts.cap_pipe_modified = FALSE; - pcap_opts.cap_pipe_byte_swapped = FALSE; -#ifdef USE_THREADS - pcap_opts.cap_pipe_buf = NULL; -#endif /* USE_THREADS */ - pcap_opts.cap_pipe_bytes_to_read = 0; - pcap_opts.cap_pipe_bytes_read = 0; - pcap_opts.cap_pipe_state = 0; - pcap_opts.cap_pipe_err = PIPOK; -#ifdef USE_THREADS - pcap_opts.cap_pipe_read_mtx = g_mutex_new(); - pcap_opts.cap_pipe_pending_q = g_async_queue_new(); - pcap_opts.cap_pipe_done_q = g_async_queue_new(); + pcap_opts->cap_pipe_read_mtx = g_mutex_new(); #endif + pcap_opts->cap_pipe_pending_q = g_async_queue_new(); + pcap_opts->cap_pipe_done_q = g_async_queue_new(); +#endif + g_array_append_val(ld->pcaps, pcap_opts); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", interface_opts.name); - pcap_opts.pcap_h = open_capture_device(&interface_opts, &open_err_str); + pcap_opts->pcap_h = open_capture_device(&interface_opts, &open_err_str); - if (pcap_opts.pcap_h != NULL) { + if (pcap_opts->pcap_h != NULL) { /* we've opened "iface" as a network device */ #ifdef _WIN32 /* try to set the capture buffer size */ if (interface_opts.buffer_size > 1 && - pcap_setbuff(pcap_opts.pcap_h, interface_opts.buffer_size * 1024 * 1024) != 0) { + pcap_setbuff(pcap_opts->pcap_h, interface_opts.buffer_size * 1024 * 1024) != 0) { sync_secondary_msg_str = g_strdup_printf( "The capture buffer size of %dMB seems to be too high for your machine,\n" "the default of 1MB will be used.\n" @@ -2297,7 +2358,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, if (interface_opts.sampling_method != CAPTURE_SAMP_NONE) { struct pcap_samp *samp; - if ((samp = pcap_setsampling(pcap_opts.pcap_h)) != NULL) { + if ((samp = pcap_setsampling(pcap_opts->pcap_h)) != NULL) { switch (interface_opts.sampling_method) { case CAPTURE_SAMP_BY_COUNT: samp->method = PCAP_SAMP_1_EVERY_N; @@ -2321,29 +2382,27 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, report_capture_error("Couldn't set the capture sampling", "Cannot get packet sampling data structure"); } - } #endif /* setting the data link type only works on real interfaces */ - if (!set_pcap_linktype(pcap_opts.pcap_h, interface_opts.linktype, interface_opts.name, + if (!set_pcap_linktype(pcap_opts->pcap_h, interface_opts.linktype, interface_opts.name, errmsg, errmsg_len, secondary_errmsg, secondary_errmsg_len)) { - g_array_append_val(ld->pcaps, pcap_opts); return FALSE; } - pcap_opts.linktype = get_pcap_linktype(pcap_opts.pcap_h, interface_opts.name); + pcap_opts->linktype = get_pcap_linktype(pcap_opts->pcap_h, interface_opts.name); } else { /* We couldn't open "iface" as a network device. */ /* Try to open it as a pipe */ - cap_pipe_open_live(interface_opts.name, &pcap_opts, &pcap_opts.cap_pipe_hdr, errmsg, (int) errmsg_len); + cap_pipe_open_live(interface_opts.name, pcap_opts, &pcap_opts->cap_pipe_hdr, errmsg, (int) errmsg_len); #ifndef _WIN32 - if (pcap_opts.cap_pipe_fd == -1) { + if (pcap_opts->cap_pipe_fd == -1) { #else - if (pcap_opts.cap_pipe_h == INVALID_HANDLE_VALUE) { + if (pcap_opts->cap_pipe_h == INVALID_HANDLE_VALUE) { #endif - if (pcap_opts.cap_pipe_err == PIPNEXIST) { + if (pcap_opts->cap_pipe_err == PIPNEXIST) { /* Pipe doesn't exist, so output message for interface */ get_capture_device_open_failure_messages(open_err_str, interface_opts.name, @@ -2356,7 +2415,6 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, * Else pipe (or file) does exist and cap_pipe_open_live() has * filled in errmsg */ - g_array_append_val(ld->pcaps, pcap_opts); return FALSE; } else { /* cap_pipe_open_live() succeeded; don't want @@ -2367,11 +2425,11 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, /* XXX - will this work for tshark? */ #ifdef MUST_DO_SELECT - if (!pcap_opts.from_cap_pipe) { + if (!pcap_opts->from_cap_pipe) { #ifdef HAVE_PCAP_GET_SELECTABLE_FD - pcap_opts.pcap_fd = pcap_get_selectable_fd(pcap_opts.pcap_h); + pcap_opts->pcap_fd = pcap_get_selectable_fd(pcap_opts->pcap_h); #else - pcap_opts.pcap_fd = pcap_fileno(pcap_opts.pcap_h); + pcap_opts->pcap_fd = pcap_fileno(pcap_opts->pcap_h); #endif } #endif @@ -2385,7 +2443,6 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, } capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i); g_array_insert_val(capture_opts->ifaces, i, interface_opts); - g_array_append_val(ld->pcaps, pcap_opts); } /* If not using libcap: we now can now set euid/egid to ruid/rgid */ @@ -2405,30 +2462,30 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, static void capture_loop_close_input(loop_data *ld) { guint i; - pcap_options pcap_opts; + pcap_options *pcap_opts; g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input"); for (i = 0; i < ld->pcaps->len; i++) { - pcap_opts = g_array_index(ld->pcaps, pcap_options, i); + pcap_opts = g_array_index(ld->pcaps, pcap_options *, i); /* if open, close the capture pipe "input file" */ #ifndef _WIN32 - if (pcap_opts.cap_pipe_fd >= 0) { - g_assert(pcap_opts.from_cap_pipe); - ws_close(pcap_opts.cap_pipe_fd); - pcap_opts.cap_pipe_fd = -1; + if (pcap_opts->cap_pipe_fd >= 0) { + g_assert(pcap_opts->from_cap_pipe); + ws_close(pcap_opts->cap_pipe_fd); + pcap_opts->cap_pipe_fd = -1; } #else - if (pcap_opts.cap_pipe_h != INVALID_HANDLE_VALUE) { - CloseHandle(pcap_opts.cap_pipe_h); - pcap_opts.cap_pipe_h = INVALID_HANDLE_VALUE; + if (pcap_opts->cap_pipe_h != INVALID_HANDLE_VALUE) { + CloseHandle(pcap_opts->cap_pipe_h); + pcap_opts->cap_pipe_h = INVALID_HANDLE_VALUE; } #endif /* if open, close the pcap "input file" */ - if (pcap_opts.pcap_h != NULL) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input: closing %p", pcap_opts.pcap_h); - pcap_close(pcap_opts.pcap_h); - pcap_opts.pcap_h = NULL; + if (pcap_opts->pcap_h != NULL) { + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input: closing %p", (void *)pcap_opts->pcap_h); + pcap_close(pcap_opts->pcap_h); + pcap_opts->pcap_h = NULL; } } @@ -2444,7 +2501,7 @@ static void capture_loop_close_input(loop_data *ld) /* init the capture filter */ static initfilter_status_t capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, - gchar * name, gchar * cfilter) + const gchar * name, const gchar * cfilter) { struct bpf_program fcode; @@ -2480,7 +2537,7 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err { int err; guint i; - pcap_options pcap_opts; + pcap_options *pcap_opts; interface_options interface_opts; gboolean successful; @@ -2502,34 +2559,47 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err if (ld->pdh) { if (capture_opts->use_pcapng) { char appname[100]; + GString *os_info_str; + + os_info_str = g_string_new(""); + get_os_version_info(os_info_str); g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_svnversion); - successful = libpcap_write_session_header_block(ld->pdh, appname, &ld->bytes_written, &err); + successful = libpcap_write_session_header_block(ld->pdh, + NULL, /* Comment*/ + NULL, /* HW*/ + os_info_str->str, /* OS*/ + appname, + -1, /* section_length */ + &ld->bytes_written, + &err); + + g_string_free(os_info_str, TRUE); + for (i = 0; successful && (i < capture_opts->ifaces->len); i++) { interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); - pcap_opts = g_array_index(ld->pcaps, pcap_options, i); - if (pcap_opts.from_cap_pipe) { - pcap_opts.snaplen = pcap_opts.cap_pipe_hdr.snaplen; + pcap_opts = g_array_index(ld->pcaps, pcap_options *, i); + if (pcap_opts->from_cap_pipe) { + pcap_opts->snaplen = pcap_opts->cap_pipe_hdr.snaplen; } else { - pcap_opts.snaplen = pcap_snapshot(pcap_opts.pcap_h); + pcap_opts->snaplen = pcap_snapshot(pcap_opts->pcap_h); } successful = libpcap_write_interface_description_block(ld->pdh, interface_opts.name, - interface_opts.cfilter, - pcap_opts.linktype, - pcap_opts.snaplen, + interface_opts.cfilter?interface_opts.cfilter:"", + pcap_opts->linktype, + pcap_opts->snaplen, &ld->bytes_written, &err); } } else { - interface_opts = g_array_index(capture_opts->ifaces, interface_options, 0); - pcap_opts = g_array_index(ld->pcaps, pcap_options, 0); - if (pcap_opts.from_cap_pipe) { - pcap_opts.snaplen = pcap_opts.cap_pipe_hdr.snaplen; + pcap_opts = g_array_index(ld->pcaps, pcap_options *, 0); + if (pcap_opts->from_cap_pipe) { + pcap_opts->snaplen = pcap_opts->cap_pipe_hdr.snaplen; } else { - pcap_opts.snaplen = pcap_snapshot(pcap_opts.pcap_h); + pcap_opts->snaplen = pcap_snapshot(pcap_opts->pcap_h); } - successful = libpcap_write_file_header(ld->pdh, pcap_opts.linktype, pcap_opts.snaplen, + successful = libpcap_write_file_header(ld->pdh, pcap_opts->linktype, pcap_opts->snaplen, &ld->bytes_written, &err); } if (!successful) { @@ -2553,7 +2623,7 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err g_snprintf(errmsg, errmsg_len, "The file to which the capture would be" " saved (\"%s\") could not be opened: %s.", - capture_opts->save_file, strerror(err)); + capture_opts->save_file, g_strerror(err)); } break; } @@ -2569,7 +2639,7 @@ capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err { unsigned int i; - pcap_options pcap_opts; + pcap_options *pcap_opts; g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_output"); @@ -2578,9 +2648,9 @@ capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err } else { if (capture_opts->use_pcapng) { for (i = 0; i < global_ld.pcaps->len; i++) { - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); - if (!pcap_opts.from_cap_pipe) { - libpcap_write_interface_statistics_block(ld->pdh, i, pcap_opts.pcap_h, &ld->bytes_written, err_close); + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); + if (!pcap_opts->from_cap_pipe) { + libpcap_write_interface_statistics_block(ld->pdh, i, pcap_opts->pcap_h, &ld->bytes_written, err_close); } } } @@ -2606,7 +2676,7 @@ capture_loop_dispatch(loop_data *ld, int inpkts; gint packet_count_before; guchar pcap_data[WTAP_MAX_PACKET_SIZE]; -#ifndef USE_THREADS +#ifndef _WIN32 int sel_ret; #endif @@ -2616,12 +2686,12 @@ capture_loop_dispatch(loop_data *ld, #ifdef LOG_CAPTURE_VERBOSE g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe"); #endif -#ifndef USE_THREADS +#ifndef _WIN32 sel_ret = cap_pipe_select(pcap_opts->cap_pipe_fd); if (sel_ret <= 0) { if (sel_ret < 0 && errno != EINTR) { g_snprintf(errmsg, errmsg_len, - "Unexpected error from select: %s", strerror(errno)); + "Unexpected error from select: %s", g_strerror(errno)); report_capture_error(errmsg, please_report); ld->go = FALSE; } @@ -2629,12 +2699,12 @@ capture_loop_dispatch(loop_data *ld, /* * "select()" says we can read from the pipe without blocking */ -#endif /* USE_THREADS */ +#endif inpkts = cap_pipe_dispatch(ld, pcap_opts, pcap_data, errmsg, errmsg_len); if (inpkts < 0) { ld->go = FALSE; } -#ifndef USE_THREADS +#ifndef _WIN32 } #endif } @@ -2671,11 +2741,9 @@ capture_loop_dispatch(loop_data *ld, * in a batch before quitting. */ if (use_threads) { - inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_queue_packet_cb, - (u_char *)&(pcap_opts->interface_id)); + inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_queue_packet_cb, (u_char *)pcap_opts); } else { - inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_write_packet_cb, - (u_char *)&(pcap_opts->interface_id)); + inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_write_packet_cb, (u_char *)pcap_opts); } if (inpkts < 0) { if (inpkts == -1) { @@ -2687,7 +2755,7 @@ capture_loop_dispatch(loop_data *ld, } else { if (sel_ret < 0 && errno != EINTR) { g_snprintf(errmsg, errmsg_len, - "Unexpected error from select: %s", strerror(errno)); + "Unexpected error from select: %s", g_strerror(errno)); report_capture_error(errmsg, please_report); ld->go = FALSE; } @@ -2709,15 +2777,15 @@ capture_loop_dispatch(loop_data *ld, * at a time, so that we can check the pipe after every packet. */ if (use_threads) { - inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_queue_packet_cb, (u_char *)&pcap_opts->interface_id); + inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_queue_packet_cb, (u_char *)pcap_opts); } else { - inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_write_packet_cb, (u_char *)&pcap_opts->interface_id); + inpkts = pcap_dispatch(pcap_opts->pcap_h, 1, capture_loop_write_packet_cb, (u_char *)pcap_opts); } #else if (use_threads) { - inpkts = pcap_dispatch(pcap_opts->pcap_h, -1, capture_loop_queue_packet_cb, (u_char *)&pcap_opts->interface_id); + inpkts = pcap_dispatch(pcap_opts->pcap_h, -1, capture_loop_queue_packet_cb, (u_char *)pcap_opts); } else { - inpkts = pcap_dispatch(pcap_opts->pcap_h, -1, capture_loop_write_packet_cb, (u_char *)&pcap_opts->interface_id); + inpkts = pcap_dispatch(pcap_opts->pcap_h, -1, capture_loop_write_packet_cb, (u_char *)pcap_opts); } #endif if (inpkts < 0) { @@ -2752,9 +2820,9 @@ capture_loop_dispatch(loop_data *ld, while(ld->go && (in = pcap_next_ex(pcap_opts->pcap_h, &pkt_header, &pkt_data)) == 1) { if (use_threads) { - capture_loop_queue_packet_cb((u_char *)&pcap_opts->interface_id, pkt_header, pkt_data); + capture_loop_queue_packet_cb((u_char *)pcap_opts, pkt_header, pkt_data); } else { - capture_loop_write_packet_cb((u_char *)&pcap_opts->interface_id, pkt_header, pkt_data); + capture_loop_write_packet_cb((u_char *)pcap_opts, pkt_header, pkt_data); } } @@ -2859,15 +2927,21 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, is_tempfile = FALSE; } else { /* Choose a random name for the temporary capture buffer */ + if (global_capture_opts.ifaces->len > 1) { + prefix = g_strdup_printf("wireshark_%d_interfaces", global_capture_opts.ifaces->len); + } else { + gchar *basename; #ifdef _WIN32 - GString *iface; - - iface = isolate_uuid(g_array_index(global_capture_opts.ifaces, interface_options, global_capture_opts.ifaces->len - 1).name); - prefix = g_strconcat("wireshark_", g_basename(iface->str), NULL); - g_string_free(iface, TRUE); + GString *iface; + iface = isolate_uuid(g_array_index(global_capture_opts.ifaces, interface_options, 0).name); + basename = g_path_get_basename(iface->str); + g_string_free(iface, TRUE); #else - prefix = g_strconcat("wireshark_", g_basename(g_array_index(global_capture_opts.ifaces, interface_options, global_capture_opts.ifaces->len - 1).name), NULL); + basename = g_path_get_basename(g_array_index(global_capture_opts.ifaces, interface_options, 0).name); #endif + prefix = g_strconcat("wireshark_", basename, NULL); + g_free(basename); + } *save_file_fd = create_tempfile(&tmpname, prefix); g_free(prefix); capfile_name = g_strdup(tmpname); @@ -2879,7 +2953,7 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, if (is_tempfile) { g_snprintf(errmsg, errmsg_len, "The temporary file to which the capture would be saved (\"%s\") " - "could not be opened: %s.", capfile_name, strerror(errno)); + "could not be opened: %s.", capfile_name, g_strerror(errno)); } else { if (capture_opts->multi_files_on) { ringbuf_error_cleanup(); @@ -2888,7 +2962,7 @@ capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, g_snprintf(errmsg, errmsg_len, "The file to which the capture would be saved (\"%s\") " "could not be opened: %s.", capfile_name, - strerror(errno)); + g_strerror(errno)); } g_free(capfile_name); return FALSE; @@ -2914,7 +2988,7 @@ do_file_switch_or_stop(capture_options *capture_opts, condition *cnd_file_duration) { guint i; - pcap_options pcap_opts; + pcap_options *pcap_opts; interface_options interface_opts; gboolean successful; @@ -2934,24 +3008,37 @@ do_file_switch_or_stop(capture_options *capture_opts, global_ld.bytes_written = 0; if (capture_opts->use_pcapng) { char appname[100]; + GString *os_info_str; + + os_info_str = g_string_new(""); + get_os_version_info(os_info_str); g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_svnversion); - successful = libpcap_write_session_header_block(global_ld.pdh, appname, &(global_ld.bytes_written), &global_ld.err); + successful = libpcap_write_session_header_block(global_ld.pdh, + NULL, /* Comment */ + NULL, /* HW */ + os_info_str->str, /* OS */ + appname, + -1, /* section_length */ + &(global_ld.bytes_written), + &global_ld.err); + + g_string_free(os_info_str, TRUE); + for (i = 0; successful && (i < capture_opts->ifaces->len); i++) { interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); successful = libpcap_write_interface_description_block(global_ld.pdh, interface_opts.name, - interface_opts.cfilter, - pcap_opts.linktype, - pcap_opts.snaplen, + interface_opts.cfilter?interface_opts.cfilter:"", + pcap_opts->linktype, + pcap_opts->snaplen, &(global_ld.bytes_written), &global_ld.err); } } else { - interface_opts = g_array_index(capture_opts->ifaces, interface_options, 0); - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, 0); - successful = libpcap_write_file_header(global_ld.pdh, pcap_opts.linktype, pcap_opts.snaplen, + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, 0); + successful = libpcap_write_file_header(global_ld.pdh, pcap_opts->linktype, pcap_opts->snaplen, &global_ld.bytes_written, &global_ld.err); } if (!successful) { @@ -2985,23 +3072,20 @@ do_file_switch_or_stop(capture_options *capture_opts, static void * pcap_read_handler(void* arg) { - pcap_options pcap_opts; - guint interface_id; + pcap_options *pcap_opts; char errmsg[MSG_MAX_LENGTH+1]; - interface_id = *(guint *)arg; - g_free(arg); - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, interface_id); + pcap_opts = (pcap_options *)arg; g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Started thread for interface %d.", - interface_id); + pcap_opts->interface_id); while (global_ld.go) { /* dispatch incoming packets */ - capture_loop_dispatch(&global_ld, errmsg, sizeof(errmsg), &pcap_opts); + capture_loop_dispatch(&global_ld, errmsg, sizeof(errmsg), pcap_opts); } g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Stopped thread for interface %d.", - interface_id); + pcap_opts->interface_id); g_thread_exit(NULL); return (NULL); } @@ -3012,7 +3096,7 @@ static gboolean capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats) { #ifdef WIN32 - time_t upd_time, cur_time; + DWORD upd_time, cur_time; /* GetTickCount() returns a "DWORD" (which is 'unsigned long') */ #else struct timeval upd_time, cur_time; #endif @@ -3027,11 +3111,10 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct gboolean cfilter_error = FALSE; char errmsg[MSG_MAX_LENGTH+1]; char secondary_errmsg[MSG_MAX_LENGTH+1]; - pcap_options pcap_opts; + pcap_options *pcap_opts; interface_options interface_opts; - guint i; + guint i, error_index = 0; - interface_opts = capture_opts->default_options; *errmsg = '\0'; *secondary_errmsg = '\0'; @@ -3041,7 +3124,6 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct #ifdef SIGINFO global_ld.report_packet_count = FALSE; #endif - global_ld.pcaps = g_array_new(FALSE, FALSE, sizeof(pcap_options)); if (capture_opts->has_autostop_packets) global_ld.packet_max = capture_opts->autostop_packets; else @@ -3064,24 +3146,30 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct goto error; } for (i = 0; i < capture_opts->ifaces->len; i++) { - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); /* init the input filter from the network interface (capture pipe will do nothing) */ - switch (capture_loop_init_filter(pcap_opts.pcap_h, pcap_opts.from_cap_pipe, + /* + * When remote capturing WinPCap crashes when the capture filter + * is NULL. This might be a bug in WPCap. Therefore we provide an emtpy + * string. + */ + switch (capture_loop_init_filter(pcap_opts->pcap_h, pcap_opts->from_cap_pipe, interface_opts.name, - interface_opts.cfilter)) { + interface_opts.cfilter?interface_opts.cfilter:"")) { case INITFILTER_NO_ERROR: break; case INITFILTER_BAD_FILTER: cfilter_error = TRUE; - g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(pcap_opts.pcap_h)); + error_index = i; + g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(pcap_opts->pcap_h)); goto error; case INITFILTER_OTHER_ERROR: g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).", - pcap_geterr(pcap_opts.pcap_h)); + pcap_geterr(pcap_opts->pcap_h)); g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report); goto error; } @@ -3154,20 +3242,19 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_queue_bytes = 0; pcap_queue_packets = 0; for (i = 0; i < global_ld.pcaps->len; i++) { - gint *interface_id; - - interface_id = (gint *)g_malloc(sizeof(guint)); - *interface_id = i; - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); - pcap_opts.tid = g_thread_create(pcap_read_handler, interface_id, TRUE, NULL); - global_ld.pcaps = g_array_remove_index(global_ld.pcaps, i); - g_array_insert_val(global_ld.pcaps, i, pcap_opts); + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); +#if GLIB_CHECK_VERSION(2,31,0) + /* XXX - Add an interface name here? */ + pcap_opts->tid = g_thread_new("Capture read", pcap_read_handler, pcap_opts); +#else + pcap_opts->tid = g_thread_create(pcap_read_handler, pcap_opts, TRUE, NULL); +#endif } } while (global_ld.go) { /* dispatch incoming packets */ if (use_threads) { - GTimeVal write_thread_time; + GTimeVal write_thread_time; pcap_queue_element *queue_element; g_get_current_time(&write_thread_time); @@ -3182,9 +3269,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct if (queue_element) { g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Dequeued a packet of length %d captured on interface %d.", - queue_element->phdr.caplen, queue_element->interface_id); + queue_element->phdr.caplen, queue_element->pcap_opts->interface_id); - capture_loop_write_packet_cb((u_char *)&queue_element->interface_id, + capture_loop_write_packet_cb((u_char *) queue_element->pcap_opts, &queue_element->phdr, queue_element->pd); g_free(queue_element->pd); @@ -3194,8 +3281,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct inpkts = 0; } } else { + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, 0); inpkts = capture_loop_dispatch(&global_ld, errmsg, - sizeof(errmsg), &pcap_opts); + sizeof(errmsg), pcap_opts); } #ifdef SIGINFO /* Were we asked to print packet counts by the SIGINFO handler? */ @@ -3236,8 +3324,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct #define DUMPCAP_UPD_TIME 500 #ifdef WIN32 - cur_time = GetTickCount(); - if ( (cur_time - upd_time) > DUMPCAP_UPD_TIME) { + cur_time = GetTickCount(); /* Note: wraps to 0 if sys runs for 49.7 days */ + if ((cur_time - upd_time) > DUMPCAP_UPD_TIME) { /* wrap just causes an extra update */ #else gettimeofday(&cur_time, NULL); if ((cur_time.tv_sec * 1000000 + cur_time.tv_usec) > @@ -3286,12 +3374,12 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_queue_element *queue_element; for (i = 0; i < global_ld.pcaps->len; i++) { - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Waiting for thread of interface %u...", - pcap_opts.interface_id); - g_thread_join(pcap_opts.tid); + pcap_opts->interface_id); + g_thread_join(pcap_opts->tid); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Thread of interface %u terminated.", - pcap_opts.interface_id); + pcap_opts->interface_id); } while (1) { g_async_queue_lock(pcap_queue); @@ -3306,8 +3394,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct } g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Dequeued a packet of length %d captured on interface %d.", - queue_element->phdr.caplen, queue_element->interface_id); - capture_loop_write_packet_cb((u_char *)&queue_element->interface_id, + queue_element->phdr.caplen, queue_element->pcap_opts->interface_id); + capture_loop_write_packet_cb((u_char *)queue_element->pcap_opts, &queue_element->phdr, queue_element->pd); g_free(queue_element->pd); @@ -3330,14 +3418,14 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct if (cnd_autostop_duration != NULL) cnd_delete(cnd_autostop_duration); - /* did we had a pcap (input) error? */ + /* did we have a pcap (input) error? */ for (i = 0; i < capture_opts->ifaces->len; i++) { - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); - if (pcap_opts.pcap_err) { + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); + if (pcap_opts->pcap_err) { /* On Linux, if an interface goes down while you're capturing on it, you'll get a "recvfrom: Network is down" or "The interface went down" error (ENETDOWN). - (At least you will if strerror() doesn't show a local translation + (At least you will if g_strerror() doesn't show a local translation of the error.) On FreeBSD and OS X, if a network adapter disappears while @@ -3349,7 +3437,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct These should *not* be reported to the Wireshark developers. */ char *cap_err_str; - cap_err_str = pcap_geterr(pcap_opts.pcap_h); + cap_err_str = pcap_geterr(pcap_opts->pcap_h); if (strcmp(cap_err_str, "recvfrom: Network is down") == 0 || strcmp(cap_err_str, "The interface went down") == 0 || strcmp(cap_err_str, "read: Device not configured") == 0 || @@ -3364,7 +3452,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct report_capture_error(errmsg, please_report); } break; - } else if (pcap_opts.from_cap_pipe && pcap_opts.cap_pipe_err == PIPERR) { + } else if (pcap_opts->from_cap_pipe && pcap_opts->cap_pipe_err == PIPERR) { report_capture_error(errmsg, ""); break; } @@ -3410,26 +3498,32 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct * mode, cap_pipe_open_live() will say "End of file on pipe during open". */ - report_capture_count(); /* print final capture count only if (quiet && !capture_child) */ + report_capture_count(TRUE); /* get packet drop statistics from pcap */ for (i = 0; i < capture_opts->ifaces->len; i++) { - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); + guint32 received; + guint32 dropped; + + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); - if (pcap_opts.pcap_h != NULL) { - g_assert(!pcap_opts.from_cap_pipe); + received = pcap_opts->received; + dropped = pcap_opts->dropped; + if (pcap_opts->pcap_h != NULL) { + g_assert(!pcap_opts->from_cap_pipe); /* Get the capture statistics, so we know how many packets were dropped. */ - if (pcap_stats(pcap_opts.pcap_h, stats) >= 0) { + if (pcap_stats(pcap_opts->pcap_h, stats) >= 0) { *stats_known = TRUE; /* Let the parent process know. */ - report_packet_drops(stats->ps_recv, stats->ps_drop, interface_opts.name); + dropped += stats->ps_drop; } else { g_snprintf(errmsg, sizeof(errmsg), "Can't get packet-drop statistics: %s", - pcap_geterr(pcap_opts.pcap_h)); + pcap_geterr(pcap_opts->pcap_h)); report_capture_error(errmsg, please_report); } } + report_packet_drops(received, dropped, interface_opts.name); } /* close the input file (pcap or capture pipe) */ @@ -3460,7 +3554,7 @@ error: } capture_opts->save_file = NULL; if (cfilter_error) - report_cfilter_error(interface_opts.cfilter, errmsg); + report_cfilter_error(capture_opts, error_index, errmsg); else report_capture_error(errmsg, secondary_errmsg); @@ -3477,12 +3571,12 @@ static void capture_loop_stop(void) { #ifdef HAVE_PCAP_BREAKLOOP guint i; - pcap_options pcap_opts; + pcap_options *pcap_opts; for (i = 0; i < global_ld.pcaps->len; i++) { - pcap_opts = g_array_index(global_ld.pcaps, pcap_options, i); - if (pcap_opts.pcap_h != NULL) - pcap_breakloop(pcap_opts.pcap_h); + pcap_opts = g_array_index(global_ld.pcaps, pcap_options *, i); + if (pcap_opts->pcap_h != NULL) + pcap_breakloop(pcap_opts->pcap_h); } #endif global_ld.go = FALSE; @@ -3521,13 +3615,13 @@ capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fname, g_snprintf(errmsg, errmsglen, "The file to which the capture was being saved\n" "(\"%s\") could not be closed: %s.", - fname, strerror(err)); + fname, g_strerror(err)); } else { g_snprintf(errmsg, errmsglen, "An error occurred while writing to the file" " to which the capture was being saved\n" "(\"%s\"): %s.", - fname, strerror(err)); + fname, g_strerror(err)); } break; } @@ -3536,10 +3630,10 @@ capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fname, /* one packet was captured, process it */ static void -capture_loop_write_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, +capture_loop_write_packet_cb(u_char *pcap_opts_p, const struct pcap_pkthdr *phdr, const u_char *pd) { - guint interface_id = *(guint *) (void *) user; + pcap_options *pcap_opts = (pcap_options *) (void *) pcap_opts_p; int err; /* We may be called multiple times from pcap_dispatch(); if we've set @@ -3555,7 +3649,7 @@ capture_loop_write_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, If this fails, set "ld->go" to FALSE, to stop the capture, and set "ld->err" to the error. */ if (global_capture_opts.use_pcapng) { - successful = libpcap_write_enhanced_packet_block(global_ld.pdh, phdr, interface_id, pd, &global_ld.bytes_written, &err); + successful = libpcap_write_enhanced_packet_block(global_ld.pdh, phdr, pcap_opts->interface_id, pd, &global_ld.bytes_written, &err); } else { successful = libpcap_write_packet(global_ld.pdh, phdr, pd, &global_ld.bytes_written, &err); } @@ -3565,8 +3659,9 @@ capture_loop_write_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, } else { g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Wrote a packet of length %d captured on interface %u.", - phdr->caplen, interface_id); + phdr->caplen, pcap_opts->interface_id); global_ld.packet_count++; + pcap_opts->received++; /* if the user told us to stop after x packets, do we already have enough? */ if ((global_ld.packet_max > 0) && (global_ld.packet_count >= global_ld.packet_max)) { global_ld.go = FALSE; @@ -3577,11 +3672,11 @@ capture_loop_write_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, /* one packet was captured, queue it */ static void -capture_loop_queue_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, +capture_loop_queue_packet_cb(u_char *pcap_opts_p, const struct pcap_pkthdr *phdr, const u_char *pd) { + pcap_options *pcap_opts = (pcap_options *) (void *) pcap_opts_p; pcap_queue_element *queue_element; - guint interface_id; gboolean limit_reached; /* We may be called multiple times from pcap_dispatch(); if we've set @@ -3590,15 +3685,16 @@ capture_loop_queue_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, if (!global_ld.go) return; - interface_id = *(guint *) (void *) user; queue_element = (pcap_queue_element *)g_malloc(sizeof(pcap_queue_element)); if (queue_element == NULL) { - return; + pcap_opts->dropped++; + return; } - queue_element->interface_id = interface_id; + queue_element->pcap_opts = pcap_opts; queue_element->phdr = *phdr; queue_element->pd = (u_char *)g_malloc(phdr->caplen); if (queue_element->pd == NULL) { + pcap_opts->dropped++; g_free(queue_element); return; } @@ -3615,15 +3711,17 @@ capture_loop_queue_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, } g_async_queue_unlock(pcap_queue); if (limit_reached) { + pcap_opts->dropped++; g_free(queue_element->pd); g_free(queue_element); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Dropped a packet of length %d captured on interface %u.", - phdr->caplen, interface_id); + phdr->caplen, pcap_opts->interface_id); } else { + pcap_opts->received++; g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Queued a packet of length %d captured on interface %u.", - phdr->caplen, interface_id); + phdr->caplen, pcap_opts->interface_id); } /* I don't want to hold the mutex over the debug output. So the output may be wrong */ @@ -3641,8 +3739,6 @@ main(int argc, char *argv[]) #ifdef _WIN32 WSADATA wsaData; - LPWSTR *wc_argv; - int wc_argc; #else struct sigaction action, oldaction; #endif @@ -3664,15 +3760,10 @@ main(int argc, char *argv[]) #if defined(__APPLE__) && defined(__LP64__) struct utsname osinfo; #endif + GString *str; #ifdef _WIN32 - /* Convert our arg list to UTF-8. */ - wc_argv = CommandLineToArgvW(GetCommandLineW(), &wc_argc); - if (wc_argv && wc_argc == argc) { - for (i = 0; i < argc; i++) { - argv[i] = g_utf16_to_utf8(wc_argv[i], -1, NULL, NULL, NULL); - } - } /* XXX else bail because something is horribly, horribly wrong? */ + arg_list_utf_16to8(argc, argv); #endif /* _WIN32 */ #ifdef _WIN32 @@ -3717,7 +3808,7 @@ main(int argc, char *argv[]) #define OPTSTRING_d "" #endif -#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:" OPTSTRING_d "Df:ghi:" OPTSTRING_I "L" OPTSTRING_m "Mnpq" OPTSTRING_r "Ss:t" OPTSTRING_u "vw:y:Z:" +#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:" OPTSTRING_d "Df:ghi:" OPTSTRING_I "L" OPTSTRING_m "MnpPq" OPTSTRING_r "Ss:t" OPTSTRING_u "vw:y:Z:" #ifdef DEBUG_CHILD_DUMPCAP if ((debug_log = ws_fopen("dumpcap_debug_log.tmp","w")) == NULL) { @@ -3814,9 +3905,14 @@ main(int argc, char *argv[]) log_flags, console_log_handler, NULL /* user_data */); + /* Initialize the pcaps list */ + global_ld.pcaps = g_array_new(FALSE, FALSE, sizeof(pcap_options *)); + +#if !GLIB_CHECK_VERSION(2,31,0) /* Initialize the thread system */ - if (!g_thread_supported()) - g_thread_init(NULL); + g_thread_init(NULL); +#endif + #ifdef _WIN32 /* Load wpcap if possible. Do this before collecting the run-time version information */ load_wpcap(); @@ -3944,9 +4040,6 @@ main(int argc, char *argv[]) by the command line parameters. */ capture_opts_init(&global_capture_opts, NULL); - /* Default to capturing the entire packet. */ - global_capture_opts.snaplen = WTAP_MAX_PACKET_SIZE; - /* We always save to a file - if no file was specified, we save to a temporary file. */ global_capture_opts.saving_to_file = TRUE; @@ -3984,6 +4077,7 @@ main(int argc, char *argv[]) case 'i': /* Use interface x */ case 'n': /* Use pcapng format */ case 'p': /* Don't capture in promiscuous mode */ + case 'P': /* Use pcap format */ case 's': /* Set the snapshot (capture) length */ case 'w': /* Write to capture file x */ case 'g': /* enable group read accesson file(s) */ @@ -4035,7 +4129,6 @@ main(int argc, char *argv[]) case 'q': /* Quiet */ quiet = TRUE; break; - case 't': use_threads = TRUE; break; @@ -4062,28 +4155,30 @@ main(int argc, char *argv[]) machine_readable = TRUE; break; default: - case '?': /* Bad flag - print usage message */ cmdarg_err("Invalid Option: %s", argv[optind-1]); + /* FALLTHROUGH */ + case '?': /* Bad flag - print usage message */ arg_error = TRUE; break; } } - argc -= optind; - argv += optind; - if (argc >= 1) { - /* user specified file name as regular command-line argument */ - /* XXX - use it as the capture file name (or something else)? */ - argc--; - argv++; - } - - if (argc != 0) { - /* - * Extra command line arguments were specified; complain. - * XXX - interpret as capture filter, as tcpdump and tshark do? - */ - cmdarg_err("Invalid argument: %s", argv[0]); - arg_error = TRUE; + if (!arg_error) { + argc -= optind; + argv += optind; + if (argc >= 1) { + /* user specified file name as regular command-line argument */ + /* XXX - use it as the capture file name (or something else)? */ + argc--; + argv++; + } + if (argc != 0) { + /* + * Extra command line arguments were specified; complain. + * XXX - interpret as capture filter, as tcpdump and tshark do? + */ + cmdarg_err("Invalid argument: %s", argv[0]); + arg_error = TRUE; + } } if (arg_error) { @@ -4102,8 +4197,13 @@ main(int argc, char *argv[]) exit_main(1); } } else { - /* We're supposed to capture traffic; was the ring buffer option - specified and, if so, does it make sense? */ + /* We're supposed to capture traffic; */ + /* Are we capturing on multiple interface? If so, use threads and pcapng. */ + if (global_capture_opts.ifaces->len > 1) { + use_threads = TRUE; + global_capture_opts.use_pcapng = TRUE; + } + /* Was the ring buffer option specified and, if so, does it make sense? */ if (global_capture_opts.multi_files_on) { /* Ring buffer works only under certain conditions: a) ring buffer does not work with temporary files; @@ -4137,6 +4237,7 @@ main(int argc, char *argv[]) if (if_list == NULL) { switch (err) { case CANT_GET_INTERFACE_LIST: + case DONT_HAVE_PCAP: cmdarg_err("%s", err_str); g_free(err_str); exit_main(2); @@ -4185,11 +4286,41 @@ main(int argc, char *argv[]) /* Let the user know what interfaces were chosen. */ /* get_interface_descriptive_name() is not available! */ - for (j = 0; j < global_capture_opts.ifaces->len; j++) { - interface_options interface_opts; + if (capture_child) { + for (j = 0; j < global_capture_opts.ifaces->len; j++) { + interface_options interface_opts; - interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j); - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s", interface_opts.name); + interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s\n", + interface_opts.name); + } + } else { + str = g_string_new(""); +#ifdef _WIN32 + if (global_capture_opts.ifaces->len < 2) { +#else + if (global_capture_opts.ifaces->len < 4) { +#endif + for (j = 0; j < global_capture_opts.ifaces->len; j++) { + interface_options interface_opts; + + interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j); + if (j > 0) { + if (global_capture_opts.ifaces->len > 2) { + g_string_append_printf(str, ","); + } + g_string_append_printf(str, " "); + if (j == global_capture_opts.ifaces->len - 1) { + g_string_append_printf(str, "and "); + } + } + g_string_append_printf(str, "%s", interface_opts.name); + } + } else { + g_string_append_printf(str, "%u interfaces", global_capture_opts.ifaces->len); + } + fprintf(stderr, "Capturing on %s\n", str->str); + g_string_free(str, TRUE); } if (list_link_layer_types) { @@ -4361,7 +4492,7 @@ report_packet_count(int packet_count) } } -void +static void report_new_capture_file(const char *filename) { if(capture_child) { @@ -4395,23 +4526,34 @@ report_new_capture_file(const char *filename) } } -void -report_cfilter_error(const char *cfilter, const char *errmsg) +static void +report_cfilter_error(capture_options *capture_opts, guint i, const char *errmsg) { - if (capture_child) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg); - pipe_write_block(2, SP_BAD_FILTER, errmsg); - } else { - fprintf(stderr, - "Invalid capture filter: \"%s\"!\n" - "\n" - "That string isn't a valid capture filter (%s).\n" - "See the User's Guide for a description of the capture filter syntax.\n", - cfilter, errmsg); + interface_options interface_opts; + char tmp[MSG_MAX_LENGTH+1+6]; + + if (i < capture_opts->ifaces->len) { + if (capture_child) { + g_snprintf(tmp, sizeof(tmp), "%u:%s", i, errmsg); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg); + pipe_write_block(2, SP_BAD_FILTER, tmp); + } else { + /* + * clopts_step_invalid_capfilter in test/suite-clopts.sh MUST match + * the error message below. + */ + interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); + cmdarg_err( + "Invalid capture filter: \"%s\" for interface %s!\n" + "\n" + "That string isn't a valid capture filter (%s).\n" + "See the User's Guide for a description of the capture filter syntax.", + interface_opts.cfilter, interface_opts.name, errmsg); + } } } -void +static void report_capture_error(const char *error_msg, const char *secondary_error_msg) { if(capture_child) { @@ -4421,27 +4563,30 @@ report_capture_error(const char *error_msg, const char *secondary_error_msg) "Secondary Error: %s", secondary_error_msg); sync_pipe_errmsg_to_parent(2, error_msg, secondary_error_msg); } else { - fprintf(stderr, "%s\n", error_msg); + cmdarg_err("%s", error_msg); if (secondary_error_msg[0] != '\0') - fprintf(stderr, "%s\n", secondary_error_msg); + cmdarg_err_cont("%s", secondary_error_msg); } } -void +static void report_packet_drops(guint32 received, guint32 drops, gchar *name) { - char tmp1[SP_DECISIZE+1+1]; - char tmp2[SP_DECISIZE+1+1]; + char tmp[SP_DECISIZE+1+1]; - g_snprintf(tmp1, sizeof(tmp1), "%u", received); - g_snprintf(tmp2, sizeof(tmp2), "%u", drops); + g_snprintf(tmp, sizeof(tmp), "%u", drops); if(capture_child) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets captured/dropped on interface %s: %s/%s", name, tmp1, tmp2); + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + "Packets received/dropped on interface %s: %u/%u", + name, received, drops); /* XXX: Need to provide interface id, changes to consumers required. */ - pipe_write_block(2, SP_DROPS, tmp2); + pipe_write_block(2, SP_DROPS, tmp); } else { - fprintf(stderr, "Packets captured/dropped on interface %s: %s/%s\n", name, tmp1, tmp2); + fprintf(stderr, + "Packets received/dropped on interface %s: %u/%u (%.1f%%)\n", + name, received, drops, + received ? 100.0 * received / (received + drops) : 0.0); /* stderr could be line buffered */ fflush(stderr); } @@ -4505,6 +4650,6 @@ signal_pipe_check_running(void) * indent-tabs-mode: nil * End: * - * vi: set shiftwidth=4 tabstop=8 expandtab + * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */