Skip to content

结构体 ​

c++
#ifndef FORMAT_H
#define FORMAT_H
typedef unsigned char u_char;     // 1 byte
typedef unsigned short u_short;   // 2 byte
typedef unsigned int u_int;       // 4 byte
typedef unsigned long u_long;     // 4 byte

//***************************************************************
// Ethernet protocol format 数据链路层mac帧头部
/*
+-------------------+-----------------+------+
|       6 byte      |     6 byte      |2 byte|
+-------------------+-----------------+------+
|destination address|  source address | type |
+-------------------+-----------------+------+

    type:
        0x0800:表示IPv4数据包。当类型标识字段的值为0x0800时,接收方会将数据部分解析为IPv4协议的数据包。
        0x86DD:表示IPv6数据包。当类型标识字段的值为0x86DD时,接收方会将数据部分解析为IPv6协议的数据包。
        0x0806:表示ARP数据包。当类型标识字段的值为0x0806时,接收方会将数据部分解析为ARP协议的数据包。
        0x8100:表示VLAN标记帧。当类型标识字段的值为0x8100时,接收方会将数据部分解析为VLAN标记帧的数据包。
        0x8847:表示MPLS(Multiprotocol Label Switching)数据包。当类型标识字段的值为0x8847时,接收方会将数据部分解析为MPLS协议的数据包。
*/
typedef struct ether_header{   // 14 byte
    u_char ether_des_host[6];  // destination addr [6 byte]
    u_char ether_src_host[6];  // source addr [6 byte]
    u_short ether_type;        // type [2 byte]
}ETHER_HEADER;

//----------------------------------------------------------------------------------------------------------------------
// Ipv4 header
/*
+-------+-----------+---------------+-------------------------+
| 4 bit |   4 bit   |    8 bit      |          16 bit         |
+-------+-----------+---------------+-------------------------+
|version|head length|  TOS/DS_byte  |        total length     |
+-------------------+--+---+---+----+-+-+-+-------------------+
|          identification           |R|D|M|    offset         |
+-------------------+---------------+-+-+-+-------------------+
|       ttl         |     protocol  |         checksum        |
+-------------------+---------------+-------------------------+
|                   source ip address                         |
+-------------------------------------------------------------+
|                 destination ip address                      |
+-------------------------------------------------------------+

IP头中的R|D|M字段是IP标志字段,共3位,分别代表Reserved(保留位)、Don't Fragment(不分片位)和More Fragments(更多分片位)。
其中,Reserved位是保留位,目前没有使用,必须设置为0。Don't Fragment位表示是否允许分片,如果设置为1,则表示不允许分片;如果设置为0,
则表示允许分片。More Fragments位表示是否是最后一片分片,如果设置为1,则表示还有后续分片;如果设置为0,则表示这是最后一片分片。
这些标志位在IP分组的传输过程中起到了重要的作用,可以帮助网络设备和主机进行分组的重组和重传,从而保证数据的完整性和可靠性。
*/

//结构体中每个字段的顺序 一定要和ip头的字节结构对应 为了之后转换的时候内存对得上
typedef struct ip_header{           // 共20 byte
    u_char versiosn_head_length;    // version [4 bit] + length of header [4 bit] 头部长度最小长度为20字节,最大长度为60字节
    u_char TOS;                     // [1 byte] 指定服务类型(Type of Service)和差错控制(Differentiated Services)
    u_short total_length;           // [2 byte] 指定整个IP数据包的长度,包括首部和数据部分。
    u_short identification;         // [2 byte] 用于唯一标识IP数据包,通常由发送方生成。
    u_short flag_offset;            // [2 byte] RDM 和 offset
    u_char ttl;                     // [1 byte]
    u_char protocol;                // [1 byte] 指定数据部分使用的协议类型,如TCP、UDP等。
    u_short checksum;               // [2 byte] 用于检验IP首部是否正确。
    u_int src_addr;                 // [4 byte] 原地址
    u_int des_addr;                 // [4 byte] 目的地址
}IP_HEADER;

//----------------------------------------------------------------------------------------------------------------------
// Tcp header
/*
+----------------------+---------------------+
|         16 bit       |       16 bit        |
+----------------------+---------------------+
|      source port     |  destination port   |
+----------------------+---------------------+
|              sequence number               |
+----------------------+---------------------+
|                 ack number                 |
+----+---------+-------+---------------------+
|head 4|reserve 6|flags 6|     window size   |
+----+---------+-------+---------------------+
|     checksum         |   urgent pointer    |
+----------------------+---------------------+
reserve占6个比特  全部位都为0
*/
typedef struct tcp_header{    // 20 byte
    u_short src_port;         // [2 byte]
    u_short des_port;         // [2 byte]
    u_int sequence;           // [4 byte] 序列号 标识发送数据的起点。
    u_int ack;                // [4 byte] 确认号 标识接收端希望接收到的下一批数据的起点。
    u_char header_length;     // [8 bit] tcp首部长20~60字节 后四位是保留位
    u_char flags;             // [8 bit] 前两位是保留位 后6位是标志位
    u_short window_size;      // [2 byte] 窗口大小 接收端告诉发送端自己可以接收多少数据的大小。
    u_short checksum;         // [2 byte] 校验和 用于保证数据传输的正确性的校验值。
    u_short urgent;           // [2 byte] 紧急指针 标识TCP数据段中紧急重要的数据的起始位置。
}TCP_HEADER;

//----------------------------------------------------------------------------------------------------------------------
// TLS RecordHeader
//typedef struct {
//    u_char type;    // 记录类型
//    u_short version; // TLS协议版本
//    u_short length;  // 记录长度
//} TLSRecordHead;

//typedef struct {
//    u_char handshakeType; // 握手消息类型
//    u_char length[24]; //  握手消息长度
//    // 具体的握手消息内容
//} TLSHandshakeHeader;

//----------------------------------------------------------------------------------------------------------------------
// Udp header
/*
+---------------------+---------------------+
|        16 bit       |        16 bit       |
+---------------------+---------------------+
|    source port      |   destination port  |
+---------------------+---------------------+
| data package length |       checksum      |
+---------------------+---------------------+
*/
typedef struct udp_header{ // 8 byte
    u_short src_port;      // source port [2 byte]
    u_short des_port;      // destination port [2 byte]
    u_short data_length;   // data length [2 byte]
    u_short checksum;      // checksum [2 byte]

}UDP_HEADER;

//----------------------------------------------------------------------------------------------------------------------
// Icmp header
/*
+---------------------+---------------------+
|  1 byte  |  1 byte  |        2 byte       |
+---------------------+---------------------+
|   type   |   code   |       checksum      |
+---------------------+---------------------+
|    identification   |       sequence      |
+---------------------+---------------------+
|                  option                   |
+-------------------------------------------+
*/
typedef struct icmp_header{         // at least 8 byte
    u_char type;                    // type [1 byte]
    u_char code;                    // code [1 byte]
    u_short checksum;               // checksum [2 byte]
    u_short identification;         // identification [2 byte]
    u_short sequence;               // sequence [2 byte]
}ICMP_HEADER;

//----------------------------------------------------------------------------------------------------------------------
//Arp
/*
|<--------  ARP header  ------------>|
+------+--------+-----+------+-------+----------+---------+---------------+--------------+
|2 byte| 2 byte |1byte| 1byte|2 byte |  6 byte  | 4 byte  |     6 byte    |     4 byte   |
+------+--------+-----+------+-------+----------+---------+---------------+--------------+
| type |protocol|e_len|ip_len|op_type|source mac|source ip|destination mac|destination ip|
+------+--------+-----+------+-------+----------+---------+---------------+--------------+
*/
typedef struct arp_header{   // 28 byte
    u_short hardware_type;   // [2 byte] ARP报文类型,固定为1 (ARPHDR_ETHERNET)
    u_short protocol_type;   // [2 byte] 上层协议类型,固定为0x0800,即IP协议
    u_char mac_length;       // [1 byte] Ethernet长度字段,表示以太网地址长度,固定为6。
    u_char ip_length;        // [1 byte] IPv4长度字段,表示IPv4地址长度,固定为4。
    u_short op_code;         // [2 byte] ARP报文操作类型,包括请求(1)和响应(2)。

    u_char src_eth_addr[6];  // [6 byte] 发送ARP报文的源MAC地址。
    u_char src_ip_addr[4];   // [4 byte] 发送ARP报文的源IP地址。
    u_char des_eth_addr[6];  // [6 byte] 目标MAC地址。
    u_char des_ip_addr[4];   // [4 byte] 目标IP地址。

}ARP_HEADER;
//----------------------------------------------------------------------------------------------------------------------
// dns
/*
+--------------------------+---------------------------+
|           16 bit         |1b|4bit|1b|1b|1b|1b|3b|4bit|
+--------------------------+--+----+--+--+--+--+--+----+
|      identification      |QR| OP |AA|TC|RD|RA|..|Resp|
+--------------------------+--+----+--+--+--+--+--+----+
|         Question         |       Answer RRs          |
+--------------------------+---------------------------+
|     Authority RRs        |      Additional RRs       |
+--------------------------+---------------------------+
*/
typedef struct dns_header{  // 12 byte
    u_short identification; // Identification [2 byte]
    u_short flags;          // Flags [total 2 byte]
    u_short question;       // Question Number [2 byte]
    u_short answer;         // Answer RRs [2 byte]
    u_short authority;      // Authority RRs [2 byte]
    u_short additional;     // Additional RRs [2 byte]
}DNS_HEADER;

// dns question
typedef struct dns_question{
    // char* name;          // Non-fixed
    u_short query_type;     // 2 byte
    u_short query_class;    // 2 byte
}DNS_QUESITON;

typedef struct dns_answer{
    // char* name          // Non-fixed
    u_short answer_type;   // 2 byte
    u_short answer_class;  // 2 byte
    u_int TTL;             // 4 byte
    u_short dataLength;    // 2 byte
    //char* name           // Non-fixed
}DNS_ANSWER;

#endif // FORMAT_H

主窗口 ​

c++
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include "childthread.h"
#include "pcap.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    int capture();
    void showNetworkCard();
    void AddItem(DataPackage& data);
private slots:
    void on_comboBox_currentIndexChanged(int index);
    void on_tableView_clicked(const QModelIndex &index);
    void on_lineEdit_textEdited(const QString &arg1);

private:
    Ui::MainWindow *ui;
    pcap_if_t *all_devices;                 // all adapter device
    pcap_if_t *device;                      // An adapter
    pcap_t *pointer;                        // data package pointer
    ChildThread* thread;
    QSortFilterProxyModel* sortFilterProxyModel;
    QStandardItemModel* standardItemModel;
    bool is_capture;
    int select_row;//当前选中的行
    char errbuf[PCAP_ERRBUF_SIZE];          // error buffer
    QVector<DataPackage> datas;

};
#endif // MAINWINDOW_H
c++
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QCompleter>
#include <QStringListModel>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow),is_capture(false)
{
    ui->setupUi(this);
    setWindowTitle("capture package");
    sortFilterProxyModel = new QSortFilterProxyModel;
    standardItemModel = new QStandardItemModel;
    sortFilterProxyModel->setSourceModel(standardItemModel);
    ui->tableView->setModel(sortFilterProxyModel);

//**********************GUI****************************
    //            设置treewidget隐藏标题
    ui->treeWidget->setHeaderHidden(true);
    //            QLineEdit 提示输入
    ui->lineEdit->setPlaceholderText("search keyword");
    //            QLineEdit自动完成
    // 创建一个字符串列表作为自动完成的候选项
     QStringListModel *model = new QStringListModel();
     QStringList words;
     words << "udp" << "tcp" << "tls" << "dns" << "arp";
     model->setStringList(words);

     // 创建QCompleter并设置候选项模型
     QCompleter *completer = new QCompleter(model, ui->lineEdit);
     completer->setCaseSensitivity(Qt::CaseInsensitive);  // 设置大小写不敏感

     // 将QCompleter关联到QLineEdit
     ui->lineEdit->setCompleter(completer);


    select_row = -1; //当前选中行设置为-1
    ui->run_and_stop->setIcon(QIcon(":/img/start.png"));
    ui->clear->setIcon(QIcon(":/img/empty.png"));
    ui->auto_scroll->setIcon(QIcon(":/img/downest.png"));
    //            statusBar()获取状态栏
    statusBar()->showMessage("welcome");
    //            给工具栏添加菜单栏里的按钮
    ui->toolBar->addAction(ui->run_and_stop);
    ui->toolBar->addAction(ui->clear);
    ui->toolBar->addAction(ui->auto_scroll);
    ui->toolBar->setMovable(false); //设置状态栏不可移动

    //是否显示网格线
    ui->tableView->setShowGrid(true);
    //是否显示自带的表格行号
    ui->tableView->verticalHeader()->setVisible(false);
    //点击一个item的选择模式(设置为选择一行)
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    //添加标题
    QStringList title = {"NO.","Time","Source","Destination","Protocol","Length","Info"};
    standardItemModel->setColumnCount(title.size());//设置列数
    standardItemModel->setHorizontalHeaderLabels(title);

    //字体自动换行
    ui->treeWidget->setWordWrap(true);

    //设置小标题大小
    ui->tableView->horizontalHeader()->resizeSection(0, 250);
    // 将列标题设置为自动调整大小,铺满控件
    ui->tableView->horizontalHeader()->setSectionResizeMode(title.size() - 1,QHeaderView::Stretch);

    //设置每个小标题的宽
    ui->tableView->setColumnWidth(0,50);
    ui->tableView->setColumnWidth(1,130);
    ui->tableView->setColumnWidth(2,180);
    ui->tableView->setColumnWidth(3,180);
    ui->tableView->setColumnWidth(4,100);
    ui->tableView->setColumnWidth(5,100);
    ui->tableView->setColumnWidth(6,500);

    //每一行的行高
    ui->tableView->verticalHeader()->setDefaultSectionSize(30);
    ui->tableView->setShowGrid(false);//显示网格线
    ui->tableView->verticalHeader()->setVisible(false);//自带的表格行号设置为false

    //设置搜索栏按全列模糊搜素
    sortFilterProxyModel->setFilterKeyColumn(-1);
    //设置大小写不敏感
    sortFilterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);

    //设置平滑滚动 像素滚动
    ui->treeWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);

//**********************Connect*******************************
    thread = new ChildThread;
   //获取网卡列表信息
    showNetworkCard();

    //开始捕获选定网卡的数据包
    connect(ui->run_and_stop,&QAction::triggered,this,[=](){

        //没有在捕获数据包 就开启一个线程来捕获
        if(!is_capture){
            //如果打开当前combobox选定网卡成功
            if(capture() == 0){
                qDebug()<<ui->comboBox->currentText();
                standardItemModel->removeRows(0,standardItemModel->rowCount());
                thread->SetPointer(pointer);
                thread->SetState(false);
                thread->start();
                is_capture = true; // 表示正在捕获
                ui->comboBox->setEnabled(false);//设置按钮不能再选了
                ui->run_and_stop->setIcon(QIcon(":/img/stop.png"));//修改捕获按钮的图标
                qDebug()<<"start capture";
            }else{
                qDebug()<<"fail";
            }

        }else{//否则为正在捕获 说明这次点击是暂停

            thread->SetState(true);
            thread->quit(); //终止线程
            thread->wait(); //等待线程退出
            ui->run_and_stop->setIcon(QIcon(":/img/start.png"));
            ui->comboBox->setEnabled(true);//设置按钮不能再选了
            pcap_close(pointer); //关闭已经开启的网卡
            pointer = nullptr;
            is_capture = false;
            qDebug()<<"stop capture";

        }
    });

    //接收Send信号
    connect(thread,&ChildThread::Send,this,[=](DataPackage data){
        AddItem(data);
    });
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::showNetworkCard(){
    //获取网卡信息到all_devices   all_devices指向一个包含所有网卡信息的链表
    int n = pcap_findalldevs(&all_devices,errbuf);

    //说明找不到网卡设备
    if(n == -1){
        ui->comboBox->addItem("Cannot find a matching network card, please restart and test");
        return;
    }
    ui->comboBox->clear();
    ui->comboBox->addItem("please chose the Network Card!");//添加第一项 作为提示
    for(device = all_devices;device!= nullptr;device = device->next){//遍历网卡名链表
        //处理设备名
//        QString device_name = device->name;
//        device_name.replace("\\Device\\","");
        QString device_description = device->description;
//        QString item = device_name + "   " + device_description;

        QString item =  device_description;
        //添加到combobox
        ui->comboBox->addItem(item);
    }
}

void MainWindow::AddItem(DataPackage& data)
{

    datas.push_back(data);

    int type = data.packageType;
    QColor color;
    if(type == ChildThread::ProtocolType::TCP){
        color = QColor(216,191,216);
    }else if(type == ChildThread::ProtocolType::UDP){
        color = QColor(144,238,144);
    }
    else if(type == ChildThread::ProtocolType::ICMP){
        color = QColor(238,238,0);
    }
    else if(type == ChildThread::ProtocolType::DNS){
        color = QColor(255,255,224);
    }else if(type == ChildThread::ProtocolType::HTTP){
        color = QColor(255,140,0);
    }else if(type == ChildThread::ProtocolType::TLS){
        color = QColor(255,140,224);
    }else if(type == ChildThread::ProtocolType::SSL){
        color = QColor(140,255,224);
    }else if(type == ChildThread::ProtocolType::FTP){
        color = QColor(200,200,224);
    }else{
        color = QColor(255,218,185);
    }
    QList<QStandardItem*> items;
    items.append(new QStandardItem(QString::number(standardItemModel->rowCount()+1)));
    items.append(new QStandardItem(data.timeStamp));
    items.append(new QStandardItem(data.GetIPSrc()));
    items.append(new QStandardItem(data.GetIPDes()));
    items.append(new QStandardItem(data.GetIPProtocol()));
    items.append(new QStandardItem(QString::number(data.data_length)));
    items.append(new QStandardItem(data.info));

    for(auto item:items ){
        item->setTextAlignment(Qt::AlignCenter);
    }
    standardItemModel->appendRow(items);

    for(int i = 0;i < 7;i++){
        standardItemModel->item(standardItemModel->rowCount()-1,i)->setBackground(color);
    }
}

void MainWindow::on_comboBox_currentIndexChanged(int index)
{
    int i = 0;
    if(index!=0){
        for(device = all_devices;i<index - 1;i++,device = device->next);
    }else{
        device = nullptr;
    }
    return;
}

int MainWindow::capture(){
    // 打开combobox中选择的设备device
    if(device)
        pointer = pcap_open_live(device->name,65536,1,1000,errbuf);
    else{
        return -1;
    }
    if(!pointer){//如果为空 就说明打开失败
        pcap_freealldevs(all_devices);
        device = nullptr;
        return -1;
    }else{
        // check the data link IEEE 802.3
        if(pcap_datalink(pointer) != DLT_EN10MB){
            pcap_close(pointer);
            pcap_freealldevs(all_devices);
            device = nullptr;
            return -1;
        }
    }
    return 0;
}

void MainWindow::on_tableView_clicked(const QModelIndex &index)
{
    int row = index.row();
    if(row < 0){
        return;
    }
    ui->treeWidget->clear();
    //添加mac帧
    QString src_mac = datas[row].GetSrcMac();
    QString des_mac = datas[row].GetDesMac();
    QTreeWidgetItem* mac_item =
            new QTreeWidgetItem(QStringList()<<("Ethernet    ["+src_mac+" -> "+des_mac+"]"));
    mac_item->addChild(new QTreeWidgetItem(QStringList()<<("Destination=" + src_mac)));
    mac_item->addChild(new QTreeWidgetItem(QStringList()<<("Source=" + des_mac)));
    QString mac_type = datas[row].GetMacType();
    mac_item->addChild(new QTreeWidgetItem(QStringList()<<("Type=" + mac_type)));
    ui->treeWidget->addTopLevelItem(mac_item);

    if(mac_type == "ARP(0x806)"){
        //添加arp帧
        QString op_code = (datas[row].GetArpOpCode()==1)?"request(1)":"response(0)";
        QTreeWidgetItem* arp_item = new QTreeWidgetItem(QStringList()<<("Address Resolution Protocol " + op_code));
        arp_item->addChild(new QTreeWidgetItem(QStringList()<<("op_code: "+QString::number(datas[row].GetArpOpCode()))));
        arp_item->addChild(new QTreeWidgetItem(QStringList()<<("src_mac_addr: "+datas[row].GetArpMacSrc())));
        arp_item->addChild(new QTreeWidgetItem(QStringList()<<("des_mac_addr: "+datas[row].GetArpMacDes())));
        arp_item->addChild(new QTreeWidgetItem(QStringList()<<("src_ip_addr: "+datas[row].GetArpIpSrc())));
        arp_item->addChild(new QTreeWidgetItem(QStringList()<<("des_ip_addr: "+datas[row].GetArpIpDes())));
        ui->treeWidget->addTopLevelItem(arp_item);
    }else if(mac_type == "IPv4(0x800)"){
        //添加ip帧
        QString src_ip = datas[row].GetIPSrc();
        QString des_ip = datas[row].GetIPDes();
        QTreeWidgetItem* ip_item = new QTreeWidgetItem(QStringList()<<("Internet Protocol Version 4    ["+src_ip+" -> "+des_ip+"]"));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"version: 4"));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"DSCP_ECN: " + datas[row].GetIPTOS()));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"total_length: " + datas[row].GetIPTotalLength()));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"identification: " + datas[row].GetIPIdentification()));

        //R D M
        QTreeWidgetItem* rdm = new QTreeWidgetItem(QStringList()<<"RDM");
        rdm->addChild(new QTreeWidgetItem(QStringList()<<("Reserved: " + datas[row].GetIPReserved())));
        rdm->addChild(new QTreeWidgetItem(QStringList()<<("Don't Fragment: " + datas[row].GetIPDoNotFragment())));
        rdm->addChild(new QTreeWidgetItem(QStringList()<<("More Fragments: " + datas[row].GetIPMoreFragments())));
        ip_item->addChild(rdm);

        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"flag_offset: " + datas[row].GetIPFragmentOffset()));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"ttl: " + datas[row].GetIPTTL()));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"protocol: " + datas[row].GetIPProtocol()));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"src_addr: " + src_ip));
        ip_item->addChild(new QTreeWidgetItem(QStringList()<<"des_addr: " + des_ip));
        ui->treeWidget->addTopLevelItem(ip_item);

        //根据IP封装的应用层协议 继续解析
        if(datas[row].GetIPProtocol() == "TCP"){
            QString src_port = datas[row].GetTcpSrcPort();
            QString des_port = datas[row].GetTcpDesPort();

            QTreeWidgetItem* tcp_item = new QTreeWidgetItem(
                        QStringList()<<("Transmission Control Protocol    ["+src_ip+":"+src_port+" -> "+des_ip+":"+des_port+"]"));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("src_port: " + src_port)));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("des_port: " + des_port)));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("sequence: "+ datas[row].GetTcpSeq())));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("ack: " + datas[row].GetTcpAck())));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("header_length: " + datas[row].GetTcpHeadLength())));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<"reserve: 000000"));

            QString flags_str = datas[row].GetTcpFlags();
            QTreeWidgetItem* flags = new QTreeWidgetItem(QStringList()<<("flags: " + flags_str));
            flags->addChild(new QTreeWidgetItem(QStringList()<<"UGR: " + flags_str[0]));
            flags->addChild(new QTreeWidgetItem(QStringList()<<"ACK: " + flags_str[1]));
            flags->addChild(new QTreeWidgetItem(QStringList()<<"PSH: " + flags_str[2]));
            flags->addChild(new QTreeWidgetItem(QStringList()<<"RST: " + flags_str[3]));
            flags->addChild(new QTreeWidgetItem(QStringList()<<"SYN: " + flags_str[4]));
            flags->addChild(new QTreeWidgetItem(QStringList()<<"FIN: " + flags_str[5]));
            tcp_item->addChild(flags);

            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("window_size: " + datas[row].GetTcpWinSize())));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("checksum: " + datas[row].GetTcpChecksum())));
            tcp_item->addChild(new QTreeWidgetItem(QStringList()<<("urgent: " + datas[row].GetTcpUrgent())));
            ui->treeWidget->addTopLevelItem(tcp_item);
            //如果是443 端口 就按https解析
            //先解析TLS
        }else{ //否则为UDP
            QTreeWidgetItem* udp_item = new QTreeWidgetItem(QStringList()<<"User Datagram Protocol");
            QTreeWidgetItem* checksum = new QTreeWidgetItem(QStringList()<<"checksum: "+datas[row].GetUdpChecksum());
            QTreeWidgetItem* data_length = new QTreeWidgetItem(QStringList()<<"data_length: "+datas[row].GetUdpDataLength());
            QTreeWidgetItem* udp_data = new QTreeWidgetItem(QStringList()<<"data: "+datas[row].GetUdpData());
            udp_item->setSelected(true);
            udp_item->addChild(data_length);
            udp_item->addChild(checksum);
            udp_item->addChild(udp_data);
            ui->treeWidget->addTopLevelItem(udp_item);
        }
    }
}

void MainWindow::on_lineEdit_textEdited(const QString &arg1)
{
    qDebug()<< "lineEdit: "<<arg1;
    //按空格分词
    sortFilterProxyModel->setFilterRegExp(arg1);
}

数据包 ​

c++
#ifndef DATAPACKAGE_H
#define DATAPACKAGE_H

#include <QString>
#include "format.h"
#include <sstream>
#include <iostream>
#include <QDebug>
#include <bitset>
class DataPackage
{
public:
    DataPackage();
    u_int data_length;
    QString timeStamp;
    QString info;
    int packageType;
    const u_char* raw_data;

    //字符转16进制
    QString ByteToHex(const u_char& ch);

    void SetRawData(const u_char* data,int len);
//**********************************************************
    //mac
    ETHER_HEADER* mac_head;
    QString GetSrcMac();
    QString GetDesMac();
    QString GetMacType();

//**********************************************************
//arp
    ARP_HEADER* arp_head;
    short GetArpOpCode();
    QString GetArpMacSrc();
    QString GetArpMacDes();
    QString GetArpIpSrc();
    QString GetArpIpDes();

//**********************************************************
//ip
    IP_HEADER* ip_head;
    QString GetIPHeadLength();
    QString GetIPTOS();
    QString GetIPTotalLength();
    QString GetIPIdentification();
    //R D M
    QString GetIPReserved();
    QString GetIPDoNotFragment();
    QString GetIPMoreFragments();

    QString GetIPFragmentOffset();
    QString GetIPTTL();
    QString GetIPProtocol();
    QString GetIPSrc();
    QString GetIPDes();

//**********************************************************
//tcp
    TCP_HEADER* tcp_head;
    QString GetTcpSrcPort();
    QString GetTcpDesPort();
    QString GetTcpSeq();
    QString GetTcpAck();
    QString GetTcpHeadLength();
    QString GetTcpFlags();
    QString GetTcpWinSize();
    QString GetTcpChecksum();
    QString GetTcpUrgent();

//**********************************************************
//udp
    UDP_HEADER* udp_head;
    QString GetUdpDataLength();
    QString GetUdpChecksum();
    QString GetUdpData();

};
#endif // DATAPACKAGE_H
c++
#include "datapackage.h"
#include <QMetaType>
#include "winsock.h"
/*

    //位运算实现点分十进制IP和u_char[4]的转换
    QString ip = "127.0.0.1";
    u_char ip_char[4] = {0};
    QVector<QString> vec;

    ip.append('.');
    QString temp;
    for(int i = 0;i < ip.size();i++){

        if(ip[i] == '.'){
            vec.append(temp);
                temp.clear();
        }else{
            temp.append(ip[i]);
        }
    }
    for(int i = 0;i < vec.size();i++){

        ip_char[i] = (u_char)vec[i].toInt();
    }

    QString ctoip;
    for(int i = 0;i < 4;i++){
        ctoip += (QString::number((int)ip_char[i])+ '.');
    }
    ctoip.remove(ctoip.size(),1);
    qDebug()<< ctoip;


*/
DataPackage::DataPackage()
{
    qRegisterMetaType<DataPackage>("DataPackage");
    this->timeStamp = "";
    this->data_length = 0;
    this->packageType = 0;
    this->raw_data = nullptr;
}

QString DataPackage::ByteToHex(const u_char &ch)
{
    std::ostringstream ss;
    ss << std::hex << static_cast<short>(ch);
    QString res(QString::fromStdString(ss.str()));


    if(res.size() == 1){
        res.push_front('0');
    }
    return res;
}

void DataPackage::SetRawData(const u_char *data,int len)
{
    raw_data = (u_char*)malloc(len);
    ::memcpy((u_char*)raw_data, data , len);
    mac_head = (ETHER_HEADER*)(raw_data);
    ip_head = (IP_HEADER*)(raw_data + 14);
    tcp_head = (TCP_HEADER*)(raw_data + 14 + 20);
    arp_head = (ARP_HEADER*)(raw_data + 14);
    udp_head = (UDP_HEADER*)(raw_data + 14 + 20);
}

QString DataPackage::GetSrcMac()
{
    QString ether_src_host;
    for(int i = 0;i<6;i++){
        ether_src_host += ByteToHex(mac_head->ether_src_host[i]);
        ether_src_host += ":";
    }
    ether_src_host.remove(ether_src_host.size()-1,1);//删掉最后一个分号

    return ether_src_host;
}

QString DataPackage::GetDesMac()
{

    QString ether_des_host;
    for(int i = 0;i<6;i++){
        ether_des_host += ByteToHex(mac_head->ether_des_host[i]);
        ether_des_host += ":";
    }
    ether_des_host.remove(ether_des_host.size()-1,1);//删掉最后一个分号
    return ether_des_host;
}

QString DataPackage::GetMacType()
{
    switch(ntohs(mac_head->ether_type)){
        case 0x800:
           return "IPv4(0x800)";
        case 0x86DD:
           return "IPv6(0x86DD)";
        case 0x806:
           return "ARP(0x806)";

    default: break;

    }
    return "Nuknown Type";
}

short DataPackage::GetArpOpCode()
{
    return ntohs(arp_head->op_code);
}

QString DataPackage::GetArpMacSrc()
{

    QString res;
    for(int i = 0;i < 6;i++){
        res += ByteToHex(arp_head->src_eth_addr[i]);
        res += ":";
    }
    res.remove(res.size()-1,1);
    return res;
}

QString DataPackage::GetArpMacDes()
{
    QString res;
    for(int i = 0;i < 6;i++){
        res += ByteToHex(arp_head->des_eth_addr[i]);
        res += ":";
    }
    res.remove(res.size()-1,1);
    return res;
}

QString DataPackage::GetArpIpSrc()
{
    QString res;
    for(int i = 0;i < 4;i++){
        res += QString::number(static_cast<short>(arp_head->src_ip_addr[i]));
        res += ":";
    }
    res.remove(res.size()-1,1);
    return res;
}

QString DataPackage::GetArpIpDes()
{
    QString res;
    for(int i = 0;i < 4;i++){
        res += QString::number(static_cast<short>(arp_head->src_ip_addr[i]));
        res += ":";
    }
    res.remove(res.size()-1,1);
    return res;
}

QString DataPackage::GetIPHeadLength()
{
    //左移四bit 剩下head_length
    short iphead_len = static_cast<short>(ntohs(ip_head->versiosn_head_length << 4));
    return QString::number(iphead_len);
}

QString DataPackage::GetIPTOS()
{
    /*IP头(Internet Protocol header)中的Type of Service(服务类型)字段在IPv4中已经被替代为
     * Differentiated Services Code Point (DSCP)和Explicit Congestion Notification (ECN)字段。在IPv6中,这两个字段被整合到Traffic Class字段中。
        DSCP字段用于指定数据包的服务类别,它占据了IPv4头部中的高6位,共有64个不同的取值。这些取值通常分为不同的类别,如:
        Default (000000): 默认服务类别。
        Express Forwarding (101110): 低延迟、高吞吐量服务。
        Assured Forwarding (001010): 保证转发服务,提供可控的延迟和丢包率。
        Best Effort (000000): 最佳努力传输,没有特殊服务要求。
        这些只是一些示例,实际上,DSCP字段的具体含义可能在不同网络中有所不同,具体取值和含义需要根据网络配置和协议来确定。
        ECN字段用于指示网络中的拥塞情况,占据IPv4头部的低两位。它的取值包括:
        00: 未使用ECN。
        10: 支持ECN,但没有拥塞。
        01: 支持ECN,有拥塞。
        11: 保留,未定义。
        在IPv6中,Traffic Class字段的前6位也用于DSCP,而后两位用于ECN。
        需要注意的是,Type of Service字段在IPv4中已经不再直接使用,而是由DSCP和ECN字段来提供更精细的服务控制。
    */

//    0b01234567
    std::string DSCP_ECN = std::bitset<8>(ip_head->TOS).to_string();//#include <bitset>
    std::string DSCP = DSCP_ECN.substr(0,6);
    std::string ECN = DSCP_ECN.substr(6,2);

    return QString::fromStdString("DSCP: "+DSCP+" , ECN: "+ECN);
}

QString DataPackage::GetIPTotalLength()
{

    return QString::number(ntohs(ip_head->total_length));
}

QString DataPackage::GetIPIdentification()
{
    return QString::number(ntohs(ip_head->identification));
}

QString DataPackage::GetIPReserved()
{
    //保留位 设置为0
    return "0";
}

QString DataPackage::GetIPDoNotFragment()//是否允许ip分片
{
    //先转字节序
    //因为这个占16位的高3位中的第二位 所以先右移13位 再右移1位
    //最后和二进制0b01做按位与运算
    return ((ntohs(ip_head->flag_offset) >> (13 + 1)) & 0b01)?"1":"0";

}

QString DataPackage::GetIPMoreFragments()
{
    //因为这个占16位的高3位中的第3位 所以先右移13位
    //然后和0b001按位与
    return ((ntohs(ip_head->flag_offset) >> 13) & 0b001)?"1":"0";
}

QString DataPackage::GetIPFragmentOffset()
{
    //先转字节序
    //因为这个占16位中的后13位 所以先按位与把前3位置为0
    //然后再转换成short
    return QString::number(static_cast<short>(ntohs(ip_head->flag_offset) & 0b0001111111111111));
}

QString DataPackage::GetIPTTL()
{
    //TTL代表 "Time to Live",即生存时间。TTL 是一个8位的字段,用于限制IP数据报在网络中的最大传播距离,防止数据报在网络中无限循环。TTL的单位是秒。
    return QString::number(static_cast<short>(ip_head->ttl));
}

QString DataPackage::GetIPProtocol()
{
    switch (packageType) {
        case 1:
            return "ARP";
        case 2:
            return "TCP";
        case 3:
            return "UDP";
        case 4:
            return "ICMP";
        case 5:
            return "DNS";
        case 6:
            return "TLS";
        case 7:
            return "HTTP";
        case 8:
            return "FTP";
        case 9:
            return "SSL";
    default:
        break;
    }
    return "unknown";
}

QString DataPackage::GetIPSrc()
{
    sockaddr_in srcAddr;
    srcAddr.sin_addr.s_addr = ip_head->src_addr;
    return QString(inet_ntoa(srcAddr.sin_addr));
}

QString DataPackage::GetIPDes()
{
    sockaddr_in desAddr;
    desAddr.sin_addr.s_addr = ip_head->des_addr;
    return QString(inet_ntoa(desAddr.sin_addr));
}

QString DataPackage::GetTcpSrcPort()
{
    return QString::number(ntohs(tcp_head->src_port));
}

QString DataPackage::GetTcpDesPort()
{
    return QString::number(ntohs(tcp_head->des_port));
}

QString DataPackage::GetTcpSeq()
{
    return QString::number(ntohl(tcp_head->sequence));
}

QString DataPackage::GetTcpAck()
{
    return QString::number(ntohl(tcp_head->ack));
}

QString DataPackage::GetTcpHeadLength()
{
    //右移四位 然后以short读出来
    return QString::number(static_cast<short>(tcp_head->header_length >> 4));
}

QString DataPackage::GetTcpFlags()
{
    //前两位是保留位 但是保留位默认为0
    //6个保留位 逐个判断是否被置位
    QString res = "";
    tcp_head->flags & 0b00100000 ? res.push_back('1'):res.push_back('0');
    tcp_head->flags & 0b00010000 ? res.push_back('1'):res.push_back('0');
    tcp_head->flags & 0b00001000 ? res.push_back('1'):res.push_back('0');
    tcp_head->flags & 0b00000100 ? res.push_back('1'):res.push_back('0');
    tcp_head->flags & 0b00000010 ? res.push_back('1'):res.push_back('0');
    tcp_head->flags & 0b00000001 ? res.push_back('1'):res.push_back('0');
    return res;
}

QString DataPackage::GetTcpWinSize()
{

    return QString::number(ntohs(tcp_head->window_size));
}

QString DataPackage::GetTcpChecksum()
{
    return QString::number(ntohs(tcp_head->checksum));
}

QString DataPackage::GetTcpUrgent()
{
    return QString::number(ntohs(tcp_head->urgent));
}

QString DataPackage::GetUdpDataLength()
{
    return QString::number(ntohs(udp_head->data_length));
}

QString DataPackage::GetUdpChecksum()
{
    return QString::number(ntohs(udp_head->checksum));
}

QString DataPackage::GetUdpData()
{
    unsigned short data_length = ntohs(udp_head->data_length);
    QByteArray data;
    const char* udp_data = ((char*)udp_head) + 8;
    data.setRawData(udp_data, data_length);


    return data.toBase64();
}

子线程 ​

c++
#ifndef CHILDTHREAD_H
#define CHILDTHREAD_H

#include <QThread>
#include <QDebug>
#include "pcap.h"
#include "format.h"
#include "datapackage.h"
#include <sstream>

class ChildThread : public QThread
{
    Q_OBJECT
public:
    ChildThread();
    void SetState(bool flag);
    void SetPointer(pcap_t* pointer);
    int EthernetPackageHandle(const u_char *pkt_content,QString& info);
    int IpPackageHandle(const u_char *pkt_content,int& ipPackage);
    QString IcmpPackageHandle(const u_char *pkt_content);
    QString IcmpTypeToString(u_char type);
    QString IcmpCodeToString(u_char code);
    //tcp tls
    int TcpPackageHandle(const u_char* pkt_content,QString &info,int ipPackage);
    int TLSRecordHeadHandle(const u_char* pkt_content,QString &info);

    int UdpPackageHandle(const u_char *pkt_content,QString&info);
    QString ArpPackageHandle(const u_char *pkt_content);
    void run() override;

    //被强转成u_char的十进制数 转换成16进制数字符串
    QString ByteToHex(u_char& byte);

    enum ProtocolType{
        ARP = 1,
        TCP = 2,
        UDP = 3,
        ICMP = 4,
        DNS = 5,
        TLS = 6,
        HTTP = 7,
        FTP = 8,
        SSL = 9
    };

public:
    struct pcap_pkthdr *pkt_header; //指向当前数据包的元数据
    pcap_t *p; //指向已经打开的网卡接口

signals:
    void Send(DataPackage data);

private:
    int number_package; // 已经捕获的数据包个数
    bool isDone;
    struct pcap_pkthdr* header; //pcap给这个数据包的头部 里面有时间戳(捕获的时间等内容)
    const u_char *pkt_data; // 生数据包 从这个自底向下依次解析

    time_t local_time_version_sec;//生时间戳
    struct tm local_time;
    char timeString[16];// 人读的"%H:%M:%S"时间格式

};

#endif // CHILDTHREAD_H
c++
#include "childthread.h"

ChildThread::ChildThread()
{
    number_package = 0;
    isDone = false;
}

void ChildThread::SetState(bool flag)
{
    isDone = flag;
}

void ChildThread::SetPointer(pcap_t *pointer)
{
    p = pointer;
}

void ChildThread::run()
{
    while(true){
        if(isDone){
            break;
        }

        //获取一个数据包
        int res = pcap_next_ex(p,&header,&pkt_data);
        /*
            - 如果成功捕获到数据包,则返回值为 1。
            - 如果超时而没有捕获到数据包,则返回值为 0。
            - 如果发生错误,则返回值为 -1。
        */
        if(res == 0){
            continue;
        }

        //获取捕获时间
        local_time_version_sec = header->ts.tv_sec;//读取生时间戳
        localtime_s(&local_time,&local_time_version_sec);
        strftime(timeString,sizeof(timeString),"%H:%M:%S",&local_time);

        //解析数据包
        QString info = "";
        int type = EthernetPackageHandle(pkt_data,info);//解析数据链路层


        if(type != 0){
            DataPackage data;//用于传给gui界面的包;
            int len = header->len;
            data.packageType = type;
            data.timeStamp = QString(timeString);
            data.data_length = len;
            data.info = info;
            data.SetRawData(pkt_data, len);


//            qDebug()<<info;
            emit Send(data);
            number_package++;

        }
    }
}

QString ChildThread::ByteToHex(u_char& byte)
{
    //把10进制数 转换成 16进制
    std::ostringstream ss;
    ss << std::hex << static_cast<short>(byte);

    return QString::fromStdString(ss.str());
}

//enum MacHeadType{
//    IPv4 = 0x0800,
//    IPv6 = 0x86DD,
//    ARP = 0x0806,
//    VLAN = 0x8100,
//    MPLS = 0x8847
//};

//enum IpHeadType{
//    ICMP = 1,
//    TCP = 6,
//    UDP = 17
//};

//传入生的数据包
int ChildThread::EthernetPackageHandle(const u_char *pkt_content,QString& info){
    ETHER_HEADER* ethernet; //mac帧头
    u_short ethernet_type;//类型标识字段

    ethernet = (ETHER_HEADER*)pkt_content;// 这包整个就一mac帧

    ethernet_type = ntohs(ethernet->ether_type);//转成本机字节序
    //根据ethernet_type 得知这个mac封装的是ip 还是 arp
    switch(ethernet_type){

        case 0x0800:{
            int dataPackage = 0;//数据载荷的大小
            int protocol_type = IpPackageHandle(pkt_content,dataPackage);//判断ip封装的是什么协议 是icmp、tcp、udp

            switch (protocol_type) {
                case 1:{
                    info = IcmpPackageHandle(pkt_content);
                    return ProtocolType::ICMP;
                }
                case 6:{
                    return TcpPackageHandle(pkt_content,info,dataPackage);

                }
                case 17:{

                    return UdpPackageHandle(pkt_content,info);;
                }
                default:break;
            }
                break;
        }

        case 0x0806:{// arp
            info = ArpPackageHandle(pkt_content);
            return ProtocolType::ARP;
        }
        default:{// undefined package
            break;
        }
    }
    return 0;
}



int ChildThread::IpPackageHandle(const u_char *pkt_content,int& ipPackage)
{
    IP_HEADER* ip;
    ip = (IP_HEADER*)(pkt_content + 14); //前面14个字节是mac帧头6+6+4 所以跳过
    int protocol = (int)ip->protocol;//::memcpy(&protocol,&ip->protocol,1);

    //total_length是ip首部和数据载荷的总长 我现在只需要数据载荷的长度 所以要减去首部
    //首部长度存储在versiosn_head_length的后4位
    //IPv4头部长度字段的取值范围是5-15,是因为该字段使用4位来表示,
    //最大可以表示的十进制数是15(1111)。这4位的取值范围是从0000到1111,
    //但是其中的0000和1111是保留值,不用于表示头部长度。

    //ipPackage = (htons(ip->total_length) - static_cast<int>((ip->versiosn_head_length & 0x0F)) * 4);

    //0x0F 相当于 0b1111  因为 &运算一假则假 versiosn_head_length的前4位全部被&为0 所以只剩下后四位了
    //我们把0b0000xxxx 用int型来读  读到的就是head length 再乘4就是首部长度
    ipPackage = (htons(ip->total_length) - (ip->versiosn_head_length & 0x0F) * 4);
    return protocol;
}

QString ChildThread::IcmpPackageHandle(const u_char *pkt_content)
{
    ICMP_HEADER* icmp_head;
    icmp_head = (ICMP_HEADER*)(pkt_content+14+20);
    QString result = "type: %1 , code: %2";
    result = result.arg(IcmpTypeToString(icmp_head->type));
    result = result.arg(IcmpCodeToString(icmp_head->code));
    return result;
}

QString ChildThread::IcmpTypeToString(u_char type){
    switch (type) {
        case 0:
            return "Echo Request(回声请求):用于测试网络连通性和响应时间,如ping命令使用的报文类型。";
        case 3:
            return "Time Exceeded(超时):表示IP包在传输过程中经过了太多的路由器跳数,或者IP包的时间超时。";
        case 8:
            return "Parameter Problem(参数问题):表示IP包中的参数有错误,如TTL(生存时间)值为0。";
        case 11:
            return "Timestamp Request(时间戳请求):用于获取两个主机之间的时间戳。";
        case 12:
            return "Timestamp Reply(时间戳应答):用于返回时间戳请求的应答报文。";
        case 13:
            return "Information Request(信息请求):用于请求主机的某些信息,如域名解析请求。";
        case 14:
            return "Information Reply(信息应答):用于返回信息请求的应答报文。";
        case 15:
            return "Address Mask Request(地址掩码请求):用于请求主机的子网掩码。";
        case 17:
            return "Address Mask Reply(地址掩码应答):用于返回地址掩码请求的应答报文。";
        default:
            break;
    }
    return "未知类型";
}

QString ChildThread::IcmpCodeToString(u_char code)
{
    switch (code) {
        case 0:
            return "无错误 ";
        case 1:
            return "协议不可达 ";
        case 2:
            return "端口不可达";
        case 3:
            return "TTL超时";
        case 4:
            return "参数问题";
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
            return "用于特定的请求类型,如时间戳请求、信息请求等";
        case 13:
        case 14:
        case 15:
            return "保留字段,目前没有使用";
        default:
            break;
    }
    return "未知代码";
}



int ChildThread::TcpPackageHandle(const u_char *pkt_content, QString &info, int ipPackage)
{
    TCP_HEADER* tcp_head;
    tcp_head = (TCP_HEADER*)(pkt_content+14+20);
    //数值型数据的存储有字节序的问题
    u_short src_port = ntohs(tcp_head->src_port);
    u_short des_port = ntohs(tcp_head->des_port);
    //拆seq序列号和ack确认号
    u_int seq = ntohl(tcp_head->sequence);
    u_int ack = ntohl(tcp_head->ack);
    //头部长 存在了tcp_head->header_length >> 4 里 我们用int可以读出来对应的整形值
    int head_len = static_cast<int>(tcp_head->header_length >> 4) * 4;
    int data_len = ipPackage - head_len;//数据载荷    ipPackage就是整个tcp包的长度
    //上面拆完了数据载荷 接下来开始拆6个标志位 一个个位置来拆 然后拼在flag里
    QString flag = "";
    //通过位运算
    if(tcp_head->flags & 0b00100000) flag += "UGR,";
    if(tcp_head->flags & 0b00010000) flag += "ACK,"; // 0b010000 == 0b10000
    if(tcp_head->flags & 0b00001000) flag += "PSH,";
    if(tcp_head->flags & 0b00000100) flag += "RST,";
    if(tcp_head->flags & 0b00000010) flag += "SYN,";
    if(tcp_head->flags & 0b00000001) flag += "FIN,";
    //拆滑动窗口大小 校验和 紧急指针
    u_short window_size = ntohs(tcp_head->window_size);
    //u_short checksum = ntohs(tcp_head->checksum);
    //u_short urgent = ntohs(tcp_head->urgent);

    //是TLS协议有关的端口
    //HTTPS  443
    //SMTPS  465
    //IMAPS  993
    //FTPS   21
    //但是因为TLS包装的协议都被加密了 没法按响应的格式解析了 所以我们只解析到TLS即可
    if(src_port == 443 || des_port == 443
     ||src_port == 21 || des_port == 21
            && (data_len >0)){
            return TLSRecordHeadHandle((((u_char*)tcp_head) + head_len),info);
    }


    //端口到端口
    info += QString::number(src_port) +
            "->"+
            QString::number(des_port);
    //如果有标志位被置位  删掉falg后面的逗号
    if(flag != ""){
         flag.remove(flag.length()-1,1);
         //拼被置位的标志位
         info += " ["+flag+"] ";
    }

    //序列号 确认号 滑动窗口大小 数据载荷 拼起来 作为info
    info += " seq="+QString::number(seq) +
            " ack="+QString::number(ack) +
            " win="+QString::number(window_size) +
            " len="+QString::number(data_len);


    return ProtocolType::TCP;
}

int ChildThread::TLSRecordHeadHandle(const u_char *pkt_content, QString &info)
{
//        typedef struct {
//            u_char type;
//            u_short version;
//            u_short length;
//        } TLSRecordHead;
    u_char* tls = (u_char*)pkt_content;
    u_char type = *tls;
    u_short version = ntohs(*(u_short*)(tls+1));

//    u_short length = *(tls+1+2);
//    qDebug()<<"type version:"<< type << version;
    if(type >= 20
    && type <= 23
    && version >= 0x0301 //769
    && version <= 0x0304){//772
        //TLS是分层协议  根据记录协议 知道接下来的是握手协议 还是秘钥交换 告警协议等
        switch(type){
            case 20:{
                info = "Change Cipher Spec";
                break;
            }
            case 21:{
                info = "Alert";
                break;
            }
            case 22:{
                info = "Handshake";
                //跳过TLS记录协议
                u_char* tlsHandshakeHeader = (u_char*)(pkt_content +1+2+2);
                u_char handshakeType = *tlsHandshakeHeader;

                switch (handshakeType) {
                    case 1: //客户端发起连接请求。
                        info += " ClientHello";
                    break;
                    case 2: //服务器回复连接请求。
                        info += " ServerHello";
                    break;
                    case 11: //服务器发送数字证书。
                        info += " Certificate";
                    break;
                    case 12: //服务器发送用于密钥协商的信息。
                        info += " ServerKeyExchange";
                    break;
                    case 16: //服务器请求客户端提供数字证书。
                        info += " CertificateRequest";
                    break;
                    case 14: //服务器完成握手协商。
                        info += " ServerHelloDone";
                    break;
                default: info+= " error";
                    break;
                }
                break;

            }
            case 23:{
                info = "Application Data";
                break;
            }
            default:{
                break;
            }
        }
    }

    //否则就是ssl
    else{
        info = "Continuation Data";
        return ProtocolType::SSL;
    }
    return ProtocolType::TLS;
}



int ChildThread::UdpPackageHandle(const u_char *pkt_content, QString &info)
{
    UDP_HEADER* udp_head;
    udp_head = (UDP_HEADER*)(pkt_content + 14 + 20);
    u_short src_port = ntohs(udp_head->src_port);
    u_short des_port = ntohs(udp_head->des_port);
    u_short data_length = ntohs(udp_head->data_length);
    u_short checksum = ntohs(udp_head->checksum);
    info = QString::number(src_port) + "->" + QString::number(des_port) +
            " Len="+QString::number(data_length);


    return ProtocolType::UDP;
}

QString ChildThread::ArpPackageHandle(const u_char *pkt_content)
{
    ARP_HEADER* arp_head;
    arp_head = (ARP_HEADER*)(pkt_content+14);
    QString res = "";
    //根据报文中的操作码 判断是arp请求 还是响应报文
    u_short op_code = ntohs(arp_head->op_code);

    //arp请求
    if(op_code == 1){
        //ip是点分十进制数字。 最大是255 恰好是1个字节8位可以表示的最大数 所以4组数字每组存在一个char里
        QString des_ip = QString::number(static_cast<int>(arp_head->des_ip_addr[0])) + "." +
                         QString::number(static_cast<int>(arp_head->des_ip_addr[1])) + "." +
                         QString::number(static_cast<int>(arp_head->des_ip_addr[2])) + "." +
                         QString::number(static_cast<int>(arp_head->des_ip_addr[3]));
        res = "Whose IP address is" +des_ip+", please tell me your mac address";
    }
    //arp响应
    else if(op_code == 2){
        QString src_ip = QString::number(static_cast<int>(arp_head->src_ip_addr[0])) + "." +
                         QString::number(static_cast<int>(arp_head->src_ip_addr[1])) + "." +
                         QString::number(static_cast<int>(arp_head->src_ip_addr[2])) + "." +
                         QString::number(static_cast<int>(arp_head->src_ip_addr[3]));


        //mac地址是48位 6字节 ,MAC地址定义格式为前24位厂商代码,后24位厂商指定的序列号。
        //00:1A:2B:3C:4D:5E 冒号分割的16进制数  00:00:00:00:00:00 ~ FF:FF:FF:FF:FF:FF

        QString src_mac = ByteToHex(arp_head->src_eth_addr[0])+ ":"+
                          ByteToHex(arp_head->src_eth_addr[1])+ ":"+
                          ByteToHex(arp_head->src_eth_addr[2])+ ":"+
                          ByteToHex(arp_head->src_eth_addr[3])+ ":"+
                          ByteToHex(arp_head->src_eth_addr[4])+ ":"+
                          ByteToHex(arp_head->src_eth_addr[5]) ;

        res = "[ip = " + src_ip + ", mac = " + src_mac + "]";
    }

    return res;
}

学 习 记 录