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/wslog.h>
32 #include <wsutil/version_info.h>
33 #include <wiretap/wtap_opttypes.h>
35 #include <epan/decode_as.h>
36 #include <epan/timestamp.h>
37 #include <epan/packet.h>
38 #include "frame_tvbuff.h"
39 #include <epan/disabled_protos.h>
40 #include <epan/prefs.h>
41 #include <epan/column.h>
42 #include <epan/print.h>
43 #include <epan/addr_resolv.h>
45 #include "ui/ws_ui_util.h"
46 #include "ui/decode_as_utils.h"
47 #include "wsutil/filter_files.h"
48 #include "ui/tap_export_pdu.h"
49 #include "ui/failure_message.h"
50 #include <wiretap/wtap.h>
51 #include <epan/epan_dissect.h>
53 #include <epan/uat-int.h>
54 #include <epan/secrets.h>
56 #include <wsutil/codecs.h>
58 #include <wsutil/str_util.h>
59 #include <wsutil/utf8_entities.h>
62 #include <wsutil/plugins.h>
67 #define SHARKD_INIT_FAILED 1
68 #define SHARKD_EPAN_INIT_FAIL 2
72 static uint32_t cum_bytes
;
73 static frame_data ref_frame
;
75 static void sharkd_cmdarg_err(const char *msg_format
, va_list ap
);
76 static void sharkd_cmdarg_err_cont(const char *msg_format
, va_list ap
);
79 print_current_user(void)
81 char *cur_user
, *cur_group
;
83 if (started_with_special_privs()) {
84 cur_user
= get_cur_username();
85 cur_group
= get_cur_groupname();
86 fprintf(stderr
, "Running as user \"%s\" and group \"%s\".",
90 if (running_with_special_privs()) {
91 fprintf(stderr
, " This could be dangerous.");
93 fprintf(stderr
, "\n");
98 main(int argc
, char *argv
[])
100 char *configuration_init_error
;
102 char *err_msg
= NULL
;
104 int ret
= EXIT_SUCCESS
;
106 cmdarg_err_init(sharkd_cmdarg_err
, sharkd_cmdarg_err_cont
);
108 /* Initialize log handler early so we can have proper logging during startup. */
109 ws_log_init("sharkd", vcmdarg_err
);
111 /* Early logging command-line initialization. */
112 ws_log_parse_args(&argc
, argv
, vcmdarg_err
, SHARKD_INIT_FAILED
);
114 ws_noisy("Finished log init and parsing command line log arguments");
117 * Get credential information for later use, and drop privileges
118 * before doing anything else.
119 * Let the user know if anything happened.
121 init_process_policies();
122 relinquish_special_privs_perm();
123 print_current_user();
126 * Attempt to get the pathname of the executable file.
128 configuration_init_error
= configuration_init(argv
[0], NULL
);
129 if (configuration_init_error
!= NULL
) {
130 fprintf(stderr
, "sharkd: Can't get pathname of sharkd program: %s.\n",
131 configuration_init_error
);
134 /* Initialize the version information. */
135 ws_init_version_info("Sharkd",
136 epan_gather_compile_info
,
137 epan_gather_runtime_info
);
139 if (sharkd_init(argc
, argv
) < 0)
141 printf("cannot initialize sharkd\n");
142 ret
= SHARKD_INIT_FAILED
;
146 init_report_failure_message("sharkd");
148 timestamp_set_type(TS_RELATIVE
);
149 timestamp_set_precision(TS_PREC_AUTO
);
150 timestamp_set_seconds_type(TS_SECONDS_DEFAULT
);
153 * Libwiretap must be initialized before libwireshark is, so that
154 * dissection-time handlers for file-type-dependent blocks can
155 * register using the file type/subtype value for the file type.
159 /* Register all dissectors; we must do this before checking for the
160 "-G" flag, as the "-G" flag dumps information registered by the
161 dissectors, and we must do it before we read the preferences, in
162 case any dissectors register preferences. */
163 if (!epan_init(NULL
, NULL
, true)) {
164 ret
= SHARKD_EPAN_INIT_FAIL
;
170 /* Load libwireshark settings from the current profile. */
171 prefs_p
= epan_load_settings();
173 if (!color_filters_init(&err_msg
, NULL
)) {
174 fprintf(stderr
, "%s\n", err_msg
);
178 cap_file_init(&cfile
);
180 /* Notify all registered modules that have had any of their preferences
181 changed either from one of the preferences file or from the command
182 line that their preferences have changed. */
185 /* Build the column format array */
186 build_column_format_array(&cfile
.cinfo
, prefs_p
->num_cols
, true);
188 #ifdef HAVE_MAXMINDDB
189 /* 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.
190 * Need to stop it, otherwise all sharkd will have same mmdbresolve process, including pipe descriptors to read and write. */
191 uat_get_table_by_name("MaxMind Database Paths")->reset_cb();
194 ret
= sharkd_loop(argc
, argv
);
196 col_cleanup(&cfile
.cinfo
);
204 sharkd_epan_new(capture_file
*cf
)
206 static const struct packet_provider_funcs funcs
= {
207 cap_file_provider_get_frame_ts
,
208 cap_file_provider_get_interface_name
,
209 cap_file_provider_get_interface_description
,
210 cap_file_provider_get_modified_block
213 return epan_new(&cf
->provider
, &funcs
);
217 process_packet(capture_file
*cf
, epan_dissect_t
*edt
,
218 int64_t offset
, wtap_rec
*rec
, Buffer
*buf
)
223 /* If we're not running a display filter and we're not printing any
224 packet information, we don't need to do a dissection. This means
225 that all packets can be marked as 'passed'. */
228 /* The frame number of this packet, if we add it to the set of frames,
229 would be one more than the count of frames in the file so far. */
230 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cum_bytes
);
232 /* If we're going to print packet information, or we're going to
233 run a read filter, or display filter, or we're going to process taps, set up to
234 do a dissection and do so. */
236 if (gbl_resolv_flags
.mac_name
|| gbl_resolv_flags
.network_name
||
237 gbl_resolv_flags
.transport_name
)
238 /* Grab any resolved addresses */
239 host_name_lookup_process();
241 /* If we're running a read filter, prime the epan_dissect_t with that
244 epan_dissect_prime_with_dfilter(edt
, cf
->rfcode
);
247 epan_dissect_prime_with_dfilter(edt
, cf
->dfcode
);
249 /* This is the first and only pass, so prime the epan_dissect_t
250 with the hfids postdissectors want on the first pass. */
251 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
253 frame_data_set_before_dissect(&fdlocal
, &cf
->elapsed_time
,
254 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
255 if (cf
->provider
.ref
== &fdlocal
) {
257 cf
->provider
.ref
= &ref_frame
;
260 epan_dissect_run(edt
, cf
->cd_t
, rec
,
261 frame_tvbuff_new_buffer(&cf
->provider
, &fdlocal
, buf
),
264 /* Run the read filter if we have one. */
266 passed
= dfilter_apply_edt(cf
->rfcode
, edt
);
270 frame_data_set_after_dissect(&fdlocal
, &cum_bytes
);
271 cf
->provider
.prev_cap
= cf
->provider
.prev_dis
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
273 /* If we're not doing dissection then there won't be any dependent frames.
274 * More importantly, edt.pi.fd.dependent_frames won't be initialized because
275 * epan hasn't been initialized.
276 * if we *are* doing dissection, then mark the dependent frames, but only
277 * if a display filter was given and it matches this packet.
279 if (edt
&& cf
->dfcode
) {
280 if (dfilter_apply_edt(cf
->dfcode
, edt
) && edt
->pi
.fd
->dependent_frames
) {
281 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
287 /* if we don't add it to the frame_data_sequence, clean it up right now
289 frame_data_destroy(&fdlocal
);
293 epan_dissect_reset(edt
);
300 load_cap_file(capture_file
*cf
, int max_packet_count
, int64_t max_byte_count
)
303 char *err_info
= NULL
;
307 epan_dissect_t
*edt
= NULL
;
310 /* Allocate a frame_data_sequence for all the frames. */
311 cf
->provider
.frames
= new_frame_data_sequence();
314 bool create_proto_tree
;
317 * Determine whether we need to create a protocol tree.
320 * we're going to apply a read filter;
322 * we're going to apply a display filter;
324 * a postdissector wants field values or protocols
328 (cf
->rfcode
!= NULL
|| cf
->dfcode
!= NULL
|| postdissectors_want_hfids());
330 /* We're not going to display the protocol tree on this pass,
331 so it's not going to be "visible". */
332 edt
= epan_dissect_new(cf
->epan
, create_proto_tree
, false);
336 ws_buffer_init(&buf
, 1514);
338 while (wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
, &data_offset
)) {
339 if (process_packet(cf
, edt
, data_offset
, &rec
, &buf
)) {
340 wtap_rec_reset(&rec
);
341 /* Stop reading if we have the maximum number of packets;
342 * When the -c option has not been used, max_packet_count
343 * starts at 0, which practically means, never stop reading.
344 * (unless we roll over max_packet_count ?)
346 if ( (--max_packet_count
== 0) || (max_byte_count
!= 0 && data_offset
>= max_byte_count
)) {
347 err
= 0; /* This is not an error */
354 epan_dissect_free(edt
);
358 wtap_rec_cleanup(&rec
);
359 ws_buffer_free(&buf
);
361 /* Close the sequential I/O side, to free up memory it requires. */
362 wtap_sequential_close(cf
->provider
.wth
);
364 /* Allow the protocol dissectors to free up memory that they
365 * don't need after the sequential run-through of the packets. */
366 postseq_cleanup_all_protocols();
368 cf
->provider
.prev_dis
= NULL
;
369 cf
->provider
.prev_cap
= NULL
;
373 cfile_read_failure_message(cf
->filename
, err
, err_info
);
380 cf_open(capture_file
*cf
, const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
385 wth
= wtap_open_offline(fname
, type
, err
, &err_info
, true);
389 /* The open succeeded. Fill in the information for this file. */
391 cf
->provider
.wth
= wth
;
392 cf
->f_datalen
= 0; /* not used, but set it anyway */
394 /* Set the file name because we need it to set the follow stream filter.
395 XXX - is that still true? We need it for other reasons, though,
397 cf
->filename
= g_strdup(fname
);
399 /* Indicate whether it's a permanent or temporary file. */
400 cf
->is_tempfile
= is_tempfile
;
402 /* No user changes yet. */
403 cf
->unsaved_changes
= false;
405 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
406 cf
->open_type
= type
;
408 cf
->drops_known
= false;
410 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
411 nstime_set_zero(&cf
->elapsed_time
);
412 cf
->provider
.ref
= NULL
;
413 cf
->provider
.prev_dis
= NULL
;
414 cf
->provider
.prev_cap
= NULL
;
416 /* Create new epan session for dissection. */
418 cf
->epan
= sharkd_epan_new(cf
);
420 cf
->state
= FILE_READ_IN_PROGRESS
;
422 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
423 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
424 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
429 cfile_open_failure_message(fname
, *err
, err_info
);
434 * Report an error in command-line arguments.
437 sharkd_cmdarg_err(const char *msg_format
, va_list ap
)
439 fprintf(stderr
, "sharkd: ");
440 vfprintf(stderr
, msg_format
, ap
);
441 fprintf(stderr
, "\n");
445 * Report additional information for an error in command-line arguments.
448 sharkd_cmdarg_err_cont(const char *msg_format
, va_list ap
)
450 vfprintf(stderr
, msg_format
, ap
);
451 fprintf(stderr
, "\n");
455 sharkd_cf_open(const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
457 return cf_open(&cfile
, fname
, type
, is_tempfile
, err
);
461 sharkd_load_cap_file(void)
463 return load_cap_file(&cfile
, 0, 0);
467 sharkd_get_frame(uint32_t framenum
)
469 return frame_data_sequence_find(cfile
.provider
.frames
, framenum
);
472 enum dissect_request_status
473 sharkd_dissect_request(uint32_t framenum
, uint32_t frame_ref_num
,
474 uint32_t prev_dis_num
, wtap_rec
*rec
, Buffer
*buf
,
475 column_info
*cinfo
, uint32_t dissect_flags
,
476 sharkd_dissect_func_t cb
, void *data
,
477 int *err
, char **err_info
)
481 bool create_proto_tree
;
483 fdata
= sharkd_get_frame(framenum
);
485 return DISSECT_REQUEST_NO_SUCH_FRAME
;
487 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, rec
, buf
, err
, err_info
)) {
489 col_fill_in_error(cinfo
, fdata
, false, false /* fill_fd_columns */);
490 return DISSECT_REQUEST_READ_ERROR
; /* error reading the record */
493 create_proto_tree
= ((dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ||
494 ((dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) && color_filters_used()) ||
495 (cinfo
&& have_custom_cols(cinfo
)));
496 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
));
498 if (dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) {
499 color_filters_prime_edt(&edt
);
500 fdata
->need_colorize
= 1;
504 col_custom_prime_edt(&edt
, cinfo
);
507 * XXX - need to catch an OutOfMemoryError exception and
508 * attempt to recover from it.
510 fdata
->ref_time
= (framenum
== frame_ref_num
);
511 fdata
->frame_ref_num
= frame_ref_num
;
512 fdata
->prev_dis_num
= prev_dis_num
;
513 epan_dissect_run(&edt
, cfile
.cd_t
, rec
,
514 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, buf
),
518 /* "Stringify" non frame_data vals */
519 epan_dissect_fill_in_columns(&edt
, false, true/* fill_fd_columns */);
522 cb(&edt
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ? edt
.tree
: NULL
,
523 cinfo
, (dissect_flags
& SHARKD_DISSECT_FLAG_BYTES
) ? edt
.pi
.data_src
: NULL
,
527 epan_dissect_cleanup(&edt
);
528 return DISSECT_REQUEST_SUCCESS
;
539 char *err_info
= NULL
;
542 bool create_proto_tree
;
546 /* Get the union of the flags for all tap listeners. */
547 tap_flags
= union_of_tap_listener_flags();
549 /* If any tap listeners require the columns, construct them. */
550 cinfo
= (tap_listeners_require_columns()) ? &cfile
.cinfo
: NULL
;
553 * Determine whether we need to create a protocol tree.
556 * one of the tap listeners is going to apply a filter;
558 * one of the tap listeners requires a protocol tree.
561 (have_filtering_tap_listeners() || (tap_flags
& TL_REQUIRES_PROTO_TREE
));
564 ws_buffer_init(&buf
, 1514);
565 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, false);
567 reset_tap_listeners();
569 for (framenum
= 1; framenum
<= cfile
.count
; framenum
++) {
570 fdata
= sharkd_get_frame(framenum
);
572 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
575 fdata
->ref_time
= false;
576 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
577 fdata
->prev_dis_num
= framenum
- 1;
578 epan_dissect_run_with_taps(&edt
, cfile
.cd_t
, &rec
,
579 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
581 wtap_rec_reset(&rec
);
582 epan_dissect_reset(&edt
);
585 wtap_rec_cleanup(&rec
);
586 ws_buffer_free(&buf
);
587 epan_dissect_cleanup(&edt
);
589 draw_tap_listeners(true);
595 sharkd_filter(const char *dftext
, uint8_t **result
)
597 dfilter_t
*dfcode
= NULL
;
599 uint32_t framenum
, prev_dis_num
= 0;
600 uint32_t frames_count
;
604 char *err_info
= NULL
;
606 uint8_t *result_bits
;
611 if (!dfilter_compile(dftext
, &dfcode
, NULL
)) {
615 /* if dfilter_compile() success, but (dfcode == NULL) all frames are matching */
616 if (dfcode
== NULL
) {
621 frames_count
= cfile
.count
;
624 ws_buffer_init(&buf
, 1514);
625 epan_dissect_init(&edt
, cfile
.epan
, true, false);
628 result_bits
= (uint8_t *) g_malloc(2 + (frames_count
/ 8));
630 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
631 frame_data
*fdata
= sharkd_get_frame(framenum
);
633 if ((framenum
& 7) == 0) {
634 result_bits
[(framenum
/ 8) - 1] = passed_bits
;
638 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
641 /* frame_data_set_before_dissect */
642 epan_dissect_prime_with_dfilter(&edt
, dfcode
);
644 fdata
->ref_time
= false;
645 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
646 fdata
->prev_dis_num
= prev_dis_num
;
647 epan_dissect_run(&edt
, cfile
.cd_t
, &rec
,
648 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
651 if (dfilter_apply_edt(dfcode
, &edt
)) {
652 passed_bits
|= (1 << (framenum
% 8));
653 prev_dis_num
= framenum
;
656 /* if passed or ref -> frame_data_set_after_dissect */
658 wtap_rec_reset(&rec
);
659 epan_dissect_reset(&edt
);
662 if ((framenum
& 7) == 0)
664 result_bits
[framenum
/ 8] = passed_bits
;
666 wtap_rec_cleanup(&rec
);
667 ws_buffer_free(&buf
);
668 epan_dissect_cleanup(&edt
);
670 dfilter_free(dfcode
);
672 *result
= result_bits
;
678 * Get the modified block if available, nothing otherwise.
679 * Must be cloned if changes desired.
682 sharkd_get_modified_block(const frame_data
*fd
)
684 return cap_file_provider_get_modified_block(&cfile
.provider
, fd
);
688 * Gets the modified block if available, otherwise the packet's default block,
689 * or a new packet block.
690 * User must wtap_block_unref() it when done.
693 sharkd_get_packet_block(const frame_data
*fd
)
695 if (fd
->has_modified_block
)
696 return wtap_block_ref(cap_file_provider_get_modified_block(&cfile
.provider
, fd
));
699 wtap_rec rec
; /* Record metadata */
700 Buffer buf
; /* Record data */
706 ws_buffer_init(&buf
, 1514);
708 if (!wtap_seek_read(cfile
.provider
.wth
, fd
->file_off
, &rec
, &buf
, &err
, &err_info
))
709 { /* XXX, what we can do here? */ }
711 /* rec.block is owned by the record, steal it before it is gone. */
712 block
= wtap_block_ref(rec
.block
);
714 wtap_rec_cleanup(&rec
);
715 ws_buffer_free(&buf
);
721 sharkd_set_modified_block(frame_data
*fd
, wtap_block_t new_block
)
723 cap_file_provider_set_modified_block(&cfile
.provider
, fd
, new_block
);