Skip to content

fix: optimize network switching detection - #601

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
ut003640:master
Aug 11, 2026
Merged

fix: optimize network switching detection#601
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
ut003640:master

Conversation

@ut003640

@ut003640 ut003640 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

When network connectivity is lost, automatically switch to another NIC that has internet access.

Previous approach: After detecting network unreachable, sequentially switch the primary link to the next NIC, then check if the switched NIC has connectivity. If still unreachable, continue switching. This causes NICs to keep switching back and forth.

Improved approach: After detecting network unreachable, individually check each alternative NIC to see if it can access the internet. Only switch the primary link to the target NIC after confirming it is online; otherwise, do not switch.

fix: 优化网络切换检测功能

在检测到网络不通的情况下,自动切换到其他可以上网的网卡
之前方案:在检测到网络不通后,依次将主链接切换到下一个网卡,再判断切换后的网卡网络是否通,如果还是不通,继续切换,这样就会导致网卡在不停切换 修改方案:在检测到网络不通后,依次针对其他的网卡单独检测这个网卡是否可以上网,只有在检测到可以上网后,才将主链接切换到当前网卡,否则不予切换

Log: 优化网卡自动切换功能
Influence: 切换主链接
Bug: https://pms.uniontech.com/bug-view-372223.html

Summary by Sourcery

Optimize automatic NIC switching so the primary link only moves to interfaces that are confirmed to have internet connectivity, reducing unnecessary flapping between devices.

Bug Fixes:

  • Ensure network failover selects a NIC with verified outbound connectivity instead of cycling blindly through available interfaces, preventing repeated primary link switching in unreachable-network scenarios.

Enhancements:

  • Introduce per-interface connectivity checks using DNS and TCP reachability, prioritizing wired over wireless devices when choosing a new primary NIC.
  • Replace the previous never-default/metric-toggling and timer-based switching logic with route metric reapplication that cleanly promotes the chosen NIC to primary.
  • Add more robust DNS resolution paths (UDP, TCP, and system resolver) bound to specific interfaces to improve online detection in constrained network environments such as mobile hotspots.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @ut003640, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@sourcery-ai

sourcery-ai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors InternetChecker to avoid oscillating primary NICs by probing each candidate interface’s real connectivity (DNS + TCP from that interface) before switching, and switches primary routing via per-device route metrics instead of toggling never-default and relying on NetworkManager primary-connection changes.

Sequence diagram for optimized NIC switching in InternetChecker

sequenceDiagram
    actor Caller
    participant InternetChecker
    participant NetworkManager
    participant Device

    Caller->>InternetChecker: switchInternetAccess(checkPrimaryConnection)
    InternetChecker->>NetworkManager: primaryConnection()
    InternetChecker->>NetworkManager: networkInterfaces()
    InternetChecker->>InternetChecker: build checkedDevices (wired + wireless)
    alt checkedDevices is empty
        InternetChecker-->>Caller: switchFailed()
    else checkedDevices not empty
        alt checkPrimaryConnection && primaryDevice exists
            InternetChecker->>InternetChecker: checkInterfaceOnline(primaryDevice)
            alt primaryDevice online
                InternetChecker-->>Caller: switchSuccess()
            else primaryDevice offline
                loop for each device in checkedDevices
                    InternetChecker->>InternetChecker: checkInterfaceOnline(device)
                    alt device online
                        InternetChecker->>InternetChecker: setPrimaryDevice(device, devices)
                        InternetChecker-->>Caller: switchSuccess()
                        %% break
                    end
                end
                InternetChecker-->>Caller: switchFailed()
            end
        else no primary check or no primaryDevice
            loop for each device in checkedDevices
                InternetChecker->>InternetChecker: checkInterfaceOnline(device)
                alt device online
                    InternetChecker->>InternetChecker: setPrimaryDevice(device, devices)
                    InternetChecker-->>Caller: switchSuccess()
                    %% break
                end
            end
            InternetChecker-->>Caller: switchFailed()
        end
    end
Loading

File-Level Changes

Change Details Files
Replace global HTTP-based connectivity checks with per-interface online detection that runs from the specific NIC using DNS and TCP reachability tests.
  • Remove HttpManager-based URL probing helpers (checkInternetAccessible*, checkInternetAccessibleWithRetry) and associated includes.
  • Introduce getDeviceDnsList to read IPv4 DNS servers from a device’s active connection.
  • Implement checkInterfaceOnline to test one NIC against configured checker URLs, handling both literal IPs and hostnames, with a total timeout split per URL.
  • Add fallback connectivity check to well-known public DNS IPs via direct TCP to handle environments where DNS queries may be blocked.
network-service-plugin/src/system/internetchecker.cpp
network-service-plugin/src/system/internetchecker.h
Add DNS-resolution helpers that bind traffic to a specific interface and support UDP, TCP, and system resolver fallback for A-record lookups.
  • Implement resolveByBindIface to resolve a domain using the NIC’s DNS list with per-server timeouts and three-step strategy: UDP DNS, TCP DNS, then getaddrinfo.
  • Add buildDnsQueryPacket to construct RFC 1035 DNS query packets with size/label validation.
  • Add parseDnsResponse to parse DNS responses, handle compression, and extract A records robustly.
  • Implement checkIpAddrByUDP and checkIpAddrByTCP to send DNS queries bound to the target NIC (SO_BINDTODEVICE + bind to NIC IP), manage non-blocking sockets and select-based timeouts, and feed responses into parseDnsResponse.
network-service-plugin/src/system/internetchecker.cpp
network-service-plugin/src/system/internetchecker.h
Introduce low-level, per-interface TCP reachability testing and use it to drive interface online checks without depending on NetworkManager primary-connection changes.
  • Implement isIfaceReachable using non-blocking TCP connect with SO_BINDTODEVICE, select-based timeout, and SO_ERROR verification.
  • Implement checkNetCardOnline to resolve a domain via resolveByBindIface then test TCP reachability to port 80 of the resolved IP via isIfaceReachable, splitting timeout between DNS and connect phases.
  • Use these helpers inside checkInterfaceOnline to decide whether a candidate NIC is considered online.
network-service-plugin/src/system/internetchecker.cpp
network-service-plugin/src/system/internetchecker.h
Change the switching algorithm to probe all candidate NICs and only switch primary routing to one that is confirmed online by adjusting route metrics.
  • Refactor switchInternetAccess to enumerate all managed, up, and actively connected devices, group them into wired-then-wireless candidate list, and optionally short-circuit if the current primary device is online.
  • Iterate candidate devices and call checkInterfaceOnline plus setPrimaryDevice, emitting switchSuccess on the first success or switchFailed if none are online.
  • Implement setPrimaryDevice to adjust IPv4/IPv6 routeMetric for all active devices (target gets low metric, others high), update connection settings, and call NetworkManager::Device::reapplyConnection via D-Bus so routing changes take effect.
network-service-plugin/src/system/internetchecker.cpp
network-service-plugin/src/system/internetchecker.h
Remove the previous stateful switching mechanism based on never-default flags, retry lists, timers, and primaryConnectionChanged callbacks.
  • Delete resetAllNeverDefault, setConnectionNeverDefault, setPrimaryDeviceNeverDefault, changeDeviceNeverDefault, and all checkInternetAccessible* helpers.
  • Remove m_tryIndex, m_tryDevices, m_switchTimer, and m_isSwitching members and the associated logic.
  • Remove onPrimaryConnectionChanged and onPrimaryConnectionTimeout slots and the QTimer-based fallback switching path.
  • Simplify constructor/destructor: drop NetworkManager notifier connections and QTimer cleanup, use defaulted destructor.
network-service-plugin/src/system/internetchecker.cpp
network-service-plugin/src/system/internetchecker.h

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help


using namespace network::systemservice;

// 注册 NMVariantMapMap (QMap<QString,QVariantMap>) 到 D-Bus 元类型系统,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注册 NMVariantMapMap的代码没看到,代码与注释不一致?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

注释忘记删了,不需要这个

When network connectivity is lost, automatically switch to another NIC that has internet access.

Previous approach: After detecting network unreachable, sequentially switch the primary link to the next NIC, then check if the switched NIC has connectivity. If still unreachable, continue switching. This causes NICs to keep switching back and forth.

Improved approach: After detecting network unreachable, individually check each alternative NIC to see if it can access the internet. Only switch the primary link to the target NIC after confirming it is online; otherwise, do not switch.

fix: 优化网络切换检测功能

在检测到网络不通的情况下,自动切换到其他可以上网的网卡
之前方案:在检测到网络不通后,依次将主链接切换到下一个网卡,再判断切换后的网卡网络是否通,如果还是不通,继续切换,这样就会导致网卡在不停切换
修改方案:在检测到网络不通后,依次针对其他的网卡单独检测这个网卡是否可以上网,只有在检测到可以上网后,才将主链接切换到当前网卡,否则不予切换

Log: 优化网卡自动切换功能
Influence: 切换主链接
Bug: https://pms.uniontech.com/bug-view-372223.html
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:95分

■ 【总体评价】

代码重构了网络切换逻辑,使用底层socket绑定网卡进行连通性检测和DNS解析,逻辑严密且鲁棒性强
代码质量高,边界处理完善,无安全漏洞,因部分代码可进一步优化扣5分

■ 【详细分析】

  • 1.语法逻辑(基本正确)✓

switchInternetAccessisIfaceReachableparseDnsResponse等函数逻辑清晰,正确处理了非阻塞socket的EINPROGRESS状态和SO_ERROR检查。DNS解析包构造和响应解析的边界检查基本到位,如buildDnsQueryPacket中对标签长度和总包长的校验。
潜在问题:parseDnsResponse中跳过Question Section时,p += buf[p] + 1如果buf[p]值很大,可能导致p溢出,但由于外层有p < len的保护,不会导致越界读取,仅可能导致逻辑提前终止。
建议:在p += buf[p] + 1前增加对p + buf[p] + 1是否超过len的校验,增强代码健壮性。

  • 2.代码质量(良好)✓

代码注释非常详尽,清楚地解释了使用底层socket和DNS解析的原因以及手机热点等特殊场景的处理。函数划分合理,职责单一,如将DNS查询拆分为UDP、TCP和系统调用三种方式。
潜在问题:checkIpAddrByUDPcheckIpAddrByTCP中绑定网卡和源IP的代码存在重复。
建议:可以将绑定网卡和源IP的逻辑提取为一个独立的辅助函数,减少代码冗余。

  • 3.代码性能(良好)✓

使用非阻塞socket配合select进行超时控制,避免了网络检测过程中的永久阻塞。通过QElapsedTimer对总检测时间进行限制,并在多URL和多DNS服务器之间合理分配超时时间。
潜在问题:无
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码在处理网络数据包时进行了严格的长度校验,未发现缓冲区溢出、注入等安全风险。memset确保了结构体初始化,strncpy配合清零操作保证了字符串安全截断。

  • 建议:继续保持严格的输入校验和边界检查习惯。

■ 【改进建议代码示例】

// 优化 parseDnsResponse 中的边界检查
bool InternetChecker::parseDnsResponse(const unsigned char *buf, int len, unsigned short txId, in_addr &outIp)
{
    // ... 前置代码 ...
    // 跳过 Question Section:每个问题包含域名 + QTYPE(2) + QCLASS(2)
    for (int i = 0; i < qnum; i++) {
        bool compressed = false;
        // 跳过域名:逐标签跳过,遇到压缩指针(高两 bit 为 11)则跳过 2 字节
        while (p < len && buf[p] != 0) {
            if ((buf[p] & 0xC0) == 0xC0) {
                if (p + 2 > len)
                    break;
                p += 2;
                compressed = true;
                break;
            }
            // 增加边界检查,防止 p 溢出
            if (p + buf[p] + 1 >= len) {
                p = len; // 强制退出
                break;
            }
            p += buf[p] + 1;
        }
        // ... 后续代码 ...
    }
    // ... 后续 Answer Section 解析逻辑 ...
}

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: caixr23, ut003640

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ut003640

Copy link
Copy Markdown
Contributor Author

/force

@ut003640

Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot
deepin-bot Bot merged commit 4f21702 into linuxdeepin:master Aug 11, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants