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