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
23 #include <epan/exceptions.h>
24 #include <epan/epan.h>
26 #include <ui/clopts_common.h>
27 #include <ui/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 <version_info.h>
33 #include <wiretap/wtap_opttypes.h>
34 #include <wiretap/pcapng.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 "ui/filter_files.h"
49 #include "ui/tap_export_pdu.h"
50 #include "ui/failure_message.h"
51 #include <epan/epan_dissect.h>
53 #include <epan/uat-int.h>
54 #include <epan/secrets.h>
56 #include <wsutil/codecs.h>
60 #include <wsutil/str_util.h>
61 #include <wsutil/utf8_entities.h>
64 #include <wsutil/plugins.h>
70 #define EPAN_INIT_FAIL 2
74 static guint32 cum_bytes
;
75 static frame_data ref_frame
;
77 static void failure_warning_message(const char *msg_format
, va_list ap
);
78 static void open_failure_message(const char *filename
, int err
,
79 gboolean for_writing
);
80 static void read_failure_message(const char *filename
, int err
);
81 static void write_failure_message(const char *filename
, int err
);
82 static void failure_message_cont(const char *msg_format
, va_list ap
);
85 print_current_user(void) {
86 gchar
*cur_user
, *cur_group
;
88 if (started_with_special_privs()) {
89 cur_user
= get_cur_username();
90 cur_group
= get_cur_groupname();
91 fprintf(stderr
, "Running as user \"%s\" and group \"%s\".",
95 if (running_with_special_privs()) {
96 fprintf(stderr
, " This could be dangerous.");
98 fprintf(stderr
, "\n");
103 main(int argc
, char *argv
[])
105 char *init_progfile_dir_error
;
107 char *err_msg
= NULL
;
109 int ret
= EXIT_SUCCESS
;
111 cmdarg_err_init(failure_warning_message
, failure_message_cont
);
114 * Get credential information for later use, and drop privileges
115 * before doing anything else.
116 * Let the user know if anything happened.
118 init_process_policies();
119 relinquish_special_privs_perm();
120 print_current_user();
123 * Attempt to get the pathname of the executable file.
125 init_progfile_dir_error
= init_progfile_dir(argv
[0]);
126 if (init_progfile_dir_error
!= NULL
) {
127 fprintf(stderr
, "sharkd: Can't get pathname of sharkd program: %s.\n",
128 init_progfile_dir_error
);
131 /* Initialize the version information. */
132 ws_init_version_info("Sharkd (Wireshark)", NULL
,
133 epan_get_compiled_version_info
,
134 epan_get_runtime_version_info
);
136 if (sharkd_init(argc
, argv
) < 0)
138 printf("cannot initialize sharkd\n");
143 init_report_message(failure_warning_message
, failure_warning_message
,
144 open_failure_message
, read_failure_message
,
145 write_failure_message
);
147 timestamp_set_type(TS_RELATIVE
);
148 timestamp_set_precision(TS_PREC_AUTO
);
149 timestamp_set_seconds_type(TS_SECONDS_DEFAULT
);
153 /* Register all dissectors; we must do this before checking for the
154 "-G" flag, as the "-G" flag dumps information registered by the
155 dissectors, and we must do it before we read the preferences, in
156 case any dissectors register preferences. */
157 if (!epan_init(NULL
, NULL
, TRUE
)) {
158 ret
= EPAN_INIT_FAIL
;
164 /* Load libwireshark settings from the current profile. */
165 prefs_p
= epan_load_settings();
167 read_filter_list(CFILTER_LIST
);
169 if (!color_filters_init(&err_msg
, NULL
)) {
170 fprintf(stderr
, "%s\n", err_msg
);
174 cap_file_init(&cfile
);
176 /* Notify all registered modules that have had any of their preferences
177 changed either from one of the preferences file or from the command
178 line that their preferences have changed. */
181 /* Build the column format array */
182 build_column_format_array(&cfile
.cinfo
, prefs_p
->num_cols
, TRUE
);
184 #ifdef HAVE_MAXMINDDB
185 /* 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.
186 * Need to stop it, otherwise all sharkd will have same mmdbresolve process, including pipe descriptors to read and write. */
187 uat_clear(uat_get_table_by_name("MaxMind Database Paths"));
192 col_cleanup(&cfile
.cinfo
);
200 static const nstime_t
*
201 sharkd_get_frame_ts(struct packet_provider_data
*prov
, guint32 frame_num
)
203 if (prov
->ref
&& prov
->ref
->num
== frame_num
)
204 return &prov
->ref
->abs_ts
;
206 if (prov
->prev_dis
&& prov
->prev_dis
->num
== frame_num
)
207 return &prov
->prev_dis
->abs_ts
;
209 if (prov
->prev_cap
&& prov
->prev_cap
->num
== frame_num
)
210 return &prov
->prev_cap
->abs_ts
;
213 frame_data
*fd
= frame_data_sequence_find(prov
->frames
, frame_num
);
215 return (fd
) ? &fd
->abs_ts
: NULL
;
222 sharkd_epan_new(capture_file
*cf
)
224 static const struct packet_provider_funcs funcs
= {
226 cap_file_provider_get_interface_name
,
227 cap_file_provider_get_interface_description
,
228 cap_file_provider_get_user_comment
231 return epan_new(&cf
->provider
, &funcs
);
235 process_packet(capture_file
*cf
, epan_dissect_t
*edt
,
236 gint64 offset
, wtap_rec
*rec
, Buffer
*buf
)
241 /* If we're not running a display filter and we're not printing any
242 packet information, we don't need to do a dissection. This means
243 that all packets can be marked as 'passed'. */
246 /* The frame number of this packet, if we add it to the set of frames,
247 would be one more than the count of frames in the file so far. */
248 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cum_bytes
);
250 /* If we're going to print packet information, or we're going to
251 run a read filter, or display filter, or we're going to process taps, set up to
252 do a dissection and do so. */
254 if (gbl_resolv_flags
.mac_name
|| gbl_resolv_flags
.network_name
||
255 gbl_resolv_flags
.transport_name
)
256 /* Grab any resolved addresses */
257 host_name_lookup_process();
259 /* If we're running a read filter, prime the epan_dissect_t with that
262 epan_dissect_prime_with_dfilter(edt
, cf
->rfcode
);
265 epan_dissect_prime_with_dfilter(edt
, cf
->dfcode
);
267 /* This is the first and only pass, so prime the epan_dissect_t
268 with the hfids postdissectors want on the first pass. */
269 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
271 frame_data_set_before_dissect(&fdlocal
, &cf
->elapsed_time
,
272 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
273 if (cf
->provider
.ref
== &fdlocal
) {
275 cf
->provider
.ref
= &ref_frame
;
278 epan_dissect_run(edt
, cf
->cd_t
, rec
,
279 frame_tvbuff_new_buffer(&cf
->provider
, &fdlocal
, buf
),
282 /* Run the read filter if we have one. */
284 passed
= dfilter_apply_edt(cf
->rfcode
, edt
);
288 frame_data_set_after_dissect(&fdlocal
, &cum_bytes
);
289 cf
->provider
.prev_cap
= cf
->provider
.prev_dis
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
291 /* If we're not doing dissection then there won't be any dependent frames.
292 * More importantly, edt.pi.dependent_frames won't be initialized because
293 * epan hasn't been initialized.
294 * if we *are* doing dissection, then mark the dependent frames, but only
295 * if a display filter was given and it matches this packet.
297 if (edt
&& cf
->dfcode
) {
298 if (dfilter_apply_edt(cf
->dfcode
, edt
)) {
299 g_slist_foreach(edt
->pi
.dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
305 /* if we don't add it to the frame_data_sequence, clean it up right now
307 frame_data_destroy(&fdlocal
);
311 epan_dissect_reset(edt
);
318 load_cap_file(capture_file
*cf
, int max_packet_count
, gint64 max_byte_count
)
321 gchar
*err_info
= NULL
;
325 epan_dissect_t
*edt
= NULL
;
328 /* Allocate a frame_data_sequence for all the frames. */
329 cf
->provider
.frames
= new_frame_data_sequence();
332 gboolean create_proto_tree
;
335 * Determine whether we need to create a protocol tree.
338 * we're going to apply a read filter;
340 * we're going to apply a display filter;
342 * a postdissector wants field values or protocols
346 (cf
->rfcode
!= NULL
|| cf
->dfcode
!= NULL
|| postdissectors_want_hfids());
348 /* We're not going to display the protocol tree on this pass,
349 so it's not going to be "visible". */
350 edt
= epan_dissect_new(cf
->epan
, create_proto_tree
, FALSE
);
354 ws_buffer_init(&buf
, 1514);
356 while (wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
, &data_offset
)) {
357 if (process_packet(cf
, edt
, data_offset
, &rec
, &buf
)) {
358 /* Stop reading if we have the maximum number of packets;
359 * When the -c option has not been used, max_packet_count
360 * starts at 0, which practically means, never stop reading.
361 * (unless we roll over max_packet_count ?)
363 if ( (--max_packet_count
== 0) || (max_byte_count
!= 0 && data_offset
>= max_byte_count
)) {
364 err
= 0; /* This is not an error */
371 epan_dissect_free(edt
);
375 wtap_rec_cleanup(&rec
);
376 ws_buffer_free(&buf
);
378 /* Close the sequential I/O side, to free up memory it requires. */
379 wtap_sequential_close(cf
->provider
.wth
);
381 /* Allow the protocol dissectors to free up memory that they
382 * don't need after the sequential run-through of the packets. */
383 postseq_cleanup_all_protocols();
385 cf
->provider
.prev_dis
= NULL
;
386 cf
->provider
.prev_cap
= NULL
;
390 cfile_read_failure_message("sharkd", cf
->filename
, err
, err_info
);
397 cf_open(capture_file
*cf
, const char *fname
, unsigned int type
, gboolean is_tempfile
, int *err
)
402 wth
= wtap_open_offline(fname
, type
, err
, &err_info
, TRUE
);
406 /* The open succeeded. Fill in the information for this file. */
408 cf
->provider
.wth
= wth
;
409 cf
->f_datalen
= 0; /* not used, but set it anyway */
411 /* Set the file name because we need it to set the follow stream filter.
412 XXX - is that still true? We need it for other reasons, though,
414 cf
->filename
= g_strdup(fname
);
416 /* Indicate whether it's a permanent or temporary file. */
417 cf
->is_tempfile
= is_tempfile
;
419 /* No user changes yet. */
420 cf
->unsaved_changes
= FALSE
;
422 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
423 cf
->open_type
= type
;
425 cf
->drops_known
= FALSE
;
427 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
428 nstime_set_zero(&cf
->elapsed_time
);
429 cf
->provider
.ref
= NULL
;
430 cf
->provider
.prev_dis
= NULL
;
431 cf
->provider
.prev_cap
= NULL
;
433 /* Create new epan session for dissection. */
435 cf
->epan
= sharkd_epan_new(cf
);
437 cf
->state
= FILE_READ_IN_PROGRESS
;
439 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
440 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
441 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
446 cfile_open_failure_message("sharkd", fname
, *err
, err_info
);
451 * General errors and warnings are reported with an console message
455 failure_warning_message(const char *msg_format
, va_list ap
)
457 fprintf(stderr
, "sharkd: ");
458 vfprintf(stderr
, msg_format
, ap
);
459 fprintf(stderr
, "\n");
463 * Open/create errors are reported with an console message in sharkd.
466 open_failure_message(const char *filename
, int err
, gboolean for_writing
)
468 fprintf(stderr
, "sharkd: ");
469 fprintf(stderr
, file_open_error_message(err
, for_writing
), filename
);
470 fprintf(stderr
, "\n");
474 * Read errors are reported with an console message in sharkd.
477 read_failure_message(const char *filename
, int err
)
479 cmdarg_err("An error occurred while reading from the file \"%s\": %s.",
480 filename
, g_strerror(err
));
484 * Write errors are reported with an console message in sharkd.
487 write_failure_message(const char *filename
, int err
)
489 cmdarg_err("An error occurred while writing to the file \"%s\": %s.",
490 filename
, g_strerror(err
));
494 * Report additional information for an error in command-line arguments.
497 failure_message_cont(const char *msg_format
, va_list ap
)
499 vfprintf(stderr
, msg_format
, ap
);
500 fprintf(stderr
, "\n");
504 sharkd_cf_open(const char *fname
, unsigned int type
, gboolean is_tempfile
, int *err
)
506 return cf_open(&cfile
, fname
, type
, is_tempfile
, err
);
510 sharkd_load_cap_file(void)
512 return load_cap_file(&cfile
, 0, 0);
516 sharkd_get_frame(guint32 framenum
)
518 return frame_data_sequence_find(cfile
.provider
.frames
, framenum
);
522 sharkd_dissect_request(guint32 framenum
, guint32 frame_ref_num
, guint32 prev_dis_num
, sharkd_dissect_func_t cb
, guint32 dissect_flags
, void *data
)
525 column_info
*cinfo
= (dissect_flags
& SHARKD_DISSECT_FLAG_COLUMNS
) ? &cfile
.cinfo
: NULL
;
527 gboolean create_proto_tree
;
528 wtap_rec rec
; /* Record metadata */
529 Buffer buf
; /* Record data */
532 char *err_info
= NULL
;
534 fdata
= sharkd_get_frame(framenum
);
539 ws_buffer_init(&buf
, 1514);
541 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
)) {
542 wtap_rec_cleanup(&rec
);
543 ws_buffer_free(&buf
);
544 return -1; /* error reading the record */
547 create_proto_tree
= ((dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ||
548 ((dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) && color_filters_used()) ||
549 (cinfo
&& have_custom_cols(cinfo
)));
550 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
));
552 if (dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) {
553 color_filters_prime_edt(&edt
);
554 fdata
->need_colorize
= 1;
558 col_custom_prime_edt(&edt
, cinfo
);
561 * XXX - need to catch an OutOfMemoryError exception and
562 * attempt to recover from it.
564 fdata
->ref_time
= (framenum
== frame_ref_num
);
565 fdata
->frame_ref_num
= frame_ref_num
;
566 fdata
->prev_dis_num
= prev_dis_num
;
567 epan_dissect_run(&edt
, cfile
.cd_t
, &rec
,
568 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
572 /* "Stringify" non frame_data vals */
573 epan_dissect_fill_in_columns(&edt
, FALSE
, TRUE
/* fill_fd_columns */);
576 cb(&edt
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ? edt
.tree
: NULL
,
577 cinfo
, (dissect_flags
& SHARKD_DISSECT_FLAG_BYTES
) ? edt
.pi
.data_src
: NULL
,
580 epan_dissect_cleanup(&edt
);
581 wtap_rec_cleanup(&rec
);
582 ws_buffer_free(&buf
);
586 /* based on packet_list_dissect_and_cache_record */
588 sharkd_dissect_columns(frame_data
*fdata
, guint32 frame_ref_num
, guint32 prev_dis_num
, column_info
*cinfo
, gboolean dissect_color
)
591 gboolean create_proto_tree
;
592 wtap_rec rec
; /* Record metadata */
593 Buffer buf
; /* Record data */
596 char *err_info
= NULL
;
599 ws_buffer_init(&buf
, 1514);
601 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
)) {
602 col_fill_in_error(cinfo
, fdata
, FALSE
, FALSE
/* fill_fd_columns */);
603 wtap_rec_cleanup(&rec
);
604 ws_buffer_free(&buf
);
605 return -1; /* error reading the record */
608 create_proto_tree
= (dissect_color
&& color_filters_used()) || (cinfo
&& have_custom_cols(cinfo
));
610 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, FALSE
/* proto_tree_visible */);
613 color_filters_prime_edt(&edt
);
614 fdata
->need_colorize
= 1;
618 col_custom_prime_edt(&edt
, cinfo
);
621 * XXX - need to catch an OutOfMemoryError exception and
622 * attempt to recover from it.
624 fdata
->ref_time
= (fdata
->num
== frame_ref_num
);
625 fdata
->frame_ref_num
= frame_ref_num
;
626 fdata
->prev_dis_num
= prev_dis_num
;
627 epan_dissect_run(&edt
, cfile
.cd_t
, &rec
,
628 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
632 /* "Stringify" non frame_data vals */
633 epan_dissect_fill_in_columns(&edt
, FALSE
, TRUE
/* fill_fd_columns */);
636 epan_dissect_cleanup(&edt
);
637 wtap_rec_cleanup(&rec
);
638 ws_buffer_free(&buf
);
650 char *err_info
= NULL
;
653 gboolean create_proto_tree
;
657 /* Get the union of the flags for all tap listeners. */
658 tap_flags
= union_of_tap_listener_flags();
660 /* If any tap listeners require the columns, construct them. */
661 cinfo
= (tap_flags
& TL_REQUIRES_COLUMNS
) ? &cfile
.cinfo
: NULL
;
664 * Determine whether we need to create a protocol tree.
667 * one of the tap listeners is going to apply a filter;
669 * one of the tap listeners requires a protocol tree.
672 (have_filtering_tap_listeners() || (tap_flags
& TL_REQUIRES_PROTO_TREE
));
675 ws_buffer_init(&buf
, 1514);
676 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, FALSE
);
678 reset_tap_listeners();
680 for (framenum
= 1; framenum
<= cfile
.count
; framenum
++) {
681 fdata
= sharkd_get_frame(framenum
);
683 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
686 fdata
->ref_time
= FALSE
;
687 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
688 fdata
->prev_dis_num
= framenum
- 1;
689 epan_dissect_run_with_taps(&edt
, cfile
.cd_t
, &rec
,
690 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
692 epan_dissect_reset(&edt
);
695 wtap_rec_cleanup(&rec
);
696 ws_buffer_free(&buf
);
697 epan_dissect_cleanup(&edt
);
699 draw_tap_listeners(TRUE
);
705 sharkd_filter(const char *dftext
, guint8
**result
)
707 dfilter_t
*dfcode
= NULL
;
709 guint32 framenum
, prev_dis_num
= 0;
710 guint32 frames_count
;
714 char *err_info
= NULL
;
721 if (!dfilter_compile(dftext
, &dfcode
, &err_info
)) {
726 /* if dfilter_compile() success, but (dfcode == NULL) all frames are matching */
727 if (dfcode
== NULL
) {
732 frames_count
= cfile
.count
;
735 ws_buffer_init(&buf
, 1514);
736 epan_dissect_init(&edt
, cfile
.epan
, TRUE
, FALSE
);
739 result_bits
= (guint8
*) g_malloc(2 + (frames_count
/ 8));
741 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
742 frame_data
*fdata
= sharkd_get_frame(framenum
);
744 if ((framenum
& 7) == 0) {
745 result_bits
[(framenum
/ 8) - 1] = passed_bits
;
749 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
752 /* frame_data_set_before_dissect */
753 epan_dissect_prime_with_dfilter(&edt
, dfcode
);
755 fdata
->ref_time
= FALSE
;
756 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
757 fdata
->prev_dis_num
= prev_dis_num
;
758 epan_dissect_run(&edt
, cfile
.cd_t
, &rec
,
759 frame_tvbuff_new_buffer(&cfile
.provider
, fdata
, &buf
),
762 if (dfilter_apply_edt(dfcode
, &edt
)) {
763 passed_bits
|= (1 << (framenum
% 8));
764 prev_dis_num
= framenum
;
767 /* if passed or ref -> frame_data_set_after_dissect */
769 epan_dissect_reset(&edt
);
772 if ((framenum
& 7) == 0)
774 result_bits
[framenum
/ 8] = passed_bits
;
776 wtap_rec_cleanup(&rec
);
777 ws_buffer_free(&buf
);
778 epan_dissect_cleanup(&edt
);
780 dfilter_free(dfcode
);
782 *result
= result_bits
;
788 sharkd_get_user_comment(const frame_data
*fd
)
790 return cap_file_provider_get_user_comment(&cfile
.provider
, fd
);
794 sharkd_set_user_comment(frame_data
*fd
, const gchar
*new_comment
)
796 cap_file_provider_set_user_comment(&cfile
.provider
, fd
, new_comment
);
801 const char *sharkd_version(void)
803 /* based on get_ws_vcs_version_info(), but shorter */
812 * Editor modelines - https://www.wireshark.org/tools/modelines.html
817 * indent-tabs-mode: nil
820 * vi: set shiftwidth=2 tabstop=8 expandtab:
821 * :indentSize=2:tabSize=8:noTabs=true: