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