README.md

    PCAP集线器

    1.需求场景

    在调试嵌入式物联设备时,尤其是在多个以太网物联设备交错通信的情况下,很难通过在捉襟见肘的嵌入式系统上进行数据记录与调试。如果设备连接的是一般的消费交换机,以及工业的架上交换机(一般位于车间的集控箱内),把调试笔记本插到空闲端口,是无法看到其他端口上设备的大部分数据的。这是因为交换机为了带宽和效率,会“记住”哪些MAC地址出现在哪些端口上,从而自动按照目的地址实现了点对点交换。也就是说,插在空闲口上的PC只能看到一些广播消息,大部分的UDP和TCP包是看不到的。

    在古老的年代,有一种设备叫做集线器(Hub)。Hub是一种广播式的线路组合设备,可以达到这个要求。但由于所有端口共享一个带宽,导致通信效率很差,现在已经买不到了。当代通常在交换机上进行包测试,用的是镜像端口。如果恰好没有这种工业交换机,或者需要很多的镜像端口,又该如何调试呢?针对这种调试需求,可以使用PCAP,把一台插有多个以太网端口的PC变成Hub,观察所有接口上的数据流。

    当然,这个小工具不只是一个Hub。它还具备一个点对点的Tcp隧道,允许在两个车间之间构建虚拟的交换机/集线器。同时,您可以指定任意网口采用交换机的记忆策略,或者路由器的全通策略。

    UI

    2.功能与原理

    本软件主要功能如下:

    1. 支持以太网类型(10,100,1000M)接口。
    2. 灵活选取多个接口参与构建集线器。
    3. 可以为每个接口指定Filter条件。
    4. 可以指定每个网口工作在交换机或者集线器模式。
    5. 交换机模式下双通道性能:>=100Mbps。
    6. 具备远程Tcp隧道,可把本地以太网数据带到远程。

    通过上述功能,就能够组成一个交换网络。

    (1) 基本原理

    本软件运行在调试工作站上,进程为“pcapHub”。调试的常见场景如下图所示:

    基本原理

    当进行调试时,把待调试的工业设备从工业交换机断开,并临时接入在调试工作站的网卡上。同时,也可以接驳一些便携机(如果工作站没有显示器)。为了保持与原有工业网络的联通,还需要引一路线缆,把调试工作站和工业交换机连接起来。位于两个车间上的调试工作站,可以通过额外的网口进行TCP连接,甚至可以通过互联网进行异地组网调试(TCP以太网隧道)。

    经过上述连接,调试工作站和便携机上就能看到待调试工业设备的所有通信。调试工作站PC上的两个关键数据结构是实时队列和窗口知识。这两个结构保证了低延迟(1毫秒)、不重复(防止反复抓取冗余数据造成流量风暴)。

    (2) 实时队列

    本软件的实时队列是一个环形的预分配队列,一行一个pcap包,每行一个tag_packages数据结构:

    	struct tag_packages{
    		int from_id;
    		int len;
    		QByteArray data;
    	};
    
    QVector<tag_packages> global_buffer;
    QAtomicInteger<quint64> pcap_recv_pos;
    

    data 虽然为 QByteArray,但实际已经被预分配空间。因此,global_buffer 是一个静态的内存资源。

    1. 参与软集线器的网口,被分配了ID,以便简单的维护和区分。from_id就是网口的ID,表明这个包中,来源MAC设备连接在编号为from_id的网口上。TCP远程隧道的ID是0x7FFFFFFF,地位与其余网口是平齐的。
    2. 全局只有1个队列,存储着实时的网络数据。队列长度为 PCAPIO_BUFCNT,每个队列中最常的数据长度为PCAPIO_MAXPACK字节。
    3. 全局只有1个写游标(pcap_recv_pos),所有的网口获取的数据,都会写入同一个队列。
    4. 各个网口在抓取时,会判断来源MAC是不是关联在本网口。关联在本网口上的来源MAC才会被入队
    5. 每个网口有1个读游标,不停地追赶写游标。在读取队列时,只有别的网口的来源MAC才会进行pcap_sendpack。

    上述步骤,可以确保高效的进行数据流转。

    (3)窗口知识

    窗口知识记录着每个MAC地址连着哪个网口,是一个动态字典。其最外层数据结构是一个QMap,变量名称pcap_ports。Key是MAC地址(64位整形),Value是tag_portAssign结构。

    	struct tag_portAssign{
    		int curr_id;
    		quint64 mac;
    		QString portName;
    		QDateTime dtmLastAck;
    	};
        static  QMap<quint64,tag_portAssign> pcap_ports;
    	static  QMutex mtx_ports;
    

    这个结构有个显著的特点,就是标记了最后一次捕获这种对应关系的时刻。这个时刻使得能够在5秒后捕获插拔网口更换位置的情况。

    在抓取包时,一个网卡抓获一个包,并得到一个来源MAC,遵循下面的规则来对待这个包,以避免重复抓取到刚刚写入的内容。

    ON 捕获新包,得到来源MAC
    若:字典pcap_ports内查不到来源MAC
    	(说明来源MAC就连接在本网口上,它第一次出现)
        在字典中添加新的MAC知识;
        入队,更新pcap_recv_pos;
    否则:
    	若:pcap_ports[来源MAC].curr_id==本网口ID
        	入队,更新pcap_recv_pos;
            pcap_ports[来源MAC].dtmLastAck=NOW();
        否则:
        	若 pcap_ports[来源MAC].dtmLastAck 比现在时间早5秒以上
            	(说明当前字典知识是老的,可能网线拔了,换了网口)
                pcap_ports[来源MAC].curr_id=本网口ID;
                pcap_ports[来源MAC].portName=本网口名字;
                pcap_ports[来源MAC].dtmLastAck=NOW();
            判断结束;
        判断结束;
    判断结束

    在处理队列准备向本网卡推送包时,仅推送 tag_packages.from_id != 本网口ID 的包。

    (4)并行读写

    • 各个网口对应了自己的1个抓取线程、1个写入线程。
    • 总的业务线程个数为参与网口x2
    • 对字典的访问是有互斥的。
    • 队列追赶使用的是atomic整形。

    3. 支持编译环境

    已测试的编译器:

    windows Msys2 Msys64 Qt5.15/6.4 Linux G++ Qt5.15/6.4

    项目简介

    使用libpcap或者npcap构造一个软集线器,使得调试嵌入式设备时,可以使用PC和多个网卡进行旁路wireshark调试。它还支持点对点TCP/SSL隧道,灵活选择各个接口的工作模式(Hub或者交换机)以及嵌入taskBus作为模块运行。可以说,有了PCAPHUB,对基于以太网的IoT调试就会容易很多。

    发行版本 2

    PCAPHub 20230120 Released

    全部发行版

    贡献者 2

    丁劲犇 @goldenhawking
    M manjaro-xfce @manjaro-xfce

    开发语言

    • C 72.6 %
    • C++ 26.0 %
    • CMake 0.8 %
    • QMake 0.4 %
    • HTML 0.2 %