#include "pcapwin.h" #include "table.h" #include #include #include #include #include #include #include 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='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; icaplen; 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)); }