使用Qt實現(xiàn)控制臺抓取tcp數(shù)據(jù)包
前提條件
安裝npcap: 鏈接
項目準備
創(chuàng)建控制臺程序
在項目文件中添加包含目錄、附加庫目錄、附加庫
INCLUDEPATH += D:/softwares/Libs/NpcapSDK/Include LIBS += -LD:/softwares/Libs/NpcapSDK/Lib/x64 LIBS += -lwpcap LIBS += -lole32 LIBS += -lPacket LIBS += -lIphlpapi
檢查是否已經(jīng)安裝npcap
bool checkNpcapExist()
{
WCHAR path[512];
uint len = GetSystemDirectory(path, 480);
QString systemPath = QString::fromWCharArray(path, len);
QString npcapFolder = QDir(systemPath).filePath("Npcap");
return QDir(npcapFolder).exists();
}
也就是判斷目錄: C:\Windows\System32\Npcap 存不存在
獲取網(wǎng)絡(luò)適配器列表
我們需要選擇一個網(wǎng)絡(luò)適配器去抓取tcp數(shù)據(jù)包,所以需要獲取本地機器的所有網(wǎng)絡(luò)適配器,當然 npcap 提供了 pcap_findalldevs api,但是如果我們要想獲取它的可讀化的 FriendName,需要經(jīng)過一些操作
QString getDeviceFriendName(const char *devName)
{
QString friendName(devName);
// extract guid string by regex
QRegularExpression regex(R"(({[A-F0-9\-]+}))");
auto match = regex.match(friendName);
if (!match.hasMatch()) return friendName;
// translate guid string to GUID
GUID guid;
HRESULT hr = CLSIDFromString(match.captured(1).toStdWString().c_str(), &guid);
if (!SUCCEEDED(hr)) return friendName;
// GUID => LUID => Alias(FriendName)
NET_LUID luid;
if (0 == ConvertInterfaceGuidToLuid(&guid, &luid))
{
WCHAR buffer[256] = {0};
if (0 == ConvertInterfaceLuidToAlias(&luid, buffer, 256))
{
friendName = QString::fromWCharArray(buffer);
}
}
return friendName;
}
int main()
{
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t *alldevs;
// pcap_t *handle;
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
qCritical() << "Error in pcap_findalldevs:" << errbuf;
return -1;
}
QStringList devNames;
pcap_if_t *dev = alldevs;
char* lastName = nullptr;
while (dev)
{
QString devName = getDeviceFriendName(dev->name);
devNames.append(devName);
lastName = dev->name;
dev = dev->next;
}
return 0;
}
打開網(wǎng)絡(luò)適配器并設(shè)置篩選條件
一個網(wǎng)絡(luò)適配器抓到的tcp數(shù)據(jù)包有很多,但是我們只想關(guān)注我們想要的tcp數(shù)據(jù)包,所以需要設(shè)置篩選條件
// open the adapter
pcap_t* adapter = pcap_open_live(lastName, 65536, 1, 1000, errbuf);
if (adapter == nullptr)
{
pcap_freealldevs(alldevs);
qDebug() << "fail to open the net adapter: " << lastName;
return -1;
}
pcap_freealldevs(alldevs);
// set filter
struct bpf_program fcode;
int res = 0;
if ((res = pcap_compile(adapter, &fcode, "tcp port 3000", 1, PCAP_NETMASK_UNKNOWN)) < 0)
{
qDebug() << "fail to compile:" << pcap_statustostr(res);
pcap_close(adapter);
return -1;
}
if ((res = pcap_setfilter(adapter, &fcode) < 0))
{
qDebug() << "fail to set filter:" << pcap_statustostr(res);
pcap_close(adapter);
return -1;
}
這里我們設(shè)置的條件是只篩選 端口號3000的tcp數(shù)據(jù)包,篩選字符串為: tcp port 3000
開始抓包,設(shè)置處理函數(shù)
void main()
{
// start capture loop
pcap_loop(adapter, 0, packet_handler, nullptr);
pcap_close(adapter);
}
void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data)
{
Q_UNUSED(param);
Q_UNUSED(pkt_data);
uint len = header->len;
QString str = QString::asprintf("%ld:%ld (%ld)", header->ts.tv_sec, header->ts.tv_usec, len);
qDebug() << str;
}
運行效果

完整代碼
#include <QCoreApplication>
#include <winsock2.h>
#include <QDebug>
#include <windows.h>
#include <QDir>
#include <pcap.h>
#include <QRegularExpression>
#include <objbase.h>
#include <netioapi.h>
bool checkNpcapExist()
{
WCHAR path[512];
uint len = GetSystemDirectory(path, 480);
QString systemPath = QString::fromWCharArray(path, len);
QString npcapFolder = QDir(systemPath).filePath("Npcap");
return QDir(npcapFolder).exists();
}
QString getDeviceFriendName(const char *devName)
{
QString friendName(devName);
// extract guid string by regex
QRegularExpression regex(R"(({[A-F0-9\-]+}))");
auto match = regex.match(friendName);
if (!match.hasMatch()) return friendName;
// translate guid string to GUID
GUID guid;
HRESULT hr = CLSIDFromString(match.captured(1).toStdWString().c_str(), &guid);
if (!SUCCEEDED(hr)) return friendName;
// GUID => LUID => Alias(FriendName)
NET_LUID luid;
if (0 == ConvertInterfaceGuidToLuid(&guid, &luid))
{
WCHAR buffer[256] = {0};
if (0 == ConvertInterfaceLuidToAlias(&luid, buffer, 256))
{
friendName = QString::fromWCharArray(buffer);
}
}
return friendName;
}
void packet_handler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data)
{
Q_UNUSED(param);
Q_UNUSED(pkt_data);
// struct tm* ltime;
// char timestr[16];
// time_t local_tv_sec;
uint len = header->len;
QString str = QString::asprintf("%ld:%ld (%ld)", header->ts.tv_sec, header->ts.tv_usec, len);
qDebug() << str;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 判斷npcap是否存在
if (!checkNpcapExist())
{
qDebug() << "Npcap not exists";
return -1;
}
// 檢索網(wǎng)卡列表
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t *alldevs;
// pcap_t *handle;
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
qCritical() << "Error in pcap_findalldevs:" << errbuf;
return -1;
}
QStringList devNames;
pcap_if_t *dev = alldevs;
char* lastName = nullptr;
while (dev)
{
QString devName = getDeviceFriendName(dev->name);
devNames.append(devName);
lastName = dev->name;
dev = dev->next;
}
// open the adapter
pcap_t* adapter = pcap_open_live(lastName, 65536, 1, 1000, errbuf);
if (adapter == nullptr)
{
pcap_freealldevs(alldevs);
qDebug() << "fail to open the net adapter: " << lastName;
return -1;
}
pcap_freealldevs(alldevs);
// set filter
struct bpf_program fcode;
int res = 0;
if ((res = pcap_compile(adapter, &fcode, "tcp port 3000", 1, PCAP_NETMASK_UNKNOWN)) < 0)
{
qDebug() << "fail to compile:" << pcap_statustostr(res);
pcap_close(adapter);
return -1;
}
if ((res = pcap_setfilter(adapter, &fcode) < 0))
{
qDebug() << "fail to set filter:" << pcap_statustostr(res);
pcap_close(adapter);
return -1;
}
// start capture loop
pcap_loop(adapter, 0, packet_handler, nullptr);
pcap_close(adapter);
qDebug() << "hello";
return a.exec();
}
以上就是使用Qt實現(xiàn)控制臺抓取tcp數(shù)據(jù)包的詳細內(nèi)容,更多關(guān)于Qt抓取tcp數(shù)據(jù)包的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言如何實現(xiàn)順序表(數(shù)據(jù)結(jié)構(gòu))
這篇文章主要介紹了C語言如何實現(xiàn)順序表(數(shù)據(jù)結(jié)構(gòu))問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08

