tshark源码解析

鉴于没有在网上找到很好的tshark源码解析资源,自己就捣鼓一篇吧,作为备忘录。

本文基于tshark.c,源自wirshark 3.2.4。

  • tshark介绍

Tshark是wireshark的命令行版本,安装wireshark之后,能够通过tshark -h获得完整的参数说明,安装目录下的tshark.html提供了更详细的说明。本文不关注使用tshark,而是为了改造tshark做源代码准备。

  • 本文tshark源码解析的关注点

tshark的源码在当前版本中长达4000+行,由于个人原因,本文并非对tshark的完整解析,而仅关注离线文件解析的部分。

  • tshark的整体结构

tshark包含全局变量、辅助函数和main函数3个主要的部分,在main函数中,包含初始化、命令行参数解析、数据包获取、数据包解析、协议解析结果打印几个主要部分。

  • main的初始化

  setlocale(LC_ALL, "");
  cmdarg_err_init(failure_warning_message, failure_message_cont);
  init_process_policies();
  relinquish_special_privs_perm();
  print_current_user();
  err_msg = init_progfile_dir(argv[0]);
  initialize_funnel_ops();
  timestamp_set_type(TS_RELATIVE);
  timestamp_set_precision(TS_PREC_AUTO);
  timestamp_set_seconds_type(TS_SECONDS_DEFAULT);

  wtap_init(TRUE);

  /* Register all dissectors; we must do this before checking for the
     "-G" flag, as the "-G" flag dumps information registered by the
     dissectors, and we must do it before we read the preferences, in
     case any dissectors register preferences. */
  if (!epan_init(NULL, NULL, TRUE)) {
    exit_status = INIT_FAILED;
    goto clean_exit;
  }

  /* Register all tap listeners; we do this before we parse the arguments,
     as the "-z" argument can specify a registered tap. */

  /* we register the plugin taps before the other taps because
     stats_tree taps plugins will be registered as tap listeners
     by stats_tree_stat.c and need to registered before that */
#ifdef HAVE_PLUGINS
  register_all_plugin_tap_listeners();
#endif
  extcap_register_preferences();
  /* Register all tap listeners. */
  for (tap_reg_t *t = tap_reg_listener; t->cb_func != NULL; t++) {
    t->cb_func();
  }
  conversation_table_set_gui_info(init_iousers);
  hostlist_table_set_gui_info(init_hostlists);
  srt_table_iterate_tables(register_srt_tables, NULL);
  rtd_table_iterate_tables(register_rtd_tables, NULL);
  stat_tap_iterate_tables(register_simple_stat_tables, NULL);
/* Load libwireshark settings from the current profile. */
  prefs_p = epan_load_settings();
  prefs_loaded = TRUE;

  read_filter_list(CFILTER_LIST);

  cap_file_init(&cfile);
  • 命令行参数解析

命令行参数的解析由下列代码完成,与pcap解析相关的是-r、-Y、-J等参数,与输出相关的是-T、-e等参数,这些参数在解析的过程中会设置一些控制变量或编译成内部状态。

/* Now get our args */
  while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
  • 数据包获取与解析

pcap数据获取和解析由下列代码完成。cf_name是-r参数获取的pcap文件路径,cf_open函数位于tshark.c中,用于打开cf_name指向的文件,并将相关信息写入cfile中,cfile是一个capture_file结构体,其中包含了很多信息,如rfcode(read filter)、dfcode(display filter)等。

if (cf_name) {
    tshark_debug("tshark: Opening capture file: %s", cf_name);
    /*
     * We're reading a capture file.
     */
    if (cf_open(&cfile, cf_name, in_file_type, FALSE, &err) != CF_OK) {
      epan_cleanup();
      extcap_cleanup();
      exit_status = INVALID_FILE;
      goto clean_exit;
    }

    /* Start statistics taps; we do so after successfully opening the
       capture file, so we know we have something to compute stats
       on, and after registering all dissectors, so that MATE will
       have registered its field array so we can have a tap filter
       with one of MATE's late-registered fields as part of the
       filter. */
    start_requested_stats();

    /* Do we need to do dissection of packets?  That depends on, among
       other things, what taps are listening, so determine that after
       starting the statistics taps. */
    do_dissection = must_do_dissection(rfcode, dfcode, pdu_export_arg);

    /* Process the packets in the file */
    tshark_debug("tshark: invoking process_cap_file() to process the packets");
    TRY {
      status = process_cap_file(&cfile, output_file_name, out_file_type,         
                              out_file_name_res,
                              max_packet_count,
                               0);
    }

process_cap_file是处理pcap文件的主要函数,当不输入-2参数时,该函数内部主要调用process_cap_file_single_pass函数,在这个函数中主要的逻辑代码如下。epan_dissect_new初始化协议解析器,wtap_read逐一读取数据包,并交给process_packet_single_pass处理。

edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details);

while (wtap_read(cf->provider.wth, &rec, &buf, err, err_info, &data_offset)) {
    framenum++;

    tshark_debug("tshark: processing packet #%d", framenum);

    reset_epan_mem(cf, edt, create_proto_tree, print_packet_info && print_details);

    if (process_packet_single_pass(cf, edt, data_offset, &rec, &buf, tap_flags)) 
......

在process_packet_single_pass中,下列代码完成了协议的解析,解析结果写在edt中。可以通过迭代遍历edt来实现协议解析结果的获取。

epan_dissect_file_run_with_taps(edt, rec,
                                    frame_tvbuff_new(&cf->provider, &fdata, pd),
                                    &fdata, cinfo);

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值