X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=dumpcap.c;h=8bac9138e949ef342f894966a5a6b49bfa25c805;hb=7dd916459e2ea350dbb1e1fb5dc3fb7d5bb383a8;hp=5705ab122d7f7743f3f6099ffd6a67b9b8b50bfc;hpb=fb8054f13114a94b356f7ad0176fa981c0389de8;p=metze%2Fwireshark%2Fwip.git diff --git a/dumpcap.c b/dumpcap.c index 5705ab122d..8bac9138e9 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -18,12 +18,10 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif +#include "config.h" #include #include /* for exit() */ @@ -36,6 +34,14 @@ # include #endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + #ifdef HAVE_SYS_STAT_H # include #endif @@ -91,7 +97,6 @@ #endif #ifndef _WIN32 -#include #include #endif @@ -114,6 +119,8 @@ #include "log.h" #include "wsutil/file_util.h" +#include "ws80211_utils.h" + /* * Get information about libpcap format from "wiretap/libpcap.h". * XXX - can we just use pcap_open_offline() to read the pipe? @@ -155,6 +162,8 @@ static gboolean infoprint; /* if TRUE, print capture info after clearing in /** Stop a low-level capture (stops the capture child). */ static void capture_loop_stop(void); +/** Close a pipe, or socket if \a from_socket is TRUE */ +static void cap_pipe_close(int pipe_fd, gboolean from_socket _U_); #if !defined (__linux__) #ifndef HAVE_PCAP_BREAKLOOP @@ -230,13 +239,13 @@ typedef struct _pcap_options { gboolean ts_nsec; /* TRUE if we're using nanosecond precision. */ /* capture pipe (unix only "input file") */ gboolean from_cap_pipe; /* TRUE if we are capturing data from a capture pipe */ + gboolean from_cap_socket; /* TRUE if we're capturing from socket */ struct pcap_hdr cap_pipe_hdr; /* Pcap header when capturing from a pipe */ struct pcaprec_modified_hdr cap_pipe_rechdr; /* Pcap record header when capturing from a pipe */ #ifdef _WIN32 HANDLE cap_pipe_h; /* The handle of the capture pipe */ -#else - int cap_pipe_fd; /* the file descriptor of the capture pipe */ #endif + int cap_pipe_fd; /* the file descriptor of the capture pipe */ 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 */ #if defined(_WIN32) @@ -263,7 +272,7 @@ typedef struct _loop_data { int err; /* if non-zero, error seen while capturing */ gint packet_count; /* Number of packets we have already captured */ gint packet_max; /* Number of packets we're supposed to capture - 0 means infinite */ - gint inpkts_to_sync_pipe; /* Packets not already send out to the sync_pipe */ + guint inpkts_to_sync_pipe; /* Packets not already send out to the sync_pipe */ #ifdef SIGINFO gboolean report_packet_count; /* Set by SIGINFO handler; print packet count */ #endif @@ -350,7 +359,7 @@ static void capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fna static void WS_MSVC_NORETURN exit_main(int err) G_GNUC_NORETURN; static void report_new_capture_file(const char *filename); -static void report_packet_count(int packet_count); +static void report_packet_count(unsigned 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(capture_options *capture_opts, guint i, const char *errmsg); @@ -427,7 +436,10 @@ print_usage(gboolean print_ver) fprintf(output, "\nUsage: dumpcap [options] ...\n"); fprintf(output, "\n"); fprintf(output, "Capture interface:\n"); - fprintf(output, " -i name or idx of interface (def: first non-loopback)\n"); + fprintf(output, " -i name or idx of interface (def: first non-loopback),\n" + " or for remote capturing, use one of these formats:\n" + " rpcap:///\n" + " TCP@:\n"); fprintf(output, " -f packet filter in libpcap filter syntax\n"); fprintf(output, " -s packet snapshot length (def: 65535)\n"); fprintf(output, " -p don't capture in promiscuous mode\n"); @@ -443,6 +455,7 @@ print_usage(gboolean print_ver) #ifdef HAVE_BPF_IMAGE fprintf(output, " -d print generated BPF code for capture filter\n"); #endif + fprintf(output, " -k set channel on wifi interface ,[]\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"); @@ -479,7 +492,7 @@ print_usage(gboolean print_ver) fprintf(output, " -h display this help and exit\n"); fprintf(output, "\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, "\"Capture 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"); } @@ -637,12 +650,15 @@ open_capture_device(interface_options *interface_opts, (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); - if ((*open_err_str)[0] == '\0') { - /* Work around known WinPcap bug wherein no error message is - filled in on a failure to open an rpcap: URL. */ - g_strlcpy(*open_err_str, - "Unknown error (pcap bug; actual error cause not reported)", - sizeof *open_err_str); + if (pcap_h == NULL) { + /* Error - did pcap actually supply an error message? */ + if ((*open_err_str)[0] == '\0') { + /* Work around known WinPcap bug wherein no error message is + filled in on a failure to open an rpcap: URL. */ + g_strlcpy(*open_err_str, + "Unknown error (pcap bug; actual error cause not reported)", + sizeof *open_err_str); + } } g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "pcap_open() returned %p.", (void *)pcap_h); @@ -1649,6 +1665,23 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr } } +/* Wrapper: distinguish between recv/read if we're reading on Windows, + * or just read(). + */ +static int +cap_pipe_read(int pipe_fd, char *buf, size_t sz, gboolean from_socket _U_) +{ +#ifdef _WIN32 + if (from_socket) { + return recv(pipe_fd, buf, (int)sz, 0); + } else { + return -1; + } +#else + return ws_read(pipe_fd, buf, sz); +#endif +} + #if defined(_WIN32) /* * Thread function that reads from a pipe and pushes the data @@ -1663,10 +1696,10 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr * the queues themselves (yet). * * We might want to move some of the cap_pipe_dispatch logic here so that - * we can let cap_pipe_read run independently, queuing up multiple reads + * we can let cap_thread_read run independently, queuing up multiple reads * for the main thread (and possibly get rid of cap_pipe_read_mtx). */ -static void *cap_pipe_read(void *arg) +static void *cap_thread_read(void *arg) { pcap_options *pcap_opts; int bytes_read; @@ -1683,48 +1716,57 @@ static void *cap_pipe_read(void *arg) g_mutex_lock(pcap_opts->cap_pipe_read_mtx); bytes_read = 0; while (bytes_read < (int) pcap_opts->cap_pipe_bytes_to_read) { + if ((pcap_opts->from_cap_socket) +#ifndef _WIN32 + || 1 +#endif + ) + { + b = cap_pipe_read(pcap_opts->cap_pipe_fd, pcap_opts->cap_pipe_buf+bytes_read, + pcap_opts->cap_pipe_bytes_to_read - bytes_read, pcap_opts->from_cap_socket); + if (b <= 0) { + if (b == 0) { + pcap_opts->cap_pipe_err = PIPEOF; + bytes_read = 0; + break; + } else { + pcap_opts->cap_pipe_err = PIPERR; + bytes_read = -1; + break; + } + } else { + bytes_read += b; + } + } #ifdef _WIN32 - /* If we try to use read() on a named pipe on Windows with partial - * data it appears to return EOF. - */ - res = ReadFile(pcap_opts->cap_pipe_h, pcap_opts->cap_pipe_buf+bytes_read, - pcap_opts->cap_pipe_bytes_to_read - bytes_read, - &b, NULL); - - bytes_read += b; - if (!res) { - last_err = GetLastError(); - if (last_err == ERROR_MORE_DATA) { - continue; - } else if (last_err == ERROR_HANDLE_EOF || last_err == ERROR_BROKEN_PIPE || last_err == ERROR_PIPE_NOT_CONNECTED) { - pcap_opts->cap_pipe_err = PIPEOF; - bytes_read = 0; - break; - } - pcap_opts->cap_pipe_err = PIPERR; - bytes_read = -1; - break; - } else if (b == 0 && pcap_opts->cap_pipe_bytes_to_read > 0) { - pcap_opts->cap_pipe_err = PIPEOF; - bytes_read = 0; - break; - } -#else /* _WIN32 */ - b = read(pcap_opts->cap_pipe_fd, pcap_opts->cap_pipe_buf+bytes_read, - pcap_opts->cap_pipe_bytes_to_read - bytes_read); - if (b <= 0) { - if (b == 0) { - pcap_opts->cap_pipe_err = PIPEOF; - bytes_read = 0; - break; - } else { - pcap_opts->cap_pipe_err = PIPERR; - bytes_read = -1; - break; - } - } else { - bytes_read += b; - } + else + { + /* If we try to use read() on a named pipe on Windows with partial + * data it appears to return EOF. + */ + res = ReadFile(pcap_opts->cap_pipe_h, pcap_opts->cap_pipe_buf+bytes_read, + pcap_opts->cap_pipe_bytes_to_read - bytes_read, + &b, NULL); + + bytes_read += b; + if (!res) { + last_err = GetLastError(); + if (last_err == ERROR_MORE_DATA) { + continue; + } else if (last_err == ERROR_HANDLE_EOF || last_err == ERROR_BROKEN_PIPE || last_err == ERROR_PIPE_NOT_CONNECTED) { + pcap_opts->cap_pipe_err = PIPEOF; + bytes_read = 0; + break; + } + pcap_opts->cap_pipe_err = PIPERR; + bytes_read = -1; + break; + } else if (b == 0 && pcap_opts->cap_pipe_bytes_to_read > 0) { + pcap_opts->cap_pipe_err = PIPEOF; + bytes_read = 0; + break; + } + } #endif /*_WIN32 */ } pcap_opts->cap_pipe_bytes_read = bytes_read; @@ -1737,7 +1779,6 @@ static void *cap_pipe_read(void *arg) } #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. * @@ -1757,8 +1798,102 @@ cap_pipe_select(int pipe_fd) return select(pipe_fd+1, &rfds, NULL, NULL, &timeout); } + +#define DEF_TCP_PORT 19000 + +static int +cap_open_socket(char *pipename, pcap_options *pcap_opts, char *errmsg, int errmsgl) +{ + char *sockname = pipename + 4; + struct sockaddr_in sa; + char buf[16]; + char *p; + unsigned long port; + size_t len; + int fd; + + memset(&sa, 0, sizeof(sa)); + + p = strchr(sockname, ':'); + if (p == NULL) { + len = strlen(sockname); + port = DEF_TCP_PORT; + } + else { + len = p - sockname; + port = strtoul(p + 1, &p, 10); + if (*p || port > 65535) { + goto fail_invalid; + } + } + + if (len > 15) { + goto fail_invalid; + } + + strncpy(buf, sockname, len); + buf[len] = '\0'; + if (!inet_pton(AF_INET, buf, &sa.sin_addr)) { + goto fail_invalid; + } + + sa.sin_family = AF_INET; + sa.sin_port = htons((u_short)port); + + if (((fd = (int)socket(AF_INET, SOCK_STREAM, 0)) < 0) || + (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)) { +#ifdef _WIN32 + LPTSTR errorText = NULL; + int lastError; + + lastError = WSAGetLastError(); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&errorText, 0, NULL); +#endif + g_snprintf(errmsg, errmsgl, + "The capture session could not be initiated due to the socket error: \n" +#ifdef _WIN32 + " %d: %S", lastError, errorText ? (char *)errorText : "Unknown"); + if (errorText) + LocalFree(errorText); +#else + " %d: %s", errno, strerror(errno)); #endif + pcap_opts->cap_pipe_err = PIPERR; + + if (fd >= 0) + cap_pipe_close(fd, TRUE); + return -1; + } + pcap_opts->from_cap_socket = TRUE; + return fd; + +fail_invalid: + g_snprintf(errmsg, errmsgl, + "The capture session could not be initiated because\n" + "\"%s\" is not a valid socket specification", pipename); + pcap_opts->cap_pipe_err = PIPERR; + return -1; +} + +/* Wrapper: distinguish between closesocket on Windows; use ws_close + * otherwise. + */ +static void +cap_pipe_close(int pipe_fd, gboolean from_socket _U_) +{ +#ifdef _WIN32 + if (from_socket) { + closesocket(pipe_fd); + } +#else + ws_close(pipe_fd); +#endif +} /* Mimic pcap_open_live() for pipe captures @@ -1776,23 +1911,16 @@ cap_pipe_open_live(char *pipename, #ifndef _WIN32 ws_statb64 pipe_stat; struct sockaddr_un sa; - int b; - int fd; #else /* _WIN32 */ -#if 1 char *pncopy, *pos; wchar_t *err_str; #endif -#endif -#ifndef _WIN32 - int sel_ret; + int b, fd, sel_ret; unsigned int bytes_read; -#endif guint32 magic = 0; -#ifndef _WIN32 pcap_opts->cap_pipe_fd = -1; -#else +#ifdef _WIN32 pcap_opts->cap_pipe_h = INVALID_HANDLE_VALUE; #endif g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename); @@ -1807,6 +1935,10 @@ cap_pipe_open_live(char *pipename, #else /* _WIN32 */ pcap_opts->cap_pipe_h = GetStdHandle(STD_INPUT_HANDLE); #endif /* _WIN32 */ + } else if (!strncmp(pipename, "TCP@", 4)) { + if ((fd = cap_open_socket(pipename, pcap_opts, errmsg, errmsgl)) < 0) { + return; + } } else { #ifndef _WIN32 if (ws_stat64(pipename, &pipe_stat) < 0) { @@ -1868,6 +2000,7 @@ cap_pipe_open_live(char *pipename, "The capture session coud not be initiated " "due to error on socket connect: Path name too long"); pcap_opts->cap_pipe_err = PIPERR; + ws_close(fd); return; } b = connect(fd, (struct sockaddr *)&sa, sizeof sa); @@ -1876,6 +2009,7 @@ cap_pipe_open_live(char *pipename, "The capture session coud not be initiated " "due to error on socket connect: %s", g_strerror(errno)); pcap_opts->cap_pipe_err = PIPERR; + ws_close(fd); return; } } else { @@ -1925,7 +2059,7 @@ cap_pipe_open_live(char *pipename, break; if (GetLastError() != ERROR_PIPE_BUSY) { - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL); g_snprintf(errmsg, errmsgl, "The capture session on \"%s\" could not be started " @@ -1937,7 +2071,7 @@ cap_pipe_open_live(char *pipename, } if (!WaitNamedPipe(utf_8to16(pipename), 30 * 1000)) { - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL); g_snprintf(errmsg, errmsgl, "The capture session on \"%s\" timed out during " @@ -1953,46 +2087,53 @@ cap_pipe_open_live(char *pipename, pcap_opts->from_cap_pipe = TRUE; + if ((pcap_opts->from_cap_socket) #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", g_strerror(errno)); - goto error; - } else if (sel_ret > 0) { - b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read); - if (b <= 0) { - if (b == 0) - g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open"); - else - g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s", - g_strerror(errno)); - goto error; - } - bytes_read += b; - } + || 1 +#endif + ) + { + /* 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", g_strerror(errno)); + goto error; + } else if (sel_ret > 0) { + b = cap_pipe_read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read, pcap_opts->from_cap_socket); + if (b <= 0) { + if (b == 0) + g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open"); + else + g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s", + g_strerror(errno)); + goto error; + } + bytes_read += b; + } + } } -#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; - pcap_opts->cap_pipe_bytes_to_read = sizeof(magic); - /* We don't have to worry about cap_pipe_read_mtx here */ - g_async_queue_push(pcap_opts->cap_pipe_pending_q, pcap_opts->cap_pipe_buf); - g_async_queue_pop(pcap_opts->cap_pipe_done_q); - if (pcap_opts->cap_pipe_bytes_read <= 0) { - if (pcap_opts->cap_pipe_bytes_read == 0) - g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open"); - else - g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s", - g_strerror(errno)); - goto error; +#ifdef _WIN32 + else { + g_thread_create(&cap_thread_read, pcap_opts, FALSE, NULL); + + pcap_opts->cap_pipe_buf = (char *) &magic; + pcap_opts->cap_pipe_bytes_read = 0; + pcap_opts->cap_pipe_bytes_to_read = sizeof(magic); + /* We don't have to worry about cap_pipe_read_mtx here */ + g_async_queue_push(pcap_opts->cap_pipe_pending_q, pcap_opts->cap_pipe_buf); + g_async_queue_pop(pcap_opts->cap_pipe_done_q); + if (pcap_opts->cap_pipe_bytes_read <= 0) { + if (pcap_opts->cap_pipe_bytes_read == 0) + g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open"); + else + g_snprintf(errmsg, errmsgl, "Error on pipe magic during open: %s", + g_strerror(errno)); + goto error; + } } - #endif switch (magic) { @@ -2032,42 +2173,50 @@ cap_pipe_open_live(char *pipename, goto error; } + if ((pcap_opts->from_cap_socket) #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", g_strerror(errno)); - goto error; - } else if (sel_ret > 0) { - b = read(fd, ((char *)hdr)+bytes_read, - sizeof(struct pcap_hdr) - bytes_read); - if (b <= 0) { - if (b == 0) - g_snprintf(errmsg, errmsgl, "End of file on pipe header during open"); - else - g_snprintf(errmsg, errmsgl, "Error on pipe header during open: %s", - g_strerror(errno)); - goto error; - } - bytes_read += b; - } + || 1 +#endif + ) + { + /* 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", g_strerror(errno)); + goto error; + } else if (sel_ret > 0) { + b = cap_pipe_read(fd, ((char *)hdr)+bytes_read, + sizeof(struct pcap_hdr) - bytes_read, pcap_opts->from_cap_socket); + if (b <= 0) { + if (b == 0) + g_snprintf(errmsg, errmsgl, "End of file on pipe header during open"); + else + g_snprintf(errmsg, errmsgl, "Error on pipe header during open: %s", + g_strerror(errno)); + goto error; + } + bytes_read += b; + } + } } -#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); - g_async_queue_push(pcap_opts->cap_pipe_pending_q, pcap_opts->cap_pipe_buf); - g_async_queue_pop(pcap_opts->cap_pipe_done_q); - if (pcap_opts->cap_pipe_bytes_read <= 0) { - if (pcap_opts->cap_pipe_bytes_read == 0) - 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", - g_strerror(errno)); - goto error; +#ifdef _WIN32 + 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); + g_async_queue_push(pcap_opts->cap_pipe_pending_q, pcap_opts->cap_pipe_buf); + g_async_queue_pop(pcap_opts->cap_pipe_done_q); + if (pcap_opts->cap_pipe_bytes_read <= 0) { + if (pcap_opts->cap_pipe_bytes_read == 0) + 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", + g_strerror(errno)); + goto error; + } } #endif @@ -2087,18 +2236,14 @@ cap_pipe_open_live(char *pipename, pcap_opts->cap_pipe_state = STATE_EXPECT_REC_HDR; pcap_opts->cap_pipe_err = PIPOK; -#ifndef _WIN32 pcap_opts->cap_pipe_fd = fd; -#endif return; error: g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: error %s", errmsg); pcap_opts->cap_pipe_err = PIPERR; -#ifndef _WIN32 - ws_close(fd); + cap_pipe_close(fd, pcap_opts->from_cap_socket); pcap_opts->cap_pipe_fd = -1; -#endif return; } @@ -2117,12 +2262,9 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er GTimeVal wait_time; #endif gpointer q_status; -#else - int b; -#endif -#ifdef _WIN32 wchar_t *err_str; #endif + int b; #ifdef LOG_CAPTURE_VERBOSE g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_dispatch"); @@ -2149,9 +2291,14 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er /* Fall through */ case STATE_READ_REC_HDR: + if ((pcap_opts->from_cap_socket) #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); + || 1 +#endif + ) + { + b = cap_pipe_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, pcap_opts->from_cap_socket); if (b <= 0) { if (b == 0) result = PD_PIPE_EOF; @@ -2160,7 +2307,10 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er break; } pcap_opts->cap_pipe_bytes_read += b; -#else + } +#ifdef _WIN32 + else + { #if GLIB_CHECK_VERSION(2,31,18) q_status = g_async_queue_timeout_pop(pcap_opts->cap_pipe_done_q, PIPE_READ_TIMEOUT); #else @@ -2178,6 +2328,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er if (!q_status) { return 0; } + } #endif if ((pcap_opts->cap_pipe_bytes_read) < pcap_opts->cap_pipe_bytes_to_read) return 0; @@ -2202,9 +2353,14 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er /* Fall through */ case STATE_READ_DATA: + if ((pcap_opts->from_cap_socket) #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); + || 1 +#endif + ) + { + b = cap_pipe_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, pcap_opts->from_cap_socket); if (b <= 0) { if (b == 0) result = PD_PIPE_EOF; @@ -2213,7 +2369,11 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er break; } pcap_opts->cap_pipe_bytes_read += b; -#else + } +#ifdef _WIN32 + else + { + #if GLIB_CHECK_VERSION(2,31,18) q_status = g_async_queue_timeout_pop(pcap_opts->cap_pipe_done_q, PIPE_READ_TIMEOUT); #else @@ -2231,6 +2391,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er if (!q_status) { return 0; } + } #endif if ((pcap_opts->cap_pipe_bytes_read) < pcap_opts->cap_pipe_bytes_to_read) return 0; @@ -2285,7 +2446,7 @@ cap_pipe_dispatch(loop_data *ld, pcap_options *pcap_opts, guchar *data, char *er case PD_PIPE_ERR: #ifdef _WIN32 - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL); g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s (error %d)", @@ -2400,13 +2561,13 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld, pcap_opts->linktype = -1; pcap_opts->ts_nsec = FALSE; pcap_opts->from_cap_pipe = FALSE; + pcap_opts->from_cap_socket = 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_fd = -1; pcap_opts->cap_pipe_modified = FALSE; pcap_opts->cap_pipe_byte_swapped = FALSE; #ifdef _WIN32 @@ -2564,13 +2725,12 @@ static void capture_loop_close_input(loop_data *ld) for (i = 0; i < ld->pcaps->len; 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); + cap_pipe_close(pcap_opts->cap_pipe_fd, pcap_opts->from_cap_socket); pcap_opts->cap_pipe_fd = -1; } -#else +#ifdef _WIN32 if (pcap_opts->cap_pipe_h != INVALID_HANDLE_VALUE) { CloseHandle(pcap_opts->cap_pipe_h); pcap_opts->cap_pipe_h = INVALID_HANDLE_VALUE; @@ -3772,8 +3932,10 @@ capture_loop_write_packet_cb(u_char *pcap_opts_p, const struct pcap_pkthdr *phdr /* We may be called multiple times from pcap_dispatch(); if we've set the "stop capturing" flag, ignore this packet, as we're not supposed to be saving any more packets. */ - if (!global_ld.go) + if (!global_ld.go) { + pcap_opts->dropped++; return; + } if (global_ld.pdh) { gboolean successful; @@ -3789,11 +3951,13 @@ capture_loop_write_packet_cb(u_char *pcap_opts_p, const struct pcap_pkthdr *phdr if (!successful) { global_ld.go = FALSE; global_ld.err = err; + pcap_opts->dropped++; } else { g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Wrote a packet of length %d captured on interface %u.", 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; @@ -3864,6 +4028,49 @@ capture_loop_queue_packet_cb(u_char *pcap_opts_p, const struct pcap_pkthdr *phdr pcap_queue_bytes, pcap_queue_packets); } +static int +set_80211_channel(const char *iface, const char *opt) +{ + int freq = 0, type, ret; + gchar **options = NULL; + options = g_strsplit_set(opt, ",", 2); + + if (options[0]) + freq = atoi(options[0]); + + if (options[1]) { + type = ws80211_str_to_chan_type(options[1]); + if (type == -1) { + ret = EINVAL; + goto out; + } + } + else + type = -1; + + ret = ws80211_init(); + if (ret) { + cmdarg_err("%d: Failed to init ws80211: %s\n", abs(ret), g_strerror(abs(ret))); + ret = 2; + goto out; + } + ret = ws80211_set_freq(iface, freq, type); + + if (ret) { + cmdarg_err("%d: Failed to set channel: %s\n", abs(ret), g_strerror(abs(ret))); + ret = 2; + goto out; + } + + if (capture_child) + pipe_write_block(2, SP_SUCCESS, NULL); + ret = 0; + +out: + g_strfreev(options); + return ret; +} + /* And now our feature presentation... [ fade to music ] */ int main(int argc, char *argv[]) @@ -3886,6 +4093,8 @@ main(int argc, char *argv[]) #ifdef HAVE_BPF_IMAGE gboolean print_bpf_code = FALSE; #endif + gboolean set_chan = FALSE; + gchar *set_chan_arg = NULL; gboolean machine_readable = FALSE; gboolean print_statistics = FALSE; int status, run_once_args = 0; @@ -3942,7 +4151,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 "MnpPq" OPTSTRING_r "Ss:t" OPTSTRING_u "vw:y:Z:" +#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:" OPTSTRING_d "Df:ghi:" OPTSTRING_I "k: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) { @@ -4296,6 +4505,11 @@ main(int argc, char *argv[]) print_statistics = TRUE; run_once_args++; break; + case 'k': /* Set wireless channel */ + set_chan = TRUE; + set_chan_arg = optarg; + run_once_args++; + break; case 'M': /* For -D, -L, and -S, print machine-readable output */ machine_readable = TRUE; break; @@ -4420,6 +4634,19 @@ main(int argc, char *argv[]) exit_main(status); } + if (set_chan) { + interface_options interface_opts; + + if (global_capture_opts.ifaces->len != 1) { + cmdarg_err("Need one interface"); + exit_main(2); + } + + interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, 0); + status = set_80211_channel(interface_opts.name, set_chan_arg); + exit_main(status); + } + /* * "-L", "-d", and capturing act on a particular interface, so we have to * have an interface; if none was specified, pick a default. @@ -4620,13 +4847,13 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level, static void -report_packet_count(int packet_count) +report_packet_count(unsigned int packet_count) { char tmp[SP_DECISIZE+1+1]; - static int count = 0; + static unsigned int count = 0; if(capture_child) { - g_snprintf(tmp, sizeof(tmp), "%d", packet_count); + g_snprintf(tmp, sizeof(tmp), "%u", packet_count); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp); pipe_write_block(2, SP_PACKET_COUNT, tmp); } else {