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 <wsutil/clopts_common.h>
27 #include <wsutil/cmdarg_err.h>
28 #include <wsutil/crash_info.h>
29 #include <wsutil/filesystem.h>
30 #include <wsutil/file_util.h>
31 #include <wsutil/privileges.h>
32 #include <wsutil/report_message.h>
33 #include <version_info.h>
34 #include <wiretap/wtap_opttypes.h>
35 #include <wiretap/pcapng.h>
37 #include <epan/decode_as.h>
38 #include <epan/timestamp.h>
39 #include <epan/packet.h>
40 #include "frame_tvbuff.h"
41 #include <epan/disabled_protos.h>
42 #include <epan/prefs.h>
43 #include <epan/column.h>
44 #include <epan/print.h>
45 #include <epan/addr_resolv.h>
47 #include "ui/ws_ui_util.h"
48 #include "ui/decode_as_utils.h"
49 #include "ui/filter_files.h"
50 #include "ui/tap_export_pdu.h"
51 #include "ui/failure_message.h"
52 #include "epan/register.h"
53 #include <epan/epan_dissect.h>
55 #include <epan/uat-int.h>
57 #include <codecs/codecs.h>
61 #include <wsutil/str_util.h>
62 #include <wsutil/utf8_entities.h>
65 #include <wsutil/plugins.h>
71 #define EPAN_INIT_FAIL 2
75 static guint32 cum_bytes;
76 static frame_data ref_frame;
78 static void failure_warning_message(const char *msg_format, va_list ap);
79 static void open_failure_message(const char *filename, int err,
80 gboolean for_writing);
81 static void read_failure_message(const char *filename, int err);
82 static void write_failure_message(const char *filename, int err);
83 static void failure_message_cont(const char *msg_format, va_list ap);
86 print_current_user(void) {
87 gchar *cur_user, *cur_group;
89 if (started_with_special_privs()) {
90 cur_user = get_cur_username();
91 cur_group = get_cur_groupname();
92 fprintf(stderr, "Running as user \"%s\" and group \"%s\".",
96 if (running_with_special_privs()) {
97 fprintf(stderr, " This could be dangerous.");
99 fprintf(stderr, "\n");
104 main(int argc, char *argv[])
106 GString *comp_info_str;
107 GString *runtime_info_str;
108 char *init_progfile_dir_error;
110 char *err_msg = NULL;
112 int ret = EXIT_SUCCESS;
114 cmdarg_err_init(failure_warning_message, failure_message_cont);
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 init_progfile_dir_error = init_progfile_dir(argv[0]);
129 if (init_progfile_dir_error != NULL) {
130 fprintf(stderr, "sharkd: Can't get pathname of sharkd program: %s.\n",
131 init_progfile_dir_error);
134 /* Get the compile-time version information string */
135 comp_info_str = get_compiled_version_info(NULL, epan_get_compiled_version_info);
137 /* Get the run-time version information string */
138 runtime_info_str = get_runtime_version_info(epan_get_runtime_version_info);
140 /* Add it to the information to be reported on a crash. */
141 ws_add_crash_info("Sharkd (Wireshark) %s\n"
146 get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
147 g_string_free(comp_info_str, TRUE);
148 g_string_free(runtime_info_str, TRUE);
150 if (sharkd_init(argc, argv) < 0)
152 printf("cannot initialize sharkd\n");
157 init_report_message(failure_warning_message, failure_warning_message,
158 open_failure_message, read_failure_message,
159 write_failure_message);
161 timestamp_set_type(TS_RELATIVE);
162 timestamp_set_precision(TS_PREC_AUTO);
163 timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
167 /* Register all dissectors; we must do this before checking for the
168 "-G" flag, as the "-G" flag dumps information registered by the
169 dissectors, and we must do it before we read the preferences, in
170 case any dissectors register preferences. */
171 if (!epan_init(register_all_protocols, register_all_protocol_handoffs, NULL,
173 ret = EPAN_INIT_FAIL;
179 /* Load libwireshark settings from the current profile. */
180 prefs_p = epan_load_settings();
182 read_filter_list(CFILTER_LIST);
184 if (!color_filters_init(&err_msg, NULL)) {
185 fprintf(stderr, "%s\n", err_msg);
189 cap_file_init(&cfile);
191 /* Notify all registered modules that have had any of their preferences
192 changed either from one of the preferences file or from the command
193 line that their preferences have changed. */
196 /* Build the column format array */
197 build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE);
199 #ifdef HAVE_MAXMINDDB
200 /* 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.
201 * Need to stop it, otherwise all sharkd will have same mmdbresolve process, including pipe descriptors to read and write. */
202 uat_clear(uat_get_table_by_name("MaxMind Database Paths"));
207 col_cleanup(&cfile.cinfo);
215 static const nstime_t *
216 sharkd_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num)
218 if (prov->ref && prov->ref->num == frame_num)
219 return &prov->ref->abs_ts;
221 if (prov->prev_dis && prov->prev_dis->num == frame_num)
222 return &prov->prev_dis->abs_ts;
224 if (prov->prev_cap && prov->prev_cap->num == frame_num)
225 return &prov->prev_cap->abs_ts;
228 frame_data *fd = frame_data_sequence_find(prov->frames, frame_num);
230 return (fd) ? &fd->abs_ts : NULL;
237 sharkd_epan_new(capture_file *cf)
239 static const struct packet_provider_funcs funcs = {
241 cap_file_provider_get_interface_name,
242 cap_file_provider_get_interface_description,
243 cap_file_provider_get_user_comment
246 return epan_new(&cf->provider, &funcs);
250 process_packet(capture_file *cf, epan_dissect_t *edt,
251 gint64 offset, wtap_rec *rec, const guchar *pd)
256 /* If we're not running a display filter and we're not printing any
257 packet information, we don't need to do a dissection. This means
258 that all packets can be marked as 'passed'. */
261 /* The frame number of this packet, if we add it to the set of frames,
262 would be one more than the count of frames in the file so far. */
263 frame_data_init(&fdlocal, cf->count + 1, rec, offset, cum_bytes);
265 /* If we're going to print packet information, or we're going to
266 run a read filter, or display filter, or we're going to process taps, set up to
267 do a dissection and do so. */
269 if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
270 gbl_resolv_flags.transport_name)
271 /* Grab any resolved addresses */
272 host_name_lookup_process();
274 /* If we're running a read filter, prime the epan_dissect_t with that
277 epan_dissect_prime_with_dfilter(edt, cf->rfcode);
280 epan_dissect_prime_with_dfilter(edt, cf->dfcode);
282 /* This is the first and only pass, so prime the epan_dissect_t
283 with the hfids postdissectors want on the first pass. */
284 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
286 frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
287 &cf->provider.ref, cf->provider.prev_dis);
288 if (cf->provider.ref == &fdlocal) {
290 cf->provider.ref = &ref_frame;
293 epan_dissect_run(edt, cf->cd_t, rec,
294 frame_tvbuff_new(&cf->provider, &fdlocal, pd),
297 /* Run the read filter if we have one. */
299 passed = dfilter_apply_edt(cf->rfcode, edt);
303 frame_data_set_after_dissect(&fdlocal, &cum_bytes);
304 cf->provider.prev_cap = cf->provider.prev_dis = frame_data_sequence_add(cf->provider.frames, &fdlocal);
306 /* If we're not doing dissection then there won't be any dependent frames.
307 * More importantly, edt.pi.dependent_frames won't be initialized because
308 * epan hasn't been initialized.
309 * if we *are* doing dissection, then mark the dependent frames, but only
310 * if a display filter was given and it matches this packet.
312 if (edt && cf->dfcode) {
313 if (dfilter_apply_edt(cf->dfcode, edt)) {
314 g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
320 /* if we don't add it to the frame_data_sequence, clean it up right now
322 frame_data_destroy(&fdlocal);
326 epan_dissect_reset(edt);
333 load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count)
336 gchar *err_info = NULL;
338 epan_dissect_t *edt = NULL;
341 /* Allocate a frame_data_sequence for all the frames. */
342 cf->provider.frames = new_frame_data_sequence();
345 gboolean create_proto_tree;
348 * Determine whether we need to create a protocol tree.
351 * we're going to apply a read filter;
353 * we're going to apply a display filter;
355 * a postdissector wants field values or protocols
359 (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids());
361 /* We're not going to display the protocol tree on this pass,
362 so it's not going to be "visible". */
363 edt = epan_dissect_new(cf->epan, create_proto_tree, FALSE);
366 while (wtap_read(cf->provider.wth, &err, &err_info, &data_offset)) {
367 if (process_packet(cf, edt, data_offset, wtap_get_rec(cf->provider.wth),
368 wtap_get_buf_ptr(cf->provider.wth))) {
369 /* Stop reading if we have the maximum number of packets;
370 * When the -c option has not been used, max_packet_count
371 * starts at 0, which practically means, never stop reading.
372 * (unless we roll over max_packet_count ?)
374 if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
375 err = 0; /* This is not an error */
382 epan_dissect_free(edt);
386 /* Close the sequential I/O side, to free up memory it requires. */
387 wtap_sequential_close(cf->provider.wth);
389 /* Allow the protocol dissectors to free up memory that they
390 * don't need after the sequential run-through of the packets. */
391 postseq_cleanup_all_protocols();
393 cf->provider.prev_dis = NULL;
394 cf->provider.prev_cap = NULL;
398 cfile_read_failure_message("sharkd", cf->filename, err, err_info);
405 cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
410 wth = wtap_open_offline(fname, type, err, &err_info, TRUE);
414 /* The open succeeded. Fill in the information for this file. */
416 /* Create new epan session for dissection. */
418 cf->epan = sharkd_epan_new(cf);
420 cf->provider.wth = wth;
421 cf->f_datalen = 0; /* not used, but set it anyway */
423 /* Set the file name because we need it to set the follow stream filter.
424 XXX - is that still true? We need it for other reasons, though,
426 cf->filename = g_strdup(fname);
428 /* Indicate whether it's a permanent or temporary file. */
429 cf->is_tempfile = is_tempfile;
431 /* No user changes yet. */
432 cf->unsaved_changes = FALSE;
434 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
435 cf->open_type = type;
437 cf->drops_known = FALSE;
439 cf->snap = wtap_snapshot_length(cf->provider.wth);
440 nstime_set_zero(&cf->elapsed_time);
441 cf->provider.ref = NULL;
442 cf->provider.prev_dis = NULL;
443 cf->provider.prev_cap = NULL;
445 cf->state = FILE_READ_IN_PROGRESS;
447 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
448 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
453 cfile_open_failure_message("sharkd", fname, *err, err_info);
458 * General errors and warnings are reported with an console message
462 failure_warning_message(const char *msg_format, va_list ap)
464 fprintf(stderr, "sharkd: ");
465 vfprintf(stderr, msg_format, ap);
466 fprintf(stderr, "\n");
470 * Open/create errors are reported with an console message in sharkd.
473 open_failure_message(const char *filename, int err, gboolean for_writing)
475 fprintf(stderr, "sharkd: ");
476 fprintf(stderr, file_open_error_message(err, for_writing), filename);
477 fprintf(stderr, "\n");
481 * Read errors are reported with an console message in sharkd.
484 read_failure_message(const char *filename, int err)
486 cmdarg_err("An error occurred while reading from the file \"%s\": %s.",
487 filename, g_strerror(err));
491 * Write errors are reported with an console message in sharkd.
494 write_failure_message(const char *filename, int err)
496 cmdarg_err("An error occurred while writing to the file \"%s\": %s.",
497 filename, g_strerror(err));
501 * Report additional information for an error in command-line arguments.
504 failure_message_cont(const char *msg_format, va_list ap)
506 vfprintf(stderr, msg_format, ap);
507 fprintf(stderr, "\n");
511 sharkd_cf_open(const char *fname, unsigned int type, gboolean is_tempfile, int *err)
513 return cf_open(&cfile, fname, type, is_tempfile, err);
517 sharkd_load_cap_file(void)
519 return load_cap_file(&cfile, 0, 0);
523 sharkd_get_frame(guint32 framenum)
525 return frame_data_sequence_find(cfile.provider.frames, framenum);
529 sharkd_dissect_request(guint32 framenum, guint32 frame_ref_num, guint32 prev_dis_num, sharkd_dissect_func_t cb, int dissect_bytes, int dissect_columns, int dissect_tree, void *data)
532 column_info *cinfo = (dissect_columns) ? &cfile.cinfo : NULL;
534 gboolean create_proto_tree;
535 wtap_rec rec; /* Record metadata */
536 Buffer buf; /* Record data */
539 char *err_info = NULL;
541 fdata = sharkd_get_frame(framenum);
546 ws_buffer_init(&buf, 1500);
548 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info)) {
549 ws_buffer_free(&buf);
550 return -1; /* error reading the record */
553 create_proto_tree = (dissect_tree) || (cinfo && have_custom_cols(cinfo));
554 epan_dissect_init(&edt, cfile.epan, create_proto_tree, dissect_tree);
557 col_custom_prime_edt(&edt, cinfo);
560 * XXX - need to catch an OutOfMemoryError exception and
561 * attempt to recover from it.
563 fdata->flags.ref_time = (framenum == frame_ref_num);
564 fdata->frame_ref_num = frame_ref_num;
565 fdata->prev_dis_num = prev_dis_num;
566 epan_dissect_run(&edt, cfile.cd_t, &rec,
567 frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
571 /* "Stringify" non frame_data vals */
572 epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
575 cb(&edt, dissect_tree ? edt.tree : NULL, cinfo, dissect_bytes ? edt.pi.data_src : NULL, data);
577 epan_dissect_cleanup(&edt);
578 wtap_rec_cleanup(&rec);
579 ws_buffer_free(&buf);
583 /* based on packet_list_dissect_and_cache_record */
585 sharkd_dissect_columns(frame_data *fdata, guint32 frame_ref_num, guint32 prev_dis_num, column_info *cinfo, gboolean dissect_color)
588 gboolean create_proto_tree;
589 wtap_rec rec; /* Record metadata */
590 Buffer buf; /* Record data */
593 char *err_info = NULL;
596 ws_buffer_init(&buf, 1500);
598 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info)) {
599 col_fill_in_error(cinfo, fdata, FALSE, FALSE /* fill_fd_columns */);
600 ws_buffer_free(&buf);
601 return -1; /* error reading the record */
604 create_proto_tree = (dissect_color && color_filters_used()) || (cinfo && have_custom_cols(cinfo));
606 epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE /* proto_tree_visible */);
609 color_filters_prime_edt(&edt);
610 fdata->flags.need_colorize = 1;
614 col_custom_prime_edt(&edt, cinfo);
617 * XXX - need to catch an OutOfMemoryError exception and
618 * attempt to recover from it.
620 fdata->flags.ref_time = (fdata->num == frame_ref_num);
621 fdata->frame_ref_num = frame_ref_num;
622 fdata->prev_dis_num = prev_dis_num;
623 epan_dissect_run(&edt, cfile.cd_t, &rec,
624 frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
628 /* "Stringify" non frame_data vals */
629 epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
632 epan_dissect_cleanup(&edt);
633 wtap_rec_cleanup(&rec);
634 ws_buffer_free(&buf);
646 char *err_info = NULL;
649 gboolean create_proto_tree;
653 /* Get the union of the flags for all tap listeners. */
654 tap_flags = union_of_tap_listener_flags();
656 /* If any tap listeners require the columns, construct them. */
657 cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cfile.cinfo : NULL;
660 * Determine whether we need to create a protocol tree.
663 * one of the tap listeners is going to apply a filter;
665 * one of the tap listeners requires a protocol tree.
668 (have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE));
671 ws_buffer_init(&buf, 1500);
672 epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE);
674 reset_tap_listeners();
676 for (framenum = 1; framenum <= cfile.count; framenum++) {
677 fdata = sharkd_get_frame(framenum);
679 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
682 fdata->flags.ref_time = FALSE;
683 fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
684 fdata->prev_dis_num = framenum - 1;
685 epan_dissect_run_with_taps(&edt, cfile.cd_t, &rec,
686 frame_tvbuff_new(&cfile.provider, fdata, ws_buffer_start_ptr(&buf)),
688 epan_dissect_reset(&edt);
691 wtap_rec_cleanup(&rec);
692 ws_buffer_free(&buf);
693 epan_dissect_cleanup(&edt);
695 draw_tap_listeners(TRUE);
701 sharkd_filter(const char *dftext, guint8 **result)
703 dfilter_t *dfcode = NULL;
705 guint32 framenum, prev_dis_num = 0;
706 guint32 frames_count;
710 char *err_info = NULL;
717 if (!dfilter_compile(dftext, &dfcode, &err_info)) {
722 frames_count = cfile.count;
725 ws_buffer_init(&buf, 1500);
726 epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
729 result_bits = (guint8 *) g_malloc(2 + (frames_count / 8));
731 for (framenum = 1; framenum <= frames_count; framenum++) {
732 frame_data *fdata = sharkd_get_frame(framenum);
734 if ((framenum & 7) == 0) {
735 result_bits[(framenum / 8) - 1] = passed_bits;
739 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
742 /* frame_data_set_before_dissect */
743 epan_dissect_prime_with_dfilter(&edt, dfcode);
745 fdata->flags.ref_time = FALSE;
746 fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
747 fdata->prev_dis_num = prev_dis_num;
748 epan_dissect_run(&edt, cfile.cd_t, &rec,
749 frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
752 if (dfilter_apply_edt(dfcode, &edt)) {
753 passed_bits |= (1 << (framenum % 8));
754 prev_dis_num = framenum;
757 /* if passed or ref -> frame_data_set_after_dissect */
759 epan_dissect_reset(&edt);
762 if ((framenum & 7) == 0)
764 result_bits[framenum / 8] = passed_bits;
766 wtap_rec_cleanup(&rec);
767 ws_buffer_free(&buf);
768 epan_dissect_cleanup(&edt);
770 dfilter_free(dfcode);
772 *result = result_bits;
778 sharkd_get_user_comment(const frame_data *fd)
780 return cap_file_provider_get_user_comment(&cfile.provider, fd);
784 sharkd_set_user_comment(frame_data *fd, const gchar *new_comment)
786 cap_file_provider_set_user_comment(&cfile.provider, fd, new_comment);
791 const char *sharkd_version(void)
793 /* based on get_ws_vcs_version_info(), but shorter */
802 * Editor modelines - https://www.wireshark.org/tools/modelines.html
807 * indent-tabs-mode: nil
810 * vi: set shiftwidth=2 tabstop=8 expandtab:
811 * :indentSize=2:tabSize=8:noTabs=true: