X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=dumpcap.c;h=a86daef3d58721ec955615654da1ef11dcdfdce0;hb=609b36f938cd1a51aacdcda4b2a220a43a46c1ec;hp=22bc416b868036f101e3f3380f33a88f18c7fe21;hpb=55f70620c07741f08585cebc2cdcbee3b3c15580;p=metze%2Fwireshark%2Fwip.git diff --git a/dumpcap.c b/dumpcap.c index 22bc416b86..a86daef3d5 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -85,7 +85,6 @@ #include "pcapio.h" #ifdef _WIN32 -#include #include "capture-wpcap.h" #include #endif @@ -135,11 +134,11 @@ 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; +static gint64 pcap_queue_byte_limit = 1024 * 1024; +static gint64 pcap_queue_packet_limit = 1000; static gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */ #ifdef _WIN32 @@ -215,13 +214,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 */ @@ -242,9 +237,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(USE_THREADS) && 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 { @@ -254,7 +249,7 @@ typedef struct _pcap_options { STATE_READ_DATA } cap_pipe_state; enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err; -#ifdef USE_THREADS +#if defined(USE_THREADS) && defined(_WIN32) GMutex *cap_pipe_read_mtx; GAsyncQueue *cap_pipe_pending_q, *cap_pipe_done_q; #endif @@ -278,6 +273,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. */ @@ -319,12 +320,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(USE_THREADS) && 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 */ @@ -337,9 +337,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); @@ -350,7 +350,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 @@ -417,7 +417,9 @@ print_usage(gboolean print_ver) fprintf(output, " -n use pcapng format instead of pcap\n"); /*fprintf(output, "\n");*/ fprintf(output, "Miscellaneous:\n"); +#ifdef USE_THREADS fprintf(output, " -t use a separate thread per interface\n"); +#endif 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"); @@ -535,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); @@ -558,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) /* @@ -570,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 { @@ -585,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) @@ -608,23 +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 } - - /* If not using libcap: we now can now set euid/egid to ruid/rgid */ - /* to remove any suid privileges. */ - /* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities */ - /* (euid/egid have already previously been set to ruid/rgid. */ - /* (See comment in main() for details) */ -#ifndef HAVE_LIBCAP - relinquish_special_privs_perm(); -#else - relinquish_all_capabilities(); -#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; } @@ -722,7 +739,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]; @@ -741,7 +758,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; } @@ -788,7 +811,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); @@ -799,6 +822,16 @@ show_filter_code(capture_options *capture_opts) for (i = 0; i < fcode.bf_len; insn++, i++) printf("%s\n", bpf_image(insn, i)); } + /* If not using libcap: we now can now set euid/egid to ruid/rgid */ + /* to remove any suid privileges. */ + /* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities */ + /* (euid/egid have already previously been set to ruid/rgid. */ + /* (See comment in main() for details) */ +#ifndef HAVE_LIBCAP + relinquish_special_privs_perm(); +#else + relinquish_all_capabilities(); +#endif if (capture_child) { /* Let our parent know we succeeded. */ pipe_write_block(2, SP_SUCCESS, NULL); @@ -1379,17 +1412,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); } } @@ -1398,7 +1427,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 */ } @@ -1463,14 +1492,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"); @@ -1479,7 +1508,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"); @@ -1520,7 +1549,7 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr } } -#ifdef USE_THREADS +#if defined(USE_THREADS) && defined(_WIN32) /* * Thread function that reads from a pipe and pushes the data * to the main application thread. @@ -1539,7 +1568,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; @@ -1548,6 +1577,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); @@ -1605,22 +1635,19 @@ static void *cap_pipe_read(void *arg) } return NULL; } -#endif /* USE_THREADS */ +#endif +#if (!(defined(USE_THREADS) && 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); @@ -1628,11 +1655,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 @@ -1659,7 +1684,7 @@ cap_pipe_open_live(char *pipename, wchar_t *err_str; #endif #endif -#ifndef USE_THREADS +#if !(defined(USE_THREADS) && defined(_WIN32)) int sel_ret; unsigned int bytes_read; #endif @@ -1690,7 +1715,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; @@ -1700,7 +1725,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; } @@ -1709,7 +1734,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; } @@ -1749,7 +1774,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; } @@ -1828,14 +1853,14 @@ cap_pipe_open_live(char *pipename, pcap_opts->from_cap_pipe = TRUE; -#ifndef USE_THREADS +#if !(defined(USE_THREADS) && defined(_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); @@ -1844,14 +1869,14 @@ 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 */ - g_thread_create(&cap_pipe_read, &pcap_opts, FALSE, NULL); +#else + g_thread_create(&cap_pipe_read, pcap_opts, FALSE, NULL); pcap_opts->cap_pipe_buf = (char *) &magic; pcap_opts->cap_pipe_bytes_read = 0; @@ -1864,11 +1889,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: @@ -1903,14 +1928,14 @@ cap_pipe_open_live(char *pipename, goto error; } -#ifndef USE_THREADS +#if !(defined(USE_THREADS) && defined(_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, @@ -1920,13 +1945,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); @@ -1937,10 +1962,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. */ @@ -1983,7 +2008,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 +#if defined(USE_THREADS) && defined(_WIN32) GTimeVal wait_time; gpointer q_status; #else @@ -2000,7 +2025,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 +#if defined(USE_THREADS) && defined(_WIN32) if (g_mutex_trylock(pcap_opts->cap_pipe_read_mtx)) { #endif @@ -2009,7 +2034,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 +#if defined(USE_THREADS) && defined(_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); @@ -2018,7 +2043,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 +#if !(defined(USE_THREADS) && defined(_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) { @@ -2029,7 +2054,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); @@ -2043,14 +2068,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 +#if defined(USE_THREADS) && defined(_WIN32) if (g_mutex_trylock(pcap_opts->cap_pipe_read_mtx)) { #endif @@ -2058,7 +2083,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 +#if defined(USE_THREADS) && defined(_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); @@ -2067,7 +2092,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er /* Fall through */ case STATE_READ_DATA: -#ifndef USE_THREADS +#if !(defined(USE_THREADS) && defined(_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) { @@ -2078,7 +2103,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); @@ -2092,7 +2117,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; @@ -2118,8 +2143,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. */ @@ -2129,9 +2158,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; @@ -2150,7 +2179,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: @@ -2173,7 +2202,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; @@ -2231,54 +2260,63 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, #endif if ((use_threads == FALSE) && (capture_opts->ifaces->len > 1)) { - g_snprintf(errmsg, errmsg_len, - "Using threads is required for capturing on mulitple interfaces! Use the -t option."); + g_snprintf(errmsg, (gulong) errmsg_len, + "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; + pcap_opts->cap_pipe_h = INVALID_HANDLE_VALUE; #else - pcap_opts.cap_pipe_fd = -1; + 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_modified = FALSE; + pcap_opts->cap_pipe_byte_swapped = FALSE; +#if defined(USE_THREADS) && defined(_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; +#if defined(USE_THREADS) && defined(_WIN32) + 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(); #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" @@ -2295,7 +2333,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; @@ -2319,29 +2357,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, @@ -2354,7 +2390,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 @@ -2365,11 +2400,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 @@ -2383,9 +2418,18 @@ 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 */ + /* to remove any suid privileges. */ + /* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities */ + /* (euid/egid have already previously been set to ruid/rgid. */ + /* (See comment in main() for details) */ +#ifndef HAVE_LIBCAP + relinquish_special_privs_perm(); +#else + relinquish_all_capabilities(); +#endif return TRUE; } @@ -2393,30 +2437,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; } } @@ -2432,7 +2476,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; @@ -2468,7 +2512,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; @@ -2495,29 +2539,29 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err successful = libpcap_write_session_header_block(ld->pdh, appname, &ld->bytes_written, &err); 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) { @@ -2541,7 +2585,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; } @@ -2557,7 +2601,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"); @@ -2566,9 +2610,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); } } } @@ -2594,7 +2638,7 @@ capture_loop_dispatch(loop_data *ld, int inpkts; gint packet_count_before; guchar pcap_data[WTAP_MAX_PACKET_SIZE]; -#ifndef USE_THREADS +#if !(defined(USE_THREADS) && defined(_WIN32)) int sel_ret; #endif @@ -2604,12 +2648,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 +#if !(defined(USE_THREADS) && defined(_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; } @@ -2617,12 +2661,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 +#if !(defined(USE_THREADS) && defined(_WIN32)) } #endif } @@ -2658,12 +2702,10 @@ capture_loop_dispatch(loop_data *ld, * processing immediately, rather than processing all packets * 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)); + if (use_threads) { + 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) { @@ -2675,7 +2717,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; } @@ -2696,16 +2738,16 @@ capture_loop_dispatch(loop_data *ld, * after processing packets. We therefore process only one packet * 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); + if (use_threads) { + 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); + if (use_threads) { + 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) { @@ -2740,9 +2782,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); } } @@ -2847,15 +2889,19 @@ 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 { #ifdef _WIN32 - GString *iface; + 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); + iface = isolate_uuid(g_array_index(global_capture_opts.ifaces, interface_options, 0).name); + prefix = g_strconcat("wireshark_", g_basename(iface->str), NULL); + 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); + prefix = g_strconcat("wireshark_", g_basename(g_array_index(global_capture_opts.ifaces, interface_options, 0).name), NULL); #endif + } *save_file_fd = create_tempfile(&tmpname, prefix); g_free(prefix); capfile_name = g_strdup(tmpname); @@ -2867,7 +2913,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(); @@ -2876,7 +2922,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; @@ -2902,7 +2948,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; @@ -2927,19 +2973,19 @@ do_file_switch_or_stop(capture_options *capture_opts, successful = libpcap_write_session_header_block(global_ld.pdh, appname, &(global_ld.bytes_written), &global_ld.err); 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) { @@ -2973,23 +3019,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); } @@ -3015,9 +3058,9 @@ 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'; @@ -3029,7 +3072,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 @@ -3052,24 +3094,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; } @@ -3139,32 +3187,34 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct /* please fasten your seat belts, we will enter now the actual capture loop */ if (use_threads) { pcap_queue = g_async_queue_new(); + 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); + pcap_opts->tid = g_thread_create(pcap_read_handler, pcap_opts, TRUE, NULL); } } 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); g_time_val_add(&write_thread_time, WRITER_THREAD_TIMEOUT); - queue_element = g_async_queue_timed_pop(pcap_queue, &write_thread_time); + g_async_queue_lock(pcap_queue); + queue_element = g_async_queue_timed_pop_unlocked(pcap_queue, &write_thread_time); + if (queue_element) { + pcap_queue_bytes -= queue_element->phdr.caplen; + pcap_queue_packets -= 1; + } + g_async_queue_unlock(pcap_queue); 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); @@ -3174,8 +3224,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? */ @@ -3266,18 +3317,28 @@ 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 ((queue_element = g_async_queue_try_pop(pcap_queue))) { + while (1) { + g_async_queue_lock(pcap_queue); + queue_element = g_async_queue_try_pop_unlocked(pcap_queue); + if (queue_element) { + pcap_queue_bytes -= queue_element->phdr.caplen; + pcap_queue_packets -= 1; + } + g_async_queue_unlock(pcap_queue); + if (queue_element == NULL) { + break; + } 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); @@ -3300,14 +3361,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 @@ -3319,7 +3380,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 || @@ -3334,7 +3395,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; } @@ -3380,26 +3441,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) */ @@ -3430,7 +3497,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); @@ -3447,12 +3514,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; @@ -3491,13 +3558,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; } @@ -3506,10 +3573,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 @@ -3525,7 +3592,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); } @@ -3535,8 +3602,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; @@ -3547,11 +3615,12 @@ 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 the "stop capturing" flag, ignore this packet, as we're not @@ -3559,16 +3628,49 @@ 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)); - queue_element->interface_id = interface_id; + if (queue_element == NULL) { + pcap_opts->dropped++; + return; + } + 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; + } memcpy(queue_element->pd, pd, phdr->caplen); - g_async_queue_push(pcap_queue, queue_element); + g_async_queue_lock(pcap_queue); + if (((pcap_queue_byte_limit > 0) && (pcap_queue_bytes < pcap_queue_byte_limit)) && + ((pcap_queue_packet_limit > 0) && (pcap_queue_packets < pcap_queue_packet_limit))) { + limit_reached = FALSE; + g_async_queue_push_unlocked(pcap_queue, queue_element); + pcap_queue_bytes += phdr->caplen; + pcap_queue_packets += 1; + } else { + limit_reached = TRUE; + } + 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, 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, pcap_opts->interface_id); + } + /* I don't want to hold the mutex over the debug output. So the + output may be wrong */ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, - "Queued a packet of length %d captured on interface %u.", - phdr->caplen, interface_id); + "Queue size is now %" G_GINT64_MODIFIER "d bytes (%" G_GINT64_MODIFIER "d packets)", + pcap_queue_bytes, pcap_queue_packets); } /* And now our feature presentation... [ fade to music ] */ @@ -3580,8 +3682,6 @@ main(int argc, char *argv[]) #ifdef _WIN32 WSADATA wsaData; - LPWSTR *wc_argv; - int wc_argc; #else struct sigaction action, oldaction; #endif @@ -3605,13 +3705,7 @@ main(int argc, char *argv[]) #endif #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 @@ -3656,7 +3750,12 @@ 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:" +#ifdef USE_THREADS +#define OPTSTRING_t "t" +#else +#define OPTSTRING_t "" +#endif +#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:" OPTSTRING_d "Df:ghi:" OPTSTRING_I "L" OPTSTRING_m "MnpPq" OPTSTRING_r "Ss:" OPTSTRING_t OPTSTRING_u "vw:y:Z:" #ifdef DEBUG_CHILD_DUMPCAP if ((debug_log = ws_fopen("dumpcap_debug_log.tmp","w")) == NULL) { @@ -3753,9 +3852,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 *)); + /* Initialize the thread system */ +#ifdef USE_THREADS if (!g_thread_supported()) g_thread_init(NULL); +#endif #ifdef _WIN32 /* Load wpcap if possible. Do this before collecting the run-time version information */ load_wpcap(); @@ -3883,9 +3987,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; @@ -3923,6 +4024,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) */ @@ -3974,10 +4076,11 @@ main(int argc, char *argv[]) case 'q': /* Quiet */ quiet = TRUE; break; - +#ifdef USE_THREADS case 't': use_threads = TRUE; break; +#endif /*** all non capture option specific ***/ case 'D': /* Print a list of capture devices and exit */ list_interfaces = TRUE; @@ -4001,28 +4104,29 @@ main(int argc, char *argv[]) machine_readable = TRUE; break; default: - case '?': /* Bad flag - print usage message */ cmdarg_err("Invalid Option: %s", argv[optind-1]); + 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) { @@ -4041,8 +4145,15 @@ 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. */ +#ifdef USE_THREADS + if (global_capture_opts.ifaces->len > 1) { + use_threads = TRUE; + global_capture_opts.use_pcapng = TRUE; + } +#endif + /* 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; @@ -4300,7 +4411,7 @@ report_packet_count(int packet_count) } } -void +static void report_new_capture_file(const char *filename) { if(capture_child) { @@ -4334,23 +4445,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); + fprintf(stderr, + "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.\n", + 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) { @@ -4366,21 +4488,24 @@ report_capture_error(const char *error_msg, const char *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); }