windows 驱动实例分析系列: wireguard-nt驱动分析-driver篇(一)

📅 2026/8/22 16:28:45
windows 驱动实例分析系列: wireguard-nt驱动分析-driver篇(一)
WireGuardNT 驱动代码解析 - 第一篇设备管理与IOCTL接口1. 概述WireGuardNT 驱动driver/目录是 WireGuard 在 Windows NT 内核中的核心实现负责处理 VPN 隧道的数据包加解密、路由、对等体管理以及网络接口操作。本系列文档将驱动代码分为四个部分进行解析本文为第一部分涵盖设备初始化、适配器管理、IOCTL 控制接口以及与网络状态指示器NSI的交互。主要涉及以下源文件main.c– 驱动入口点DriverEntry和卸载例程。device.c/device.h– 定义 WG_DEVICE 结构实现 NDIS 微型端口驱动回调初始化、暂停、重启、发送、接收、OID 请求等。ioctl.c/ioctl.h– 实现用户态与驱动通信的 IOCTL 接口获取/设置配置、适配器状态、读取日志。nsi.c/nsi.h– 与 Windows 网络状态指示器NSI集成监控 MTU 变化并拦截 NSI 设置请求。wireguard.inf– 驱动安装信息文件。wireguard.rc/wireguard.ico– 资源文件。2. 驱动入口与初始化main.cDriverEntry是驱动的初始化入口其流程如下调用ExInitializeDriverRuntime(DrvRtPoolNxOptIn)启用非执行池保护。调用CryptoDriverEntry()检测 CPU 特性SSSE3、AVX、AVX2、AVX512 等为后续加密算法选择最佳实现。调用NoiseDriverEntry()预计算 Noise 握手协议所需的初始哈希和链密钥基于固定字符串。调用MemDriverEntry()初始化内存池NET_BUFFER 和 NET_BUFFER_LIST 缓存。调用RcuDriverEntry()初始化 RCU 机制每 CPU 的 DPC 和清理线程。调用AllowedIpsDriverEntry()初始化 AllowedIPs 查找树的节点缓存。调用RatelimiterDriverEntry()初始化速率限制器GC 线程和哈希表。调用PeerDriverEntry()初始化对等体对象的后备列表lookaside list。调用DeviceDriverEntry()注册 NDIS 微型端口驱动NdisMRegisterMiniportDriver。调用IoctlDriverEntry()和NsiDriverEntry()分别挂接 IOCTL 派遣例程和 NSI 过滤。若调试版本DBG启用了自测试还会执行CryptoSelftest、AllowedIpsSelftest、PacketCounterSelftest和RatelimiterSelftest。卸载例程Unload依次调用DeviceUnload、WskUnload、PeerUnload、RatelimiterUnload、AllowedIpsUnload、RcuUnload、MemUnload释放资源。3. NDIS 微型端口驱动device.cdevice.c实现了 NDIS 微型端口驱动所需的回调函数并管理WG_DEVICE结构每个适配器一个实例。3.1 核心数据结构WG_DEVICE定义在device.h中包含MiniportAdapterHandle– NDIS 适配器句柄。Statistics– 接口统计信息收发字节、包数等。ItemsInFlight– 引用计数用于控制暂停/重启时的资源释放。多个环形队列EncryptQueue、DecryptQueue、HandshakeRxQueue用于异步处理。多核工作队列EncryptThreads、DecryptThreads、HandshakeTxThreads、HandshakeRxThreads用于并行加解密和握手。套接字指针Sock4和Sock6RCU 保护。静态身份标识StaticIdentity公钥/私钥。Cookie 检查器CookieChecker。对等体哈希表PeerHashtable和索引哈希表IndexHashtable。AllowedIPs 表PeerAllowedIps。设备锁DeviceUpdateLock和套接字更新锁SocketUpdateLock。对等体列表PeerList和计数NumPeers。接口索引、LUID、属主进程、监听端口、UP/DOWN 状态等。3.2 NDIS 回调函数InitializeEx创建WG_DEVICE实例初始化所有队列、锁、哈希表、工作线程并调用RegisterAdapter注册适配器属性。若成功调用NsiActivate激活 NSI 监控。HaltEx反向清理关闭套接字、移除所有对等体、销毁工作线程、释放内存。Pause在适配器暂停时调用等待所有飞行中的包完成调用DeviceStop停止设备清空密钥、清除握手状态。Restart恢复适配器重新初始化ItemsInFlight并调用DeviceStart启动对等体的待发送包和保活定时器。SendNetBufferLists处理上层协议栈发来的数据包。对每个 NBL检查协议IPv4/IPv6提取 IP 头通过AllowedIpsLookupDst查找目标对等体然后将包加入对等体的暂存队列StagedPacketQueue并触发PacketSendStagedPackets发送。OidRequest处理 OID 查询和设置请求例如返回厂商 ID、速度、统计信息、链路状态等。对于OID_GEN_CURRENT_PACKET_FILTER等设置仅验证长度并返回成功对于OID_PNP_SET_POWER若进入 D1 以上状态则调用RcuBarrier。ReturnNetBufferLists释放接收到的 NBL由PacketReceive处理后调用。3.3 适配器状态管理DeviceStart和DeviceStop分别启动/停止设备其中DeviceStart遍历所有对等体发送暂存包和保活包DeviceStop清除所有对等体的密钥和握手状态并清空握手队列。DeviceIndicateConnectionStatus用于向 NDIS 报告链路连接状态UP/DOWN并更新链路速度。4. IOCTL 接口ioctl.c / ioctl.h用户态 DLLwireguard.dll通过 IOCTL 与驱动通信。驱动在IoctlDriverEntry中替换IRP_MJ_DEVICE_CONTROL的派遣例程并设置安全描述符允许 SYSTEM 和 Administrators 完全访问。定义的控制代码ioctl.hWG_IOCTL_GETMETHOD_OUT_DIRECT获取当前适配器配置接口信息、对等体列表、AllowedIPs。返回WG_IOCTL_INTERFACE结构及其后跟随的WG_IOCTL_PEER和WG_IOCTL_ALLOWED_IP结构。若缓冲区不足返回STATUS_BUFFER_OVERFLOW并给出所需大小。WG_IOCTL_SETMETHOD_IN_DIRECT设置配置。输入为一个WG_IOCTL_INTERFACE后接若干WG_IOCTL_PEER和WG_IOCTL_ALLOWED_IP。驱动解析并应用配置设置监听端口、私钥、添加/删除对等体、更新 AllowedIPs。WG_IOCTL_SET_ADAPTER_STATEMETHOD_BUFFERED设置适配器状态UP/DOWN或查询当前状态。WG_IOCTL_READ_LOG_LINEMETHOD_BUFFERED读取下一条日志条目环形缓冲区。关键辅助函数HasAccess使用安全描述符检查调用者权限。WgDeviceFromFdo从设备对象提取WG_DEVICE指针利用NdisWdfGetAdapterContextFromAdapterHandle。Get操作遍历对等体和 AllowedIPs填充输出缓冲区。注意使用锁保护DeviceUpdateLock和各个子锁。Set操作解析WG_IOCTL_INTERFACE调用SetListenPort、SetPrivateKey并循环处理每个对等体SetPeer。SetPeer中会查找或创建对等体更新预共享密钥、端点、持久保活间隔并调用AllowedIpsInsertV4/V6或Remove更新路由表。SetAdapterState根据命令调用Up或Down内部会创建/销毁 UDP 套接字、更新链路状态、启动/停止定时器。ReadLogLine从LOG_RING中读取一条日志非阻塞等待可被设备移除事件中断。5. NSI 集成nsi.c / nsi.h为了监控和调节接口 MTU驱动挂钩了 NSI网络状态指示器的IOCTL_NSI_SET_ALL_PARAMETERS调用。NsiDriverEntry替换了IRP_MJ_PNP和IRP_MJ_DEVICE_CONTROL的派遣例程并在首次有设备激活时附加到\Device\Nsi设备对象。NsiActivate将设备加入全局DeviceList若列表原本为空则调用Attach挂载过滤设备。NsiDeactivate从列表中移除若列表变空则调用Detach卸载过滤。过滤派遣例程FilterDispatch拦截IOCTL_NSI_SET_ALL_PARAMETERS提取出MIB_IPINTERFACE_ROW包括接口 LUID 和 MTU然后调用原始的 NSI 请求并在成功后回调IpInterfaceChangeNotification更新设备的Mtu4或Mtu6根据地址族。该回调也通过NotifyRouteChange2注册以响应路由变化。通过这种方式驱动能感知上层设置的 MTU并调整数据包填充大小确保不超过 MTU。6. 自测试与调试在调试版本中main.c中会执行一系列自测试加密、AllowedIPs、计数器、速率限制器这些测试定义在selftest/目录下的文件中如chacha20poly1305.c、allowedips.c、counter.c、ratelimiter.c。测试失败将导致驱动加载失败返回STATUS_INTERNAL_ERROR。7. 总结第一部分的代码构成了驱动的基础骨架负责驱动的加载、初始化、卸载。NDIS 微型端口驱动的注册和回调实现。用户态 IOCTL 接口实现配置的获取、设置及适配器状态控制。与 NSI 集成自适应 MTU 变化。后续文档将深入探讨加密与 Noise 协议、数据包收发路径以及辅助模块。