#include "MainWindow.h" #include "NetworkManager.h" #include "SshClient.h" #include "Logger.h" #include #include #include #include #include #include #include #include #include #include static const char *kInterfacesPath = "/etc/network/interfaces"; // 尝试在存在参考文件时使用其前缀以保持格式一致 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ipInput(new QLineEdit(this)), macInput(new QLineEdit(this)), currentMacLabel(new QLabel("当前MAC: 未读取", this)), modifyButton(new QPushButton("修改MAC", this)), backupButton(new QPushButton("备份文件", this)), logView(new QTextEdit(this)), useSshCheck(new QCheckBox("使用SSH远程执行", this)), sshUserInput(new QLineEdit(this)), sshPassInput(new QLineEdit(this)), presetPassCombo(new QComboBox(this)), connectButton(new QPushButton("连接", this)), refreshButton(new QPushButton("刷新", this)), netMgr(new NetworkManager(this)), sshClient(new SshClient(this)), logger(new Logger(this)) { setWindowTitle("MAC修改工具"); logView->setReadOnly(true); // 根据屏幕分辨率自适应调整日志框大小 QScreen *screen = QGuiApplication::primaryScreen(); if (screen) { QRect screenGeometry = screen->availableGeometry(); int screenWidth = screenGeometry.width(); int screenHeight = screenGeometry.height(); // 日志框宽度为屏幕宽度的 25-30%,最小 390px int logWidth = qMax(390, static_cast(screenWidth * 0.25)); // 日志框高度为屏幕高度的 40-50%,最小 410px int logHeight = qMax(410, static_cast(screenHeight * 0.4)); logView->setMinimumWidth(logWidth); logView->setMinimumHeight(logHeight); } else { // 如果无法获取屏幕信息,使用默认值 logView->setMinimumWidth(390); logView->setMinimumHeight(410); } sshPassInput->setEchoMode(QLineEdit::Password); auto *central = new QWidget(this); auto *layout = new QVBoxLayout(central); auto *form = new QFormLayout(); form->addRow("SSH主机/IP", ipInput); presetIpCombo = new QComboBox(this); presetIpCombo->addItem("自定义"); presetIpCombo->addItem("圆通"); presetIpCombo->addItem("拼多多"); form->addRow("内置IP", presetIpCombo); form->addRow("SSH用户", sshUserInput); presetPassCombo->addItem("自定义"); presetPassCombo->addItem("圆通"); presetPassCombo->addItem("拼多多"); presetPassCombo->addItem("兔喜"); form->addRow("内置密码", presetPassCombo); form->addRow("登录密码", sshPassInput); form->addRow("修改MAC地址", macInput); // 在“当前MAC”行右侧添加 连接/刷新 按钮 QWidget *macButtonsWidget = new QWidget(this); auto *macBtnsLayout = new QHBoxLayout(macButtonsWidget); macBtnsLayout->setContentsMargins(0,0,0,0); macBtnsLayout->addWidget(connectButton); macBtnsLayout->addWidget(refreshButton); form->addRow(currentMacLabel, macButtonsWidget); layout->addLayout(form); auto *btns = new QHBoxLayout(); btns->addWidget(backupButton); btns->addWidget(modifyButton); layout->addLayout(btns); layout->addWidget(useSshCheck); useSshCheck->setChecked(true); useSshCheck->hide(); connect(useSshCheck, &QCheckBox::toggled, this, &MainWindow::onSshModeToggled); layout->addWidget(new QLabel("日志", this)); layout->addWidget(logView); setCentralWidget(central); connect(modifyButton, &QPushButton::clicked, this, &MainWindow::onModifyClicked); connect(backupButton, &QPushButton::clicked, this, &MainWindow::onBackupClicked); connect(connectButton, &QPushButton::clicked, this, &MainWindow::onConnectClicked); connect(refreshButton, &QPushButton::clicked, this, &MainWindow::onRefreshClicked); connect(presetPassCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::onPresetPassChanged); connect(presetIpCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::onPresetIpChanged); // 默认使用SSH远程执行,提供占位提示 useSshCheck->setChecked(true); ipInput->setPlaceholderText("例: 10.10.12.12/hostname"); macInput->setText("90:A9:F7:30:00:00"); sshUserInput->setText("root"); sshPassInput->setPlaceholderText("登录密码"); updateCurrentMac(); } MainWindow::~MainWindow() {} void MainWindow::log(const QString &msg) { QString ts = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); QString line = ts + " - " + msg; logger->append(msg); logView->append(line); logView->append(""); } QString MainWindow::generateMacFromIp(const QString &ip) { // 简单示例:固定前缀90:A9:F7:30,根据IP最后两段计算两个字节,末尾固定00 QRegularExpression re("^(?:\\d{1,3}\\.){3}\\d{1,3}$"); if (!re.match(ip).hasMatch()) return {}; auto parts = ip.split('.'); if (parts.size() != 4) return {}; bool ok1=false, ok2=false; int p2 = parts[2].toInt(&ok1); int p3 = parts[3].toInt(&ok2); if (!ok1 || !ok2) return {}; auto toHexByte = [](int v){ v = qBound(0, v, 255); return QString("%1").arg(v,2,16,QChar('0')).toUpper(); }; QString mac = QString("90:A9:F7:30:%1:%2").arg(toHexByte(p2)) .arg(toHexByte(p3)); return mac; } bool MainWindow::isValidMac(const QString &mac) const { QRegularExpression mre("^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}$"); return mre.match(mac).hasMatch(); } void MainWindow::updateCurrentMac() { if (useSshCheck->isChecked() && !sshConnected) { setCurrentMacStatus("当前MAC: 未连接主机", false); return; } auto mac = netMgr->readCurrentMac(kInterfacesPath); if (mac.isEmpty()) { setCurrentMacStatus("当前MAC: 未找到或读取失败", false); } else { setCurrentMacStatus("当前MAC: " + mac, true); } } void MainWindow::onBackupClicked() { QString err; // 检查是否使用 SSH 远程模式 if (useSshCheck->isChecked()) { QString host = ipInput->text().trimmed(); QString user = sshUserInput->text().trimmed(); QString password = sshPassInput->text().trimmed(); if (host.isEmpty() || user.isEmpty()) { QMessageBox::warning(this, "参数错误", "请先填写IP地址和SSH用户名"); return; } // 使用 SshClient 执行远程备份 SshClient ssh; if (!ssh.backupRemoteFile(host, user, password, kInterfacesPath, &err)) { QMessageBox::critical(this, "备份失败", err); log("备份失败: " + err); return; } QMessageBox::information(this, "备份完成", "已在远程服务器备份到 " + QString(kInterfacesPath) + ".bak"); log("已备份远程 interfaces 文件"); return; } // 本地模式 if (!netMgr->backupFile(kInterfacesPath, &err)) { QMessageBox::critical(this, "备份失败", err); log("备份失败: " + err); return; } QMessageBox::information(this, "备份完成", "已备份到同目录 .bak 文件"); log("已备份 interfaces 文件"); } void MainWindow::onModifyClicked() { QString ip = ipInput->text().trimmed(); QString mac = macInput->text().trimmed(); if (mac.isEmpty()) mac = generateMacFromIp(ip); if (!isValidMac(mac)) { QMessageBox::warning(this, "输入错误", "MAC地址格式错误,需形如AA:BB:CC:DD:EE:FF"); return; } if (useSshCheck->isChecked()) { // 通过SSH远程执行修改 QString host = ipInput->text().trimmed(); QString user = sshUserInput->text().trimmed(); QString auth = QString("密码"); QString secret = sshPassInput->text(); QString err; QString refPath = QCoreApplication::applicationDirPath() + "/interfaces"; QString useRef = QFile::exists(refPath) ? refPath : QString(); bool ok = sshClient->applyMacRemote(host, user, auth, secret, mac, kInterfacesPath, useRef, &err); if (!ok) { QMessageBox::critical(this, "远程修改失败", err); log("远程修改失败: " + err); return; } QMessageBox::information(this, "远程修改完成", "已通过SSH修改MAC"); log("远程修改完成"); if (!err.isEmpty()) log(err); onRefreshClicked(); } else { // 本地修改 QString err; if (!netMgr->ensureRootPermission(&err)) { QMessageBox::critical(this, "权限不足", err); log("权限不足: " + err); return; } QString refPath = QCoreApplication::applicationDirPath() + "/interfaces"; QString useRef = QFile::exists(refPath) ? refPath : QString(); if (!netMgr->applyMacLocal(kInterfacesPath, useRef, mac, &err)) { QMessageBox::critical(this, "修改失败", err); log("修改失败: " + err); return; } QMessageBox::information(this, "修改完成", "MAC地址已更新"); log("本地修改完成,更新MAC为: " + mac); updateCurrentMac(); } } void MainWindow::onConnectClicked() { // 连接:尝试读取远程当前MAC QString host = ipInput->text().trimmed(); QString user = sshUserInput->text().trimmed(); QString secret = sshPassInput->text(); QString err; // 远端读取:复用 applyMacRemote 的读取函数(将实现) QString remoteMac; if (sshClient->readRemoteCurrentMac(host, user, secret, kInterfacesPath, &remoteMac, &err)) { setCurrentMacStatus("当前MAC: " + remoteMac, true); log("已连接并读取远程MAC: " + remoteMac); sshConnected = true; } else { QMessageBox::critical(this, "连接失败", err); log("连接失败: " + err); sshConnected = false; setCurrentMacStatus("当前MAC: 未连接主机", false); } } void MainWindow::onRefreshClicked() { // 刷新当前MAC(根据是否使用SSH选择本地或远程) if (useSshCheck->isChecked()) { QString host = ipInput->text().trimmed(); QString user = sshUserInput->text().trimmed(); QString secret = sshPassInput->text(); QString err; QString remoteMac; if (sshClient->readRemoteCurrentMac(host, user, secret, kInterfacesPath, &remoteMac, &err)) { setCurrentMacStatus("当前MAC: " + remoteMac, true); log("已刷新远程MAC: " + remoteMac); sshConnected = true; } else { QMessageBox::warning(this, "刷新失败", err); log("刷新失败: " + err); sshConnected = false; setCurrentMacStatus("当前MAC: 未连接主机", false); } } else { updateCurrentMac(); log("已刷新本地MAC"); } } void MainWindow::onPresetPassChanged(int idx) { switch (idx) { case 1: sshPassInput->setText("&Over#B0Ost!"); break; case 2: sshPassInput->setText("PddloTSecPwdOnly!"); break; case 3: sshPassInput->setText("TxApPwd#2025!"); break; default: // 自定义:不覆盖用户输入,可选择清空 // sshPassInput->clear(); break; } } void MainWindow::onPresetIpChanged(int idx) { switch (idx) { case 1: ipInput->setText("192.168.172.173"); break; case 2: ipInput->setText("10.10.12.12"); break; default: // 自定义:不强制覆盖,保留用户当前输入 break; } } void MainWindow::onSshModeToggled(bool checked) { sshConnected = false; updateCurrentMac(); } void MainWindow::setCurrentMacStatus(const QString &text, bool ok) { currentMacLabel->setText(text); QPalette pal = currentMacLabel->palette(); pal.setColor(QPalette::WindowText, ok ? QColor(0, 128, 0) : QColor(200, 0, 0)); currentMacLabel->setPalette(pal); }