• Wireshark - tshark支持iptables提供数据包


    tshark现在的数据包获取方式有两种,分别是读文件、网口监听(af-packet原始套接字)。两种方式在包获取上,都是通过读文件的形式;存在文件io操作,在专门处理大流量的情境下, 我们复用wireshark去做功能开发是不适合的,在文件io这部分很消耗性能。

    此前什么iptables和转发nat需要配置

    准备工作

    ../build/CMakeFiles/tshark.dir/link.txt 链接-lnetfilter_queue库

    通过iptables提供数据包,跳过文件读写的过程,可以大大提升性能(没有进行性能测试)

    一、将iptables加到收包方式中

    在原始代码中,real_main接口为tshark工具的入口函数,前半部分都是参数解析(我们不关注),在中间部分找到,收包代码;

    其中第一个条件if (cf_name)这里是读文件的形式,使用是通过-r *.pcap判断的,第二个else位置,里面是capture用来监听网口通过-I eth0使用。

    追加第三个iptables收包方式。

    直接固定通过iptables收包。

    cf_init_iptables接口完成初始化工作,cf是全局的数据,数据包信息,数据包状态相关,比如处理多少,丢掉多少,提供的解码工具等外来数据。里面还加了一个wtap空间,这里是关联到每个数据包的,保存数据包内容。

    cf_status_t

    cf_init_iptables(capture_file *cf,unsigned int type, gboolean is_tempfile, int *err)

    {

      wtap  *wth;

      gchar *err_info;

      wth = iptables_get_wtap_init();

     

      /* The open succeeded.  Fill in the information for this file. */

      /* Create new epan session for dissection. */

      epan_free(cf->epan);

      cf->epan = tshark_epan_new(cf);

      cf->provider.wth = wth;

      cf->f_datalen = 0; /* not used, but set it anyway */

      /* Set the file name because we need it to set the follow stream filter.

         XXX - is that still true?  We need it for other reasons, though,

         in any case. */

      /* Indicate whether it's a permanent or temporary file. */

      cf->is_tempfile = is_tempfile;

      /* No user changes yet. */

      cf->unsaved_changes = FALSE;

      cf->cd_t      = WTAP_FILE_TYPE_SUBTYPE_PCAP;

      cf->open_type = type;

      cf->count     = 0;

      cf->drops_known = FALSE;

      cf->drops     = 0;

      cf->snap      = 262144;

      nstime_set_zero(&cf->elapsed_time);

      cf->provider.ref = NULL;

      cf->provider.prev_dis = NULL;

      cf->provider.prev_cap = NULL;

      cf->state = FILE_READ_IN_PROGRESS;

      wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);

      wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);

      // 输出格式初始化

      write_preamble(cf);

      return CF_OK;

    }

    running_get_pkt_from_nfqueue0接口完成iptables初始化,创建接收队列数据包的回调,将数据包接入到tshrak的解密解码逻辑。

    void running_get_pkt_from_nfqueue0(void)

    {

    struct nfq_handle *h;

    struct nfq_q_handle *qh;

    struct nfnl_handle *nh;

    int fd;

    int rv;

    char buf[4096] __attribute__ ((aligned));

    printf("opening library handle\n");

    h = nfq_open();//创建 netfilter_queue

    if (!h) {//创建失败

    fprintf(stderr, "error during nfq_open()\n");

    exit(1);

    }

    printf("unbinding existing nf_queue handler for AF_INET (if any)\n");//解绑已经存在的队列

    if (nfq_unbind_pf(h, AF_INET) < 0) {

    fprintf(stderr, "error during nfq_unbind_pf()\n");

    exit(1);

    }

    printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");//绑定上我们创建的队列

    if (nfq_bind_pf(h, AF_INET) < 0) {

    fprintf(stderr, "error during nfq_bind_pf()\n");

    exit(1);

    }

    printf("binding this socket to queue '0'\n");//cb是回调函数

    qh = nfq_create_queue(h,  0, &cb, NULL);

    if (!qh) {

    fprintf(stderr, "error during nfq_create_queue()\n");

    exit(1);

    }

    printf("setting copy_packet mode\n");

    if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {//设置的包处理模式

    fprintf(stderr, "can't set packet_copy mode\n");

    exit(1);

    }

    fd = nfq_fd(h);

    for (;;) {

    if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) {

    //printf("pkt received\n");

    nfq_handle_packet(h, buf, rv);

    continue;

    }

    /* if your application is too slow to digest the packets that

     * are sent from kernel-space, the socket buffer that we use

     * to enqueue packets may fill up returning ENOBUFS. Depending

     * on your application, this error may be ignored. Please, see

     * the doxygen documentation of this library on how to improve

     * this situation.

     */

    if (rv < 0 && errno == ENOBUFS) {

    printf("losing packets!\n");

    continue;

    }

    perror("recv failed");

    break;

    }

    printf("unbinding from queue 0\n");

    nfq_destroy_queue(qh);//摧毁队列,退出

    #ifdef INSANE

    /* normally, applications SHOULD NOT issue this command, since

     * it detaches other programs/sockets from AF_INET, too ! */

    printf("unbinding from AF_INET\n");

    nfq_unbind_pf(h, AF_INET);

    #endif

    printf("closing library handle\n");

    nfq_close(h);

    exit(0);

    }

    回调函数,这里需要做个额外的事情,因为iptables是一个三层工具,拿不到mac信息,所以这里需要加一个mac头,位置看注释。将数据包发给处理函数

    int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,

              struct nfq_data *nfa, void *data) {

    //printf("entering callback\n");

    struct nfqnl_msg_packet_hdr *ph;

    int id = 0;

    ph = nfq_get_msg_packet_hdr(nfa);

    if (ph) {

        id = ntohl(ph->packet_id);

    }

    struct iphdr *ip_header;

    unsigned char *data_buf;

    int data_len = nfq_get_payload(nfa, &data_buf);

    if (data_len > 0) {

        ip_header = (struct iphdr *)data_buf;

        //printf("Source IP: %s\n", inet_ntoa(*(struct in_addr *)&ip_header->saddr));

        //printf("Destination IP: %s\n", inet_ntoa(*(struct in_addr *)&ip_header->daddr));

    // 构造新的缓冲区

        int new_buf_len = 14 + data_len;

        unsigned char *new_buf = (unsigned char *)malloc(new_buf_len);

        if (new_buf == NULL) {

            perror("malloc");

            return nfq_set_verdict(qh, id, NF_DROP, 0, NULL);

        }

        // 将MAC头复制到新的缓冲区

        memcpy(new_buf, temp_mac_header, 14);

        // 将data_buf复制到新的缓冲区中紧随MAC头的位置

        memcpy(new_buf + 14, data_buf, data_len);

    process_iptables_queue_packet_signle(new_buf_len,new_buf);

      

       free(new_buf);

    }

        return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);

    }

    处理函数,初始化一个空间,数据包的所有内容保存在这里,用完释放

    void process_iptables_queue_packet_signle(int datalen, unsigned char *data)

    {

    capture_file *cf = &cfile;

    int create_proto_tree = 1; // 是否生成解析树

    int print_detile = 1;      // 是否打印详细信息

    epan_dissect_t *edt = epan_dissect_new(cf->epan, create_proto_tree, print_detile);

    iptables_set_wth_rec_values(cf->provider.wth,datalen);

    process_packet_single_pass(cf,edt,0,wtap_get_rec(cf->provider.wth),data,0);

    if (edt) {

          epan_dissect_free(edt);

          edt = NULL;

        }

    }

    这里对iptables的patch就完成了,试验一下

    Run/tshark执行,提示绑定队列

    重放数据包正常打印解析结果

  • 相关阅读:
    【Matlab】-- 飞蛾扑火优化算法
    Android系统10 RK3399 init进程启动(三十五) 属性文件介绍和生成过程
    mongdb shell无法链接数据库
    场景交互与场景漫游-对象选取(8-2)
    策略验证_指标买点分析技法_运用KDJ随机指标选择买点
    常见的垃圾回收算法有以下几种
    matlab 点云最小二乘拟合平面(PCA法)
    微信机器人开发
    GBase 8c向表中插入数据(二)
    45 深度学习(九):transformer
  • 原文地址:https://blog.csdn.net/qq_41167620/article/details/140107045