From 7e642b6963d10e44d20468be42e16a436c3e1ef9 Mon Sep 17 00:00:00 2001 From: gongheng Date: Wed, 27 May 2026 14:33:28 +0800 Subject: [PATCH] fix: use NetworkManager D-Bus to enable/disable network interfaces Replace the previous iw/rfkill/ifconfig and ioctl approach with NetworkManager D-Bus API as the primary method for controlling network interface state. The D-Bus method sets the DeviceEnabled property via GetDeviceByIpIface. Fall back to the ioctl method when the D-Bus approach is unavailable or fails. - Add enableNetworkByDBus() as primary method (scheme 1) - Add enableNetworkByIoctl() as fallback method (scheme 2) - Remove wlan/wlp-specific iw/rfkill/ifconfig logic - Refactor ioctlOperateNetworkLogicalName() to try D-Bus first, then fall back to ioctl - Add QDBus headers and update SPDX copyright year Log: fix issue Bug: https://pms.uniontech.com/bug-view-362409.html --- .../src/enablecontrol/enableutils.cpp | 177 ++++++++++-------- .../src/enablecontrol/enableutils.h | 26 ++- 2 files changed, 118 insertions(+), 85 deletions(-) diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp index f94661f8e..04ed9a70d 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019 ~ 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2019 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -9,13 +9,17 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include #include #include -#include #define LEAST_NUM 10 #define REG_ADDRESS "^[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}$" @@ -140,88 +144,101 @@ void EnableUtils::disableInDevice() bool EnableUtils::ioctlOperateNetworkLogicalName(const QString &logicalName, bool enable) { - if (logicalName.startsWith("wlan") || logicalName.startsWith("wlp")) { // Wireless LAN - // 第一步:获取 wiphy 编号 - QProcess iwProcess; - iwProcess.start("iw", QStringList() << "dev" << logicalName << "info"); - iwProcess.waitForFinished(); - QString iwOutput = QString::fromUtf8(iwProcess.readAllStandardOutput()); - - // 解析 wiphy 编号 - QRegularExpression wiphyRe("wiphy\\s+(\\d+)"); - QRegularExpressionMatch wiphyMatch = wiphyRe.match(iwOutput); - if (!wiphyMatch.hasMatch()) { - qCritical() << "Failed to get wiphy number for interface: " << logicalName; - return false; - } - QString phyNum = wiphyMatch.captured(1); - - // 第二步:获取 rfkill 设备编号 - QProcess rfkillListProcess; - rfkillListProcess.start("rfkill", QStringList() << "list"); - rfkillListProcess.waitForFinished(); - QString rfkillOutput = QString::fromUtf8(rfkillListProcess.readAllStandardOutput()); - - // 查找对应的 rfkill 编号 - QRegularExpression rfkillRe("^(\\d+):.*\\n.*\\n.*phy" + phyNum); - QRegularExpressionMatch rfkillMatch = rfkillRe.match(rfkillOutput); - QString rfkillId; - if (rfkillMatch.hasMatch()) { - rfkillId = rfkillMatch.captured(1); - } + // 方案一:通过NetworkManager D-Bus设置DeviceEnabled属性 + if (enableNetworkByDBus(logicalName, enable)) + return true; - // 第三步:执行 rfkill block/unblock - if (!rfkillId.isEmpty()) { - QProcess rfkillBlockProcess; - rfkillBlockProcess.start("rfkill", QStringList() << (enable ? "unblock" : "block") << rfkillId); - rfkillBlockProcess.waitForFinished(); - int ret = rfkillBlockProcess.exitCode(); - if (ret != 0) { - qCritical() << "Failed to block/unblock wifi: error code: " << ret; - } - } + // 方案二:方案一失败,回退到ioctl方式 + qWarning() << "Fallback to ioctl method for" << logicalName; + return enableNetworkByIoctl(logicalName, enable); +} - // 第四步:执行 ifconfig up/down - QProcess ifconfigProcess; - ifconfigProcess.start("/sbin/ifconfig", QStringList() << logicalName << (enable ? "up" : "down")); - ifconfigProcess.waitForFinished(); - int ret = ifconfigProcess.exitCode(); - if (ret != 0) { - qCritical() << "Failed to up/down network: " << logicalName << enable << " error code: " << ret; - return false; - } - } else { - // 1. 通过ioctl禁用 - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd < 0) - return false; - - struct ifreq ifr; - strncpy(ifr.ifr_name, logicalName.toStdString().c_str(),IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ - 1] = '\0'; - short flag; - if (enable) { - flag = IFF_UP | IFF_PROMISC; - } else { - flag = ~(IFF_UP | IFF_PROMISC); - } - // 先获取标识 - if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { - close(fd); - return false; - } - // 获取后重新设置标识 - if (enable) { - ifr.ifr_ifru.ifru_flags |= flag; - } else { - ifr.ifr_ifru.ifru_flags &= flag; - } +// 方案一:通过NetworkManager D-Bus设置DeviceEnabled属性 +bool EnableUtils::enableNetworkByDBus(const QString &logicalName, bool enable) +{ + // 1. 通过 system dbus 获取 devicePath + QDBusInterface nmInterface("org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager", + "org.freedesktop.NetworkManager", + QDBusConnection::systemBus()); + if (!nmInterface.isValid()) { + qCritical() << "Failed to connect to NetworkManager:" << nmInterface.lastError().message(); + return false; + } - if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { - close(fd); - return false; - } + QDBusReply reply = nmInterface.call("GetDeviceByIpIface", logicalName); + if (!reply.isValid()) { + qCritical() << "Failed to GetDeviceByIpIface for" << logicalName << ":" << reply.error().message(); + return false; + } + + QString devicePath = reply.value().path(); + if (devicePath.isEmpty()) { + qCritical() << "Got empty devicePath for interface:" << logicalName; + return false; + } + + // 2. 通过 system dbus 设置 DeviceEnabled 属性 + QDBusInterface deviceInterface("org.freedesktop.NetworkManager", + devicePath, + "org.freedesktop.DBus.Properties", + QDBusConnection::systemBus()); + if (!deviceInterface.isValid()) { + qCritical() << "Failed to connect to device properties:" << deviceInterface.lastError().message(); + return false; + } + + QDBusReply setReply = deviceInterface.call("Set", + "org.freedesktop.NetworkManager.Device", + "DeviceEnabled", + QVariant::fromValue(QDBusVariant(enable))); + if (!setReply.isValid()) { + qCritical() << "Failed to set DeviceEnabled for" << logicalName << ":" << setReply.error().message(); + return false; + } + + return true; +} + +// 方案二:通过ioctl控制网卡 +bool EnableUtils::enableNetworkByIoctl(const QString &logicalName, bool enable) +{ + // 安全校验:网卡名长度合法性 + if (logicalName.isEmpty() || logicalName.length() >= IFNAMSIZ) { + qCritical() << "Invalid logicalName length for ioctl"; + return false; + } + + // 通过ioctl设置网卡启用/禁用 + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) + return false; + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + + std::string nameStr = logicalName.toStdString(); + strncpy(ifr.ifr_name, nameStr.c_str(),IFNAMSIZ - 1); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + + // 先获取标识 + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + close(fd); + return false; } + + if (enable) { + ifr.ifr_flags |= IFF_UP; + } else { + ifr.ifr_flags &= ~IFF_UP; + } + // 设置新标识 + if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { + close(fd); + return false; + } + + close(fd); return true; } diff --git a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h index ba02af528..164227499 100644 --- a/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h +++ b/deepin-devicemanager-server/deepin-devicecontrol/src/enablecontrol/enableutils.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019 ~ 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2019 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -25,13 +25,29 @@ class EnableUtils static void disableInDevice(); /** - * @brief ioctlOperateNetworkLogicalName 通过ioctl设置网卡是否可用 - * @param logicalName - * @param enable - * @return + * @brief ioctlOperateNetworkLogicalName 设置网卡是否可用,优先使用D-Bus方案,失败回退到ioctl方案 + * @param logicalName 网卡逻辑名称 + * @param enable true启用,false禁用 + * @return 成功返回true,失败返回false */ static bool ioctlOperateNetworkLogicalName(const QString &logicalName, bool enable); + /** + * @brief enableNetworkByDBus 方案一:通过NetworkManager D-Bus设置DeviceEnabled属性 + * @param logicalName 网卡逻辑名称 + * @param enable true启用,false禁用 + * @return 成功返回true,失败返回false + */ + static bool enableNetworkByDBus(const QString &logicalName, bool enable); + + /** + * @brief enableNetworkByIoctl 方案二:通过ioctl控制网卡是否可用 + * @param logicalName 网卡逻辑名称 + * @param enable true启用,false禁用 + * @return 成功返回true,失败返回false + */ + static bool enableNetworkByIoctl(const QString &logicalName, bool enable); + /** * @brief getMapInfo 解析usb信息 * @param item