290 lines
11 KiB
C++
290 lines
11 KiB
C++
|
#include "pcapwin.h"
|
||
|
#include "table.h"
|
||
|
#include <QTextEdit>
|
||
|
#include <QPushButton>
|
||
|
#include <QMessageBox>
|
||
|
#include <QLabel>
|
||
|
#include <QDateTime>
|
||
|
#include <QRadioButton>
|
||
|
#include <QDebug>
|
||
|
|
||
|
PcapWin *PcapWin::newIns(QWidget *parent) {
|
||
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||
|
pcap_if_t *devs;
|
||
|
if(pcap_findalldevs(&devs, errbuf) == -1) {
|
||
|
QMessageBox::critical(parent, "Error", QString("寻找网卡失败")+errbuf);
|
||
|
return 0;
|
||
|
}
|
||
|
auto table = new Table{
|
||
|
{"name", "网卡名称", 400},
|
||
|
{"desc", "网卡描述", 300},
|
||
|
{"loopback","Loopback"},
|
||
|
{"ip","IP"},
|
||
|
{"netmask","Netmask"},
|
||
|
{"broadaddr","Broad Addr"},
|
||
|
{"dstaddr","Dst Addr"}
|
||
|
};
|
||
|
|
||
|
pcap_if_t *device = 0;
|
||
|
for(pcap_if_t *dev = devs; dev; dev = dev->next) {
|
||
|
pcap_addr_t *a;
|
||
|
for(a=dev->addresses; a; a=a->next) {
|
||
|
auto sa_family = a->addr->sa_family;
|
||
|
if(sa_family==AF_INET) {
|
||
|
auto rr = table->rowCount();
|
||
|
table->setRowCount(rr+1);
|
||
|
table->setValue(rr, "name", dev->name);
|
||
|
table->setValue(rr, "desc", dev->description);
|
||
|
table->setValue(rr, "loopback", (dev->flags & PCAP_IF_LOOPBACK)?"True":"False");
|
||
|
auto ip = (u_char *) &((sockaddr_in *) a->addr)->sin_addr.s_addr;
|
||
|
table->setValue(rr, "ip", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||
|
if(a->netmask) {
|
||
|
ip = (u_char *) &((sockaddr_in *) a->netmask)->sin_addr.s_addr;
|
||
|
table->setValue(rr, "netmask", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||
|
}
|
||
|
if(a->broadaddr) {
|
||
|
ip = (u_char *) &((sockaddr_in *) a->broadaddr)->sin_addr.s_addr;
|
||
|
table->setValue(rr, "broadaddr", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||
|
}
|
||
|
if(a->dstaddr) {
|
||
|
ip = (u_char *) &((sockaddr_in *) a->dstaddr)->sin_addr.s_addr;
|
||
|
table->setValue(rr, "dstaddr", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||
|
}
|
||
|
if(device==0) device = dev;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
pcap_freealldevs(devs);
|
||
|
|
||
|
auto rowCnt = table->rowCount();
|
||
|
if(rowCnt==0) {
|
||
|
table->deleteLater();
|
||
|
QMessageBox::critical(parent, "Error", "没找到 internet 设备");
|
||
|
return 0;
|
||
|
} else if(rowCnt==1) {
|
||
|
table->deleteLater();
|
||
|
auto name = table->item(0, "name")->text().toLocal8Bit();
|
||
|
auto pcapRe = pcap_open(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 100, 0, errbuf);
|
||
|
if(pcapRe == 0) {
|
||
|
QMessageBox::critical(parent, "Error", QString("打开网卡失败")+errbuf);
|
||
|
return 0;
|
||
|
}
|
||
|
auto pcapSe = pcap_open(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 100, 0, errbuf);
|
||
|
if(pcapSe == 0) {
|
||
|
QMessageBox::critical(parent, "Error", QString("打开网卡失败")+errbuf);
|
||
|
return 0;
|
||
|
}
|
||
|
return new PcapWin(pcapRe, pcapSe, parent);
|
||
|
} else {
|
||
|
auto dlg = new BaseDlg(parent);
|
||
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||
|
dlg->setWindowTitle("选择网卡");
|
||
|
dlg->resize(1200, 300);
|
||
|
|
||
|
auto vBox = new QVBoxLayout(dlg->center);
|
||
|
vBox->setContentsMargins(0,0,0,0);
|
||
|
vBox->setSpacing(3);
|
||
|
vBox->addSpacing(30);
|
||
|
|
||
|
table->setDefs();
|
||
|
table->setSelectionMode(QAbstractItemView::SingleSelection);
|
||
|
table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||
|
table->selectRow(0);
|
||
|
pcap_t *pcapRece;
|
||
|
pcap_t *pcapSend;
|
||
|
connect(table, &Table::cellDoubleClicked, dlg, [dlg, table, &pcapRece, &pcapSend, &errbuf](int row) {
|
||
|
auto name = table->item(row, "name")->text().toLocal8Bit();
|
||
|
pcapRece = pcap_open(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 100, 0, errbuf);
|
||
|
if(pcapRece == 0) {
|
||
|
QMessageBox::critical(dlg, "Error", QString("打开网卡失败")+errbuf);
|
||
|
return;
|
||
|
}
|
||
|
pcapSend = pcap_open(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 100, 0, errbuf);
|
||
|
if(pcapSend == 0) {
|
||
|
QMessageBox::critical(dlg, "Error", QString("打开网卡失败")+errbuf);
|
||
|
return;
|
||
|
}
|
||
|
dlg->accept();
|
||
|
});
|
||
|
vBox->addWidget(table);
|
||
|
|
||
|
auto hBox = new QHBoxLayout;
|
||
|
hBox->addStretch();
|
||
|
auto btnOk = new QPushButton("确定");
|
||
|
btnOk->setMinimumWidth(80);
|
||
|
connect(btnOk, &QPushButton::clicked, dlg, [dlg, table, &pcapRece, &pcapSend, &errbuf] {
|
||
|
auto sels = table->selectedRanges();
|
||
|
if(sels.isEmpty()) {
|
||
|
QMessageBox::warning(dlg, "Warning", "请选择网卡");
|
||
|
return;
|
||
|
}
|
||
|
auto name = table->item(sels[0].topRow(), "name")->text().toLocal8Bit();
|
||
|
pcapRece = pcap_open(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 100, 0, errbuf);
|
||
|
if(pcapRece == 0) {
|
||
|
QMessageBox::critical(dlg, "Error", QString("打开网卡失败")+errbuf);
|
||
|
return;
|
||
|
}
|
||
|
pcapSend = pcap_open(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 100, 0, errbuf);
|
||
|
if(pcapSend == 0) {
|
||
|
QMessageBox::critical(dlg, "Error", QString("打开网卡失败")+errbuf);
|
||
|
return;
|
||
|
}
|
||
|
dlg->accept();
|
||
|
});
|
||
|
hBox->addWidget(btnOk);
|
||
|
|
||
|
hBox->addStretch();
|
||
|
|
||
|
auto btnClose = new QPushButton("关闭");
|
||
|
btnClose->setMinimumWidth(80);
|
||
|
connect(btnClose, &QPushButton::clicked, dlg, &QDialog::reject);
|
||
|
hBox->addWidget(btnClose);
|
||
|
hBox->addStretch();
|
||
|
|
||
|
vBox->addLayout(hBox);
|
||
|
if(QDialog::Accepted==dlg->exec()) return new PcapWin(pcapRece, pcapSend, parent);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PcapWin::PcapWin(pcap_t *pcapRece, pcap_t *pcapSend, QWidget *parent) : BaseWin{parent}, pcap(pcapSend) {
|
||
|
setWindowModality(Qt::WindowModal);
|
||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||
|
setWindowTitle("网口通信");
|
||
|
resize(1024, 720);
|
||
|
|
||
|
auto vBox = new QVBoxLayout(center);
|
||
|
vBox->setContentsMargins(0,0,0,0);
|
||
|
vBox->setSpacing(3);
|
||
|
vBox->addLayout(addBtns(new QHBoxLayout()));
|
||
|
|
||
|
auto fdReceive = new QTextEdit;
|
||
|
fdReceive->setFontFamily("Consolas");
|
||
|
fdReceive->setReadOnly(true);
|
||
|
fdReceive->document()->setMaximumBlockCount(1000);
|
||
|
|
||
|
auto hBox = new QHBoxLayout;
|
||
|
{
|
||
|
auto vBox = new QVBoxLayout;
|
||
|
auto hBox2 = new QHBoxLayout;
|
||
|
|
||
|
hBox2->addWidget(new QLabel("接收:"));
|
||
|
hBox2->addStretch();
|
||
|
|
||
|
auto fdStart = new QRadioButton("开始");
|
||
|
fdStart->setChecked(true);
|
||
|
connect(fdStart, &QPushButton::toggled, this, [this](bool checked) {
|
||
|
thd->status = checked ? 0 : 1;
|
||
|
});
|
||
|
hBox2->addWidget(fdStart);
|
||
|
hBox2->addSpacing(20);
|
||
|
|
||
|
auto fdEnd = new QRadioButton("暂停");
|
||
|
hBox2->addWidget(fdEnd);
|
||
|
|
||
|
hBox2->addStretch();
|
||
|
|
||
|
auto btnClear = new QPushButton("清除");
|
||
|
btnClear->setMinimumWidth(120);
|
||
|
connect(btnClear, &QPushButton::clicked, fdReceive, &QTextEdit::clear);
|
||
|
hBox2->addWidget(btnClear);
|
||
|
|
||
|
hBox2->addStretch();
|
||
|
|
||
|
vBox->addLayout(hBox2);
|
||
|
|
||
|
vBox->addWidget(fdReceive);
|
||
|
|
||
|
hBox->addLayout(vBox);
|
||
|
}
|
||
|
{
|
||
|
auto wgt = new QWidget;
|
||
|
wgt->setMaximumWidth(400);
|
||
|
|
||
|
auto vBox = new QVBoxLayout(wgt);
|
||
|
vBox->setContentsMargins(0,0,0,0);
|
||
|
vBox->setSpacing(3);
|
||
|
|
||
|
auto hBox2 = new QHBoxLayout;
|
||
|
hBox2->addStretch();
|
||
|
|
||
|
auto btnSend = new QPushButton("发送");
|
||
|
btnSend->setMinimumWidth(120);
|
||
|
hBox2->addWidget(btnSend);
|
||
|
|
||
|
hBox2->addStretch();
|
||
|
|
||
|
auto btnClear = new QPushButton("清除");
|
||
|
btnClear->setMinimumWidth(120);
|
||
|
hBox2->addWidget(btnClear);
|
||
|
hBox2->addStretch();
|
||
|
|
||
|
vBox->addLayout(hBox2);
|
||
|
|
||
|
auto fdSend = new QTextEdit;
|
||
|
fdSend->setFontFamily("Consolas");
|
||
|
vBox->addWidget(fdSend);
|
||
|
|
||
|
connect(btnSend, &QPushButton::clicked, this, [this, fdSend] {
|
||
|
auto text = fdSend->toPlainText();
|
||
|
auto len = text.size();
|
||
|
QByteArray bytes;
|
||
|
for(int i=0; i<len; i++) {
|
||
|
auto ch = text[i].toLatin1();
|
||
|
if((ch>='0' && ch<='9') || (ch>='A' && ch<='F') || (ch>='a' && ch<='f')) bytes.append(ch);
|
||
|
}
|
||
|
if(bytes.size() % 2) bytes.append('0');
|
||
|
bytes = QByteArray::fromHex(bytes);
|
||
|
if(pcap_sendpacket(pcap, (u_char*)bytes.data(), bytes.size())) {
|
||
|
QMessageBox::critical(this, "Error", QString("发送失败: ")+pcap_geterr(pcap));
|
||
|
return;
|
||
|
}
|
||
|
});
|
||
|
connect(btnClear, &QPushButton::clicked, fdSend, &QTextEdit::clear);
|
||
|
|
||
|
hBox->addWidget(wgt);
|
||
|
}
|
||
|
vBox->addLayout(hBox);
|
||
|
|
||
|
thd = new PcapThread(pcapRece);
|
||
|
connect(thd, &PcapThread::onMsg, fdReceive, &QTextEdit::append);
|
||
|
thd->start();
|
||
|
}
|
||
|
|
||
|
PcapThread::PcapThread(pcap_t *pcap) : pcap(pcap) {
|
||
|
connect(this, &QThread::finished, this, &QThread::deleteLater);
|
||
|
}
|
||
|
void PcapThread::run() {
|
||
|
pcap_pkthdr *header;
|
||
|
const u_char *data;
|
||
|
int res;
|
||
|
while((res = pcap_next_ex(pcap, &header, &data)) >= 0) {
|
||
|
if(status==2) return;
|
||
|
if(status==1 || res == 0) continue; //超时
|
||
|
if(data[0]!=0x55 || data[1]!=0x55) continue;
|
||
|
QString data_str;
|
||
|
data_str.append(QDateTime::fromSecsSinceEpoch(header->ts.tv_sec).toString("yy-MM-dd HH:mm:ss.")+QString::number(header->ts.tv_usec));
|
||
|
data_str.append(" len:").append(QString::number(header->caplen)).append("/").append(QString::number(header->len)).append("\n");
|
||
|
char line[LINE_LEN + 1];
|
||
|
int l = 0;
|
||
|
for(uint i=0; i<header->caplen; i++) {
|
||
|
data_str.append(QString::asprintf("%.2x ", data[i]));
|
||
|
if(i > 13) {
|
||
|
if(isgraph(data[i]) || data[i] == ' ') line[l] = data[i];
|
||
|
else line[l] = '.';
|
||
|
if(l==15) {
|
||
|
line[16] = 0;
|
||
|
data_str.append(" ").append(line).append("\n");
|
||
|
l = 0;
|
||
|
} else l++;
|
||
|
} else if(i == 13) {
|
||
|
data_str.append("\n");
|
||
|
}
|
||
|
}
|
||
|
line[l] = 0;
|
||
|
data_str.append(" ").append(line).append("\n\n");
|
||
|
emit onMsg(data_str);
|
||
|
}
|
||
|
emit onError(pcap_geterr(pcap));
|
||
|
}
|