3 * Daemon variant of Wireshark
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
23 #include <epan/exceptions.h>
24 #include <epan/epan.h>
26 #include <wsutil/clopts_common.h>
27 #include <wsutil/cmdarg_err.h>
28 #include <wsutil/filesystem.h>
29 #include <wsutil/file_util.h>
30 #include <wsutil/privileges.h>
31 #include <wsutil/report_message.h>
32 #include <wsutil/wslog.h>
33 #include <wsutil/version_info.h>
34 #include <wiretap/wtap_opttypes.h>
36 #include <epan/decode_as.h>
37 #include <epan/timestamp.h>
38 #include <epan/packet.h>
39 #include "frame_tvbuff.h"
40 #include <epan/disabled_protos.h>
41 #include <epan/prefs.h>
42 #include <epan/column.h>
43 #include <epan/print.h>
44 #include <epan/addr_resolv.h>
46 #include "ui/ws_ui_util.h"
47 #include "ui/decode_as_utils.h"
48 #include "wsutil/filter_files.h"
49 #include "ui/tap_export_pdu.h"
50 #include "ui/failure_message.h"
52 #include <epan/epan_dissect.h>
54 #include <epan/uat-int.h>
55 #include <epan/secrets.h>
57 #include <wsutil/codecs.h>
59 #include <wsutil/str_util.h>
60 #include <wsutil/utf8_entities.h>
63 #include <wsutil/plugins.h>
68 #define SHARKD_INIT_FAILED 1
69 #define SHARKD_EPAN_INIT_FAIL 2
73 static uint32_t cum_bytes
;
74 static frame_data ref_frame
;
76 static void sharkd_cmdarg_err(const char *msg_format
, va_list ap
);
77 static void sharkd_cmdarg_err_cont(const char *msg_format
, va_list ap
);
80 print_current_user(void)
82 char *cur_user
, *cur_group
;
84 if (started_with_special_privs()) {
85 cur_user
= get_cur_username();
86 cur_group
= get_cur_groupname();
87 fprintf(stderr
, "Running as user \"%s\" and group \"%s\".",
91 if (running_with_special_privs()) {
92 fprintf(stderr
, " This could be dangerous.");
94 fprintf(stderr
, "\n");
99 main(int argc
, char *argv
[])
101 char *configuration_init_error
;
103 char *err_msg
= NULL
;
105 int ret
= EXIT_SUCCESS
;
106 static const struct report_message_routines sharkd_report_routines
= {
109 open_failure_message
,
110 read_failure_message
,
111 write_failure_message
,
112 cfile_open_failure_message
,
113 cfile_dump_open_failure_message
,
114 cfile_read_failure_message
,
115 cfile_write_failure_message
,
116 cfile_close_failure_message
119 cmdarg_err_init(sharkd_cmdarg_err
, sharkd_cmdarg_err_cont
);
121 /* Initialize log handler early so we can have proper logging during startup. */
122 ws_log_init("sharkd", vcmdarg_err
);
124 /* Early logging command-line initialization. */
125 ws_log_parse_args(&argc
, argv
, vcmdarg_err
, SHARKD_INIT_FAILED
);
127 ws_noisy("Finished log init and parsing command line log arguments");
130 * Get credential information for later use, and drop privileges
131 * before doing anything else.
132 * Let the user know if anything happened.
134 init_process_policies();
135 relinquish_special_privs_perm();
136 print_current_user();
139 * Attempt to get the pathname of the executable file.
141 configuration_init_error
= configuration_init(argv
[0], NULL
);
142 if (configuration_init_error
!= NULL
) {
143 fprintf(stderr
, "sharkd: Can't get pathname of sharkd program: %s.\n",
144 configuration_init_error
);
147 /* Initialize the version information. */
148 ws_init_version_info("Sharkd",
149 epan_gather_compile_info
,
150 epan_gather_runtime_info
);
152 if (sharkd_init(argc
, argv
) < 0)
154 printf("cannot initialize sharkd\n");
155 ret
= SHARKD_INIT_FAILED
;
159 init_report_message("sharkd", &sharkd_report_routines
);
161 timestamp_set_type(TS_RELATIVE
);
162 timestamp_set_precision(TS_PREC_AUTO
);
163 timestamp_set_seconds_type(TS_SECONDS_DEFAULT
);
166 * Libwiretap must be initialized before libwireshark is, so that
167 * dissection-time handlers for file-type-dependent blocks can
168 * register using the file type/subtype value for the file type.
172 /* Register all dissectors; we must do this before checking for the
173 "-G" flag, as the "-G" flag dumps information registered by the
174 dissectors, and we must do it before we read the preferences, in
175 case any dissectors register preferences. */
176 if (!epan_init(NULL
, NULL
, true)) {
177 ret
= SHARKD_EPAN_INIT_FAIL
;
183 /* Load libwireshark settings from the current profile. */
184 prefs_p
= epan_load_settings();
186 if (!color_filters_init(&err_msg
, NULL
)) {
187 fprintf(stderr
, "%s\n", err_msg
);
191 cap_file_init(&cfile
);
193 /* Notify all registered modules that have had any of their preferences
194 changed either from one of the preferences file or from the command
195 line that their preferences have changed. */
198 /* Build the column format array */
199 build_column_format_array(&cfile
.cinfo
, prefs_p
->num_cols
, true);
201 #ifdef HAVE_MAXMINDDB
202 /* mmdbresolve is started from mmdb_resolve_start(), which is called from epan_load_settings via: read_prefs -> (...) uat_load_all -> maxmind_db_post_update_cb.
203 * Need to stop it, otherwise all sharkd will have same mmdbresolve process, including pipe descriptors to read and write. */
204 uat_get_table_by_name("MaxMind Database Paths")->reset_cb();
207 ret
= sharkd_loop(argc
, argv
);
209 col_cleanup(&cfile
.cinfo
);
217 sharkd_epan_new(capture_file
*cf
)
219 static const struct packet_provider_funcs funcs
= {
220 cap_file_provider_get_frame_ts
,
221 cap_file_provider_get_interface_name
,
222 cap_file_provider_get_interface_description
,
223 cap_file_provider_get_modified_block
226 return epan_new(&cf
->provider
, &funcs
);
230 process_packet(capture_file
*cf
, epan_dissect_t
*edt
,
231 int64_t offset
, wtap_rec
*rec
, Buffer
*buf
)
236 /* If we're not running a display filter and we're not printing any
237 packet information, we don't need to do a dissection. This means
238 that all packets can be marked as 'passed'. */
241 /* The frame number of this packet, if we add it to the set of frames,
242 would be one more than the count of frames in the file so far. */
243 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cum_bytes
);
245 /* If we're going to print packet information, or we're going to
246 run a read filter, or display filter, or we're going to process taps, set up to
247 do a dissection and do so. */
249 if (gbl_resolv_flags
.mac_name
|| gbl_resolv_flags
.network_name
||
250 gbl_resolv_flags
.transport_name
)
251 /* Grab any resolved addresses */
252 host_name_lookup_process();
254 /* If we're running a read filter, prime the epan_dissect_t with that
257 epan_dissect_prime_with_dfilter(edt
, cf
->rfcode
);
260 epan_dissect_prime_with_dfilter(edt
, cf
->dfcode
);
262 /* This is the first and only pass, so prime the epan_dissect_t
263 with the hfids postdissectors want on the first pass. */
264 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
266 frame_data_set_before_dissect(&fdlocal
, &cf
->elapsed_time
,
267 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
268 if (cf
->provider
.ref
== &fdlocal
) {
270 cf
->provider
.ref
= &ref_frame
;
273 epan_dissect_run(edt
, cf
->cd_t
, rec
,
274 frame_tvbuff_new_buffer(&cf
->provider
, &fdlocal
, buf
),
277 /* Run the read filter if we have one. */
279 passed
= dfilter_apply_edt(cf
->rfcode
, edt
);
283 frame_data_set_after_dissect(&fdlocal
, &cum_bytes
);
284 cf
->provider
.prev_cap
= cf
->provider
.prev_dis
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
286 /* If we're not doing dissection then there won't be any dependent frames.
287 * More importantly, edt.pi.fd.dependent_frames won't be initialized because
288 * epan hasn't been initialized.
289 * if we *are* doing dissection, then mark the dependent frames, but only
290 * if a display filter was given and it matches this packet.
292 if (edt
&& cf
->dfcode
) {
293 if (dfilter_apply_edt(cf
->dfcode
, edt
) && edt
->pi
.fd
->dependent_frames
) {
294 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
300 /* if we don't add it to the frame_data_sequence, clean it up right now
302 frame_data_destroy(&fdlocal
);
306 epan_dissect_reset(edt
);
313 load_cap_file(capture_file
*cf
, int max_packet_count
, int64_t max_byte_count
)
316 char *err_info
= NULL
;
320 epan_dissect_t
*edt
= NULL
;
323 /* Allocate a frame_data_sequence for all the frames. */
324 cf
->provider
.frames
= new_frame_data_sequence();
327 bool create_proto_tree
;
330 * Determine whether we need to create a protocol tree.
333 * we're going to apply a read filter;
335 * we're going to apply a display filter;
337 * a postdissector wants field values or protocols
341 (cf
->rfcode
!= NULL
|| cf
->dfcode
!= NULL
|| postdissectors_want_hfids());
343 /* We're not going to display the protocol tree on this pass,
344 so it's not going to be "visible". */
345 edt
= epan_dissect_new(cf
->epan
, create_proto_tree
, false);
349 ws_buffer_init(&buf
, 1514);
351 while (wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
, &data_offset
)) {
352 if (process_packet(cf
, edt
, data_offset
, &rec
, &buf
)) {
353 wtap_rec_reset(&rec
);
354 /* Stop reading if we have the maximum number of packets;
355 * When the -c option has not been used, max_packet_count
356 * starts at 0, which practically means, never stop reading.
357 * (unless we roll over max_packet_count ?)
359 if ( (--max_packet_count
== 0) || (max_byte_count
!= 0 && data_offset
>= max_byte_count
)) {
360 err
= 0; /* This is not an error */
367 epan_dissect_free(edt
);
371 wtap_rec_cleanup(&rec
);
372 ws_buffer_free(&buf
);
374 /* Close the sequential I/O side, to free up memory it requires. */
375 wtap_sequential_close(cf
->provider
.wth
);
377 /* Allow the protocol dissectors to free up memory that they
378 * don't need after the sequential run-through of the packets. */
379 postseq_cleanup_all_protocols();
381 cf
->provider
.prev_dis
= NULL
;
382 cf
->provider
.prev_cap
= NULL
;
386 cfile_read_failure_message(cf
->filename
, err
, err_info
);
393 cf_open(capture_file
*cf
, const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
398 wth
= wtap_open_offline(fname
, type
, err
, &err_info
, true);
402 /* The open succeeded. Fill in the information for this file. */
404 cf
->provider
.wth
= wth
;
405 cf
->f_datalen
= 0; /* not used, but set it anyway */
407 /* Set the file name because we need it to set the follow stream filter.
408 XXX - is that still true? We need it for other reasons, though,
410 cf
->filename
= g_strdup(fname
);
412 /* Indicate whether it's a permanent or temporary file. */
413 cf
->is_tempfile
= is_tempfile
;
415 /* No user changes yet. */
416 cf
->unsaved_changes
= false;
418 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
419 cf
->open_type
= type
;
421 cf
->drops_known
= false;
423 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
424 nstime_set_zero(&cf
->elapsed_time
);
425 cf
->provider
.ref
= NULL
;
426 cf
->provider
.prev_dis
= NULL
;
427 cf
->provider
.prev_cap
= NULL
;
429 /* Create new epan session for dissection. */
431 cf
->epan
= sharkd_epan_new(cf
);
433 cf
->state
= FILE_READ_IN_PROGRESS
;
435 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
436 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
437 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
442 cfile_open_failure_message(fname
, *err
, err_info
);
447 * Report an error in command-line arguments.
450 sharkd_cmdarg_err(const char *msg_format
, va_list ap
)
452 fprintf(stderr
, "sharkd: ");
453 vfprintf(stderr
, msg_format
, ap
);
454 fprintf(stderr
, "\n");
458 * Report additional information for an error in command-line arguments.
461 sharkd_cmdarg_err_cont(const char *msg_format
, va_list ap
)
463 vfprintf(stderr
, msg_format
, ap
);
464 fprintf(stderr
, "\n");
468 sharkd_cf_open(const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
470 return cf_open(&cfile
, fname
, type
, is_tempfile
, err
);
474 sharkd_load_cap_file(void)
476 return load_cap_file(&cfile
, 0, 0);
480 sharkd_get_frame(uint32_t framenum
)
482 return frame_data_sequence_find(cfile
.provider
.frames
, framenum
);
485 enum dissect_request_status
486 sharkd_dissect_request(uint32_t framenum
, uint32_t frame_ref_num
,
487 uint32_t prev_dis_num
, wtap_rec
*rec
, Buffer
*buf
,
488 column_info
*cinfo
, uint32_t dissect_flags
,
489 sharkd_dissect_func_t cb
, void *data
,
490 int *err
, char **err_info
)
494 bool create_proto_tree
;
496 fdata
= sharkd_get_frame(framenum
);
498 return DISSECT_REQUEST_NO_SUCH_FRAME
;
500 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, rec
, buf
, err
, err_info
)) {
502 col_fill_in_error(cinfo
, fdata
, false, false /* fill_fd_columns */);
503 return DISSECT_REQUEST_READ_ERROR
; /* error reading the record */
506 create_proto_tree
= ((dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ||
507 ((dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) && color_filters_used()) ||
508 (cinfo
&& have_custom_cols(cinfo
)));
509 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
));
511 if (dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) {
512 color_filters_prime_edt(&edt
);
513 fdata
->need_colorize
= 1;
517 col_custom_prime_edt(&edt
, cinfo
);
520 * XXX - need to catch an OutOfMemoryError exception and
521 * attempt to recover from it.
523 fdata
->ref_time
= (framenum
== frame_ref_num
);
524 fdata
->frame_ref_num
= frame_ref_num
;
525 fdata
->prev_dis_num
= prev_dis_num
;
526 epan_dissect_run(&edt
, cfile
.cd_t
, rec
,
527 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, buf
),
531 /* "Stringify" non frame_data vals */
532 epan_dissect_fill_in_columns(&edt
, false, true/* fill_fd_columns */);
535 cb(&edt
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ? edt
.tree
: NULL
,
536 cinfo
, (dissect_flags
& SHARKD_DISSECT_FLAG_BYTES
) ? edt
.pi
.data_src
: NULL
,
540 epan_dissect_cleanup(&edt
);
541 return DISSECT_REQUEST_SUCCESS
;
552 char *err_info
= NULL
;
555 bool create_proto_tree
;
559 /* Get the union of the flags for all tap listeners. */
560 tap_flags
= union_of_tap_listener_flags();
562 /* If any tap listeners require the columns, construct them. */
563 cinfo
= (tap_listeners_require_columns()) ? &cfile
.cinfo
: NULL
;
566 * Determine whether we need to create a protocol tree.
569 * one of the tap listeners is going to apply a filter;
571 * one of the tap listeners requires a protocol tree.
574 (have_filtering_tap_listeners() || (tap_flags
& TL_REQUIRES_PROTO_TREE
));
577 ws_buffer_init(&buf
, 1514);
578 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, false);
580 reset_tap_listeners();
582 for (framenum
= 1; framenum
<= cfile
.count
; framenum
++) {
583 fdata
= sharkd_get_frame(framenum
);
585 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
588 fdata
->ref_time
= false;
589 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
590 fdata
->prev_dis_num
= framenum
- 1;
591 epan_dissect_run_with_taps(&edt
, cfile
.cd_t
, &rec
,
592 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
594 wtap_rec_reset(&rec
);
595 epan_dissect_reset(&edt
);
598 wtap_rec_cleanup(&rec
);
599 ws_buffer_free(&buf
);
600 epan_dissect_cleanup(&edt
);
602 draw_tap_listeners(true);
608 sharkd_filter(const char *dftext
, uint8_t **result
)
610 dfilter_t
*dfcode
= NULL
;
612 uint32_t framenum
, prev_dis_num
= 0;
613 uint32_t frames_count
;
617 char *err_info
= NULL
;
619 uint8_t *result_bits
;
624 if (!dfilter_compile(dftext
, &dfcode
, NULL
)) {
628 /* if dfilter_compile() success, but (dfcode == NULL) all frames are matching */
629 if (dfcode
== NULL
) {
634 frames_count
= cfile
.count
;
637 ws_buffer_init(&buf
, 1514);
638 epan_dissect_init(&edt
, cfile
.epan
, true, false);
641 result_bits
= (uint8_t *) g_malloc(2 + (frames_count
/ 8));
643 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
644 frame_data
*fdata
= sharkd_get_frame(framenum
);
646 if ((framenum
& 7) == 0) {
647 result_bits
[(framenum
/ 8) - 1] = passed_bits
;
651 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
654 /* frame_data_set_before_dissect */
655 epan_dissect_prime_with_dfilter(&edt
, dfcode
);
657 fdata
->ref_time
= false;
658 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
659 fdata
->prev_dis_num
= prev_dis_num
;
660 epan_dissect_run(&edt
, cfile
.cd_t
, &rec
,
661 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
664 if (dfilter_apply_edt(dfcode
, &edt
)) {
665 passed_bits
|= (1 << (framenum
% 8));
666 prev_dis_num
= framenum
;
669 /* if passed or ref -> frame_data_set_after_dissect */
671 wtap_rec_reset(&rec
);
672 epan_dissect_reset(&edt
);
675 if ((framenum
& 7) == 0)
677 result_bits
[framenum
/ 8] = passed_bits
;
679 wtap_rec_cleanup(&rec
);
680 ws_buffer_free(&buf
);
681 epan_dissect_cleanup(&edt
);
683 dfilter_free(dfcode
);
685 *result
= result_bits
;
691 * Get the modified block if available, nothing otherwise.
692 * Must be cloned if changes desired.
695 sharkd_get_modified_block(const frame_data
*fd
)
697 return cap_file_provider_get_modified_block(&cfile
.provider
, fd
);
701 * Gets the modified block if available, otherwise the packet's default block,
702 * or a new packet block.
703 * User must wtap_block_unref() it when done.
706 sharkd_get_packet_block(const frame_data
*fd
)
708 if (fd
->has_modified_block
)
709 return wtap_block_ref(cap_file_provider_get_modified_block(&cfile
.provider
, fd
));
712 wtap_rec rec
; /* Record metadata */
713 Buffer buf
; /* Record data */
719 ws_buffer_init(&buf
, 1514);
721 if (!wtap_seek_read(cfile
.provider
.wth
, fd
->file_off
, &rec
, &buf
, &err
, &err_info
))
722 { /* XXX, what we can do here? */ }
724 /* rec.block is owned by the record, steal it before it is gone. */
725 block
= wtap_block_ref(rec
.block
);
727 wtap_rec_cleanup(&rec
);
728 ws_buffer_free(&buf
);
734 sharkd_set_modified_block(frame_data
*fd
, wtap_block_t new_block
)
736 cap_file_provider_set_modified_block(&cfile
.provider
, fd
, new_block
);