#include "debug.h"
#include "ui_debug.h"
#include "multhread.h"
#include <QThreadPool>
Debug::Debug(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::Debug)
{
ui->setupUi(this);
showNetworkCard();
//初始化
ui->NetworkDisplay->horizontalHeader()->setStyleSheet(
"QHeaderView::section {"
" background-color: #e1e1e1;"
" padding: 4px 8px;"
" border: none;"
" font-weight: bold;"
"}"
);
ui->NetworkDisplay->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); //保持表头的字符在最左边
ui->Filter->setPlaceholderText ("输入过滤表达式,如:tcp.port == 80");
ui->NetworkDisplay->setShowGrid (false); //去除竖着的网格线
ui->NetworkDisplay->verticalHeader ()->setVisible (false); //去除自带的编号
ui->NetworkDisplay->setSelectionBehavior (QAbstractItemView::SelectRows); //选择一整行
ui->NetworkParse->setHeaderHidden (true); //隐藏树形结构的头
ui->actionrun_stop->setIcon(QIcon(":/source/start.png")); //把工具栏中的开始按钮图形初始化
statusBar ()->showMessage ("欢迎访问!");
countNumber = 0; //设置数据包当前个数,初始化为0
numberRow = -1; //初始化为-1
ui->toolBar->setMovable (false); //固定工具栏
ui->toolBar->addAction(ui->actionrun_stop); //工具栏中加入开始按钮
ui->NetworkDisplay->setColumnCount (7); //初始化表头
ui->NetworkDisplay->verticalHeader ()->setDefaultSectionSize (30); //设置widget的行高
QStringList title = {"序号" , "时间", "源IP地址" , "目的IP地址", "协议", "数据包总长度", "数据包信息(端口、数据包内容长度)"};
ui->NetworkDisplay->setHorizontalHeaderLabels (title);
ui->NetworkDisplay->setColumnWidth (0, 50);
ui->NetworkDisplay->setColumnWidth (1, 150);
ui->NetworkDisplay->setColumnWidth (2, 300);
ui->NetworkDisplay->setColumnWidth (3, 300);
ui->NetworkDisplay->setColumnWidth (4, 100);
ui->NetworkDisplay->setColumnWidth (5, 100);
ui->NetworkDisplay->setColumnWidth (6, 1000);
readOnlyDelegate = new ProtocolDelegate(); //创建一个“只读”控制器,但是没有父对象,所以需要在析构函数中自己删除
ui->NetworkDisplay->setItemDelegate (readOnlyDelegate);
udpsocket = new QUdpSocket;
multhread *sunThread = new multhread; //新建一个线程
static bool flag = false; //用于判断是否点击
htwj_content = new infdisplay(); //实例化软件类,根据不同结构体去进行不同展示
htwj_content->setWidgets (ui->NetworkParse, ui->ContentParse);
QThread *parseThread = new QThread(this);
parsethread *parse = new parsethread(this);
parse->moveToThread (parseThread);
//开启子线程
connect(ui->actionrun_stop, &QAction::triggered, this, [=](){
flag = !flag;
if(flag){
//在进入抓包前询问是否要保存文件,后续加逻辑
if(!currentDevice){
QMessageBox::warning(this, "错误", "请选择一个网卡设备");
flag = !flag;
return;
}
//初始化操作
ui->NetworkDisplay->clearContents (); //开始一轮新的捕获前清空
ui->NetworkParse->clear (); //清空
ui->ContentParse->clear ();
ui->NetworkDisplay->setRowCount (0); //设置行数
countNumber = 0;
numberRow = -1;
//进行内存清空的操作,因为抓包使用了memcpy,所以需要去主动释放内存
int dataSize = this->pData.size ();
for(int i = 0; i < dataSize; i++){
free((char*)pData[i].pkt_content);
this->pData[i].pkt_content = nullptr; //防止出现野指针
}
QVector<DataPackage>().swap(pData); //用空的容器和pData进行内存交换来释放内存
//开始
int res = Capture();
//调试是否正确捕捉到
qDebug() << "Capture result:" << res;
if (point) qDebug() << "Device opened:" << currentDevice->name;
else qDebug() << "Error:" << errBuf;
if(res != -1 && point){ //若网卡设备没问题,且当前设备指针不为空,则开始捕获分析数据包
parseThread->start ();
sunThread->setPointer(point);
sunThread->setFlag();
sunThread->start();
ui->actionrun_stop->setIcon(QIcon(":/source/stop.png"));
ui->NetworkCardBox->setEnabled(false); //开始捕获一张网卡的数据包后,在不暂停前不能更换网卡,所以列表无法选择
}else{
flag = !flag;
countNumber = 0;
numberRow = -1;
}
}else{
//停止
//释放掉线程
sunThread->resetFlag();
sunThread->quit();
sunThread->wait();
ui->actionrun_stop->setIcon(QIcon(":/source/start.png"));
ui->NetworkCardBox->setEnabled(true);
pcap_close(point); //释放掉指针资源
point = nullptr;
//开一个新的线程用来写文件
}
});
//抓包线程给主线程发信号以后,目前由主线程进行解析
connect (sunThread, &multhread::send, this, &Debug::HandleMessage);
//高亮的ui设置
connect(ui->ContentParse, &QPlainTextEdit::cursorPositionChanged, [this](){
htwj_content->locateFromHexClick(ui->ContentParse->textCursor().position());
});
connect(ui->NetworkParse, &QTreeWidget::itemClicked, [this](QTreeWidgetItem *item){
htwj_content->highlightFromTree(item);
});
connect(ui->NetworkParse, &QTreeWidget::currentItemChanged, [this](QTreeWidgetItem *item){
htwj_content->highlightFromTree(item);
});
//解析包
connect(this, &Debug::sendClickPackage, parse, &parsethread::parsePackage);
connect(parse, &parsethread::sendUI, this, [=](QList<QTreeWidgetItem*> items, QByteArray rawData, infdisplay *m_htwj_content){
ui->NetworkParse->addTopLevelItems (items);
ui->ContentParse->setPlainText (rawData.toHex (' '));
htwj_content = m_htwj_content;
});
}
Debug::~Debug()
{
int dataSize = pData.size();
for(int i = 0; i < dataSize; i++){
free((char*)(this->pData[i].pkt_content));
this->pData[i].pkt_content = nullptr;
}
QVector<DataPackage>().swap(pData);
delete ui;
}
//显示所有机器上的网卡设备,来确认选择哪个网卡进行抓包
void Debug::showNetworkCard(){
//通过导入的函数去判断是否找到了所有的网卡
int n = pcap_findalldevs(&all_device, errBuf); //此处会获取到一个所有网卡的列表,并把首地址给放到all_device中
if(n == -1){
//正常获取成功时,n不为-1,所以当n为-1时报错
ui->NetworkCardBox->addItem("error:" + (QString)errBuf);
}else{
//把所有获取到的设备都加载到NetworkCardBox中
ui->NetworkCardBox->clear();
ui->NetworkCardBox->addItem("选择一个网卡设备进行抓包!");
for( currentDevice = all_device; currentDevice != nullptr; currentDevice = currentDevice->next){
QString device_name = currentDevice->name; //获取设备名称
device_name.replace("\\Device\\", ""); //把前缀替换掉
QString device_Des = currentDevice->description; //获取设备描述
QString item = device_name + device_Des;
ui->NetworkCardBox->addItem(item);
}
}
}
//获取当下盒子里我选择的网卡是哪一张,此时的currentDevice指向我当前选择的那张网卡了,我再进行操作
void Debug::on_NetworkCardBox_currentIndexChanged(int index)
{
int i = 0;
if(index != 0){ //如果index是0说明没有选择网卡,所以就不需要获取当前网卡
for(currentDevice = all_device; i < index - 1; currentDevice = currentDevice->next){
i++;
}
}
return ;
}
//抓包,获取到网卡上的网络包
int Debug::Capture(){
if(currentDevice){
point = pcap_open_live(currentDevice->name, 65536, 1, 1000, errBuf); //打开网络设备进行数据包捕获,第二位表示捕获的最大字节数,第三位表示是否启用混杂模式,开启则捕获所有经过网卡的数据包,而不仅是发给本机的,第四位表示超时时间(毫秒)
}else{
return -1;
}
//判断设备是否打开成功
if(!point){
pcap_freealldevs(all_device); //没打开成功就关闭设备
currentDevice = nullptr; //避免出现野指针
return -1;
}else{ //不为空则打开成功,捕获自己想要的数据包
int link_type = pcap_datalink(point);
if(link_type != DLT_EN10MB && link_type != DLT_NULL && link_type !=DLT_RAW){ //不满足自己的协议就关闭设备,把指针清空
qDebug() << "网卡无法接收到,线程阻塞!";
pcap_close(point);
pcap_freealldevs(all_device);
currentDevice = nullptr;
point = nullptr;
return -1;
}
}
statusBar()->showMessage(currentDevice->name);
return 0;
}
//线程信号发送的接收槽函数
//子线程处理完一个网络数据包后会给主线程发送一个信号,此时槽函数将数据填入到窗口中
//因为每一次信号都会触发这个槽函数,所以函数中只需要处理一个数据包就行
void Debug::HandleMessage (DataPackage data){
ui->NetworkDisplay->insertRow(countNumber); //插入新的一行
this->pData.push_back (data);
QString type = data.getPackageType ();
QColor color;
if(type == "tcp"){
color = QColor(255, 255, 200);
}
else if(type == "udp"){
color = QColor(200, 255, 200);
}
else if(type == "arp"){
color = QColor(238, 238, 0);
}
else if(type == "dns"){
color = QColor(144, 144, 144);
}
else{
color = QColor(255, 218, 185);
}
//把数据内容根据所需插入到表格中
ui->NetworkDisplay->setItem (countNumber, 0, new QTableWidgetItem(QString ::number (countNumber)));
ui->NetworkDisplay->setItem (countNumber, 1, new QTableWidgetItem(data.getTimeStamp ()));
ui->NetworkDisplay->setItem (countNumber, 2, new QTableWidgetItem(data.getSource ())); //数据包的源IP或源Mac
ui->NetworkDisplay->setItem (countNumber, 3, new QTableWidgetItem(data.getDestination ())); //数据包的目的IP或目的Mac
ui->NetworkDisplay->setItem (countNumber, 4, new QTableWidgetItem(type.toUpper ()));
ui->NetworkDisplay->setItem (countNumber, 5, new QTableWidgetItem(data.getDataLength ()));
ui->NetworkDisplay->setItem (countNumber, 6, new QTableWidgetItem(data.getInfo ()));
//设置每一个单元格的背景颜色
for(int i = 0; i < 7; i++) {
ui->NetworkDisplay->item(countNumber, i)->setBackground(color);
}
countNumber++;
}
//点击网络包后,在下面树形结构中展示网络包的详细内容
void Debug::on_NetworkDisplay_cellClicked(int row, int column){
emit sendClickPackage (row, numberRow, countNumber, pData);
}
//处理数据包的函数,添加树形结构,存储数据包发送元数据,后续改处理逻辑在这里改就行
// void Debug::handleNetworkSelection (int row, int column){
// if(row == numberRow || row < 0){
// return ;
// }else{
// ui->NetworkParse->clear ();
// numberRow = row;
// //边界判断
// if(numberRow < 0 || numberRow > countNumber)
// return;
// //Ethernet层的树形结构
// QString desMac = pData[numberRow].getDstMacAddr ();
// QString srcMac = pData[numberRow].getSrcMacAddr ();
// QString type = pData[numberRow].getMacType ();
// QString tree = "Ethernet , Src: " + srcMac + " Dst: " + desMac;
// QTreeWidgetItem *item1 = new QTreeWidgetItem(QStringList()<<tree);
// ui->NetworkParse->addTopLevelItem (item1);
// item1->addChild (new QTreeWidgetItem(QStringList()<< "Destination:" + desMac));
// item1->addChild (new QTreeWidgetItem(QStringList()<< "Source:" + srcMac));
// item1->addChild (new QTreeWidgetItem(QStringList()<< "Type:" + type));
// QString packageType = pData[numberRow].getPackageType (); //获取当前行的上层协议类型
// //处理各种不同协议的树形结构
// //处理ARP包
// if(packageType == "arp"){
// ui->ContentParse->clear ();
// QString arpType = pData[numberRow].getArpOperationCode ();
// QTreeWidgetItem *item2 = new QTreeWidgetItem(QStringList()<< "Address Resolution Protocol " + arpType);
// ui->NetworkParse->addTopLevelItem (item2);
// QString HardwareType = pData[numberRow].getArpHardwareType ();
// QString protocolType = pData[numberRow].getArpProtocolType ();
// QString HardwareLength = pData[numberRow].getArpHardwareLength ();
// QString protocolLength = pData[numberRow].getArpProtocolLength ();
// QString srcMacAddr = pData[numberRow].getArpSourceEtherAddr ();
// QString dstMacAddr = pData[numberRow].getArpDestinationEtherAddr ();
// QString srcIpAddr = pData[numberRow].getArpSourceIpAddr ();
// QString dstIpAddr = pData[numberRow].getArpDestinationIpAddr ();
// item2->addChild (new QTreeWidgetItem(QStringList() << "Hardware Type: " + HardwareType));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Protocol type:" + protocolType));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Hardware size:" + HardwareLength));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Protocol size:" + protocolLength));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Opcode:" + arpType));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Sender MAC address:" + srcMacAddr));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Sender IP address:" + srcIpAddr));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Target MAC address:" + dstMacAddr));
// item2->addChild(new QTreeWidgetItem(QStringList()<<"Target IP address:" + dstIpAddr));
// return;
// }
// //处理IP包
// else{
// ui->ContentParse->clear ();
// QString srcIp = pData[numberRow].getSrcIpAddr ();
// QString dstIp = pData[numberRow].getDstIpAddr ();
// QTreeWidgetItem *item3 = new QTreeWidgetItem(QStringList() << "Internet Protocol Version 4, Src: " + srcIp + " , Dst: " + dstIp);
// ui->NetworkParse->addTopLevelItem (item3);
// QString version = pData[numberRow].getIpVersion ();
// QString headerLength = pData[numberRow].getIpHeaderLength ();
// QString Tos = pData[numberRow].getIpTos ();
// QString totalLength = pData[numberRow].getIpTotalLength ();
// QString id = "0x" + pData[numberRow].getIpIdentification ();
// QString flags = pData[numberRow].getIpFlag ();
// if(flags.size() < 2) //格式化处理,确保是2位十六进制数
// flags = "0" + flags;
// flags = "0x" + flags;
// QString FragmentOffset = pData[numberRow].getIpFragmentOffset ();
// QString ttl = pData[numberRow].getIpTTL ();
// QString protocol = pData[numberRow].getIpProtocol ();
// QString checksum = "0x" + pData[numberRow].getIpCheckSum();
// int dataLengthofIp = totalLength.toUtf8 ().toInt () - 20;
// item3->addChild (new QTreeWidgetItem(QStringList() << "0100.... = version: " + version));
// item3->addChild (new QTreeWidgetItem(QStringList() << "....0101 = Header Length: " + headerLength));
// item3->addChild (new QTreeWidgetItem(QStringList() << "TOS: " + Tos));
// item3->addChild (new QTreeWidgetItem(QStringList() << "Total Length: " + totalLength));
// item3->addChild (new QTreeWidgetItem(QStringList() << "Identification: " + id));
// QString reservedBit = pData[numberRow].getIpReservedBit ();
// QString DF = pData[numberRow].getIpDF ();
// QString MF = pData[numberRow].getIpMF ();
// QString FLAG = ",";
// if(reservedBit == "1"){
// FLAG += "ReserverBit";
// }
// else if(DF == "1"){
// FLAG += "Don't fragment";
// }
// else if(MF == "1"){
// FLAG += "More fragment";
// }
// if(FLAG.size() == 1){
// FLAG = "";
// }
// QTreeWidgetItem *bitTree = new QTreeWidgetItem(QStringList() << "Flags: " + flags + FLAG);
// item3->addChild (bitTree);
// QString temp = reservedBit == "1" ? "Set" : "Not set";
// bitTree->addChild (new QTreeWidgetItem(QStringList() << reservedBit + "... .... = Reserved bit:" + temp));
// temp = DF == "1"?"Set":"Not set";
// bitTree->addChild(new QTreeWidgetItem(QStringList()<<"." + DF + ".. .... = Don't fragment:" + temp));
// temp = MF == "1"?"Set":"Not set";
// bitTree->addChild(new QTreeWidgetItem(QStringList()<<".." + MF + ". .... = More fragment:" + temp));
// item3->addChild(new QTreeWidgetItem(QStringList()<<"Fragment Offset:" + FragmentOffset));
// item3->addChild(new QTreeWidgetItem(QStringList()<<"Time to Live:" + ttl));
// item3->addChild(new QTreeWidgetItem(QStringList()<<"Protocol:" + protocol));
// item3->addChild(new QTreeWidgetItem(QStringList()<<"Header checksum:" + checksum));
// item3->addChild(new QTreeWidgetItem(QStringList()<<"Source Address:" + srcIp));
// item3->addChild(new QTreeWidgetItem(QStringList()<<"Destination Address:" + dstIp));
// //处理TCP、TLS和SSL包
// if(packageType == "tcp" || packageType == "tls" || packageType == "ssl"){
// ui->ContentParse->clear ();
// }
// //可以从这里开始看,反正只发送udp包
// //处理UDP和DNS包
// if(packageType == "udp" || packageType == "dns"){
// ui->ContentParse->clear ();
// //infdisplay *htwj_content = new infdisplay(); //实例化软件类,根据不同结构体去进行不同展示
// htwj_content->setWidgets (ui->NetworkParse, ui->ContentParse);
// htwj_content->clearFields ();
// // qDebug() << "出问题了";
// QString srcPort = pData[numberRow].getUdpSourcePort ();
// QString dstPort = pData[numberRow].getUdpDestinationPort ();
// QString Length = pData[numberRow].getUdpDataLength ();
// QString Checksum = pData[numberRow].getUdpCheckSum ();
// QTreeWidgetItem *item4 = new QTreeWidgetItem(QStringList() << "User Datagram Protocol, Src Port: " + srcPort + " Dst Port: " + dstPort);
// ui->NetworkParse->addTopLevelItem (item4);
// item4->addChild (new QTreeWidgetItem(QStringList() << "Source Port: " + srcPort));
// item4->addChild (new QTreeWidgetItem(QStringList() << "Destination Port: " + dstPort));
// item4->addChild (new QTreeWidgetItem(QStringList() << "Length: " + Length));
// item4->addChild (new QTreeWidgetItem(QStringList() << "Checksum: " + Checksum));
// int udpLength = Length.toUtf8 ().toInt ();
// int udp_payLoad = udpLength - 8;
// if(udpLength > 0){
// item4->addChild (new QTreeWidgetItem(QStringList() << "UDP PayLoad (" + QString::number (udpLength - 8) + " bytes)"));
// }
// //处理发送的UDP报文中的信息,重新添加一个树形结构,展示各种结构体,并且把原始数据转换为16进制放到右边框中
// QTreeWidgetItem *htwj_item = new QTreeWidgetItem(QStringList() << "对应发送的原始数据");
// ui->NetworkParse->addTopLevelItem (htwj_item);
// const u_char *current_pkt_content = pData[numberRow].pkt_content; //获取数据包原始内容
// //!!!!!!!!!!!!这里还得改本地包和网络包的区别
// QByteArray rawData = QByteArray(reinterpret_cast<const char*>(current_pkt_content + 4 + 20 + 8), udp_payLoad); //把const u_char转换为QByteArray,方便以十六进制形式展示
// ui->ContentParse->setPlainText (rawData.toHex (' ')); //转换为十六进制,并用空格来分隔
// //目前根据结构体的字节长度去判断是哪种结构体类型
// switch(udp_payLoad){
// case 44:{
// QStringList sceneInfo = htwj_content->getSceneInformation (current_pkt_content);
// for (const QString &info : sceneInfo) {
// htwj_item->addChild(new QTreeWidgetItem(QStringList() << info));
// }
// }
// case 82:{
// QStringList platformInfo = htwj_content->getPlatformInformation (current_pkt_content);
// for (const QString &info : platformInfo) {
// htwj_item->addChild(new QTreeWidgetItem(QStringList() << info));
// }
// }
// }
// }
// }
// }
// }
void Debug::on_FilterButton_clicked()
{
//获取过滤框中内容
QString filterText = ui->Filter->text().trimmed();
//逐行去筛选
if(filterText.isEmpty ()){
for(int row = 0; row < ui->NetworkDisplay->rowCount(); row++){
ui->NetworkDisplay->setRowHidden(row, false);
}
return;
}
filter = new FilterParse;
if (!filter) {
qDebug() << "FilterParse creation failed!";
return;
}else{
qDebug() << "FilterParse creation succeed!";
}
qDebug() << ui->NetworkDisplay->rowCount();
for(int row = 0; row < ui->NetworkDisplay->rowCount(); row++){
//因为解析器中match的值是true的时候需要显示,但是设置只能设置隐形,所以初始值为false
bool match = false;
DataPackage data = pData[row];
match = filter->parse(filterText, data);
//qDebug() << match;
ui->NetworkDisplay->setRowHidden(row, !match);
}
}
//用于实现键盘上下切换行时,下方的展示格也同步变换
void Debug::on_NetworkDisplay_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
{
Q_UNUSED(previousRow);
Q_UNUSED(previousColumn);
//handleNetworkSelection (currentRow, currentColumn);
}
这是主线程,问题在哪
最新发布