结构体
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_Hc++
#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_Hc++
#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_Hc++
#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;
}