3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * Rawshark - Raw field extractor by Gerald Combs <gerald@wireshark.org>
8 * and Loris Degioanni <loris.degioanni@cacetech.com>
9 * Based on TShark, by Gilbert Ramirez <gram@alumni.rice.edu> and Guy Harris
12 * SPDX-License-Identifier: GPL-2.0-or-later
16 * Rawshark does the following:
17 * - Opens a specified file or named pipe
18 * - Applies a specified DLT or "decode as" encapsulation
19 * - Reads frames prepended with a libpcap packet header.
20 * - Prints a status line, followed by fields from a specified list.
24 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
34 #include <sys/resource.h>
39 #include <ws_exit_codes.h>
40 #include <wsutil/ws_getopt.h>
43 #include <epan/epan.h>
45 #include <wsutil/cmdarg_err.h>
46 #include <wsutil/filesystem.h>
47 #include <wsutil/file_util.h>
48 #include <wsutil/socket.h>
49 #include <wsutil/plugins.h>
50 #include <wsutil/privileges.h>
51 #include <wsutil/report_message.h>
52 #include <wsutil/please_report_bug.h>
53 #include <wsutil/wslog.h>
54 #include <wsutil/clopts_common.h>
57 #include <wsutil/unicode-utils.h>
58 #include <wsutil/win32-utils.h>
62 #include <epan/packet.h>
63 #include <epan/ftypes/ftypes.h>
65 #include "frame_tvbuff.h"
66 #include <epan/disabled_protos.h>
67 #include <epan/prefs.h>
68 #include <epan/column.h>
69 #include <epan/print.h>
70 #include <epan/addr_resolv.h>
72 #include "ui/capture_ui_utils.h"
75 #include "ui/dissect_opts.h"
76 #include "ui/failure_message.h"
77 #include <epan/epan_dissect.h>
78 #include <epan/stat_tap_ui.h>
79 #include <epan/timestamp.h>
80 #include "epan/column-utils.h"
81 #include "epan/proto.h"
84 #include <wiretap/wtap.h>
85 #include <wiretap/libpcap.h>
86 #include <wiretap/pcap-encap.h>
89 #include <wsutil/version_info.h>
91 #include "capture/capture-pcap-util.h"
96 #include "capture/capture-wpcap.h"
98 #endif /* HAVE_LIBPCAP */
102 * This is the template for the decode as option; it is shared between the
103 * various functions that output the usage for this parameter.
105 static const char decode_as_arg_template
[] = "<layer_type>==<selector>,<decode_as_protocol>";
108 /* Additional exit codes */
109 #define INVALID_DFILTER 2
110 #define FORMAT_ERROR 2
114 static uint32_t cum_bytes
;
115 static frame_data ref_frame
;
116 static frame_data prev_dis_frame
;
117 static frame_data prev_cap_frame
;
120 * The way the packet decode is to be written.
123 WRITE_TEXT
, /* summary or detail text */
124 WRITE_XML
/* PDML or PSML */
125 /* Add CSV and the like here */
128 static bool line_buffered
;
129 static print_format_e print_format
= PR_FMT_TEXT
;
131 static bool want_pcap_pkthdr
;
133 cf_status_t
raw_cf_open(capture_file
*cf
, const char *fname
);
134 static bool load_cap_file(capture_file
*cf
);
135 static bool process_packet(capture_file
*cf
, epan_dissect_t
*edt
, int64_t offset
,
136 wtap_rec
*rec
, Buffer
*buf
);
137 static void show_print_file_io_error(int err
);
139 static void rawshark_cmdarg_err(const char *fmt
, va_list ap
);
140 static void rawshark_cmdarg_err_cont(const char *fmt
, va_list ap
);
141 static void protocolinfo_init(char *field
);
142 static bool parse_field_string_format(char *format
);
145 SF_NONE
, /* No format (placeholder) */
146 SF_NAME
, /* %D Field name / description */
147 SF_NUMVAL
, /* %N Numeric value */
148 SF_STRVAL
/* %S String value */
151 typedef struct string_fmt_s
{
153 string_fmt_e format
; /* Valid if plain is NULL */
158 dfilter_t
*rfcodes
[64];
160 dfilter_t
*rfieldfcodes
[64];
163 GPtrArray
*string_fmts
;
166 print_usage(FILE *output
)
168 fprintf(output
, "\n");
169 fprintf(output
, "Usage: rawshark [options] ...\n");
170 fprintf(output
, "\n");
172 fprintf(output
, "Input file:\n");
173 fprintf(output
, " -r <infile>, --read-file <infile>\n");
174 fprintf(output
," set the pipe or file name to read from\n");
176 fprintf(output
, "\n");
177 fprintf(output
, "Processing:\n");
178 fprintf(output
, " -d <encap:linktype>|<proto:protoname>\n");
179 fprintf(output
, " packet encapsulation or protocol\n");
180 fprintf(output
, " -F <field> field to display\n");
181 #if !defined(_WIN32) && defined(RLIMIT_AS)
182 fprintf(output
, " -m virtual memory limit, in bytes\n");
184 fprintf(output
, " -n disable all name resolutions (def: \"mNd\" enabled, or\n");
185 fprintf(output
, " as set in preferences)\n");
186 fprintf(output
, " -N <name resolve flags> enable specific name resolution(s): \"mnNtdv\"\n");
187 fprintf(output
, " -p use the system's packet header format\n");
188 fprintf(output
, " (which may have 64-bit timestamps)\n");
189 fprintf(output
, " -R <read filter>, --read-filter <read filter>\n");
190 fprintf(output
, " packet filter in Wireshark display filter syntax\n");
191 fprintf(output
, " -s skip PCAP header on input\n");
192 fprintf(output
, " -Y <display filter>, --display-filter <display filter>\n");
193 fprintf(output
, " packet filter in Wireshark display filter syntax\n");
194 fprintf(output
, " --enable-protocol <proto_name>\n");
195 fprintf(output
, " enable dissection of proto_name\n");
196 fprintf(output
, " --disable-protocol <proto_name>\n");
197 fprintf(output
, " disable dissection of proto_name\n");
198 fprintf(output
, " --only-protocols <protocols>\n");
199 fprintf(output
, " Only enable dissection of these protocols, comma\n");
200 fprintf(output
, " separated. Disable everything else\n");
201 fprintf(output
, " --disable-all-protocols\n");
202 fprintf(output
, " Disable dissection of all protocols\n");
203 fprintf(output
, " --enable-heuristic <short_name>\n");
204 fprintf(output
, " enable dissection of heuristic protocol\n");
205 fprintf(output
, " --disable-heuristic <short_name>\n");
206 fprintf(output
, " disable dissection of heuristic protocol\n");
208 fprintf(output
, "\n");
209 fprintf(output
, "Output:\n");
210 fprintf(output
, " -l flush output after each packet\n");
211 fprintf(output
, " -S format string for fields\n");
212 fprintf(output
, " (%%D - name, %%S - stringval, %%N numval)\n");
213 fprintf(output
, " -t (a|ad|adoy|d|dd|e|r|u|ud|udoy)[.[N]]|.[N]\n");
214 fprintf(output
, " output format of time stamps (def: r: rel. to first)\n");
215 fprintf(output
, " -u s|hms output format of seconds (def: s: seconds)\n");
216 fprintf(output
, "\n");
218 ws_log_print_usage(output
);
219 fprintf(output
, "\n");
221 fprintf(output
, "\n");
222 fprintf(output
, "Miscellaneous:\n");
223 fprintf(output
, " -h, --help display this help and exit\n");
224 fprintf(output
, " -v, --version display version info and exit\n");
225 fprintf(output
, " -o <name>:<value> ... override preference setting\n");
226 fprintf(output
, " -K <keytab> keytab file to use for kerberos decryption\n");
230 * Open a pipe for raw input. This is a stripped-down version of
231 * pcap_loop.c:cap_pipe_open_live().
232 * We check if "pipe_name" is "-" (stdin) or a FIFO, and open it.
233 * @param pipe_name The name of the pipe or FIFO.
234 * @return A POSIX file descriptor on success, or -1 on failure.
237 raw_pipe_open(const char *pipe_name
)
240 ws_statb64 pipe_stat
;
248 ws_log(LOG_DOMAIN_CAPCHILD
, LOG_LEVEL_DEBUG
, "open_raw_pipe: %s", pipe_name
);
251 * XXX Rawshark blocks until we return
253 if (strcmp(pipe_name
, "-") == 0) {
254 rfd
= 0; /* read from stdin */
257 * This is needed to set the stdin pipe into binary mode, otherwise
258 * CR/LF are mangled...
260 _setmode(0, _O_BINARY
);
264 if (ws_stat64(pipe_name
, &pipe_stat
) < 0) {
265 fprintf(stderr
, "rawshark: The pipe %s could not be checked: %s\n",
266 pipe_name
, g_strerror(errno
));
269 if (! S_ISFIFO(pipe_stat
.st_mode
)) {
270 if (S_ISCHR(pipe_stat
.st_mode
)) {
272 * Assume the user specified an interface on a system where
273 * interfaces are in /dev. Pretend we haven't seen it.
277 fprintf(stderr
, "rawshark: \"%s\" is neither an interface nor a pipe\n",
282 rfd
= ws_open(pipe_name
, O_RDONLY
| O_NONBLOCK
, 0000 /* no creation so don't matter */);
284 fprintf(stderr
, "rawshark: \"%s\" could not be opened: %s\n",
285 pipe_name
, g_strerror(errno
));
289 if (!win32_is_pipe_name(pipe_name
)) {
290 fprintf(stderr
, "rawshark: \"%s\" is neither an interface nor a pipe\n",
295 /* Wait for the pipe to appear */
297 hPipe
= CreateFile(utf_8to16(pipe_name
), GENERIC_READ
, 0, NULL
,
298 OPEN_EXISTING
, 0, NULL
);
300 if (hPipe
!= INVALID_HANDLE_VALUE
)
303 err
= GetLastError();
304 if (err
!= ERROR_PIPE_BUSY
) {
305 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_IGNORE_INSERTS
,
306 NULL
, err
, 0, (LPTSTR
) &err_str
, 0, NULL
);
307 fprintf(stderr
, "rawshark: \"%s\" could not be opened: %s (error %lu)\n",
308 pipe_name
, utf_16to8(err_str
), err
);
313 if (!WaitNamedPipe(utf_8to16(pipe_name
), 30 * 1000)) {
314 err
= GetLastError();
315 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_IGNORE_INSERTS
,
316 NULL
, err
, 0, (LPTSTR
) &err_str
, 0, NULL
);
317 fprintf(stderr
, "rawshark: \"%s\" could not be waited for: %s (error %lu)\n",
318 pipe_name
, utf_16to8(err_str
), err
);
324 rfd
= _open_osfhandle((intptr_t) hPipe
, _O_RDONLY
);
326 fprintf(stderr
, "rawshark: \"%s\" could not be opened: %s\n",
327 pipe_name
, g_strerror(errno
));
337 * Parse a link-type argument of the form "encap:<pcap linktype>" or
338 * "proto:<proto name>". "Pcap linktype" must be a name conforming to
339 * pcap_datalink_name_to_val() or an integer; the integer should be
340 * a LINKTYPE_ value supported by Wiretap. "Proto name" must be
341 * a protocol name, e.g. "http".
344 set_link_type(const char *lt_arg
) {
345 char *spec_ptr
= strchr(lt_arg
, ':');
349 dissector_handle_t dhandle
;
358 if (strncmp(lt_arg
, "encap:", strlen("encap:")) == 0) {
359 dlt_val
= linktype_name_to_val(spec_ptr
);
362 val
= strtol(spec_ptr
, &p
, 10);
363 if (p
== spec_ptr
|| *p
!= '\0' || errno
!= 0 || val
> INT_MAX
) {
369 * In those cases where a given link-layer header type
370 * has different LINKTYPE_ and DLT_ values, linktype_name_to_val()
371 * will return the OS's DLT_ value for that link-layer header
372 * type, not its OS-independent LINKTYPE_ value.
374 * On a given OS, wtap_pcap_encap_to_wtap_encap() should
375 * be able to map either LINKTYPE_ values or DLT_ values
376 * for the OS to the appropriate Wiretap encapsulation.
378 encap
= wtap_pcap_encap_to_wtap_encap(dlt_val
);
379 if (encap
== WTAP_ENCAP_UNKNOWN
) {
383 } else if (strncmp(lt_arg
, "proto:", strlen("proto:")) == 0) {
384 dhandle
= find_dissector(spec_ptr
);
386 encap
= WTAP_ENCAP_USER0
;
387 pref_str
= g_string_new("uat:user_dlts:");
388 /* This must match the format used in the user_dlts file */
389 g_string_append_printf(pref_str
,
390 "\"User 0 (DLT=147)\",\"%s\",\"0\",\"\",\"0\",\"\"",
392 if (prefs_set_pref(pref_str
->str
, &errmsg
) != PREFS_SET_OK
) {
393 g_string_free(pref_str
, TRUE
);
397 g_string_free(pref_str
, TRUE
);
405 main(int argc
, char *argv
[])
411 #if !defined(_WIN32) && defined(RLIMIT_AS)
415 char *pipe_name
= NULL
;
418 GPtrArray
*disp_fields
= g_ptr_array_new();
420 bool skip_pcap_header
= false;
421 int ret
= EXIT_SUCCESS
;
422 static const struct ws_option long_options
[] = {
423 {"help", ws_no_argument
, NULL
, 'h'},
424 {"version", ws_no_argument
, NULL
, 'v'},
425 LONGOPT_DISSECT_COMMON
426 LONGOPT_READ_CAPTURE_COMMON
430 #define OPTSTRING_INIT OPTSTRING_DISSECT_COMMON OPTSTRING_READ_CAPTURE_COMMON "F:hlm:o:psS:v"
432 static const char optstring
[] = OPTSTRING_INIT
;
433 static const struct report_message_routines rawshark_report_routines
= {
436 open_failure_message
,
437 read_failure_message
,
438 write_failure_message
,
439 cfile_open_failure_message
,
440 cfile_dump_open_failure_message
,
441 cfile_read_failure_message
,
442 cfile_write_failure_message
,
443 cfile_close_failure_message
447 * Set the C-language locale to the native environment and set the
448 * code page to UTF-8 on Windows.
451 setlocale(LC_ALL
, ".UTF-8");
453 setlocale(LC_ALL
, "");
456 cmdarg_err_init(rawshark_cmdarg_err
, rawshark_cmdarg_err_cont
);
458 /* Initialize log handler early so we can have proper logging during startup. */
459 ws_log_init("rawshark", vcmdarg_err
);
461 /* Early logging command-line initialization. */
462 ws_log_parse_args(&argc
, argv
, vcmdarg_err
, WS_EXIT_INVALID_OPTION
);
464 ws_noisy("Finished log init and parsing command line log arguments");
466 /* Initialize the version information. */
467 ws_init_version_info("Rawshark",
468 epan_gather_compile_info
,
472 create_app_running_mutex();
476 * Get credential information for later use.
478 init_process_policies();
481 * Clear the filters arrays
483 memset(rfilters
, 0, sizeof(rfilters
));
484 memset(rfcodes
, 0, sizeof(rfcodes
));
489 * Initialize our string format
491 string_fmts
= g_ptr_array_new();
494 * Attempt to get the pathname of the directory containing the
497 err_msg
= configuration_init(argv
[0], NULL
);
498 if (err_msg
!= NULL
) {
499 fprintf(stderr
, "rawshark: Can't get pathname of rawshark program: %s.\n",
503 init_report_message("rawshark", &rawshark_report_routines
);
505 timestamp_set_type(TS_RELATIVE
);
506 timestamp_set_precision(TS_PREC_AUTO
);
507 timestamp_set_seconds_type(TS_SECONDS_DEFAULT
);
510 * XXX - is this necessary, given that we're not reading a
511 * regular capture file, we're reading rawshark's packet
514 * If it is, note that libwiretap must be initialized before
515 * libwireshark is, so that dissection-time handlers for
516 * file-type-dependent blocks can register using the file
517 * type/subtype value for the file type.
521 /* Register all dissectors; we must do this before checking for the
522 "-G" flag, as the "-G" flag dumps information registered by the
523 dissectors, and we must do it before we read the preferences, in
524 case any dissectors register preferences. */
525 if (!epan_init(NULL
, NULL
, true)) {
526 ret
= WS_EXIT_INIT_FAILED
;
530 /* Load libwireshark settings from the current profile. */
531 prefs_p
= epan_load_settings();
534 ws_init_dll_search_path();
535 /* Load Wpcap, if possible */
539 cap_file_init(&cfile
);
541 /* Print format defaults to this. */
542 print_format
= PR_FMT_TEXT
;
544 /* Initialize our encapsulation type */
545 encap
= WTAP_ENCAP_UNKNOWN
;
547 /* Now get our args */
548 /* XXX - We should probably have an option to dump libpcap link types */
549 while ((opt
= ws_getopt_long(argc
, argv
, optstring
, long_options
, NULL
)) != -1) {
551 case 'd': /* Payload type */
552 /* XXX: This option should probably be changed so it doesn't
553 * conflict with the common dissection option for Decode As.
555 if (!set_link_type(ws_optarg
)) {
556 cmdarg_err("Invalid link type or protocol \"%s\"", ws_optarg
);
557 ret
= WS_EXIT_INVALID_OPTION
;
561 case 'F': /* Read field to display */
562 g_ptr_array_add(disp_fields
, g_strdup(ws_optarg
));
564 case 'h': /* Print help and exit */
565 show_help_header("Dump and analyze network traffic.");
569 case 'l': /* "Line-buffer" standard output */
570 /* This isn't line-buffering, strictly speaking, it's just
571 flushing the standard output after the information for
572 each packet is printed; however, that should be good
573 enough for all the purposes to which "-l" is put (and
574 is probably actually better for "-V", as it does fewer
577 See the comment in "process_packet()" for an explanation of
578 why we do that, and why we don't just use "setvbuf()" to
579 make the standard output line-buffered (short version: in
580 Windows, "line-buffered" is the same as "fully-buffered",
581 and the output buffer is only flushed when it fills up). */
582 line_buffered
= true;
584 #if !defined(_WIN32) && defined(RLIMIT_AS)
586 limit
.rlim_cur
= get_positive_int(ws_optarg
, "memory limit");
587 limit
.rlim_max
= get_positive_int(ws_optarg
, "memory limit");
589 if(setrlimit(RLIMIT_AS
, &limit
) != 0) {
590 cmdarg_err("setrlimit(RLIMIT_AS) failed: %s",
592 ret
= WS_EXIT_INVALID_OPTION
;
597 case 'o': /* Override preference from command line */
601 switch (prefs_set_pref(ws_optarg
, &errmsg
)) {
606 case PREFS_SET_SYNTAX_ERR
:
607 cmdarg_err("Invalid -o flag \"%s\"%s%s", ws_optarg
,
608 errmsg
? ": " : "", errmsg
? errmsg
: "");
610 ret
= WS_EXIT_INVALID_OPTION
;
614 case PREFS_SET_NO_SUCH_PREF
:
615 cmdarg_err("-o flag \"%s\" specifies unknown preference", ws_optarg
);
616 ret
= WS_EXIT_INVALID_OPTION
;
620 case PREFS_SET_OBSOLETE
:
621 cmdarg_err("-o flag \"%s\" specifies obsolete preference", ws_optarg
);
622 ret
= WS_EXIT_INVALID_OPTION
;
628 case 'p': /* Expect pcap_pkthdr packet headers, which may have 64-bit timestamps */
629 want_pcap_pkthdr
= true;
631 case 'r': /* Read capture file xxx */
632 pipe_name
= g_strdup(ws_optarg
);
634 case 'R': /* Read file filter */
635 case 'Y': /* Read file filter */
636 /* Read and display filters are the same for rawshark */
637 if(n_rfilters
< (int)array_length(rfilters
)) {
638 rfilters
[n_rfilters
++] = ws_optarg
;
641 cmdarg_err("Too many display filters");
642 ret
= WS_EXIT_INVALID_OPTION
;
646 case 's': /* Skip PCAP header */
647 skip_pcap_header
= true;
649 case 'S': /* Print string representations */
650 if (!parse_field_string_format(ws_optarg
)) {
651 cmdarg_err("Invalid field string format");
652 ret
= WS_EXIT_INVALID_OPTION
;
656 case 'v': /* Show version and exit */
661 /* Common dissection options - 'd' for Decode As also makes
662 * sense, but rawshark uses it for the payload link layer/
663 * dissector selection.
665 case 'K': /* Kerberos keytab file */
666 case 'n': /* No name resolution */
667 case 'N': /* Select what types of addresses/port #s to resolve */
668 case 't': /* Time stamp type */
669 case 'u': /* Seconds type */
670 case LONGOPT_DISABLE_PROTOCOL
: /* disable dissection of protocol */
671 case LONGOPT_ENABLE_HEURISTIC
: /* enable heuristic dissection of protocol */
672 case LONGOPT_DISABLE_HEURISTIC
: /* disable heuristic dissection of protocol */
673 case LONGOPT_ENABLE_PROTOCOL
: /* enable dissection of protocol (that is disabled by default) */
674 case LONGOPT_ONLY_PROTOCOLS
: /* enable dissection of only this comma separated list of protocols */
675 case LONGOPT_DISABLE_ALL_PROTOCOLS
: /* enable dissection of protocol (that is disabled by default) */
676 if (!dissect_opts_handle_opt(opt
, ws_optarg
)) {
677 ret
= WS_EXIT_INVALID_OPTION
;
682 case '?': /* Bad flag - print usage message */
684 ret
= WS_EXIT_INVALID_OPTION
;
689 /* Notify all registered modules that have had any of their preferences
690 changed either from one of the preferences file or from the command
691 line that their preferences have changed.
692 Initialize preferences before display filters, otherwise modules
693 like MATE won't work. */
696 /* Initialize our display fields */
697 for (fc
= 0; fc
< disp_fields
->len
; fc
++) {
698 protocolinfo_init((char *)g_ptr_array_index(disp_fields
, fc
));
700 g_ptr_array_free(disp_fields
, TRUE
);
704 /* If no capture filter or read filter has been specified, and there are
705 still command-line arguments, treat them as the tokens of a capture
706 filter (if no "-r" flag was specified) or a read filter (if a "-r"
707 flag was specified. */
708 if (ws_optind
< argc
) {
709 if (pipe_name
!= NULL
) {
710 if (n_rfilters
!= 0) {
711 cmdarg_err("Read filters were specified both with \"-R\" "
712 "and with additional command-line arguments");
713 ret
= WS_EXIT_INVALID_OPTION
;
716 rfilters
[n_rfilters
] = get_args_as_string(argc
, argv
, ws_optind
);
720 /* Make sure we got a dissector handle for our payload. */
721 if (encap
== WTAP_ENCAP_UNKNOWN
) {
722 cmdarg_err("No valid payload dissector specified.");
723 ret
= WS_EXIT_INVALID_OPTION
;
727 err_msg
= ws_init_sockets();
730 cmdarg_err("%s", err_msg
);
732 cmdarg_err_cont("%s", please_report_bug());
733 ret
= WS_EXIT_INIT_FAILED
;
737 if (global_dissect_options
.time_format
!= TS_NOT_SET
)
738 timestamp_set_type(global_dissect_options
.time_format
);
739 if (global_dissect_options
.time_precision
!= TS_PREC_NOT_SET
)
740 timestamp_set_precision(global_dissect_options
.time_precision
);
743 * Enabled and disabled protocols and heuristic dissectors as per
744 * command-line options.
746 if (!setup_enabled_and_disabled_protocols()) {
747 ret
= WS_EXIT_INVALID_OPTION
;
751 /* Build the column format array */
752 build_column_format_array(&cfile
.cinfo
, prefs_p
->num_cols
, true);
754 if (n_rfilters
!= 0) {
755 for (i
= 0; i
< n_rfilters
; i
++) {
756 if (!dfilter_compile(rfilters
[i
], &rfcodes
[n_rfcodes
], &df_err
)) {
757 cmdarg_err("%s", df_err
->msg
);
758 df_error_free(&df_err
);
759 ret
= INVALID_DFILTER
;
768 * We're reading a pipe (or capture file).
772 * Immediately relinquish any special privileges we have; we must not
773 * be allowed to read any capture files the user running Rawshark
776 relinquish_special_privs_perm();
778 if (raw_cf_open(&cfile
, pipe_name
) != CF_OK
) {
779 ret
= WS_EXIT_OPEN_ERROR
;
783 /* Do we need to PCAP header and magic? */
784 if (skip_pcap_header
) {
785 unsigned int bytes_left
= (unsigned int) sizeof(struct pcap_hdr
) + sizeof(uint32_t);
786 char buf
[sizeof(struct pcap_hdr
) + sizeof(uint32_t)];
787 while (bytes_left
!= 0) {
788 ssize_t bytes
= ws_read(fd
, buf
, bytes_left
);
790 cmdarg_err("Not enough bytes for pcap header.");
794 bytes_left
-= (unsigned int)bytes
;
798 /* Process the packets in the file */
799 if (!load_cap_file(&cfile
)) {
800 ret
= WS_EXIT_OPEN_ERROR
;
804 /* If you want to capture live packets, use TShark. */
805 cmdarg_err("Input file or pipe name not specified.");
806 ret
= WS_EXIT_OPEN_ERROR
;
812 epan_free(cfile
.epan
);
819 * Read data from a raw pipe. The "raw" data consists of a libpcap
820 * packet header followed by the payload.
821 * @param buf [IN] A POSIX file descriptor. Because that's _exactly_ the sort
822 * of thing you want to use in Windows.
823 * @param err [OUT] Error indicator. Uses wiretap values.
824 * @param err_info [OUT] Error message.
825 * @param data_offset [OUT] data offset in the pipe.
826 * @return true on success, false on failure.
829 raw_pipe_read(wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
, int64_t *data_offset
) {
830 struct pcap_pkthdr mem_hdr
;
831 struct pcaprec_hdr disk_hdr
;
832 ssize_t bytes_read
= 0;
833 unsigned int bytes_needed
= (unsigned int) sizeof(disk_hdr
);
834 unsigned char *ptr
= (unsigned char*) &disk_hdr
;
838 if (want_pcap_pkthdr
) {
839 bytes_needed
= sizeof(mem_hdr
);
840 ptr
= (unsigned char*) &mem_hdr
;
844 * Newer versions of the VC runtime do parameter validation. If stdin
845 * has been closed, calls to _read, _get_osfhandle, et al will trigger
846 * the invalid parameter handler and crash.
847 * We could alternatively use ReadFile or set an invalid parameter
849 * We could also tell callers not to close stdin prematurely.
853 if (fd
== 0 && GetHandleInformation(GetStdHandle(STD_INPUT_HANDLE
), &ghi_flags
) == 0) {
860 /* Copied from capture_loop.c */
861 while (bytes_needed
> 0) {
862 bytes_read
= ws_read(fd
, ptr
, bytes_needed
);
863 if (bytes_read
== 0) {
867 } else if (bytes_read
< 0) {
872 bytes_needed
-= (unsigned int)bytes_read
;
873 *data_offset
+= bytes_read
;
877 rec
->rec_type
= REC_TYPE_PACKET
;
878 rec
->presence_flags
= WTAP_HAS_TS
|WTAP_HAS_CAP_LEN
;
879 if (want_pcap_pkthdr
) {
880 rec
->ts
.secs
= mem_hdr
.ts
.tv_sec
;
881 rec
->ts
.nsecs
= (int32_t)mem_hdr
.ts
.tv_usec
* 1000;
882 rec
->rec_header
.packet_header
.caplen
= mem_hdr
.caplen
;
883 rec
->rec_header
.packet_header
.len
= mem_hdr
.len
;
885 rec
->ts
.secs
= disk_hdr
.ts_sec
;
886 rec
->ts
.nsecs
= disk_hdr
.ts_usec
* 1000;
887 rec
->rec_header
.packet_header
.caplen
= disk_hdr
.incl_len
;
888 rec
->rec_header
.packet_header
.len
= disk_hdr
.orig_len
;
890 bytes_needed
= rec
->rec_header
.packet_header
.caplen
;
892 rec
->rec_header
.packet_header
.pkt_encap
= encap
;
895 printf("mem_hdr: %lu disk_hdr: %lu\n", sizeof(mem_hdr
), sizeof(disk_hdr
));
896 printf("tv_sec: %d (%04x)\n", (unsigned int) rec
->ts
.secs
, (unsigned int) rec
->ts
.secs
);
897 printf("tv_nsec: %d (%04x)\n", rec
->ts
.nsecs
, rec
->ts
.nsecs
);
898 printf("caplen: %d (%04x)\n", rec
->rec_header
.packet_header
.caplen
, rec
->rec_header
.packet_header
.caplen
);
899 printf("len: %d (%04x)\n", rec
->rec_header
.packet_header
.len
, rec
->rec_header
.packet_header
.len
);
901 if (bytes_needed
> WTAP_MAX_PACKET_SIZE_STANDARD
) {
902 *err
= WTAP_ERR_BAD_FILE
;
903 *err_info
= ws_strdup_printf("Bad packet length: %lu",
904 (unsigned long) bytes_needed
);
908 ws_buffer_assure_space(buf
, bytes_needed
);
909 ptr
= ws_buffer_start_ptr(buf
);
910 while (bytes_needed
> 0) {
911 bytes_read
= ws_read(fd
, ptr
, bytes_needed
);
912 if (bytes_read
== 0) {
913 *err
= WTAP_ERR_SHORT_READ
;
916 } else if (bytes_read
< 0) {
921 bytes_needed
-= (unsigned int)bytes_read
;
922 *data_offset
+= bytes_read
;
929 load_cap_file(capture_file
*cf
)
932 char *err_info
= NULL
;
933 int64_t data_offset
= 0;
940 ws_buffer_init(&buf
, 1514);
942 epan_dissect_init(&edt
, cf
->epan
, true, false);
944 while (raw_pipe_read(&rec
, &buf
, &err
, &err_info
, &data_offset
)) {
945 process_packet(cf
, &edt
, data_offset
, &rec
, &buf
);
948 epan_dissect_cleanup(&edt
);
950 wtap_rec_cleanup(&rec
);
951 ws_buffer_free(&buf
);
953 /* Print a message noting that the read failed somewhere along the line. */
954 cfile_read_failure_message(cf
->filename
, err
, err_info
);
962 process_packet(capture_file
*cf
, epan_dissect_t
*edt
, int64_t offset
,
963 wtap_rec
*rec
, Buffer
*buf
)
969 if(rec
->rec_header
.packet_header
.len
== 0)
971 /* The user sends an empty packet when he wants to get output from us even if we don't currently have
972 packets to process. We spit out a line with the timestamp and the text "void"
974 printf("%lu %" PRIu64
" %d void -\n", (unsigned long int)cf
->count
,
975 (uint64_t)rec
->ts
.secs
, rec
->ts
.nsecs
);
982 /* Count this packet. */
985 /* If we're going to print packet information, or we're going to
986 run a read filter, or we're going to process taps, set up to
987 do a dissection and do so. */
988 frame_data_init(&fdata
, cf
->count
, rec
, offset
, cum_bytes
);
992 /* If we're running a read filter, prime the epan_dissect_t with that
994 if (n_rfilters
> 0) {
995 for(i
= 0; i
< n_rfcodes
; i
++) {
996 epan_dissect_prime_with_dfilter(edt
, rfcodes
[i
]);
1000 printf("%lu", (unsigned long int) cf
->count
);
1002 frame_data_set_before_dissect(&fdata
, &cf
->elapsed_time
,
1003 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
1005 if (cf
->provider
.ref
== &fdata
) {
1007 cf
->provider
.ref
= &ref_frame
;
1010 /* We only need the columns if we're printing packet info but we're
1011 *not* verbose; in verbose mode, we print the protocol tree, not
1012 the protocol summary. */
1013 epan_dissect_run_with_taps(edt
, cf
->cd_t
, rec
,
1014 frame_tvbuff_new_buffer(&cf
->provider
, &fdata
, buf
),
1015 &fdata
, &cf
->cinfo
);
1017 frame_data_set_after_dissect(&fdata
, &cum_bytes
);
1018 prev_dis_frame
= fdata
;
1019 cf
->provider
.prev_dis
= &prev_dis_frame
;
1021 prev_cap_frame
= fdata
;
1022 cf
->provider
.prev_cap
= &prev_cap_frame
;
1024 for(i
= 0; i
< n_rfilters
; i
++) {
1025 /* Run the read filter if we have one. */
1027 passed
= dfilter_apply_edt(rfcodes
[i
], edt
);
1031 /* Print a one-line summary */
1032 printf(" %d", passed
? 1 : 0);
1037 /* The ANSI C standard does not appear to *require* that a line-buffered
1038 stream be flushed to the host environment whenever a newline is
1039 written, it just says that, on such a stream, characters "are
1040 intended to be transmitted to or from the host environment as a
1041 block when a new-line character is encountered".
1043 The Visual C++ 6.0 C implementation doesn't do what is intended;
1044 even if you set a stream to be line-buffered, it still doesn't
1045 flush the buffer at the end of every line.
1047 So, if the "-l" flag was specified, we flush the standard output
1048 at the end of a packet. This will do the right thing if we're
1049 printing packet summary lines, and, as we print the entire protocol
1050 tree for a single packet without waiting for anything to happen,
1051 it should be as good as line-buffered mode if we're printing
1052 protocol trees. (The whole reason for the "-l" flag in either
1053 tcpdump or Rawshark is to allow the output of a live capture to
1054 be piped to a program or script and to have that script see the
1055 information for the packet as soon as it's printed, rather than
1056 having to wait until a standard I/O buffer fills up. */
1060 if (ferror(stdout
)) {
1061 show_print_file_io_error(errno
);
1065 epan_dissect_reset(edt
);
1066 frame_data_destroy(&fdata
);
1071 /****************************************************************************************
1072 * FIELD EXTRACTION ROUTINES
1073 ****************************************************************************************/
1074 typedef struct _pci_t
{
1080 static const char* ftenum_to_string(header_field_info
*hfi
)
1087 if (string_fmts
->len
> 0 && hfi
->strings
) {
1091 str
= ftype_name(hfi
->type
);
1099 static void field_display_to_string(header_field_info
*hfi
, char* buf
, int size
)
1101 if (hfi
->type
!= FT_BOOLEAN
)
1103 (void) g_strlcpy(buf
, proto_field_display_to_string(hfi
->display
), size
);
1107 snprintf(buf
, size
, "(Bit count: %d)", hfi
->display
);
1112 * Copied from various parts of proto.c
1114 #define FIELD_STR_INIT_LEN 256
1115 #define cVALS(x) (const value_string*)(x)
1116 static bool print_field_value(field_info
*finfo
, int cmd_line_index
)
1118 const header_field_info
*hfinfo
;
1120 char *fs_ptr
= NULL
;
1121 static GString
*label_s
= NULL
;
1130 hfinfo
= finfo
->hfinfo
;
1133 label_s
= g_string_new("");
1136 fs_buf
= fvalue_to_string_repr(NULL
, finfo
->value
,
1137 FTREPR_DFILTER
, finfo
->hfinfo
->display
);
1138 if (fs_buf
!= NULL
) {
1140 * this field has an associated value,
1143 fs_len
= strlen(fs_buf
);
1146 /* String types are quoted. Remove them. */
1147 if (FT_IS_STRING(fvalue_type_ftenum(finfo
->value
)) && fs_len
> 2) {
1148 fs_buf
[fs_len
- 1] = '\0';
1153 if (string_fmts
->len
> 0 && finfo
->hfinfo
->strings
) {
1154 g_string_truncate(label_s
, 0);
1155 for (i
= 0; i
< string_fmts
->len
; i
++) {
1156 sf
= (string_fmt_t
*)g_ptr_array_index(string_fmts
, i
);
1158 g_string_append(label_s
, sf
->plain
);
1160 switch (sf
->format
) {
1162 g_string_append(label_s
, hfinfo
->name
);
1165 g_string_append(label_s
, fs_ptr
);
1168 switch(hfinfo
->type
) {
1170 uvalue64
= fvalue_get_uinteger64(finfo
->value
);
1171 g_string_append(label_s
, tfs_get_string(!!uvalue64
, hfinfo
->strings
));
1177 DISSECTOR_ASSERT(!hfinfo
->bitmask
);
1178 svalue
= fvalue_get_sinteger(finfo
->value
);
1179 if (hfinfo
->display
& BASE_RANGE_STRING
) {
1180 g_string_append(label_s
, rval_to_str_const(svalue
, (const range_string
*) hfinfo
->strings
, "Unknown"));
1181 } else if (hfinfo
->display
& BASE_EXT_STRING
) {
1182 g_string_append(label_s
, val_to_str_ext_const(svalue
, (value_string_ext
*) hfinfo
->strings
, "Unknown"));
1184 g_string_append(label_s
, val_to_str_const(svalue
, cVALS(hfinfo
->strings
), "Unknown"));
1187 case FT_INT40
: /* XXX: Shouldn't these be as smart as FT_INT{8,16,24,32}? */
1191 DISSECTOR_ASSERT(!hfinfo
->bitmask
);
1192 svalue64
= fvalue_get_sinteger64(finfo
->value
);
1193 if (hfinfo
->display
& BASE_VAL64_STRING
) {
1194 g_string_append(label_s
, val64_to_str_const(svalue64
, (const val64_string
*)(hfinfo
->strings
), "Unknown"));
1201 DISSECTOR_ASSERT(!hfinfo
->bitmask
);
1202 uvalue
= fvalue_get_uinteger(finfo
->value
);
1203 if (!hfinfo
->bitmask
&& hfinfo
->display
& BASE_RANGE_STRING
) {
1204 g_string_append(label_s
, rval_to_str_const(uvalue
, (const range_string
*) hfinfo
->strings
, "Unknown"));
1205 } else if (hfinfo
->display
& BASE_EXT_STRING
) {
1206 g_string_append(label_s
, val_to_str_ext_const(uvalue
, (value_string_ext
*) hfinfo
->strings
, "Unknown"));
1208 g_string_append(label_s
, val_to_str_const(uvalue
, cVALS(hfinfo
->strings
), "Unknown"));
1211 case FT_UINT40
: /* XXX: Shouldn't these be as smart as FT_INT{8,16,24,32}? */
1215 DISSECTOR_ASSERT(!hfinfo
->bitmask
);
1216 uvalue64
= fvalue_get_uinteger64(finfo
->value
);
1217 if (hfinfo
->display
& BASE_VAL64_STRING
) {
1218 g_string_append(label_s
, val64_to_str_const(uvalue64
, (const val64_string
*)(hfinfo
->strings
), "Unknown"));
1230 printf(" %d=\"%s\"", cmd_line_index
, label_s
->str
);
1231 wmem_free(NULL
, fs_buf
);
1237 printf(" %d=\"%s\"", cmd_line_index
, fs_ptr
);
1238 wmem_free(NULL
, fs_buf
);
1243 * This field doesn't have an associated value,
1247 printf(" %d=\"n.a.\"", cmd_line_index
);
1251 static tap_packet_status
1252 protocolinfo_packet(void *prs
, packet_info
*pinfo _U_
, epan_dissect_t
*edt
, const void *dummy _U_
, tap_flags_t flags _U_
)
1254 pci_t
*rs
=(pci_t
*)prs
;
1258 gp
=proto_get_finfo_ptr_array(edt
->tree
, rs
->hf_index
);
1261 return TAP_PACKET_DONT_REDRAW
;
1265 * Print each occurrence of the field
1267 for (i
= 0; i
< gp
->len
; i
++) {
1268 print_field_value((field_info
*)gp
->pdata
[i
], rs
->cmd_line_index
);
1271 return TAP_PACKET_DONT_REDRAW
;
1274 int g_cmd_line_index
;
1277 * field must be persistent - we don't g_strdup() it below
1280 protocolinfo_init(char *field
)
1283 header_field_info
*hfi
;
1284 GString
*error_string
;
1287 hfi
=proto_registrar_get_byname(field
);
1289 fprintf(stderr
, "rawshark: Field \"%s\" doesn't exist.\n", field
);
1293 field_display_to_string(hfi
, hfibuf
, sizeof(hfibuf
));
1294 printf("%d %s %s - ",
1296 ftenum_to_string(hfi
),
1300 rs
->hf_index
=hfi
->id
;
1302 rs
->cmd_line_index
= g_cmd_line_index
++;
1304 error_string
=register_tap_listener("frame", rs
, rs
->filter
, TL_REQUIRES_PROTO_TREE
, NULL
, protocolinfo_packet
, NULL
, NULL
);
1306 /* error, we failed to attach to the tap. complain and clean up */
1307 fprintf(stderr
, "rawshark: Couldn't register field extraction tap: %s\n",
1309 g_string_free(error_string
, TRUE
);
1320 * Given a format string, split it into a GPtrArray of string_fmt_t structs
1321 * and fill in string_fmt_parts.
1325 add_string_fmt(string_fmt_e format
, char *plain
) {
1326 string_fmt_t
*sf
= g_new(string_fmt_t
, 1);
1328 sf
->format
= format
;
1329 sf
->plain
= g_strdup(plain
);
1331 g_ptr_array_add(string_fmts
, sf
);
1335 parse_field_string_format(char *format
) {
1343 GString
*plain_s
= g_string_new("");
1345 len
= strlen(format
);
1346 g_ptr_array_set_size(string_fmts
, 0);
1349 if (format
[pos
] == '%') {
1350 if (pos
>= (len
-1)) { /* There should always be a following specifier character */
1354 if (plain_s
->len
> 0) {
1355 add_string_fmt(SF_NONE
, plain_s
->str
);
1356 g_string_truncate(plain_s
, 0);
1358 switch (format
[pos
]) {
1360 add_string_fmt(SF_NAME
, NULL
);
1363 add_string_fmt(SF_NUMVAL
, NULL
);
1366 add_string_fmt(SF_STRVAL
, NULL
);
1369 g_string_append_c(plain_s
, '%');
1371 default: /* Invalid format */
1375 g_string_append_c(plain_s
, format
[pos
]);
1380 if (plain_s
->len
> 0) {
1381 add_string_fmt(SF_NONE
, plain_s
->str
);
1383 g_string_free(plain_s
, TRUE
);
1387 /****************************************************************************************
1388 * END OF FIELD EXTRACTION ROUTINES
1389 ****************************************************************************************/
1392 show_print_file_io_error(int err
)
1397 cmdarg_err("Not all the packets could be printed because there is "
1398 "no space left on the file system.");
1403 cmdarg_err("Not all the packets could be printed because you are "
1404 "too close to, or over your disk quota.");
1409 cmdarg_err("An error occurred while printing packets: %s.",
1416 raw_epan_new(capture_file
*cf
)
1418 static const struct packet_provider_funcs funcs
= {
1419 cap_file_provider_get_frame_ts
,
1420 cap_file_provider_get_interface_name
,
1421 cap_file_provider_get_interface_description
,
1425 return epan_new(&cf
->provider
, &funcs
);
1429 raw_cf_open(capture_file
*cf
, const char *fname
)
1431 if ((fd
= raw_pipe_open(fname
)) < 0)
1434 /* The open succeeded. Fill in the information for this file. */
1436 /* Create new epan session for dissection. */
1437 epan_free(cf
->epan
);
1438 cf
->epan
= raw_epan_new(cf
);
1440 cf
->provider
.wth
= NULL
;
1441 cf
->f_datalen
= 0; /* not used, but set it anyway */
1443 /* Set the file name because we need it to set the follow stream filter.
1444 XXX - is that still true? We need it for other reasons, though,
1446 cf
->filename
= g_strdup(fname
);
1448 /* Indicate whether it's a permanent or temporary file. */
1449 cf
->is_tempfile
= false;
1451 /* No user changes yet. */
1452 cf
->unsaved_changes
= false;
1454 cf
->cd_t
= WTAP_FILE_TYPE_SUBTYPE_UNKNOWN
;
1455 cf
->open_type
= WTAP_TYPE_AUTO
;
1457 cf
->drops_known
= false;
1460 nstime_set_zero(&cf
->elapsed_time
);
1461 cf
->provider
.ref
= NULL
;
1462 cf
->provider
.prev_dis
= NULL
;
1463 cf
->provider
.prev_cap
= NULL
;
1469 * Report an error in command-line arguments.
1472 rawshark_cmdarg_err(const char *fmt
, va_list ap
)
1474 fprintf(stderr
, "rawshark: ");
1475 vfprintf(stderr
, fmt
, ap
);
1476 fprintf(stderr
, "\n");
1480 * Report additional information for an error in command-line arguments.
1483 rawshark_cmdarg_err_cont(const char *fmt
, va_list ap
)
1485 vfprintf(stderr
, fmt
, ap
);
1486 fprintf(stderr
, "\n");
1495 * indent-tabs-mode: nil
1498 * ex: set shiftwidth=4 tabstop=8 expandtab:
1499 * :indentSize=4:tabSize=8:noTabs=true: