SCTP: plug the remaining memleaks in the tap
[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 #include <epan/uat-int.h>
56
57 #include <codecs/codecs.h>
58
59 #include "log.h"
60
61 #include <wsutil/str_util.h>
62 #include <wsutil/utf8_entities.h>
63
64 #ifdef HAVE_PLUGINS
65 #include <wsutil/plugins.h>
66 #endif
67
68 #include "sharkd.h"
69
70 #define INIT_FAILED 1
71 #define EPAN_INIT_FAIL 2
72
73 capture_file cfile;
74
75 static guint32 cum_bytes;
76 static frame_data ref_frame;
77
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);
84
85 static void
86 print_current_user(void) {
87   gchar *cur_user, *cur_group;
88
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\".",
93       cur_user, cur_group);
94     g_free(cur_user);
95     g_free(cur_group);
96     if (running_with_special_privs()) {
97       fprintf(stderr, " This could be dangerous.");
98     }
99     fprintf(stderr, "\n");
100   }
101 }
102
103 int
104 main(int argc, char *argv[])
105 {
106   GString             *comp_info_str;
107   GString             *runtime_info_str;
108   char                *init_progfile_dir_error;
109
110   char                *err_msg = NULL;
111   e_prefs             *prefs_p;
112   int                  ret = EXIT_SUCCESS;
113
114   cmdarg_err_init(failure_warning_message, failure_message_cont);
115
116   /*
117    * Get credential information for later use, and drop privileges
118    * before doing anything else.
119    * Let the user know if anything happened.
120    */
121   init_process_policies();
122   relinquish_special_privs_perm();
123   print_current_user();
124
125   /*
126    * Attempt to get the pathname of the executable file.
127    */
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);
132   }
133
134   /* Get the compile-time version information string */
135   comp_info_str = get_compiled_version_info(NULL, epan_get_compiled_version_info);
136
137   /* Get the run-time version information string */
138   runtime_info_str = get_runtime_version_info(epan_get_runtime_version_info);
139
140   /* Add it to the information to be reported on a crash. */
141   ws_add_crash_info("Sharkd (Wireshark) %s\n"
142          "\n"
143          "%s"
144          "\n"
145          "%s",
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);
149
150   if (sharkd_init(argc, argv) < 0)
151   {
152     printf("cannot initialize sharkd\n");
153     ret = INIT_FAILED;
154     goto clean_exit;
155   }
156
157   init_report_message(failure_warning_message, failure_warning_message,
158                       open_failure_message, read_failure_message,
159                       write_failure_message);
160
161   timestamp_set_type(TS_RELATIVE);
162   timestamp_set_precision(TS_PREC_AUTO);
163   timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
164
165   wtap_init(TRUE);
166
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,
172                  NULL)) {
173     ret = EPAN_INIT_FAIL;
174     goto clean_exit;
175   }
176
177   codecs_init();
178
179   /* Load libwireshark settings from the current profile. */
180   prefs_p = epan_load_settings();
181
182   read_filter_list(CFILTER_LIST);
183
184   if (!color_filters_init(&err_msg, NULL)) {
185      fprintf(stderr, "%s\n", err_msg);
186      g_free(err_msg);
187   }
188
189   cap_file_init(&cfile);
190
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. */
194   prefs_apply_all();
195
196   /* Build the column format array */
197   build_column_format_array(&cfile.cinfo, prefs_p->num_cols, TRUE);
198
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"));
203 #endif
204
205   ret = sharkd_loop();
206 clean_exit:
207   col_cleanup(&cfile.cinfo);
208   free_filter_lists();
209   codecs_cleanup();
210   wtap_cleanup();
211   free_progdirs();
212   return ret;
213 }
214
215 static const nstime_t *
216 sharkd_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num)
217 {
218   if (prov->ref && prov->ref->num == frame_num)
219     return &prov->ref->abs_ts;
220
221   if (prov->prev_dis && prov->prev_dis->num == frame_num)
222     return &prov->prev_dis->abs_ts;
223
224   if (prov->prev_cap && prov->prev_cap->num == frame_num)
225     return &prov->prev_cap->abs_ts;
226
227   if (prov->frames) {
228      frame_data *fd = frame_data_sequence_find(prov->frames, frame_num);
229
230      return (fd) ? &fd->abs_ts : NULL;
231   }
232
233   return NULL;
234 }
235
236 static epan_t *
237 sharkd_epan_new(capture_file *cf)
238 {
239   static const struct packet_provider_funcs funcs = {
240     sharkd_get_frame_ts,
241     cap_file_provider_get_interface_name,
242     cap_file_provider_get_interface_description,
243     cap_file_provider_get_user_comment
244   };
245
246   return epan_new(&cf->provider, &funcs);
247 }
248
249 static gboolean
250 process_packet(capture_file *cf, epan_dissect_t *edt,
251                gint64 offset, wtap_rec *rec, const guchar *pd)
252 {
253   frame_data     fdlocal;
254   gboolean       passed;
255
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'. */
259   passed = TRUE;
260
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);
264
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. */
268   if (edt) {
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();
273
274     /* If we're running a read filter, prime the epan_dissect_t with that
275        filter. */
276     if (cf->rfcode)
277       epan_dissect_prime_with_dfilter(edt, cf->rfcode);
278
279     if (cf->dfcode)
280       epan_dissect_prime_with_dfilter(edt, cf->dfcode);
281
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);
285
286     frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
287                                   &cf->provider.ref, cf->provider.prev_dis);
288     if (cf->provider.ref == &fdlocal) {
289       ref_frame = fdlocal;
290       cf->provider.ref = &ref_frame;
291     }
292
293     epan_dissect_run(edt, cf->cd_t, rec,
294                      frame_tvbuff_new(&cf->provider, &fdlocal, pd),
295                      &fdlocal, NULL);
296
297     /* Run the read filter if we have one. */
298     if (cf->rfcode)
299       passed = dfilter_apply_edt(cf->rfcode, edt);
300   }
301
302   if (passed) {
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);
305
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.
311      */
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);
315       }
316     }
317
318     cf->count++;
319   } else {
320     /* if we don't add it to the frame_data_sequence, clean it up right now
321      * to avoid leaks */
322     frame_data_destroy(&fdlocal);
323   }
324
325   if (edt)
326     epan_dissect_reset(edt);
327
328   return passed;
329 }
330
331
332 static int
333 load_cap_file(capture_file *cf, int max_packet_count, gint64 max_byte_count)
334 {
335   int          err;
336   gchar       *err_info = NULL;
337   gint64       data_offset;
338   epan_dissect_t *edt = NULL;
339
340   {
341     /* Allocate a frame_data_sequence for all the frames. */
342     cf->provider.frames = new_frame_data_sequence();
343
344     {
345       gboolean create_proto_tree;
346
347       /*
348        * Determine whether we need to create a protocol tree.
349        * We do if:
350        *
351        *    we're going to apply a read filter;
352        *
353        *    we're going to apply a display filter;
354        *
355        *    a postdissector wants field values or protocols
356        *    on the first pass.
357        */
358       create_proto_tree =
359         (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids());
360
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);
364     }
365
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 ?)
373          */
374         if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
375           err = 0; /* This is not an error */
376           break;
377         }
378       }
379     }
380
381     if (edt) {
382       epan_dissect_free(edt);
383       edt = NULL;
384     }
385
386     /* Close the sequential I/O side, to free up memory it requires. */
387     wtap_sequential_close(cf->provider.wth);
388
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();
392
393     cf->provider.prev_dis = NULL;
394     cf->provider.prev_cap = NULL;
395   }
396
397   if (err != 0) {
398     cfile_read_failure_message("sharkd", cf->filename, err, err_info);
399   }
400
401   return err;
402 }
403
404 cf_status_t
405 cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
406 {
407   wtap  *wth;
408   gchar *err_info;
409
410   wth = wtap_open_offline(fname, type, err, &err_info, TRUE);
411   if (wth == NULL)
412     goto fail;
413
414   /* The open succeeded.  Fill in the information for this file. */
415
416   /* Create new epan session for dissection. */
417   epan_free(cf->epan);
418   cf->epan = sharkd_epan_new(cf);
419
420   cf->provider.wth = wth;
421   cf->f_datalen = 0; /* not used, but set it anyway */
422
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,
425      in any case. */
426   cf->filename = g_strdup(fname);
427
428   /* Indicate whether it's a permanent or temporary file. */
429   cf->is_tempfile = is_tempfile;
430
431   /* No user changes yet. */
432   cf->unsaved_changes = FALSE;
433
434   cf->cd_t      = wtap_file_type_subtype(cf->provider.wth);
435   cf->open_type = type;
436   cf->count     = 0;
437   cf->drops_known = FALSE;
438   cf->drops     = 0;
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;
444
445   cf->state = FILE_READ_IN_PROGRESS;
446
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);
449
450   return CF_OK;
451
452 fail:
453   cfile_open_failure_message("sharkd", fname, *err, err_info);
454   return CF_ERROR;
455 }
456
457 /*
458  * General errors and warnings are reported with an console message
459  * in sharkd.
460  */
461 static void
462 failure_warning_message(const char *msg_format, va_list ap)
463 {
464   fprintf(stderr, "sharkd: ");
465   vfprintf(stderr, msg_format, ap);
466   fprintf(stderr, "\n");
467 }
468
469 /*
470  * Open/create errors are reported with an console message in sharkd.
471  */
472 static void
473 open_failure_message(const char *filename, int err, gboolean for_writing)
474 {
475   fprintf(stderr, "sharkd: ");
476   fprintf(stderr, file_open_error_message(err, for_writing), filename);
477   fprintf(stderr, "\n");
478 }
479
480 /*
481  * Read errors are reported with an console message in sharkd.
482  */
483 static void
484 read_failure_message(const char *filename, int err)
485 {
486   cmdarg_err("An error occurred while reading from the file \"%s\": %s.",
487           filename, g_strerror(err));
488 }
489
490 /*
491  * Write errors are reported with an console message in sharkd.
492  */
493 static void
494 write_failure_message(const char *filename, int err)
495 {
496   cmdarg_err("An error occurred while writing to the file \"%s\": %s.",
497           filename, g_strerror(err));
498 }
499
500 /*
501  * Report additional information for an error in command-line arguments.
502  */
503 static void
504 failure_message_cont(const char *msg_format, va_list ap)
505 {
506   vfprintf(stderr, msg_format, ap);
507   fprintf(stderr, "\n");
508 }
509
510 cf_status_t
511 sharkd_cf_open(const char *fname, unsigned int type, gboolean is_tempfile, int *err)
512 {
513   return cf_open(&cfile, fname, type, is_tempfile, err);
514 }
515
516 int
517 sharkd_load_cap_file(void)
518 {
519   return load_cap_file(&cfile, 0, 0);
520 }
521
522 frame_data *
523 sharkd_get_frame(guint32 framenum)
524 {
525   return frame_data_sequence_find(cfile.provider.frames, framenum);
526 }
527
528 int
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)
530 {
531   frame_data *fdata;
532   column_info *cinfo = (dissect_columns) ? &cfile.cinfo : NULL;
533   epan_dissect_t edt;
534   gboolean create_proto_tree;
535   wtap_rec rec; /* Record metadata */
536   Buffer buf;   /* Record data */
537
538   int err;
539   char *err_info = NULL;
540
541   fdata = sharkd_get_frame(framenum);
542   if (fdata == NULL)
543     return -1;
544
545   wtap_rec_init(&rec);
546   ws_buffer_init(&buf, 1500);
547
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 */
551   }
552
553   create_proto_tree = (dissect_tree) || (cinfo && have_custom_cols(cinfo));
554   epan_dissect_init(&edt, cfile.epan, create_proto_tree, dissect_tree);
555
556   if (cinfo)
557     col_custom_prime_edt(&edt, cinfo);
558
559   /*
560    * XXX - need to catch an OutOfMemoryError exception and
561    * attempt to recover from it.
562    */
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),
568                    fdata, cinfo);
569
570   if (cinfo) {
571     /* "Stringify" non frame_data vals */
572     epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
573   }
574
575   cb(&edt, dissect_tree ? edt.tree : NULL, cinfo, dissect_bytes ? edt.pi.data_src : NULL, data);
576
577   epan_dissect_cleanup(&edt);
578   wtap_rec_cleanup(&rec);
579   ws_buffer_free(&buf);
580   return 0;
581 }
582
583 /* based on packet_list_dissect_and_cache_record */
584 int
585 sharkd_dissect_columns(frame_data *fdata, guint32 frame_ref_num, guint32 prev_dis_num, column_info *cinfo, gboolean dissect_color)
586 {
587   epan_dissect_t edt;
588   gboolean create_proto_tree;
589   wtap_rec rec; /* Record metadata */
590   Buffer buf;   /* Record data */
591
592   int err;
593   char *err_info = NULL;
594
595   wtap_rec_init(&rec);
596   ws_buffer_init(&buf, 1500);
597
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 */
602   }
603
604   create_proto_tree = (dissect_color && color_filters_used()) || (cinfo && have_custom_cols(cinfo));
605
606   epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE /* proto_tree_visible */);
607
608   if (dissect_color) {
609     color_filters_prime_edt(&edt);
610     fdata->flags.need_colorize = 1;
611   }
612
613   if (cinfo)
614     col_custom_prime_edt(&edt, cinfo);
615
616   /*
617    * XXX - need to catch an OutOfMemoryError exception and
618    * attempt to recover from it.
619    */
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),
625                    fdata, cinfo);
626
627   if (cinfo) {
628     /* "Stringify" non frame_data vals */
629     epan_dissect_fill_in_columns(&edt, FALSE, TRUE/* fill_fd_columns */);
630   }
631
632   epan_dissect_cleanup(&edt);
633   wtap_rec_cleanup(&rec);
634   ws_buffer_free(&buf);
635   return 0;
636 }
637
638 int
639 sharkd_retap(void)
640 {
641   guint32          framenum;
642   frame_data      *fdata;
643   Buffer           buf;
644   wtap_rec         rec;
645   int err;
646   char *err_info = NULL;
647
648   guint         tap_flags;
649   gboolean      create_proto_tree;
650   epan_dissect_t edt;
651   column_info   *cinfo;
652
653   /* Get the union of the flags for all tap listeners. */
654   tap_flags = union_of_tap_listener_flags();
655
656   /* If any tap listeners require the columns, construct them. */
657   cinfo = (tap_flags & TL_REQUIRES_COLUMNS) ? &cfile.cinfo : NULL;
658
659   /*
660    * Determine whether we need to create a protocol tree.
661    * We do if:
662    *
663    *    one of the tap listeners is going to apply a filter;
664    *
665    *    one of the tap listeners requires a protocol tree.
666    */
667   create_proto_tree =
668     (have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE));
669
670   wtap_rec_init(&rec);
671   ws_buffer_init(&buf, 1500);
672   epan_dissect_init(&edt, cfile.epan, create_proto_tree, FALSE);
673
674   reset_tap_listeners();
675
676   for (framenum = 1; framenum <= cfile.count; framenum++) {
677     fdata = sharkd_get_frame(framenum);
678
679     if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
680       break;
681
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)),
687                                fdata, cinfo);
688     epan_dissect_reset(&edt);
689   }
690
691   wtap_rec_cleanup(&rec);
692   ws_buffer_free(&buf);
693   epan_dissect_cleanup(&edt);
694
695   draw_tap_listeners(TRUE);
696
697   return 0;
698 }
699
700 int
701 sharkd_filter(const char *dftext, guint8 **result)
702 {
703   dfilter_t  *dfcode = NULL;
704
705   guint32 framenum, prev_dis_num = 0;
706   guint32 frames_count;
707   Buffer buf;
708   wtap_rec rec;
709   int err;
710   char *err_info = NULL;
711
712   guint8 *result_bits;
713   guint8  passed_bits;
714
715   epan_dissect_t edt;
716
717   if (!dfilter_compile(dftext, &dfcode, &err_info)) {
718     g_free(err_info);
719     return -1;
720   }
721
722   frames_count = cfile.count;
723
724   wtap_rec_init(&rec);
725   ws_buffer_init(&buf, 1500);
726   epan_dissect_init(&edt, cfile.epan, TRUE, FALSE);
727
728   passed_bits = 0;
729   result_bits = (guint8 *) g_malloc(2 + (frames_count / 8));
730
731   for (framenum = 1; framenum <= frames_count; framenum++) {
732     frame_data *fdata = sharkd_get_frame(framenum);
733
734     if ((framenum & 7) == 0) {
735       result_bits[(framenum / 8) - 1] = passed_bits;
736       passed_bits = 0;
737     }
738
739     if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
740       break;
741
742     /* frame_data_set_before_dissect */
743     epan_dissect_prime_with_dfilter(&edt, dfcode);
744
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),
750                      fdata, NULL);
751
752     if (dfilter_apply_edt(dfcode, &edt)) {
753       passed_bits |= (1 << (framenum % 8));
754       prev_dis_num = framenum;
755     }
756
757     /* if passed or ref -> frame_data_set_after_dissect */
758
759     epan_dissect_reset(&edt);
760   }
761
762   if ((framenum & 7) == 0)
763       framenum--;
764   result_bits[framenum / 8] = passed_bits;
765
766   wtap_rec_cleanup(&rec);
767   ws_buffer_free(&buf);
768   epan_dissect_cleanup(&edt);
769
770   dfilter_free(dfcode);
771
772   *result = result_bits;
773
774   return framenum;
775 }
776
777 const char *
778 sharkd_get_user_comment(const frame_data *fd)
779 {
780   return cap_file_provider_get_user_comment(&cfile.provider, fd);
781 }
782
783 int
784 sharkd_set_user_comment(frame_data *fd, const gchar *new_comment)
785 {
786   cap_file_provider_set_user_comment(&cfile.provider, fd, new_comment);
787   return 0;
788 }
789
790 #include "version.h"
791 const char *sharkd_version(void)
792 {
793   /* based on get_ws_vcs_version_info(), but shorter */
794 #ifdef VCSVERSION
795   return VCSVERSION;
796 #else
797   return VERSION;
798 #endif
799 }
800
801 /*
802  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
803  *
804  * Local variables:
805  * c-basic-offset: 2
806  * tab-width: 8
807  * indent-tabs-mode: nil
808  * End:
809  *
810  * vi: set shiftwidth=2 tabstop=8 expandtab:
811  * :indentSize=2:tabSize=8:noTabs=true:
812  */