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
,
217 int64_t offset
, wtap_rec
*rec
, Buffer
*buf
)
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
,
260 ws_buffer_start_ptr(buf
),
263 /* Run the read filter if we have one. */
265 passed
= dfilter_apply_edt(cf
->rfcode
, edt
);
269 frame_data_set_after_dissect(&fdlocal
, &cum_bytes
);
270 cf
->provider
.prev_cap
= cf
->provider
.prev_dis
= frame_data_sequence_add(cf
->provider
.frames
, &fdlocal
);
272 /* If we're not doing dissection then there won't be any dependent frames.
273 * More importantly, edt.pi.fd.dependent_frames won't be initialized because
274 * epan hasn't been initialized.
275 * if we *are* doing dissection, then mark the dependent frames, but only
276 * if a display filter was given and it matches this packet.
278 if (edt
&& cf
->dfcode
) {
279 if (dfilter_apply_edt(cf
->dfcode
, edt
) && edt
->pi
.fd
->dependent_frames
) {
280 g_hash_table_foreach(edt
->pi
.fd
->dependent_frames
, find_and_mark_frame_depended_upon
, cf
->provider
.frames
);
286 /* if we don't add it to the frame_data_sequence, clean it up right now
288 frame_data_destroy(&fdlocal
);
292 epan_dissect_reset(edt
);
299 load_cap_file(capture_file
*cf
, int max_packet_count
, int64_t max_byte_count
)
302 char *err_info
= NULL
;
306 epan_dissect_t
*edt
= NULL
;
309 /* Allocate a frame_data_sequence for all the frames. */
310 cf
->provider
.frames
= new_frame_data_sequence();
313 bool create_proto_tree
;
316 * Determine whether we need to create a protocol tree.
319 * we're going to apply a read filter;
321 * we're going to apply a display filter;
323 * a postdissector wants field values or protocols
327 (cf
->rfcode
!= NULL
|| cf
->dfcode
!= NULL
|| postdissectors_want_hfids());
329 /* We're not going to display the protocol tree on this pass,
330 so it's not going to be "visible". */
331 edt
= epan_dissect_new(cf
->epan
, create_proto_tree
, false);
335 ws_buffer_init(&buf
, 1514);
337 while (wtap_read(cf
->provider
.wth
, &rec
, &buf
, &err
, &err_info
, &data_offset
)) {
338 if (process_packet(cf
, edt
, data_offset
, &rec
, &buf
)) {
339 wtap_rec_reset(&rec
);
340 /* Stop reading if we have the maximum number of packets;
341 * When the -c option has not been used, max_packet_count
342 * starts at 0, which practically means, never stop reading.
343 * (unless we roll over max_packet_count ?)
345 if ( (--max_packet_count
== 0) || (max_byte_count
!= 0 && data_offset
>= max_byte_count
)) {
346 err
= 0; /* This is not an error */
353 epan_dissect_free(edt
);
357 wtap_rec_cleanup(&rec
);
358 ws_buffer_free(&buf
);
360 /* Close the sequential I/O side, to free up memory it requires. */
361 wtap_sequential_close(cf
->provider
.wth
);
363 /* Allow the protocol dissectors to free up memory that they
364 * don't need after the sequential run-through of the packets. */
365 postseq_cleanup_all_protocols();
367 cf
->provider
.prev_dis
= NULL
;
368 cf
->provider
.prev_cap
= NULL
;
372 cfile_read_failure_message(cf
->filename
, err
, err_info
);
379 cf_open(capture_file
*cf
, const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
384 wth
= wtap_open_offline(fname
, type
, err
, &err_info
, true);
388 /* The open succeeded. Fill in the information for this file. */
390 cf
->provider
.wth
= wth
;
391 cf
->f_datalen
= 0; /* not used, but set it anyway */
393 /* Set the file name because we need it to set the follow stream filter.
394 XXX - is that still true? We need it for other reasons, though,
396 cf
->filename
= g_strdup(fname
);
398 /* Indicate whether it's a permanent or temporary file. */
399 cf
->is_tempfile
= is_tempfile
;
401 /* No user changes yet. */
402 cf
->unsaved_changes
= false;
404 cf
->cd_t
= wtap_file_type_subtype(cf
->provider
.wth
);
405 cf
->open_type
= type
;
407 cf
->drops_known
= false;
409 cf
->snap
= wtap_snapshot_length(cf
->provider
.wth
);
410 nstime_set_zero(&cf
->elapsed_time
);
411 cf
->provider
.ref
= NULL
;
412 cf
->provider
.prev_dis
= NULL
;
413 cf
->provider
.prev_cap
= NULL
;
415 /* Create new epan session for dissection. */
417 cf
->epan
= sharkd_epan_new(cf
);
419 cf
->state
= FILE_READ_IN_PROGRESS
;
421 wtap_set_cb_new_ipv4(cf
->provider
.wth
, add_ipv4_name
);
422 wtap_set_cb_new_ipv6(cf
->provider
.wth
, (wtap_new_ipv6_callback_t
) add_ipv6_name
);
423 wtap_set_cb_new_secrets(cf
->provider
.wth
, secrets_wtap_callback
);
428 cfile_open_failure_message(fname
, *err
, err_info
);
433 sharkd_cf_open(const char *fname
, unsigned int type
, bool is_tempfile
, int *err
)
435 return cf_open(&cfile
, fname
, type
, is_tempfile
, err
);
439 sharkd_load_cap_file(void)
441 return load_cap_file(&cfile
, 0, 0);
445 sharkd_get_frame(uint32_t framenum
)
447 return frame_data_sequence_find(cfile
.provider
.frames
, framenum
);
450 enum dissect_request_status
451 sharkd_dissect_request(uint32_t framenum
, uint32_t frame_ref_num
,
452 uint32_t prev_dis_num
, wtap_rec
*rec
, Buffer
*buf
,
453 column_info
*cinfo
, uint32_t dissect_flags
,
454 sharkd_dissect_func_t cb
, void *data
,
455 int *err
, char **err_info
)
459 bool create_proto_tree
;
461 fdata
= sharkd_get_frame(framenum
);
463 return DISSECT_REQUEST_NO_SUCH_FRAME
;
465 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, rec
, buf
, err
, err_info
)) {
467 col_fill_in_error(cinfo
, fdata
, false, false /* fill_fd_columns */);
468 return DISSECT_REQUEST_READ_ERROR
; /* error reading the record */
471 create_proto_tree
= ((dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ||
472 ((dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) && color_filters_used()) ||
473 (cinfo
&& have_custom_cols(cinfo
)));
474 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
));
476 if (dissect_flags
& SHARKD_DISSECT_FLAG_COLOR
) {
477 color_filters_prime_edt(&edt
);
478 fdata
->need_colorize
= 1;
482 col_custom_prime_edt(&edt
, cinfo
);
485 * XXX - need to catch an OutOfMemoryError exception and
486 * attempt to recover from it.
488 fdata
->ref_time
= (framenum
== frame_ref_num
);
489 fdata
->frame_ref_num
= frame_ref_num
;
490 fdata
->prev_dis_num
= prev_dis_num
;
491 epan_dissect_run(&edt
, cfile
.cd_t
, rec
,
492 ws_buffer_start_ptr(buf
),
496 /* "Stringify" non frame_data vals */
497 epan_dissect_fill_in_columns(&edt
, false, true/* fill_fd_columns */);
500 cb(&edt
, (dissect_flags
& SHARKD_DISSECT_FLAG_PROTO_TREE
) ? edt
.tree
: NULL
,
501 cinfo
, (dissect_flags
& SHARKD_DISSECT_FLAG_BYTES
) ? edt
.pi
.data_src
: NULL
,
505 epan_dissect_cleanup(&edt
);
506 return DISSECT_REQUEST_SUCCESS
;
517 char *err_info
= NULL
;
520 bool create_proto_tree
;
524 /* Get the union of the flags for all tap listeners. */
525 tap_flags
= union_of_tap_listener_flags();
527 /* If any tap listeners require the columns, construct them. */
528 cinfo
= (tap_listeners_require_columns()) ? &cfile
.cinfo
: NULL
;
531 * Determine whether we need to create a protocol tree.
534 * one of the tap listeners is going to apply a filter;
536 * one of the tap listeners requires a protocol tree.
539 (have_filtering_tap_listeners() || (tap_flags
& TL_REQUIRES_PROTO_TREE
));
542 ws_buffer_init(&buf
, 1514);
543 epan_dissect_init(&edt
, cfile
.epan
, create_proto_tree
, false);
545 reset_tap_listeners();
547 for (framenum
= 1; framenum
<= cfile
.count
; framenum
++) {
548 fdata
= sharkd_get_frame(framenum
);
550 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
553 fdata
->ref_time
= false;
554 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
555 fdata
->prev_dis_num
= framenum
- 1;
556 epan_dissect_run_with_taps(&edt
, cfile
.cd_t
, &rec
,
557 ws_buffer_start_ptr(&buf
),
559 wtap_rec_reset(&rec
);
560 epan_dissect_reset(&edt
);
563 wtap_rec_cleanup(&rec
);
564 ws_buffer_free(&buf
);
565 epan_dissect_cleanup(&edt
);
567 draw_tap_listeners(true);
573 sharkd_filter(const char *dftext
, uint8_t **result
)
575 dfilter_t
*dfcode
= NULL
;
577 uint32_t framenum
, prev_dis_num
= 0;
578 uint32_t frames_count
;
582 char *err_info
= NULL
;
584 uint8_t *result_bits
;
589 if (!dfilter_compile(dftext
, &dfcode
, NULL
)) {
593 /* if dfilter_compile() success, but (dfcode == NULL) all frames are matching */
594 if (dfcode
== NULL
) {
599 frames_count
= cfile
.count
;
602 ws_buffer_init(&buf
, 1514);
603 epan_dissect_init(&edt
, cfile
.epan
, true, false);
606 result_bits
= (uint8_t *) g_malloc(2 + (frames_count
/ 8));
608 for (framenum
= 1; framenum
<= frames_count
; framenum
++) {
609 frame_data
*fdata
= sharkd_get_frame(framenum
);
611 if ((framenum
& 7) == 0) {
612 result_bits
[(framenum
/ 8) - 1] = passed_bits
;
616 if (!wtap_seek_read(cfile
.provider
.wth
, fdata
->file_off
, &rec
, &buf
, &err
, &err_info
))
619 /* frame_data_set_before_dissect */
620 epan_dissect_prime_with_dfilter(&edt
, dfcode
);
622 fdata
->ref_time
= false;
623 fdata
->frame_ref_num
= (framenum
!= 1) ? 1 : 0;
624 fdata
->prev_dis_num
= prev_dis_num
;
625 epan_dissect_run(&edt
, cfile
.cd_t
, &rec
,
626 ws_buffer_start_ptr(&cfile
.buf
),
629 if (dfilter_apply_edt(dfcode
, &edt
)) {
630 passed_bits
|= (1 << (framenum
% 8));
631 prev_dis_num
= framenum
;
634 /* if passed or ref -> frame_data_set_after_dissect */
636 wtap_rec_reset(&rec
);
637 epan_dissect_reset(&edt
);
640 if ((framenum
& 7) == 0)
642 result_bits
[framenum
/ 8] = passed_bits
;
644 wtap_rec_cleanup(&rec
);
645 ws_buffer_free(&buf
);
646 epan_dissect_cleanup(&edt
);
648 dfilter_free(dfcode
);
650 *result
= result_bits
;
656 * Get the modified block if available, nothing otherwise.
657 * Must be cloned if changes desired.
660 sharkd_get_modified_block(const frame_data
*fd
)
662 return cap_file_provider_get_modified_block(&cfile
.provider
, fd
);
666 * Gets the modified block if available, otherwise the packet's default block,
667 * or a new packet block.
668 * User must wtap_block_unref() it when done.
671 sharkd_get_packet_block(const frame_data
*fd
)
673 if (fd
->has_modified_block
)
674 return wtap_block_ref(cap_file_provider_get_modified_block(&cfile
.provider
, fd
));
677 wtap_rec rec
; /* Record metadata */
678 Buffer buf
; /* Record data */
684 ws_buffer_init(&buf
, 1514);
686 if (!wtap_seek_read(cfile
.provider
.wth
, fd
->file_off
, &rec
, &buf
, &err
, &err_info
))
687 { /* XXX, what we can do here? */ }
689 /* rec.block is owned by the record, steal it before it is gone. */
690 block
= wtap_block_ref(rec
.block
);
692 wtap_rec_cleanup(&rec
);
693 ws_buffer_free(&buf
);
699 sharkd_set_modified_block(frame_data
*fd
, wtap_block_t new_block
)
701 cap_file_provider_set_modified_block(&cfile
.provider
, fd
, new_block
);