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 <epan/disabled_protos.h>
39 #include <epan/prefs.h>
40 #include <epan/column.h>
41 #include <epan/print.h>
42 #include <epan/addr_resolv.h>
44 #include "ui/ws_ui_util.h"
45 #include "ui/decode_as_utils.h"
46 #include "wsutil/filter_files.h"
47 #include "ui/tap_export_pdu.h"
48 #include "ui/failure_message.h"
49 #include <wiretap/wtap.h>
50 #include <epan/epan_dissect.h>
52 #include <epan/uat-int.h>
53 #include <epan/secrets.h>
55 #include <wsutil/codecs.h>
57 #include <wsutil/str_util.h>
58 #include <wsutil/utf8_entities.h>
61 #include <wsutil/plugins.h>
66 #define SHARKD_INIT_FAILED 1
67 #define SHARKD_EPAN_INIT_FAIL 2
71 static uint32_t cum_bytes
;
72 static frame_data ref_frame
;
75 print_current_user(void)
77 char *cur_user
, *cur_group
;
79 if (started_with_special_privs()) {
80 cur_user
= get_cur_username();
81 cur_group
= get_cur_groupname();
82 fprintf(stderr
, "Running as user \"%s\" and group \"%s\".",
86 if (running_with_special_privs()) {
87 fprintf(stderr
, " This could be dangerous.");
89 fprintf(stderr
, "\n");
94 main(int argc
, char *argv
[])
96 char *configuration_init_error
;
100 int ret
= EXIT_SUCCESS
;
102 /* Set the program name. */
103 g_set_prgname("sharkd");
105 cmdarg_err_init(stderr_cmdarg_err
, stderr_cmdarg_err_cont
);
107 /* Initialize log handler early so we can have proper logging during startup. */
108 ws_log_init(vcmdarg_err
);
110 /* Early logging command-line initialization. */
111 ws_log_parse_args(&argc
, argv
, vcmdarg_err
, SHARKD_INIT_FAILED
);
113 ws_noisy("Finished log init and parsing command line log arguments");
116 * Get credential information for later use, and drop privileges
117 * before doing anything else.
118 * Let the user know if anything happened.
120 init_process_policies();
121 relinquish_special_privs_perm();
122 print_current_user();
125 * Attempt to get the pathname of the executable file.
127 configuration_init_error
= configuration_init(argv
[0]);
128 if (configuration_init_error
!= NULL
) {
129 fprintf(stderr
, "sharkd: Can't get pathname of sharkd program: %s.\n",
130 configuration_init_error
);
133 /* Initialize the version information. */
134 ws_init_version_info("Sharkd",
135 epan_gather_compile_info
,
136 epan_gather_runtime_info
);
138 if (sharkd_init(argc
, argv
) < 0)
140 fputs("Cannot initialize sharkd.\n", stderr
);
141 ret
= SHARKD_INIT_FAILED
;
145 init_report_failure_message("sharkd");
147 timestamp_set_type(TS_RELATIVE
);
148 timestamp_set_precision(TS_PREC_AUTO
);
149 timestamp_set_seconds_type(TS_SECONDS_DEFAULT
);
152 * Libwiretap must be initialized before libwireshark is, so that
153 * dissection-time handlers for file-type-dependent blocks can
154 * register using the file type/subtype value for the file type.
158 /* Register all dissectors; we must do this before checking for the
159 "-G" flag, as the "-G" flag dumps information registered by the
160 dissectors, and we must do it before we read the preferences, in
161 case any dissectors register preferences. */
162 if (!epan_init(NULL
, NULL
, true)) {
163 ret
= SHARKD_EPAN_INIT_FAIL
;
169 /* Load libwireshark settings from the current profile. */
170 prefs_p
= epan_load_settings();
172 if (!color_filters_init(&err_msg
, NULL
)) {
173 fprintf(stderr
, "%s\n", err_msg
);
177 cap_file_init(&cfile
);
179 /* Notify all registered modules that have had any of their preferences
180 changed either from one of the preferences file or from the command
181 line that their preferences have changed. */
184 /* Build the column format array */
185 build_column_format_array(&cfile
.cinfo
, prefs_p
->num_cols
, true);
187 #ifdef HAVE_MAXMINDDB
188 /* 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.
189 * Need to stop it, otherwise all sharkd will have same mmdbresolve process, including pipe descriptors to read and write. */
190 uat_get_table_by_name("MaxMind Database Paths")->reset_cb();
193 ret
= sharkd_loop(argc
, argv
);
195 col_cleanup(&cfile
.cinfo
);
203 sharkd_epan_new(capture_file
*cf
)
205 static const struct packet_provider_funcs funcs
= {
206 cap_file_provider_get_frame_ts
,
207 cap_file_provider_get_interface_name
,
208 cap_file_provider_get_interface_description
,
209 cap_file_provider_get_modified_block
212 return epan_new(&cf
->provider
, &funcs
);
216 process_packet(capture_file
*cf
, epan_dissect_t
*edt
, int64_t offset
,
222 /* If we're not running a display filter and we're not printing any
223 packet information, we don't need to do a dissection. This means
224 that all packets can be marked as 'passed'. */
227 /* The frame number of this packet, if we add it to the set of frames,
228 would be one more than the count of frames in the file so far. */
229 frame_data_init(&fdlocal
, cf
->count
+ 1, rec
, offset
, cum_bytes
);
231 /* If we're going to print packet information, or we're going to
232 run a read filter, or display filter, or we're going to process taps, set up to
233 do a dissection and do so. */
235 if (gbl_resolv_flags
.mac_name
|| gbl_resolv_flags
.network_name
||
236 gbl_resolv_flags
.transport_name
)
237 /* Grab any resolved addresses */
238 host_name_lookup_process();
240 /* If we're running a read filter, prime the epan_dissect_t with that
243 epan_dissect_prime_with_dfilter(edt
, cf
->rfcode
);
246 epan_dissect_prime_with_dfilter(edt
, cf
->dfcode
);
248 /* This is the first and only pass, so prime the epan_dissect_t
249 with the hfids postdissectors want on the first pass. */
250 prime_epan_dissect_with_postdissector_wanted_hfids(edt
);
252 frame_data_set_before_dissect(&fdlocal
, &cf
->elapsed_time
,
253 &cf
->provider
.ref
, cf
->provider
.prev_dis
);
254 if (cf
->provider
.ref
== &fdlocal
) {
256 cf
->provider
.ref
= &ref_frame
;
259 epan_dissect_run(edt
, cf
->cd_t
, rec
, &fdlocal
, NULL
);
261 /* Run the read filter if we have one. */
263 passed
= dfilter_apply_edt(cf
->rfcode
, edt
);
267 frame_data_set_after_dissect(&fdlocal
, &cum_bytes
);
268 cf
->provider
.prev_cap
= cf
->provider
.prev_dis
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
270 /* If we're not doing dissection then there won't be any dependent frames.
271 * More importantly, edt.pi.fd.dependent_frames won't be initialized because
272 * epan hasn't been initialized.
273 * if we *are* doing dissection, then mark the dependent frames, but only
274 * if a display filter was given and it matches this packet.
276 if (edt
&& cf
->dfcode
) {
277 if (dfilter_apply_edt(cf
->dfcode
, edt
) && edt
->pi
.fd
->dependent_frames
) {
278 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
284 /* if we don't add it to the frame_data_sequence, clean it up right now
286 frame_data_destroy(&fdlocal
);
290 epan_dissect_reset(edt
);
297 load_cap_file(capture_file
*cf
, int max_packet_count
, int64_t max_byte_count
)
300 char *err_info
= NULL
;
303 epan_dissect_t
*edt
= NULL
;
306 /* Allocate a frame_data_sequence for all the frames. */
307 cf
->provider
.frames
= new_frame_data_sequence();
310 bool create_proto_tree
;
313 * Determine whether we need to create a protocol tree.
316 * we're going to apply a read filter;
318 * we're going to apply a display filter;
320 * a postdissector wants field values or protocols
324 (cf
->rfcode
!= NULL
|| cf
->dfcode
!= NULL
|| postdissectors_want_hfids());
326 /* We're not going to display the protocol tree on this pass,
327 so it's not going to be "visible". */
328 edt
= epan_dissect_new(cf
->epan
, create_proto_tree
, false);
331 wtap_rec_init(&rec
, 1514);
333 while (wtap_read(cf
->provider
.wth
, &rec
, &err
, &err_info
, &data_offset
)) {
334 if (process_packet(cf
, edt
, data_offset
, &rec
)) {
335 wtap_rec_reset(&rec
);
336 /* Stop reading if we have the maximum number of packets;
337 * When the -c option has not been used, max_packet_count
338 * starts at 0, which practically means, never stop reading.
339 * (unless we roll over max_packet_count ?)
341 if ( (--max_packet_count
== 0) || (max_byte_count
!= 0 && data_offset
>= max_byte_count
)) {
342 err
= 0; /* This is not an error */
349 epan_dissect_free(edt
);
353 wtap_rec_cleanup(&rec
);
355 /* Close the sequential I/O side, to free up memory it requires. */
356 wtap_sequential_close(cf
->provider
.wth
);
358 /* Allow the protocol dissectors to free up memory that they
359 * don't need after the sequential run-through of the packets. */
360 postseq_cleanup_all_protocols();
362 cf
->provider
.prev_dis
= NULL
;
363 cf
->provider
.prev_cap
= NULL
;
367 cfile_read_failure_message(cf
->filename
, err
, err_info
);
374 cf_open(capture_file
*cf
, const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
379 wth
= wtap_open_offline(fname
, type
, err
, &err_info
, true);
383 /* The open succeeded. Fill in the information for this file. */
385 cf
->provider
.wth
= wth
;
386 cf
->f_datalen
= 0; /* not used, but set it anyway */
388 /* Set the file name because we need it to set the follow stream filter.
389 XXX - is that still true? We need it for other reasons, though,
391 cf
->filename
= g_strdup(fname
);
393 /* Indicate whether it's a permanent or temporary file. */
394 cf
->is_tempfile
= is_tempfile
;
396 /* No user changes yet. */
397 cf
->unsaved_changes
= false;
399 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
400 cf
->open_type
= type
;
402 cf
->drops_known
= false;
404 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
405 nstime_set_zero(&cf
->elapsed_time
);
406 cf
->provider
.ref
= NULL
;
407 cf
->provider
.prev_dis
= NULL
;
408 cf
->provider
.prev_cap
= NULL
;
410 /* Create new epan session for dissection. */
412 cf
->epan
= sharkd_epan_new(cf
);
414 cf
->state
= FILE_READ_IN_PROGRESS
;
416 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
417 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
418 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
423 cfile_open_failure_message(fname
, *err
, err_info
);
428 sharkd_cf_open(const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
430 return cf_open(&cfile
, fname
, type
, is_tempfile
, err
);
434 sharkd_load_cap_file(void)
436 return load_cap_file(&cfile
, 0, 0);
440 sharkd_get_frame(uint32_t framenum
)
442 return frame_data_sequence_find(cfile
.provider
.frames
, framenum
);
445 enum dissect_request_status
446 sharkd_dissect_request(uint32_t framenum
, uint32_t frame_ref_num
,
447 uint32_t prev_dis_num
, wtap_rec
*rec
,
448 column_info
*cinfo
, uint32_t dissect_flags
,
449 sharkd_dissect_func_t cb
, void *data
,
450 int *err
, char **err_info
)
454 bool create_proto_tree
;
456 fdata
= sharkd_get_frame(framenum
);
458 return DISSECT_REQUEST_NO_SUCH_FRAME
;
460 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, rec
, err
, err_info
)) {
462 col_fill_in_error(cinfo
, fdata
, false, false /* fill_fd_columns */);
463 return DISSECT_REQUEST_READ_ERROR
; /* error reading the record */
466 create_proto_tree
= ((dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ||
467 ((dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) && color_filters_used()) ||
468 (cinfo
&& have_custom_cols(cinfo
)));
469 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
));
471 if (dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) {
472 color_filters_prime_edt(&edt
);
473 fdata
->need_colorize
= 1;
477 col_custom_prime_edt(&edt
, cinfo
);
480 * XXX - need to catch an OutOfMemoryError exception and
481 * attempt to recover from it.
483 fdata
->ref_time
= (framenum
== frame_ref_num
);
484 fdata
->frame_ref_num
= frame_ref_num
;
485 fdata
->prev_dis_num
= prev_dis_num
;
486 epan_dissect_run(&edt
, cfile
.cd_t
, rec
, fdata
, cinfo
);
489 /* "Stringify" non frame_data vals */
490 epan_dissect_fill_in_columns(&edt
, false, true/* fill_fd_columns */);
493 cb(&edt
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ? edt
.tree
: NULL
,
494 cinfo
, (dissect_flags
& SHARKD_DISSECT_FLAG_BYTES
) ? edt
.pi
.data_src
: NULL
,
498 epan_dissect_cleanup(&edt
);
499 return DISSECT_REQUEST_SUCCESS
;
509 char *err_info
= NULL
;
512 bool create_proto_tree
;
516 /* Get the union of the flags for all tap listeners. */
517 tap_flags
= union_of_tap_listener_flags();
519 /* If any tap listeners require the columns, construct them. */
520 cinfo
= (tap_listeners_require_columns()) ? &cfile
.cinfo
: NULL
;
523 * Determine whether we need to create a protocol tree.
526 * one of the tap listeners is going to apply a filter;
528 * one of the tap listeners requires a protocol tree.
531 (have_filtering_tap_listeners() || (tap_flags
& TL_REQUIRES_PROTO_TREE
));
533 wtap_rec_init(&rec
, 1514);
534 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, false);
536 reset_tap_listeners();
538 for (framenum
= 1; framenum
<= cfile
.count
; framenum
++) {
539 fdata
= sharkd_get_frame(framenum
);
541 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &err
, &err_info
))
544 fdata
->ref_time
= false;
545 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
546 fdata
->prev_dis_num
= framenum
- 1;
547 epan_dissect_run_with_taps(&edt
, cfile
.cd_t
, &rec
, fdata
, cinfo
);
548 wtap_rec_reset(&rec
);
549 epan_dissect_reset(&edt
);
552 wtap_rec_cleanup(&rec
);
553 epan_dissect_cleanup(&edt
);
555 draw_tap_listeners(true);
561 sharkd_filter(const char *dftext
, uint8_t **result
)
563 dfilter_t
*dfcode
= NULL
;
565 uint32_t framenum
, prev_dis_num
= 0;
566 uint32_t frames_count
;
569 char *err_info
= NULL
;
571 uint8_t *result_bits
;
576 if (!dfilter_compile(dftext
, &dfcode
, NULL
)) {
580 /* if dfilter_compile() success, but (dfcode == NULL) all frames are matching */
581 if (dfcode
== NULL
) {
586 frames_count
= cfile
.count
;
588 wtap_rec_init(&rec
, 1514);
589 epan_dissect_init(&edt
, cfile
.epan
, true, false);
592 result_bits
= (uint8_t *) g_malloc(2 + (frames_count
/ 8));
594 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
595 frame_data
*fdata
= sharkd_get_frame(framenum
);
597 if ((framenum
& 7) == 0) {
598 result_bits
[(framenum
/ 8) - 1] = passed_bits
;
602 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &err
, &err_info
))
605 /* frame_data_set_before_dissect */
606 epan_dissect_prime_with_dfilter(&edt
, dfcode
);
608 fdata
->ref_time
= false;
609 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
610 fdata
->prev_dis_num
= prev_dis_num
;
611 epan_dissect_run(&edt
, cfile
.cd_t
, &rec
, fdata
, NULL
);
613 if (dfilter_apply_edt(dfcode
, &edt
)) {
614 passed_bits
|= (1 << (framenum
% 8));
615 prev_dis_num
= framenum
;
618 /* if passed or ref -> frame_data_set_after_dissect */
620 wtap_rec_reset(&rec
);
621 epan_dissect_reset(&edt
);
624 if ((framenum
& 7) == 0)
626 result_bits
[framenum
/ 8] = passed_bits
;
628 wtap_rec_cleanup(&rec
);
629 epan_dissect_cleanup(&edt
);
631 dfilter_free(dfcode
);
633 *result
= result_bits
;
639 * Get the modified block if available, nothing otherwise.
640 * Must be cloned if changes desired.
643 sharkd_get_modified_block(const frame_data
*fd
)
645 return cap_file_provider_get_modified_block(&cfile
.provider
, fd
);
649 * Gets the modified block if available, otherwise the packet's default block,
650 * or a new packet block.
651 * User must wtap_block_unref() it when done.
654 sharkd_get_packet_block(const frame_data
*fd
)
656 if (fd
->has_modified_block
)
657 return wtap_block_ref(cap_file_provider_get_modified_block(&cfile
.provider
, fd
));
660 wtap_rec rec
; /* Record information */
665 wtap_rec_init(&rec
, 1514);
667 if (!wtap_seek_read(cfile
.provider
.wth
, fd
->file_off
, &rec
, &err
, &err_info
))
668 { /* XXX, what we can do here? */ }
670 /* rec.block is owned by the record, steal it before it is gone. */
671 block
= wtap_block_ref(rec
.block
);
673 wtap_rec_cleanup(&rec
);
679 sharkd_set_modified_block(frame_data
*fd
, wtap_block_t new_block
)
681 cap_file_provider_set_modified_block(&cfile
.provider
, fd
, new_block
);