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+
23 #include <epan/exceptions.h>
24 #include <epan/epan-int.h>
25 #include <epan/epan.h>
27 #include <wsutil/clopts_common.h>
28 #include <wsutil/cmdarg_err.h>
29 #include <wsutil/crash_info.h>
30 #include <wsutil/filesystem.h>
31 #include <wsutil/file_util.h>
32 #include <wsutil/privileges.h>
33 #include <wsutil/report_message.h>
34 #include <version_info.h>
35 #include <wiretap/wtap_opttypes.h>
36 #include <wiretap/pcapng.h>
38 #include <epan/decode_as.h>
39 #include <epan/timestamp.h>
40 #include <epan/packet.h>
41 #include "frame_tvbuff.h"
42 #include <epan/disabled_protos.h>
43 #include <epan/prefs.h>
44 #include <epan/column.h>
45 #include <epan/print.h>
46 #include <epan/addr_resolv.h>
48 #include "ui/ws_ui_util.h"
49 #include "ui/decode_as_utils.h"
50 #include "ui/filter_files.h"
51 #include "ui/tap_export_pdu.h"
52 #include "ui/failure_message.h"
53 #include "epan/register.h"
54 #include <epan/epan_dissect.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], main);
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);
168 /* Register all the plugin types we have. */
169 epan_register_plugin_types(); /* Types known to libwireshark */
171 /* Scan for plugins. This does *not* call their registration routines;
172 that's done later. */
173 scan_plugins(REPORT_LOAD_FAILURE);
175 /* Register all libwiretap plugin modules. */
176 register_all_wiretap_modules();
179 register_all_codecs();
181 /* Register all dissectors; we must do this before checking for the
182 "-G" flag, as the "-G" flag dumps information registered by the
183 dissectors, and we must do it before we read the preferences, in
184 case any dissectors register preferences. */
185 if (!epan_init(register_all_protocols, register_all_protocol_handoffs, NULL,
187 ret = EPAN_INIT_FAIL;
191 /* Load libwireshark settings from the current profile. */
192 prefs_p = epan_load_settings();
194 read_filter_list(CFILTER_LIST);
196 if (!color_filters_init(&err_msg, NULL)) {
197 fprintf(stderr, "%s\n", err_msg);
201 cap_file_init(&cfile);
203 /* Notify all registered modules that have had any of their preferences
204 changed either from one of the preferences file or from the command
205 line that their preferences have changed. */
208 /* Build the column format array */
209 build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE);
213 col_cleanup(&cfile.cinfo);
223 static const nstime_t *
224 sharkd_get_frame_ts(frame_set *fs, guint32 frame_num)
226 if (fs->ref && fs->ref->num == frame_num)
227 return &fs->ref->abs_ts;
229 if (fs->prev_dis && fs->prev_dis->num == frame_num)
230 return &fs->prev_dis->abs_ts;
232 if (fs->prev_cap && fs->prev_cap->num == frame_num)
233 return &fs->prev_cap->abs_ts;
236 frame_data *fd = frame_data_sequence_find(fs->frames, frame_num);
238 return (fd) ? &fd->abs_ts : NULL;
245 sharkd_epan_new(capture_file *cf)
247 epan_t *epan = epan_new();
249 epan->fs = &cf->frame_set_info;
250 epan->get_frame_ts = sharkd_get_frame_ts;
251 epan->get_interface_name = frame_set_get_interface_name;
252 epan->get_interface_description = frame_set_get_interface_description;
253 epan->get_user_comment = frame_set_get_user_comment;
259 process_packet(capture_file *cf, epan_dissect_t *edt,
260 gint64 offset, struct wtap_pkthdr *whdr,
267 /* The frame number of this packet is one more than the count of
268 frames in this packet. */
269 framenum = cf->count + 1;
271 /* If we're not running a display filter and we're not printing any
272 packet information, we don't need to do a dissection. This means
273 that all packets can be marked as 'passed'. */
276 frame_data_init(&fdlocal, framenum, whdr, offset, cum_bytes);
278 /* If we're going to print packet information, or we're going to
279 run a read filter, or display filter, or we're going to process taps, set up to
280 do a dissection and do so. */
282 if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
283 gbl_resolv_flags.transport_name)
284 /* Grab any resolved addresses */
285 host_name_lookup_process();
287 /* If we're running a read filter, prime the epan_dissect_t with that
290 epan_dissect_prime_with_dfilter(edt, cf->rfcode);
293 epan_dissect_prime_with_dfilter(edt, cf->dfcode);
295 /* This is the first and only pass, so prime the epan_dissect_t
296 with the hfids postdissectors want on the first pass. */
297 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
299 frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
300 &cf->frame_set_info.ref, cf->frame_set_info.prev_dis);
301 if (cf->frame_set_info.ref == &fdlocal) {
303 cf->frame_set_info.ref = &ref_frame;
306 epan_dissect_run(edt, cf->cd_t, whdr, frame_tvbuff_new(&fdlocal, pd), &fdlocal, NULL);
308 /* Run the read filter if we have one. */
310 passed = dfilter_apply_edt(cf->rfcode, edt);
314 frame_data_set_after_dissect(&fdlocal, &cum_bytes);
315 cf->frame_set_info.prev_cap = cf->frame_set_info.prev_dis = frame_data_sequence_add(cf->frame_set_info.frames, &fdlocal);
317 /* If we're not doing dissection then there won't be any dependent frames.
318 * More importantly, edt.pi.dependent_frames won't be initialized because
319 * epan hasn't been initialized.
320 * if we *are* doing dissection, then mark the dependent frames, but only
321 * if a display filter was given and it matches this packet.
323 if (edt && cf->dfcode) {
324 if (dfilter_apply_edt(cf->dfcode, edt)) {
325 g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frame_set_info.frames);
331 /* if we don't add it to the frame_data_sequence, clean it up right now
333 frame_data_destroy(&fdlocal);
337 epan_dissect_reset(edt);
344 load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count)
347 gchar *err_info = NULL;
349 epan_dissect_t *edt = NULL;
352 /* Allocate a frame_data_sequence for all the frames. */
353 cf->frame_set_info.frames = new_frame_data_sequence();
356 gboolean create_proto_tree;
359 * Determine whether we need to create a protocol tree.
362 * we're going to apply a read filter;
364 * we're going to apply a display filter;
366 * a postdissector wants field values or protocols
370 (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids());
372 /* We're not going to display the protocol tree on this pass,
373 so it's not going to be "visible". */
374 edt = epan_dissect_new(cf->epan, create_proto_tree, FALSE);
377 while (wtap_read(cf->frame_set_info.wth, &err, &err_info, &data_offset)) {
378 if (process_packet(cf, edt, data_offset, wtap_phdr(cf->frame_set_info.wth),
379 wtap_buf_ptr(cf->frame_set_info.wth))) {
380 /* Stop reading if we have the maximum number of packets;
381 * When the -c option has not been used, max_packet_count
382 * starts at 0, which practically means, never stop reading.
383 * (unless we roll over max_packet_count ?)
385 if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
386 err = 0; /* This is not an error */
393 epan_dissect_free(edt);
397 /* Close the sequential I/O side, to free up memory it requires. */
398 wtap_sequential_close(cf->frame_set_info.wth);
400 /* Allow the protocol dissectors to free up memory that they
401 * don't need after the sequential run-through of the packets. */
402 postseq_cleanup_all_protocols();
404 cf->frame_set_info.prev_dis = NULL;
405 cf->frame_set_info.prev_cap = NULL;
409 cfile_read_failure_message("sharkd", cf->filename, err, err_info);
416 cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
421 wth = wtap_open_offline(fname, type, err, &err_info, TRUE);
425 /* The open succeeded. Fill in the information for this file. */
427 /* Create new epan session for dissection. */
429 cf->epan = sharkd_epan_new(cf);
431 cf->frame_set_info.wth = wth;
432 cf->f_datalen = 0; /* not used, but set it anyway */
434 /* Set the file name because we need it to set the follow stream filter.
435 XXX - is that still true? We need it for other reasons, though,
437 cf->filename = g_strdup(fname);
439 /* Indicate whether it's a permanent or temporary file. */
440 cf->is_tempfile = is_tempfile;
442 /* No user changes yet. */
443 cf->unsaved_changes = FALSE;
445 cf->cd_t = wtap_file_type_subtype(cf->frame_set_info.wth);
446 cf->open_type = type;
448 cf->drops_known = FALSE;
450 cf->snap = wtap_snapshot_length(cf->frame_set_info.wth);
451 nstime_set_zero(&cf->elapsed_time);
452 cf->frame_set_info.ref = NULL;
453 cf->frame_set_info.prev_dis = NULL;
454 cf->frame_set_info.prev_cap = NULL;
456 cf->state = FILE_READ_IN_PROGRESS;
458 wtap_set_cb_new_ipv4(cf->frame_set_info.wth, add_ipv4_name);
459 wtap_set_cb_new_ipv6(cf->frame_set_info.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
464 cfile_open_failure_message("sharkd", fname, *err, err_info);
469 * General errors and warnings are reported with an console message
473 failure_warning_message(const char *msg_format, va_list ap)
475 fprintf(stderr, "sharkd: ");
476 vfprintf(stderr, msg_format, ap);
477 fprintf(stderr, "\n");
481 * Open/create errors are reported with an console message in sharkd.
484 open_failure_message(const char *filename, int err, gboolean for_writing)
486 fprintf(stderr, "sharkd: ");
487 fprintf(stderr, file_open_error_message(err, for_writing), filename);
488 fprintf(stderr, "\n");
492 * Read errors are reported with an console message in sharkd.
495 read_failure_message(const char *filename, int err)
497 cmdarg_err("An error occurred while reading from the file \"%s\": %s.",
498 filename, g_strerror(err));
502 * Write errors are reported with an console message in sharkd.
505 write_failure_message(const char *filename, int err)
507 cmdarg_err("An error occurred while writing to the file \"%s\": %s.",
508 filename, g_strerror(err));
512 * Report additional information for an error in command-line arguments.
515 failure_message_cont(const char *msg_format, va_list ap)
517 vfprintf(stderr, msg_format, ap);
518 fprintf(stderr, "\n");
522 sharkd_cf_open(const char *fname, unsigned int type, gboolean is_tempfile, int *err)
524 return cf_open(&cfile, fname, type, is_tempfile, err);
528 sharkd_load_cap_file(void)
530 return load_cap_file(&cfile, 0, 0);
534 sharkd_dissect_request(unsigned int framenum, void (*cb)(epan_dissect_t *, proto_tree *, struct epan_column_info *, const GSList *, void *), int dissect_bytes, int dissect_columns, int dissect_tree, void *data)
537 column_info *cinfo = (dissect_columns) ? &cfile.cinfo : NULL;
539 gboolean create_proto_tree;
540 struct wtap_pkthdr phdr; /* Packet header */
541 Buffer buf; /* Packet data */
544 char *err_info = NULL;
546 fdata = frame_data_sequence_find(cfile.frame_set_info.frames, framenum);
550 wtap_phdr_init(&phdr);
551 ws_buffer_init(&buf, 1500);
553 if (!wtap_seek_read(cfile.frame_set_info.wth, fdata->file_off, &phdr, &buf, &err, &err_info)) {
554 ws_buffer_free(&buf);
555 return -1; /* error reading the record */
558 create_proto_tree = (dissect_tree) || (cinfo && have_custom_cols(cinfo));
559 epan_dissect_init(&edt, cfile.epan, create_proto_tree, dissect_tree);
562 col_custom_prime_edt(&edt, cinfo);
565 * XXX - need to catch an OutOfMemoryError exception and
566 * attempt to recover from it.
568 epan_dissect_run(&edt, cfile.cd_t, &phdr, frame_tvbuff_new_buffer(fdata, &buf), fdata, cinfo);
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_phdr_cleanup(&phdr);
579 ws_buffer_free(&buf);
583 /* based on packet_list_dissect_and_cache_record */
585 sharkd_dissect_columns(int framenum, column_info *cinfo, gboolean dissect_color)
589 gboolean create_proto_tree;
590 struct wtap_pkthdr phdr; /* Packet header */
591 Buffer buf; /* Packet data */
594 char *err_info = NULL;
596 fdata = frame_data_sequence_find(cfile.frame_set_info.frames, framenum);
598 col_fill_in_error(cinfo, fdata, FALSE, TRUE/* fill_fd_columns */);
599 return -1; /* error reading the record */
602 wtap_phdr_init(&phdr);
603 ws_buffer_init(&buf, 1500);
605 if (!wtap_seek_read(cfile.frame_set_info.wth, fdata->file_off, &phdr, &buf, &err, &err_info)) {
606 col_fill_in_error(cinfo, fdata, FALSE, FALSE /* fill_fd_columns */);
607 ws_buffer_free(&buf);
608 return -1; /* error reading the record */
611 create_proto_tree = (dissect_color && color_filters_used()) || (cinfo && have_custom_cols(cinfo));
613 epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE /* proto_tree_visible */);
616 color_filters_prime_edt(&edt);
617 fdata->flags.need_colorize = 1;
621 col_custom_prime_edt(&edt, cinfo);
624 * XXX - need to catch an OutOfMemoryError exception and
625 * attempt to recover from it.
627 epan_dissect_run(&edt, cfile.cd_t, &phdr, frame_tvbuff_new_buffer(fdata, &buf), fdata, cinfo);
630 /* "Stringify" non frame_data vals */
631 epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
634 epan_dissect_cleanup(&edt);
635 wtap_phdr_cleanup(&phdr);
636 ws_buffer_free(&buf);
646 struct wtap_pkthdr phdr;
648 char *err_info = NULL;
651 gboolean create_proto_tree;
655 /* Get the union of the flags for all tap listeners. */
656 tap_flags = union_of_tap_listener_flags();
658 /* If any tap listeners require the columns, construct them. */
659 cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cfile.cinfo : NULL;
662 * Determine whether we need to create a protocol tree.
665 * one of the tap listeners is going to apply a filter;
667 * one of the tap listeners requires a protocol tree.
670 (have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE));
672 wtap_phdr_init(&phdr);
673 ws_buffer_init(&buf, 1500);
674 epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE);
676 reset_tap_listeners();
678 for (framenum = 1; framenum <= cfile.count; framenum++) {
679 fdata = frame_data_sequence_find(cfile.frame_set_info.frames, framenum);
681 if (!wtap_seek_read(cfile.frame_set_info.wth, fdata->file_off, &phdr, &buf, &err, &err_info))
684 epan_dissect_run_with_taps(&edt, cfile.cd_t, &phdr, frame_tvbuff_new(fdata, ws_buffer_start_ptr(&buf)), fdata, cinfo);
685 epan_dissect_reset(&edt);
688 wtap_phdr_cleanup(&phdr);
689 ws_buffer_free(&buf);
690 epan_dissect_cleanup(&edt);
692 draw_tap_listeners(TRUE);
698 sharkd_filter(const char *dftext, guint8 **result)
700 dfilter_t *dfcode = NULL;
703 guint32 frames_count;
705 struct wtap_pkthdr phdr;
707 char *err_info = NULL;
714 if (!dfilter_compile(dftext, &dfcode, &err_info)) {
719 frames_count = cfile.count;
721 wtap_phdr_init(&phdr);
722 ws_buffer_init(&buf, 1500);
723 epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
726 result_bits = (guint8 *) g_malloc(2 + (frames_count / 8));
728 for (framenum = 1; framenum <= frames_count; framenum++) {
729 frame_data *fdata = frame_data_sequence_find(cfile.frame_set_info.frames, framenum);
731 if ((framenum & 7) == 0) {
732 result_bits[(framenum / 8) - 1] = passed_bits;
736 if (!wtap_seek_read(cfile.frame_set_info.wth, fdata->file_off, &phdr, &buf, &err, &err_info))
739 /* frame_data_set_before_dissect */
740 epan_dissect_prime_with_dfilter(&edt, dfcode);
742 epan_dissect_run(&edt, cfile.cd_t, &phdr, frame_tvbuff_new_buffer(fdata, &buf), fdata, NULL);
744 if (dfilter_apply_edt(dfcode, &edt))
745 passed_bits |= (1 << (framenum % 8));
747 /* if passed or ref -> frame_data_set_after_dissect */
749 epan_dissect_reset(&edt);
752 if ((framenum & 7) == 0)
754 result_bits[framenum / 8] = passed_bits;
756 wtap_phdr_cleanup(&phdr);
757 ws_buffer_free(&buf);
758 epan_dissect_cleanup(&edt);
760 dfilter_free(dfcode);
762 *result = result_bits;
768 sharkd_get_user_comment(const frame_data *fd)
770 return frame_set_get_user_comment(&cfile.frame_set_info, fd);
774 sharkd_set_user_comment(frame_data *fd, const gchar *new_comment)
776 frame_set_set_user_comment(&cfile.frame_set_info, fd, new_comment);
781 const char *sharkd_version(void)
783 /* based on get_ws_vcs_version_info(), but shorter */
792 * Editor modelines - https://www.wireshark.org/tools/modelines.html
797 * indent-tabs-mode: nil
800 * vi: set shiftwidth=2 tabstop=8 expandtab:
801 * :indentSize=2:tabSize=8:noTabs=true: