Don't use dladdr() to get a pathname for the current executable().
[metze/wireshark/wip.git] / sharkd.c
1 /* sharkd.c
2  *
3  * Daemon variant of Wireshark
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11
12 #include <config.h>
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <limits.h>
18 #include <errno.h>
19 #include <signal.h>
20
21 #include <glib.h>
22
23 #include <epan/exceptions.h>
24 #include <epan/epan.h>
25
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>
36
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>
46 #include "ui/util.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>
54 #include <epan/tap.h>
55
56 #include <codecs/codecs.h>
57
58 #include "log.h"
59
60 #include <wsutil/str_util.h>
61 #include <wsutil/utf8_entities.h>
62
63 #ifdef HAVE_PLUGINS
64 #include <wsutil/plugins.h>
65 #endif
66
67 #include "sharkd.h"
68
69 #define INIT_FAILED 1
70 #define EPAN_INIT_FAIL 2
71
72 capture_file cfile;
73
74 static guint32 cum_bytes;
75 static frame_data ref_frame;
76
77 static void failure_warning_message(const char *msg_format, va_list ap);
78 static void open_failure_message(const char *filename, int err,
79     gboolean for_writing);
80 static void read_failure_message(const char *filename, int err);
81 static void write_failure_message(const char *filename, int err);
82 static void failure_message_cont(const char *msg_format, va_list ap);
83
84 static void
85 print_current_user(void) {
86   gchar *cur_user, *cur_group;
87
88   if (started_with_special_privs()) {
89     cur_user = get_cur_username();
90     cur_group = get_cur_groupname();
91     fprintf(stderr, "Running as user \"%s\" and group \"%s\".",
92       cur_user, cur_group);
93     g_free(cur_user);
94     g_free(cur_group);
95     if (running_with_special_privs()) {
96       fprintf(stderr, " This could be dangerous.");
97     }
98     fprintf(stderr, "\n");
99   }
100 }
101
102 int
103 main(int argc, char *argv[])
104 {
105   GString             *comp_info_str;
106   GString             *runtime_info_str;
107   char                *init_progfile_dir_error;
108
109   char                *err_msg = NULL;
110   e_prefs             *prefs_p;
111   int                  ret = EXIT_SUCCESS;
112
113   cmdarg_err_init(failure_warning_message, failure_message_cont);
114
115   /*
116    * Get credential information for later use, and drop privileges
117    * before doing anything else.
118    * Let the user know if anything happened.
119    */
120   init_process_policies();
121   relinquish_special_privs_perm();
122   print_current_user();
123
124   /*
125    * Attempt to get the pathname of the executable file.
126    */
127   init_progfile_dir_error = init_progfile_dir(argv[0]);
128   if (init_progfile_dir_error != NULL) {
129     fprintf(stderr, "sharkd: Can't get pathname of sharkd program: %s.\n",
130             init_progfile_dir_error);
131   }
132
133   /* Get the compile-time version information string */
134   comp_info_str = get_compiled_version_info(NULL, epan_get_compiled_version_info);
135
136   /* Get the run-time version information string */
137   runtime_info_str = get_runtime_version_info(epan_get_runtime_version_info);
138
139   /* Add it to the information to be reported on a crash. */
140   ws_add_crash_info("Sharkd (Wireshark) %s\n"
141          "\n"
142          "%s"
143          "\n"
144          "%s",
145       get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
146   g_string_free(comp_info_str, TRUE);
147   g_string_free(runtime_info_str, TRUE);
148
149   if (sharkd_init(argc, argv) < 0)
150   {
151     printf("cannot initialize sharkd\n");
152     ret = INIT_FAILED;
153     goto clean_exit;
154   }
155
156   init_report_message(failure_warning_message, failure_warning_message,
157                       open_failure_message, read_failure_message,
158                       write_failure_message);
159
160   timestamp_set_type(TS_RELATIVE);
161   timestamp_set_precision(TS_PREC_AUTO);
162   timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
163
164   wtap_init(TRUE);
165
166   /* Register all dissectors; we must do this before checking for the
167      "-G" flag, as the "-G" flag dumps information registered by the
168      dissectors, and we must do it before we read the preferences, in
169      case any dissectors register preferences. */
170   if (!epan_init(register_all_protocols, register_all_protocol_handoffs, NULL,
171                  NULL)) {
172     ret = EPAN_INIT_FAIL;
173     goto clean_exit;
174   }
175
176   codecs_init();
177
178   /* Load libwireshark settings from the current profile. */
179   prefs_p = epan_load_settings();
180
181   read_filter_list(CFILTER_LIST);
182
183   if (!color_filters_init(&err_msg, NULL)) {
184      fprintf(stderr, "%s\n", err_msg);
185      g_free(err_msg);
186   }
187
188   cap_file_init(&cfile);
189
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. */
193   prefs_apply_all();
194
195   /* Build the column format array */
196   build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE);
197
198   ret = sharkd_loop();
199 clean_exit:
200   col_cleanup(&cfile.cinfo);
201   free_filter_lists();
202   codecs_cleanup();
203   wtap_cleanup();
204   free_progdirs();
205   return ret;
206 }
207
208 static const nstime_t *
209 sharkd_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num)
210 {
211   if (prov->ref && prov->ref->num == frame_num)
212     return &prov->ref->abs_ts;
213
214   if (prov->prev_dis && prov->prev_dis->num == frame_num)
215     return &prov->prev_dis->abs_ts;
216
217   if (prov->prev_cap && prov->prev_cap->num == frame_num)
218     return &prov->prev_cap->abs_ts;
219
220   if (prov->frames) {
221      frame_data *fd = frame_data_sequence_find(prov->frames, frame_num);
222
223      return (fd) ? &fd->abs_ts : NULL;
224   }
225
226   return NULL;
227 }
228
229 static epan_t *
230 sharkd_epan_new(capture_file *cf)
231 {
232   static const struct packet_provider_funcs funcs = {
233     sharkd_get_frame_ts,
234     cap_file_provider_get_interface_name,
235     cap_file_provider_get_interface_description,
236     cap_file_provider_get_user_comment
237   };
238
239   return epan_new(&cf->provider, &funcs);
240 }
241
242 static gboolean
243 process_packet(capture_file *cf, epan_dissect_t *edt,
244                gint64 offset, wtap_rec *rec, const guchar *pd)
245 {
246   frame_data     fdlocal;
247   gboolean       passed;
248
249   /* If we're not running a display filter and we're not printing any
250      packet information, we don't need to do a dissection. This means
251      that all packets can be marked as 'passed'. */
252   passed = TRUE;
253
254   /* The frame number of this packet, if we add it to the set of frames,
255      would be one more than the count of frames in the file so far. */
256   frame_data_init(&fdlocal, cf->count + 1, rec, offset, cum_bytes);
257
258   /* If we're going to print packet information, or we're going to
259      run a read filter, or display filter, or we're going to process taps, set up to
260      do a dissection and do so. */
261   if (edt) {
262     if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
263         gbl_resolv_flags.transport_name)
264       /* Grab any resolved addresses */
265       host_name_lookup_process();
266
267     /* If we're running a read filter, prime the epan_dissect_t with that
268        filter. */
269     if (cf->rfcode)
270       epan_dissect_prime_with_dfilter(edt, cf->rfcode);
271
272     if (cf->dfcode)
273       epan_dissect_prime_with_dfilter(edt, cf->dfcode);
274
275     /* This is the first and only pass, so prime the epan_dissect_t
276        with the hfids postdissectors want on the first pass. */
277     prime_epan_dissect_with_postdissector_wanted_hfids(edt);
278
279     frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
280                                   &cf->provider.ref, cf->provider.prev_dis);
281     if (cf->provider.ref == &fdlocal) {
282       ref_frame = fdlocal;
283       cf->provider.ref = &ref_frame;
284     }
285
286     epan_dissect_run(edt, cf->cd_t, rec,
287                      frame_tvbuff_new(&cf->provider, &fdlocal, pd),
288                      &fdlocal, NULL);
289
290     /* Run the read filter if we have one. */
291     if (cf->rfcode)
292       passed = dfilter_apply_edt(cf->rfcode, edt);
293   }
294
295   if (passed) {
296     frame_data_set_after_dissect(&fdlocal, &cum_bytes);
297     cf->provider.prev_cap = cf->provider.prev_dis = frame_data_sequence_add(cf->provider.frames, &fdlocal);
298
299     /* If we're not doing dissection then there won't be any dependent frames.
300      * More importantly, edt.pi.dependent_frames won't be initialized because
301      * epan hasn't been initialized.
302      * if we *are* doing dissection, then mark the dependent frames, but only
303      * if a display filter was given and it matches this packet.
304      */
305     if (edt && cf->dfcode) {
306       if (dfilter_apply_edt(cf->dfcode, edt)) {
307         g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
308       }
309     }
310
311     cf->count++;
312   } else {
313     /* if we don't add it to the frame_data_sequence, clean it up right now
314      * to avoid leaks */
315     frame_data_destroy(&fdlocal);
316   }
317
318   if (edt)
319     epan_dissect_reset(edt);
320
321   return passed;
322 }
323
324
325 static int
326 load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count)
327 {
328   int          err;
329   gchar       *err_info = NULL;
330   gint64       data_offset;
331   epan_dissect_t *edt = NULL;
332
333   {
334     /* Allocate a frame_data_sequence for all the frames. */
335     cf->provider.frames = new_frame_data_sequence();
336
337     {
338       gboolean create_proto_tree;
339
340       /*
341        * Determine whether we need to create a protocol tree.
342        * We do if:
343        *
344        *    we're going to apply a read filter;
345        *
346        *    we're going to apply a display filter;
347        *
348        *    a postdissector wants field values or protocols
349        *    on the first pass.
350        */
351       create_proto_tree =
352         (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids());
353
354       /* We're not going to display the protocol tree on this pass,
355          so it's not going to be "visible". */
356       edt = epan_dissect_new(cf->epan, create_proto_tree, FALSE);
357     }
358
359     while (wtap_read(cf->provider.wth, &err, &err_info, &data_offset)) {
360       if (process_packet(cf, edt, data_offset, wtap_get_rec(cf->provider.wth),
361                          wtap_get_buf_ptr(cf->provider.wth))) {
362         /* Stop reading if we have the maximum number of packets;
363          * When the -c option has not been used, max_packet_count
364          * starts at 0, which practically means, never stop reading.
365          * (unless we roll over max_packet_count ?)
366          */
367         if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
368           err = 0; /* This is not an error */
369           break;
370         }
371       }
372     }
373
374     if (edt) {
375       epan_dissect_free(edt);
376       edt = NULL;
377     }
378
379     /* Close the sequential I/O side, to free up memory it requires. */
380     wtap_sequential_close(cf->provider.wth);
381
382     /* Allow the protocol dissectors to free up memory that they
383      * don't need after the sequential run-through of the packets. */
384     postseq_cleanup_all_protocols();
385
386     cf->provider.prev_dis = NULL;
387     cf->provider.prev_cap = NULL;
388   }
389
390   if (err != 0) {
391     cfile_read_failure_message("sharkd", cf->filename, err, err_info);
392   }
393
394   return err;
395 }
396
397 cf_status_t
398 cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
399 {
400   wtap  *wth;
401   gchar *err_info;
402
403   wth = wtap_open_offline(fname, type, err, &err_info, TRUE);
404   if (wth == NULL)
405     goto fail;
406
407   /* The open succeeded.  Fill in the information for this file. */
408
409   /* Create new epan session for dissection. */
410   epan_free(cf->epan);
411   cf->epan = sharkd_epan_new(cf);
412
413   cf->provider.wth = wth;
414   cf->f_datalen = 0; /* not used, but set it anyway */
415
416   /* Set the file name because we need it to set the follow stream filter.
417      XXX - is that still true?  We need it for other reasons, though,
418      in any case. */
419   cf->filename = g_strdup(fname);
420
421   /* Indicate whether it's a permanent or temporary file. */
422   cf->is_tempfile = is_tempfile;
423
424   /* No user changes yet. */
425   cf->unsaved_changes = FALSE;
426
427   cf->cd_t      = wtap_file_type_subtype(cf->provider.wth);
428   cf->open_type = type;
429   cf->count     = 0;
430   cf->drops_known = FALSE;
431   cf->drops     = 0;
432   cf->snap      = wtap_snapshot_length(cf->provider.wth);
433   nstime_set_zero(&cf->elapsed_time);
434   cf->provider.ref = NULL;
435   cf->provider.prev_dis = NULL;
436   cf->provider.prev_cap = NULL;
437
438   cf->state = FILE_READ_IN_PROGRESS;
439
440   wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
441   wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
442
443   return CF_OK;
444
445 fail:
446   cfile_open_failure_message("sharkd", fname, *err, err_info);
447   return CF_ERROR;
448 }
449
450 /*
451  * General errors and warnings are reported with an console message
452  * in sharkd.
453  */
454 static void
455 failure_warning_message(const char *msg_format, va_list ap)
456 {
457   fprintf(stderr, "sharkd: ");
458   vfprintf(stderr, msg_format, ap);
459   fprintf(stderr, "\n");
460 }
461
462 /*
463  * Open/create errors are reported with an console message in sharkd.
464  */
465 static void
466 open_failure_message(const char *filename, int err, gboolean for_writing)
467 {
468   fprintf(stderr, "sharkd: ");
469   fprintf(stderr, file_open_error_message(err, for_writing), filename);
470   fprintf(stderr, "\n");
471 }
472
473 /*
474  * Read errors are reported with an console message in sharkd.
475  */
476 static void
477 read_failure_message(const char *filename, int err)
478 {
479   cmdarg_err("An error occurred while reading from the file \"%s\": %s.",
480           filename, g_strerror(err));
481 }
482
483 /*
484  * Write errors are reported with an console message in sharkd.
485  */
486 static void
487 write_failure_message(const char *filename, int err)
488 {
489   cmdarg_err("An error occurred while writing to the file \"%s\": %s.",
490           filename, g_strerror(err));
491 }
492
493 /*
494  * Report additional information for an error in command-line arguments.
495  */
496 static void
497 failure_message_cont(const char *msg_format, va_list ap)
498 {
499   vfprintf(stderr, msg_format, ap);
500   fprintf(stderr, "\n");
501 }
502
503 cf_status_t
504 sharkd_cf_open(const char *fname, unsigned int type, gboolean is_tempfile, int *err)
505 {
506   return cf_open(&cfile, fname, type, is_tempfile, err);
507 }
508
509 int
510 sharkd_load_cap_file(void)
511 {
512   return load_cap_file(&cfile, 0, 0);
513 }
514
515 frame_data *
516 sharkd_get_frame(guint32 framenum)
517 {
518   return frame_data_sequence_find(cfile.provider.frames, framenum);
519 }
520
521 int
522 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)
523 {
524   frame_data *fdata;
525   column_info *cinfo = (dissect_columns) ? &cfile.cinfo : NULL;
526   epan_dissect_t edt;
527   gboolean create_proto_tree;
528   wtap_rec rec; /* Record metadata */
529   Buffer buf;   /* Record data */
530
531   int err;
532   char *err_info = NULL;
533
534   fdata = sharkd_get_frame(framenum);
535   if (fdata == NULL)
536     return -1;
537
538   wtap_rec_init(&rec);
539   ws_buffer_init(&buf, 1500);
540
541   if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info)) {
542     ws_buffer_free(&buf);
543     return -1; /* error reading the record */
544   }
545
546   create_proto_tree = (dissect_tree) || (cinfo && have_custom_cols(cinfo));
547   epan_dissect_init(&edt, cfile.epan, create_proto_tree, dissect_tree);
548
549   if (cinfo)
550     col_custom_prime_edt(&edt, cinfo);
551
552   /*
553    * XXX - need to catch an OutOfMemoryError exception and
554    * attempt to recover from it.
555    */
556   fdata->flags.ref_time = (framenum == frame_ref_num);
557   fdata->frame_ref_num = frame_ref_num;
558   fdata->prev_dis_num = prev_dis_num;
559   epan_dissect_run(&edt, cfile.cd_t, &rec,
560                    frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
561                    fdata, cinfo);
562
563   if (cinfo) {
564     /* "Stringify" non frame_data vals */
565     epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
566   }
567
568   cb(&edt, dissect_tree ? edt.tree : NULL, cinfo, dissect_bytes ? edt.pi.data_src : NULL, data);
569
570   epan_dissect_cleanup(&edt);
571   wtap_rec_cleanup(&rec);
572   ws_buffer_free(&buf);
573   return 0;
574 }
575
576 /* based on packet_list_dissect_and_cache_record */
577 int
578 sharkd_dissect_columns(frame_data *fdata, guint32 frame_ref_num, guint32 prev_dis_num, column_info *cinfo, gboolean dissect_color)
579 {
580   epan_dissect_t edt;
581   gboolean create_proto_tree;
582   wtap_rec rec; /* Record metadata */
583   Buffer buf;   /* Record data */
584
585   int err;
586   char *err_info = NULL;
587
588   wtap_rec_init(&rec);
589   ws_buffer_init(&buf, 1500);
590
591   if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info)) {
592     col_fill_in_error(cinfo, fdata, FALSE, FALSE /* fill_fd_columns */);
593     ws_buffer_free(&buf);
594     return -1; /* error reading the record */
595   }
596
597   create_proto_tree = (dissect_color && color_filters_used()) || (cinfo && have_custom_cols(cinfo));
598
599   epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE /* proto_tree_visible */);
600
601   if (dissect_color) {
602     color_filters_prime_edt(&edt);
603     fdata->flags.need_colorize = 1;
604   }
605
606   if (cinfo)
607     col_custom_prime_edt(&edt, cinfo);
608
609   /*
610    * XXX - need to catch an OutOfMemoryError exception and
611    * attempt to recover from it.
612    */
613   fdata->flags.ref_time = (fdata->num == frame_ref_num);
614   fdata->frame_ref_num = frame_ref_num;
615   fdata->prev_dis_num = prev_dis_num;
616   epan_dissect_run(&edt, cfile.cd_t, &rec,
617                    frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
618                    fdata, cinfo);
619
620   if (cinfo) {
621     /* "Stringify" non frame_data vals */
622     epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
623   }
624
625   epan_dissect_cleanup(&edt);
626   wtap_rec_cleanup(&rec);
627   ws_buffer_free(&buf);
628   return 0;
629 }
630
631 int
632 sharkd_retap(void)
633 {
634   guint32          framenum;
635   frame_data      *fdata;
636   Buffer           buf;
637   wtap_rec         rec;
638   int err;
639   char *err_info = NULL;
640
641   guint         tap_flags;
642   gboolean      create_proto_tree;
643   epan_dissect_t edt;
644   column_info   *cinfo;
645
646   /* Get the union of the flags for all tap listeners. */
647   tap_flags = union_of_tap_listener_flags();
648
649   /* If any tap listeners require the columns, construct them. */
650   cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cfile.cinfo : NULL;
651
652   /*
653    * Determine whether we need to create a protocol tree.
654    * We do if:
655    *
656    *    one of the tap listeners is going to apply a filter;
657    *
658    *    one of the tap listeners requires a protocol tree.
659    */
660   create_proto_tree =
661     (have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE));
662
663   wtap_rec_init(&rec);
664   ws_buffer_init(&buf, 1500);
665   epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE);
666
667   reset_tap_listeners();
668
669   for (framenum = 1; framenum <= cfile.count; framenum++) {
670     fdata = sharkd_get_frame(framenum);
671
672     if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
673       break;
674
675     fdata->flags.ref_time = FALSE;
676     fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
677     fdata->prev_dis_num = framenum - 1;
678     epan_dissect_run_with_taps(&edt, cfile.cd_t, &rec,
679                                frame_tvbuff_new(&cfile.provider, fdata, ws_buffer_start_ptr(&buf)),
680                                fdata, cinfo);
681     epan_dissect_reset(&edt);
682   }
683
684   wtap_rec_cleanup(&rec);
685   ws_buffer_free(&buf);
686   epan_dissect_cleanup(&edt);
687
688   draw_tap_listeners(TRUE);
689
690   return 0;
691 }
692
693 int
694 sharkd_filter(const char *dftext, guint8 **result)
695 {
696   dfilter_t  *dfcode = NULL;
697
698   guint32 framenum, prev_dis_num = 0;
699   guint32 frames_count;
700   Buffer buf;
701   wtap_rec rec;
702   int err;
703   char *err_info = NULL;
704
705   guint8 *result_bits;
706   guint8  passed_bits;
707
708   epan_dissect_t edt;
709
710   if (!dfilter_compile(dftext, &dfcode, &err_info)) {
711     g_free(err_info);
712     return -1;
713   }
714
715   frames_count = cfile.count;
716
717   wtap_rec_init(&rec);
718   ws_buffer_init(&buf, 1500);
719   epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
720
721   passed_bits = 0;
722   result_bits = (guint8 *) g_malloc(2 + (frames_count / 8));
723
724   for (framenum = 1; framenum <= frames_count; framenum++) {
725     frame_data *fdata = sharkd_get_frame(framenum);
726
727     if ((framenum & 7) == 0) {
728       result_bits[(framenum / 8) - 1] = passed_bits;
729       passed_bits = 0;
730     }
731
732     if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
733       break;
734
735     /* frame_data_set_before_dissect */
736     epan_dissect_prime_with_dfilter(&edt, dfcode);
737
738     fdata->flags.ref_time = FALSE;
739     fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
740     fdata->prev_dis_num = prev_dis_num;
741     epan_dissect_run(&edt, cfile.cd_t, &rec,
742                      frame_tvbuff_new_buffer(&cfile.provider, fdata, &buf),
743                      fdata, NULL);
744
745     if (dfilter_apply_edt(dfcode, &edt)) {
746       passed_bits |= (1 << (framenum % 8));
747       prev_dis_num = framenum;
748     }
749
750     /* if passed or ref -> frame_data_set_after_dissect */
751
752     epan_dissect_reset(&edt);
753   }
754
755   if ((framenum & 7) == 0)
756       framenum--;
757   result_bits[framenum / 8] = passed_bits;
758
759   wtap_rec_cleanup(&rec);
760   ws_buffer_free(&buf);
761   epan_dissect_cleanup(&edt);
762
763   dfilter_free(dfcode);
764
765   *result = result_bits;
766
767   return framenum;
768 }
769
770 const char *
771 sharkd_get_user_comment(const frame_data *fd)
772 {
773   return cap_file_provider_get_user_comment(&cfile.provider, fd);
774 }
775
776 int
777 sharkd_set_user_comment(frame_data *fd, const gchar *new_comment)
778 {
779   cap_file_provider_set_user_comment(&cfile.provider, fd, new_comment);
780   return 0;
781 }
782
783 #include "version.h"
784 const char *sharkd_version(void)
785 {
786   /* based on get_ws_vcs_version_info(), but shorter */
787 #ifdef VCSVERSION
788   return VCSVERSION;
789 #else
790   return VERSION;
791 #endif
792 }
793
794 /*
795  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
796  *
797  * Local variables:
798  * c-basic-offset: 2
799  * tab-width: 8
800  * indent-tabs-mode: nil
801  * End:
802  *
803  * vi: set shiftwidth=2 tabstop=8 expandtab:
804  * :indentSize=2:tabSize=8:noTabs=true:
805  */