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/epan_dissect.h>
54 #include <epan/uat-int.h>
55 #include <epan/secrets.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(NULL, NULL, TRUE)) {
172 ret = EPAN_INIT_FAIL;
178 /* Load libwireshark settings from the current profile. */
179 prefs_p = epan_load_settings();
181 read_filter_list(CFILTER_LIST);
183 if (!color_filters_init(&err_msg, NULL)) {
184 fprintf(stderr, "%s\n", err_msg);
188 cap_file_init(&cfile);
190 /* Notify all registered modules that have had any of their preferences
191 changed either from one of the preferences file or from the command
192 line that their preferences have changed. */
195 /* Build the column format array */
196 build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE);
198 #ifdef HAVE_MAXMINDDB
199 /* 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.
200 * Need to stop it, otherwise all sharkd will have same mmdbresolve process, including pipe descriptors to read and write. */
201 uat_clear(uat_get_table_by_name("MaxMind Database Paths"));
206 col_cleanup(&cfile.cinfo);
214 static const nstime_t *
215 sharkd_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num)
217 if (prov->ref && prov->ref->num == frame_num)
218 return &prov->ref->abs_ts;
220 if (prov->prev_dis && prov->prev_dis->num == frame_num)
221 return &prov->prev_dis->abs_ts;
223 if (prov->prev_cap && prov->prev_cap->num == frame_num)
224 return &prov->prev_cap->abs_ts;
227 frame_data *fd = frame_data_sequence_find(prov->frames, frame_num);
229 return (fd) ? &fd->abs_ts : NULL;
236 sharkd_epan_new(capture_file *cf)
238 static const struct packet_provider_funcs funcs = {
240 cap_file_provider_get_interface_name,
241 cap_file_provider_get_interface_description,
242 cap_file_provider_get_user_comment
245 return epan_new(&cf->provider, &funcs);
249 process_packet(capture_file *cf, epan_dissect_t *edt,
250 gint64 offset, wtap_rec *rec, const guchar *pd)
255 /* If we're not running a display filter and we're not printing any
256 packet information, we don't need to do a dissection. This means
257 that all packets can be marked as 'passed'. */
260 /* The frame number of this packet, if we add it to the set of frames,
261 would be one more than the count of frames in the file so far. */
262 frame_data_init(&fdlocal, cf->count + 1, rec, offset, cum_bytes);
264 /* If we're going to print packet information, or we're going to
265 run a read filter, or display filter, or we're going to process taps, set up to
266 do a dissection and do so. */
268 if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
269 gbl_resolv_flags.transport_name)
270 /* Grab any resolved addresses */
271 host_name_lookup_process();
273 /* If we're running a read filter, prime the epan_dissect_t with that
276 epan_dissect_prime_with_dfilter(edt, cf->rfcode);
279 epan_dissect_prime_with_dfilter(edt, cf->dfcode);
281 /* This is the first and only pass, so prime the epan_dissect_t
282 with the hfids postdissectors want on the first pass. */
283 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
285 frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
286 &cf->provider.ref, cf->provider.prev_dis);
287 if (cf->provider.ref == &fdlocal) {
289 cf->provider.ref = &ref_frame;
292 epan_dissect_run(edt, cf->cd_t, rec,
293 frame_tvbuff_new(&cf->provider, &fdlocal, pd),
296 /* Run the read filter if we have one. */
298 passed = dfilter_apply_edt(cf->rfcode, edt);
302 frame_data_set_after_dissect(&fdlocal, &cum_bytes);
303 cf->provider.prev_cap = cf->provider.prev_dis = frame_data_sequence_add(cf->provider.frames, &fdlocal);
305 /* If we're not doing dissection then there won't be any dependent frames.
306 * More importantly, edt.pi.dependent_frames won't be initialized because
307 * epan hasn't been initialized.
308 * if we *are* doing dissection, then mark the dependent frames, but only
309 * if a display filter was given and it matches this packet.
311 if (edt && cf->dfcode) {
312 if (dfilter_apply_edt(cf->dfcode, edt)) {
313 g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
319 /* if we don't add it to the frame_data_sequence, clean it up right now
321 frame_data_destroy(&fdlocal);
325 epan_dissect_reset(edt);
332 load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count)
335 gchar *err_info = NULL;
337 epan_dissect_t *edt = NULL;
340 /* Allocate a frame_data_sequence for all the frames. */
341 cf->provider.frames = new_frame_data_sequence();
344 gboolean create_proto_tree;
347 * Determine whether we need to create a protocol tree.
350 * we're going to apply a read filter;
352 * we're going to apply a display filter;
354 * a postdissector wants field values or protocols
358 (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids());
360 /* We're not going to display the protocol tree on this pass,
361 so it's not going to be "visible". */
362 edt = epan_dissect_new(cf->epan, create_proto_tree, FALSE);
365 while (wtap_read(cf->provider.wth, &err, &err_info, &data_offset)) {
366 if (process_packet(cf, edt, data_offset, wtap_get_rec(cf->provider.wth),
367 wtap_get_buf_ptr(cf->provider.wth))) {
368 /* Stop reading if we have the maximum number of packets;
369 * When the -c option has not been used, max_packet_count
370 * starts at 0, which practically means, never stop reading.
371 * (unless we roll over max_packet_count ?)
373 if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
374 err = 0; /* This is not an error */
381 epan_dissect_free(edt);
385 /* Close the sequential I/O side, to free up memory it requires. */
386 wtap_sequential_close(cf->provider.wth);
388 /* Allow the protocol dissectors to free up memory that they
389 * don't need after the sequential run-through of the packets. */
390 postseq_cleanup_all_protocols();
392 cf->provider.prev_dis = NULL;
393 cf->provider.prev_cap = NULL;
397 cfile_read_failure_message("sharkd", cf->filename, err, err_info);
404 cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
409 wth = wtap_open_offline(fname, type, err, &err_info, TRUE);
413 /* The open succeeded. Fill in the information for this file. */
415 cf->provider.wth = wth;
416 cf->f_datalen = 0; /* not used, but set it anyway */
418 /* Set the file name because we need it to set the follow stream filter.
419 XXX - is that still true? We need it for other reasons, though,
421 cf->filename = g_strdup(fname);
423 /* Indicate whether it's a permanent or temporary file. */
424 cf->is_tempfile = is_tempfile;
426 /* No user changes yet. */
427 cf->unsaved_changes = FALSE;
429 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
430 cf->open_type = type;
432 cf->drops_known = FALSE;
434 cf->snap = wtap_snapshot_length(cf->provider.wth);
435 nstime_set_zero(&cf->elapsed_time);
436 cf->provider.ref = NULL;
437 cf->provider.prev_dis = NULL;
438 cf->provider.prev_cap = NULL;
440 /* Create new epan session for dissection. */
442 cf->epan = sharkd_epan_new(cf);
444 cf->state = FILE_READ_IN_PROGRESS;
446 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
447 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
448 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
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, guint32 dissect_flags, void *data)
532 column_info *cinfo = (dissect_flags & SHARKD_DISSECT_FLAG_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 wtap_rec_cleanup(&rec);
550 ws_buffer_free(&buf);
551 return -1; /* error reading the record */
554 create_proto_tree = ((dissect_flags & SHARKD_DISSECT_FLAG_PROTO_TREE) ||
555 ((dissect_flags & SHARKD_DISSECT_FLAG_COLOR) && color_filters_used()) ||
556 (cinfo && have_custom_cols(cinfo)));
557 epan_dissect_init(&edt, cfile.epan, create_proto_tree, (dissect_flags & SHARKD_DISSECT_FLAG_PROTO_TREE));
559 if (dissect_flags & SHARKD_DISSECT_FLAG_COLOR) {
560 color_filters_prime_edt(&edt);
561 fdata->flags.need_colorize = 1;
565 col_custom_prime_edt(&edt, cinfo);
568 * XXX - need to catch an OutOfMemoryError exception and
569 * attempt to recover from it.
571 fdata->flags.ref_time = (framenum == frame_ref_num);
572 fdata->frame_ref_num = frame_ref_num;
573 fdata->prev_dis_num = prev_dis_num;
574 epan_dissect_run(&edt, cfile.cd_t, &rec,
575 frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
579 /* "Stringify" non frame_data vals */
580 epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
583 cb(&edt, (dissect_flags & SHARKD_DISSECT_FLAG_PROTO_TREE) ? edt.tree : NULL,
584 cinfo, (dissect_flags & SHARKD_DISSECT_FLAG_BYTES) ? edt.pi.data_src : NULL,
587 epan_dissect_cleanup(&edt);
588 wtap_rec_cleanup(&rec);
589 ws_buffer_free(&buf);
593 /* based on packet_list_dissect_and_cache_record */
595 sharkd_dissect_columns(frame_data *fdata, guint32 frame_ref_num, guint32 prev_dis_num, column_info *cinfo, gboolean dissect_color)
598 gboolean create_proto_tree;
599 wtap_rec rec; /* Record metadata */
600 Buffer buf; /* Record data */
603 char *err_info = NULL;
606 ws_buffer_init(&buf, 1500);
608 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info)) {
609 col_fill_in_error(cinfo, fdata, FALSE, FALSE /* fill_fd_columns */);
610 wtap_rec_cleanup(&rec);
611 ws_buffer_free(&buf);
612 return -1; /* error reading the record */
615 create_proto_tree = (dissect_color && color_filters_used()) || (cinfo && have_custom_cols(cinfo));
617 epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE /* proto_tree_visible */);
620 color_filters_prime_edt(&edt);
621 fdata->flags.need_colorize = 1;
625 col_custom_prime_edt(&edt, cinfo);
628 * XXX - need to catch an OutOfMemoryError exception and
629 * attempt to recover from it.
631 fdata->flags.ref_time = (fdata->num == frame_ref_num);
632 fdata->frame_ref_num = frame_ref_num;
633 fdata->prev_dis_num = prev_dis_num;
634 epan_dissect_run(&edt, cfile.cd_t, &rec,
635 frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
639 /* "Stringify" non frame_data vals */
640 epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
643 epan_dissect_cleanup(&edt);
644 wtap_rec_cleanup(&rec);
645 ws_buffer_free(&buf);
657 char *err_info = NULL;
660 gboolean create_proto_tree;
664 /* Get the union of the flags for all tap listeners. */
665 tap_flags = union_of_tap_listener_flags();
667 /* If any tap listeners require the columns, construct them. */
668 cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cfile.cinfo : NULL;
671 * Determine whether we need to create a protocol tree.
674 * one of the tap listeners is going to apply a filter;
676 * one of the tap listeners requires a protocol tree.
679 (have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE));
682 ws_buffer_init(&buf, 1500);
683 epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE);
685 reset_tap_listeners();
687 for (framenum = 1; framenum <= cfile.count; framenum++) {
688 fdata = sharkd_get_frame(framenum);
690 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
693 fdata->flags.ref_time = FALSE;
694 fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
695 fdata->prev_dis_num = framenum - 1;
696 epan_dissect_run_with_taps(&edt, cfile.cd_t, &rec,
697 frame_tvbuff_new(&cfile.provider, fdata, ws_buffer_start_ptr(&buf)),
699 epan_dissect_reset(&edt);
702 wtap_rec_cleanup(&rec);
703 ws_buffer_free(&buf);
704 epan_dissect_cleanup(&edt);
706 draw_tap_listeners(TRUE);
712 sharkd_filter(const char *dftext, guint8 **result)
714 dfilter_t *dfcode = NULL;
716 guint32 framenum, prev_dis_num = 0;
717 guint32 frames_count;
721 char *err_info = NULL;
728 if (!dfilter_compile(dftext, &dfcode, &err_info)) {
733 /* if dfilter_compile() success, but (dfcode == NULL) all frames are matching */
734 if (dfcode == NULL) {
739 frames_count = cfile.count;
742 ws_buffer_init(&buf, 1500);
743 epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
746 result_bits = (guint8 *) g_malloc(2 + (frames_count / 8));
748 for (framenum = 1; framenum <= frames_count; framenum++) {
749 frame_data *fdata = sharkd_get_frame(framenum);
751 if ((framenum & 7) == 0) {
752 result_bits[(framenum / 8) - 1] = passed_bits;
756 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
759 /* frame_data_set_before_dissect */
760 epan_dissect_prime_with_dfilter(&edt, dfcode);
762 fdata->flags.ref_time = FALSE;
763 fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
764 fdata->prev_dis_num = prev_dis_num;
765 epan_dissect_run(&edt, cfile.cd_t, &rec,
766 frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
769 if (dfilter_apply_edt(dfcode, &edt)) {
770 passed_bits |= (1 << (framenum % 8));
771 prev_dis_num = framenum;
774 /* if passed or ref -> frame_data_set_after_dissect */
776 epan_dissect_reset(&edt);
779 if ((framenum & 7) == 0)
781 result_bits[framenum / 8] = passed_bits;
783 wtap_rec_cleanup(&rec);
784 ws_buffer_free(&buf);
785 epan_dissect_cleanup(&edt);
787 dfilter_free(dfcode);
789 *result = result_bits;
795 sharkd_get_user_comment(const frame_data *fd)
797 return cap_file_provider_get_user_comment(&cfile.provider, fd);
801 sharkd_set_user_comment(frame_data *fd, const gchar *new_comment)
803 cap_file_provider_set_user_comment(&cfile.provider, fd, new_comment);
808 const char *sharkd_version(void)
810 /* based on get_ws_vcs_version_info(), but shorter */
819 * Editor modelines - https://www.wireshark.org/tools/modelines.html
824 * indent-tabs-mode: nil
827 * vi: set shiftwidth=2 tabstop=8 expandtab:
828 * :indentSize=2:tabSize=8:noTabs=true: