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