ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

WSL 2 内部网络守护进程 GNS 全面解析:从 hvsocket 通道到 DNS 隧道

WSL 2 内部网络守护进程 GNS 全面解析:从 hvsocket 通道到 DNS 隧道 WSL 2 内部网络守护进程 GNS 全面解析从 hvsocket 通道到 DNS 隧道【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL导读GNSGuest Networking Service是 WSL2 虚拟机内部负责网络配置的核心守护进程由mini_init在虚拟机启动阶段创建负责在 Linux 客户机内落实 Windows 主机wslservice.exe下发的全部网络配置。本文基于仓库文档与源码梳理 GNS 的进程定位、hvsocket 通信通道、消息协议、网络配置处理流程与 DNS 隧道机制帮助读者理解 WSL2 的 NAT / 镜像Mirrored网络模式是如何在客户机内落地生效的读完可掌握查看 GNS 网络配置逻辑 → 定位网卡 / 路由 / DNS 相关源码的完整分析路径。GNS 是什么由 mini_init 创建的客户机网络守护进程gns是一个运行在 WSL2 虚拟机内部的 Linux 进程由mini_init创建其唯一职责是在 WSL2 虚拟机内配置网络gns.md。这里的mini_init是 WSL2 虚拟机启动后执行的第一个用户态可执行程序它在完成/proc、/sys、/dev等标准挂载与 crash dump、日志等初始化工作后会作为启动流程的一部分拉起gnsmini_init.md。从 boot-process.md 的启动时序可以看到 GNS 在系统启动中的确切位置即wslservice.exe先向mini_init发送LxMiniInitMessageEarlyConfig包含系统 VHD、主机名、内存回收模式等信息随后mini_init通过fork()exec(/gns)创建 GNS 进程紧接着wslservice.exe就向 GNS 发送第一条LxGnsMessageInterfaceConfiguration消息开始下发初始网络配置。GNS 与 mini_init 通道的区别mini_init自身维护着两条与wslservice.exe之间的 hvsocket 通道mini_init 通道接收wslservice.exe下发的管理消息例如LxMiniInitMessageLaunchInit挂载虚拟磁盘并启动发行版、LxMiniInitMessageMount用于wsl --mount等消息与响应定义见 lxinitshared.h通知通道用于向wslservice.exe上报 Linux 进程退出等事件。GNS 的 hvsocket 通道是独立于上述两条通道之外的第三条专用通道专用于网络配置二者职责互不重叠mini_init 管系统与发行版生命周期GNS 管网络。共享的网络配置所有 WSL2 发行版共用一套网络设置文档明确指出一个关键设计网络设置由所有 WSL2 发行版共享gns.md。WSL2 的网络能力NAT、端口转发、DNS 解析、与 Windows 主机的回环互通等是由虚拟机层面统一提供的而非由某个发行版内的init进程各自配置。因此GNS 随虚拟机启动、随虚拟机退出独立于任何具体发行版虚拟机内同时运行多个发行版时它们共享同一套由 GNS 维护的接口、路由与 DNS 配置接口配置并非通过修改发行版文件实现而是由 GNS 直接操作内核 netlink 接口完成。这一点可以从源码中印证GNS 的接口操作全部通过 netlink 子系统完成例如 Interface.cpp、RoutingTable.cpp 所在的netlinkutil目录封装了对 netlink 套接字的读写NetworkManager.h 中的ModifyAddress、ModifyRoute、ResetRoutingTable等方法构成了 GNS 操纵内核网络栈的核心能力。hvsocket 通道wslservice.exe 与 gns 的通信桥梁WSL2 虚拟机运行期间GNS 维护着一条到 Windows 主机wslservice.exe的hvsocket 通道hypervisor socket用于收发各类网络相关配置。这条通道的两端实现在仓库中分别位于端文件职责Linux 客户机端src/linux/init/GnsEngine.cpp接收并处理消息、调用 NetworkManager 落地配置Windows 主机端src/windows/common/GnsChannel.cpp由 wslservice.exe 持有发送网络配置到虚拟机Windows 侧的GnsChannel类头文件注释直接说明了它的定位This class manages the hvsocket channel between wslservice and the gns process inside the VM. This channel is used for network configuration inside the guest.GnsChannel.h。通道上的消息类型两端通信的消息类型统一定义在 lxinitshared.h 的LX_MESSAGE_TYPE枚举中其中 GNS 相关的核心消息包括消息含义结合 GnsEngine.cpp 处理逻辑LxGnsMessageInterfaceConfiguration配置网卡HNS endpoint设置网卡名、下发 IP 地址、将网卡置为 UpLxGnsMessageNotification通用资源通知通过 JSON 携带具体资源类型路由 / IP / MAC / DNS / 链路状态LxGnsMessageVmNicCreatedNotification新网卡创建通知触发在对应接口上启用回环路由LxGnsMessageCreateDeviceRequest创建设备请求如回环设备触发回环配置初始化LxGnsMessageModifyGuestDeviceSettingRequest修改设备设置如接口链路状态、MTU、MetricLxGnsMessageLoopbackRoutesRequest镜像网络模式下增删回环路由LxGnsMessageInitialIpConfigurationNotification初始 IP 配置通知切换主路由表、重置 IPv6 状态、清理回环路由、启用 IPv4 arp_filterLxGnsMessageSetupIpv6IPv6 初始化禁用 DAD重复地址检测、路由器发现与 IPv6 地址自动生成LxGnsMessageGlobalNetFilter/LxGnsMessageInterfaceNetFilter通过nft配置全局与按网卡的 SNAT 规则LxGnsMessageConnectTestRequest连通性测试请求返回 IPv4/IPv6 状态码LxGnsMessageDnsTunnelingDNS 隧道相关消息消息内容以 JSON 字符串承载Windows 侧通过SendNetworkDeviceMessage/SendHnsNotification发送GnsChannel.cppLinux 侧在ProcessNextMessage中解析并分发GnsEngine.cpp。wslservice.exe对GnsChannel的持有与使用可参见 WslCoreVm.cpp、HcsVirtualMachine.cpp 等虚拟机管理代码。GNS 负责落地的四类核心网络配置文档列出 GNS 负责下发的四类核心配置接口 IP 配置、路由表条目、DNS 配置、MTU 大小配置gns.md。结合GnsEngine::ProcessNextMessage与各类Process*Change处理函数可看到这些配置在客户机内具体如何落地。1. 接口 IP 配置LxGnsMessageNotification携带GuestEndpointResourceType::IPAddress时GNS 调用ProcessIpAddressChangeGnsEngine.cpp将 Windows 侧的地址族枚举WinAf转换为 Linux 地址族仅接受AF_INETIPv4与AF_INET6IPv6构造Address对象包含前缀长度、地址、PrefixOrigin/SuffixOrigin 及 PreferredLifetime特别地禁用 Linux 自动生成前缀路由SetIsPrefixRouteAutogenerationDisabled(true)因为对应的前缀路由会由独立的 Route 消息单独下发避免重复依据ModifyRequestTypeAdd/Remove/Update调用manager.ModifyAddress执行实际的地址增删改。接口 IP 也可以由LxGnsMessageInterfaceConfiguration一次性下发消息中携带 HNS endpoint 的IPAddressGNS 调用manager.SetAdapterConfiguration(interface, endpoint)完成整网卡配置并将网卡状态置为 UpGnsEngine.cpp。2. 路由表条目ProcessRouteChangeGnsEngine.cpp处理路由的增删改收到Reset操作时直接调用manager.ResetRoutingTable清空指定地址族在接口上的路由表通过LX_INIT_DEFAULT_ROUTE_PREFIXIPv4与LX_INIT_DEFAULT_ROUTE_V6_PREFIXIPv6判断是否为默认路由——默认路由不需要目标前缀而非默认路由则由Address::FromPrefixString从DestinationPrefix解析出目标网段构造Route对象含地址族、下一跳、接口索引、默认路由标记、目标、Metric按Add/Remove/Update调用manager.ModifyRoute。路由的底层实现封装在 netlinkutil/RoutingTable.cpp 与 netlinkutil/Route.cpp 中通过 netlink 的RTM_NEWROUTE/RTM_DELROUTE与内核交互。NetworkManager还维护着用于回环镜像的自定义路由表loopbackRoutingTable与localRoutingTableNetworkManager.h支撑镜像网络模式下Windows 与 Linux 共享 localhost的能力。3. DNS 配置ProcessDNSChangeGnsEngine.cpp将 DNS 配置写入客户机的/etc/resolv.conf忽略Remove操作——后续的Add/Update会整体覆盖符合 resolv.conf 文件式配置的特性将Options字段作为文件头写入Windows 侧可借此传递options等指令把ServerList按逗号拆分逐行写出nameserver server将SearchDNS 搜索后缀按逗号拆分后以空格连接写出search suffix1 suffix2 ...源码注释特别引用了 resolv.conf(5) 手册domain指令是search的过时别名故统一使用search写入前确保/etc目录存在UtilMkdirPath(/etc, 0755)随后以 truncate 模式打开/etc/resolv.conf写入。这也是用户在发行版内修改/etc/resolv.conf后会被 WSL2 重置的原因只要虚拟机运行期间收到新的 DNS 配置GNS 就会重写该文件。4. MTU 与链路状态ProcessLinkChangeGnsEngine.cpp处理网卡链路状态变化根据link.Connected将接口置为InterfaceState::Up或InterfaceState::Down接口 Connected 且NlMtu ! 0时调用interface.SetMtu(link.NlMtu)设置 MTU接口 Connected 且Metric ! 0时调用interface.SetMetric(link.Metric)设置路由度量值。此外GNS 还处理两类文档之外但同样关键的配置以支撑完整网络栈MAC 地址ProcessMacAddressChange解析 Windows 侧以-分隔的物理地址并设置到接口会翻转接口状态以生效接口命名与虚拟 Wi-FiLxGnsMessageInterfaceConfiguration处理PortFriendlyName必要时通过manager.SetAdapterName重命名接口对以wlan开头的名称会先把物理接口改名成_wlanxx再通过CreateVirtualWifiAdapter创建虚拟 Wi-Fi 接口GnsEngine.cpp。启动与主循环一个长期运行的消息分发器GnsEngine::run()GnsEngine.cpp是 GNS 的主循环将线程命名为GnsEngine循环调用channel.ReceiveTransaction()从 hvsocket 通道接收消息事务调用ProcessNextMessage分发处理处理成功则通过statusRoutine(return_value, , transaction)回复LxGnsMessageResult处理异常则回复-1与错误信息保证 wslservice.exe 能感知到配置失败收到空消息通道关闭时退出循环。Windows 侧的GnsChannel使用事务式Transaction通信每条消息发出后等待对应的LxGnsMessageResult返回若结果非 0 则抛出E_UNEXPECTED异常若返回ERROR_FATAL_APP_EXIT则说明 GNS 进程已退出GnsChannel.cpp。这保证了配置必须被客户机确认的可靠性语义。值得注意的是GNS 在收到LxGnsMessageInterfaceConfiguration时会通过OpenAdapter在/sys/class/net/目录下遍历查找与 HNS endpoint GUID 匹配的网卡GnsEngine.cpp通过读取/sys/class/net/iface/device符号链接解析出设备 GUID特殊处理_wlanxx跳过等待虚拟 Wi-Fi 接口与wlanxx回溯两级目录接口查找带 30 秒超时、100 毫秒重试周期的重试封装RetryWithTimeout以容忍内核设备枚举的时序延迟。DNS 隧道GNS 在客户机内应答 DNS 请求当DNS tunnelingDNS 隧道开启时GNS 还承担了在客户机内应答 DNS 请求的职责gns.md。这一机制在 GNS 构造函数中初始化GnsEngine.cpp将隧道使用的 IP 地址添加到回环接口lo上源码注释说明Linux 允许将不属于127.0.0.0/8的 IPv4 地址添加到回环接口构造DnsTunnelingManager持有 hvsocket 文件描述符与隧道 IP 地址。DnsTunnelingManagerDnsTunnelingManager.cpp由两个部件组成DnsTunnelingManager.hDnsTunnelingChannel负责与主机之间传输原始 DNS 消息的 hvsocket 通道。收到主机的 DNS 响应时回调m_dnsServer.HandleDnsResponseDnsServer客户机内的 DNS 服务器同时支持 UDP 与 TCP。收到客户机内进程的 DNS 查询时将报文原样通过DnsTunnelingChannel.SendDnsMessage转发给主机由主机完成实际解析后回传。因此数据流向为客户机进程 → 客户机内 DnsServerUDP/TCP→ DnsTunnelingChannelhvsocket→ Windows 主机解析 → 原路返回。源码注释还指出一个细节由于 GNS 守护进程先于GnsPortTracker启动DNS 服务器的绑定不会被 bind seccomp 钩子拦截——在镜像FSEFull System Emulation实为 Flow Steering / Firewall模式下无需 host↔guest 回环通信所有指向 DNS 服务器的流量都留在容器内DnsTunnelingManager.cpp因此该时序是安全的。Windows 侧与 DNS 隧道相关的处理可进一步阅读 DnsTunnelingChannel.cpp 与 DnsResolver.cpp。网络过滤与连通性GNS 对流量策略的落地除上述基础配置外GNS 还通过nftables落实主机下发的流量策略对应 Windows 侧防火墙 / 镜像网络规则全局过滤LxGnsMessageGlobalNetFilter分别对 IPv4、IPv6 建立filter表与nat表在WSLOUTPUT链中将源自 root 命名空间的流量打上0x1标记并在WSLPOSTROUTING链准备 SNAT 挂载点GnsEngine.cpp按接口过滤LxGnsMessageInterfaceNetFilter为指定网卡在WSLPOSTROUTING链创建 UDP/TCP 的 masquerade SNAT 规则端口范围由请求携带并为标记不等于0x1的流量做源端口映射到指定的临时端口区间移除时先通过nft -a list chain解析规则 handle 再逐一删除同时同步更新镜像回环规则GnsEngine.cpp。这些nft规则共同实现了镜像网络模式下区分根命名空间流量与容器流量、并对非标记流量做 SNAT的核心语义。另外LxGnsMessageConnectTestRequest让 GNS 充当连通性探测的执行者将 IPv4 状态置于返回值低 16 位、IPv6 状态置于高 16 位返回给主机GnsEngine.cppWindows 侧则通过GnsChannel::SendNetworkDeviceMessageReturnResult获取该结果GnsChannel.cpp。如何进一步阅读与验证围绕 GNS 主题仓库内可按以下路径继续深入协议定义lxinitshared.h 中的LX_MESSAGE_TYPE枚举与LX_GNS_*结构体定义了全部消息格式客户机端实现GnsEngine.cpp消息分发、NetworkManager.h 与 NetworkManager.cppnetlink 落地、netlinkutil/netlink 底层封装主机端实现GnsChannel.cpp通道封装、WslCoreVm.cpp虚拟机与通道生命周期、MirroredNetworking.cpp 与 BridgedNetworking.h不同网络模式在主机侧的配置生成启动上下文mini_init.md、boot-process.md 与 index.mdWSL 整体架构图其中明确标注了wslservice.exe -----|hvsocket| gns与mini_init---|exec()|gns两条连接。需要说明的是GNS 在客户机内通过 netlink 直接操作内核网络栈其效果可通过发行版内的ip addr、ip route、ip link与cat /etc/resolv.conf直接观察而通道消息属于 Windows 与 Linux 之间的内部协议除非开启 GNS 日志GNS_LOG_INFO/GNS_LOG_ERROR宏否则用户一般只能观察到配置结果而非消息本身。小结GNS 是 WSL2 虚拟机的网络管家它以独立于发行版的姿态随虚拟机启动通过一条专用 hvsocket 通道接收wslservice.exe的网络指令借助 netlink 将接口 IP、路由、MTU、MAC、链路状态逐项落地到客户机内核把 DNS 配置写进/etc/resolv.conf并在 DNS 隧道模式下直接扮演客户机内 DNS 服务器。理解了 GNS 的角色与消息流就掌握了 WSL2 网络架构从 Windows 主机到 Linux 客户机的完整主线无论是排查网络问题还是阅读 WSL 源码都能快速定位到正确的代码路径。【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表