From 59386d5c6ab09de0a639b27a1d25607d59680844 Mon Sep 17 00:00:00 2001 From: randolphcyg Date: Wed, 22 May 2024 11:47:42 +0800 Subject: [PATCH] [IMP]upgrade wireshark dll --- README-zh.md | 6 +- README.md | 6 +- go.mod | 2 +- include/wireshark/capinfos.c | 1795 ----- include/wireshark/capture_opts.c | 1471 ---- include/wireshark/capture_opts.h | 425 -- include/wireshark/captype.c | 204 - include/wireshark/cli_main.c | 78 - include/wireshark/cli_main.h | 22 - include/wireshark/config.h | 10 +- include/wireshark/dftest.c | 457 -- include/wireshark/dumpcap.c | 6245 ----------------- include/wireshark/editcap.c | 2645 ------- include/wireshark/epan/CMakeLists.txt | 2 +- include/wireshark/epan/dfilter/scanner.l | 2 +- include/wireshark/epan/diam_dict.l | 2 +- .../epan/dissectors/asn1/nr-rrc/nr-rrc.cnf | 88 +- .../asn1/nr-rrc/packet-nr-rrc-template.c | 2 +- .../epan/dissectors/packet-5co-legacy.c | 16 +- .../epan/dissectors/packet-5co-rap.c | 18 +- .../wireshark/epan/dissectors/packet-btmesh.c | 13 +- .../epan/dissectors/packet-coseventcomm.c | 2 +- .../epan/dissectors/packet-cosnaming.c | 2 +- .../wireshark/epan/dissectors/packet-cql.c | 35 +- .../epan/dissectors/packet-docsis-macmgmt.c | 3 +- .../wireshark/epan/dissectors/packet-e212.c | 554 +- .../wireshark/epan/dissectors/packet-epl.c | 19 +- .../wireshark/epan/dissectors/packet-fcfzs.c | 16 +- .../wireshark/epan/dissectors/packet-gias.c | 2 +- .../wireshark/epan/dissectors/packet-gquic.c | 4 +- .../wireshark/epan/dissectors/packet-grpc.c | 137 +- .../epan/dissectors/packet-gsm_a_rp.c | 12 +- .../wireshark/epan/dissectors/packet-http2.c | 21 +- .../wireshark/epan/dissectors/packet-http2.h | 8 + .../wireshark/epan/dissectors/packet-icmpv6.c | 51 +- .../epan/dissectors/packet-ieee1905.c | 60 +- .../epan/dissectors/packet-ieee80211.c | 12 +- .../wireshark/epan/dissectors/packet-ipars.c | 2 +- .../epan/dissectors/packet-json_3gpp.c | 28 +- .../wireshark/epan/dissectors/packet-lapd.c | 8 +- .../wireshark/epan/dissectors/packet-lldp.c | 6 +- .../wireshark/epan/dissectors/packet-mongo.c | 8 +- .../epan/dissectors/packet-nas_5gs.c | 20 +- .../wireshark/epan/dissectors/packet-nr-rrc.c | 69 +- .../wireshark/epan/dissectors/packet-parlay.c | 56 +- .../wireshark/epan/dissectors/packet-per.c | 22 +- .../wireshark/epan/dissectors/packet-pfcp.c | 129 +- .../wireshark/epan/dissectors/packet-ptp.c | 2 +- .../wireshark/epan/dissectors/packet-quic.c | 8 + .../wireshark/epan/dissectors/packet-ssh.c | 3 +- .../wireshark/epan/dissectors/packet-tango.c | 2 +- .../wireshark/epan/dissectors/packet-tipc.c | 7 +- .../epan/dissectors/packet-tls-utils.c | 29 +- .../epan/dissectors/packet-zbee-direct.c | 6 +- .../epan/dissectors/packet-zbee-tlv.c | 10 +- include/wireshark/epan/dissectors/usb.c | 1 + include/wireshark/epan/dtd_grammar.lemon | 2 +- include/wireshark/epan/dtd_parse.l | 2 +- include/wireshark/epan/dtd_preparse.l | 2 +- include/wireshark/epan/enterprises.c | 234 +- include/wireshark/epan/manuf-data.c | 695 +- include/wireshark/epan/packet.c | 12 +- include/wireshark/epan/packet.h | 5 +- include/wireshark/epan/pci-ids.c | 596 +- .../wireshark/epan/protobuf_lang_parser.lemon | 2 +- .../wireshark/epan/protobuf_lang_scanner.l | 2 +- include/wireshark/epan/radius_dict.l | 2 +- include/wireshark/epan/services-data.c | 2 +- include/wireshark/epan/uat_load.l | 2 +- include/wireshark/epan/wslua/init_wslua.c | 34 +- .../epan/wslua/lrexlib/pcre2/lpcre2.c | 2 +- include/wireshark/epan/wslua/make-taps.py | 24 +- include/wireshark/epan/wslua/wslua.h | 4 + .../wireshark/epan/wslua/wslua_byte_array.c | 12 +- .../wireshark/epan/wslua/wslua_dissector.c | 53 +- include/wireshark/epan/wslua/wslua_field.c | 12 +- include/wireshark/epan/wslua/wslua_file.c | 6 +- .../wireshark/epan/wslua/wslua_file_handler.c | 8 +- .../wireshark/epan/wslua/wslua_frame_info.c | 8 +- include/wireshark/epan/wslua/wslua_int64.c | 2 +- include/wireshark/epan/wslua/wslua_pinfo.c | 2 +- include/wireshark/epan/wslua/wslua_pref.c | 4 +- include/wireshark/epan/wslua/wslua_proto.c | 4 +- include/wireshark/epan/wslua/wslua_struct.c | 10 +- include/wireshark/epan/wslua/wslua_tree.c | 10 +- include/wireshark/epan/wslua/wslua_tvb.c | 56 +- include/wireshark/epan/wslua/wslua_wtap.c | 10 +- include/wireshark/extcap.c | 2225 ------ include/wireshark/extcap.h | 272 - include/wireshark/extcap_parser.c | 1003 --- include/wireshark/extcap_parser.h | 226 - include/wireshark/file.c | 5443 -------------- include/wireshark/file.h | 734 -- include/wireshark/file_packet_provider.c | 93 - include/wireshark/fileset.c | 435 -- include/wireshark/fileset.h | 88 - include/wireshark/frame_tvbuff.c | 331 - include/wireshark/frame_tvbuff.h | 39 - include/wireshark/globals.h | 41 - include/wireshark/mergecap.c | 428 -- include/wireshark/mmdbresolve.c | 203 - include/wireshark/randpkt.c | 319 - include/wireshark/rawshark.c | 1521 ---- include/wireshark/reordercap.c | 391 -- include/wireshark/ringbuffer.c | 597 -- include/wireshark/ringbuffer.h | 39 - include/wireshark/sharkd.c | 758 -- include/wireshark/sharkd.h | 73 - include/wireshark/sharkd_daemon.c | 475 -- include/wireshark/sharkd_session.c | 5926 ---------------- include/wireshark/sync_pipe.h | 97 - include/wireshark/sync_pipe_write.c | 141 - include/wireshark/text2pcap.c | 1081 --- include/wireshark/text2pcap.h | 43 - include/wireshark/tfshark.c | 2100 ------ include/wireshark/tshark.c | 4888 ------------- include/wireshark/wiretap/CMakeLists.txt | 2 +- include/wireshark/wiretap/ascend_scanner.l | 2 +- include/wireshark/wiretap/blf.c | 191 +- include/wireshark/wiretap/blf.h | 28 +- .../wireshark/wiretap/busmaster_parser.lemon | 2 +- include/wireshark/wiretap/busmaster_scanner.l | 4 +- .../wireshark/wiretap/candump_parser.lemon | 2 +- include/wireshark/wiretap/candump_scanner.l | 4 +- include/wireshark/wiretap/file_access.c | 2 +- include/wireshark/wiretap/k12text.l | 2 +- include/wireshark/wiretap/pcapng.c | 112 +- include/wireshark/wiretap/wtap.h | 3 +- include/wireshark/wiretap/wtap_opttypes.c | 26 + include/wireshark/wiretap/wtap_opttypes.h | 23 + include/wireshark/ws_version.h | 2 +- include/wireshark/wsutil/cpu_info.c | 3 +- 132 files changed, 2766 insertions(+), 44334 deletions(-) delete mode 100644 include/wireshark/capinfos.c delete mode 100644 include/wireshark/capture_opts.c delete mode 100644 include/wireshark/capture_opts.h delete mode 100644 include/wireshark/captype.c delete mode 100644 include/wireshark/cli_main.c delete mode 100644 include/wireshark/cli_main.h delete mode 100644 include/wireshark/dftest.c delete mode 100644 include/wireshark/dumpcap.c delete mode 100644 include/wireshark/editcap.c delete mode 100644 include/wireshark/extcap.c delete mode 100644 include/wireshark/extcap.h delete mode 100644 include/wireshark/extcap_parser.c delete mode 100644 include/wireshark/extcap_parser.h delete mode 100644 include/wireshark/file.c delete mode 100644 include/wireshark/file.h delete mode 100644 include/wireshark/file_packet_provider.c delete mode 100644 include/wireshark/fileset.c delete mode 100644 include/wireshark/fileset.h delete mode 100644 include/wireshark/frame_tvbuff.c delete mode 100644 include/wireshark/frame_tvbuff.h delete mode 100644 include/wireshark/globals.h delete mode 100644 include/wireshark/mergecap.c delete mode 100644 include/wireshark/mmdbresolve.c delete mode 100644 include/wireshark/randpkt.c delete mode 100644 include/wireshark/rawshark.c delete mode 100644 include/wireshark/reordercap.c delete mode 100644 include/wireshark/ringbuffer.c delete mode 100644 include/wireshark/ringbuffer.h delete mode 100644 include/wireshark/sharkd.c delete mode 100644 include/wireshark/sharkd.h delete mode 100644 include/wireshark/sharkd_daemon.c delete mode 100644 include/wireshark/sharkd_session.c delete mode 100644 include/wireshark/sync_pipe.h delete mode 100644 include/wireshark/sync_pipe_write.c delete mode 100644 include/wireshark/text2pcap.c delete mode 100644 include/wireshark/text2pcap.h delete mode 100644 include/wireshark/tfshark.c delete mode 100644 include/wireshark/tshark.c diff --git a/README-zh.md b/README-zh.md index 3ebda7c0..b462218d 100644 --- a/README-zh.md +++ b/README-zh.md @@ -122,10 +122,10 @@ gowireshark │   ├── libpcap.so.1 │   ├── libwireshark.so │   ├── libwireshark.so.17 -│   ├── libwireshark.so.17.0.4 +│   ├── libwireshark.so.17.0.5 │   ├── libwiretap.so │   ├── libwiretap.so.14 -│   ├── libwiretap.so.14.1.4 +│   ├── libwiretap.so.14.1.5 │   ├── libwsutil.so │   ├── libwsutil.so.15 │   └── libwsutil.so.15.0.0 @@ -179,7 +179,7 @@ graph LR ```shell # 确定最新发行版本并设置环境变量 -export WIRESHARKV=4.2.4 +export WIRESHARKV=4.2.5 # 到/opt目录下操作 cd /opt/ # 下载源码 diff --git a/README.md b/README.md index 780fd64f..da003a85 100644 --- a/README.md +++ b/README.md @@ -123,10 +123,10 @@ gowireshark │   ├── libpcap.so.1 │   ├── libwireshark.so │   ├── libwireshark.so.17 -│   ├── libwireshark.so.17.0.4 +│   ├── libwireshark.so.17.0.5 │   ├── libwiretap.so │   ├── libwiretap.so.14 -│   ├── libwiretap.so.14.1.4 +│   ├── libwiretap.so.14.1.5 │   ├── libwsutil.so │   ├── libwsutil.so.15 │   └── libwsutil.so.15.0.0 @@ -185,7 +185,7 @@ Note that some interfaces in this project may not be valid if the wireshark vers ```shell # Determine the latest release version and set environment variables -export WIRESHARKV=4.2.4 +export WIRESHARKV=4.2.5 # Operate in the /opt directory cd /opt/ # Download the source code diff --git a/go.mod b/go.mod index dd252331..ed17963e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/randolphcyg/gowireshark -go 1.22.2 +go 1.22.3 require ( github.com/pkg/errors v0.9.1 diff --git a/include/wireshark/capinfos.c b/include/wireshark/capinfos.c deleted file mode 100644 index 286532d0..00000000 --- a/include/wireshark/capinfos.c +++ /dev/null @@ -1,1795 +0,0 @@ -/* capinfos.c - * Reports capture file information including # of packets, duration, others - * - * Copyright 2004 Ian Schorr - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -/* - * 2009-09-19: jyoung - * - * New capinfos features - * - * Continue processing additional files after - * a wiretap open failure. The new -C option - * reverts to capinfos' original behavior which - * is to cancel any further file processing at - * first file open failure. - * - * Change the behavior of how the default display - * of all infos is initiated. This gets rid of a - * special post getopt() argument count test. - * - * Add new table output format (with related options) - * This feature allows outputting the various infos - * into a tab delimited text file, or to a comma - * separated variables file (*.csv) instead of the - * original "long" format. - * - * 2011-04-05: wmeier - * behaviour changed: Upon exit capinfos will return - * an error status if an error occurred at any - * point during "continuous" file processing. - * (Previously a success status was always - * returned if the -C option was not used). - * - */ - - -#include -#define WS_LOG_DOMAIN LOG_DOMAIN_MAIN - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_PLUGINS -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include "ui/failure_message.h" - -/* - * By default capinfos now continues processing - * the next filename if and when wiretap detects - * a problem opening or reading a file. - * Use the '-C' option to revert back to original - * capinfos behavior which is to abort any - * additional file processing at the first file - * open or read failure. - */ - -static gboolean stop_after_failure = FALSE; - -/* - * table report variables - */ - -static gboolean long_report = TRUE; /* By default generate long report */ -static gchar table_report_header = TRUE; /* Generate column header by default */ -static gchar field_separator = '\t'; /* Use TAB as field separator by default */ -static gchar quote_char = '\0'; /* Do NOT quote fields by default */ -static gboolean machine_readable = FALSE; /* Display machine-readable numbers */ - -/* - * capinfos has the ability to report on a number of - * various characteristics ("infos") for each input file. - * - * By default reporting of all info fields is enabled. - * - * Optionally the reporting of any specific info field - * or combination of info fields can be enabled with - * individual options. - */ - -static gboolean report_all_infos = TRUE; /* Report all infos */ - -static gboolean cap_file_type = TRUE; /* Report capture type */ -static gboolean cap_file_encap = TRUE; /* Report encapsulation */ -static gboolean cap_snaplen = TRUE; /* Packet size limit (snaplen)*/ -static gboolean cap_packet_count = TRUE; /* Report packet count */ -static gboolean cap_file_size = TRUE; /* Report file size */ -static gboolean cap_comment = TRUE; /* Display the capture comment */ -static gboolean cap_file_more_info = TRUE; /* Report more file info */ -static gboolean cap_file_idb = TRUE; /* Report Interface info */ -static gboolean cap_file_nrb = TRUE; /* Report Name Resolution Block info */ -static gboolean cap_file_dsb = TRUE; /* Report Decryption Secrets Block info */ - -static gboolean cap_data_size = TRUE; /* Report packet byte size */ -static gboolean cap_duration = TRUE; /* Report capture duration */ -static gboolean cap_start_time = TRUE; /* Report capture start time */ -static gboolean cap_end_time = TRUE; /* Report capture end time */ -static gboolean time_as_secs = FALSE; /* Report time values as raw seconds */ - -static gboolean cap_data_rate_byte = TRUE; /* Report data rate bytes/sec */ -static gboolean cap_data_rate_bit = TRUE; /* Report data rate bites/sec */ -static gboolean cap_packet_size = TRUE; /* Report average packet size */ -static gboolean cap_packet_rate = TRUE; /* Report average packet rate */ -static gboolean cap_order = TRUE; /* Report if packets are in chronological order (True/False) */ -static gboolean pkt_comments = TRUE; /* Report individual packet comments */ - -static gboolean cap_file_hashes = TRUE; /* Calculate file hashes */ - -// Strongest to weakest -#define HASH_SIZE_SHA256 32 -#define HASH_SIZE_SHA1 20 - -#define HASH_STR_SIZE (65) /* Max hash size * 2 + '\0' */ -#define HASH_BUF_SIZE (1024 * 1024) - - -static gchar file_sha256[HASH_STR_SIZE]; -static gchar file_sha1[HASH_STR_SIZE]; - -static char *hash_buf = NULL; -static gcry_md_hd_t hd = NULL; - -static guint num_ipv4_addresses; -static guint num_ipv6_addresses; -static guint num_decryption_secrets; - -/* - * If we have at least two packets with time stamps, and they're not in - * order - i.e., the later packet has a time stamp older than the earlier - * packet - the time stamps are known not to be in order. - * - * If every packet has a time stamp, and they're all in order, the time - * stamp is known to be in order. - * - * Otherwise, we have no idea. - */ -typedef enum { - IN_ORDER, - NOT_IN_ORDER, - ORDER_UNKNOWN -} order_t; - -typedef struct _pkt_cmt { - int recno; - gchar *cmt; - struct _pkt_cmt *next; -} pkt_cmt; - -typedef struct _capture_info { - const char *filename; - guint16 file_type; - wtap_compression_type compression_type; - int file_encap; - int file_tsprec; - wtap *wth; - gint64 filesize; - guint64 packet_bytes; - gboolean times_known; - nstime_t start_time; - int start_time_tsprec; - nstime_t stop_time; - int stop_time_tsprec; - guint32 packet_count; - gboolean snap_set; /* If set in capture file header */ - guint32 snaplen; /* value from the capture file header */ - guint32 snaplen_min_inferred; /* If caplen < len for 1 or more rcds */ - guint32 snaplen_max_inferred; /* ... */ - gboolean drops_known; - guint32 drop_count; - - nstime_t duration; - int duration_tsprec; - double packet_rate; - double packet_size; - double data_rate; /* in bytes/s */ - gboolean know_order; - order_t order; - - int *encap_counts; /* array of per_packet encap counts; array has one entry per wtap_encap type */ - pkt_cmt *pkt_cmts; /* list of packet comments */ - - guint num_interfaces; /* number of IDBs, and thus size of interface_packet_counts array */ - GArray *interface_packet_counts; /* array of per_packet interface_id counts; one entry per file IDB */ - guint32 pkt_interface_id_unknown; /* counts if packet interface_id didn't match a known one */ - GArray *idb_info_strings; /* array of IDB info strings */ -} capture_info; - -static char *decimal_point; - -static void -enable_all_infos(void) -{ - report_all_infos = TRUE; - - cap_file_type = TRUE; - cap_file_encap = TRUE; - cap_snaplen = TRUE; - cap_packet_count = TRUE; - cap_file_size = TRUE; - cap_comment = TRUE; - pkt_comments = TRUE; - cap_file_more_info = TRUE; - cap_file_idb = TRUE; - cap_file_nrb = TRUE; - cap_file_dsb = TRUE; - - cap_data_size = TRUE; - cap_duration = TRUE; - cap_start_time = TRUE; - cap_end_time = TRUE; - cap_order = TRUE; - - cap_data_rate_byte = TRUE; - cap_data_rate_bit = TRUE; - cap_packet_size = TRUE; - cap_packet_rate = TRUE; - - cap_file_hashes = TRUE; -} - -static void -disable_all_infos(void) -{ - report_all_infos = FALSE; - - cap_file_type = FALSE; - cap_file_encap = FALSE; - cap_snaplen = FALSE; - cap_packet_count = FALSE; - cap_file_size = FALSE; - cap_comment = FALSE; - pkt_comments = FALSE; - cap_file_more_info = FALSE; - cap_file_idb = FALSE; - cap_file_nrb = FALSE; - cap_file_dsb = FALSE; - - cap_data_size = FALSE; - cap_duration = FALSE; - cap_start_time = FALSE; - cap_end_time = FALSE; - cap_order = FALSE; - - cap_data_rate_byte = FALSE; - cap_data_rate_bit = FALSE; - cap_packet_size = FALSE; - cap_packet_rate = FALSE; - - cap_file_hashes = FALSE; -} - -static const gchar * -order_string(order_t order) -{ - switch (order) { - - case IN_ORDER: - return "True"; - - case NOT_IN_ORDER: - return "False"; - - case ORDER_UNKNOWN: - return "Unknown"; - - default: - return "???"; /* "cannot happen" (the next step is "Profit!") */ - } -} - -static gchar * -absolute_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info) -{ - /* - * https://web.archive.org/web/20120513133703/http://www.idrbt.ac.in/publications/workingpapers/Working%20Paper%20No.%209.pdf - * - * says: - * - * A 64-bit Unix time would be safe for the indefinite future, as - * this variable would not overflow until 2**63 or - * 9,223,372,036,854,775,808 (over nine quintillion) seconds - * after the beginning of the Unix epoch - corresponding to - * GMT 15:30:08, Sunday, 4th December, 292,277,026,596. - * - * So, if we're displaying the time as YYYY-MM-DD HH:MM:SS.SSSSSSSSS, - * we'll have the buffer be large enough for a date of the format - * 292277026596-MM-DD HH:MM:SS.SSSSSSSSS, which is the biggest value - * you'll get with a 64-bit time_t and a nanosecond-resolution - * fraction-of-a-second. - * - * That's 12+1+2+1+2+1+2+1+2+2+2+1+9+1, including the terminating - * \0, or 39. - * - * If we're displaying the time as epoch time, and the time is - * unsigned, 2^64-1 is 18446744073709551615, so the buffer has - * to be big enough for 18446744073709551615.999999999. That's - * 20+1+9+1, including the terminating '\0', or 31. If it's - * signed, 2^63 is 9223372036854775808, so the buffer has to - * be big enough for -9223372036854775808.999999999, which is - * again 20+1+9+1, or 31. - * - * So we go with 39. - */ - static gchar time_string_buf[39]; - - if (cf_info->times_known && cf_info->packet_count > 0) { - if (time_as_secs) { - display_epoch_time(time_string_buf, sizeof time_string_buf, timer, tsprecision); - } else { - format_nstime_as_iso8601(time_string_buf, sizeof time_string_buf, timer, decimal_point, TRUE, tsprecision); - } - } else { - snprintf(time_string_buf, sizeof time_string_buf, "n/a"); - } - return time_string_buf; -} - -static gchar * -relative_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info, gboolean want_seconds) -{ - const gchar *second = want_seconds ? " second" : ""; - const gchar *plural = want_seconds ? "s" : ""; - /* - * If we're displaying the time as epoch time, and the time is - * unsigned, 2^64-1 is 18446744073709551615, so the buffer has - * to be big enough for "18446744073709551615.999999999 seconds". - * That's 20+1+9+1+7+1, including the terminating '\0', or 39. - * If it'ssigned, 2^63 is 9223372036854775808, so the buffer has to - * be big enough for "-9223372036854775808.999999999 seconds", - * which is again 20+1+9+1+7+1, or 39. - */ - static gchar time_string_buf[39]; - - if (cf_info->times_known && cf_info->packet_count > 0) { - char *ptr; - size_t remaining; - int num_bytes; - - ptr = time_string_buf; - remaining = sizeof time_string_buf; - num_bytes = snprintf(ptr, remaining, - "%"PRId64, - (gint64)timer->secs); - if (num_bytes < 0) { - /* - * That got an error. - * Not much else we can do. - */ - snprintf(ptr, remaining, "snprintf() failed"); - return time_string_buf; - } - if ((unsigned int)num_bytes >= remaining) { - /* - * That filled up or would have overflowed the buffer. - * Nothing more we can do. - */ - return time_string_buf; - } - ptr += num_bytes; - remaining -= num_bytes; - - if (tsprecision != 0) { - /* - * Append the fractional part. - */ - num_bytes = format_fractional_part_nsecs(ptr, remaining, timer->nsecs, decimal_point, tsprecision); - if ((unsigned int)num_bytes >= remaining) { - /* - * That filled up or would have overflowed the buffer. - * Nothing more we can do. - */ - return time_string_buf; - } - ptr += num_bytes; - remaining -= num_bytes; - } - - /* - * Append the units. - */ - snprintf(ptr, remaining, "%s%s", - second, - timer->secs == 1 ? "" : plural); - - return time_string_buf; - } - - snprintf(time_string_buf, sizeof time_string_buf, "n/a"); - return time_string_buf; -} - -static void print_value(const gchar *text_p1, gint width, const gchar *text_p2, double value) -{ - if (value > 0.0) - printf("%s%.*f%s\n", text_p1, width, value, text_p2); - else - printf("%sn/a\n", text_p1); -} - -/* multi-line comments would conflict with the formatting that capinfos uses - we replace linefeeds with spaces */ -static void -string_replace_newlines(gchar *str) -{ - gchar *p; - - if (str) { - p = str; - while (*p != '\0') { - if (*p == '\n') - *p = ' '; - if (*p == '\r') - *p = ' '; - p++; - } - } -} - -static void -show_option_string(const char *prefix, const char *option_str) -{ - char *str; - - if (option_str != NULL && option_str[0] != '\0') { - str = g_strdup(option_str); - string_replace_newlines(str); - printf("%s%s\n", prefix, str); - g_free(str); - } -} - -static void -print_stats(const gchar *filename, capture_info *cf_info) -{ - const gchar *file_type_string, *file_encap_string; - gchar *size_string; - pkt_cmt *p, *prev; - - /* Build printable strings for various stats */ - if (machine_readable) { - file_type_string = wtap_file_type_subtype_name(cf_info->file_type); - file_encap_string = wtap_encap_name(cf_info->file_encap); - } - else { - file_type_string = wtap_file_type_subtype_description(cf_info->file_type); - file_encap_string = wtap_encap_description(cf_info->file_encap); - } - - if (filename) printf ("File name: %s\n", filename); - if (cap_file_type) { - const char *compression_type_description; - compression_type_description = wtap_compression_type_description(cf_info->compression_type); - if (compression_type_description == NULL) - printf ("File type: %s\n", - file_type_string); - else - printf ("File type: %s (%s)\n", - file_type_string, compression_type_description); - } - if (cap_file_encap) { - printf ("File encapsulation: %s\n", file_encap_string); - if (cf_info->file_encap == WTAP_ENCAP_PER_PACKET) { - int i; - printf ("Encapsulation in use by packets (# of pkts):\n"); - for (i=0; iencap_counts[i] > 0) - printf(" %s (%d)\n", - wtap_encap_description(i), cf_info->encap_counts[i]); - } - } - } - if (cap_file_more_info) { - printf ("File timestamp precision: %s (%d)\n", - wtap_tsprec_string(cf_info->file_tsprec), cf_info->file_tsprec); - } - - if (cap_snaplen && cf_info->snap_set) - printf ("Packet size limit: file hdr: %u bytes\n", cf_info->snaplen); - else if (cap_snaplen && !cf_info->snap_set) - printf ("Packet size limit: file hdr: (not set)\n"); - if (cf_info->snaplen_max_inferred > 0) { - if (cf_info->snaplen_min_inferred == cf_info->snaplen_max_inferred) - printf ("Packet size limit: inferred: %u bytes\n", cf_info->snaplen_min_inferred); - else - printf ("Packet size limit: inferred: %u bytes - %u bytes (range)\n", - cf_info->snaplen_min_inferred, cf_info->snaplen_max_inferred); - } - if (cap_packet_count) { - printf ("Number of packets: "); - if (machine_readable) { - printf ("%u\n", cf_info->packet_count); - } else { - size_string = format_size(cf_info->packet_count, FORMAT_SIZE_UNIT_NONE, 0); - printf ("%s\n", size_string); - g_free(size_string); - } - } - if (cap_file_size) { - printf ("File size: "); - if (machine_readable) { - printf ("%" PRId64 " bytes\n", cf_info->filesize); - } else { - size_string = format_size(cf_info->filesize, FORMAT_SIZE_UNIT_BYTES, 0); - printf ("%s\n", size_string); - g_free(size_string); - } - } - if (cap_data_size) { - printf ("Data size: "); - if (machine_readable) { - printf ("%" PRIu64 " bytes\n", cf_info->packet_bytes); - } else { - size_string = format_size(cf_info->packet_bytes, FORMAT_SIZE_UNIT_BYTES, 0); - printf ("%s\n", size_string); - g_free(size_string); - } - } - if (cf_info->times_known) { - if (cap_duration) /* XXX - shorten to hh:mm:ss */ - printf("Capture duration: %s\n", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, TRUE)); - if (cap_start_time) - printf("First packet time: %s\n", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info)); - if (cap_end_time) - printf("Last packet time: %s\n", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info)); - if (cap_data_rate_byte) { - printf("Data byte rate: "); - if (machine_readable) { - print_value("", 2, " bytes/sec", cf_info->data_rate); - } else { - size_string = format_size((int64_t)cf_info->data_rate, FORMAT_SIZE_UNIT_BYTES_S, 0); - printf ("%s\n", size_string); - g_free(size_string); - } - } - if (cap_data_rate_bit) { - printf("Data bit rate: "); - if (machine_readable) { - print_value("", 2, " bits/sec", cf_info->data_rate*8); - } else { - size_string = format_size((int64_t)(cf_info->data_rate*8), FORMAT_SIZE_UNIT_BITS_S, 0); - printf ("%s\n", size_string); - g_free(size_string); - } - } - } - if (cap_packet_size) printf("Average packet size: %.2f bytes\n", cf_info->packet_size); - if (cf_info->times_known) { - if (cap_packet_rate) { - printf("Average packet rate: "); - if (machine_readable) { - print_value("", 2, " packets/sec", cf_info->packet_rate); - } else { - size_string = format_size((int64_t)cf_info->packet_rate, FORMAT_SIZE_UNIT_PACKETS_S, 0); - printf ("%s\n", size_string); - g_free(size_string); - } - } - } - if (cap_file_hashes) { - printf ("SHA256: %s\n", file_sha256); - printf ("SHA1: %s\n", file_sha1); - } - if (cap_order) printf ("Strict time order: %s\n", order_string(cf_info->order)); - - gboolean has_multiple_sections = (wtap_file_get_num_shbs(cf_info->wth) > 1); - - for (guint section_number = 0; - section_number < wtap_file_get_num_shbs(cf_info->wth); - section_number++) { - wtap_block_t shb; - - // If we have more than one section, add headers for each section. - if (has_multiple_sections) - printf("Section %u:\n\n", section_number); - - shb = wtap_file_get_shb(cf_info->wth, section_number); - if (shb != NULL) { - if (cap_file_more_info) { - char *str; - - if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS) - show_option_string("Capture hardware: ", str); - if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS) - show_option_string("Capture oper-sys: ", str); - if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS) - show_option_string("Capture application: ", str); - } - if (cap_comment) { - unsigned int i; - char *str; - - for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &str) == WTAP_OPTTYPE_SUCCESS; i++) { - show_option_string("Capture comment: ", str); - } - } - - if (pkt_comments && cf_info->pkt_cmts != NULL) { - for (p = cf_info->pkt_cmts; p != NULL; prev = p, p = p->next, g_free(prev)) { - if (machine_readable){ - printf("Packet %d Comment: %s\n", p->recno, g_strescape(p->cmt, NULL)); - } else { - printf("Packet %d Comment: %s\n", p->recno, p->cmt); - } - g_free(p->cmt); - } - } - - if (cap_file_idb && cf_info->num_interfaces != 0) { - guint i; - ws_assert(cf_info->num_interfaces == cf_info->idb_info_strings->len); - printf ("Number of interfaces in file: %u\n", cf_info->num_interfaces); - for (i = 0; i < cf_info->idb_info_strings->len; i++) { - gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i); - guint32 packet_count = 0; - if (i < cf_info->interface_packet_counts->len) - packet_count = g_array_index(cf_info->interface_packet_counts, guint32, i); - printf ("Interface #%u info:\n", i); - printf ("%s", s); - printf (" Number of packets = %u\n", packet_count); - } - } - } - - if (cap_file_nrb) { - if (num_ipv4_addresses != 0) - printf ("Number of resolved IPv4 addresses in file: %u\n", num_ipv4_addresses); - if (num_ipv6_addresses != 0) - printf ("Number of resolved IPv6 addresses in file: %u\n", num_ipv6_addresses); - } - if (cap_file_dsb) { - if (num_decryption_secrets != 0) - printf ("Number of decryption secrets in file: %u\n", num_decryption_secrets); - } - } -} - -static void -putsep(void) -{ - if (field_separator) putchar(field_separator); -} - -static void -putquote(void) -{ - if (quote_char) putchar(quote_char); -} - -static void -print_stats_table_header_label(const gchar *label) -{ - putsep(); - putquote(); - printf("%s", label); - putquote(); -} - -static void -print_stats_table_header(capture_info *cf_info) -{ - pkt_cmt *p; - char *buf; - - putquote(); - printf("File name"); - putquote(); - - if (cap_file_type) print_stats_table_header_label("File type"); - if (cap_file_encap) print_stats_table_header_label("File encapsulation"); - if (cap_file_more_info) print_stats_table_header_label("File time precision"); - if (cap_snaplen) { - print_stats_table_header_label("Packet size limit"); - print_stats_table_header_label("Packet size limit min (inferred)"); - print_stats_table_header_label("Packet size limit max (inferred)"); - } - if (cap_packet_count) print_stats_table_header_label("Number of packets"); - if (cap_file_size) print_stats_table_header_label("File size (bytes)"); - if (cap_data_size) print_stats_table_header_label("Data size (bytes)"); - if (cap_duration) print_stats_table_header_label("Capture duration (seconds)"); - if (cap_start_time) print_stats_table_header_label("Start time"); - if (cap_end_time) print_stats_table_header_label("End time"); - if (cap_data_rate_byte) print_stats_table_header_label("Data byte rate (bytes/sec)"); - if (cap_data_rate_bit) print_stats_table_header_label("Data bit rate (bits/sec)"); - if (cap_packet_size) print_stats_table_header_label("Average packet size (bytes)"); - if (cap_packet_rate) print_stats_table_header_label("Average packet rate (packets/sec)"); - if (cap_file_hashes) { - print_stats_table_header_label("SHA256"); - print_stats_table_header_label("SHA1"); - } - if (cap_order) print_stats_table_header_label("Strict time order"); - if (cap_file_more_info) { - print_stats_table_header_label("Capture hardware"); - print_stats_table_header_label("Capture oper-sys"); - print_stats_table_header_label("Capture application"); - } - if (cap_comment) print_stats_table_header_label("Capture comment"); - - if (pkt_comments && cf_info->pkt_cmts != NULL) { - /* Packet 2^64 Comment" + NULL */ - buf = (char *)g_malloc0(strlen("Packet 18446744073709551616 Comment") + 1); - - for (p = cf_info->pkt_cmts; p != NULL; p = p->next) { - snprintf(buf, strlen(buf), "Packet %d Comment", p->recno); - print_stats_table_header_label(buf); - } - } - - printf("\n"); -} - -static void -print_stats_table(const gchar *filename, capture_info *cf_info) -{ - const gchar *file_type_string, *file_encap_string; - pkt_cmt *p, *prev; - - /* Build printable strings for various stats */ - file_type_string = wtap_file_type_subtype_name(cf_info->file_type); - file_encap_string = wtap_encap_name(cf_info->file_encap); - - if (filename) { - putquote(); - printf("%s", filename); - putquote(); - } - - if (cap_file_type) { - putsep(); - putquote(); - printf("%s", file_type_string); - putquote(); - } - - /* ToDo: If WTAP_ENCAP_PER_PACKET, show the list of encapsulations encountered; - * Output a line for each different encap with all fields repeated except - * the encapsulation field which has "Per Packet: ..." for each - * encapsulation type seen ? - */ - if (cap_file_encap) { - putsep(); - putquote(); - printf("%s", file_encap_string); - putquote(); - } - - if (cap_file_more_info) { - putsep(); - putquote(); - printf("%s", wtap_tsprec_string(cf_info->file_tsprec)); - putquote(); - } - - if (cap_snaplen) { - putsep(); - putquote(); - if (cf_info->snap_set) - printf("%u", cf_info->snaplen); - else - printf("(not set)"); - putquote(); - if (cf_info->snaplen_max_inferred > 0) { - putsep(); - putquote(); - printf("%u", cf_info->snaplen_min_inferred); - putquote(); - putsep(); - putquote(); - printf("%u", cf_info->snaplen_max_inferred); - putquote(); - } - else { - putsep(); - putquote(); - printf("n/a"); - putquote(); - putsep(); - putquote(); - printf("n/a"); - putquote(); - } - } - - if (cap_packet_count) { - putsep(); - putquote(); - printf("%u", cf_info->packet_count); - putquote(); - } - - if (cap_file_size) { - putsep(); - putquote(); - printf("%" PRId64, cf_info->filesize); - putquote(); - } - - if (cap_data_size) { - putsep(); - putquote(); - printf("%" PRIu64, cf_info->packet_bytes); - putquote(); - } - - if (cap_duration) { - putsep(); - putquote(); - printf("%s", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, FALSE)); - putquote(); - } - - if (cap_start_time) { - putsep(); - putquote(); - printf("%s", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info)); - putquote(); - } - - if (cap_end_time) { - putsep(); - putquote(); - printf("%s", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info)); - putquote(); - } - - if (cap_data_rate_byte) { - putsep(); - putquote(); - if (cf_info->times_known) - printf("%.2f", cf_info->data_rate); - else - printf("n/a"); - putquote(); - } - - if (cap_data_rate_bit) { - putsep(); - putquote(); - if (cf_info->times_known) - printf("%.2f", cf_info->data_rate*8); - else - printf("n/a"); - putquote(); - } - - if (cap_packet_size) { - putsep(); - putquote(); - printf("%.2f", cf_info->packet_size); - putquote(); - } - - if (cap_packet_rate) { - putsep(); - putquote(); - if (cf_info->times_known) - printf("%.2f", cf_info->packet_rate); - else - printf("n/a"); - putquote(); - } - - if (cap_file_hashes) { - putsep(); - putquote(); - printf("%s", file_sha256); - putquote(); - - putsep(); - putquote(); - printf("%s", file_sha1); - putquote(); - } - - if (cap_order) { - putsep(); - putquote(); - printf("%s", order_string(cf_info->order)); - putquote(); - } - - for (guint section_number = 0; - section_number < wtap_file_get_num_shbs(cf_info->wth); - section_number++) { - wtap_block_t shb; - - shb = wtap_file_get_shb(cf_info->wth, section_number); - if (cap_file_more_info) { - char *str; - - putsep(); - putquote(); - if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS) { - printf("%s", str); - } - putquote(); - - putsep(); - putquote(); - if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS) { - printf("%s", str); - } - putquote(); - - putsep(); - putquote(); - if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS) { - printf("%s", str); - } - putquote(); - } - - /* - * One might argue that the following is silly to put into a table format, - * but oh well note that there may be *more than one* of each of these types - * of options. To mitigate some of the potential silliness the if(cap_comment) - * block is moved AFTER the if(cap_file_more_info) block. This will make any - * comments the last item(s) in each row. We now have a new -K option to - * disable cap_comment to more easily manage the potential silliness. - * Potential silliness includes multiple comments (therefore resulting in - * more than one additional column and/or comments with embedded newlines - * and/or possible delimiters). - * - * To mitigate embedded newlines and other special characters, use -M - */ - if (cap_comment) { - unsigned int i; - char *opt_comment; - gboolean have_cap = FALSE; - - for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &opt_comment) == WTAP_OPTTYPE_SUCCESS; i++) { - have_cap = TRUE; - putsep(); - putquote(); - if (machine_readable){ - printf("%s", g_strescape(opt_comment, NULL)); - } else { - printf("%s", opt_comment); - } - putquote(); - } - if(!have_cap) { - /* Maintain column alignment when we have no OPT_COMMENT */ - putsep(); - putquote(); - putquote(); - } - } - - } - - if (pkt_comments && cf_info->pkt_cmts != NULL) { - for(p = cf_info->pkt_cmts; p != NULL; prev = p, p = p->next, g_free(prev)) { - putsep(); - putquote(); - if (machine_readable) { - printf("%s", g_strescape(p->cmt, NULL)); - } else { - printf("%s", p->cmt); - } - g_free(p->cmt); - putquote(); - } - } - - printf("\n"); -} - -static void -cleanup_capture_info(capture_info *cf_info) -{ - guint i; - ws_assert(cf_info != NULL); - - g_free(cf_info->encap_counts); - cf_info->encap_counts = NULL; - - g_array_free(cf_info->interface_packet_counts, TRUE); - cf_info->interface_packet_counts = NULL; - - if (cf_info->idb_info_strings) { - for (i = 0; i < cf_info->idb_info_strings->len; i++) { - gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i); - g_free(s); - } - g_array_free(cf_info->idb_info_strings, TRUE); - } - cf_info->idb_info_strings = NULL; -} - -static void -count_ipv4_address(const guint addr _U_, const gchar *name _U_, const gboolean static_entry _U_) -{ - num_ipv4_addresses++; -} - -static void -count_ipv6_address(const void *addrp _U_, const gchar *name _U_, const gboolean static_entry _U_) -{ - num_ipv6_addresses++; -} - -static void -count_decryption_secret(guint32 secrets_type _U_, const void *secrets _U_, guint size _U_) -{ - /* XXX - count them based on the secrets type (which is an opaque code, - not a small integer)? */ - num_decryption_secrets++; -} - -static void -hash_to_str(const unsigned char *hash, size_t length, char *str) -{ - int i; - - for (i = 0; i < (int) length; i++) { - snprintf(str+(i*2), 3, "%02x", hash[i]); - } -} - -static void -calculate_hashes(const char *filename) -{ - FILE *fh; - size_t hash_bytes; - - (void) g_strlcpy(file_sha256, "", HASH_STR_SIZE); - (void) g_strlcpy(file_sha1, "", HASH_STR_SIZE); - - if (cap_file_hashes) { - fh = ws_fopen(filename, "rb"); - if (fh && hd) { - while((hash_bytes = fread(hash_buf, 1, HASH_BUF_SIZE, fh)) > 0) { - gcry_md_write(hd, hash_buf, hash_bytes); - } - gcry_md_final(hd); - hash_to_str(gcry_md_read(hd, GCRY_MD_SHA256), HASH_SIZE_SHA256, file_sha256); - hash_to_str(gcry_md_read(hd, GCRY_MD_SHA1), HASH_SIZE_SHA1, file_sha1); - } - if (fh) fclose(fh); - if (hd) gcry_md_reset(hd); - } -} - -static int -process_cap_file(const char *filename, gboolean need_separator) -{ - int status = 0; - int err; - gchar *err_info; - gint64 size; - gint64 data_offset; - - guint32 packet = 0; - gint64 bytes = 0; - guint32 snaplen_min_inferred = 0xffffffff; - guint32 snaplen_max_inferred = 0; - wtap_rec rec; - Buffer buf; - capture_info cf_info; - gboolean have_times = TRUE; - nstime_t start_time; - int start_time_tsprec; - nstime_t stop_time; - int stop_time_tsprec; - nstime_t cur_time; - nstime_t prev_time; - gboolean know_order = FALSE; - order_t order = IN_ORDER; - guint i; - wtapng_iface_descriptions_t *idb_info; - - pkt_cmt *pc = NULL, *prev = NULL; - - cf_info.wth = wtap_open_offline(filename, WTAP_TYPE_AUTO, &err, &err_info, FALSE); - if (!cf_info.wth) { - cfile_open_failure_message(filename, err, err_info); - return 2; - } - - /* - * Calculate the checksums. Do this after wtap_open_offline, so we don't - * bother calculating them for files that are not known capture types - * where we wouldn't print them anyway. - */ - calculate_hashes(filename); - - if (need_separator && long_report) { - printf("\n"); - } - - nstime_set_zero(&start_time); - start_time_tsprec = WTAP_TSPREC_UNKNOWN; - nstime_set_zero(&stop_time); - stop_time_tsprec = WTAP_TSPREC_UNKNOWN; - nstime_set_zero(&cur_time); - nstime_set_zero(&prev_time); - - cf_info.encap_counts = g_new0(int,WTAP_NUM_ENCAP_TYPES); - - idb_info = wtap_file_get_idb_info(cf_info.wth); - - ws_assert(idb_info->interface_data != NULL); - - cf_info.pkt_cmts = NULL; - cf_info.num_interfaces = idb_info->interface_data->len; - cf_info.interface_packet_counts = g_array_sized_new(FALSE, TRUE, sizeof(guint32), cf_info.num_interfaces); - g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces); - cf_info.pkt_interface_id_unknown = 0; - - g_free(idb_info); - idb_info = NULL; - - /* Zero out the counters for the callbacks. */ - num_ipv4_addresses = 0; - num_ipv6_addresses = 0; - num_decryption_secrets = 0; - - /* Register callbacks for new name<->address maps from the file and - decryption secrets from the file. */ - wtap_set_cb_new_ipv4(cf_info.wth, count_ipv4_address); - wtap_set_cb_new_ipv6(cf_info.wth, count_ipv6_address); - wtap_set_cb_new_secrets(cf_info.wth, count_decryption_secret); - - /* Tally up data that we need to parse through the file to find */ - wtap_rec_init(&rec); - ws_buffer_init(&buf, 1514); - while (wtap_read(cf_info.wth, &rec, &buf, &err, &err_info, &data_offset)) { - if (rec.presence_flags & WTAP_HAS_TS) { - prev_time = cur_time; - cur_time = rec.ts; - if (packet == 0) { - start_time = rec.ts; - start_time_tsprec = rec.tsprec; - stop_time = rec.ts; - stop_time_tsprec = rec.tsprec; - prev_time = rec.ts; - } - if (nstime_cmp(&cur_time, &prev_time) < 0) { - order = NOT_IN_ORDER; - } - if (nstime_cmp(&cur_time, &start_time) < 0) { - start_time = cur_time; - start_time_tsprec = rec.tsprec; - } - if (nstime_cmp(&cur_time, &stop_time) > 0) { - stop_time = cur_time; - stop_time_tsprec = rec.tsprec; - } - } else { - have_times = FALSE; /* at least one packet has no time stamp */ - if (order != NOT_IN_ORDER) - order = ORDER_UNKNOWN; - } - - if (rec.rec_type == REC_TYPE_PACKET) { - bytes += rec.rec_header.packet_header.len; - packet++; - /* packet comments */ - if (pkt_comments && wtap_block_count_option(rec.block, OPT_COMMENT) > 0) { - char *cmt_buff; - for (i = 0; wtap_block_get_nth_string_option_value(rec.block, OPT_COMMENT, i, &cmt_buff) == WTAP_OPTTYPE_SUCCESS; i++) { - pc = g_new0(pkt_cmt, 1); - - pc->recno = packet; - pc->cmt = g_strdup(cmt_buff); - pc->next = NULL; - - if (prev == NULL) - cf_info.pkt_cmts = pc; - else - prev->next = pc; - - prev = pc; - } - } - - /* If caplen < len for a rcd, then presumably */ - /* 'Limit packet capture length' was done for this rcd. */ - /* Keep track as to the min/max actual snapshot lengths */ - /* seen for this file. */ - if (rec.rec_header.packet_header.caplen < rec.rec_header.packet_header.len) { - if (rec.rec_header.packet_header.caplen < snaplen_min_inferred) - snaplen_min_inferred = rec.rec_header.packet_header.caplen; - if (rec.rec_header.packet_header.caplen > snaplen_max_inferred) - snaplen_max_inferred = rec.rec_header.packet_header.caplen; - } - - if ((rec.rec_header.packet_header.pkt_encap > 0) && - (rec.rec_header.packet_header.pkt_encap < WTAP_NUM_ENCAP_TYPES)) { - cf_info.encap_counts[rec.rec_header.packet_header.pkt_encap] += 1; - } else { - fprintf(stderr, "capinfos: Unknown packet encapsulation %d in frame %u of file \"%s\"\n", - rec.rec_header.packet_header.pkt_encap, packet, filename); - } - - /* Packet interface_id info */ - if (rec.presence_flags & WTAP_HAS_INTERFACE_ID) { - /* cf_info.num_interfaces is size, not index, so it's one more than max index */ - if (rec.rec_header.packet_header.interface_id >= cf_info.num_interfaces) { - /* - * OK, re-fetch the number of interfaces, as there might have - * been an interface that was in the middle of packets, and - * grow the array to be big enough for the new number of - * interfaces. - */ - idb_info = wtap_file_get_idb_info(cf_info.wth); - - cf_info.num_interfaces = idb_info->interface_data->len; - g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces); - - g_free(idb_info); - idb_info = NULL; - } - if (rec.rec_header.packet_header.interface_id < cf_info.num_interfaces) { - g_array_index(cf_info.interface_packet_counts, guint32, - rec.rec_header.packet_header.interface_id) += 1; - } - else { - cf_info.pkt_interface_id_unknown += 1; - } - } - else { - /* it's for interface_id 0 */ - if (cf_info.num_interfaces != 0) { - g_array_index(cf_info.interface_packet_counts, guint32, 0) += 1; - } - else { - cf_info.pkt_interface_id_unknown += 1; - } - } - } - - wtap_rec_reset(&rec); - } /* while */ - wtap_rec_cleanup(&rec); - ws_buffer_free(&buf); - - /* - * Get IDB info strings. - * We do this at the end, so we can get information for all IDBs in - * the file, even those that come after packet records, and so that - * we get, for example, a count of the number of statistics entries - * for each interface as of the *end* of the file. - */ - idb_info = wtap_file_get_idb_info(cf_info.wth); - - cf_info.idb_info_strings = g_array_sized_new(FALSE, FALSE, sizeof(gchar*), cf_info.num_interfaces); - cf_info.num_interfaces = idb_info->interface_data->len; - for (i = 0; i < cf_info.num_interfaces; i++) { - const wtap_block_t if_descr = g_array_index(idb_info->interface_data, wtap_block_t, i); - gchar *s = wtap_get_debug_if_descr(if_descr, 21, "\n"); - g_array_append_val(cf_info.idb_info_strings, s); - } - - g_free(idb_info); - idb_info = NULL; - - if (err != 0) { - fprintf(stderr, - "capinfos: An error occurred after reading %u packets from \"%s\".\n", - packet, filename); - cfile_read_failure_message(filename, err, err_info); - if (err == WTAP_ERR_SHORT_READ) { - /* Don't give up completely with this one. */ - status = 1; - fprintf(stderr, - " (will continue anyway, checksums might be incorrect)\n"); - } else { - cleanup_capture_info(&cf_info); - wtap_close(cf_info.wth); - return 2; - } - } - - /* File size */ - size = wtap_file_size(cf_info.wth, &err); - if (size == -1) { - fprintf(stderr, - "capinfos: Can't get size of \"%s\": %s.\n", - filename, g_strerror(err)); - cleanup_capture_info(&cf_info); - wtap_close(cf_info.wth); - return 2; - } - - cf_info.filesize = size; - - /* File Type */ - cf_info.file_type = wtap_file_type_subtype(cf_info.wth); - cf_info.compression_type = wtap_get_compression_type(cf_info.wth); - - /* File Encapsulation */ - cf_info.file_encap = wtap_file_encap(cf_info.wth); - - cf_info.file_tsprec = wtap_file_tsprec(cf_info.wth); - - /* Packet size limit (snaplen) */ - cf_info.snaplen = wtap_snapshot_length(cf_info.wth); - if (cf_info.snaplen > 0) - cf_info.snap_set = TRUE; - else - cf_info.snap_set = FALSE; - - cf_info.snaplen_min_inferred = snaplen_min_inferred; - cf_info.snaplen_max_inferred = snaplen_max_inferred; - - /* # of packets */ - cf_info.packet_count = packet; - - /* File Times */ - cf_info.times_known = have_times; - cf_info.start_time = start_time; - cf_info.start_time_tsprec = start_time_tsprec; - cf_info.stop_time = stop_time; - cf_info.stop_time_tsprec = stop_time_tsprec; - nstime_delta(&cf_info.duration, &stop_time, &start_time); - /* Duration precision is the higher of the start and stop time precisions. */ - if (cf_info.stop_time_tsprec > cf_info.start_time_tsprec) - cf_info.duration_tsprec = cf_info.stop_time_tsprec; - else - cf_info.duration_tsprec = cf_info.start_time_tsprec; - cf_info.know_order = know_order; - cf_info.order = order; - - /* Number of packet bytes */ - cf_info.packet_bytes = bytes; - - cf_info.data_rate = 0.0; - cf_info.packet_rate = 0.0; - cf_info.packet_size = 0.0; - - if (packet > 0) { - double delta_time = nstime_to_sec(&stop_time) - nstime_to_sec(&start_time); - if (delta_time > 0.0) { - cf_info.data_rate = (double)bytes / delta_time; /* Data rate per second */ - cf_info.packet_rate = (double)packet / delta_time; /* packet rate per second */ - } - cf_info.packet_size = (double)bytes / packet; /* Avg packet size */ - } - - if (!long_report && table_report_header) { - print_stats_table_header(&cf_info); - } - - if (long_report) { - print_stats(filename, &cf_info); - } else { - print_stats_table(filename, &cf_info); - } - - cleanup_capture_info(&cf_info); - wtap_close(cf_info.wth); - - return status; -} - -static void -print_usage(FILE *output) -{ - fprintf(output, "\n"); - fprintf(output, "Usage: capinfos [options] ...\n"); - fprintf(output, "\n"); - fprintf(output, "General infos:\n"); - fprintf(output, " -t display the capture file type\n"); - fprintf(output, " -E display the capture file encapsulation\n"); - fprintf(output, " -I display the capture file interface information\n"); - fprintf(output, " -F display additional capture file information\n"); - fprintf(output, " -H display the SHA256 and SHA1 hashes of the file\n"); - fprintf(output, " -k display the capture comment\n"); - fprintf(output, " -p display individual packet comments\n"); - fprintf(output, "\n"); - fprintf(output, "Size infos:\n"); - fprintf(output, " -c display the number of packets\n"); - fprintf(output, " -s display the size of the file (in bytes)\n"); - fprintf(output, " -d display the total length of all packets (in bytes)\n"); - fprintf(output, " -l display the packet size limit (snapshot length)\n"); - fprintf(output, "\n"); - fprintf(output, "Time infos:\n"); - fprintf(output, " -u display the capture duration (in seconds)\n"); - fprintf(output, " -a display the capture start time\n"); - fprintf(output, " -e display the capture end time\n"); - fprintf(output, " -o display the capture file chronological status (True/False)\n"); - fprintf(output, " -S display start and end times as seconds\n"); - fprintf(output, "\n"); - fprintf(output, "Statistic infos:\n"); - fprintf(output, " -y display average data rate (in bytes/sec)\n"); - fprintf(output, " -i display average data rate (in bits/sec)\n"); - fprintf(output, " -z display average packet size (in bytes)\n"); - fprintf(output, " -x display average packet rate (in packets/sec)\n"); - fprintf(output, "\n"); - fprintf(output, "Metadata infos:\n"); - fprintf(output, " -n display number of resolved IPv4 and IPv6 addresses\n"); - fprintf(output, " -D display number of decryption secrets\n"); - fprintf(output, "\n"); - fprintf(output, "Output format:\n"); - fprintf(output, " -L generate long report (default)\n"); - fprintf(output, " -T generate table report\n"); - fprintf(output, " -M display machine-readable values in long reports\n"); - fprintf(output, "\n"); - fprintf(output, "Table report options:\n"); - fprintf(output, " -R generate header record (default)\n"); - fprintf(output, " -r do not generate header record\n"); - fprintf(output, "\n"); - fprintf(output, " -B separate infos with TAB character (default)\n"); - fprintf(output, " -m separate infos with comma (,) character\n"); - fprintf(output, " -b separate infos with SPACE character\n"); - fprintf(output, "\n"); - fprintf(output, " -N do not quote infos (default)\n"); - fprintf(output, " -q quote infos with single quotes (')\n"); - fprintf(output, " -Q quote infos with double quotes (\")\n"); - fprintf(output, "\n"); - fprintf(output, "Miscellaneous:\n"); - fprintf(output, " -h, --help display this help and exit\n"); - fprintf(output, " -v, --version display version info and exit\n"); - fprintf(output, " -C cancel processing if file open fails (default is to continue)\n"); - fprintf(output, " -A generate all infos (default)\n"); - fprintf(output, " -K disable displaying the capture comment\n"); - fprintf(output, " -P disable displaying individual packet comments\n"); - fprintf(output, "\n"); - fprintf(output, "Options are processed from left to right order with later options superseding\n"); - fprintf(output, "or adding to earlier options.\n"); - fprintf(output, "\n"); - fprintf(output, "If no options are given the default is to display all infos in long report\n"); - fprintf(output, "output format.\n"); -} - -/* - * Report an error in command-line arguments. - */ -static void -capinfos_cmdarg_err(const char *msg_format, va_list ap) -{ - fprintf(stderr, "capinfos: "); - vfprintf(stderr, msg_format, ap); - fprintf(stderr, "\n"); -} - -/* - * Report additional information for an error in command-line arguments. - */ -static void -capinfos_cmdarg_err_cont(const char *msg_format, va_list ap) -{ - vfprintf(stderr, msg_format, ap); - fprintf(stderr, "\n"); -} - -int -main(int argc, char *argv[]) -{ - char *configuration_init_error; - static const struct report_message_routines capinfos_report_routines = { - failure_message, - failure_message, - open_failure_message, - read_failure_message, - write_failure_message, - cfile_open_failure_message, - cfile_dump_open_failure_message, - cfile_read_failure_message, - cfile_write_failure_message, - cfile_close_failure_message - }; - gboolean need_separator = FALSE; - int opt; - int overall_error_status = EXIT_SUCCESS; - static const struct ws_option long_options[] = { - {"help", ws_no_argument, NULL, 'h'}, - {"version", ws_no_argument, NULL, 'v'}, - {0, 0, 0, 0 } - }; - - int status = 0; - - /* - * Set the C-language locale to the native environment and set the - * code page to UTF-8 on Windows. - */ -#ifdef _WIN32 - setlocale(LC_ALL, ".UTF-8"); -#else - setlocale(LC_ALL, ""); -#endif - - cmdarg_err_init(capinfos_cmdarg_err, capinfos_cmdarg_err_cont); - - /* Initialize log handler early so we can have proper logging during startup. */ - ws_log_init("capinfos", vcmdarg_err); - - /* Early logging command-line initialization. */ - ws_log_parse_args(&argc, argv, vcmdarg_err, WS_EXIT_INVALID_OPTION); - - ws_noisy("Finished log init and parsing command line log arguments"); - - /* Get the decimal point. */ - decimal_point = g_strdup(localeconv()->decimal_point); - - /* Initialize the version information. */ - ws_init_version_info("Capinfos", NULL, NULL); - -#ifdef _WIN32 - create_app_running_mutex(); -#endif /* _WIN32 */ - - /* - * Get credential information for later use. - */ - init_process_policies(); - - /* - * Attempt to get the pathname of the directory containing the - * executable file. - */ - configuration_init_error = configuration_init(argv[0], NULL); - if (configuration_init_error != NULL) { - fprintf(stderr, - "capinfos: Can't get pathname of directory containing the capinfos program: %s.\n", - configuration_init_error); - g_free(configuration_init_error); - } - - init_report_message("capinfos", &capinfos_report_routines); - - wtap_init(TRUE); - - /* Process the options */ - while ((opt = ws_getopt_long(argc, argv, "abcdehiklmnopqrstuvxyzABCDEFHIKLMNPQRST", long_options, NULL)) !=-1) { - - switch (opt) { - - case 't': - if (report_all_infos) disable_all_infos(); - cap_file_type = TRUE; - break; - - case 'E': - if (report_all_infos) disable_all_infos(); - cap_file_encap = TRUE; - break; - - case 'l': - if (report_all_infos) disable_all_infos(); - cap_snaplen = TRUE; - break; - - case 'c': - if (report_all_infos) disable_all_infos(); - cap_packet_count = TRUE; - break; - - case 's': - if (report_all_infos) disable_all_infos(); - cap_file_size = TRUE; - break; - - case 'd': - if (report_all_infos) disable_all_infos(); - cap_data_size = TRUE; - break; - - case 'u': - if (report_all_infos) disable_all_infos(); - cap_duration = TRUE; - break; - - case 'a': - if (report_all_infos) disable_all_infos(); - cap_start_time = TRUE; - break; - - case 'e': - if (report_all_infos) disable_all_infos(); - cap_end_time = TRUE; - break; - - case 'S': - time_as_secs = TRUE; - break; - - case 'y': - if (report_all_infos) disable_all_infos(); - cap_data_rate_byte = TRUE; - break; - - case 'i': - if (report_all_infos) disable_all_infos(); - cap_data_rate_bit = TRUE; - break; - - case 'z': - if (report_all_infos) disable_all_infos(); - cap_packet_size = TRUE; - break; - - case 'x': - if (report_all_infos) disable_all_infos(); - cap_packet_rate = TRUE; - break; - - case 'H': - if (report_all_infos) disable_all_infos(); - cap_file_hashes = TRUE; - break; - - case 'o': - if (report_all_infos) disable_all_infos(); - cap_order = TRUE; - break; - - case 'k': - if (report_all_infos) disable_all_infos(); - cap_comment = TRUE; - break; - - case 'p': - if (report_all_infos) disable_all_infos(); - pkt_comments = TRUE; - break; - - case 'K': - cap_comment = FALSE; - break; - - case 'P': - pkt_comments = FALSE; - break; - - case 'F': - if (report_all_infos) disable_all_infos(); - cap_file_more_info = TRUE; - break; - - case 'I': - if (report_all_infos) disable_all_infos(); - cap_file_idb = TRUE; - break; - - case 'n': - if (report_all_infos) disable_all_infos(); - cap_file_nrb = TRUE; - break; - - case 'D': - if (report_all_infos) disable_all_infos(); - cap_file_dsb = TRUE; - break; - - case 'C': - stop_after_failure = TRUE; - break; - - case 'A': - enable_all_infos(); - break; - - case 'L': - long_report = TRUE; - break; - - case 'T': - long_report = FALSE; - break; - - case 'M': - machine_readable = TRUE; - break; - - case 'R': - table_report_header = TRUE; - break; - - case 'r': - table_report_header = FALSE; - break; - - case 'N': - quote_char = '\0'; - break; - - case 'q': - quote_char = '\''; - break; - - case 'Q': - quote_char = '"'; - break; - - case 'B': - field_separator = '\t'; - break; - - case 'm': - field_separator = ','; - break; - - case 'b': - field_separator = ' '; - break; - - case 'h': - show_help_header("Print various information (infos) about capture files."); - print_usage(stdout); - goto exit; - break; - - case 'v': - show_version(); - goto exit; - break; - - case '?': /* Bad flag - print usage message */ - print_usage(stderr); - overall_error_status = WS_EXIT_INVALID_OPTION; - goto exit; - break; - } - } - - if ((argc - ws_optind) < 1) { - print_usage(stderr); - overall_error_status = WS_EXIT_INVALID_OPTION; - goto exit; - } - - if (cap_file_hashes) { - gcry_check_version(NULL); - gcry_md_open(&hd, GCRY_MD_SHA256, 0); - if (hd) - gcry_md_enable(hd, GCRY_MD_SHA1); - - hash_buf = (char *)g_malloc(HASH_BUF_SIZE); - } - - overall_error_status = 0; - - for (opt = ws_optind; opt < argc; opt++) { - - status = process_cap_file(argv[opt], need_separator); - if (status) { - /* Something failed. It's been reported; remember that processing - one file failed and, if -C was specified, stop. */ - overall_error_status = status; - if (stop_after_failure) - goto exit; - } - if (status != 2) { - /* Either it succeeded or it got a "short read" but printed - information anyway. Note that we need a blank line before - the next file's information, to separate it from the - previous file. */ - need_separator = TRUE; - } - } - -exit: - g_free(hash_buf); - gcry_md_close(hd); - wtap_cleanup(); - free_progdirs(); - return overall_error_status; -} diff --git a/include/wireshark/capture_opts.c b/include/wireshark/capture_opts.c deleted file mode 100644 index 4862f5b1..00000000 --- a/include/wireshark/capture_opts.c +++ /dev/null @@ -1,1471 +0,0 @@ -/* capture_opts.c - * Routines for capture options setting - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include - -#include - -#include -#include - -#include -#include -#include - -#ifdef HAVE_LIBPCAP - -#include - -#include - -#include "capture_opts.h" -#include "ringbuffer.h" - -#include -#include -#include -#include -#include -#include - -#include "capture/capture_ifinfo.h" -#include "capture/capture-pcap-util.h" - -static gboolean capture_opts_output_to_pipe(const char *save_file, gboolean *is_pipe); - - -void -capture_opts_init(capture_options *capture_opts, GList *(*get_iface_list)(int *, gchar **)) -{ - capture_opts->get_iface_list = get_iface_list; - capture_opts->ifaces = g_array_new(FALSE, FALSE, sizeof(interface_options)); - capture_opts->all_ifaces = g_array_new(FALSE, FALSE, sizeof(interface_t)); - capture_opts->num_selected = 0; - capture_opts->default_options.name = NULL; - capture_opts->default_options.descr = NULL; - capture_opts->default_options.ifname = NULL; - capture_opts->default_options.hardware = NULL; - capture_opts->default_options.display_name = NULL; - capture_opts->default_options.cfilter = NULL; - capture_opts->default_options.has_snaplen = FALSE; - capture_opts->default_options.snaplen = WTAP_MAX_PACKET_SIZE_STANDARD; - capture_opts->default_options.linktype = -1; /* use interface default */ - capture_opts->default_options.promisc_mode = TRUE; - capture_opts->default_options.if_type = IF_WIRED; - capture_opts->default_options.extcap = NULL; - capture_opts->default_options.extcap_fifo = NULL; - capture_opts->default_options.extcap_args = NULL; - capture_opts->default_options.extcap_pid = WS_INVALID_PID; - capture_opts->default_options.extcap_pipedata = NULL; - capture_opts->default_options.extcap_stderr = NULL; - capture_opts->default_options.extcap_stdout_watch = 0; - capture_opts->default_options.extcap_stderr_watch = 0; -#ifdef _WIN32 - capture_opts->default_options.extcap_pipe_h = INVALID_HANDLE_VALUE; - capture_opts->default_options.extcap_control_in_h = INVALID_HANDLE_VALUE; - capture_opts->default_options.extcap_control_out_h = INVALID_HANDLE_VALUE; -#endif - capture_opts->default_options.extcap_control_in = NULL; - capture_opts->default_options.extcap_control_out = NULL; -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - capture_opts->default_options.buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE; -#endif - capture_opts->default_options.monitor_mode = FALSE; -#ifdef HAVE_PCAP_REMOTE - capture_opts->default_options.src_type = CAPTURE_IFLOCAL; - capture_opts->default_options.remote_host = NULL; - capture_opts->default_options.remote_port = NULL; - capture_opts->default_options.auth_type = CAPTURE_AUTH_NULL; - capture_opts->default_options.auth_username = NULL; - capture_opts->default_options.auth_password = NULL; - capture_opts->default_options.datatx_udp = FALSE; - capture_opts->default_options.nocap_rpcap = TRUE; - capture_opts->default_options.nocap_local = FALSE; -#endif -#ifdef HAVE_PCAP_SETSAMPLING - capture_opts->default_options.sampling_method = CAPTURE_SAMP_NONE; - capture_opts->default_options.sampling_param = 0; -#endif - capture_opts->default_options.timestamp_type = NULL; - capture_opts->saving_to_file = FALSE; - capture_opts->save_file = NULL; - capture_opts->group_read_access = FALSE; - capture_opts->use_pcapng = TRUE; /* Save as pcapng by default */ - capture_opts->update_interval = DEFAULT_UPDATE_INTERVAL; /* 100 ms */ - capture_opts->real_time_mode = TRUE; - capture_opts->show_info = TRUE; - capture_opts->restart = FALSE; - capture_opts->orig_save_file = NULL; - - capture_opts->multi_files_on = FALSE; - capture_opts->has_file_duration = FALSE; - capture_opts->file_duration = 60.0; /* 1 min */ - capture_opts->has_file_interval = FALSE; - capture_opts->has_nametimenum = FALSE; - capture_opts->file_interval = 60; /* 1 min */ - capture_opts->has_file_packets = FALSE; - capture_opts->file_packets = 0; - capture_opts->has_ring_num_files = FALSE; - capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES; - - capture_opts->has_autostop_files = FALSE; - capture_opts->autostop_files = 1; - capture_opts->has_autostop_packets = FALSE; - capture_opts->autostop_packets = 0; - capture_opts->has_autostop_written_packets = FALSE; - capture_opts->autostop_written_packets = 0; - capture_opts->has_autostop_filesize = FALSE; - capture_opts->autostop_filesize = 1000; /* 1 MB */ - capture_opts->has_autostop_duration = FALSE; - capture_opts->autostop_duration = 60.0; /* 1 min */ - - capture_opts->output_to_pipe = FALSE; - capture_opts->capture_child = FALSE; - capture_opts->stop_after_extcaps = FALSE; - capture_opts->wait_for_extcap_cbs = FALSE; - capture_opts->print_file_names = FALSE; - capture_opts->print_name_to = NULL; - capture_opts->temp_dir = NULL; - capture_opts->compress_type = NULL; - capture_opts->closed_msg = NULL; - capture_opts->extcap_terminate_id = 0; -} - -void -capture_opts_cleanup(capture_options *capture_opts) -{ - if (!capture_opts) - return; - - if (capture_opts->ifaces) { - while (capture_opts->ifaces->len > 0) { - capture_opts_del_iface(capture_opts, 0); - } - g_array_free(capture_opts->ifaces, TRUE); - capture_opts->ifaces = NULL; - } - if (capture_opts->all_ifaces) { - while (capture_opts->all_ifaces->len > 0) { - interface_t *device = &g_array_index(capture_opts->all_ifaces, interface_t, 0); - capture_opts_free_interface_t(device); - capture_opts->all_ifaces = g_array_remove_index(capture_opts->all_ifaces, 0); - } - g_array_free(capture_opts->all_ifaces, TRUE); - capture_opts->all_ifaces = NULL; - } - g_free(capture_opts->save_file); - g_free(capture_opts->temp_dir); - - if (capture_opts->closed_msg) { - g_free(capture_opts->closed_msg); - capture_opts->closed_msg = NULL; - } - if (capture_opts->extcap_terminate_id > 0) { - g_source_remove(capture_opts->extcap_terminate_id); - capture_opts->extcap_terminate_id = 0; - } -} - -/* log content of capture_opts */ -void -capture_opts_log(const char *log_domain, enum ws_log_level log_level, capture_options *capture_opts) { - guint i; - - ws_log(log_domain, log_level, "CAPTURE OPTIONS :"); - - for (i = 0; i < capture_opts->ifaces->len; i++) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i); - ws_log(log_domain, log_level, "Interface name[%02d] : %s", i, interface_opts->name ? interface_opts->name : "(unspecified)"); - ws_log(log_domain, log_level, "Interface description[%02d] : %s", i, interface_opts->descr ? interface_opts->descr : "(unspecified)"); - ws_log(log_domain, log_level, "Interface vendor description[%02d] : %s", i, interface_opts->hardware ? interface_opts->hardware : "(unspecified)"); - ws_log(log_domain, log_level, "Display name[%02d]: %s", i, interface_opts->display_name ? interface_opts->display_name : "(unspecified)"); - ws_log(log_domain, log_level, "Capture filter[%02d] : %s", i, interface_opts->cfilter ? interface_opts->cfilter : "(unspecified)"); - ws_log(log_domain, log_level, "Snap length[%02d] (%u) : %d", i, interface_opts->has_snaplen, interface_opts->snaplen); - ws_log(log_domain, log_level, "Link Type[%02d] : %d", i, interface_opts->linktype); - ws_log(log_domain, log_level, "Promiscuous Mode[%02d]: %s", i, interface_opts->promisc_mode?"TRUE":"FALSE"); - ws_log(log_domain, log_level, "Extcap[%02d] : %s", i, interface_opts->extcap ? interface_opts->extcap : "(unspecified)"); - ws_log(log_domain, log_level, "Extcap FIFO[%02d] : %s", i, interface_opts->extcap_fifo ? interface_opts->extcap_fifo : "(unspecified)"); - ws_log(log_domain, log_level, "Extcap PID[%02d] : %"PRIdMAX, i, (intmax_t)interface_opts->extcap_pid); -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - ws_log(log_domain, log_level, "Buffer size[%02d] : %d (MB)", i, interface_opts->buffer_size); -#endif - ws_log(log_domain, log_level, "Monitor Mode[%02d] : %s", i, interface_opts->monitor_mode?"TRUE":"FALSE"); -#ifdef HAVE_PCAP_REMOTE - ws_log(log_domain, log_level, "Capture source[%02d] : %s", i, - interface_opts->src_type == CAPTURE_IFLOCAL ? "Local interface" : - interface_opts->src_type == CAPTURE_IFREMOTE ? "Remote interface" : - "Unknown"); - if (interface_opts->src_type == CAPTURE_IFREMOTE) { - ws_log(log_domain, log_level, "Remote host[%02d] : %s", i, interface_opts->remote_host ? interface_opts->remote_host : "(unspecified)"); - ws_log(log_domain, log_level, "Remote port[%02d] : %s", i, interface_opts->remote_port ? interface_opts->remote_port : "(unspecified)"); - } - ws_log(log_domain, log_level, "Authentication[%02d] : %s", i, - interface_opts->auth_type == CAPTURE_AUTH_NULL ? "Null" : - interface_opts->auth_type == CAPTURE_AUTH_PWD ? "By username/password" : - "Unknown"); - if (interface_opts->auth_type == CAPTURE_AUTH_PWD) { - ws_log(log_domain, log_level, "Auth username[%02d] : %s", i, interface_opts->auth_username ? interface_opts->auth_username : "(unspecified)"); - ws_log(log_domain, log_level, "Auth password[%02d] : ", i); - } - ws_log(log_domain, log_level, "UDP data tfer[%02d] : %u", i, interface_opts->datatx_udp); - ws_log(log_domain, log_level, "No cap. RPCAP[%02d] : %u", i, interface_opts->nocap_rpcap); - ws_log(log_domain, log_level, "No cap. local[%02d] : %u", i, interface_opts->nocap_local); -#endif -#ifdef HAVE_PCAP_SETSAMPLING - ws_log(log_domain, log_level, "Sampling meth.[%02d] : %d", i, interface_opts->sampling_method); - ws_log(log_domain, log_level, "Sampling param.[%02d] : %d", i, interface_opts->sampling_param); -#endif - ws_log(log_domain, log_level, "Timestamp type [%02d] : %s", i, interface_opts->timestamp_type); - } - ws_log(log_domain, log_level, "Interface name[df] : %s", capture_opts->default_options.name ? capture_opts->default_options.name : "(unspecified)"); - ws_log(log_domain, log_level, "Interface Descr[df] : %s", capture_opts->default_options.descr ? capture_opts->default_options.descr : "(unspecified)"); - ws_log(log_domain, log_level, "Interface Hardware Descr[df] : %s", capture_opts->default_options.hardware ? capture_opts->default_options.hardware : "(unspecified)"); - ws_log(log_domain, log_level, "Interface display name[df] : %s", capture_opts->default_options.display_name ? capture_opts->default_options.display_name : "(unspecified)"); - ws_log(log_domain, log_level, "Capture filter[df] : %s", capture_opts->default_options.cfilter ? capture_opts->default_options.cfilter : "(unspecified)"); - ws_log(log_domain, log_level, "Snap length[df] (%u) : %d", capture_opts->default_options.has_snaplen, capture_opts->default_options.snaplen); - ws_log(log_domain, log_level, "Link Type[df] : %d", capture_opts->default_options.linktype); - ws_log(log_domain, log_level, "Promiscuous Mode[df]: %s", capture_opts->default_options.promisc_mode?"TRUE":"FALSE"); - ws_log(log_domain, log_level, "Extcap[df] : %s", capture_opts->default_options.extcap ? capture_opts->default_options.extcap : "(unspecified)"); - ws_log(log_domain, log_level, "Extcap FIFO[df] : %s", capture_opts->default_options.extcap_fifo ? capture_opts->default_options.extcap_fifo : "(unspecified)"); -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - ws_log(log_domain, log_level, "Buffer size[df] : %d (MB)", capture_opts->default_options.buffer_size); -#endif - ws_log(log_domain, log_level, "Monitor Mode[df] : %s", capture_opts->default_options.monitor_mode?"TRUE":"FALSE"); -#ifdef HAVE_PCAP_REMOTE - ws_log(log_domain, log_level, "Capture source[df] : %s", - capture_opts->default_options.src_type == CAPTURE_IFLOCAL ? "Local interface" : - capture_opts->default_options.src_type == CAPTURE_IFREMOTE ? "Remote interface" : - "Unknown"); - if (capture_opts->default_options.src_type == CAPTURE_IFREMOTE) { - ws_log(log_domain, log_level, "Remote host[df] : %s", capture_opts->default_options.remote_host ? capture_opts->default_options.remote_host : "(unspecified)"); - ws_log(log_domain, log_level, "Remote port[df] : %s", capture_opts->default_options.remote_port ? capture_opts->default_options.remote_port : "(unspecified)"); - } - ws_log(log_domain, log_level, "Authentication[df] : %s", - capture_opts->default_options.auth_type == CAPTURE_AUTH_NULL ? "Null" : - capture_opts->default_options.auth_type == CAPTURE_AUTH_PWD ? "By username/password" : - "Unknown"); - if (capture_opts->default_options.auth_type == CAPTURE_AUTH_PWD) { - ws_log(log_domain, log_level, "Auth username[df] : %s", capture_opts->default_options.auth_username ? capture_opts->default_options.auth_username : "(unspecified)"); - ws_log(log_domain, log_level, "Auth password[df] : "); - } - ws_log(log_domain, log_level, "UDP data tfer[df] : %u", capture_opts->default_options.datatx_udp); - ws_log(log_domain, log_level, "No cap. RPCAP[df] : %u", capture_opts->default_options.nocap_rpcap); - ws_log(log_domain, log_level, "No cap. local[df] : %u", capture_opts->default_options.nocap_local); -#endif -#ifdef HAVE_PCAP_SETSAMPLING - ws_log(log_domain, log_level, "Sampling meth. [df] : %d", capture_opts->default_options.sampling_method); - ws_log(log_domain, log_level, "Sampling param.[df] : %d", capture_opts->default_options.sampling_param); -#endif - ws_log(log_domain, log_level, "Timestamp type [df] : %s", capture_opts->default_options.timestamp_type ? capture_opts->default_options.timestamp_type : "(unspecified)"); - ws_log(log_domain, log_level, "SavingToFile : %u", capture_opts->saving_to_file); - ws_log(log_domain, log_level, "SaveFile : %s", (capture_opts->save_file) ? capture_opts->save_file : ""); - ws_log(log_domain, log_level, "GroupReadAccess : %u", capture_opts->group_read_access); - ws_log(log_domain, log_level, "Fileformat : %s", (capture_opts->use_pcapng) ? "PCAPNG" : "PCAP"); - ws_log(log_domain, log_level, "UpdateInterval : %u (ms)", capture_opts->update_interval); - ws_log(log_domain, log_level, "RealTimeMode : %u", capture_opts->real_time_mode); - ws_log(log_domain, log_level, "ShowInfo : %u", capture_opts->show_info); - - ws_log(log_domain, log_level, "MultiFilesOn : %u", capture_opts->multi_files_on); - ws_log(log_domain, log_level, "FileDuration (%u) : %.3f", capture_opts->has_file_duration, capture_opts->file_duration); - ws_log(log_domain, log_level, "FileInterval (%u) : %u", capture_opts->has_file_interval, capture_opts->file_interval); - ws_log(log_domain, log_level, "FilePackets (%u) : %u", capture_opts->has_file_packets, capture_opts->file_packets); - ws_log(log_domain, log_level, "FileNameType : %s", (capture_opts->has_nametimenum) ? "prefix_time_num.suffix" : "prefix_num_time.suffix"); - ws_log(log_domain, log_level, "RingNumFiles (%u) : %u", capture_opts->has_ring_num_files, capture_opts->ring_num_files); - ws_log(log_domain, log_level, "RingPrintFiles (%u) : %s", capture_opts->print_file_names, (capture_opts->print_file_names ? capture_opts->print_name_to : "")); - - ws_log(log_domain, log_level, "AutostopFiles (%u) : %u", capture_opts->has_autostop_files, capture_opts->autostop_files); - ws_log(log_domain, log_level, "AutostopPackets (%u) : %u", capture_opts->has_autostop_packets, capture_opts->autostop_packets); - ws_log(log_domain, log_level, "AutostopWrittenPackets (%u) : %u", capture_opts->has_autostop_written_packets, capture_opts->autostop_written_packets); - ws_log(log_domain, log_level, "AutostopFilesize(%u) : %u (KB)", capture_opts->has_autostop_filesize, capture_opts->autostop_filesize); - ws_log(log_domain, log_level, "AutostopDuration(%u) : %.3f", capture_opts->has_autostop_duration, capture_opts->autostop_duration); - ws_log(log_domain, log_level, "Temporary Directory : %s", capture_opts->temp_dir && capture_opts->temp_dir[0] ? capture_opts->temp_dir : g_get_tmp_dir()); -} - -/* - * Given a string of the form ":", as might appear - * as an argument to a "-a" option, parse it and set the criterion in - * question. Return an indication of whether it succeeded or failed - * in some fashion. - */ -static gboolean -set_autostop_criterion(capture_options *capture_opts, const char *autostoparg) -{ - gchar *p, *colonp; - - colonp = strchr(autostoparg, ':'); - if (colonp == NULL) - return FALSE; - - p = colonp; - *p++ = '\0'; - - /* - * Skip over any white space (there probably won't be any, but - * as we allow it in the preferences file, we might as well - * allow it here). - */ - while (g_ascii_isspace(*p)) - p++; - if (*p == '\0') { - /* - * Put the colon back, so if our caller uses, in an - * error message, the string they passed us, the message - * looks correct. - */ - *colonp = ':'; - return FALSE; - } - if (strcmp(autostoparg,"duration") == 0) { - capture_opts->has_autostop_duration = TRUE; - capture_opts->autostop_duration = get_positive_double(p,"autostop duration"); - } else if (strcmp(autostoparg,"filesize") == 0) { - capture_opts->has_autostop_filesize = TRUE; - capture_opts->autostop_filesize = get_nonzero_guint32(p,"autostop filesize"); - } else if (strcmp(autostoparg,"files") == 0) { - capture_opts->multi_files_on = TRUE; - capture_opts->has_autostop_files = TRUE; - capture_opts->autostop_files = get_positive_int(p,"autostop files"); - } else if (strcmp(autostoparg,"packets") == 0) { - capture_opts->has_autostop_written_packets = TRUE; - capture_opts->autostop_written_packets = get_positive_int(p,"packet write count"); - } else { - return FALSE; - } - *colonp = ':'; /* put the colon back */ - return TRUE; -} - -static gboolean get_filter_arguments(capture_options* capture_opts, const char* arg) -{ - char* colonp; - char* val; - char* filter_exp = NULL; - - colonp = strchr(arg, ':'); - if (colonp) { - val = colonp; - *val = '\0'; - val++; - if (strcmp(arg, "predef") == 0) { - GList* filterItem; - - filterItem = get_filter_list_first(CFILTER_LIST); - while (filterItem != NULL) { - filter_def *filterDef; - - filterDef = (filter_def*)filterItem->data; - if (strcmp(val, filterDef->name) == 0) { - filter_exp = g_strdup(filterDef->strval); - break; - } - filterItem = filterItem->next; - } - } - } - - if (filter_exp == NULL) { - /* No filter expression found yet; fallback to previous implementation - and assume the arg contains a filter expression */ - if (colonp) { - *colonp = ':'; /* restore colon */ - } - filter_exp = g_strdup(arg); - } - - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - g_free(interface_opts->cfilter); - interface_opts->cfilter = filter_exp; - return TRUE; - } - else { - g_free(capture_opts->default_options.cfilter); - capture_opts->default_options.cfilter = filter_exp; - return TRUE; - } -} - -/* - * Given a string of the form ":", as might appear - * as an argument to a "-b" option, parse it and set the arguments in - * question. Return an indication of whether it succeeded or failed - * in some fashion. - */ -static gboolean -get_ring_arguments(capture_options *capture_opts, const char *arg) -{ - gchar *p = NULL, *colonp; - - colonp = strchr(arg, ':'); - if (colonp == NULL) - return FALSE; - - p = colonp; - *p++ = '\0'; - - /* - * Skip over any white space (there probably won't be any, but - * as we allow it in the preferences file, we might as well - * allow it here). - */ - while (g_ascii_isspace(*p)) - p++; - if (*p == '\0') { - /* - * Put the colon back, so if our caller uses, in an - * error message, the string they passed us, the message - * looks correct. - */ - *colonp = ':'; - return FALSE; - } - - if (strcmp(arg,"files") == 0) { - capture_opts->has_ring_num_files = TRUE; - capture_opts->ring_num_files = get_nonzero_guint32(p, "number of ring buffer files"); - } else if (strcmp(arg,"filesize") == 0) { - capture_opts->has_autostop_filesize = TRUE; - capture_opts->autostop_filesize = get_nonzero_guint32(p, "ring buffer filesize"); - } else if (strcmp(arg,"duration") == 0) { - capture_opts->has_file_duration = TRUE; - capture_opts->file_duration = get_positive_double(p, "ring buffer duration"); - } else if (strcmp(arg,"interval") == 0) { - capture_opts->has_file_interval = TRUE; - capture_opts->file_interval = get_positive_int(p, "ring buffer interval"); - } else if (strcmp(arg,"nametimenum") == 0) { - int val = get_positive_int(p, "file name: time before num"); - capture_opts->has_nametimenum = (val > 1); - } else if (strcmp(arg,"packets") == 0) { - capture_opts->has_file_packets = TRUE; - capture_opts->file_packets = get_positive_int(p, "ring buffer packet count"); - } else if (strcmp(arg,"printname") == 0) { - capture_opts->print_file_names = TRUE; - capture_opts->print_name_to = g_strdup(p); - } - - *colonp = ':'; /* put the colon back */ - return TRUE; -} - -#ifdef HAVE_PCAP_SETSAMPLING -/* - * Given a string of the form ":", as might appear - * as an argument to a "-m" option, parse it and set the arguments in - * question. Return an indication of whether it succeeded or failed - * in some fashion. - */ -static gboolean -get_sampling_arguments(capture_options *capture_opts, const char *arg) -{ - gchar *p = NULL, *colonp; - - colonp = strchr(arg, ':'); - if (colonp == NULL) - return FALSE; - - p = colonp; - *p++ = '\0'; - - while (g_ascii_isspace(*p)) - p++; - if (*p == '\0') { - *colonp = ':'; - return FALSE; - } - - if (strcmp(arg, "count") == 0) { - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->sampling_method = CAPTURE_SAMP_BY_COUNT; - interface_opts->sampling_param = get_positive_int(p, "sampling count"); - } else { - capture_opts->default_options.sampling_method = CAPTURE_SAMP_BY_COUNT; - capture_opts->default_options.sampling_param = get_positive_int(p, "sampling count"); - } - } else if (strcmp(arg, "timer") == 0) { - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->sampling_method = CAPTURE_SAMP_BY_TIMER; - interface_opts->sampling_param = get_positive_int(p, "sampling timer"); - } else { - capture_opts->default_options.sampling_method = CAPTURE_SAMP_BY_TIMER; - capture_opts->default_options.sampling_param = get_positive_int(p, "sampling timer"); - } - } - *colonp = ':'; - return TRUE; -} -#endif - -#ifdef HAVE_PCAP_REMOTE -/* - * Given a string of the form ":", as might appear - * as an argument to a "-A" option, parse it and set the arguments in - * question. Return an indication of whether it succeeded or failed - * in some fashion. - */ -static gboolean -get_auth_arguments(capture_options *capture_opts, const char *arg) -{ - gchar *p = NULL, *colonp; - - colonp = strchr(arg, ':'); - if (colonp == NULL) - return FALSE; - - p = colonp; - *p++ = '\0'; - - while (g_ascii_isspace(*p)) - p++; - - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->auth_type = CAPTURE_AUTH_PWD; - interface_opts->auth_username = g_strdup(arg); - interface_opts->auth_password = g_strdup(p); - } else { - capture_opts->default_options.auth_type = CAPTURE_AUTH_PWD; - capture_opts->default_options.auth_username = g_strdup(arg); - capture_opts->default_options.auth_password = g_strdup(p); - } - *colonp = ':'; - return TRUE; -} -#endif - -#ifdef _WIN32 -static char * -capture_opts_generate_display_name(const char *friendly_name, - const char *name _U_) -{ - /* - * Display the friendly name rather than the not-so-friendly - * GUID-based interface name. - */ - return g_strdup(friendly_name); -} -#else -static char * -capture_opts_generate_display_name(const char *friendly_name, - const char *name) -{ - /* - * On UN*X, however, users are more used to interface names, - * and may find it helpful to see them. - */ - return ws_strdup_printf("%s: %s", friendly_name, name); -} -#endif - -static void -fill_in_interface_opts_from_ifinfo(interface_options *interface_opts, - const if_info_t *if_info) -{ - interface_opts->name = g_strdup(if_info->name); - - interface_opts->hardware = g_strdup(if_info->vendor_description); - if (if_info->friendly_name != NULL) { - /* - * We have a friendly name; remember it as the - * description... - */ - interface_opts->descr = g_strdup(if_info->friendly_name); - /* - * ...and use it in the console display name. - */ - interface_opts->display_name = capture_opts_generate_display_name(if_info->friendly_name, if_info->name); - } else { - /* fallback to the interface name */ - interface_opts->descr = NULL; - interface_opts->display_name = g_strdup(if_info->name); - } - interface_opts->ifname = NULL; - interface_opts->if_type = if_info->type; - interface_opts->extcap = g_strdup(if_info->extcap); -} - -static if_info_t* -find_ifinfo_by_name(GList *if_list, const char *name) -{ - GList *if_entry; - if_info_t *matched_if_info; - size_t prefix_length; - - matched_if_info = NULL; - if (if_list != NULL) { - /* - * Try and do an exact match (case insensitive) on the - * interface name, the interface description, and the - * hardware description. - */ - for (if_entry = g_list_first(if_list); if_entry != NULL; - if_entry = g_list_next(if_entry)) - { - if_info_t *if_info = (if_info_t *)if_entry->data; - - /* - * Does the specified name match the interface name - * with a case-insensitive match? - */ - if (g_ascii_strcasecmp(if_info->name, name) == 0) { - /* - * Yes. - */ - matched_if_info = if_info; - break; - } - - /* - * Does this interface have a friendly name and, if so, - * does the specified name match the friendly name with - * a case-insensitive match? - */ - if (if_info->friendly_name != NULL && - g_ascii_strcasecmp(if_info->friendly_name, name) == 0) { - /* - * Yes. - */ - matched_if_info = if_info; - break; - } - -#ifdef _WIN32 - /* - * On Windows, we store interface names in preferences as: - * friendlyname (name) - * Do we have a case-insensitive match for that? - */ - if (if_info->friendly_name != NULL) { - GString* combined_name = g_string_new(if_info->friendly_name); - g_string_append_printf(combined_name, " (%s)", if_info->name); - if (g_ascii_strcasecmp(combined_name->str, name) == 0) { - /* - * Yes. - */ - matched_if_info = if_info; - } - g_string_free(combined_name, TRUE); - if (matched_if_info != NULL) { - break; - } - } -#endif - } - - if (matched_if_info == NULL) { - /* - * We didn't find it; attempt a case-insensitive prefix match - * of the friendly name. - */ - prefix_length = strlen(name); - for (if_entry = g_list_first(if_list); if_entry != NULL; - if_entry = g_list_next(if_entry)) - { - if_info_t *if_info = (if_info_t *)if_entry->data; - - if (if_info->friendly_name != NULL && - g_ascii_strncasecmp(if_info->friendly_name, name, prefix_length) == 0) { - /* - * We found an interface whose friendly name matches - * with a case-insensitive prefix match. - */ - matched_if_info = if_info; - break; - } - } - } - } - - return matched_if_info; -} - -static int -capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str_p) -{ - long adapter_index; - char *p; - GList *if_list; - if_info_t *if_info; - int err; - gchar *err_str; - interface_options interface_opts; - - /* - * If the argument is a number, treat it as an index into the list - * of adapters, as printed by "tshark -D". - * - * This should be OK on UN*X systems, as interfaces shouldn't have - * names that begin with digits. It can be useful on Windows, where - * more than one interface can have the same name. - * - * XXX - "shouldn't have names that begin with digits" is not true - * on Linux; see - * - * https://github.com/the-tcpdump-group/tcpdump/issues/522 - * - * tcpdump handles that by trying to open the device by name and, - * if that fails *and* the name is a syntactically valid number - * (optional sign, followed by decimal digits), reports an error - * if it's not a valid interface index, and otherwise uses it as - * an interface index. - */ - adapter_index = strtol(optarg_str_p, &p, 10); - if (p != NULL && *p == '\0') { - if (adapter_index < 0) { - cmdarg_err("The specified adapter index is a negative number"); - return 1; - } - if (adapter_index > INT_MAX) { - cmdarg_err("The specified adapter index is too large (greater than %d)", - INT_MAX); - return 1; - } - if (adapter_index == 0) { - cmdarg_err("There is no interface with that adapter index"); - return 1; - } - if_list = capture_opts->get_iface_list(&err, &err_str); - if (if_list == NULL) { - if (err == 0) - cmdarg_err("There are no interfaces on which a capture can be done"); - else { - cmdarg_err("%s", err_str); - g_free(err_str); - } - return 2; - } - if_info = (if_info_t *)g_list_nth_data(if_list, (int)(adapter_index - 1)); - if (if_info == NULL) { - cmdarg_err("There is no interface with that adapter index"); - return 1; - } - fill_in_interface_opts_from_ifinfo(&interface_opts, if_info); - free_interface_list(if_list); - } else if (capture_opts->capture_child) { - /* - * In Wireshark capture child mode, so the exact interface name - * is supplied, and we don't need to look it up. - */ - if_info = if_info_get(optarg_str_p); - fill_in_interface_opts_from_ifinfo(&interface_opts, if_info); - if_info_free(if_info); - } else { - /* - * Search for that name in the interface list and, if we found - * it, fill in fields in the interface_opts structure. - * - * XXX - if we can't get the interface list, we don't report - * an error, as, on Windows, that might be due to WinPcap or - * Npcap not being installed, but the specified "interface" - * might be the standard input ("=") or a pipe, and dumpcap - * should support capturing from the standard input or from - * a pipe even if there's no capture support from *pcap. - * - * Perhaps doing something similar to what was suggested - * for numerical interfaces should be done. - */ - if_list = capture_opts->get_iface_list(&err, &err_str); - if_info = find_ifinfo_by_name(if_list, optarg_str_p); - if (if_info != NULL) { - /* - * We found the interface in the list; fill in the - * interface_opts structure from its if_info. - */ - fill_in_interface_opts_from_ifinfo(&interface_opts, if_info); - } else { - /* - * We didn't find the interface in the list; just use - * the specified name, so that, for example, if an - * interface doesn't show up in the list for some - * reason, the user can try specifying it explicitly - * for testing purposes. - */ - interface_opts.name = g_strdup(optarg_str_p); - interface_opts.descr = NULL; - interface_opts.hardware = NULL; - interface_opts.display_name = g_strdup(optarg_str_p); - interface_opts.ifname = NULL; - interface_opts.if_type = capture_opts->default_options.if_type; - interface_opts.extcap = g_strdup(capture_opts->default_options.extcap); - } - free_interface_list(if_list); - } - - interface_opts.cfilter = g_strdup(capture_opts->default_options.cfilter); - interface_opts.snaplen = capture_opts->default_options.snaplen; - interface_opts.has_snaplen = capture_opts->default_options.has_snaplen; - interface_opts.linktype = capture_opts->default_options.linktype; - interface_opts.promisc_mode = capture_opts->default_options.promisc_mode; - interface_opts.extcap_fifo = g_strdup(capture_opts->default_options.extcap_fifo); - interface_opts.extcap_args = NULL; - interface_opts.extcap_pid = WS_INVALID_PID; - interface_opts.extcap_pipedata = NULL; - interface_opts.extcap_stderr = NULL; - interface_opts.extcap_stdout_watch = 0; - interface_opts.extcap_stderr_watch = 0; -#ifdef _WIN32 - interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE; - interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE; - interface_opts.extcap_control_out_h = INVALID_HANDLE_VALUE; -#endif - interface_opts.extcap_control_in = g_strdup(capture_opts->default_options.extcap_control_in); - interface_opts.extcap_control_out = g_strdup(capture_opts->default_options.extcap_control_out); -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - interface_opts.buffer_size = capture_opts->default_options.buffer_size; -#endif - interface_opts.monitor_mode = capture_opts->default_options.monitor_mode; -#ifdef HAVE_PCAP_REMOTE - interface_opts.src_type = capture_opts->default_options.src_type; - interface_opts.remote_host = g_strdup(capture_opts->default_options.remote_host); - interface_opts.remote_port = g_strdup(capture_opts->default_options.remote_port); - interface_opts.auth_type = capture_opts->default_options.auth_type; - interface_opts.auth_username = g_strdup(capture_opts->default_options.auth_username); - interface_opts.auth_password = g_strdup(capture_opts->default_options.auth_password); - interface_opts.datatx_udp = capture_opts->default_options.datatx_udp; - interface_opts.nocap_rpcap = capture_opts->default_options.nocap_rpcap; - interface_opts.nocap_local = capture_opts->default_options.nocap_local; -#endif -#ifdef HAVE_PCAP_SETSAMPLING - interface_opts.sampling_method = capture_opts->default_options.sampling_method; - interface_opts.sampling_param = capture_opts->default_options.sampling_param; -#endif - interface_opts.timestamp_type = capture_opts->default_options.timestamp_type; - - g_array_append_val(capture_opts->ifaces, interface_opts); - - return 0; -} - - -int -capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_str_p) -{ - int status, snaplen; - ws_statb64 fstat; - - switch(opt) { - case 'a': /* autostop criteria */ - if (set_autostop_criterion(capture_opts, optarg_str_p) == FALSE) { - cmdarg_err("Invalid or unknown -a flag \"%s\"", optarg_str_p); - return 1; - } - break; -#ifdef HAVE_PCAP_REMOTE - case 'A': - if (get_auth_arguments(capture_opts, optarg_str_p) == FALSE) { - cmdarg_err("Invalid or unknown -A arg \"%s\"", optarg_str_p); - return 1; - } - break; -#endif - case 'b': /* Ringbuffer option */ - capture_opts->multi_files_on = TRUE; - if (get_ring_arguments(capture_opts, optarg_str_p) == FALSE) { - cmdarg_err("Invalid or unknown -b arg \"%s\"", optarg_str_p); - return 1; - } - break; -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - case 'B': /* Buffer size */ - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->buffer_size = get_positive_int(optarg_str_p, "buffer size"); - } else { - capture_opts->default_options.buffer_size = get_positive_int(optarg_str_p, "buffer size"); - } - break; -#endif - case 'c': /* Capture n packets */ - /* XXX Use set_autostop_criterion instead? */ - capture_opts->has_autostop_packets = TRUE; - capture_opts->autostop_packets = get_positive_int(optarg_str_p, "packet count"); - break; - case 'f': /* capture filter */ - get_filter_arguments(capture_opts, optarg_str_p); - break; - case 'g': /* enable group read access on the capture file(s) */ - capture_opts->group_read_access = TRUE; - break; - case 'H': /* Hide capture info dialog box */ - capture_opts->show_info = FALSE; - break; - case LONGOPT_SET_TSTAMP_TYPE: /* Set capture time stamp type */ - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - g_free(interface_opts->timestamp_type); - interface_opts->timestamp_type = g_strdup(optarg_str_p); - } else { - g_free(capture_opts->default_options.timestamp_type); - capture_opts->default_options.timestamp_type = g_strdup(optarg_str_p); - } - break; - case 'i': /* Use interface x */ - status = capture_opts_add_iface_opt(capture_opts, optarg_str_p); - if (status != 0) { - return status; - } - break; -#ifdef HAVE_PCAP_CREATE - case 'I': /* Capture in monitor mode */ - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->monitor_mode = TRUE; - } else { - capture_opts->default_options.monitor_mode = TRUE; - } - break; -#endif - /*case 'l':*/ /* Automatic scrolling in live capture mode */ -#ifdef HAVE_PCAP_SETSAMPLING - case 'm': - if (get_sampling_arguments(capture_opts, optarg_str_p) == FALSE) { - cmdarg_err("Invalid or unknown -m arg \"%s\"", optarg_str_p); - return 1; - } - break; -#endif - case 'n': /* Use pcapng format */ - capture_opts->use_pcapng = TRUE; - break; - case 'p': /* Don't capture in promiscuous mode */ - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->promisc_mode = FALSE; - } else { - capture_opts->default_options.promisc_mode = FALSE; - } - break; - case 'P': /* Use pcap format */ - capture_opts->use_pcapng = FALSE; - break; -#ifdef HAVE_PCAP_REMOTE - case 'r': - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->nocap_rpcap = FALSE; - } else { - capture_opts->default_options.nocap_rpcap = FALSE; - } - break; -#endif - case 's': /* Set the snapshot (capture) length */ - snaplen = get_natural_int(optarg_str_p, "snapshot length"); - /* - * Make a snapshot length of 0 equivalent to the maximum packet - * length, mirroring what tcpdump does. - */ - if (snaplen == 0) - snaplen = WTAP_MAX_PACKET_SIZE_STANDARD; - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->has_snaplen = TRUE; - interface_opts->snaplen = snaplen; - } else { - capture_opts->default_options.snaplen = snaplen; - capture_opts->default_options.has_snaplen = TRUE; - } - break; - case 'S': /* "Real-Time" mode: used for following file ala tail -f */ - capture_opts->real_time_mode = TRUE; - break; -#ifdef HAVE_PCAP_REMOTE - case 'u': - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->datatx_udp = TRUE; - } else { - capture_opts->default_options.datatx_udp = TRUE; - } - break; -#endif - case 'w': /* Write to capture file x */ - capture_opts->saving_to_file = TRUE; - g_free(capture_opts->save_file); - capture_opts->save_file = g_strdup(optarg_str_p); - capture_opts->orig_save_file = g_strdup(optarg_str_p); - status = capture_opts_output_to_pipe(capture_opts->save_file, &capture_opts->output_to_pipe); - return status; - case 'y': /* Set the pcap data link type */ - if (capture_opts->ifaces->len > 0) { - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); - interface_opts->linktype = linktype_name_to_val(optarg_str_p); - if (interface_opts->linktype == -1) { - cmdarg_err("The specified data link type \"%s\" isn't valid", - optarg_str_p); - return 1; - } - } else { - capture_opts->default_options.linktype = linktype_name_to_val(optarg_str_p); - if (capture_opts->default_options.linktype == -1) { - cmdarg_err("The specified data link type \"%s\" isn't valid", - optarg_str_p); - return 1; - } - } - break; - case LONGOPT_COMPRESS_TYPE: /* compress type */ - if (capture_opts->compress_type) { - cmdarg_err("--compress-type can be set only once"); - return 1; - } - if (strcmp(optarg_str_p, "none") == 0) { - ; - } else if (strcmp(optarg_str_p, "gzip") == 0) { -#ifdef HAVE_ZLIB - ; -#else - cmdarg_err("'gzip' compression is not supported"); - return 1; -#endif - } else { -#ifdef HAVE_ZLIB - cmdarg_err("parameter of --compress-type can be 'none' or 'gzip'"); -#else - cmdarg_err("parameter of --compress-type can only be 'none'"); -#endif - return 1; - } - capture_opts->compress_type = g_strdup(optarg_str_p); - break; - case LONGOPT_CAPTURE_TMPDIR: /* capture temporary directory */ - if (capture_opts->temp_dir) { - cmdarg_err("--temp-dir can be set only once"); - return 1; - } - if (ws_stat64(optarg_str_p, &fstat) < 0) { - cmdarg_err("Can't set temporary directory %s: %s", - optarg_str_p, g_strerror(errno)); - return 1; - } - if (!S_ISDIR(fstat.st_mode)) { - cmdarg_err("Can't set temporary directory %s: not a directory", - optarg_str_p); - return 1; - } -#ifdef S_IRWXU - if ((fstat.st_mode & S_IRWXU) != S_IRWXU) { - cmdarg_err("Can't set temporary directory %s: not a writable directory", - optarg_str_p); - return 1; - } -#endif /* S_IRWXU */ - capture_opts->temp_dir = g_strdup(optarg_str_p); - break; - case LONGOPT_UPDATE_INTERVAL: /* capture update interval */ - capture_opts->update_interval = get_positive_int(optarg_str_p, "update interval"); - break; - default: - /* the caller is responsible to send us only the right opt's */ - ws_assert_not_reached(); - } - - return 0; -} - -int -capture_opts_print_if_capabilities(if_capabilities_t *caps, - interface_options *interface_opts, - int queries) -{ - GList *lt_entry, *ts_entry; - - if (queries & CAPS_QUERY_LINK_TYPES) { - if (caps->data_link_types == NULL) { - cmdarg_err("The capture device \"%s\" has no data link types.", - interface_opts->name); - return WS_EXIT_IFACE_HAS_NO_LINK_TYPES; - } - if (caps->can_set_rfmon) - printf("Data link types of interface %s when %sin monitor mode (use option -y to set):\n", - interface_opts->name, - (interface_opts->monitor_mode) ? "" : "not "); - else - printf("Data link types of interface %s (use option -y to set):\n", - interface_opts->name); - for (lt_entry = caps->data_link_types; lt_entry != NULL; - lt_entry = g_list_next(lt_entry)) { - data_link_info_t *data_link_info = (data_link_info_t *)lt_entry->data; - printf(" %s", data_link_info->name); - if (data_link_info->description != NULL) - printf(" (%s)", data_link_info->description); - else - printf(" (not supported)"); - printf("\n"); - } - } - - if (queries & CAPS_QUERY_TIMESTAMP_TYPES) { - if (caps->timestamp_types == NULL) { - cmdarg_err("The capture device \"%s\" has no timestamp types.", - interface_opts->name); - return WS_EXIT_IFACE_HAS_NO_TIMESTAMP_TYPES; - } - printf("Timestamp types of the interface (use option --time-stamp-type to set):\n"); - for (ts_entry = caps->timestamp_types; ts_entry != NULL; - ts_entry = g_list_next(ts_entry)) { - timestamp_info_t *timestamp = (timestamp_info_t *)ts_entry->data; - printf(" %s", timestamp->name); - if (timestamp->description != NULL) - printf(" (%s)", timestamp->description); - else - printf(" (none)"); - printf("\n"); - } - } - return EXIT_SUCCESS; -} - -/* Print an ASCII-formatted list of interfaces. */ -void -capture_opts_print_interfaces(GList *if_list) -{ - int i; - GList *if_entry; - if_info_t *if_info; - - i = 1; /* Interface id number */ - for (if_entry = g_list_first(if_list); if_entry != NULL; - if_entry = g_list_next(if_entry)) { - if_info = (if_info_t *)if_entry->data; - printf("%d. %s", i++, if_info->name); - - /* Print the interface friendly name, if it exists; - if not, fall back to the vendor description, if it exists. */ - if (if_info->friendly_name != NULL){ - printf(" (%s)", if_info->friendly_name); - } else { - if (if_info->vendor_description != NULL) - printf(" (%s)", if_info->vendor_description); - } - printf("\n"); - } -} - - -void -capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min) -{ - guint i; - interface_options *interface_opts; - - if (capture_opts->ifaces->len > 0) { - for (i = 0; i < capture_opts->ifaces->len; i++) { - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, 0); - if (interface_opts->snaplen < 1) - interface_opts->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD; - else if (interface_opts->snaplen < snaplen_min) - interface_opts->snaplen = snaplen_min; - } - } else { - if (capture_opts->default_options.snaplen < 1) - capture_opts->default_options.snaplen = WTAP_MAX_PACKET_SIZE_STANDARD; - else if (capture_opts->default_options.snaplen < snaplen_min) - capture_opts->default_options.snaplen = snaplen_min; - } -} - - -void -capture_opts_trim_ring_num_files(capture_options *capture_opts) -{ - /* Check the value range of the ring_num_files parameter */ - if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES) { - cmdarg_err("Too many ring buffer files (%u). Reducing to %u.\n", capture_opts->ring_num_files, RINGBUFFER_MAX_NUM_FILES); - capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES; - } else if (capture_opts->ring_num_files > RINGBUFFER_WARN_NUM_FILES) { - cmdarg_err("%u is a lot of ring buffer files.\n", capture_opts->ring_num_files); - } -#if RINGBUFFER_MIN_NUM_FILES > 0 - else if (capture_opts->ring_num_files < RINGBUFFER_MIN_NUM_FILES) { - cmdarg_err("Too few ring buffer files (%u). Increasing to %u.\n", capture_opts->ring_num_files, RINGBUFFER_MIN_NUM_FILES); - capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES; - } -#endif -} - -/* - * If no interface was specified explicitly, pick a default. - */ -int -capture_opts_default_iface_if_necessary(capture_options *capture_opts, - const char *capture_device) -{ - int status; - - /* Did the user specify an interface to use? */ - if (capture_opts->num_selected != 0 || capture_opts->ifaces->len != 0) { - /* yes they did, return immediately - nothing further to do here */ - return 0; - } - - /* No - is a default specified in the preferences file? */ - if (capture_device != NULL) { - /* Yes - use it. */ - status = capture_opts_add_iface_opt(capture_opts, capture_device); - return status; - } - /* No default in preferences file, just pick the first interface from the list of interfaces. */ - return capture_opts_add_iface_opt(capture_opts, "1"); -} - -#ifndef S_IFIFO -#define S_IFIFO _S_IFIFO -#endif -#ifndef S_ISFIFO -#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) -#endif - -/* copied from filesystem.c */ -static int -capture_opts_test_for_fifo(const char *path) -{ - ws_statb64 statb; - - if (ws_stat64(path, &statb) < 0) - return errno; - - if (S_ISFIFO(statb.st_mode)) - return ESPIPE; - else - return 0; -} - -static gboolean -capture_opts_output_to_pipe(const char *save_file, gboolean *is_pipe) -{ - int err; - - *is_pipe = FALSE; - - if (save_file != NULL) { - /* We're writing to a capture file. */ - if (strcmp(save_file, "-") == 0) { - /* Writing to stdout. */ - /* XXX - should we check whether it's a pipe? It's arguably - silly to do "-w - >output_file" rather than "-w output_file", - but by not checking we might be violating the Principle Of - Least Astonishment. */ - *is_pipe = TRUE; - } else { - /* not writing to stdout, test for a FIFO (aka named pipe) */ - err = capture_opts_test_for_fifo(save_file); - switch (err) { - - case ENOENT: /* it doesn't exist, so we'll be creating it, - and it won't be a FIFO */ - case 0: /* found it, but it's not a FIFO */ - break; - - case ESPIPE: /* it is a FIFO */ - *is_pipe = TRUE; - break; - - default: /* couldn't stat it */ - break; /* ignore: later attempt to open */ - /* will generate a nice msg */ - } - } - } - - return 0; -} - -void -capture_opts_del_iface(capture_options *capture_opts, guint if_index) -{ - interface_options *interface_opts; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, if_index); - /* XXX - check if found? */ - - g_free(interface_opts->name); - g_free(interface_opts->descr); - g_free(interface_opts->hardware); - g_free(interface_opts->display_name); - g_free(interface_opts->ifname); - g_free(interface_opts->cfilter); - g_free(interface_opts->timestamp_type); - g_free(interface_opts->extcap); - g_free(interface_opts->extcap_fifo); - if (interface_opts->extcap_args) - g_hash_table_unref(interface_opts->extcap_args); - if (interface_opts->extcap_pid != WS_INVALID_PID) - ws_warning("Extcap still running during interface delete"); - g_free(interface_opts->extcap_pipedata); - if (interface_opts->extcap_stderr) - g_string_free(interface_opts->extcap_stderr, TRUE); - g_free(interface_opts->extcap_control_in); - g_free(interface_opts->extcap_control_out); -#ifdef HAVE_PCAP_REMOTE - if (interface_opts->src_type == CAPTURE_IFREMOTE) { - g_free(interface_opts->remote_host); - g_free(interface_opts->remote_port); - g_free(interface_opts->auth_username); - g_free(interface_opts->auth_password); - } -#endif - capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, if_index); -} - - - -/* - * Add all non-hidden selected interfaces in the "all interfaces" list - * to the list of interfaces for the capture. - */ -void -collect_ifaces(capture_options *capture_opts) -{ - guint i; - interface_t *device; - interface_options interface_opts; - - /* Empty out the existing list of interfaces. */ - for (i = capture_opts->ifaces->len; i != 0; i--) - capture_opts_del_iface(capture_opts, i-1); - - /* Now fill the list up again. */ - for (i = 0; i < capture_opts->all_ifaces->len; i++) { - device = &g_array_index(capture_opts->all_ifaces, interface_t, i); - if (device->selected) { - interface_opts.name = g_strdup(device->name); - interface_opts.descr = g_strdup(device->friendly_name); - interface_opts.ifname = NULL; - interface_opts.hardware = g_strdup(device->vendor_description); - interface_opts.display_name = g_strdup(device->display_name); - interface_opts.linktype = device->active_dlt; - interface_opts.cfilter = g_strdup(device->cfilter); - interface_opts.timestamp_type = g_strdup(device->timestamp_type); - interface_opts.snaplen = device->snaplen; - interface_opts.has_snaplen = device->has_snaplen; - interface_opts.promisc_mode = device->pmode; - interface_opts.if_type = device->if_info.type; - interface_opts.extcap = g_strdup(device->if_info.extcap); - interface_opts.extcap_fifo = NULL; - interface_opts.extcap_pipedata = NULL; - interface_opts.extcap_args = device->external_cap_args_settings; - interface_opts.extcap_pid = WS_INVALID_PID; - if (interface_opts.extcap_args) - g_hash_table_ref(interface_opts.extcap_args); - interface_opts.extcap_pipedata = NULL; - interface_opts.extcap_stderr = NULL; -#ifdef _WIN32 - interface_opts.extcap_pipe_h = INVALID_HANDLE_VALUE; - interface_opts.extcap_control_in_h = INVALID_HANDLE_VALUE; - interface_opts.extcap_control_out_h = INVALID_HANDLE_VALUE; -#endif - interface_opts.extcap_control_in = NULL; - interface_opts.extcap_control_out = NULL; -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - interface_opts.buffer_size = device->buffer; -#endif -#ifdef HAVE_PCAP_CREATE - interface_opts.monitor_mode = device->monitor_mode_enabled; -#endif -#ifdef HAVE_PCAP_REMOTE - interface_opts.src_type = CAPTURE_IFREMOTE; - interface_opts.remote_host = g_strdup(device->remote_opts.remote_host_opts.remote_host); - interface_opts.remote_port = g_strdup(device->remote_opts.remote_host_opts.remote_port); - interface_opts.auth_type = device->remote_opts.remote_host_opts.auth_type; - interface_opts.auth_username = g_strdup(device->remote_opts.remote_host_opts.auth_username); - interface_opts.auth_password = g_strdup(device->remote_opts.remote_host_opts.auth_password); - interface_opts.datatx_udp = device->remote_opts.remote_host_opts.datatx_udp; - interface_opts.nocap_rpcap = device->remote_opts.remote_host_opts.nocap_rpcap; - interface_opts.nocap_local = device->remote_opts.remote_host_opts.nocap_local; -#endif -#ifdef HAVE_PCAP_SETSAMPLING - interface_opts.sampling_method = device->remote_opts.sampling_method; - interface_opts.sampling_param = device->remote_opts.sampling_param; -#endif - g_array_append_val(capture_opts->ifaces, interface_opts); - } else { - continue; - } - } -} - -static void -capture_opts_free_interface_t_links(gpointer elem, gpointer unused _U_) -{ - link_row* e = (link_row*)elem; - if (e != NULL) - g_free(e->name); - g_free(elem); -} - -void -capture_opts_free_interface_t(interface_t *device) -{ - if (device != NULL) { - g_free(device->name); - g_free(device->display_name); - g_free(device->vendor_description); - g_free(device->friendly_name); - g_free(device->addresses); - g_free(device->cfilter); - g_free(device->timestamp_type); - g_list_foreach(device->links, - capture_opts_free_interface_t_links, NULL); - g_list_free(device->links); -#ifdef HAVE_PCAP_REMOTE - g_free(device->remote_opts.remote_host_opts.remote_host); - g_free(device->remote_opts.remote_host_opts.remote_port); - g_free(device->remote_opts.remote_host_opts.auth_username); - g_free(device->remote_opts.remote_host_opts.auth_password); -#endif - g_free(device->if_info.name); - g_free(device->if_info.friendly_name); - g_free(device->if_info.vendor_description); - g_slist_free_full(device->if_info.addrs, g_free); - g_free(device->if_info.extcap); - } -} - -#endif /* HAVE_LIBPCAP */ - -/* - * Editor modelines - https://www.wireshark.org/tools/modelines.html - * - * Local variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * vi: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=8:noTabs=true: - */ diff --git a/include/wireshark/capture_opts.h b/include/wireshark/capture_opts.h deleted file mode 100644 index 32b7d154..00000000 --- a/include/wireshark/capture_opts.h +++ /dev/null @@ -1,425 +0,0 @@ -/* capture_opts.h - * Capture options (all parameters needed to do the actual capture) - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - - -/** @file - * - * Capture options (all parameters needed to do the actual capture) - * - */ - -#ifndef __CAPTURE_OPTS_H__ -#define __CAPTURE_OPTS_H__ - -#include /* for gid_t */ - -#include -#include "ringbuffer.h" -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* - * Long options. - * We do not currently have long options corresponding to all short - * options; we should probably pick appropriate option names for them. - * - * NOTE: - * for tshark, we're using a leading - in the optstring to prevent getopt() - * from permuting the argv[] entries, in this case, unknown argv[] entries - * will be returned as parameters to a dummy-option 1. - * In short: we must not use 1 here, which is another reason to use - * values outside the range of ASCII graphic characters. - */ -#define LONGOPT_LIST_TSTAMP_TYPES LONGOPT_BASE_CAPTURE+1 -#define LONGOPT_SET_TSTAMP_TYPE LONGOPT_BASE_CAPTURE+2 -#define LONGOPT_COMPRESS_TYPE LONGOPT_BASE_CAPTURE+3 -#define LONGOPT_CAPTURE_TMPDIR LONGOPT_BASE_CAPTURE+4 -#define LONGOPT_UPDATE_INTERVAL LONGOPT_BASE_CAPTURE+5 - -/* - * Options for capturing common to all capturing programs. - */ -#ifdef HAVE_PCAP_REMOTE -#define OPTSTRING_A "A:" -#else -#define OPTSTRING_A -#endif - -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE -#define LONGOPT_BUFFER_SIZE \ - {"buffer-size", ws_required_argument, NULL, 'B'}, -#define OPTSTRING_B "B:" -#else -#define LONGOPT_BUFFER_SIZE -#define OPTSTRING_B -#endif - -#ifdef HAVE_PCAP_CREATE -#define LONGOPT_MONITOR_MODE {"monitor-mode", ws_no_argument, NULL, 'I'}, -#define OPTSTRING_I "I" -#else -#define LONGOPT_MONITOR_MODE -#define OPTSTRING_I -#endif - -#define LONGOPT_CAPTURE_COMMON \ - {"autostop", ws_required_argument, NULL, 'a'}, \ - {"ring-buffer", ws_required_argument, NULL, 'b'}, \ - LONGOPT_BUFFER_SIZE \ - {"list-interfaces", ws_no_argument, NULL, 'D'}, \ - {"interface", ws_required_argument, NULL, 'i'}, \ - LONGOPT_MONITOR_MODE \ - {"list-data-link-types", ws_no_argument, NULL, 'L'}, \ - {"no-promiscuous-mode", ws_no_argument, NULL, 'p'}, \ - {"snapshot-length", ws_required_argument, NULL, 's'}, \ - {"linktype", ws_required_argument, NULL, 'y'}, \ - {"list-time-stamp-types", ws_no_argument, NULL, LONGOPT_LIST_TSTAMP_TYPES}, \ - {"time-stamp-type", ws_required_argument, NULL, LONGOPT_SET_TSTAMP_TYPE}, \ - {"compress-type", ws_required_argument, NULL, LONGOPT_COMPRESS_TYPE}, \ - {"temp-dir", ws_required_argument, NULL, LONGOPT_CAPTURE_TMPDIR},\ - {"update-interval", ws_required_argument, NULL, LONGOPT_UPDATE_INTERVAL}, - - -#define OPTSTRING_CAPTURE_COMMON \ - "a:" OPTSTRING_A "b:" OPTSTRING_B "c:Df:i:" OPTSTRING_I "Lps:y:" - -#ifdef HAVE_PCAP_REMOTE -/* Type of capture source */ -typedef enum { - CAPTURE_IFLOCAL, /**< Local network interface */ - CAPTURE_IFREMOTE /**< Remote network interface */ -} capture_source; - -/* Type of RPCAPD Authentication */ -typedef enum { - CAPTURE_AUTH_NULL, /**< No authentication */ - CAPTURE_AUTH_PWD /**< User/password authentication */ -} capture_auth; -#endif -#ifdef HAVE_PCAP_SETSAMPLING -/** - * Method of packet sampling (dropping some captured packets), - * may require additional integer parameter, marked here as N - */ -typedef enum { - CAPTURE_SAMP_NONE, /**< No sampling - capture all packets */ - CAPTURE_SAMP_BY_COUNT, /**< Counter-based sampling - - capture 1 packet from every N */ - CAPTURE_SAMP_BY_TIMER /**< Timer-based sampling - - capture no more than 1 packet - in N milliseconds */ -} capture_sampling; -#endif - -#ifdef HAVE_PCAP_REMOTE -struct remote_host_info { - gchar *remote_host; /**< Host name or network address for remote capturing */ - gchar *remote_port; /**< TCP port of remote RPCAP server */ - capture_auth auth_type; /**< Authentication type */ - gchar *auth_username; /**< Remote authentication parameters */ - gchar *auth_password; /**< Remote authentication parameters */ - gboolean datatx_udp; - gboolean nocap_rpcap; - gboolean nocap_local; -}; - -struct remote_host { - gchar *r_host; /**< Host name or network address for remote capturing */ - gchar *remote_port; /**< TCP port of remote RPCAP server */ - capture_auth auth_type; /**< Authentication type */ - gchar *auth_username; /**< Remote authentication parameters */ - gchar *auth_password; /**< Remote authentication parameters */ -}; - -typedef struct remote_options_tag { - capture_source src_type; - struct remote_host_info remote_host_opts; -#ifdef HAVE_PCAP_SETSAMPLING - capture_sampling sampling_method; - int sampling_param; -#endif -} remote_options; -#endif /* HAVE_PCAP_REMOTE */ - -typedef struct interface_tag { - gchar *name; - gchar *display_name; - gchar *friendly_name; - gchar *vendor_description; - guint type; - gchar *addresses; - gint no_addresses; - gchar *cfilter; - GList *links; - gint active_dlt; - gboolean pmode; - gboolean has_snaplen; - int snaplen; - gboolean local; -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - gint buffer; -#endif -#ifdef HAVE_PCAP_CREATE - gboolean monitor_mode_enabled; - gboolean monitor_mode_supported; -#endif -#ifdef HAVE_PCAP_REMOTE - remote_options remote_opts; -#endif - guint32 last_packets; - guint32 packet_diff; - if_info_t if_info; - gboolean selected; - gboolean hidden; - /* External capture cached data */ - GHashTable *external_cap_args_settings; - gchar *timestamp_type; -} interface_t; - -typedef struct link_row_tag { - gchar *name; - gint dlt; -} link_row; - -typedef struct interface_options_tag { - gchar *name; /* the name of the interface supplied to libpcap/WinPcap/Npcap to specify the interface */ - gchar *descr; /* a more user-friendly description of the interface; may be NULL if none */ - gchar *hardware; /* description of the hardware */ - gchar *display_name; /* the name displayed in the console and title bar */ - gchar *ifname; /* if not null, name to use instead of the interface naem in IDBs */ - gchar *cfilter; - gboolean has_snaplen; - int snaplen; - int linktype; - gboolean promisc_mode; - interface_type if_type; - gchar *extcap; - gchar *extcap_fifo; - GHashTable *extcap_args; - GPid extcap_pid; /* pid of running process or WS_INVALID_PID */ - gpointer extcap_pipedata; - GString *extcap_stderr; - guint extcap_stdout_watch; - guint extcap_stderr_watch; -#ifdef _WIN32 - HANDLE extcap_pipe_h; - HANDLE extcap_control_in_h; - HANDLE extcap_control_out_h; -#endif - gchar *extcap_control_in; - gchar *extcap_control_out; -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - int buffer_size; -#endif - gboolean monitor_mode; -#ifdef HAVE_PCAP_REMOTE - capture_source src_type; - gchar *remote_host; - gchar *remote_port; - capture_auth auth_type; - gchar *auth_username; - gchar *auth_password; - gboolean datatx_udp; - gboolean nocap_rpcap; - gboolean nocap_local; -#endif -#ifdef HAVE_PCAP_SETSAMPLING - capture_sampling sampling_method; - int sampling_param; -#endif - gchar *timestamp_type; /* requested timestamp as string */ - int timestamp_type_id; /* Timestamp type to pass to pcap_set_tstamp_type. - only valid if timestamp_type != NULL */ -} interface_options; - -/** Capture options coming from user interface */ -typedef struct capture_options_tag { - /* general */ - GList *(*get_iface_list)(int *, gchar **); - /**< routine to call to get the interface list */ - GArray *ifaces; /**< the interfaces to use for the - next capture, entries are of - type interface_options */ - GArray *all_ifaces; /**< all interfaces, entries are - of type interface_t */ - int ifaces_err; /**< if all_ifaces is null, the error - when it was fetched, if any */ - gchar *ifaces_err_info; /**< error string for that error */ - guint num_selected; - - /* - * Options to be applied to all interfaces. - * - * Some of these can be set from the GUI, others can't; setting - * the link-layer header type, for example, doesn't necessarily - * make sense, as different interfaces may support different sets - * of link-layer header types. - * - * Some that can't be set from the GUI can be set from the command - * line, by specifying them before any interface is specified. - * This includes the link-layer header type, so if somebody asks - * for a link-layer header type that an interface on which they're - * capturing doesn't support, we should report an error and fail - * to capture. - * - * These can be overridden per-interface. - */ - interface_options default_options; - - gboolean saving_to_file; /**< TRUE if capture is writing to a file */ - gchar *save_file; /**< the capture file name */ - gboolean group_read_access; /**< TRUE is group read permission needs to be set */ - gboolean use_pcapng; /**< TRUE if file format is pcapng */ - guint update_interval; /**< Time in milliseconds. How often to notify parent of new packet counts, check file duration, etc. */ - - /* GUI related */ - gboolean real_time_mode; /**< Update list of packets in real time */ - gboolean show_info; /**< show the info dialog. */ - gboolean restart; /**< restart after closing is done */ - gchar *orig_save_file; /**< the original capture file name (saved for a restart) */ - - /* multiple files (and ringbuffer) */ - gboolean multi_files_on; /**< TRUE if ring buffer in use */ - - gboolean has_file_duration; /**< TRUE if ring duration specified */ - gdouble file_duration; /**< Switch file after n seconds */ - gboolean has_file_interval; /**< TRUE if ring interval specified */ - gint32 file_interval; /**< Create time intervals of n seconds */ - gboolean has_file_packets; /**< TRUE if ring packet count is - specified */ - int file_packets; /**< Switch file after n packets */ - gboolean has_ring_num_files; /**< TRUE if ring num_files specified */ - guint32 ring_num_files; /**< Number of multiple buffer files */ - gboolean has_nametimenum; /**< TRUE if file name has date part before num part */ - - /* autostop conditions */ - gboolean has_autostop_files; /**< TRUE if maximum number of capture files - are specified */ - int autostop_files; /**< Maximum number of capture files */ - - gboolean has_autostop_packets; /**< TRUE if maximum packet count is - specified */ - int autostop_packets; /**< Maximum packet count */ - gboolean has_autostop_written_packets; /**< TRUE if maximum packet count is - specified */ - int autostop_written_packets; /**< Maximum packet count */ - gboolean has_autostop_filesize; /**< TRUE if maximum capture file size - is specified */ - guint32 autostop_filesize; /**< Maximum capture file size in kB */ - gboolean has_autostop_duration; /**< TRUE if maximum capture duration - is specified */ - gdouble autostop_duration; /**< Maximum capture duration */ - - gboolean print_file_names; /**< TRUE if printing names of completed - files as we close them */ - gchar *print_name_to; /**< output file name */ - gchar *temp_dir; /**< temporary directory path */ - - /* internally used (don't touch from outside) */ - gboolean output_to_pipe; /**< save_file is a pipe (named or stdout) */ - gboolean capture_child; /**< hidden option: Wireshark child mode */ - gboolean stop_after_extcaps; /**< request dumpcap stop after last extcap */ - gboolean wait_for_extcap_cbs; /**< extcaps terminated, waiting for callbacks */ - gchar *compress_type; /**< compress type */ - gchar *closed_msg; /**< Dumpcap capture closed message */ - guint extcap_terminate_id; /**< extcap process termination source ID */ -} capture_options; - -/* - * Initialize the capture_options with some reasonable values, and - * provide a routine it can use to fetch a list of capture options - * if it needs it. - * - * (Getting that list might involve running dumpcap, so we don't want - * to waste time doing that if we don't have to.) - */ -extern void -capture_opts_init(capture_options *capture_opts, GList *(*get_iface_list)(int *, gchar **)); - -/* clean internal structures */ -extern void -capture_opts_cleanup(capture_options *capture_opts); - -/* set a command line option value */ -extern int -capture_opts_add_opt(capture_options *capture_opts, int opt, const char *ws_optarg); - -/* log content of capture_opts */ -extern void -capture_opts_log(const char *domain, enum ws_log_level level, capture_options *capture_opts); - -enum caps_query { - CAPS_QUERY_LINK_TYPES = 0x1, - CAPS_QUERY_TIMESTAMP_TYPES = 0x2 -}; - -/* print interface capabilities, including link layer types */ -extern int -capture_opts_print_if_capabilities(if_capabilities_t *caps, - interface_options *interface_opts, - int queries); - -/* print list of interfaces */ -extern void -capture_opts_print_interfaces(GList *if_list); - -/* trim the snaplen entry */ -extern void -capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min); - -/* trim the ring_num_files entry */ -extern void -capture_opts_trim_ring_num_files(capture_options *capture_opts); - -/* pick default interface if none was specified */ -extern int -capture_opts_default_iface_if_necessary(capture_options *capture_opts, - const char *capture_device); - -extern void -capture_opts_del_iface(capture_options *capture_opts, guint if_index); - -extern void -collect_ifaces(capture_options *capture_opts); - -extern void -capture_opts_free_interface_t(interface_t *device); - -/* Default capture buffer size in Mbytes. */ -#define DEFAULT_CAPTURE_BUFFER_SIZE 2 - -/* Default update interval in milliseconds */ -#define DEFAULT_UPDATE_INTERVAL 100 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __CAPTURE_OPTS_H__ */ - -/* - * Editor modelines - https://www.wireshark.org/tools/modelines.html - * - * Local variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * vi: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=8:noTabs=true: - */ diff --git a/include/wireshark/captype.c b/include/wireshark/captype.c deleted file mode 100644 index 080a5433..00000000 --- a/include/wireshark/captype.c +++ /dev/null @@ -1,204 +0,0 @@ -/* captype.c - * Reports capture file type - * - * Based on capinfos.c - * Copyright 2004 Ian Schorr - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#define WS_LOG_DOMAIN LOG_DOMAIN_MAIN - -#include -#include -#include -#include -#include - -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_PLUGINS -#include -#endif - -#include -#include -#include - -#include "ui/failure_message.h" - -static void -print_usage(FILE *output) -{ - fprintf(output, "\n"); - fprintf(output, "Usage: captype [options] ...\n"); - fprintf(output, "\n"); - fprintf(output, "Miscellaneous:\n"); - fprintf(output, " -h, --help display this help and exit\n"); - fprintf(output, " -v, --version display version info and exit\n"); -} - -/* - * Report an error in command-line arguments. - */ -static void -captype_cmdarg_err(const char *msg_format, va_list ap) -{ - fprintf(stderr, "captype: "); - vfprintf(stderr, msg_format, ap); - fprintf(stderr, "\n"); -} - -/* - * Report additional information for an error in command-line arguments. - */ -static void -captype_cmdarg_err_cont(const char *msg_format, va_list ap) -{ - vfprintf(stderr, msg_format, ap); - fprintf(stderr, "\n"); -} - -int -main(int argc, char *argv[]) -{ - char *configuration_init_error; - static const struct report_message_routines captype_report_routines = { - failure_message, - failure_message, - open_failure_message, - read_failure_message, - write_failure_message, - cfile_open_failure_message, - cfile_dump_open_failure_message, - cfile_read_failure_message, - cfile_write_failure_message, - cfile_close_failure_message - }; - wtap *wth; - int err; - gchar *err_info; - int i; - int opt; - int overall_error_status; - static const struct ws_option long_options[] = { - {"help", ws_no_argument, NULL, 'h'}, - {"version", ws_no_argument, NULL, 'v'}, - {0, 0, 0, 0 } - }; - - /* - * Set the C-language locale to the native environment and set the - * code page to UTF-8 on Windows. - */ -#ifdef _WIN32 - setlocale(LC_ALL, ".UTF-8"); -#else - setlocale(LC_ALL, ""); -#endif - - cmdarg_err_init(captype_cmdarg_err, captype_cmdarg_err_cont); - - /* Initialize log handler early so we can have proper logging during startup. */ - ws_log_init("captype", vcmdarg_err); - - /* Early logging command-line initialization. */ - ws_log_parse_args(&argc, argv, vcmdarg_err, 1); - - ws_noisy("Finished log init and parsing command line log arguments"); - - /* Initialize the version information. */ - ws_init_version_info("Captype", NULL, NULL); - -#ifdef _WIN32 - create_app_running_mutex(); -#endif /* _WIN32 */ - - /* - * Get credential information for later use. - */ - init_process_policies(); - - /* - * Attempt to get the pathname of the directory containing the - * executable file. - */ - configuration_init_error = configuration_init(argv[0], NULL); - if (configuration_init_error != NULL) { - fprintf(stderr, - "captype: Can't get pathname of directory containing the captype program: %s.\n", - configuration_init_error); - g_free(configuration_init_error); - } - - init_report_message("captype", &captype_report_routines); - - wtap_init(TRUE); - - /* Process the options */ - while ((opt = ws_getopt_long(argc, argv, "hv", long_options, NULL)) !=-1) { - - switch (opt) { - - case 'h': - show_help_header("Print the file types of capture files."); - print_usage(stdout); - exit(0); - break; - - case 'v': - show_version(); - exit(0); - break; - - case '?': /* Bad flag - print usage message */ - print_usage(stderr); - exit(1); - break; - } - } - - if (argc < 2) { - print_usage(stderr); - return 1; - } - - overall_error_status = 0; - - for (i = 1; i < argc; i++) { - wth = wtap_open_offline(argv[i], WTAP_TYPE_AUTO, &err, &err_info, FALSE); - - if(wth) { - printf("%s: %s\n", argv[i], wtap_file_type_subtype_name(wtap_file_type_subtype(wth))); - wtap_close(wth); - } else { - if (err == WTAP_ERR_FILE_UNKNOWN_FORMAT) - printf("%s: unknown\n", argv[i]); - else { - cfile_open_failure_message(argv[i], err, err_info); - overall_error_status = 2; /* remember that an error has occurred */ - } - } - - } - - wtap_cleanup(); - free_progdirs(); - return overall_error_status; -} diff --git a/include/wireshark/cli_main.c b/include/wireshark/cli_main.c deleted file mode 100644 index a478e3d3..00000000 --- a/include/wireshark/cli_main.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Compile and link this with all CLI programs where the main routine - * should get UTF-8 arguments on Windows. In those programs, include the - * cli_main.h header to rename main to real_main on Windows. - * - * This is used in software licensed under the GPLv2, and its license MUST - * be compatible with that license. - * - * This is used in software licensed under the Apache 2.0 license, and its - * license MUST be compatible with that license. - * - * For that purpose, we use the MIT (X11) license. - * - * SPDX-License-Identifier: MIT - */ - -#include "cli_main.h" - -#ifdef _WIN32 -#include -#include -#include - -int -wmain(int argc, wchar_t *wc_argv[]) -{ - char **argv; - int i; - int return_code; - - argv = (char **)malloc((argc + 1) * sizeof(char *)); - if (argv == NULL) { - fprintf(stderr, "Out of memory for converted argument list\n"); - return 2; - } - for (i = 0; i < argc; i++) { - /* - * XXX = use WC_ERR_INVALID_CHARS rather than 0, and fail if - * the argument isn't valid UTF-16? - */ - int width; - char *utf8_string; - - width = WideCharToMultiByte(CP_UTF8, 0, wc_argv[i], -1, NULL, 0, - NULL, NULL); - if (width == 0) { - fprintf(stderr, "WideCharToMultiByte failed: %d\n", - width); - return 2; - } - utf8_string = malloc(width); - if (utf8_string == NULL) { - fprintf(stderr, - "Out of memory for converted argument list\n"); - return 2; - } - if (WideCharToMultiByte(CP_UTF8, 0, wc_argv[i], -1, utf8_string, - width, NULL, NULL) == 0) { - fprintf(stderr, "WideCharToMultiByte failed: %d\n", - width); - return 2; - } - argv[i] = utf8_string; - } - argv[i] = NULL; - /* - * The original "main" routine was renamed to "real_main" via a macro in - * the cli_main.h header file since either "main" or "wmain" can be - * defined on Windows, but not both. - */ - return_code = real_main(argc, argv); - for (i = 0; i < argc; i++) { - free(argv[i]); - } - free(argv); - return return_code; -} -#endif diff --git a/include/wireshark/cli_main.h b/include/wireshark/cli_main.h deleted file mode 100644 index d05b9f28..00000000 --- a/include/wireshark/cli_main.h +++ /dev/null @@ -1,22 +0,0 @@ -/** @file - * - * Declaration of the real main routine, for all CLI programs where the - * main routine should get UTF-8 arguments on Windows. In those programs, - * in the file that defines the main routine, include this header and link - * those programs with cli_main.c. - * - * This is used in software licensed under the GPLv2, and its license MUST - * be compatible with that license. - * - * This is used in software licensed under the Apache 2.0 license, and its - * license MUST be compatible with that license. - * - * For that purpose, we use the MIT (X11) license. - * - * SPDX-License-Identifier: MIT - */ - -#ifdef _WIN32 -int real_main(int argc, char *argv[]); -#define main real_main -#endif diff --git a/include/wireshark/config.h b/include/wireshark/config.h index 7595f39f..298db6bb 100644 --- a/include/wireshark/config.h +++ b/include/wireshark/config.h @@ -11,10 +11,10 @@ #define VERSION_EXTRA "" /* Version number of Wireshark and associated utilities */ -#define VERSION "4.2.4" +#define VERSION "4.2.5" #define VERSION_MAJOR 4 #define VERSION_MINOR 2 -#define VERSION_MICRO 4 +#define VERSION_MICRO 5 /* Version number of Logray and associated utilities */ #define LOG_VERSION "0.8.3" @@ -23,7 +23,7 @@ #define VERSION_FLAVOR "" /* Build wsutil with SIMD optimization */ -/* #undef HAVE_SSE4_2 */ +#define HAVE_SSE4_2 1 /* Define to 1 if we want to enable plugins */ #define HAVE_PLUGINS 1 @@ -263,7 +263,7 @@ /* #undef HAVE_OPUS */ /* Define to 1 if you have the lixbml2 library. */ -#define HAVE_LIBXML2 1 +/* #undef HAVE_LIBXML2 */ /* Define to 1 if you have the `setresgid' function. */ #define HAVE_SETRESGID 1 @@ -281,7 +281,7 @@ #define HAVE_MEMMEM 1 /* Define if you have the 'strerrorname_np' function. */ -#define HAVE_STRERRORNAME_NP 1 +/* #undef HAVE_STRERRORNAME_NP */ /* Define if you have the 'vasprintf' function. */ #define HAVE_VASPRINTF 1 diff --git a/include/wireshark/dftest.c b/include/wireshark/dftest.c deleted file mode 100644 index 9448f7f4..00000000 --- a/include/wireshark/dftest.c +++ /dev/null @@ -1,457 +0,0 @@ -/* dftest.c - * Shows display filter byte-code, for debugging dfilter routines. - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#define WS_LOG_DOMAIN LOG_DOMAIN_MAIN - -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#ifdef HAVE_PLUGINS -#include -#endif -#include -#include -#include -#include -#include - -#include - -#include "ui/util.h" -#include "wsutil/cmdarg_err.h" -#include "ui/failure_message.h" -#include "wsutil/version_info.h" - -static int opt_verbose = 0; -#define DFTEST_LOG_NONE 0 -#define DFTEST_LOG_DEBUG 1 -#define DFTEST_LOG_NOISY 2 -static int opt_log_level = DFTEST_LOG_NONE; -static int opt_flex = 0; -static int opt_lemon = 0; -static int opt_syntax_tree = 0; -static int opt_timer = 0; -static long opt_optimize = 1; -static int opt_show_types = 0; -static int opt_dump_refs = 0; - -static gint64 elapsed_expand = 0; -static gint64 elapsed_compile = 0; - -/* - * Report an error in command-line arguments. - */ -static void -dftest_cmdarg_err(const char *fmt, va_list ap) -{ - fprintf(stderr, "dftest: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); -} - -/* - * Report additional information for an error in command-line arguments. - */ -static void -dftest_cmdarg_err_cont(const char *fmt, va_list ap) -{ - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); -} - -static void -putloc(FILE *fp, df_loc_t loc) -{ - for (long i = 0; i < loc.col_start; i++) { - fputc(' ', fp); - } - fputc('^', fp); - - for (size_t l = loc.col_len; l > 1; l--) { - fputc('~', fp); - } - fputc('\n', fp); -} - -WS_NORETURN static void -print_usage(int status) -{ - FILE *fp = stdout; - fprintf(fp, "\n"); - fprintf(fp, "Usage: dftest [OPTIONS] -- EXPRESSION\n"); - fprintf(fp, "Options:\n"); - fprintf(fp, " -V, --verbose enable verbose mode\n"); - fprintf(fp, " -d, --debug enable compiler debug logs\n"); - fprintf(fp, " -f, --flex enable Flex debug trace\n"); - fprintf(fp, " -l, --lemon enable Lemon debug trace\n"); - fprintf(fp, " -s, --syntax print syntax tree\n"); - fprintf(fp, " -t, --timer print elapsed compilation time\n"); - fprintf(fp, " -0, --optimize=0 do not optimize (check syntax)\n"); - fprintf(fp, " --types show field value types\n"); - /* NOTE: References are loaded during runtime and dftest only does compilation. - * Unless some static reference data is hard-coded at compile time during - * development the --refs option to dftest is useless because it will just - * print empty reference vectors. */ - fprintf(fp, " --refs dump some runtime data structures\n"); - fprintf(fp, " -h, --help display this help and exit\n"); - fprintf(fp, " -v, --version print version\n"); - fprintf(fp, "\n"); - ws_log_print_usage(fp); - exit(status); -} - -static void -print_syntax_tree(dfilter_t *df) -{ - printf("Syntax tree:\n%s\n\n", dfilter_syntax_tree(df)); -} - -static void -print_warnings(dfilter_t *df) -{ - guint i; - GPtrArray *deprecated; - int count = 0; - - for (GSList *l = dfilter_get_warnings(df); l != NULL; l = l->next) { - printf("\nWarning: %s.", (char *)l->data); - count++; - } - - deprecated = dfilter_deprecated_tokens(df); - if (deprecated && deprecated->len) { - for (i = 0; i < deprecated->len; i++) { - const char *token = g_ptr_array_index(deprecated, i); - printf("\nWarning: Deprecated token \"%s\".", token); - count++; - } - } - - if (count) { - printf("\n"); - } -} - -static void -print_elapsed(void) -{ - printf("\nElapsed: %"PRId64" µs (%"PRId64" µs + %"PRId64" µs)\n", - elapsed_expand + elapsed_compile, - elapsed_expand, - elapsed_compile); -} - -static char * -expand_filter(const char *text) -{ - char *expanded = NULL; - df_error_t *err = NULL; - gint64 start; - - start = g_get_monotonic_time(); - expanded = dfilter_expand(text, &err); - if (expanded == NULL) { - fprintf(stderr, "Error: %s\n", err->msg); - df_error_free(&err); - } - elapsed_expand = g_get_monotonic_time() - start; - return expanded; -} - -static gboolean -compile_filter(const char *text, dfilter_t **dfp) -{ - unsigned df_flags = 0; - gboolean ok; - df_error_t *df_err = NULL; - gint64 start; - - if (opt_optimize > 0) - df_flags |= DF_OPTIMIZE; - if (opt_syntax_tree) - df_flags |= DF_SAVE_TREE; - if (opt_flex) - df_flags |= DF_DEBUG_FLEX; - if (opt_lemon) - df_flags |= DF_DEBUG_LEMON; - - start = g_get_monotonic_time(); - ok = dfilter_compile_full(text, dfp, &df_err, df_flags, "dftest"); - if (!ok) { - fprintf(stderr, "Error: %s\n", df_err->msg); - if (df_err->loc.col_start >= 0) { - fprintf(stderr, " %s\n ", text); - putloc(stderr, df_err->loc); - } - df_error_free(&df_err); - } - elapsed_compile = g_get_monotonic_time() - start; - return ok; -} - -int -main(int argc, char **argv) -{ - char *configuration_init_error; - char *text = NULL; - char *expanded_text = NULL; - dfilter_t *df = NULL; - int exit_status = EXIT_FAILURE; - - /* - * Set the C-language locale to the native environment and set the - * code page to UTF-8 on Windows. - */ -#ifdef _WIN32 - setlocale(LC_ALL, ".UTF-8"); -#else - setlocale(LC_ALL, ""); -#endif - - cmdarg_err_init(dftest_cmdarg_err, dftest_cmdarg_err_cont); - - /* Initialize log handler early for startup. */ - ws_log_init("dftest", vcmdarg_err); - - /* Early logging command-line initialization. */ - ws_log_parse_args(&argc, argv, vcmdarg_err, 1); - - ws_noisy("Finished log init and parsing command line log arguments"); - - ws_init_version_info("DFTest", NULL, NULL); - - const char *optstring = "hvdflstV0"; - static struct ws_option long_options[] = { - { "help", ws_no_argument, 0, 'h' }, - { "version", ws_no_argument, 0, 'v' }, - { "debug", ws_no_argument, 0, 'd' }, - { "flex", ws_no_argument, 0, 'f' }, - { "lemon", ws_no_argument, 0, 'l' }, - { "syntax", ws_no_argument, 0, 's' }, - { "timer", ws_no_argument, 0, 't' }, - { "verbose", ws_no_argument, 0, 'V' }, - { "optimize", ws_required_argument, 0, 1000 }, - { "types", ws_no_argument, 0, 2000 }, - { "refs", ws_no_argument, 0, 3000 }, - { NULL, 0, 0, 0 } - }; - int opt; - - for (;;) { - opt = ws_getopt_long(argc, argv, optstring, long_options, NULL); - if (opt == -1) - break; - - switch (opt) { - case 'V': - opt_verbose = 1; - break; - case 'd': - opt_log_level = DFTEST_LOG_NOISY; - break; - case 'f': - opt_flex = 1; - break; - case 'l': - opt_lemon = 1; - break; - case 's': - opt_syntax_tree = 1; - break; - case 't': - opt_timer = 1; - break; - case '0': - opt_optimize = 0; - break; - case 1000: - if (strlen(ws_optarg) > 1 || !g_ascii_isdigit(*ws_optarg)) { - printf("Error: \"%s\" is not a valid number 0-9\n", ws_optarg); - print_usage(WS_EXIT_INVALID_OPTION); - } - errno = 0; - opt_optimize = strtol(ws_optarg, NULL, 10); - if (errno) { - printf("Error: %s\n", g_strerror(errno)); - print_usage(WS_EXIT_INVALID_OPTION); - } - break; - case 2000: - opt_show_types = 1; - break; - case 3000: - opt_dump_refs = 1; - break; - case 'v': - show_version(); - exit(EXIT_SUCCESS); - break; - case 'h': - show_help_header(NULL); - print_usage(EXIT_SUCCESS); - break; - case '?': - print_usage(EXIT_FAILURE); - default: - ws_assert_not_reached(); - } - } - - /* Check for filter on command line */ - if (argv[ws_optind] == NULL) { - printf("Error: Missing argument.\n"); - print_usage(EXIT_FAILURE); - } - - if (opt_log_level == DFTEST_LOG_NOISY) { - ws_log_set_noisy_filter(LOG_DOMAIN_DFILTER); - } - else if (opt_flex || opt_lemon) { - /* Enable some dfilter logs with flex/lemon traces for context. */ - ws_log_set_debug_filter(LOG_DOMAIN_DFILTER); - opt_log_level = DFTEST_LOG_DEBUG; - } - - /* - * Get credential information for later use. - */ - init_process_policies(); - - /* - * Attempt to get the pathname of the directory containing the - * executable file. - */ - configuration_init_error = configuration_init(argv[0], NULL); - if (configuration_init_error != NULL) { - fprintf(stderr, "Error: Can't get pathname of directory containing " - "the dftest program: %s.\n", - configuration_init_error); - g_free(configuration_init_error); - } - - static const struct report_message_routines dftest_report_routines = { - failure_message, - failure_message, - open_failure_message, - read_failure_message, - write_failure_message, - cfile_open_failure_message, - cfile_dump_open_failure_message, - cfile_read_failure_message, - cfile_write_failure_message, - cfile_close_failure_message - }; - - init_report_message("dftest", &dftest_report_routines); - - timestamp_set_type(TS_RELATIVE); - timestamp_set_seconds_type(TS_SECONDS_DEFAULT); - - /* - * Libwiretap must be initialized before libwireshark is, so that - * dissection-time handlers for file-type-dependent blocks can - * register using the file type/subtype value for the file type. - */ - wtap_init(TRUE); - - /* Register all dissectors; we must do this before checking for the - "-g" flag, as the "-g" flag dumps a list of fields registered - by the dissectors, and we must do it before we read the preferences, - in case any dissectors register preferences. */ - if (!epan_init(NULL, NULL, FALSE)) - goto out; - - /* Load libwireshark settings from the current profile. */ - epan_load_settings(); - - /* notify all registered modules that have had any of their preferences - changed either from one of the preferences file or from the command - line that its preferences have changed. */ - prefs_apply_all(); - - /* This is useful to prevent confusion with option parsing. - * Skips printing options and argv[0]. */ - if (opt_verbose) { - for (int i = ws_optind; i < argc; i++) { - fprintf(stderr, "argv[%d]: %s\n", i, argv[i]); - } - fprintf(stderr, "\n"); - } - - /* Get filter text */ - text = get_args_as_string(argc, argv, ws_optind); - - printf("Filter:\n %s\n\n", text); - - /* Expand macros. */ - expanded_text = expand_filter(text); - if (expanded_text == NULL) { - exit_status = WS_EXIT_INVALID_FILTER; - goto out; - } - - if (strcmp(text, expanded_text) != 0) - printf("Filter (after expansion):\n %s\n\n", expanded_text); - - /* Compile it */ - if (!compile_filter(expanded_text, &df)) { - exit_status = WS_EXIT_INVALID_FILTER; - goto out; - } - - /* If logging is enabled add an empty line. */ - if (opt_log_level > DFTEST_LOG_NONE) { - printf("\n"); - } - - if (df == NULL) { - printf("Filter is empty.\n"); - exit_status = WS_EXIT_INVALID_FILTER; - goto out; - } - - if (opt_syntax_tree) - print_syntax_tree(df); - - uint16_t dump_flags = 0; - if (opt_show_types) - dump_flags |= DF_DUMP_SHOW_FTYPE; - if (opt_dump_refs) - dump_flags |= DF_DUMP_REFERENCES; - - dfilter_dump(stdout, df, dump_flags); - - print_warnings(df); - - if (opt_timer) - print_elapsed(); - - exit_status = 0; - -out: - epan_cleanup(); - dfilter_free(df); - g_free(text); - g_free(expanded_text); - exit(exit_status); -} diff --git a/include/wireshark/dumpcap.c b/include/wireshark/dumpcap.c deleted file mode 100644 index b5a5423a..00000000 --- a/include/wireshark/dumpcap.c +++ /dev/null @@ -1,6245 +0,0 @@ -/* dumpcap.c - * - * Wireshark - Network traffic analyzer - * By Gerald Combs - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#include -#define WS_LOG_DOMAIN LOG_DOMAIN_CAPCHILD - -#include -#include /* for exit() */ -#include - -#include - -#include - -#ifdef HAVE_NETINET_IN_H -#include -#endif - -#include - -#if defined(__APPLE__) && defined(__LP64__) -#include -#endif - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef HAVE_LIBCAP -# include -# include -#endif - -#include "ringbuffer.h" - -#include "capture/capture_ifinfo.h" -#include "capture/capture-pcap-util.h" -#include "capture/capture-pcap-util-int.h" -#ifdef _WIN32 -#include "capture/capture-wpcap.h" -#endif /* _WIN32 */ - -#include "writecap/pcapio.h" - -#ifndef _WIN32 -#include -#endif - -#include -#include - -#include "sync_pipe.h" - -#include "capture_opts.h" -#include -#include - -#include "wsutil/tempfile.h" -#include "wsutil/file_util.h" -#include "wsutil/cpu_info.h" -#include "wsutil/os_version_info.h" -#include "wsutil/str_util.h" -#include "wsutil/inet_addr.h" -#include "wsutil/time_util.h" -#include "wsutil/please_report_bug.h" -#include "wsutil/glib-compat.h" -#include - -#include "capture/ws80211_utils.h" - -#include "extcap.h" - -/* - * Get information about libpcap format from "wiretap/libpcap.h". - * Get information about pcapng format from "wiretap/pcapng_module.h". - * XXX - can we just use pcap_open_offline() to read the pipe? - */ -#include "wiretap/libpcap.h" -#include "wiretap/pcapng_module.h" -#include "wiretap/pcapng.h" - -/* - * Define these for extra logging messages at INFO and below. Note - * that when dumpcap is spawned as a child process, logs are sent - * to the parent via the sync pipe. - */ -/**#define DEBUG_DUMPCAP**/ /* Logs INFO and below messages normally */ -/**#define DEBUG_CHILD_DUMPCAP**/ /* Writes INFO and below logs to file */ - -#ifdef _WIN32 -#include "wsutil/win32-utils.h" -#ifdef DEBUG_DUMPCAP -#include /* _getch() */ -#endif -#endif - -#ifdef DEBUG_CHILD_DUMPCAP -FILE *debug_log; /* for logging debug messages to */ - /* a file if DEBUG_CHILD_DUMPCAP */ - /* is defined */ -#ifdef DEBUG_DUMPCAP -#include /* va_copy */ -#endif -#endif - -static GAsyncQueue *pcap_queue; -static gint64 pcap_queue_bytes; -static gint64 pcap_queue_packets; -static gint64 pcap_queue_byte_limit = 0; -static gint64 pcap_queue_packet_limit = 0; - -static gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */ -static const char *report_capture_filename = NULL; /* capture child file name */ -#ifdef _WIN32 -static gchar *sig_pipe_name = NULL; -static HANDLE sig_pipe_handle = NULL; -static gboolean signal_pipe_check_running(void); -#endif - -#ifdef ENABLE_ASAN -/* This has public visibility so that if compiled with shared libasan (the - * gcc default) function interposition occurs. - */ -WS_DLL_PUBLIC int -__lsan_is_turned_off(void) -{ - /* If we're in capture child mode, don't run a LSan report and - * send it to stderr, because it isn't properly formatted for - * the sync pipe. - * We could, if debugging variables are set, send the reports - * elsewhere instead, by calling __sanitizer_set_report_path() - * or __sanitizer_set_report_fd() - */ - if (capture_child) { - return 1; - } -#ifdef HAVE_LIBCAP - /* LSan dies with a fatal error without explanation if it can't ptrace. - * Normally, the "dumpable" attribute (which also controls ptracing) - * is set to 1 (SUID_DUMP_USER, process is dumpable.) However, it is - * reset to the current value in /proc/sys/fs/suid_dumpable in the - * following circumstances: euid/egid changes, fsuid/fsgid changes, - * execve of a setuid or setgid program that changes the euid or egid, - * execve of a program with capabilities exceeding those already - * permitted for the process. - * - * Unless we're running as root, one of those applies to dumpcap. - * - * The default value of /proc/sys/fs/suid_dumpable is 0, SUID_DUMP_DISABLE. - * In such a case, LeakSanitizer temporarily sets the value to 1 to - * allow ptracing, and then sets it back to 0. - * - * Another possible value, used by Ubuntu, Fedora, etc., is 2, - * which creates dumps readable by root only. For security reasons, - * unprivileged programs are not allowed to change the value to 2. - * (See https://nvd.nist.gov/vuln/detail/CVE-2006-2451 ) - * - * LSan does not check for the value 2 and change dumpable to 1 in that - * case, possibly because if it did it could not change it back to 2 - * and would have to either leave the process dumpable or change it to 0. - * - * The usual way to control the family of sanitizers is through environment - * variables. However, complicating things, changing the dumpable attribute - * to 0 or 2 changes the ownership of files in /proc/[pid] (including - * /proc/self ) to root:root, in particular /proc/[pid]/environ, and so - * ASAN_OPTIONS=detect_leaks=0 has no effect. (Unless the process has - * CAP_SYS_PTRACE, which allows tracing of any process, but that's also - * a security risk and we'll have dropped that with other privileges.) - * - * So if prctl(PR_GET_DUMPABLE) returns 2, we know that the process will - * die with a fatal error if it attempts to run LSan, so don't. - * - * See proc(5), prctl(2), ptrace(2), and - * https://github.com/google/sanitizers/issues/1306 - * https://github.com/llvm/llvm-project/issues/55944 - */ - if (prctl(PR_GET_DUMPABLE) == 2) { - ws_debug("Not running LeakSanitizer because /proc/sys/fs/suid_dumpable is 2"); - return 1; - } -#endif - return 0; -} - -WS_DLL_PUBLIC const char* -__asan_default_options(void) -{ - /* By default don't override our exit code if there's a leak or error. - * We particularly don't want to do this if running as a capture child, - * because capture/capture_sync doesn't expect the ASan exit codes. - */ - return "exitcode=0"; -} -#endif - -#ifdef SIGINFO -static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */ -static gboolean infoprint; /* if TRUE, print capture info after clearing infodelay */ -#endif /* SIGINFO */ - -/** 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); - -#if defined (__linux__) -/* whatever the deal with pcap_breakloop, linux doesn't support timeouts - * in pcap_dispatch(); on the other hand, select() works just fine there. - * Hence we use a select for that come what may. - * - * XXX - with TPACKET_V1 and TPACKET_V2, it currently uses select() - * internally, and, with TPACKET_V3, once that's supported, it'll - * support timeouts, at least as I understand the way the code works. - */ -#define MUST_DO_SELECT -#endif - -/** init the capture filter */ -typedef enum { - INITFILTER_NO_ERROR, - INITFILTER_BAD_FILTER, - INITFILTER_OTHER_ERROR -} initfilter_status_t; - -typedef enum { - STATE_EXPECT_REC_HDR, - STATE_READ_REC_HDR, - STATE_EXPECT_DATA, - STATE_READ_DATA -} cap_pipe_state_t; - -typedef enum { - PIPOK, - PIPEOF, - PIPERR, - PIPNEXIST -} cap_pipe_err_t; - -typedef struct _pcap_pipe_info { - gboolean byte_swapped; /**< TRUE if data in the pipe is byte swapped. */ - struct pcap_hdr hdr; /**< Pcap header when capturing from a pipe */ - struct pcaprec_modified_hdr rechdr; /**< Pcap record header when capturing from a pipe */ -} pcap_pipe_info_t; - -typedef struct _pcapng_pipe_info { - pcapng_block_header_t bh; /**< Pcapng general block header when capturing from a pipe */ - GArray *src_iface_to_global; /**< Int array mapping local IDB numbers to global_ld.interface_data */ -} pcapng_pipe_info_t; - -struct _loop_data; /* forward declaration so we can use it in the cap_pipe_dispatch function pointer */ - -/* - * A source of packets from which we're capturing. - */ -typedef struct _capture_src { - guint32 received; - guint32 dropped; - guint32 flushed; - pcap_t *pcap_h; -#ifdef MUST_DO_SELECT - int pcap_fd; /**< pcap file descriptor */ -#endif - gboolean pcap_err; - guint interface_id; - guint idb_id; /**< If from_pcapng is false, the output IDB interface ID. Otherwise the mapping in src_iface_to_global is used. */ - GThread *tid; - int snaplen; - int linktype; - 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 */ - gboolean from_pcapng; /**< TRUE if we're capturing from pcapng format */ - union { - pcap_pipe_info_t pcap; /**< Pcap info when capturing from a pipe */ - pcapng_pipe_info_t pcapng; /**< Pcapng info when capturing from a pipe */ - } cap_pipe_info; -#ifdef _WIN32 - HANDLE cap_pipe_h; /**< The handle 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 */ - char * cap_pipe_databuf; /**< Pointer to the data buffer we've allocated */ - size_t cap_pipe_databuf_size; /**< Current size of the data buffer */ - guint cap_pipe_max_pkt_size; /**< Maximum packet size allowed */ -#if defined(_WIN32) - char * cap_pipe_buf; /**< Pointer to the buffer we read into */ - DWORD cap_pipe_bytes_to_read; /**< Used by cap_pipe_dispatch */ - DWORD cap_pipe_bytes_read; /**< Used by cap_pipe_dispatch */ -#else - size_t cap_pipe_bytes_to_read; /**< Used by cap_pipe_dispatch */ - size_t cap_pipe_bytes_read; /**< Used by cap_pipe_dispatch */ -#endif - int (*cap_pipe_dispatch)(struct _loop_data *, struct _capture_src *, char *, size_t); - cap_pipe_state_t cap_pipe_state; - cap_pipe_err_t cap_pipe_err; - -#if defined(_WIN32) - GMutex *cap_pipe_read_mtx; - GAsyncQueue *cap_pipe_pending_q, *cap_pipe_done_q; -#endif -} capture_src; - -typedef struct _saved_idb { - gboolean deleted; - guint interface_id; /* capture_src->interface_id for the associated SHB */ - guint8 *idb; /* If non-NULL, IDB read from capture_src. This is an interface specified on the command line otherwise. */ - guint idb_len; -} saved_idb_t; - -/* - * Global capture loop state. - */ -typedef struct _loop_data { - /* common */ - gboolean go; /**< TRUE as long as we're supposed to keep capturing */ - int err; /**< if non-zero, error seen while capturing */ - gint packets_captured; /**< Number of packets we have already captured */ - 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 - GArray *pcaps; /**< Array of capture_src's on which we're capturing */ - gboolean pcapng_passthrough; /**< We have one source and it's pcapng. Pass its SHB and IDBs through. */ - guint8 *saved_shb; /**< SHB to write when we have one pcapng input */ - GArray *saved_idbs; /**< Array of saved_idb_t, written when we have a new section or output file. */ - GRWLock saved_shb_idb_lock; /**< Saved IDB RW mutex */ - /* output file(s) */ - FILE *pdh; - int save_file_fd; - char *io_buffer; /**< Our IO buffer if we increase the size from the standard size */ - guint64 bytes_written; /**< Bytes written for the current file. */ - /* autostop conditions */ - int packets_written; /**< Packets written for the current file. */ - int file_count; - /* ring buffer conditions */ - GTimer *file_duration_timer; - time_t next_interval_time; - int interval_s; -} loop_data; - -typedef struct _pcap_queue_element { - capture_src *pcap_src; - union { - struct pcap_pkthdr phdr; - pcapng_block_header_t bh; - } u; - u_char *pd; -} pcap_queue_element; - -/* - * This needs to be static, so that the SIGINT handler can clear the "go" - * flag and for saved_shb_idb_lock. - */ -static loop_data global_ld; - -/* - * Timeout, in milliseconds, for reads from the stream of captured packets - * from a capture device. - * - * A bug in Mac OS X 10.6 and 10.6.1 causes calls to pcap_open_live(), in - * 64-bit applications, with sub-second timeouts not to work. The bug is - * fixed in 10.6.2, re-broken in 10.6.3, and again fixed in 10.6.5. - */ -#if defined(__APPLE__) && defined(__LP64__) -static gboolean need_timeout_workaround; - -#define CAP_READ_TIMEOUT (need_timeout_workaround ? 1000 : 250) -#else -#define CAP_READ_TIMEOUT 250 -#endif - -/* - * Timeout, in microseconds, for reads from the stream of captured packets - * from a pipe. Pipes don't have the same problem that BPF devices do - * in Mac OS X 10.6, 10.6.1, 10.6.3, and 10.6.4, so we always use a timeout - * of 250ms, i.e. the same value as CAP_READ_TIMEOUT when not on one - * of the offending versions of Snow Leopard. - * - * On Windows this value is converted to milliseconds and passed to - * WaitForSingleObject. If it's less than 1000 WaitForSingleObject - * will return immediately. - */ -#if defined(_WIN32) -#define PIPE_READ_TIMEOUT 100000 -#else -#define PIPE_READ_TIMEOUT 250000 -#endif - -#define WRITER_THREAD_TIMEOUT 100000 /* usecs */ - -static void -dumpcap_log_writer(const char *domain, enum ws_log_level level, - const char *file, long line, const char *func, - const char *fatal_msg, ws_log_manifest_t *mft, - const char *user_format, va_list user_ap, - void *user_data); - -/* capture related options */ -static capture_options global_capture_opts; -static GPtrArray *capture_comments = NULL; -static gboolean quiet = FALSE; -static gboolean use_threads = FALSE; -static guint64 start_time; - -static void capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr, - const u_char *pd); -static void capture_loop_queue_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr, - const u_char *pd); -static void capture_loop_write_pcapng_cb(capture_src *pcap_src, const pcapng_block_header_t *bh, u_char *pd); -static void capture_loop_queue_pcapng_cb(capture_src *pcap_src, const pcapng_block_header_t *bh, u_char *pd); -static void capture_loop_get_errmsg(char *errmsg, size_t errmsglen, - char *secondary_errmsg, - size_t secondary_errmsglen, - const char *fname, int err, - gboolean is_close); - -WS_NORETURN static void exit_main(int err); - -static void report_new_capture_file(const char *filename); -static void report_packet_count(unsigned int packet_count); -static void report_packet_drops(guint32 received, guint32 pcap_drops, guint32 drops, guint32 flushed, guint32 ps_ifdrop, 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); - -#define MSG_MAX_LENGTH 4096 - -static void -print_usage(FILE *output) -{ - fprintf(output, "\nUsage: dumpcap [options] ...\n"); - fprintf(output, "\n"); - fprintf(output, "Capture interface:\n"); - fprintf(output, " -i , --interface \n"); - fprintf(output, " 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, " --ifname name to use in the capture file for a pipe from which\n"); - fprintf(output, " we're capturing\n"); - fprintf(output, " --ifdescr \n"); - fprintf(output, " description to use in the capture file for a pipe\n"); - fprintf(output, " from which we're capturing\n"); - fprintf(output, " -f packet filter in libpcap filter syntax\n"); - fprintf(output, " -s , --snapshot-length \n"); -#ifdef HAVE_PCAP_CREATE - fprintf(output, " packet snapshot length (def: appropriate maximum)\n"); -#else - fprintf(output, " packet snapshot length (def: %u)\n", WTAP_MAX_PACKET_SIZE_STANDARD); -#endif - fprintf(output, " -p, --no-promiscuous-mode\n"); - fprintf(output, " don't capture in promiscuous mode\n"); -#ifdef HAVE_PCAP_CREATE - fprintf(output, " -I, --monitor-mode capture in monitor mode, if available\n"); -#endif -#ifdef CAN_SET_CAPTURE_BUFFER_SIZE - fprintf(output, " -B , --buffer-size \n"); - fprintf(output, " size of kernel buffer in MiB (def: %dMiB)\n", DEFAULT_CAPTURE_BUFFER_SIZE); -#endif - fprintf(output, " -y , --linktype \n"); - fprintf(output, " link layer type (def: first appropriate)\n"); - fprintf(output, " --time-stamp-type timestamp method for interface\n"); - fprintf(output, " -D, --list-interfaces print list of interfaces and exit\n"); - fprintf(output, " -L, --list-data-link-types\n"); - fprintf(output, " print list of link-layer types of iface and exit\n"); - fprintf(output, " --list-time-stamp-types print list of timestamp types for iface and exit\n"); - fprintf(output, " --update-interval interval between updates with new packets (def: %dms)\n", DEFAULT_UPDATE_INTERVAL); - fprintf(output, " -d print generated BPF code for capture filter\n"); - fprintf(output, " -k ,[],[],[]\n"); - fprintf(output, " 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"); -#ifdef HAVE_PCAP_REMOTE - fprintf(output, "RPCAP options:\n"); - fprintf(output, " -r don't ignore own RPCAP traffic in capture\n"); - fprintf(output, " -u use UDP for RPCAP data transfer\n"); - fprintf(output, " -A : use RPCAP password authentication\n"); -#ifdef HAVE_PCAP_SETSAMPLING - fprintf(output, " -m use packet sampling\n"); - fprintf(output, " count:NUM - capture one packet of every NUM\n"); - fprintf(output, " timer:NUM - capture no more than 1 packet in NUM ms\n"); -#endif -#endif - fprintf(output, "Stop conditions:\n"); - fprintf(output, " -c stop after n packets (def: infinite)\n"); - fprintf(output, " -a ..., --autostop ...\n"); - fprintf(output, " duration:NUM - stop after NUM seconds\n"); - fprintf(output, " filesize:NUM - stop this file after NUM kB\n"); - fprintf(output, " files:NUM - stop after NUM files\n"); - fprintf(output, " packets:NUM - stop after NUM packets\n"); - /*fprintf(output, "\n");*/ - fprintf(output, "Output (files):\n"); - fprintf(output, " -w name of file to save (def: tempfile)\n"); - fprintf(output, " -g enable group read access on the output file(s)\n"); - fprintf(output, " -b ..., --ring-buffer \n"); - fprintf(output, " duration:NUM - switch to next file after NUM secs\n"); - fprintf(output, " filesize:NUM - switch to next file after NUM kB\n"); - fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n"); - fprintf(output, " packets:NUM - ringbuffer: replace after NUM packets\n"); - fprintf(output, " interval:NUM - switch to next file when the time is\n"); - fprintf(output, " an exact multiple of NUM secs\n"); - fprintf(output, " printname:FILE - print filename to FILE when written\n"); - fprintf(output, " (can use 'stdout' or 'stderr')\n"); - fprintf(output, " -n use pcapng format instead of pcap (default)\n"); - fprintf(output, " -P use libpcap format instead of pcapng\n"); - fprintf(output, " --capture-comment \n"); - fprintf(output, " add a capture comment to the output file\n"); - fprintf(output, " (only for pcapng)\n"); - fprintf(output, " --temp-dir write temporary files to this directory\n"); - fprintf(output, " (default: %s)\n", g_get_tmp_dir()); - fprintf(output, "\n"); - - ws_log_print_usage(output); - fprintf(output, "\n"); - - fprintf(output, "Miscellaneous:\n"); - fprintf(output, " -N maximum number of packets buffered within dumpcap\n"); - fprintf(output, " -C maximum number of bytes used for buffering packets\n"); - fprintf(output, " within dumpcap\n"); - fprintf(output, " -t use a separate thread per interface\n"); - fprintf(output, " -q don't report packet capture counts\n"); - fprintf(output, " -v, --version print version information and exit\n"); - fprintf(output, " -h, --help display this help and exit\n"); - fprintf(output, "\n"); -#ifdef __linux__ - fprintf(output, "Dumpcap can benefit from an enabled BPF JIT compiler if available.\n"); - fprintf(output, "You might want to enable it by executing:\n"); - fprintf(output, " \"echo 1 > /proc/sys/net/core/bpf_jit_enable\"\n"); - fprintf(output, "Note that this can make your system less secure!\n"); - fprintf(output, "\n"); -#endif - fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w 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"); -} - -/* - * Report an error in command-line arguments. - * If we're a capture child, send a message back to the parent, otherwise - * just print it. - */ -static void -dumpcap_cmdarg_err(const char *fmt, va_list ap) -{ - if (capture_child) { - gchar *msg; - /* Generate a 'special format' message back to parent */ - msg = ws_strdup_vprintf(fmt, ap); - sync_pipe_write_errmsgs_to_parent(2, msg, ""); - g_free(msg); - } else { - fprintf(stderr, "dumpcap: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - } -} - -/* - * Report additional information for an error in command-line arguments. - * If we're a capture child, send a message back to the parent, otherwise - * just print it. - */ -static void -dumpcap_cmdarg_err_cont(const char *fmt, va_list ap) -{ - if (capture_child) { - gchar *msg; - msg = ws_strdup_vprintf(fmt, ap); - sync_pipe_write_errmsgs_to_parent(2, msg, ""); - g_free(msg); - } else { - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - } -} - -#ifdef HAVE_LIBCAP -static void -#if 0 /* Set to enable capability debugging */ -/* see 'man cap_to_text()' for explanation of output */ -/* '=' means 'all= ' ie: no capabilities */ -/* '=ip' means 'all=ip' ie: all capabilities are permissible and inheritable */ -/* .... */ -print_caps(const char *pfx) { - cap_t caps = cap_get_proc(); - ws_debug("%s: EUID: %d Capabilities: %s", pfx, geteuid(), cap_to_text(caps, NULL)); - cap_free(caps); -} -#else -print_caps(const char *pfx _U_) { -} -#endif - -static void -relinquish_all_capabilities(void) -{ - /* Drop any and all capabilities this process may have. */ - /* Allowed whether or not process has any privileges. */ - 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", g_strerror(errno)); - } - print_caps("Post-clear"); - cap_free(caps); -} -#endif - -/* - * Platform-dependent suggestions for fixing permissions. - */ - -#ifdef HAVE_LIBCAP - #define LIBCAP_PERMISSIONS_SUGGESTION \ - "\n\n" \ - "If you did not install Wireshark from a package, ensure that Dumpcap " \ - "has the needed CAP_NET_RAW and CAP_NET_ADMIN capabilities by running " \ - "\n\n" \ - " sudo setcap cap_net_raw,cap_net_admin=ep {path/to/}dumpcap" \ - "\n\n" \ - "and then restarting Wireshark." -#else - #define LIBCAP_PERMISSIONS_SUGGESTION -#endif - -#if defined(__linux__) - #define PLATFORM_PERMISSIONS_SUGGESTION \ - "\n\n" \ - "On Debian and Debian derivatives such as Ubuntu, if you have " \ - "installed Wireshark from a package, try running" \ - "\n\n" \ - " sudo dpkg-reconfigure wireshark-common" \ - "\n\n" \ - "selecting \"\" in response to the question" \ - "\n\n" \ - " Should non-superusers be able to capture packets?" \ - "\n\n" \ - "adding yourself to the \"wireshark\" group by running" \ - "\n\n" \ - " sudo usermod -a -G wireshark {your username}" \ - "\n\n" \ - "and then logging out and logging back in again." \ - LIBCAP_PERMISSIONS_SUGGESTION -#elif defined(__APPLE__) - #define PLATFORM_PERMISSIONS_SUGGESTION \ - "\n\n" \ - "If you installed Wireshark using the package from wireshark.org, " \ - "close this dialog and click on the \"installing ChmodBPF\" link in " \ - "\"You can fix this by installing ChmodBPF.\" on the main screen, " \ - "and then complete the installation procedure." -#else - #define PLATFORM_PERMISSIONS_SUGGESTION -#endif - -#if defined(_WIN32) -static const char * -get_platform_pcap_failure_secondary_error_message(const char *open_status_str) -{ - /* - * The error string begins with the error produced by WinPcap - * and Npcap if attempting to set promiscuous mode fails. - * (Note that this string could have a specific error message - * from an NDIS error after the initial part, so we do a prefix - * check rather than an exact match check.) - * - * If this is with Npcap 1.71 through 1.73, which have bugs that - * cause this error on Windows 11 with some drivers, suggest that - * the user upgrade to the current version of Npcap; - * otherwise, suggest that they turn off promiscuous mode - * on that device. - */ - static const char promisc_failed[] = - "failed to set hardware filter to promiscuous mode"; - - if (strncmp(open_status_str, promisc_failed, sizeof promisc_failed - 1) == 0) { - unsigned int npcap_major, npcap_minor; - - if (caplibs_get_npcap_version(&npcap_major, &npcap_minor)) { - if (npcap_major == 1 && - (npcap_minor >= 71 && npcap_minor <= 73)) { - return -"This is a bug in your version of Npcap.\n" -"\n" -"If you need to use promiscuous mode, you must upgrade to the current " -"version of Npcap, which is available from https://npcap.com/\n" -"\n" -"Otherwise, turn off promiscuous mode for this device."; - } - } - return - "Please turn off promiscuous mode for this device."; - } - return NULL; -} -#elif defined(__linux__) -static const char * -get_platform_pcap_failure_secondary_error_message(const char *open_status_str) -{ - /* - * The error string is the message provided by libpcap on - * Linux if an attempt to open a PF_PACKET socket failed - * with EAFNOSUPPORT. This probably means that either 1) - * the kernel doesn't have PF_PACKET support configured in - * or 2) this is a Flatpak version of Wireshark that's been - * sandboxed in a way that disallows opening PF_PACKET - * sockets. - * - * Suggest that the user find some other package of - * Wireshark if they want to capture traffic and are - * running a Flatpak of Wireshark or that they configure - * PF_PACKET support back in if it's configured out. - */ - static const char af_notsup[] = - "socket: Address family not supported by protocol"; - - if (strcmp(open_status_str, af_notsup) == 0) { - return - "If you are running Wireshark from a Flatpak package, " - "it does not support packet capture; you will need " - "to run a different version of Wireshark in order " - "to capture traffic.\n" - "\n" - "Otherwise, if your machine is running a kernel that " - "was not configured with CONFIG_PACKET, that kernel " - "does not support packet capture; you will need to " - "use a kernel configured with CONFIG_PACKET."; - } - return NULL; -} -#else -static const char * -get_platform_pcap_failure_secondary_error_message(const char *open_status_str _U_) -{ - /* No such message for platforms not handled above. */ - return NULL; -} -#endif - -static const char * -get_pcap_failure_secondary_error_message(cap_device_open_status open_status, - const char *open_status_str) -{ - const char *platform_secondary_error_message; - -#ifdef _WIN32 - /* - * On Windows, first make sure they *have* Npcap installed. - */ - if (!has_wpcap) { - return - "In order to capture packets, Npcap or WinPcap must be installed. See\n" - "\n" - " https://npcap.com/\n" - "\n" - "for a downloadable version of Npcap and for instructions on how to\n" - "install it."; - } -#endif - - /* - * OK, now just return a largely platform-independent error that might - * have platform-specific suggestions at the end (for example, suggestions - * for how to get permission to capture). - */ - switch (open_status) { - - case CAP_DEVICE_OPEN_NO_ERR: - case CAP_DEVICE_OPEN_WARNING_PROMISC_NOTSUP: - case CAP_DEVICE_OPEN_WARNING_TSTAMP_TYPE_NOTSUP: - case CAP_DEVICE_OPEN_WARNING_OTHER: - /* This should not happen, as those aren't errors. */ - return ""; - - case CAP_DEVICE_OPEN_ERROR_NO_SUCH_DEVICE: - case CAP_DEVICE_OPEN_ERROR_RFMON_NOTSUP: - case CAP_DEVICE_OPEN_ERROR_IFACE_NOT_UP: - /* - * Not clear what suggestions to make for these cases. - */ - return ""; - - case CAP_DEVICE_OPEN_ERROR_PERM_DENIED: - case CAP_DEVICE_OPEN_ERROR_PROMISC_PERM_DENIED: - /* - * This is a permissions error, so no need to specify any other - * warnings. - */ - return - "Please check to make sure you have sufficient permissions." - PLATFORM_PERMISSIONS_SUGGESTION; - break; - - case CAP_DEVICE_OPEN_ERROR_OTHER: - case CAP_DEVICE_OPEN_ERROR_GENERIC: - /* - * We don't know what kind of error it is. See if there's a hint - * in the error string; if not, throw all generic suggestions at - * the user. - * - * First, check for some text that pops up in some errors. - * Do platform-specific checks first. - */ - platform_secondary_error_message = - get_platform_pcap_failure_secondary_error_message(open_status_str); - if (platform_secondary_error_message != NULL) { - /* We got one, so return it. */ - return platform_secondary_error_message; - } - - /* - * Not one of those particular problems. Was this a "generic" - * error from pcap_open_live() or pcap_open(), in which case - * it might be a permissions error? - */ - if (open_status == CAP_DEVICE_OPEN_ERROR_GENERIC) { - /* Yes. */ - return - "Please check to make sure you have sufficient permissions, and that you have " - "the proper interface or pipe specified." - PLATFORM_PERMISSIONS_SUGGESTION; - } else { - /* - * This is not a permissions error, so no need to suggest - * checking permissions. - */ - return - "Please check that you have the proper interface or pipe specified."; - } - break; - - default: - /* - * This is not a permissions error, so no need to suggest - * checking permissions. - */ - return - "Please check that you have the proper interface or pipe specified."; - break; - } -} - -static void -get_capture_device_open_failure_messages(cap_device_open_status open_status, - const char *open_status_str, - const char *iface, - char *errmsg, size_t errmsg_len, - char *secondary_errmsg, - size_t secondary_errmsg_len) -{ - switch (open_status) { - - case CAP_DEVICE_OPEN_ERROR_NO_SUCH_DEVICE: - snprintf(errmsg, errmsg_len, - "There is no device named \"%s\".\n(%s)", - iface, open_status_str); - break; - - case CAP_DEVICE_OPEN_ERROR_RFMON_NOTSUP: - snprintf(errmsg, errmsg_len, - "Capturing in monitor mode is not supported on device \"%s\".\n(%s)", - iface, open_status_str); - break; - - case CAP_DEVICE_OPEN_ERROR_PERM_DENIED: - snprintf(errmsg, errmsg_len, - "You do not have permission to capture on device \"%s\".\n(%s)", - iface, open_status_str); - break; - - case CAP_DEVICE_OPEN_ERROR_IFACE_NOT_UP: - snprintf(errmsg, errmsg_len, - "Device \"%s\" is not up.\n(%s)", - iface, open_status_str); - break; - - case CAP_DEVICE_OPEN_ERROR_PROMISC_PERM_DENIED: - snprintf(errmsg, errmsg_len, - "You do not have permission to capture in promiscuous mode on device \"%s\".\n(%s)", - iface, open_status_str); - break; - - case CAP_DEVICE_OPEN_ERROR_OTHER: - default: - snprintf(errmsg, errmsg_len, - "The capture session could not be initiated on capture device \"%s\".\n(%s)", - iface, open_status_str); - break; - } - snprintf(secondary_errmsg, secondary_errmsg_len, "%s", - get_pcap_failure_secondary_error_message(open_status, open_status_str)); -} - -static gboolean -compile_capture_filter(const char *iface, pcap_t *pcap_h, - struct bpf_program *fcode, const char *cfilter) -{ - bpf_u_int32 netnum, netmask; - gchar lookup_net_err_str[PCAP_ERRBUF_SIZE]; - - if (pcap_lookupnet(iface, &netnum, &netmask, lookup_net_err_str) < 0) { - /* - * Well, we can't get the netmask for this interface; it's used - * only for filters that check for broadcast IP addresses, so - * we just punt and use 0. It might be nice to warn the user, - * but that's a pain in a GUI application, as it'd involve popping - * up a message box, and it's not clear how often this would make - * a difference (only filters that check for IP broadcast addresses - * use the netmask). - */ - /*cmdarg_err( - "Warning: Couldn't obtain netmask info (%s).", lookup_net_err_str);*/ - 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. - */ -DIAG_OFF(cast-qual) - if (pcap_compile(pcap_h, fcode, (char *)cfilter, 1, netmask) < 0) - return FALSE; -DIAG_ON(cast-qual) - return TRUE; -} - -static gboolean -show_filter_code(capture_options *capture_opts) -{ - interface_options *interface_opts; - pcap_t *pcap_h; - cap_device_open_status open_status; - gchar open_status_str[PCAP_ERRBUF_SIZE]; - char errmsg[MSG_MAX_LENGTH+1]; - char secondary_errmsg[MSG_MAX_LENGTH+1]; - struct bpf_program fcode; - struct bpf_insn *insn; - u_int i; - guint j; - - for (j = 0; j < capture_opts->ifaces->len; j++) { - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, j); - pcap_h = open_capture_device(capture_opts, interface_opts, - CAP_READ_TIMEOUT, &open_status, &open_status_str); - if (pcap_h == NULL) { - /* Open failed; get messages */ - get_capture_device_open_failure_messages(open_status, open_status_str, - interface_opts->name, - errmsg, sizeof errmsg, - secondary_errmsg, - sizeof secondary_errmsg); - /* And report them */ - report_capture_error(errmsg, secondary_errmsg); - return FALSE; - } - - /* Set the link-layer type. */ - if (!set_pcap_datalink(pcap_h, interface_opts->linktype, interface_opts->name, - errmsg, sizeof errmsg, - secondary_errmsg, sizeof secondary_errmsg)) { - pcap_close(pcap_h); - report_capture_error(errmsg, secondary_errmsg); - return FALSE; - } - - /* OK, try to compile the capture filter. */ - if (!compile_capture_filter(interface_opts->name, pcap_h, &fcode, - interface_opts->cfilter)) { - snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(pcap_h)); - pcap_close(pcap_h); - report_cfilter_error(capture_opts, j, errmsg); - return FALSE; - } - pcap_close(pcap_h); - - /* Now print the filter code. */ - insn = fcode.bf_insns; - - 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. */ - sync_pipe_write_string_msg(2, SP_SUCCESS, NULL); - } - return TRUE; -} - -/* - * Output a machine readable list of the interfaces - * This list is retrieved by the sync_interface_list_open() function - * The actual output of this function can be viewed with the command "dumpcap -D -Z none" - */ -static void -print_machine_readable_interfaces(GList *if_list) -{ - int i; - GList *if_entry; - if_info_t *if_info; - GSList *addr; - if_addr_t *if_addr; - char addr_str[WS_INET6_ADDRSTRLEN]; - - if (capture_child) { - /* Let our parent know we succeeded. */ - sync_pipe_write_string_msg(2, SP_SUCCESS, NULL); - } - - i = 1; /* Interface id number */ - for (if_entry = g_list_first(if_list); if_entry != NULL; - if_entry = g_list_next(if_entry)) { - if_info = (if_info_t *)if_entry->data; - printf("%d. %s\t", i++, if_info->name); - - /* - * Print the contents of the if_entry struct in a parseable format. - * Each if_entry element is tab-separated. Addresses are comma- - * separated. - */ - /* XXX - Make sure our description doesn't contain a tab */ - if (if_info->vendor_description != NULL) - printf("%s\t", if_info->vendor_description); - else - printf("\t"); - - /* XXX - Make sure our friendly name doesn't contain a tab */ - if (if_info->friendly_name != NULL) - printf("%s\t", if_info->friendly_name); - else - printf("\t"); - - printf("%i\t", if_info->type); - - for (addr = g_slist_nth(if_info->addrs, 0); addr != NULL; - addr = g_slist_next(addr)) { - if (addr != g_slist_nth(if_info->addrs, 0)) - printf(","); - - if_addr = (if_addr_t *)addr->data; - switch(if_addr->ifat_type) { - case IF_AT_IPv4: - printf("%s", ws_inet_ntop4(&if_addr->addr.ip4_addr, addr_str, sizeof(addr_str))); - break; - case IF_AT_IPv6: - printf("%s", ws_inet_ntop6(&if_addr->addr.ip6_addr, addr_str, sizeof(addr_str))); - break; - default: - printf("", if_addr->ifat_type); - } - } - - if (if_info->loopback) - printf("\tloopback"); - else - printf("\tnetwork"); - printf("\t%s", if_info->extcap); - printf("\n"); - } -} - -/* - * If you change the machine-readable output format of this function, - * you MUST update capture_ifinfo.c:capture_get_if_capabilities() accordingly! - */ -static void -print_machine_readable_if_capabilities(if_capabilities_t *caps, int queries) -{ - GList *lt_entry, *ts_entry; - const gchar *desc_str; - - if (capture_child) { - /* Let our parent know we succeeded. */ - sync_pipe_write_string_msg(2, SP_SUCCESS, NULL); - } - - if (queries & CAPS_QUERY_LINK_TYPES) { - if (caps->can_set_rfmon) - printf("1\n"); - else - printf("0\n"); - for (lt_entry = caps->data_link_types; lt_entry != NULL; - lt_entry = g_list_next(lt_entry)) { - data_link_info_t *data_link_info = (data_link_info_t *)lt_entry->data; - if (data_link_info->description != NULL) - desc_str = data_link_info->description; - else - desc_str = "(not supported)"; - printf("%d\t%s\t%s\n", data_link_info->dlt, data_link_info->name, - desc_str); - } - } - printf("\n"); - if (queries & CAPS_QUERY_TIMESTAMP_TYPES) { - for (ts_entry = caps->timestamp_types; ts_entry != NULL; - ts_entry = g_list_next(ts_entry)) { - timestamp_info_t *timestamp = (timestamp_info_t *)ts_entry->data; - if (timestamp->description != NULL) - desc_str = timestamp->description; - else - desc_str = "(none)"; - printf("%s\t%s\n", timestamp->name, desc_str); - } - } -} - -typedef struct { - char *name; - pcap_t *pch; -} if_stat_t; - -/* Print the number of packets captured for each interface until we're killed. */ -static int -print_statistics_loop(gboolean machine_readable) -{ - GList *if_list, *if_entry, *stat_list = NULL, *stat_entry; - if_info_t *if_info; - if_stat_t *if_stat; - int err; - gchar *err_str; - pcap_t *pch; - char errbuf[PCAP_ERRBUF_SIZE]; - struct pcap_stat ps; - - if_list = get_interface_list(&err, &err_str); - if (if_list == NULL) { - if (err == 0) - cmdarg_err("There are no interfaces on which a capture can be done"); - else { - cmdarg_err("%s", err_str); - g_free(err_str); - } - return err; - } - - for (if_entry = g_list_first(if_list); if_entry != NULL; if_entry = g_list_next(if_entry)) { - if_info = (if_info_t *)if_entry->data; - -#ifdef __linux__ - /* On Linux nf* interfaces don't collect stats properly and don't allows multiple - * connections. We avoid collecting stats on them. - */ - if (!strncmp(if_info->name, "nf", 2)) { - ws_debug("Skipping interface %s for stats", if_info->name); - continue; - } -#endif - -#ifdef HAVE_PCAP_OPEN - /* - * If we're opening a remote device, use pcap_open(); that's currently - * the only open routine that supports remote devices. - */ - if (strncmp(if_info->name, "rpcap://", 8) == 0) - pch = pcap_open(if_info->name, MIN_PACKET_SIZE, 0, 0, NULL, errbuf); - else -#endif - pch = pcap_open_live(if_info->name, MIN_PACKET_SIZE, 0, 0, errbuf); - - if (pch) { - if_stat = g_new(if_stat_t, 1); - if_stat->name = g_strdup(if_info->name); - if_stat->pch = pch; - stat_list = g_list_append(stat_list, if_stat); - } - } - - if (!stat_list) { - cmdarg_err("There are no interfaces on which a capture can be done"); - return 2; - } - - if (capture_child) { - /* Let our parent know we succeeded. */ - sync_pipe_write_string_msg(2, SP_SUCCESS, NULL); - } - - if (!machine_readable) { - printf("%-15s %10s %10s\n", "Interface", "Received", - "Dropped"); - } - - global_ld.go = TRUE; - while (global_ld.go) { - for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) { - if_stat = (if_stat_t *)stat_entry->data; - pcap_stats(if_stat->pch, &ps); - - if (!machine_readable) { - printf("%-15s %10u %10u\n", if_stat->name, - ps.ps_recv, ps.ps_drop); - } else { - printf("%s\t%u\t%u\n", if_stat->name, - ps.ps_recv, ps.ps_drop); - fflush(stdout); - } - } -#ifdef _WIN32 - /* If we have a dummy signal pipe check it */ - if (!signal_pipe_check_running()) { - global_ld.go = FALSE; - } - Sleep(1 * 1000); -#else - sleep(1); -#endif - } - - /* XXX - Not reached. Should we look for 'q' in stdin? */ - for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) { - if_stat = (if_stat_t *)stat_entry->data; - pcap_close(if_stat->pch); - g_free(if_stat->name); - g_free(if_stat); - } - g_list_free(stat_list); - free_interface_list(if_list); - - return 0; -} - - -#ifdef _WIN32 -static BOOL WINAPI -capture_cleanup_handler(DWORD dwCtrlType) -{ - /* CTRL_C_EVENT is sort of like SIGINT, CTRL_BREAK_EVENT is unique to - Windows, CTRL_CLOSE_EVENT is sort of like SIGHUP, CTRL_LOGOFF_EVENT - is also sort of like SIGHUP, and CTRL_SHUTDOWN_EVENT is sort of - like SIGTERM at least when the machine's shutting down. - - For now, if we're running as a command rather than a capture child, - we handle all but CTRL_LOGOFF_EVENT as indications that we should - clean up and quit, just as we handle SIGINT, SIGHUP, and SIGTERM - in that way on UN*X. - - If we're not running as a capture child, we might be running as - a service; ignore CTRL_LOGOFF_EVENT, so we keep running after the - user logs out. (XXX - can we explicitly check whether we're - running as a service?) */ - - ws_info("Console: Control signal"); - ws_debug("Console: Control signal, CtrlType: %lu", dwCtrlType); - - /* Keep capture running if we're a service and a user logs off */ - if (capture_child || (dwCtrlType != CTRL_LOGOFF_EVENT)) { - capture_loop_stop(); - return TRUE; - } else { - return FALSE; - } -} -#else -static void -capture_cleanup_handler(int signum _U_) -{ - /* On UN*X, we cleanly shut down the capture on SIGINT, SIGHUP, and - SIGTERM. We assume that if the user wanted it to keep running - after they logged out, they'd have nohupped it. */ - - capture_loop_stop(); -} -#endif - - -static void -report_capture_count(gboolean reportit) -{ - /* Don't print this if we're a capture child. */ - if (!capture_child && reportit) { - fprintf(stderr, "\rPackets captured: %d\n", global_ld.packets_captured); - /* stderr could be line buffered */ - fflush(stderr); - } -} - - -#ifdef SIGINFO -static void -report_counts_for_siginfo(void) -{ - report_capture_count(quiet); - infoprint = FALSE; /* we just reported it */ -} - -static void -report_counts_siginfo(int signum _U_) -{ - int sav_errno = errno; - - /* If we've been told to delay printing, just set a flag asking - that we print counts (if we're supposed to), otherwise print - the count of packets captured (if we're supposed to). */ - if (infodelay) - infoprint = TRUE; - else - report_counts_for_siginfo(); - errno = sav_errno; -} -#endif /* SIGINFO */ - -static void -exit_main(int status) -{ - ws_cleanup_sockets(); - -#ifdef _WIN32 - /* can be helpful for debugging */ -#ifdef DEBUG_DUMPCAP - printf("Press any key\n"); - _getch(); -#endif - -#endif /* _WIN32 */ - - if (ringbuf_is_initialized()) { - /* save_file is managed by ringbuffer, be sure to release the memory and - * avoid capture_opts_cleanup from double-freeing 'save_file'. */ - ringbuf_free(); - global_capture_opts.save_file = NULL; - } - - capture_opts_cleanup(&global_capture_opts); - exit(status); -} - -#ifdef HAVE_LIBCAP -/* - * If we were linked with libcap (not related to libpcap), make sure we have - * CAP_NET_ADMIN and CAP_NET_RAW, then relinquish our permissions. - * (See comment in main() for details) - */ -static void -relinquish_privs_except_capture(void) -{ - /* If 'started_with_special_privs' (ie: suid) then enable for - * ourself the NET_ADMIN and NET_RAW capabilities and then - * drop our suid privileges. - * - * CAP_NET_ADMIN: Promiscuous mode and a truckload of other - * stuff we don't need (and shouldn't have). - * CAP_NET_RAW: Packet capture (raw sockets). - */ - - if (started_with_special_privs()) { - cap_value_t cap_list[2] = { CAP_NET_ADMIN, CAP_NET_RAW }; - int cl_len = sizeof(cap_list) / sizeof(cap_value_t); - - cap_t caps = cap_init(); /* all capabilities initialized to off */ - - print_caps("Pre drop, pre set"); - - if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { - 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", g_strerror(errno)); - } - print_caps("Pre drop, post set"); - - relinquish_special_privs_perm(); - - 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", g_strerror(errno)); - } - print_caps("Post drop, post set"); - - cap_free(caps); - } -} - -#endif /* HAVE_LIBCAP */ - -/* Map DLT_ values, as returned by pcap_datalink(), to LINKTYPE_ values, - as are written to capture files. - - Most of the time, a DLT_ value and the corresponding LINKYPE_ value - are the same, but there are some cases, where a numeric value as - a DLT_ doesn't uniquely identify a particular link-layer header type, - where they differ, so that the values in files *do* identify - particular link-layer header types. */ - -/* LINKTYPE_ values that don't match corresponding DLT_ values on - all platforms. */ -#define LINKTYPE_ATM_RFC1483 100 -#define LINKTYPE_RAW 101 -#define LINKTYPE_SLIP_BSDOS 102 -#define LINKTYPE_PPP_BSDOS 103 -#define LINKTYPE_C_HDLC 104 -#define LINKTYPE_IEEE802_11 105 -#define LINKTYPE_ATM_CLIP 106 -#define LINKTYPE_FRELAY 107 -#define LINKTYPE_LOOP 108 -#define LINKTYPE_ENC 109 -#define LINKTYPE_NETBSD_HDLC 112 -#define LINKTYPE_PFSYNC 246 -#define LINKTYPE_PKTAP 258 - -static int -dlt_to_linktype(int dlt) -{ - /* DLT_NULL through DLT_FDDI have the same numeric value on - all platforms, so the corresponding LINKTYPE_s have the - same numeric values. */ - if (dlt >= DLT_NULL && dlt <= DLT_FDDI) - return (dlt); - -#if defined(DLT_PFSYNC) && DLT_PFSYNC != LINKTYPE_PFSYNC - /* DLT_PFSYNC has a value on several platforms that's in the - non-matching range, a value on FreeBSD that's in the high - matching range and that's *not* equal to LINKTYPE_PFSYNC, - and has a value on the rmaining platforms that's equal - to LINKTYPE_PFSYNC, which is in the high matching range. - - Map it to LINKTYPE_PFSYNC if it's not equal to LINKTYPE_PFSYNC. */ - if (dlt == DLT_PFSYNC) - return (LINKTYPE_PFSYNC); -#endif - - /* DLT_PKTAP is defined as DLT_USER2 - which is in the high - matching range - on Darwin because Apple used DLT_USER2 - on systems that users ran, not just as an internal thing. - - We map it to LINKTYPE_PKTAP if it's not equal to LINKTYPE_PKTAP - so that DLT_PKTAP captures from Apple machines can be read by - software that either doesn't handle DLT_USER2 or that handles it - as something other than Apple PKTAP. */ -#if defined(DLT_PKTAP) && DLT_PKTAP != LINKTYPE_PKTAP - if (dlt == DLT_PKTAP) - return (LINKTYPE_PKTAP); -#endif - - /* For all other DLT_s with values beyond 104, the value - of the corresponding LINKTYPE_ is the same. */ - if (dlt >= 104) - return (dlt); - - /* These DLT_ values have different values on different - platforms, so we assigned them LINKTYPE_ values just - below the lower bound of the high matchig range; - those values should never be equal to any DLT_ - values, so that should avoid collisions. - - That way, for example, "raw IP" packets will have - LINKTYPE_RAW as the code in all savefiles for - which the code that writes them maps to that - value, regardless of the platform on which they - were written, so they should be readable on all - platforms without having to determine on which - platform they were written. - - We map the DLT_ values on this platform, whatever - it might be, to the corresponding LINKTYPE_ values. */ -#ifdef DLT_ATM_RFC1483 - if (dlt == DLT_ATM_RFC1483) - return (LINKTYPE_ATM_RFC1483); -#endif -#ifdef DLT_RAW - if (dlt == DLT_RAW) - return (LINKTYPE_RAW); -#endif -#ifdef DLT_SLIP_BSDOS - if (dlt == DLT_SLIP_BSDOS) - return (LINKTYPE_SLIP_BSDOS); -#endif -#ifdef DLT_PPP_BSDOS - if (dlt == DLT_PPP_BSDOS) - return (LINKTYPE_PPP_BSDOS); -#endif - - /* These DLT_ values were originally defined on some platform, - and weren't defined on other platforms. - - At least some of those values, on at least one platform, - collide with the values of other DLT_s on other platforms, - e.g. DLT_LOOP, so we don't just define them, on all - platforms, as having the same value as on the original - platform. - - Therefore, we assigned new LINKTYPE_ values to them, and, - on the platforms where they weren't originally defined, - define the DLT_s to have the same value as the corresponding - LINKTYPE_. - - This means that, for capture files with the original - platform's DLT_ value rather than the LINKTYPE_ value - as a link-layer type, we will recognize those types - on that platform, but not on other platforms. */ -#ifdef DLT_FR - /* BSD/OS Frame Relay */ - if (dlt == DLT_FR) - return (LINKTYPE_FRELAY); -#endif -#if defined(DLT_HDLC) && DLT_HDLC != LINKTYPE_NETBSD_HDLC - /* NetBSD HDLC */ - if (dlt == DLT_HDLC) - return (LINKTYPE_NETBSD_HDLC); -#endif -#if defined(DLT_C_HDLC) && DLT_C_HDLC != LINKTYPE_C_HDLC - /* BSD/OS Cisco HDLC */ - if (dlt == DLT_C_HDLC) - return (LINKTYPE_C_HDLC); -#endif -#if defined(DLT_LOOP) && DLT_LOOP != LINKTYPE_LOOP - /* OpenBSD DLT_LOOP */ - if (dlt == DLT_LOOP) - return (LINKTYPE_LOOP); -#endif -#if defined(DLT_ENC) && DLT_ENC != LINKTYPE_ENC - /* OpenBSD DLT_ENC */ - if (dlt == DLT_ENC) - return (LINKTYPE_ENC); -#endif - - /* These DLT_ values are not on all platforms, but, so far, - there don't appear to be any platforms that define - other DLT_s with those values; we map them to - different LINKTYPE_ values anyway, just in case. */ -#ifdef DLT_ATM_CLIP - /* Linux ATM Classical IP */ - if (dlt == DLT_ATM_CLIP) - return (LINKTYPE_ATM_CLIP); -#endif - - /* Treat all other DLT_s as having the same value as the - corresponding LINKTYPE_. */ - return (dlt); -} - -/* Take care of byte order in the libpcap headers read from pipes. - * (function taken from wiretap/libpcap.c) */ -static void -cap_pipe_adjust_pcap_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr) -{ - if (byte_swapped) { - /* Byte-swap the record header fields. */ - rechdr->ts_sec = GUINT32_SWAP_LE_BE(rechdr->ts_sec); - rechdr->ts_usec = GUINT32_SWAP_LE_BE(rechdr->ts_usec); - rechdr->incl_len = GUINT32_SWAP_LE_BE(rechdr->incl_len); - rechdr->orig_len = GUINT32_SWAP_LE_BE(rechdr->orig_len); - } - - /* In file format version 2.3, the "incl_len" and "orig_len" fields were - swapped, in order to match the BPF header layout. - - Unfortunately, some files were, according to a comment in the "libpcap" - source, written with version 2.3 in their headers but without the - interchanged fields, so if "incl_len" is greater than "orig_len" - which - would make no sense - we assume that we need to swap them. */ - if (hdr->version_major == 2 && - (hdr->version_minor < 3 || - (hdr->version_minor == 3 && rechdr->incl_len > rechdr->orig_len))) { - guint32 temp; - - temp = rechdr->orig_len; - rechdr->orig_len = rechdr->incl_len; - rechdr->incl_len = temp; - } -} - -/* Wrapper: distinguish between recv/read if we're reading on Windows, - * or just read(). - */ -static ssize_t -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 - * to the main application thread. - */ -/* - * XXX Right now we use async queues for basic signaling. The main thread - * sets cap_pipe_buf and cap_bytes_to_read, then pushes an item onto - * cap_pipe_pending_q which triggers a read in the cap_pipe_read thread. - * Iff the read is successful cap_pipe_read pushes an item onto - * cap_pipe_done_q, otherwise an error is signaled. No data is passed in - * the queues themselves (yet). - * - * We might want to move some of the cap_pipe_dispatch logic here so that - * 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_thread_read(void *arg) -{ - capture_src *pcap_src; -#ifdef _WIN32 - BOOL res; - DWORD last_err, bytes_read; -#else /* _WIN32 */ - size_t bytes_read; -#endif /* _WIN32 */ - - pcap_src = (capture_src *)arg; - while (pcap_src->cap_pipe_err == PIPOK) { - g_async_queue_pop(pcap_src->cap_pipe_pending_q); /* Wait for our cue (ahem) from the main thread */ - g_mutex_lock(pcap_src->cap_pipe_read_mtx); - bytes_read = 0; - while (bytes_read < pcap_src->cap_pipe_bytes_to_read) { - if ((pcap_src->from_cap_socket) -#ifndef _WIN32 - || 1 -#endif - ) - { - ssize_t b; - b = cap_pipe_read(pcap_src->cap_pipe_fd, pcap_src->cap_pipe_buf+bytes_read, - pcap_src->cap_pipe_bytes_to_read - bytes_read, pcap_src->from_cap_socket); - if (b <= 0) { - if (b == 0) { - pcap_src->cap_pipe_err = PIPEOF; - bytes_read = 0; - break; - } else { - pcap_src->cap_pipe_err = PIPERR; - bytes_read = -1; - break; - } - } else { - bytes_read += (DWORD)b; - } - } -#ifdef _WIN32 - else - { - /* If we try to use read() on a named pipe on Windows with partial - * data it appears to return EOF. - */ - DWORD b; - res = ReadFile(pcap_src->cap_pipe_h, pcap_src->cap_pipe_buf+bytes_read, - pcap_src->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_src->cap_pipe_err = PIPEOF; - bytes_read = 0; - break; - } - pcap_src->cap_pipe_err = PIPERR; - bytes_read = -1; - break; - } else if (b == 0 && pcap_src->cap_pipe_bytes_to_read > 0) { - pcap_src->cap_pipe_err = PIPEOF; - bytes_read = 0; - break; - } - } -#endif /*_WIN32 */ - } - pcap_src->cap_pipe_bytes_read = bytes_read; - if (pcap_src->cap_pipe_bytes_read >= pcap_src->cap_pipe_bytes_to_read) { - g_async_queue_push(pcap_src->cap_pipe_done_q, pcap_src->cap_pipe_buf); /* Any non-NULL value will do */ - } - g_mutex_unlock(pcap_src->cap_pipe_read_mtx); - } - /* Post to queue if we didn't read enough data as the main thread waits for the message */ - g_mutex_lock(pcap_src->cap_pipe_read_mtx); - if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read) { - /* There's still more of the record to read. */ - g_async_queue_push(pcap_src->cap_pipe_done_q, pcap_src->cap_pipe_buf); /* Any non-NULL value will do */ - } - g_mutex_unlock(pcap_src->cap_pipe_read_mtx); - return NULL; -} - -/* - * Do a blocking read from a pipe within the main thread, by pushing - * the read onto the pipe queue and then popping it off that queue; - * the pipe will block until the pushed read completes. - * - * We do it with another thread because we can't use select() on - * pipes on Windows, as we can on UN*Xes, we can only use it on - * sockets. - */ -void -pipe_read_sync(capture_src *pcap_src, void *buf, DWORD nbytes) -{ - pcap_src->cap_pipe_buf = (char *) buf; - pcap_src->cap_pipe_bytes_read = 0; - pcap_src->cap_pipe_bytes_to_read = nbytes; - /* We don't have to worry about cap_pipe_read_mtx here */ - g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf); - g_async_queue_pop(pcap_src->cap_pipe_done_q); -} -#endif - -/* 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. - */ -static int -cap_pipe_select(int pipe_fd) -{ - fd_set rfds; - struct timeval timeout; - - FD_ZERO(&rfds); - FD_SET(pipe_fd, &rfds); - - timeout.tv_sec = PIPE_READ_TIMEOUT / 1000000; - timeout.tv_usec = PIPE_READ_TIMEOUT % 1000000; - - return select(pipe_fd+1, &rfds, NULL, NULL, &timeout); -} - -#define DEF_TCP_PORT 19000 - -static int -cap_open_socket(char *pipename, capture_src *pcap_src, char *errmsg, size_t errmsgl) -{ - struct sockaddr_storage sa; - socklen_t sa_len; - int fd; - - /* Skip the initial "TCP@" in the pipename. */ - if (ws_socket_ptoa(&sa, pipename + 4, DEF_TCP_PORT) < 0) { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated because" - "\"%s\" is not a valid socket specification", pipename); - pcap_src->cap_pipe_err = PIPERR; - return -1; - } - - if ((fd = (int)socket(sa.ss_family, SOCK_STREAM, 0)) < 0) { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated because" - " the socket couldn't be created due to the socket error: \n" -#ifdef _WIN32 - " %s", win32strerror(WSAGetLastError())); -#else - " %d: %s", errno, g_strerror(errno)); -#endif - pcap_src->cap_pipe_err = PIPERR; - return -1; - } - - if (sa.ss_family == AF_INET6) - sa_len = sizeof(struct sockaddr_in6); - else - sa_len = sizeof(struct sockaddr_in); - if (connect(fd, (struct sockaddr *)&sa, sa_len) < 0) { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated because" - " the socket couldn't be connected due to the socket error: \n" -#ifdef _WIN32 - " %s", win32strerror(WSAGetLastError())); -#else - " %d: %s", errno, g_strerror(errno)); -#endif - pcap_src->cap_pipe_err = PIPERR; - - cap_pipe_close(fd, TRUE); - return -1; - } - - pcap_src->from_cap_socket = TRUE; - return fd; -} - -/* Wrapper: distinguish between closesocket on Windows; use ws_close - * otherwise. - */ -static void -cap_pipe_close(int pipe_fd, gboolean from_socket) -{ -#ifdef _WIN32 - if (from_socket) { - closesocket(pipe_fd); - } -#else - (void) from_socket; /* Mark unused, similar to Q_UNUSED */ - ws_close(pipe_fd); -#endif -} - -/** Read bytes from a capture source, which is assumed to be a pipe or - * socket. - * - * Returns -1, or the number of bytes read similar to read(2). - * Sets pcap_src->cap_pipe_err on error or EOF. - */ -static ssize_t -cap_pipe_read_data_bytes(capture_src *pcap_src, char *errmsg, size_t errmsgl) -{ - int sel_ret; - int fd = pcap_src->cap_pipe_fd; -#ifdef _WIN32 - DWORD sz, bytes_read = 0; -#else /* _WIN32 */ - ssize_t sz, bytes_read = 0; -#endif /* _WIN32 */ - ssize_t b; - -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("cap_pipe_read_data_bytes read %lu of %lu", - pcap_src->cap_pipe_bytes_read, pcap_src->cap_pipe_bytes_to_read); -#endif - sz = pcap_src->cap_pipe_bytes_to_read - pcap_src->cap_pipe_bytes_read; - while (bytes_read < sz) { - if (fd == -1) { - snprintf(errmsg, errmsgl, "Invalid file descriptor."); - pcap_src->cap_pipe_err = PIPNEXIST; - return -1; - } - - sel_ret = cap_pipe_select(fd); - if (sel_ret < 0) { - snprintf(errmsg, errmsgl, - "Unexpected error from select: %s.", g_strerror(errno)); - pcap_src->cap_pipe_err = PIPERR; - return -1; - } else if (sel_ret > 0) { - b = cap_pipe_read(fd, pcap_src->cap_pipe_databuf+pcap_src->cap_pipe_bytes_read+bytes_read, - sz-bytes_read, pcap_src->from_cap_socket); - if (b <= 0) { - if (b == 0) { - snprintf(errmsg, errmsgl, - "End of file reading from pipe or socket."); - pcap_src->cap_pipe_err = PIPEOF; - } else { -#ifdef _WIN32 - /* - * On Windows, we only do this for sockets. - */ - DWORD lastError = WSAGetLastError(); - errno = lastError; - snprintf(errmsg, errmsgl, - "Error reading from pipe or socket: %s.", - win32strerror(lastError)); -#else - snprintf(errmsg, errmsgl, - "Error reading from pipe or socket: %s.", - g_strerror(errno)); -#endif - pcap_src->cap_pipe_err = PIPERR; - } - return -1; - } -#ifdef _WIN32 - bytes_read += (DWORD)b; -#else - bytes_read += b; -#endif - } - } - pcap_src->cap_pipe_bytes_read += bytes_read; -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("cap_pipe_read_data_bytes read %lu of %lu", - pcap_src->cap_pipe_bytes_read, pcap_src->cap_pipe_bytes_to_read); -#endif - return bytes_read; -} - -/* Some forward declarations for breaking up cap_pipe_open_live for pcap and pcapng formats */ -static void pcap_pipe_open_live(int fd, capture_src *pcap_src, - struct pcap_hdr *hdr, - char *errmsg, size_t errmsgl, - char *secondary_errmsg, size_t secondary_errmsgl); -static void pcapng_pipe_open_live(int fd, capture_src *pcap_src, - char *errmsg, size_t errmsgl); -static int pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, - char *errmsg, size_t errmsgl); - -/* For problems that are probably Not Our Fault. */ -static char not_our_bug[] = - "Please report this to the developers of the program writing to the pipe."; - -/* Mimic pcap_open_live() for pipe captures - - * We check if "pipename" is "-" (stdin), a AF_UNIX socket, or a FIFO, - * open it, and read the header. - * - * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3 - * because we can't seek on pipes (see wiretap/libpcap.c for details) */ -static void -cap_pipe_open_live(char *pipename, - capture_src *pcap_src, - void *hdr, - char *errmsg, size_t errmsgl, - char *secondary_errmsg, size_t secondary_errmsgl) -{ -#ifndef _WIN32 - ws_statb64 pipe_stat; - struct sockaddr_un sa; -#else /* _WIN32 */ - char *pncopy, *pos; - guintptr extcap_pipe_handle; -#endif - gboolean extcap_pipe = FALSE; - ssize_t b; - int fd = -1, sel_ret; - size_t bytes_read; - guint32 magic = 0; - pcap_src->cap_pipe_fd = -1; -#ifdef _WIN32 - pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE; -#endif - - ws_debug("cap_pipe_open_live: %s", pipename); - - /* - * XXX - this blocks until a pcap per-file header has been written to - * the pipe, so it could block indefinitely. - */ - if (strcmp(pipename, "-") == 0) { -#ifndef _WIN32 - fd = 0; /* read from stdin */ -#else /* _WIN32 */ - pcap_src->cap_pipe_h = GetStdHandle(STD_INPUT_HANDLE); -#endif /* _WIN32 */ - } else if (!strncmp(pipename, "TCP@", 4)) { - if ((fd = cap_open_socket(pipename, pcap_src, errmsg, errmsgl)) < 0) { - return; - } - } else { -#ifndef _WIN32 - if ( g_strrstr(pipename, EXTCAP_PIPE_PREFIX) != NULL ) - extcap_pipe = TRUE; - - if (ws_stat64(pipename, &pipe_stat) < 0) { - if (errno == ENOENT || errno == ENOTDIR) - pcap_src->cap_pipe_err = PIPNEXIST; - else { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated " - "due to error getting information on pipe or socket: %s.", g_strerror(errno)); - pcap_src->cap_pipe_err = PIPERR; - } - return; - } - if (S_ISFIFO(pipe_stat.st_mode)) { - fd = ws_open(pipename, O_RDONLY | O_NONBLOCK, 0000 /* no creation so don't matter */); - if (fd == -1) { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated " - "due to error on pipe open: %s.", g_strerror(errno)); - pcap_src->cap_pipe_err = PIPERR; - return; - } - } else if (S_ISSOCK(pipe_stat.st_mode)) { - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated " - "due to error on socket create: %s.", g_strerror(errno)); - pcap_src->cap_pipe_err = PIPERR; - return; - } - sa.sun_family = AF_UNIX; - /* - * The Single UNIX Specification says: - * - * The size of sun_path has intentionally been left undefined. - * This is because different implementations use different sizes. - * For example, 4.3 BSD uses a size of 108, and 4.4 BSD uses a size - * of 104. Since most implementations originate from BSD versions, - * the size is typically in the range 92 to 108. - * - * Applications should not assume a particular length for sun_path - * or assume that it can hold {_POSIX_PATH_MAX} bytes (256). - * - * It also says - * - * The header shall define the sockaddr_un structure, - * which shall include at least the following members: - * - * sa_family_t sun_family Address family. - * char sun_path[] Socket pathname. - * - * so we assume that it's an array, with a specified size, - * and that the size reflects the maximum path length. - */ - if (g_strlcpy(sa.sun_path, pipename, sizeof sa.sun_path) > sizeof sa.sun_path) { - /* Path name too long */ - snprintf(errmsg, errmsgl, - "The capture session could not be initiated " - "due to error on socket connect: Path name too long."); - pcap_src->cap_pipe_err = PIPERR; - ws_close(fd); - return; - } - b = connect(fd, (struct sockaddr *)&sa, sizeof sa); - if (b == -1) { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated " - "due to error on socket connect: %s.", g_strerror(errno)); - pcap_src->cap_pipe_err = PIPERR; - ws_close(fd); - return; - } - } else { - if (S_ISCHR(pipe_stat.st_mode)) { - /* - * Assume the user specified an interface on a system where - * interfaces are in /dev. Pretend we haven't seen it. - */ - pcap_src->cap_pipe_err = PIPNEXIST; - } else { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated because\n" - "\"%s\" is neither an interface nor a socket nor a pipe.", pipename); - pcap_src->cap_pipe_err = PIPERR; - } - return; - } - -#else /* _WIN32 */ - if (sscanf(pipename, EXTCAP_PIPE_PREFIX "%" SCNuPTR, &extcap_pipe_handle) == 1) - { - /* The client is already connected to extcap pipe. - * We have inherited the handle from parent process. - */ - extcap_pipe = TRUE; - pcap_src->cap_pipe_h = (HANDLE)extcap_pipe_handle; - } - else - { -#define PIPE_STR "\\pipe\\" - /* Under Windows, named pipes _must_ have the form - * "\\\pipe\". may be "." for localhost. - */ - pncopy = g_strdup(pipename); - if ((pos = strstr(pncopy, "\\\\")) == pncopy) { - pos = strchr(pncopy + 3, '\\'); - if (pos && g_ascii_strncasecmp(pos, PIPE_STR, strlen(PIPE_STR)) != 0) - pos = NULL; - } - - g_free(pncopy); - - if (!pos) { - snprintf(errmsg, errmsgl, - "The capture session could not be initiated because\n" - "\"%s\" is neither an interface nor a pipe.", pipename); - pcap_src->cap_pipe_err = PIPNEXIST; - return; - } - - - /* Wait for the pipe to appear */ - while (1) { - pcap_src->cap_pipe_h = CreateFile(utf_8to16(pipename), GENERIC_READ, 0, NULL, - OPEN_EXISTING, 0, NULL); - - if (pcap_src->cap_pipe_h != INVALID_HANDLE_VALUE) - break; - - if (GetLastError() != ERROR_PIPE_BUSY) { - snprintf(errmsg, errmsgl, - "The capture session on \"%s\" could not be started " - "due to error on pipe open: %s.", - pipename, win32strerror(GetLastError())); - pcap_src->cap_pipe_err = PIPERR; - return; - } - - if (!WaitNamedPipe(utf_8to16(pipename), 30 * 1000)) { - snprintf(errmsg, errmsgl, - "The capture session on \"%s\" timed out during " - "pipe open: %s.", - pipename, win32strerror(GetLastError())); - pcap_src->cap_pipe_err = PIPERR; - return; - } - } - } -#endif /* _WIN32 */ - } - - pcap_src->from_cap_pipe = TRUE; - - /* - * We start with a 2KB buffer for packet data, which should be - * large enough for most regular network packets. We increase it, - * up to the maximum size we allow, as necessary. - */ - pcap_src->cap_pipe_databuf = (char*)g_malloc(2048); - pcap_src->cap_pipe_databuf_size = 2048; - - /* - * Read the first 4 bytes of data from the pipe. - * - * If a pcap file is being written to it, that will be - * the pcap magic number. - * - * If a pcapng file is being written to it, that will be - * the block type of the initial SHB. - */ -#ifdef _WIN32 - /* - * On UN*X, we can use select() on pipes or sockets. - * - * On Windows, we can only use it on sockets; to do non-blocking - * reads from pipes, we currently do reads in a separate thread - * and use GLib asynchronous queues from the main thread to start - * read operations and to wait for them to complete. - */ - if (pcap_src->from_cap_socket) -#endif - { - bytes_read = 0; - while (bytes_read < sizeof magic) { - sel_ret = cap_pipe_select(fd); - if (sel_ret < 0) { - 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_src->from_cap_socket); - /* jump messaging, if extcap had an error, stderr will provide the correct message */ - if (extcap_pipe && b <= 0) - goto error; - - if (b <= 0) { - if (b == 0) - snprintf(errmsg, errmsgl, - "End of file on pipe magic during open."); - else - snprintf(errmsg, errmsgl, - "Error on pipe magic during open: %s.", - g_strerror(errno)); - goto error; - } - bytes_read += b; - } - } - } -#ifdef _WIN32 - else { - /* Create a thread to read from this pipe */ - g_thread_new("cap_pipe_open_live", &cap_thread_read, pcap_src); - - pipe_read_sync(pcap_src, &magic, sizeof(magic)); - /* jump messaging, if extcap had an error, stderr will provide the correct message */ - if (pcap_src->cap_pipe_bytes_read <= 0 && extcap_pipe) - goto error; - - if (pcap_src->cap_pipe_bytes_read <= 0) { - if (pcap_src->cap_pipe_bytes_read == 0) - snprintf(errmsg, errmsgl, - "End of file on pipe magic during open."); - else - snprintf(errmsg, errmsgl, - "Error on pipe magic during open: %s.", - g_strerror(errno)); - goto error; - } - } -#endif - - switch (magic) { - case PCAP_MAGIC: - case PCAP_NSEC_MAGIC: - /* This is a pcap file. - The host that wrote it has our byte order, and was running - a program using either standard or ss990417 libpcap. */ - pcap_src->cap_pipe_info.pcap.byte_swapped = FALSE; - pcap_src->cap_pipe_modified = FALSE; - pcap_src->ts_nsec = magic == PCAP_NSEC_MAGIC; - break; - case PCAP_MODIFIED_MAGIC: - /* This is a pcap file. - The host that wrote it has our byte order, but was running - a program using either ss990915 or ss991029 libpcap. */ - pcap_src->cap_pipe_info.pcap.byte_swapped = FALSE; - pcap_src->cap_pipe_modified = TRUE; - break; - case PCAP_SWAPPED_MAGIC: - case PCAP_SWAPPED_NSEC_MAGIC: - /* This is a pcap file. - The host that wrote it has a byte order opposite to ours, - and was running a program using either standard or - ss990417 libpcap. */ - pcap_src->cap_pipe_info.pcap.byte_swapped = TRUE; - pcap_src->cap_pipe_modified = FALSE; - pcap_src->ts_nsec = magic == PCAP_SWAPPED_NSEC_MAGIC; - break; - case PCAP_SWAPPED_MODIFIED_MAGIC: - /* This is a pcap file. - The host that wrote it out has a byte order opposite to - ours, and was running a program using either ss990915 - or ss991029 libpcap. */ - pcap_src->cap_pipe_info.pcap.byte_swapped = TRUE; - pcap_src->cap_pipe_modified = TRUE; - break; - case BLOCK_TYPE_SHB: - /* This is a pcapng file. */ - pcap_src->from_pcapng = TRUE; - pcap_src->cap_pipe_dispatch = pcapng_pipe_dispatch; - pcap_src->cap_pipe_info.pcapng.src_iface_to_global = g_array_new(FALSE, FALSE, sizeof(guint32)); - global_capture_opts.use_pcapng = TRUE; /* we can only output in pcapng format */ - break; - default: - /* Not a pcapng file, and either not a pcap type we know about - or not a pcap file, either. */ - snprintf(errmsg, errmsgl, - "File type is neither a supported pcap nor pcapng format. (magic = 0x%08x)", magic); - snprintf(secondary_errmsg, secondary_errmsgl, "%s", - not_our_bug); - goto error; - } - - if (pcap_src->from_pcapng) - pcapng_pipe_open_live(fd, pcap_src, errmsg, errmsgl); - else - pcap_pipe_open_live(fd, pcap_src, (struct pcap_hdr *) hdr, errmsg, errmsgl, - secondary_errmsg, secondary_errmsgl); - - return; - -error: - ws_debug("cap_pipe_open_live: error %s", errmsg); - pcap_src->cap_pipe_err = PIPERR; - cap_pipe_close(fd, pcap_src->from_cap_socket); - pcap_src->cap_pipe_fd = -1; -#ifdef _WIN32 - pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE; -#endif -} - -/* - * Read the part of the pcap file header that follows the magic - * number (we've already read the magic number). - */ -static void -pcap_pipe_open_live(int fd, - capture_src *pcap_src, - struct pcap_hdr *hdr, - char *errmsg, size_t errmsgl, - char *secondary_errmsg, size_t secondary_errmsgl) -{ - size_t bytes_read; - ssize_t b; - int sel_ret; - - /* - * We're reading from a pcap file. We've already read the magic - * number; read the rest of the header. - * - * (Note that struct pcap_hdr is a structure for the part of a - * pcap file header *following the magic number*; it does not - * include the magic number itself.) - */ -#ifdef _WIN32 - if (pcap_src->from_cap_socket) -#endif - { - /* Keep reading until we get 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) { - 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_src->from_cap_socket); - if (b <= 0) { - if (b == 0) - snprintf(errmsg, errmsgl, - "End of file on pipe header during open."); - else - snprintf(errmsg, errmsgl, - "Error on pipe header during open: %s.", - g_strerror(errno)); - snprintf(secondary_errmsg, secondary_errmsgl, - "%s", not_our_bug); - goto error; - } - bytes_read += b; - } - } - } -#ifdef _WIN32 - else { - pipe_read_sync(pcap_src, hdr, sizeof(struct pcap_hdr)); - if (pcap_src->cap_pipe_bytes_read <= 0) { - if (pcap_src->cap_pipe_bytes_read == 0) - snprintf(errmsg, errmsgl, - "End of file on pipe header during open."); - else - snprintf(errmsg, errmsgl, - "Error on pipe header header during open: %s.", - g_strerror(errno)); - snprintf(secondary_errmsg, secondary_errmsgl, "%s", - not_our_bug); - goto error; - } - } -#endif - - if (pcap_src->cap_pipe_info.pcap.byte_swapped) { - /* Byte-swap the header fields about which we care. */ - hdr->version_major = GUINT16_SWAP_LE_BE(hdr->version_major); - hdr->version_minor = GUINT16_SWAP_LE_BE(hdr->version_minor); - hdr->snaplen = GUINT32_SWAP_LE_BE(hdr->snaplen); - hdr->network = GUINT32_SWAP_LE_BE(hdr->network); - } - /* - * The link-layer header type field of the pcap header is - * probably a LINKTYPE_ value, as the vast majority of - * LINKTYPE_ values and their corresponding DLT_ values - * are the same. - * - * However, in case the file was written by a program - * that used a DLT_ value, rather than a LINKTYPE_ value, - * in one of the cases where the two differ, use dlt_to_linktype() - * to map to a LINKTYPE_ value, just as we use it to map - * the result of pcap_datalink() to a LINKTYPE_ value. - */ - pcap_src->linktype = dlt_to_linktype(hdr->network); - /* Pick the appropriate maximum packet size for the link type */ - switch (pcap_src->linktype) { - - case 231: /* DLT_DBUS */ - pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_DBUS; - break; - - case 279: /* DLT_EBHSCR */ - pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_EBHSCR; - break; - - case 249: /* DLT_USBPCAP */ - pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_USBPCAP; - break; - - default: - pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_STANDARD; - break; - } - - if (hdr->version_major < 2) { - snprintf(errmsg, errmsgl, - "The old pcap format version %d.%d is not supported.", - hdr->version_major, hdr->version_minor); - snprintf(secondary_errmsg, secondary_errmsgl, "%s", - not_our_bug); - goto error; - } - - pcap_src->cap_pipe_fd = fd; - return; - -error: - ws_debug("pcap_pipe_open_live: error %s", errmsg); - pcap_src->cap_pipe_err = PIPERR; - cap_pipe_close(fd, pcap_src->from_cap_socket); - pcap_src->cap_pipe_fd = -1; -#ifdef _WIN32 - pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE; -#endif -} - -/* - * Synchronously read the fixed portion of the pcapng section header block - * (we've already read the pcapng block header). - */ -static int -pcapng_read_shb(capture_src *pcap_src, - char *errmsg, - size_t errmsgl) -{ - pcapng_section_header_block_t shb; - -#ifdef _WIN32 - if (pcap_src->from_cap_socket) -#endif - { - pcap_src->cap_pipe_bytes_to_read = sizeof(pcapng_block_header_t) + sizeof(pcapng_section_header_block_t); - if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) { - return -1; - } - } -#ifdef _WIN32 - else { - pipe_read_sync(pcap_src, pcap_src->cap_pipe_databuf + sizeof(pcapng_block_header_t), - sizeof(pcapng_section_header_block_t)); - if (pcap_src->cap_pipe_bytes_read <= 0) { - if (pcap_src->cap_pipe_bytes_read == 0) - snprintf(errmsg, errmsgl, - "End of file reading from pipe or socket."); - else - snprintf(errmsg, errmsgl, - "Error reading from pipe or socket: %s.", - g_strerror(errno)); - return -1; - } - /* Continuing with STATE_EXPECT_DATA requires reading into cap_pipe_databuf at offset cap_pipe_bytes_read */ - pcap_src->cap_pipe_bytes_read = sizeof(pcapng_block_header_t) + sizeof(pcapng_section_header_block_t); - } -#endif - memcpy(&shb, pcap_src->cap_pipe_databuf + sizeof(pcapng_block_header_t), sizeof(pcapng_section_header_block_t)); - switch (shb.magic) - { - case PCAPNG_MAGIC: - ws_debug("pcapng SHB MAGIC"); - break; - case PCAPNG_SWAPPED_MAGIC: - ws_debug("pcapng SHB SWAPPED MAGIC"); - /* - * pcapng sources can contain all sorts of block types. - * Rather than add a bunch of complexity to this code (which is - * often privileged), punt and tell the user to swap bytes - * elsewhere. - * - * XXX - punting means that the Wireshark test suite must be - * modified to: - * - * 1) have both little-endian and big-endian versions of - * all pcapng files piped to dumpcap; - * - * 2) pipe the appropriate file to dumpcap, depending on - * the byte order of the host on which the tests are - * being run; - * - * as per comments in bug 15772 and 15754. - * - * Are we *really* certain that the complexity added would be - * significant enough to make adding it a security risk? And - * why would this code even be running with any elevated - * privileges if you're capturing from a pipe? We should not - * only have given up all additional privileges if we're reading - * from a pipe, we should give them up in such a fashion that - * we can't reclaim them. - */ -#if G_BYTE_ORDER == G_BIG_ENDIAN -#define OUR_ENDIAN "big" -#define IFACE_ENDIAN "little" -#else -#define OUR_ENDIAN "little" -#define IFACE_ENDIAN "big" -#endif - snprintf(errmsg, errmsgl, - "Interface %u is " IFACE_ENDIAN " endian but we're " OUR_ENDIAN " endian.", - pcap_src->interface_id); - return -1; - default: - /* Not a pcapng type we know about, or not pcapng at all. */ - snprintf(errmsg, errmsgl, - "Unrecognized pcapng format or not pcapng data."); - return -1; - } - - pcap_src->cap_pipe_max_pkt_size = WTAP_MAX_PACKET_SIZE_STANDARD; - - /* Setup state to capture any options following the section header block */ - pcap_src->cap_pipe_state = STATE_EXPECT_DATA; - - return 0; -} - -/* - * Save IDB blocks for playback whenever we change output files, and - * fix LINKTYPE_ values that are really platform-dependent DLT_ values. - * Rewrite EPB and ISB interface IDs. - */ -static gboolean -pcapng_adjust_block(capture_src *pcap_src, const pcapng_block_header_t *bh, u_char *pd) -{ - switch(bh->block_type) { - case BLOCK_TYPE_SHB: - { - if (global_ld.pcapng_passthrough) { - /* - * We have a single pcapng input. We pass the SHB through when - * writing a single output file and for the first ring buffer - * file. We need to save it for the second and subsequent ring - * buffer files. - */ - g_free(global_ld.saved_shb); - global_ld.saved_shb = (guint8 *) g_memdup2(pd, bh->block_total_length); - - /* - * We're dealing with one section at a time, so we can (and must) - * get rid of our old IDBs. - */ - for (unsigned i = 0; i < global_ld.saved_idbs->len; i++) { - saved_idb_t *idb_source = &g_array_index(global_ld.saved_idbs, saved_idb_t, i); - g_free(idb_source->idb); - } - g_array_set_size(global_ld.saved_idbs, 0); - } else { - /* - * We have a new SHB from this capture source. We need to keep - * global_ld.saved_idbs intact, so we mark IDBs we previously - * collected from this source as deleted. - */ - for (unsigned i = 0; i < pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len; i++) { - guint32 iface_id = g_array_index(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, guint32, i); - saved_idb_t *idb_source = &g_array_index(global_ld.saved_idbs, saved_idb_t, iface_id); - ws_assert(idb_source->interface_id == pcap_src->interface_id); - g_free(idb_source->idb); - memset(idb_source, 0, sizeof(saved_idb_t)); - idb_source->deleted = TRUE; - ws_debug("%s: deleted pcapng IDB %u", G_STRFUNC, iface_id); - } - } - g_array_set_size(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, 0); - } - break; - case BLOCK_TYPE_IDB: - { - /* - * Always gather IDBs. We can remove them or mark them as deleted - * when we get a new SHB. - */ - saved_idb_t idb_source = { 0 }; - idb_source.interface_id = pcap_src->interface_id; - idb_source.idb_len = bh->block_total_length; - idb_source.idb = (guint8 *) g_memdup2(pd, idb_source.idb_len); - g_array_append_val(global_ld.saved_idbs, idb_source); - guint32 iface_id = global_ld.saved_idbs->len - 1; - g_array_append_val(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, iface_id); - ws_debug("%s: mapped pcapng IDB %u -> %u from source %u", - G_STRFUNC, pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len - 1, iface_id, pcap_src->interface_id); - } - break; - case BLOCK_TYPE_EPB: - case BLOCK_TYPE_ISB: - { - if (global_ld.pcapng_passthrough) { - /* Our input and output interface IDs are the same. */ - break; - } - /* The interface ID is the first 32-bit field after the BH for both EPBs and ISBs. */ - guint32 iface_id; - memcpy(&iface_id, pd + sizeof(pcapng_block_header_t), 4); - if (iface_id < pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len) { - memcpy(pd + sizeof(pcapng_block_header_t), - &g_array_index(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, guint32, iface_id), 4); - } else { - ws_debug("%s: pcapng EPB or ISB interface id %u > max %u", G_STRFUNC, iface_id, pcap_src->cap_pipe_info.pcapng.src_iface_to_global->len); - return FALSE; - } - } - break; - default: - break; - } - - return TRUE; -} - -/* - * Read the part of the initial pcapng SHB following the block type - * (we've already read the block type). - */ -static void -pcapng_pipe_open_live(int fd, - capture_src *pcap_src, - char *errmsg, - size_t errmsgl) -{ - guint32 type = BLOCK_TYPE_SHB; - pcapng_block_header_t *bh = &pcap_src->cap_pipe_info.pcapng.bh; - - ws_debug("pcapng_pipe_open_live: fd %d", fd); - - /* - * A pcapng block begins with the block type followed by the block - * total length; we've already read the block type, now read the - * block length. - */ -#ifdef _WIN32 - /* - * On UN*X, we can use select() on pipes or sockets. - * - * On Windows, we can only use it on sockets; to do non-blocking - * reads from pipes, we currently do reads in a separate thread - * and use GLib asynchronous queues from the main thread to start - * read operations and to wait for them to complete. - */ - if (pcap_src->from_cap_socket) -#endif - { - memcpy(pcap_src->cap_pipe_databuf, &type, sizeof(guint32)); - pcap_src->cap_pipe_bytes_read = sizeof(guint32); - pcap_src->cap_pipe_bytes_to_read = sizeof(pcapng_block_header_t); - pcap_src->cap_pipe_fd = fd; - if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) { - goto error; - } - memcpy(bh, pcap_src->cap_pipe_databuf, sizeof(pcapng_block_header_t)); - } -#ifdef _WIN32 - else { - g_thread_new("cap_pipe_open_live", &cap_thread_read, pcap_src); - - bh->block_type = type; - pipe_read_sync(pcap_src, &bh->block_total_length, - sizeof(bh->block_total_length)); - if (pcap_src->cap_pipe_bytes_read <= 0) { - if (pcap_src->cap_pipe_bytes_read == 0) - snprintf(errmsg, errmsgl, - "End of file reading from pipe or socket."); - else - snprintf(errmsg, errmsgl, - "Error reading from pipe or socket: %s.", - g_strerror(errno)); - goto error; - } - pcap_src->cap_pipe_bytes_read = sizeof(pcapng_block_header_t); - memcpy(pcap_src->cap_pipe_databuf, bh, sizeof(pcapng_block_header_t)); - pcap_src->cap_pipe_fd = fd; - } -#endif - if ((bh->block_total_length & 0x03) != 0) { - snprintf(errmsg, errmsgl, - "block_total_length read from pipe is %u, which is not a multiple of 4.", - bh->block_total_length); - goto error; - } - if (pcapng_read_shb(pcap_src, errmsg, errmsgl)) { - goto error; - } - - return; - -error: - ws_debug("pcapng_pipe_open_live: error %s", errmsg); - pcap_src->cap_pipe_err = PIPERR; - cap_pipe_close(fd, pcap_src->from_cap_socket); - pcap_src->cap_pipe_fd = -1; -#ifdef _WIN32 - pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE; -#endif -} - -/* We read one record from the pipe, take care of byte order in the record - * header, write the record to the capture file, and update capture statistics. */ -static int -pcap_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, size_t errmsgl) -{ - struct pcap_pkthdr phdr; - enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR, - PD_ERR } result; -#ifdef _WIN32 - gpointer q_status; -#endif - ssize_t b; - guint new_bufsize; - pcap_pipe_info_t *pcap_info = &pcap_src->cap_pipe_info.pcap; - -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("pcap_pipe_dispatch"); -#endif - - switch (pcap_src->cap_pipe_state) { - - case STATE_EXPECT_REC_HDR: -#ifdef _WIN32 - if (g_mutex_trylock(pcap_src->cap_pipe_read_mtx)) { -#endif - - pcap_src->cap_pipe_state = STATE_READ_REC_HDR; - pcap_src->cap_pipe_bytes_to_read = pcap_src->cap_pipe_modified ? - sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr); - pcap_src->cap_pipe_bytes_read = 0; - -#ifdef _WIN32 - pcap_src->cap_pipe_buf = (char *) &pcap_info->rechdr; - g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf); - g_mutex_unlock(pcap_src->cap_pipe_read_mtx); - } -#endif - /* Fall through */ - - case STATE_READ_REC_HDR: -#ifdef _WIN32 - if (pcap_src->from_cap_socket) -#endif - { - b = cap_pipe_read(pcap_src->cap_pipe_fd, ((char *)&pcap_info->rechdr)+pcap_src->cap_pipe_bytes_read, - pcap_src->cap_pipe_bytes_to_read - pcap_src->cap_pipe_bytes_read, pcap_src->from_cap_socket); - if (b <= 0) { - if (b == 0) - result = PD_PIPE_EOF; - else - result = PD_PIPE_ERR; - break; - } -#ifdef _WIN32 - pcap_src->cap_pipe_bytes_read += (DWORD)b; -#else - pcap_src->cap_pipe_bytes_read += b; -#endif - } -#ifdef _WIN32 - else { - q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT); - if (pcap_src->cap_pipe_err == PIPEOF) { - result = PD_PIPE_EOF; - break; - } else if (pcap_src->cap_pipe_err == PIPERR) { - result = PD_PIPE_ERR; - break; - } - if (!q_status) { - return 0; - } - } -#endif - if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read) { - /* There's still more of the pcap packet header to read. */ - return 0; - } - result = PD_REC_HDR_READ; - break; - - case STATE_EXPECT_DATA: -#ifdef _WIN32 - if (g_mutex_trylock(pcap_src->cap_pipe_read_mtx)) { -#endif - - pcap_src->cap_pipe_state = STATE_READ_DATA; - pcap_src->cap_pipe_bytes_to_read = pcap_info->rechdr.hdr.incl_len; - pcap_src->cap_pipe_bytes_read = 0; - -#ifdef _WIN32 - pcap_src->cap_pipe_buf = pcap_src->cap_pipe_databuf; - g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf); - g_mutex_unlock(pcap_src->cap_pipe_read_mtx); - } -#endif - /* Fall through */ - - case STATE_READ_DATA: -#ifdef _WIN32 - if (pcap_src->from_cap_socket) -#endif - { - b = cap_pipe_read(pcap_src->cap_pipe_fd, - pcap_src->cap_pipe_databuf+pcap_src->cap_pipe_bytes_read, - pcap_src->cap_pipe_bytes_to_read - pcap_src->cap_pipe_bytes_read, - pcap_src->from_cap_socket); - if (b <= 0) { - if (b == 0) - result = PD_PIPE_EOF; - else - result = PD_PIPE_ERR; - break; - } -#ifdef _WIN32 - pcap_src->cap_pipe_bytes_read += (DWORD)b; -#else - pcap_src->cap_pipe_bytes_read += b; -#endif - } -#ifdef _WIN32 - else { - - q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT); - if (pcap_src->cap_pipe_err == PIPEOF) { - result = PD_PIPE_EOF; - break; - } else if (pcap_src->cap_pipe_err == PIPERR) { - result = PD_PIPE_ERR; - break; - } - if (!q_status) { - return 0; - } - } -#endif /* _WIN32 */ - if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read) { - /* There's still more of the pcap packet data to read. */ - return 0; - } - result = PD_DATA_READ; - break; - - default: - snprintf(errmsg, errmsgl, - "pcap_pipe_dispatch: invalid state"); - result = PD_ERR; - - } /* switch (pcap_src->cap_pipe_state) */ - - /* - * We've now read as much data as we were expecting, so process it. - */ - switch (result) { - - case PD_REC_HDR_READ: - /* - * We've read the packet header, so we know the captured length, - * and thus the number of packet data bytes. Take care of byte order. - */ - cap_pipe_adjust_pcap_header(pcap_src->cap_pipe_info.pcap.byte_swapped, &pcap_info->hdr, - &pcap_info->rechdr.hdr); - if (pcap_info->rechdr.hdr.incl_len > pcap_src->cap_pipe_max_pkt_size) { - /* - * The record contains more data than the advertised/allowed in the - * pcap header, do not try to read more data (do not change to - * STATE_EXPECT_DATA) as that would not fit in the buffer and - * instead stop with an error. - */ - snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)", - ld->packets_captured+1, pcap_info->rechdr.hdr.incl_len); - break; - } - - if (pcap_info->rechdr.hdr.incl_len > pcap_src->cap_pipe_databuf_size) { - /* - * Grow the buffer to the packet size, rounded up to a power of - * 2. - */ - new_bufsize = pcap_info->rechdr.hdr.incl_len; - /* - * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - */ - new_bufsize--; - new_bufsize |= new_bufsize >> 1; - new_bufsize |= new_bufsize >> 2; - new_bufsize |= new_bufsize >> 4; - new_bufsize |= new_bufsize >> 8; - new_bufsize |= new_bufsize >> 16; - new_bufsize++; - pcap_src->cap_pipe_databuf = (char*)g_realloc(pcap_src->cap_pipe_databuf, new_bufsize); - pcap_src->cap_pipe_databuf_size = new_bufsize; - } - - if (pcap_info->rechdr.hdr.incl_len) { - /* - * The record has some data following the header, try - * to read it next time. - */ - pcap_src->cap_pipe_state = STATE_EXPECT_DATA; - return 0; - } - - /* - * No data following the record header? Then no more data needs to be - * read and we will fallthrough and emit an empty packet. - */ - /* FALLTHROUGH */ - - case PD_DATA_READ: - /* - * We've read the full contents of the packet record. - * Fill in a "struct pcap_pkthdr", and process the packet. - */ - phdr.ts.tv_sec = pcap_info->rechdr.hdr.ts_sec; - phdr.ts.tv_usec = pcap_info->rechdr.hdr.ts_usec; - phdr.caplen = pcap_info->rechdr.hdr.incl_len; - phdr.len = pcap_info->rechdr.hdr.orig_len; - - if (use_threads) { - capture_loop_queue_packet_cb((u_char *)pcap_src, &phdr, pcap_src->cap_pipe_databuf); - } else { - capture_loop_write_packet_cb((u_char *)pcap_src, &phdr, pcap_src->cap_pipe_databuf); - } - - /* - * Now we want to read the next packet's header. - */ - pcap_src->cap_pipe_state = STATE_EXPECT_REC_HDR; - return 1; - - case PD_PIPE_EOF: - pcap_src->cap_pipe_err = PIPEOF; - return -1; - - case PD_PIPE_ERR: - snprintf(errmsg, errmsgl, "Error reading from pipe: %s", -#ifdef _WIN32 - win32strerror(GetLastError())); -#else - g_strerror(errno)); -#endif - /* Fall through */ - case PD_ERR: - break; - } - - pcap_src->cap_pipe_err = PIPERR; - /* Return here rather than inside the switch to prevent GCC warning */ - return -1; -} - -static int -pcapng_pipe_dispatch(loop_data *ld, capture_src *pcap_src, char *errmsg, size_t errmsgl) -{ - enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR, - PD_ERR } result; -#ifdef _WIN32 - gpointer q_status; -#endif - guint new_bufsize; - pcapng_block_header_t *bh = &pcap_src->cap_pipe_info.pcapng.bh; - -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("pcapng_pipe_dispatch"); -#endif - - switch (pcap_src->cap_pipe_state) { - - case STATE_EXPECT_REC_HDR: -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("pcapng_pipe_dispatch STATE_EXPECT_REC_HDR"); -#endif -#ifdef _WIN32 - if (g_mutex_trylock(pcap_src->cap_pipe_read_mtx)) { -#endif - - pcap_src->cap_pipe_state = STATE_READ_REC_HDR; - pcap_src->cap_pipe_bytes_to_read = sizeof(pcapng_block_header_t); - pcap_src->cap_pipe_bytes_read = 0; - -#ifdef _WIN32 - if (!pcap_src->from_cap_socket) { - pcap_src->cap_pipe_buf = pcap_src->cap_pipe_databuf; - g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf); - } - g_mutex_unlock(pcap_src->cap_pipe_read_mtx); - } -#endif - /* Fall through */ - - case STATE_READ_REC_HDR: -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("pcapng_pipe_dispatch STATE_READ_REC_HDR"); -#endif -#ifdef _WIN32 - if (pcap_src->from_cap_socket) { -#endif - if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) { - return -1; - } -#ifdef _WIN32 - } else { - q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT); - if (pcap_src->cap_pipe_err == PIPEOF) { - result = PD_PIPE_EOF; - break; - } else if (pcap_src->cap_pipe_err == PIPERR) { - result = PD_PIPE_ERR; - break; - } - if (!q_status) { - return 0; - } - } -#endif - if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read) { - /* There's still more of the pcapng block header to read. */ - return 0; - } - memcpy(bh, pcap_src->cap_pipe_databuf, sizeof(pcapng_block_header_t)); - result = PD_REC_HDR_READ; - break; - - case STATE_EXPECT_DATA: -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("pcapng_pipe_dispatch STATE_EXPECT_DATA"); -#endif -#ifdef _WIN32 - if (g_mutex_trylock(pcap_src->cap_pipe_read_mtx)) { -#endif - pcap_src->cap_pipe_state = STATE_READ_DATA; - pcap_src->cap_pipe_bytes_to_read = bh->block_total_length; - -#ifdef _WIN32 - if (!pcap_src->from_cap_socket) { - pcap_src->cap_pipe_bytes_to_read -= pcap_src->cap_pipe_bytes_read; - pcap_src->cap_pipe_buf = pcap_src->cap_pipe_databuf + pcap_src->cap_pipe_bytes_read; - pcap_src->cap_pipe_bytes_read = 0; - g_async_queue_push(pcap_src->cap_pipe_pending_q, pcap_src->cap_pipe_buf); - } - g_mutex_unlock(pcap_src->cap_pipe_read_mtx); - } -#endif - /* Fall through */ - - case STATE_READ_DATA: -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("pcapng_pipe_dispatch STATE_READ_DATA"); -#endif -#ifdef _WIN32 - if (pcap_src->from_cap_socket) { -#endif - if (cap_pipe_read_data_bytes(pcap_src, errmsg, errmsgl) < 0) { - return -1; - } -#ifdef _WIN32 - } else { - - q_status = g_async_queue_timeout_pop(pcap_src->cap_pipe_done_q, PIPE_READ_TIMEOUT); - if (pcap_src->cap_pipe_err == PIPEOF) { - result = PD_PIPE_EOF; - break; - } else if (pcap_src->cap_pipe_err == PIPERR) { - result = PD_PIPE_ERR; - break; - } - if (!q_status) { - return 0; - } - } -#endif /* _WIN32 */ - if (pcap_src->cap_pipe_bytes_read < pcap_src->cap_pipe_bytes_to_read) { - /* There's still more of the pcap block contents to read. */ - return 0; - } - result = PD_DATA_READ; - break; - - default: - snprintf(errmsg, errmsgl, - "pcapng_pipe_dispatch: invalid state"); - result = PD_ERR; - - } /* switch (pcap_src->cap_pipe_state) */ - - /* - * We've now read as much data as we were expecting, so process it. - */ - switch (result) { - - case PD_REC_HDR_READ: - /* - * We've read the pcapng block header, so we know the block type - * and length. - */ - if (bh->block_type == BLOCK_TYPE_SHB) { - /* - * We need to read the fixed portion of the SHB before to - * get the endianness before we can interpret the block length. - * (The block type of the SHB is byte-order-independent, so that - * an SHB can be recognized before we know the endianness of - * the section.) - * - * Continue the read process. - */ - pcapng_read_shb(pcap_src, errmsg, errmsgl); - return 1; - } - - if ((bh->block_total_length & 0x03) != 0) { - snprintf(errmsg, errmsgl, - "Total length of pcapng block read from pipe is %u, which is not a multiple of 4.", - bh->block_total_length); - break; - } - if (bh->block_total_length > pcap_src->cap_pipe_max_pkt_size) { - /* - * The record contains more data than the advertised/allowed in the - * pcapng header, do not try to read more data (do not change to - * STATE_EXPECT_DATA) as that would not fit in the buffer and - * instead stop with an error. - */ - snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)", - ld->packets_captured+1, bh->block_total_length); - break; - } - - if (bh->block_total_length > pcap_src->cap_pipe_databuf_size) { - /* - * Grow the buffer to the packet size, rounded up to a power of - * 2. - */ - new_bufsize = bh->block_total_length; - /* - * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - */ - new_bufsize--; - new_bufsize |= new_bufsize >> 1; - new_bufsize |= new_bufsize >> 2; - new_bufsize |= new_bufsize >> 4; - new_bufsize |= new_bufsize >> 8; - new_bufsize |= new_bufsize >> 16; - new_bufsize++; - pcap_src->cap_pipe_databuf = (guchar*)g_realloc(pcap_src->cap_pipe_databuf, new_bufsize); - pcap_src->cap_pipe_databuf_size = new_bufsize; - } - - /* The record always has at least the block total length following the header */ - if (bh->block_total_length < sizeof(pcapng_block_header_t)+sizeof(guint32)) { - snprintf(errmsg, errmsgl, - "malformed pcapng block_total_length < minimum"); - pcap_src->cap_pipe_err = PIPEOF; - return -1; - } - - /* - * Now we want to read the block contents. - */ - pcap_src->cap_pipe_state = STATE_EXPECT_DATA; - return 0; - - case PD_DATA_READ: - /* - * We've read the full contents of the block. - * Process the block. - */ - if (use_threads) { - capture_loop_queue_pcapng_cb(pcap_src, bh, pcap_src->cap_pipe_databuf); - } else { - capture_loop_write_pcapng_cb(pcap_src, bh, pcap_src->cap_pipe_databuf); - } - - /* - * Now we want to read the next block's header. - */ - pcap_src->cap_pipe_state = STATE_EXPECT_REC_HDR; - return 1; - - case PD_PIPE_EOF: - pcap_src->cap_pipe_err = PIPEOF; - return -1; - - case PD_PIPE_ERR: - snprintf(errmsg, errmsgl, "Error reading from pipe: %s", -#ifdef _WIN32 - win32strerror(GetLastError())); -#else - g_strerror(errno)); -#endif - /* Fall through */ - case PD_ERR: - break; - } - - pcap_src->cap_pipe_err = PIPERR; - /* Return here rather than inside the switch to prevent GCC warning */ - return -1; -} - -/** Open the capture input sources; each one is either a pcap device, - * a capture pipe, or a capture socket. - * Returns TRUE if it succeeds, FALSE otherwise. */ -static gboolean -capture_loop_open_input(capture_options *capture_opts, loop_data *ld, - char *errmsg, size_t errmsg_len, - char *secondary_errmsg, size_t secondary_errmsg_len) -{ - cap_device_open_status open_status; - gchar open_status_str[PCAP_ERRBUF_SIZE]; - gchar *sync_msg_str; - interface_options *interface_opts; - capture_src *pcap_src; - guint i; - - if ((use_threads == FALSE) && - (capture_opts->ifaces->len > 1)) { - snprintf(errmsg, errmsg_len, - "Using threads is required for capturing on multiple interfaces."); - return FALSE; - } - - int pcapng_src_count = 0; - for (i = 0; i < capture_opts->ifaces->len; i++) { - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i); - pcap_src = g_new0(capture_src, 1); - if (pcap_src == NULL) { - snprintf(errmsg, errmsg_len, - "Could not allocate memory."); - return FALSE; - } - -#ifdef MUST_DO_SELECT - pcap_src->pcap_fd = -1; -#endif - pcap_src->interface_id = i; - pcap_src->linktype = -1; -#ifdef _WIN32 - pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE; -#endif - pcap_src->cap_pipe_fd = -1; - pcap_src->cap_pipe_dispatch = pcap_pipe_dispatch; - pcap_src->cap_pipe_state = STATE_EXPECT_REC_HDR; - pcap_src->cap_pipe_err = PIPOK; -#ifdef _WIN32 - pcap_src->cap_pipe_read_mtx = g_new(GMutex, 1); - g_mutex_init(pcap_src->cap_pipe_read_mtx); - pcap_src->cap_pipe_pending_q = g_async_queue_new(); - pcap_src->cap_pipe_done_q = g_async_queue_new(); -#endif - g_array_append_val(ld->pcaps, pcap_src); - - ws_debug("capture_loop_open_input : %s", interface_opts->name); - pcap_src->pcap_h = open_capture_device(capture_opts, interface_opts, - CAP_READ_TIMEOUT, &open_status, &open_status_str); - - if (pcap_src->pcap_h != NULL) { - /* we've opened "iface" as a network device */ - -#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION - /* Find out if we're getting nanosecond-precision time stamps */ - pcap_src->ts_nsec = have_high_resolution_timestamp(pcap_src->pcap_h); -#endif - -#if defined(HAVE_PCAP_SETSAMPLING) - if (interface_opts->sampling_method != CAPTURE_SAMP_NONE) { - struct pcap_samp *samp; - - if ((samp = pcap_setsampling(pcap_src->pcap_h)) != NULL) { - switch (interface_opts->sampling_method) { - case CAPTURE_SAMP_BY_COUNT: - samp->method = PCAP_SAMP_1_EVERY_N; - break; - - case CAPTURE_SAMP_BY_TIMER: - samp->method = PCAP_SAMP_FIRST_AFTER_N_MS; - break; - - default: - sync_msg_str = ws_strdup_printf( - "Unknown sampling method %d specified,\n" - "continue without packet sampling", - interface_opts->sampling_method); - report_capture_error("Couldn't set the capture " - "sampling", sync_msg_str); - g_free(sync_msg_str); - } - samp->value = interface_opts->sampling_param; - } else { - 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_datalink(pcap_src->pcap_h, interface_opts->linktype, - interface_opts->name, - errmsg, errmsg_len, - secondary_errmsg, secondary_errmsg_len)) { - return FALSE; - } - pcap_src->linktype = dlt_to_linktype(get_pcap_datalink(pcap_src->pcap_h, interface_opts->name)); - } else { - /* We couldn't open "iface" as a network device. */ - /* Try to open it as a pipe */ - gboolean pipe_err = FALSE; - cap_pipe_open_live(interface_opts->name, pcap_src, - &pcap_src->cap_pipe_info.pcap.hdr, - errmsg, errmsg_len, - secondary_errmsg, secondary_errmsg_len); - -#ifdef _WIN32 - if (pcap_src->from_cap_socket) { -#endif - if (pcap_src->cap_pipe_fd == -1) { - pipe_err = TRUE; - } -#ifdef _WIN32 - } else { - if (pcap_src->cap_pipe_h == INVALID_HANDLE_VALUE) { - pipe_err = TRUE; - } - } -#endif - - if (pipe_err) { - if (pcap_src->cap_pipe_err == PIPNEXIST) { - /* - * We tried opening as an interface, and that failed, - * so we tried to open it as a pipe, but the pipe - * doesn't exist. Report the error message for - * the interface. - */ - get_capture_device_open_failure_messages(open_status, - open_status_str, - interface_opts->name, - errmsg, - errmsg_len, - secondary_errmsg, - secondary_errmsg_len); - } - /* - * Else pipe (or file) does exist and cap_pipe_open_live() has - * filled in errmsg - */ - return FALSE; - } else { - /* - * We tried opening as an interface, and that failed, - * so we tried to open it as a pipe, and that succeeded. - */ - open_status = CAP_DEVICE_OPEN_NO_ERR; - } - } - -/* XXX - will this work for tshark? */ -#ifdef MUST_DO_SELECT - if (!pcap_src->from_cap_pipe) { - pcap_src->pcap_fd = pcap_get_selectable_fd(pcap_src->pcap_h); - } -#endif - - /* Is "open_status" something other than CAP_DEVICE_OPEN_NO_ERR? - If so, "open_capture_device()" returned a warning; print it, - but keep capturing. */ - if (open_status != CAP_DEVICE_OPEN_NO_ERR) { - sync_msg_str = ws_strdup_printf("%s.", open_status_str); - report_capture_error(sync_msg_str, ""); - g_free(sync_msg_str); - } - if (pcap_src->from_pcapng) { - /* - * We will use the IDBs from the source (but rewrite the - * interface IDs if there's more than one source.) - */ - pcapng_src_count++; - } else { - /* - * Add our pcapng interface entry. - */ - saved_idb_t idb_source = { 0 }; - idb_source.interface_id = i; - g_rw_lock_writer_lock (&ld->saved_shb_idb_lock); - pcap_src->idb_id = global_ld.saved_idbs->len; - g_array_append_val(global_ld.saved_idbs, idb_source); - g_rw_lock_writer_unlock (&ld->saved_shb_idb_lock); - ws_debug("%s: saved capture_opts %u to IDB %u", - G_STRFUNC, i, pcap_src->idb_id); - } - } - - /* - * Are we capturing from one source that is providing pcapng - * information? - */ - if (capture_opts->ifaces->len == 1 && pcapng_src_count == 1) { - /* - * Yes; pass through SHBs and IDBs from the source, rather - * than generating our own. - */ - ld->pcapng_passthrough = TRUE; - g_rw_lock_writer_lock (&ld->saved_shb_idb_lock); - ws_assert(global_ld.saved_idbs->len == 0); - ws_debug("%s: Pass through SHBs and IDBs directly", G_STRFUNC); - g_rw_lock_writer_unlock (&ld->saved_shb_idb_lock); - } - - /* 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; -} - -/* close the capture input file (pcap or capture pipe) */ -static void capture_loop_close_input(loop_data *ld) -{ - guint i; - capture_src *pcap_src; - - ws_debug("capture_loop_close_input"); - - for (i = 0; i < ld->pcaps->len; i++) { - pcap_src = g_array_index(ld->pcaps, capture_src *, i); - /* Pipe, or capture device? */ - if (pcap_src->from_cap_pipe) { - /* Pipe. If open, close the capture pipe "input file". */ - if (pcap_src->cap_pipe_fd >= 0) { - cap_pipe_close(pcap_src->cap_pipe_fd, pcap_src->from_cap_socket); - pcap_src->cap_pipe_fd = -1; - } -#ifdef _WIN32 - if (pcap_src->cap_pipe_h != INVALID_HANDLE_VALUE) { - CloseHandle(pcap_src->cap_pipe_h); - pcap_src->cap_pipe_h = INVALID_HANDLE_VALUE; - } -#endif - if (pcap_src->cap_pipe_databuf != NULL) { - /* Free the buffer. */ - g_free(pcap_src->cap_pipe_databuf); - pcap_src->cap_pipe_databuf = NULL; - } - if (pcap_src->from_pcapng) { - g_array_free(pcap_src->cap_pipe_info.pcapng.src_iface_to_global, TRUE); - pcap_src->cap_pipe_info.pcapng.src_iface_to_global = NULL; - } - } else { - /* Capture device. If open, close the pcap_t. */ - if (pcap_src->pcap_h != NULL) { - ws_debug("capture_loop_close_input: closing %p", (void *)pcap_src->pcap_h); - pcap_close(pcap_src->pcap_h); - pcap_src->pcap_h = NULL; - } - } - } - - ld->go = FALSE; -} - - -/* init the capture filter */ -static initfilter_status_t -capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, - const gchar * name, const gchar * cfilter) -{ - struct bpf_program fcode; - - ws_debug("capture_loop_init_filter: %s", cfilter); - - /* capture filters only work on real interfaces */ - if (cfilter && !from_cap_pipe) { - /* A capture filter was specified; set it up. */ - if (!compile_capture_filter(name, pcap_h, &fcode, cfilter)) { - /* Treat this specially - our caller might try to compile this - as a display filter and, if that succeeds, warn the user that - the display and capture filter syntaxes are different. */ - return INITFILTER_BAD_FILTER; - } - if (pcap_setfilter(pcap_h, &fcode) < 0) { -#ifdef HAVE_PCAP_FREECODE - pcap_freecode(&fcode); -#endif - return INITFILTER_OTHER_ERROR; - } -#ifdef HAVE_PCAP_FREECODE - pcap_freecode(&fcode); -#endif - } - - return INITFILTER_NO_ERROR; -} - -/* - * Write the dumpcap pcapng SHB and IDBs if needed. - * Called from capture_loop_init_output and do_file_switch_or_stop. - */ -static gboolean -capture_loop_init_pcapng_output(capture_options *capture_opts, loop_data *ld, - int *err) -{ - g_rw_lock_reader_lock (&ld->saved_shb_idb_lock); - - if (ld->pcapng_passthrough && !ld->saved_shb) { - /* We have a single pcapng capture interface and this is the first or only output file. */ - ws_debug("%s: skipping dumpcap SHB and IDBs in favor of source", G_STRFUNC); - g_rw_lock_reader_unlock (&ld->saved_shb_idb_lock); - return TRUE; - } - - gboolean successful = TRUE; - GString *os_info_str = g_string_new(""); - - *err = 0; - get_os_version_info(os_info_str); - - if (ld->saved_shb) { - /* We have a single pcapng capture interface and multiple output files. */ - - pcapng_block_header_t bh; - - memcpy(&bh, ld->saved_shb, sizeof(pcapng_block_header_t)); - - successful = pcapng_write_block(ld->pdh, ld->saved_shb, bh.block_total_length, &ld->bytes_written, err); - - ws_debug("%s: wrote saved passthrough SHB %d", G_STRFUNC, successful); - } else { - GString *cpu_info_str = g_string_new(""); - get_cpu_info(cpu_info_str); - - successful = pcapng_write_section_header_block(ld->pdh, - capture_comments, /* Comments */ - cpu_info_str->str, /* HW */ - os_info_str->str, /* OS */ - get_appname_and_version(), - -1, /* section_length */ - &ld->bytes_written, - err); - ws_debug("%s: wrote dumpcap SHB %d", G_STRFUNC, successful); - g_string_free(cpu_info_str, TRUE); - } - - for (unsigned i = 0; successful && (i < ld->saved_idbs->len); i++) { - saved_idb_t idb_source = g_array_index(ld->saved_idbs, saved_idb_t, i); - if (idb_source.deleted) { - /* - * Our interface is out of scope. Suppose we're writing multiple - * files and a source switches sections. We currently write dummy - * IDBs like so: - * - * File 1: IDB0, IDB1, IDB2 - * [ The source of IDBs 1 and 2 writes an SHB with two new IDBs ] - * [ We switch output files ] - * File 2: IDB0, dummy IDB, dummy IDB, IDB3, IDB4 - * - * It might make more sense to write the original data so that - * so that our IDB lists are more consistent across files. - */ - successful = pcapng_write_interface_description_block(global_ld.pdh, - "Interface went out of scope", /* OPT_COMMENT 1 */ - "dummy", /* IDB_NAME 2 */ - "Dumpcap dummy interface", /* IDB_DESCRIPTION 3 */ - NULL, /* IDB_FILTER 11 */ - os_info_str->str, /* IDB_OS 12 */ - NULL, /* IDB_HARDWARE 15 */ - -1, - 0, - &(global_ld.bytes_written), - 0, /* IDB_IF_SPEED 8 */ - 6, /* IDB_TSRESOL 9 */ - &global_ld.err); - ws_debug("%s: skipping deleted pcapng IDB %u", G_STRFUNC, i); - } else if (idb_source.idb && idb_source.idb_len) { - successful = pcapng_write_block(global_ld.pdh, idb_source.idb, idb_source.idb_len, &ld->bytes_written, err); - ws_debug("%s: wrote pcapng IDB %d", G_STRFUNC, successful); - } else if (idb_source.interface_id < capture_opts->ifaces->len) { - unsigned if_id = idb_source.interface_id; - interface_options *interface_opts = &g_array_index(capture_opts->ifaces, interface_options, if_id); - capture_src *pcap_src = g_array_index(ld->pcaps, capture_src *, if_id); - if (pcap_src->from_cap_pipe) { - pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen; - } else { - pcap_src->snaplen = pcap_snapshot(pcap_src->pcap_h); - } - successful = pcapng_write_interface_description_block(global_ld.pdh, - NULL, /* OPT_COMMENT 1 */ - (interface_opts->ifname != NULL) ? interface_opts->ifname : interface_opts->name, /* IDB_NAME 2 */ - interface_opts->descr, /* IDB_DESCRIPTION 3 */ - interface_opts->cfilter, /* IDB_FILTER 11 */ - os_info_str->str, /* IDB_OS 12 */ - interface_opts->hardware, /* IDB_HARDWARE 15 */ - pcap_src->linktype, - pcap_src->snaplen, - &(global_ld.bytes_written), - 0, /* IDB_IF_SPEED 8 */ - pcap_src->ts_nsec ? 9 : 6, /* IDB_TSRESOL 9 */ - &global_ld.err); - ws_debug("%s: wrote capture_opts IDB %d: %d", G_STRFUNC, if_id, successful); - } - } - g_rw_lock_reader_unlock (&ld->saved_shb_idb_lock); - - g_string_free(os_info_str, TRUE); - - return successful; -} - -/* set up to write to the already-opened capture output file/files */ -static gboolean -capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len) -{ - int err = 0; - - ws_debug("capture_loop_init_output"); - - if ((capture_opts->use_pcapng == FALSE) && - (capture_opts->ifaces->len > 1)) { - snprintf(errmsg, errmsg_len, - "Using PCAPNG is required for capturing on multiple interfaces. Use the -n option."); - return FALSE; - } - - /* Set up to write to the capture file. */ - if (capture_opts->multi_files_on) { - ld->pdh = ringbuf_init_libpcap_fdopen(&err); - } else { - ld->pdh = ws_fdopen(ld->save_file_fd, "wb"); - if (ld->pdh == NULL) { - err = errno; - } else { - size_t buffsize = IO_BUF_SIZE; -#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - ws_statb64 statb; - - if (ws_fstat64(ld->save_file_fd, &statb) == 0) { - if (statb.st_blksize > IO_BUF_SIZE) { - buffsize = statb.st_blksize; - } - } -#endif - /* Increase the size of the IO buffer */ - ld->io_buffer = (char *)g_malloc(buffsize); - setvbuf(ld->pdh, ld->io_buffer, _IOFBF, buffsize); - ws_debug("capture_loop_init_output: buffsize %zu", buffsize); - } - } - if (ld->pdh) { - gboolean successful; - if (capture_opts->use_pcapng) { - successful = capture_loop_init_pcapng_output(capture_opts, ld, &err); - } else { - capture_src *pcap_src; - pcap_src = g_array_index(ld->pcaps, capture_src *, 0); - if (pcap_src->from_cap_pipe) { - pcap_src->snaplen = pcap_src->cap_pipe_info.pcap.hdr.snaplen; - } else { - pcap_src->snaplen = pcap_snapshot(pcap_src->pcap_h); - } - successful = libpcap_write_file_header(ld->pdh, pcap_src->linktype, pcap_src->snaplen, - pcap_src->ts_nsec, &ld->bytes_written, &err); - } - if (!successful) { - fclose(ld->pdh); - ld->pdh = NULL; - g_free(ld->io_buffer); - ld->io_buffer = NULL; - } - } - - if (ld->pdh == NULL) { - /* We couldn't set up to write to the capture file. */ - /* XXX - use cf_open_error_message from tshark instead? */ - if (err < 0) { - snprintf(errmsg, errmsg_len, - "The file to which the capture would be" - " saved (\"%s\") could not be opened: Error %d.", - capture_opts->save_file, err); - } else { - snprintf(errmsg, errmsg_len, - "The file to which the capture would be" - " saved (\"%s\") could not be opened: %s.", - capture_opts->save_file, g_strerror(err)); - } - return FALSE; - } - - return TRUE; -} - -static gboolean -capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err_close) -{ - - unsigned int i; - capture_src *pcap_src; - guint64 end_time = create_timestamp(); - gboolean success; - - ws_debug("capture_loop_close_output"); - - if (capture_opts->multi_files_on) { - return ringbuf_libpcap_dump_close(&capture_opts->save_file, err_close); - } else { - if (capture_opts->use_pcapng) { - for (i = 0; i < global_ld.pcaps->len; i++) { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, i); - if (!pcap_src->from_cap_pipe) { - guint64 isb_ifrecv, isb_ifdrop; - struct pcap_stat stats; - - if (pcap_stats(pcap_src->pcap_h, &stats) >= 0) { - isb_ifrecv = pcap_src->received; - isb_ifdrop = stats.ps_drop + pcap_src->dropped + pcap_src->flushed; - } else { - isb_ifrecv = G_MAXUINT64; - isb_ifdrop = G_MAXUINT64; - } - pcapng_write_interface_statistics_block(ld->pdh, - i, - &ld->bytes_written, - "Counters provided by dumpcap", - start_time, - end_time, - isb_ifrecv, - isb_ifdrop, - err_close); - } - } - } - if (fclose(ld->pdh) == EOF) { - if (err_close != NULL) { - *err_close = errno; - } - success = FALSE; - } else { - success = TRUE; - } - g_free(ld->io_buffer); - ld->io_buffer = NULL; - return success; - } -} - -/* dispatch incoming packets (pcap or capture pipe) - * - * Waits for incoming packets to be available, and calls pcap_dispatch() - * to cause them to be processed. - * - * Returns the number of packets which were processed. - * - * Times out (returning zero) after CAP_READ_TIMEOUT ms; this ensures that the - * packet-batching behaviour does not cause packets to get held back - * indefinitely. - */ -static int -capture_loop_dispatch(loop_data *ld, - char *errmsg, int errmsg_len, capture_src *pcap_src) -{ - int inpkts = 0; - gint packet_count_before; - int sel_ret; - - packet_count_before = ld->packets_captured; - if (pcap_src->from_cap_pipe) { - /* dispatch from capture pipe */ -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("capture_loop_dispatch: from capture pipe"); -#endif -#ifdef _WIN32 - if (pcap_src->from_cap_socket) { -#endif - sel_ret = cap_pipe_select(pcap_src->cap_pipe_fd); - if (sel_ret <= 0) { - if (sel_ret < 0 && errno != EINTR) { - snprintf(errmsg, errmsg_len, - "Unexpected error from select: %s", g_strerror(errno)); - report_capture_error(errmsg, please_report_bug()); - ld->go = FALSE; - } - } -#ifdef _WIN32 - } else { - /* Windows does not have select() for pipes. */ - /* Proceed with _dispatch() which waits for cap_pipe_done_q - * notification from cap_thread_read() when ReadFile() on - * the pipe has read enough bytes. */ - sel_ret = 1; - } -#endif - if (sel_ret > 0) { - /* - * "select()" says we can read from the pipe without blocking - */ - inpkts = pcap_src->cap_pipe_dispatch(ld, pcap_src, errmsg, errmsg_len); - if (inpkts < 0) { - ws_debug("%s: src %u pipe reached EOF or err, rcv: %u drop: %u flush: %u", - G_STRFUNC, pcap_src->interface_id, pcap_src->received, pcap_src->dropped, pcap_src->flushed); - ws_assert(pcap_src->cap_pipe_err != PIPOK); - } - } - } - else - { - /* dispatch from pcap */ -#ifdef MUST_DO_SELECT - /* - * If we have "pcap_get_selectable_fd()", we use it to get the - * descriptor on which to select; if that's -1, it means there - * is no descriptor on which you can do a "select()" (perhaps - * because you're capturing on a special device, and that device's - * driver unfortunately doesn't support "select()", in which case - * we don't do the select - which means it might not be possible - * to stop a capture until a packet arrives. If that's unacceptable, - * plead with whoever supplies the software for that device to add - * "select()" support, or upgrade to libpcap 0.8.1 or later, and - * rebuild Wireshark or get a version built with libpcap 0.8.1 or - * later, so it can use pcap_breakloop(). - */ -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("capture_loop_dispatch: from pcap_dispatch with select"); -#endif - if (pcap_src->pcap_fd != -1) { - sel_ret = cap_pipe_select(pcap_src->pcap_fd); - if (sel_ret > 0) { - /* - * "select()" says we can read from it without blocking; go for - * it. - * - * We don't have pcap_breakloop(), so we only process one packet - * per pcap_dispatch() call, to allow a signal to stop the - * processing immediately, rather than processing all packets - * in a batch before quitting. - */ - if (use_threads) { - inpkts = pcap_dispatch(pcap_src->pcap_h, 1, capture_loop_queue_packet_cb, (u_char *)pcap_src); - } else { - inpkts = pcap_dispatch(pcap_src->pcap_h, 1, capture_loop_write_packet_cb, (u_char *)pcap_src); - } - if (inpkts < 0) { - if (inpkts == -1) { - /* Error, rather than pcap_breakloop(). */ - pcap_src->pcap_err = TRUE; - } - ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */ - } - } else { - if (sel_ret < 0 && errno != EINTR) { - snprintf(errmsg, errmsg_len, - "Unexpected error from select: %s", g_strerror(errno)); - report_capture_error(errmsg, please_report_bug()); - ld->go = FALSE; - } - } - } - else -#endif /* MUST_DO_SELECT */ - { - /* dispatch from pcap without select */ -#if 1 -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("capture_loop_dispatch: from pcap_dispatch"); -#endif -#ifdef _WIN32 - /* - * On Windows, we don't support asynchronously telling a process to - * stop capturing; instead, we check for an indication on a pipe - * 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_src->pcap_h, 1, capture_loop_queue_packet_cb, (u_char *)pcap_src); - } else { - inpkts = pcap_dispatch(pcap_src->pcap_h, 1, capture_loop_write_packet_cb, (u_char *)pcap_src); - } -#else - if (use_threads) { - inpkts = pcap_dispatch(pcap_src->pcap_h, -1, capture_loop_queue_packet_cb, (u_char *)pcap_src); - } else { - inpkts = pcap_dispatch(pcap_src->pcap_h, -1, capture_loop_write_packet_cb, (u_char *)pcap_src); - } -#endif - if (inpkts < 0) { - if (inpkts == -1) { - /* Error, rather than pcap_breakloop(). */ - pcap_src->pcap_err = TRUE; - } - ld->go = FALSE; /* error or pcap_breakloop() - stop capturing */ - } -#else /* pcap_next_ex */ -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("capture_loop_dispatch: from pcap_next_ex"); -#endif - /* XXX - this is currently unused, as there is some confusion with pcap_next_ex() vs. pcap_dispatch() */ - - /* - * WinPcap's remote capturing feature doesn't work with pcap_dispatch(), - * see https://gitlab.com/wireshark/wireshark/-/wikis/CaptureSetup/WinPcapRemote - * This should be fixed in the WinPcap 4.0 alpha release. - * - * For reference, an example remote interface: - * rpcap://[1.2.3.4]/\Device\NPF_{39993D68-7C9B-4439-A329-F2D888DA7C5C} - */ - - /* emulate dispatch from pcap */ - { - int in; - struct pcap_pkthdr *pkt_header; - u_char *pkt_data; - - in = 0; - while(ld->go && - (in = pcap_next_ex(pcap_src->pcap_h, &pkt_header, &pkt_data)) == 1) { - if (use_threads) { - capture_loop_queue_packet_cb((u_char *)pcap_src, pkt_header, pkt_data); - } else { - capture_loop_write_packet_cb((u_char *)pcap_src, pkt_header, pkt_data); - } - } - - if (in < 0) { - pcap_src->pcap_err = TRUE; - ld->go = FALSE; - } - } -#endif /* pcap_next_ex */ - } - } - -#ifdef LOG_CAPTURE_VERBOSE - ws_debug("capture_loop_dispatch: %d new packet%s", inpkts, plurality(inpkts, "", "s")); -#endif - - return ld->packets_captured - packet_count_before; -} - -#ifdef _WIN32 -/* Isolate the Universally Unique Identifier from the interface. Basically, we - * want to grab only the characters between the '{' and '}' delimiters. - * - * Returns a GString that must be freed with g_string_free(). */ -static GString * -isolate_uuid(const char *iface) -{ - gchar *ptr; - GString *gstr; - - ptr = strchr(iface, '{'); - if (ptr == NULL) - return g_string_new(iface); - gstr = g_string_new(ptr + 1); - - ptr = strchr(gstr->str, '}'); - if (ptr == NULL) - return gstr; - - gstr = g_string_truncate(gstr, ptr - gstr->str); - return gstr; -} -#endif - -/* open the output file (temporary/specified name/ringbuffer/named pipe/stdout) */ -/* Returns TRUE if the file opened successfully, FALSE otherwise. */ -static gboolean -capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, - char *errmsg, int errmsg_len) -{ - gchar *capfile_name = NULL; - gchar *prefix, *suffix; - gboolean is_tempfile; - GError *err_tempfile = NULL; - - ws_debug("capture_loop_open_output: %s", - (capture_opts->save_file) ? capture_opts->save_file : "(not specified)"); - - if (capture_opts->save_file != NULL) { - /* We return to the caller while the capture is in progress. - * Therefore we need to take a copy of save_file in - * case the caller destroys it after we return. - */ - capfile_name = g_strdup(capture_opts->save_file); - - if (capture_opts->output_to_pipe == TRUE) { /* either "-" or named pipe */ - if (capture_opts->multi_files_on) { - /* ringbuffer is enabled; that doesn't work with standard output or a named pipe */ - snprintf(errmsg, errmsg_len, - "Ring buffer requested, but capture is being written to standard output or to a named pipe."); - g_free(capfile_name); - return FALSE; - } - if (strcmp(capfile_name, "-") == 0) { - /* write to stdout */ - *save_file_fd = 1; -#ifdef _WIN32 - /* set output pipe to binary mode to avoid Windows text-mode processing (eg: for CR/LF) */ - _setmode(1, O_BINARY); -#endif - } else { - /* Try to open the specified FIFO for use as a capture buffer. - Do *not* create it if it doesn't exist. There's nothing - to truncate. If we need to read it, We Have A Problem. */ - *save_file_fd = ws_open(capfile_name, O_WRONLY|O_BINARY, 0); - } - } /* if (...output_to_pipe ... */ - - else { - if (capture_opts->multi_files_on) { - /* ringbuffer is enabled */ - *save_file_fd = ringbuf_init(capfile_name, - (capture_opts->has_ring_num_files) ? capture_opts->ring_num_files : 0, - capture_opts->group_read_access, - capture_opts->compress_type, - capture_opts->has_nametimenum); - - /* capfile_name is unused as the ringbuffer provides its own filename. */ - if (*save_file_fd != -1) { - g_free(capfile_name); - capfile_name = NULL; - } - if (capture_opts->print_file_names) { - if (!ringbuf_set_print_name(capture_opts->print_name_to, NULL)) { - snprintf(errmsg, errmsg_len, "Could not write filenames to %s: %s.\n", - capture_opts->print_name_to, - g_strerror(errno)); - g_free(capfile_name); - ringbuf_error_cleanup(); - return FALSE; - } - } - } else { - /* Try to open/create the specified file for use as a capture buffer. */ - *save_file_fd = ws_open(capfile_name, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, - (capture_opts->group_read_access) ? 0640 : 0600); - } - } - is_tempfile = FALSE; - } else { - /* Choose a random name for the temporary capture buffer */ - if (global_capture_opts.ifaces->len > 1) { - /* - * More than one interface; just use the number of interfaces - * to generate the temporary file name prefix. - */ - prefix = ws_strdup_printf("wireshark_%d_interfaces", global_capture_opts.ifaces->len); - } else { - /* - * One interface; use its description, if it has one, to generate - * the temporary file name, otherwise use its name. - */ - gchar *basename; - const interface_options *interface_opts; - - interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, 0); - - /* - * Do we have a description? - */ - if (interface_opts->descr) { - /* - * Yes - use it. - * - * Strip off any stuff we shouldn't use in the file name, - * by getting the last component of what would be a file - * name. - */ - basename = g_path_get_basename(interface_opts->descr); - } else { - /* - * No - use the name. - * - * Strip off any stuff we shouldn't use in the file name, - * by getting the last component of what would be a file - * name. - */ - basename = g_path_get_basename(interface_opts->name); -#ifdef _WIN32 - /* - * This is Windows, where we might have an ugly GUID-based - * interface name. - * - * If it's an ugly GUID-based name, use the generic portion - * of the interface GUID to form the basis of the filename. - */ - if (strncmp("NPF_{", basename, 5) == 0) { - /* - * We have a GUID-based name; extract the GUID digits - * as the basis of the filename. - */ - GString *iface; - iface = isolate_uuid(basename); - g_free(basename); - basename = g_strdup(iface->str); - g_string_free(iface, TRUE); - } -#endif - } - /* generate the temp file name prefix */ - prefix = g_strconcat("wireshark_", basename, NULL); - g_free(basename); - } - - /* Generate the appropriate suffix. */ - if (capture_opts->use_pcapng) { - suffix = ".pcapng"; - } else { - suffix = ".pcap"; - } - *save_file_fd = create_tempfile(capture_opts->temp_dir, &capfile_name, prefix, suffix, &err_tempfile); - g_free(prefix); - is_tempfile = TRUE; - } - - /* did we fail to open the output file? */ - if (*save_file_fd == -1) { - if (is_tempfile) { - snprintf(errmsg, errmsg_len, - "The temporary file to which the capture would be saved " - "could not be opened: %s.", err_tempfile->message); - g_error_free(err_tempfile); - } else { - if (capture_opts->multi_files_on) { - /* Ensures that the ringbuffer is not used. This ensures that - * !ringbuf_is_initialized() is equivalent to - * capture_opts->save_file not being part of ringbuffer. */ - ringbuf_error_cleanup(); - } - - snprintf(errmsg, errmsg_len, - "The file to which the capture would be saved (\"%s\") " - "could not be opened: %s.", capfile_name, - g_strerror(errno)); - } - g_free(capfile_name); - return FALSE; - } - - g_free(capture_opts->save_file); - if (!is_tempfile && capture_opts->multi_files_on) { - /* In ringbuffer mode, save_file points to a filename from ringbuffer.c. - * capfile_name was already freed before. */ - capture_opts->save_file = (char *)ringbuf_current_filename(); - } else { - /* capture_opts_cleanup will g_free(capture_opts->save_file). */ - capture_opts->save_file = capfile_name; - } - - return TRUE; -} - -static time_t get_next_time_interval(int interval_s) { - time_t next_time = time(NULL); - next_time -= next_time % interval_s; - next_time += interval_s; - return next_time; -} - -/* Do the work of handling either the file size or file duration capture - conditions being reached, and switching files or stopping. */ -static gboolean -do_file_switch_or_stop(capture_options *capture_opts) -{ - gboolean successful; - - if (capture_opts->multi_files_on) { - if (capture_opts->has_autostop_files && - ++global_ld.file_count >= capture_opts->autostop_files) { - /* no files left: stop here */ - global_ld.go = FALSE; - return FALSE; - } - - /* Switch to the next ringbuffer file */ - if (ringbuf_switch_file(&global_ld.pdh, &capture_opts->save_file, - &global_ld.save_file_fd, &global_ld.err)) { - - /* File switch succeeded: reset the conditions */ - global_ld.bytes_written = 0; - global_ld.packets_written = 0; - if (capture_opts->use_pcapng) { - successful = capture_loop_init_pcapng_output(capture_opts, &global_ld, &global_ld.err); - } else { - capture_src *pcap_src; - pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0); - successful = libpcap_write_file_header(global_ld.pdh, pcap_src->linktype, pcap_src->snaplen, - pcap_src->ts_nsec, &global_ld.bytes_written, &global_ld.err); - } - - if (!successful) { - fclose(global_ld.pdh); - global_ld.pdh = NULL; - global_ld.go = FALSE; - g_free(global_ld.io_buffer); - global_ld.io_buffer = NULL; - return FALSE; - } - if (global_ld.file_duration_timer) { - g_timer_reset(global_ld.file_duration_timer); - } - if (global_ld.next_interval_time) { - global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s); - } - fflush(global_ld.pdh); - if (global_ld.inpkts_to_sync_pipe) { - if (!quiet) - report_packet_count(global_ld.inpkts_to_sync_pipe); - global_ld.inpkts_to_sync_pipe = 0; - } - report_new_capture_file(capture_opts->save_file); - } else { - /* File switch failed: stop here */ - global_ld.go = FALSE; - return FALSE; - } - } else { - /* single file, stop now */ - global_ld.go = FALSE; - return FALSE; - } - return TRUE; -} - -static void * -pcap_read_handler(void* arg) -{ - capture_src *pcap_src = (capture_src *)arg; - char errmsg[MSG_MAX_LENGTH+1]; - - ws_info("Started thread for interface %d.", pcap_src->interface_id); - - /* If this is a pipe input it might finish early. */ - while (global_ld.go && pcap_src->cap_pipe_err == PIPOK) { - /* dispatch incoming packets */ - capture_loop_dispatch(&global_ld, errmsg, sizeof(errmsg), pcap_src); - } - - ws_info("Stopped thread for interface %d.", pcap_src->interface_id); - g_thread_exit(NULL); - return (NULL); -} - -/* Try to pop an item off the packet queue and if it exists, write it */ -static gboolean -capture_loop_dequeue_packet(void) { - pcap_queue_element *queue_element; - - g_async_queue_lock(pcap_queue); - queue_element = (pcap_queue_element *)g_async_queue_timeout_pop_unlocked(pcap_queue, WRITER_THREAD_TIMEOUT); - if (queue_element) { - if (queue_element->pcap_src->from_pcapng) { - pcap_queue_bytes -= queue_element->u.bh.block_total_length; - } else { - pcap_queue_bytes -= queue_element->u.phdr.caplen; - } - pcap_queue_packets -= 1; - } - g_async_queue_unlock(pcap_queue); - if (queue_element) { - if (queue_element->pcap_src->from_pcapng) { - ws_info("Dequeued a block of type 0x%08x of length %d captured on interface %d.", - queue_element->u.bh.block_type, queue_element->u.bh.block_total_length, - queue_element->pcap_src->interface_id); - - capture_loop_write_pcapng_cb(queue_element->pcap_src, - &queue_element->u.bh, - queue_element->pd); - } else { - ws_info("Dequeued a packet of length %d captured on interface %d.", - queue_element->u.phdr.caplen, queue_element->pcap_src->interface_id); - - capture_loop_write_packet_cb((u_char *) queue_element->pcap_src, - &queue_element->u.phdr, - queue_element->pd); - } - g_free(queue_element->pd); - g_free(queue_element); - return TRUE; - } - return FALSE; -} - -/* - * Note: this code will never be run on any OS other than Windows. - * - * We keep the arguments in case there's something in the future - * that needs to be reported as an NPCAP bug. - */ -static char * -handle_npcap_bug(char *adapter_name _U_, char *cap_err_str _U_) -{ - gboolean have_npcap = FALSE; - -#ifdef _WIN32 - have_npcap = caplibs_have_npcap(); -#endif - - if (!have_npcap) { - /* - * We're not using Npcap, so don't recomment a user - * file a bug against Npcap. - */ - return g_strdup(""); - } - - return ws_strdup_printf("If you have not removed that adapter, this " - "is probably a known issue in Npcap resulting from " - "the behavior of the Windows networking stack. " - "Work is being done in Npcap to improve the " - "handling of this issue; it does not need to " - "be reported as a Wireshark or Npcap bug."); -} - -/* Do the low-level work of a capture. - Returns TRUE if it succeeds, FALSE otherwise. */ -static gboolean -capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats) -{ -#ifdef _WIN32 - DWORD upd_time, cur_time; /* GetTickCount() returns a "DWORD" (which is 'unsigned long') */ -#else - struct timeval upd_time, cur_time; -#endif - int err_close; - int inpkts; - GTimer *autostop_duration_timer = NULL; - gboolean write_ok; - gboolean close_ok; - gboolean cfilter_error = FALSE; - char errmsg[MSG_MAX_LENGTH+1]; - char secondary_errmsg[MSG_MAX_LENGTH+1]; - capture_src *pcap_src; - interface_options *interface_opts; - guint i, error_index = 0; - - *errmsg = '\0'; - *secondary_errmsg = '\0'; - - /* init the loop data */ - global_ld.go = TRUE; - global_ld.packets_captured = 0; -#ifdef SIGINFO - global_ld.report_packet_count = FALSE; -#endif - global_ld.inpkts_to_sync_pipe = 0; - global_ld.err = 0; /* no error seen yet */ - global_ld.pdh = NULL; - global_ld.save_file_fd = -1; - global_ld.io_buffer = NULL; - global_ld.file_count = 0; - global_ld.file_duration_timer = NULL; - global_ld.next_interval_time = 0; - global_ld.interval_s = 0; - - /* We haven't yet gotten the capture statistics. */ - *stats_known = FALSE; - - ws_info("Capture loop starting ..."); - capture_opts_log(LOG_DOMAIN_CAPCHILD, LOG_LEVEL_DEBUG, capture_opts); - - /* open the "input file" from network interface or capture pipe */ - if (!capture_loop_open_input(capture_opts, &global_ld, errmsg, sizeof(errmsg), - secondary_errmsg, sizeof(secondary_errmsg))) { - goto error; - } - for (i = 0; i < capture_opts->ifaces->len; i++) { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, 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) */ - /* - * When remote capturing WinPCap crashes when the capture filter - * is NULL. This might be a bug in WPCap. Therefore we provide an empty - * string. - */ - switch (capture_loop_init_filter(pcap_src->pcap_h, pcap_src->from_cap_pipe, - interface_opts->name, - interface_opts->cfilter?interface_opts->cfilter:"")) { - - case INITFILTER_NO_ERROR: - break; - - case INITFILTER_BAD_FILTER: - cfilter_error = TRUE; - error_index = i; - snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(pcap_src->pcap_h)); - goto error; - - case INITFILTER_OTHER_ERROR: - snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).", - pcap_geterr(pcap_src->pcap_h)); - snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report_bug()); - goto error; - } - } - - /* If we're supposed to write to a capture file, open it for output - (temporary/specified name/ringbuffer) */ - if (capture_opts->saving_to_file) { - if (!capture_loop_open_output(capture_opts, &global_ld.save_file_fd, - errmsg, sizeof(errmsg))) { - goto error; - } - - /* set up to write to the already-opened capture output file/files */ - if (!capture_loop_init_output(capture_opts, &global_ld, errmsg, - sizeof(errmsg))) { - goto error; - } - - /* XXX - capture SIGTERM and close the capture, in case we're on a - Linux 2.0[.x] system and you have to explicitly close the capture - stream in order to turn promiscuous mode off? We need to do that - in other places as well - and I don't think that works all the - time in any case, due to libpcap bugs. */ - - /* Well, we should be able to start capturing. - - Sync out the capture file, so the header makes it to the file system, - and send a "capture started successfully and capture file created" - message to our parent so that they'll open the capture file and - update its windows to indicate that we have a live capture in - progress. */ - fflush(global_ld.pdh); - report_new_capture_file(capture_opts->save_file); - } - - if (capture_opts->has_file_interval) { - global_ld.interval_s = capture_opts->file_interval; - global_ld.next_interval_time = get_next_time_interval(global_ld.interval_s); - } - /* create stop conditions */ - if (capture_opts->has_autostop_filesize) { - if (capture_opts->autostop_filesize > (((guint32)INT_MAX + 1) / 1000)) { - capture_opts->autostop_filesize = ((guint32)INT_MAX + 1) / 1000; - } - } - if (capture_opts->has_autostop_duration) { - autostop_duration_timer = g_timer_new(); - } - - if (capture_opts->multi_files_on) { - if (capture_opts->has_file_duration) { - global_ld.file_duration_timer = g_timer_new(); - } - } - - /* init the time values */ -#ifdef _WIN32 - upd_time = GetTickCount(); -#else - gettimeofday(&upd_time, NULL); -#endif - start_time = create_timestamp(); - ws_info("Capture loop running."); - capture_opts_log(LOG_DOMAIN_CAPCHILD, LOG_LEVEL_DEBUG, capture_opts); - - /* WOW, everything is prepared! */ - /* 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++) { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, i); - /* XXX - Add an interface name here? */ - pcap_src->tid = g_thread_new("Capture read", pcap_read_handler, pcap_src); - } - } - while (global_ld.go) { - /* dispatch incoming packets */ - if (use_threads) { - gboolean dequeued = capture_loop_dequeue_packet(); - - if (dequeued) { - inpkts = 1; - } else { - inpkts = 0; - } - } else { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, 0); - inpkts = capture_loop_dispatch(&global_ld, errmsg, - sizeof(errmsg), pcap_src); - } - if (inpkts == 0) { - /* Stop capturing if all of our sources are pipes and none of them are open. */ - gboolean open_interfaces = FALSE; - for (i = 0; i < global_ld.pcaps->len; i++) { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, i); - if (pcap_src->cap_pipe_err == PIPOK) { - /* True for both non-pipes and open pipes. */ - open_interfaces = TRUE; - } - } - if (!open_interfaces) { - global_ld.go = FALSE; - } - } -#ifdef SIGINFO - /* Were we asked to print packet counts by the SIGINFO handler? */ - if (global_ld.report_packet_count) { - fprintf(stderr, "%u packet%s captured\n", global_ld.packets_captured, - plurality(global_ld.packets_captured, "", "s")); - global_ld.report_packet_count = FALSE; - } -#endif - -#ifdef _WIN32 - /* any news from our parent (signal pipe)? -> just stop the capture */ - if (!signal_pipe_check_running()) { - global_ld.go = FALSE; - } -#endif - - if (inpkts > 0) { - if (capture_opts->output_to_pipe) { - fflush(global_ld.pdh); - } - } /* inpkts */ - - /* Only update after an interval so as not to overload slow displays. - * This also prevents too much context-switching between the dumpcap - * and wireshark processes. - * XXX: Should we send updates sooner if there have been lots of - * packets we haven't notified the parent about, such as on fast links? - */ -#ifdef _WIN32 - cur_time = GetTickCount(); /* Note: wraps to 0 if sys runs for 49.7 days */ - if ((cur_time - upd_time) > capture_opts->update_interval) /* wrap just causes an extra update */ -#else - gettimeofday(&cur_time, NULL); - if (((guint64)cur_time.tv_sec * 1000000 + cur_time.tv_usec) > - ((guint64)upd_time.tv_sec * 1000000 + upd_time.tv_usec + capture_opts->update_interval*1000)) -#endif - { - - upd_time = cur_time; - -#if 0 - if (pcap_stats(pch, stats) >= 0) { - *stats_known = TRUE; - } -#endif - /* Let the parent process know. */ - if (global_ld.inpkts_to_sync_pipe) { - /* do sync here */ - fflush(global_ld.pdh); - - /* Send our parent a message saying we've written out - "global_ld.inpkts_to_sync_pipe" packets to the capture file. */ - if (!quiet) - report_packet_count(global_ld.inpkts_to_sync_pipe); - - global_ld.inpkts_to_sync_pipe = 0; - } - - /* check capture duration condition */ - if (autostop_duration_timer != NULL && g_timer_elapsed(autostop_duration_timer, NULL) >= capture_opts->autostop_duration) { - /* The maximum capture time has elapsed; stop the capture. */ - global_ld.go = FALSE; - continue; - } - - /* check capture file duration condition */ - if (global_ld.file_duration_timer != NULL && g_timer_elapsed(global_ld.file_duration_timer, NULL) >= capture_opts->file_duration) { - /* duration limit reached, do we have another file? */ - if (!do_file_switch_or_stop(capture_opts)) - continue; - } /* cnd_file_duration */ - - /* check capture file interval condition */ - if (global_ld.interval_s && time(NULL) >= global_ld.next_interval_time) { - /* end of interval reached, do we have another file? */ - if (!do_file_switch_or_stop(capture_opts)) - continue; - } /* cnd_file_interval */ - } - } - - ws_info("Capture loop stopping ..."); - if (use_threads) { - - for (i = 0; i < global_ld.pcaps->len; i++) { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, i); - ws_info("Waiting for thread of interface %u...", pcap_src->interface_id); - g_thread_join(pcap_src->tid); - ws_info("Thread of interface %u terminated.", pcap_src->interface_id); - } - while (1) { - gboolean dequeued = capture_loop_dequeue_packet(); - if (!dequeued) { - break; - } - if (capture_opts->output_to_pipe) { - fflush(global_ld.pdh); - } - } - } - - - /* delete stop conditions */ - if (global_ld.file_duration_timer != NULL) - g_timer_destroy(global_ld.file_duration_timer); - if (autostop_duration_timer != NULL) - g_timer_destroy(autostop_duration_timer); - - /* did we have a pcap (input) error? */ - for (i = 0; i < capture_opts->ifaces->len; i++) { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, i); - if (pcap_src->pcap_err) { - /* On Linux, if an interface goes down while you're capturing on it, - you'll get "recvfrom: Network is down". - (At least you will if g_strerror() doesn't show a local translation - of the error.) - - Newer versions of libpcap maps that to just - "The interface went down". - - On FreeBSD, DragonFly BSD, and macOS, if a network adapter - disappears while you're capturing on it, you'll get - "read: Device not configured" error (ENXIO). (See previous - parenthetical note.) - - On OpenBSD, you get "read: I/O error" (EIO) in the same case. - - With WinPcap and Npcap, you'll get - "read error: PacketReceivePacket failed" or - "PacketReceivePacket error: The device has been removed. (1617)". - - Newer versions of libpcap map some or all of those to just - "The interface disappeared" or something beginning with - "The interface disappeared". - - These should *not* be reported to the Wireshark developers, - although, with Npcap, "The interface disappeared" messages - should perhaps be reported to the Npcap developers, at least - until errors of that sort that shouldn't happen are fixed, - if that's possible. */ - char *cap_err_str; - char *primary_msg; - char *secondary_msg; - - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i); - cap_err_str = pcap_geterr(pcap_src->pcap_h); - if (strcmp(cap_err_str, "The interface went down") == 0 || - strcmp(cap_err_str, "recvfrom: Network is down") == 0) { - primary_msg = ws_strdup_printf("The network adapter \"%s\" " - "is no longer running; the " - "capture has stopped.", - interface_opts->display_name); - secondary_msg = g_strdup(""); - } else if (strcmp(cap_err_str, "The interface disappeared") == 0 || - strcmp(cap_err_str, "read: Device not configured") == 0 || - strcmp(cap_err_str, "read: I/O error") == 0 || - strcmp(cap_err_str, "read error: PacketReceivePacket failed") == 0) { - primary_msg = ws_strdup_printf("The network adapter \"%s\" " - "is no longer attached; the " - "capture has stopped.", - interface_opts->display_name); - secondary_msg = g_strdup(""); - } else if (g_str_has_prefix(cap_err_str, "The interface disappeared ")) { - /* - * Npcap, if it picks up a recent commit to libpcap, will - * report an error *beginning* with "The interface - * disappeared", with the name of the Windows status code, - * and the corresponding NT status code, after it. - * - * Those should be reported as Npcap issues. - */ - primary_msg = ws_strdup_printf("The network adapter \"%s\" " - "is no longer attached; the " - "capture has stopped.", - interface_opts->display_name); - secondary_msg = handle_npcap_bug(interface_opts->display_name, - cap_err_str); - } else if (g_str_has_prefix(cap_err_str, "PacketReceivePacket error:") && - g_str_has_suffix(cap_err_str, "(1617)")) { - /* - * "PacketReceivePacket error: {message in arbitrary language} (1617)", - * which is ERROR_DEVICE_REMOVED. - * - * Current libpcap/Npcap treat ERROR_GEN_FAILURE as - * "the device is no longer attached"; users are also - * getting ERROR_DEVICE_REMOVED. - * - * For now, some users appear to be getg ERROR_DEVICE_REMOVED - * in cases where the device *wasn't* removed, so tell - * them to report this as an Npcap issue; I seem to - * remember some discussion between Daniel and somebody - * at Microsoft about the Windows 10 network stack setup/ - * teardown code being modified to try to prevent those - * sort of problems popping up, but I can't find that - * discussion. - */ - primary_msg = ws_strdup_printf("The network adapter \"%s\" " - "is no longer attached; the " - "capture has stopped.", - interface_opts->display_name); - secondary_msg = handle_npcap_bug(interface_opts->display_name, - "The interface disappeared (error code ERROR_DEVICE_REMOVED/STATUS_DEVICE_REMOVED)"); - } else if (strcmp(cap_err_str, "The other host terminated the connection.") == 0 || - g_str_has_prefix(cap_err_str, "Is the server properly installed?")) { - /* - * Networking error for a remote capture. - */ - primary_msg = g_strdup(cap_err_str); - secondary_msg = g_strdup("This may be a problem with the " - "remote host on which you are " - "capturing packets."); - } else { - primary_msg = ws_strdup_printf("Error while capturing packets: %s", - cap_err_str); - secondary_msg = g_strdup(please_report_bug()); - } - report_capture_error(primary_msg, secondary_msg); - g_free(primary_msg); - g_free(secondary_msg); - break; - } else if (pcap_src->from_cap_pipe && pcap_src->cap_pipe_err == PIPERR) { - report_capture_error(errmsg, ""); - break; - } - } - /* did we have an output error while capturing? */ - if (global_ld.err == 0) { - write_ok = TRUE; - } else { - capture_loop_get_errmsg(errmsg, sizeof(errmsg), secondary_errmsg, - sizeof(secondary_errmsg), - capture_opts->save_file, global_ld.err, FALSE); - report_capture_error(errmsg, secondary_errmsg); - write_ok = FALSE; - } - - if (capture_opts->saving_to_file) { - /* close the output file */ - close_ok = capture_loop_close_output(capture_opts, &global_ld, &err_close); - } else - close_ok = TRUE; - - /* there might be packets not yet notified to the parent */ - /* (do this after closing the file, so all packets are already flushed) */ - if (global_ld.inpkts_to_sync_pipe) { - if (!quiet) - report_packet_count(global_ld.inpkts_to_sync_pipe); - global_ld.inpkts_to_sync_pipe = 0; - } - - /* If we've displayed a message about a write error, there's no point - in displaying another message about an error on close. */ - if (!close_ok && write_ok) { - capture_loop_get_errmsg(errmsg, sizeof(errmsg), secondary_errmsg, - sizeof(secondary_errmsg), - capture_opts->save_file, err_close, TRUE); - report_capture_error(errmsg, secondary_errmsg); - } - - /* - * XXX We exhibit different behaviour between normal mode and sync mode - * when the pipe is stdin and not already at EOF. If we're a child, the - * parent's stdin isn't closed, so if the user starts another capture, - * cap_pipe_open_live() will very likely not see the expected magic bytes and - * will say "Unrecognized libpcap format". On the other hand, in normal - * mode, cap_pipe_open_live() will say "End of file on pipe during open". - */ - - report_capture_count(TRUE); - - /* get packet drop statistics from pcap */ - for (i = 0; i < capture_opts->ifaces->len; i++) { - guint32 received; - guint32 pcap_dropped = 0; - - pcap_src = g_array_index(global_ld.pcaps, capture_src *, i); - interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i); - received = pcap_src->received; - if (pcap_src->pcap_h != NULL) { - ws_assert(!pcap_src->from_cap_pipe); - /* Get the capture statistics, so we know how many packets were dropped. */ - if (pcap_stats(pcap_src->pcap_h, stats) >= 0) { - *stats_known = TRUE; - /* Let the parent process know. */ - pcap_dropped += stats->ps_drop; - } else { - snprintf(errmsg, sizeof(errmsg), - "Can't get packet-drop statistics: %s", - pcap_geterr(pcap_src->pcap_h)); - report_capture_error(errmsg, please_report_bug()); - } - } - report_packet_drops(received, pcap_dropped, pcap_src->dropped, pcap_src->flushed, stats->ps_ifdrop, interface_opts->display_name); - } - - /* close the input file (pcap or capture pipe) */ - capture_loop_close_input(&global_ld); - - ws_info("Capture loop stopped."); - - /* ok, if the write and the close were successful. */ - return write_ok && close_ok; - -error: - if (capture_opts->multi_files_on) { - /* cleanup ringbuffer */ - ringbuf_error_cleanup(); - } else { - /* We can't use the save file, and we have no FILE * for the stream - to close in order to close it, so close the FD directly. */ - if (global_ld.save_file_fd != -1) { - ws_close(global_ld.save_file_fd); - } - - /* We couldn't even start the capture, so get rid of the capture - file. */ - if (capture_opts->save_file != NULL) { - ws_unlink(capture_opts->save_file); - } - } - if (cfilter_error) - report_cfilter_error(capture_opts, error_index, errmsg); - else - report_capture_error(errmsg, secondary_errmsg); - - /* close the input file (pcap or cap_pipe) */ - capture_loop_close_input(&global_ld); - - ws_info("Capture loop stopped with error"); - - return FALSE; -} - - -static void -capture_loop_stop(void) -{ - guint i; - capture_src *pcap_src; - - for (i = 0; i < global_ld.pcaps->len; i++) { - pcap_src = g_array_index(global_ld.pcaps, capture_src *, i); - if (pcap_src->pcap_h != NULL) - pcap_breakloop(pcap_src->pcap_h); - } - global_ld.go = FALSE; -} - - -static void -capture_loop_get_errmsg(char *errmsg, size_t errmsglen, char *secondary_errmsg, - size_t secondary_errmsglen, const char *fname, - int err, gboolean is_close) -{ - static const char find_space[] = - "You will need to free up space on that file system" - " or put the capture file on a different file system."; - - switch (err) { - - case ENOSPC: - snprintf(errmsg, errmsglen, - "Not all the packets could be written to the file" - " to which the capture was being saved\n" - "(\"%s\") because there is no space left on the file system\n" - "on which that file resides.", - fname); - snprintf(secondary_errmsg, secondary_errmsglen, "%s", find_space); - break; - -#ifdef EDQUOT - case EDQUOT: - snprintf(errmsg, errmsglen, - "Not all the packets could be written to the file" - " to which the capture was being saved\n" - "(\"%s\") because you are too close to, or over," - " your disk quota\n" - "on the file system on which that file resides.", - fname); - snprintf(secondary_errmsg, secondary_errmsglen, "%s", find_space); - break; -#endif - - default: - if (is_close) { - snprintf(errmsg, errmsglen, - "The file to which the capture was being saved\n" - "(\"%s\") could not be closed: %s.", - fname, g_strerror(err)); - } else { - snprintf(errmsg, errmsglen, - "An error occurred while writing to the file" - " to which the capture was being saved\n" - "(\"%s\"): %s.", - fname, g_strerror(err)); - } - snprintf(secondary_errmsg, secondary_errmsglen, - "%s", please_report_bug()); - break; - } -} - -/* - * We wrote one packet. Update some statistics and check if we've met any - * autostop or ring buffer conditions. - */ -static void -capture_loop_wrote_one_packet(capture_src *pcap_src) { - global_ld.packets_captured++; - global_ld.packets_written++; - global_ld.inpkts_to_sync_pipe++; - - if (!use_threads) { - pcap_src->received++; - } - - /* check -c NUM */ - if (global_capture_opts.has_autostop_packets && global_ld.packets_captured >= global_capture_opts.autostop_packets) { - fflush(global_ld.pdh); - global_ld.go = FALSE; - return; - } - /* check -a packets:NUM (treat like -c NUM) */ - if (global_capture_opts.has_autostop_written_packets && global_ld.packets_captured >= global_capture_opts.autostop_written_packets) { - fflush(global_ld.pdh); - global_ld.go = FALSE; - return; - } - /* check -b packets:NUM */ - if (global_capture_opts.has_file_packets && global_ld.packets_written >= global_capture_opts.file_packets) { - do_file_switch_or_stop(&global_capture_opts); - return; - } - /* check -a filesize:NUM */ - if (global_capture_opts.has_autostop_filesize && - global_capture_opts.autostop_filesize > 0 && - global_ld.bytes_written / 1000 >= global_capture_opts.autostop_filesize) { - /* Capture size limit reached, do we have another file? */ - do_file_switch_or_stop(&global_capture_opts); - return; - } -} - -/* one pcapng block was captured, process it */ -static void -capture_loop_write_pcapng_cb(capture_src *pcap_src, const pcapng_block_header_t *bh, u_char *pd) -{ - int err; - - /* - * This should never be called if we're not writing pcapng. - */ - ws_assert(global_capture_opts.use_pcapng); - - /* 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) { - pcap_src->flushed++; - return; - } - - if (!pcapng_adjust_block(pcap_src, bh, pd)) { - ws_info("%s failed to adjust pcapng block.", G_STRFUNC); - ws_assert_not_reached(); - return; - } - - if (bh->block_type == BLOCK_TYPE_SHB && !global_ld.pcapng_passthrough) { - /* - * capture_loop_init_pcapng_output should've handled this. We need - * to write ISBs when they're initially read so we shouldn't skip - * them here. - */ - return; - } - - if (global_ld.pdh) { - gboolean successful; - - /* We're supposed to write the packet to a file; do so. - If this fails, set "ld->go" to FALSE, to stop the capture, and set - "ld->err" to the error. */ - successful = pcapng_write_block(global_ld.pdh, - pd, - bh->block_total_length, - &global_ld.bytes_written, &err); - - fflush(global_ld.pdh); - if (!successful) { - global_ld.go = FALSE; - global_ld.err = err; - pcap_src->dropped++; - } else if (bh->block_type == BLOCK_TYPE_EPB || bh->block_type == BLOCK_TYPE_SPB || bh->block_type == BLOCK_TYPE_SYSTEMD_JOURNAL_EXPORT || bh->block_type == BLOCK_TYPE_SYSDIG_EVENT || bh->block_type == BLOCK_TYPE_SYSDIG_EVENT_V2 || bh->block_type == BLOCK_TYPE_SYSDIG_EVENT_V2_LARGE) { - /* Count packets for block types that should be dissected, i.e. ones that show up in the packet list. */ -#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP) - ws_info("Wrote a pcapng block type %u of length %d captured on interface %u.", - bh->block_type, bh->block_total_length, pcap_src->interface_id); -#endif - capture_loop_wrote_one_packet(pcap_src); - } else if (bh->block_type == BLOCK_TYPE_SHB && report_capture_filename) { -#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP) - ws_info("Sending SP_FILE on first SHB"); -#endif - /* SHB is now ready for capture parent to read on SP_FILE message */ - sync_pipe_write_string_msg(2, SP_FILE, report_capture_filename); - report_capture_filename = NULL; - } - } -} - -/* one pcap packet was captured, process it */ -static void -capture_loop_write_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr, - const u_char *pd) -{ - capture_src *pcap_src = (capture_src *) (void *) pcap_src_p; - int err; - guint ts_mul = pcap_src->ts_nsec ? 1000000000 : 1000000; - - ws_debug("capture_loop_write_packet_cb"); - - /* 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) { - pcap_src->flushed++; - return; - } - - if (global_ld.pdh) { - gboolean successful; - - /* We're supposed to write the packet to a file; do so. - 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 = pcapng_write_enhanced_packet_block(global_ld.pdh, - NULL, - phdr->ts.tv_sec, (gint32)phdr->ts.tv_usec, - phdr->caplen, phdr->len, - pcap_src->idb_id, - ts_mul, - pd, 0, - &global_ld.bytes_written, &err); - } else { - successful = libpcap_write_packet(global_ld.pdh, - phdr->ts.tv_sec, (gint32)phdr->ts.tv_usec, - phdr->caplen, phdr->len, - pd, - &global_ld.bytes_written, &err); - } - if (!successful) { - global_ld.go = FALSE; - global_ld.err = err; - pcap_src->dropped++; - } else { -#if defined(DEBUG_DUMPCAP) || defined(DEBUG_CHILD_DUMPCAP) - ws_info("Wrote a pcap packet of length %d captured on interface %u.", - phdr->caplen, pcap_src->interface_id); -#endif - capture_loop_wrote_one_packet(pcap_src); - } - } -} - -/* one packet was captured, queue it */ -static void -capture_loop_queue_packet_cb(u_char *pcap_src_p, const struct pcap_pkthdr *phdr, - const u_char *pd) -{ - capture_src *pcap_src = (capture_src *) (void *) pcap_src_p; - pcap_queue_element *queue_element; - 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 - supposed to be saving any more packets. */ - if (!global_ld.go) { - pcap_src->flushed++; - return; - } - - queue_element = g_new(pcap_queue_element, 1); - if (queue_element == NULL) { - pcap_src->dropped++; - return; - } - queue_element->pcap_src = pcap_src; - queue_element->u.phdr = *phdr; - queue_element->pd = (u_char *)g_malloc(phdr->caplen); - if (queue_element->pd == NULL) { - pcap_src->dropped++; - g_free(queue_element); - return; - } - memcpy(queue_element->pd, pd, phdr->caplen); - 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_src->dropped++; - g_free(queue_element->pd); - g_free(queue_element); - ws_info("Dropped a packet of length %d captured on interface %u.", - phdr->caplen, pcap_src->interface_id); - } else { - pcap_src->received++; - ws_info("Queued a packet of length %d captured on interface %u.", - phdr->caplen, pcap_src->interface_id); - } - /* I don't want to hold the mutex over the debug output. So the - output may be wrong */ - ws_info("Queue size is now %" PRId64 " bytes (%" PRId64 " packets)", - pcap_queue_bytes, pcap_queue_packets); -} - -/* one pcapng block was captured, queue it */ -static void -capture_loop_queue_pcapng_cb(capture_src *pcap_src, const pcapng_block_header_t *bh, u_char *pd) -{ - pcap_queue_element *queue_element; - 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 - supposed to be saving any more packets. */ - if (!global_ld.go) { - pcap_src->flushed++; - return; - } - - queue_element = g_new(pcap_queue_element, 1); - if (queue_element == NULL) { - pcap_src->dropped++; - return; - } - queue_element->pcap_src = pcap_src; - queue_element->u.bh = *bh; - queue_element->pd = (u_char *)g_malloc(bh->block_total_length); - if (queue_element->pd == NULL) { - pcap_src->dropped++; - g_free(queue_element); - return; - } - memcpy(queue_element->pd, pd, bh->block_total_length); - 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 += bh->block_total_length; - pcap_queue_packets += 1; - } else { - limit_reached = TRUE; - } - g_async_queue_unlock(pcap_queue); - if (limit_reached) { - pcap_src->dropped++; - g_free(queue_element->pd); - g_free(queue_element); - ws_info("Dropped a packet of length %d captured on interface %u.", - bh->block_total_length, pcap_src->interface_id); - } else { - pcap_src->received++; - ws_info("Queued a block of type 0x%08x of length %d captured on interface %u.", - bh->block_type, bh->block_total_length, pcap_src->interface_id); - } - /* I don't want to hold the mutex over the debug output. So the - output may be wrong */ - ws_info("Queue size is now %" PRId64 " bytes (%" PRId64 " packets)", - pcap_queue_bytes, pcap_queue_packets); -} - -static int -set_80211_channel(const char *iface, const char *opt) -{ - guint32 freq = 0; - int type = -1; - guint32 center_freq1 = 0; - guint32 center_freq2 = 0; - int args; - int ret = 0; - gchar **options = NULL; - - options = g_strsplit_set(opt, ",", 4); - for (args = 0; options[args]; args++) - ; - - ret = ws80211_init(); - if (ret != WS80211_INIT_OK) { - if (ret == WS80211_INIT_NOT_SUPPORTED) - cmdarg_err("Setting 802.11 channels is not supported on this platform"); - else - cmdarg_err("Failed to init ws80211: %s", g_strerror(abs(ret))); - ret = 2; - goto out; - } - - if (options[0]) - freq = get_nonzero_guint32(options[0], "802.11 channel frequency"); - - if (args >= 1 && options[1]) { - type = ws80211_str_to_chan_type(options[1]); - if (type == -1) { - cmdarg_err("\"%s\" is not a valid 802.11 channel type", options[1]); - ret = EINVAL; - goto out; - } - } - - if (args >= 2 && options[2]) - center_freq1 = get_nonzero_guint32(options[2], "VHT center frequency"); - - if (args >= 3 && options[3]) - center_freq2 = get_nonzero_guint32(options[3], "VHT center frequency 2"); - - ret = ws80211_set_freq(iface, freq, type, center_freq1, center_freq2); - - if (ret) { - cmdarg_err("%d: Failed to set channel: %s\n", abs(ret), g_strerror(abs(ret))); - ret = 2; - goto out; - } - - if (capture_child) - sync_pipe_write_string_msg(2, SP_SUCCESS, NULL); - -out: - g_strfreev(options); - return ret; -} - -static void -gather_dumpcap_compiled_info(feature_list l) -{ - /* Capture libraries */ - gather_caplibs_compile_info(l); -} - -static void -gather_dumpcap_runtime_info(feature_list l) -{ - /* Capture libraries */ - gather_caplibs_runtime_info(l); -} - -#define LONGOPT_IFNAME LONGOPT_BASE_APPLICATION+1 -#define LONGOPT_IFDESCR LONGOPT_BASE_APPLICATION+2 -#define LONGOPT_CAPTURE_COMMENT LONGOPT_BASE_APPLICATION+3 - -/* And now our feature presentation... [ fade to music ] */ -int -main(int argc, char *argv[]) -{ - char *err_msg; - int opt; - static const struct ws_option long_options[] = { - {"help", ws_no_argument, NULL, 'h'}, - {"version", ws_no_argument, NULL, 'v'}, - LONGOPT_CAPTURE_COMMON - {"ifname", ws_required_argument, NULL, LONGOPT_IFNAME}, - {"ifdescr", ws_required_argument, NULL, LONGOPT_IFDESCR}, - {"capture-comment", ws_required_argument, NULL, LONGOPT_CAPTURE_COMMENT}, - {0, 0, 0, 0 } - }; - - gboolean arg_error = FALSE; - -#ifndef _WIN32 - struct sigaction action, oldaction; -#endif - - gboolean stats_known; - struct pcap_stat stats = {0}; - gboolean list_interfaces = FALSE; - int caps_queries = 0; - gboolean print_bpf_code = FALSE; - gboolean set_chan = FALSE; - gchar *set_chan_arg = NULL; - gboolean machine_readable = FALSE; - gboolean print_statistics = FALSE; - int status, run_once_args = 0; - gint i; - guint j; -#if defined(__APPLE__) && defined(__LP64__) - struct utsname osinfo; -#endif - GString *str; - - /* - * Determine if dumpcap is being requested to run in a special - * capture_child mode by going thru the command line args to see if - * a -Z is present. (-Z is a hidden option). - * - * The primary result of running in capture_child mode is that - * all messages sent out on stderr are in a special type/len/string - * format to allow message processing by type. These messages include - * error messages if dumpcap fails to start the operation it was - * requested to do, as well as various "status" messages which are sent - * when an actual capture is in progress, and a "success" message sent - * if dumpcap was requested to perform an operation other than a - * capture. - * - * Capture_child mode would normally be requested by a parent process - * which invokes dumpcap and obtains dumpcap stderr output via a pipe - * to which dumpcap stderr has been redirected. It might also have - * another pipe to obtain dumpcap stdout output; for operations other - * than a capture, that information is formatted specially for easier - * parsing by the parent process. - * - * Capture_child mode needs to be determined immediately upon - * startup so that any messages generated by dumpcap in this mode - * (eg: during initialization) will be formatted properly. - */ - - for (i=1; i