支持 UNC 命名和 MUP

本文介绍网络重定向程序如何支持统一命名约定 (UNC) 命名和多 UNC 提供程序 (MUP)。

MUP 是一个系统提供的内核模式组件,负责处理 UNC 路径:

  • 它可帮助定位被标识为使用 UNC 的网络资源。

  • 它会将所有使用 UNC 名称的远程文件系统访问引导至能够处理远程文件系统请求的网络重定向程序。 网络重定向程序是 UNC 提供程序

当应用程序使用 UNC 路径时,就会涉及 MUP;例如,以下命令行命令:

notepad \\server\public\readme.txt

MUP 会从应用程序接收包含 UNC 名称的命令。 它会将名称发送给每个已注册的 UNC 提供程序和已安装的任何其他网络提供程序。 当 UNC 提供程序将一个 UNC 名称识别为自己的名称时,MUP 会自动将该名称的未来实例重定向到该提供程序。

在创建映射驱动器号的操作(例如,“NET USE”命令)过程中不涉及 MUP。 取而代之的是用于网络重定向程序的多提供程序路由器 (MPR) 和用户模式 Windows 网络 (WNet) 提供程序 DLL 来处理此操作。 但是,用户模式 WNet 提供程序 DLL 可以在此操作期间直接与内核模式网络重定向程序驱动程序通信。

对于符合 Windows Vista 中引入的重定向程序模型的网络重定向程序,即使使用映射的网络驱动器,也会涉及 MUP。 对映射驱动器执行的文件操作通过 MUP 转到网络重定向程序。 在这种情况下,MUP 只是将操作传递给所涉及的网络重定向程序。

MUP 是 mup.sys 二进制文件的一部分,其中还包括 DFS(分布式文件系统)客户端。

内核网络重定向程序通常也有一个用户模式的 WNet 提供程序 DLL,以支持建立与远程资源的连接(例如,将驱动器号映射到远程资源)。 MPR 是一个用户模式 DLL,它基于对 WNet 提供程序的查询建立网络连接。 调用 MPR 是以下任何操作的结果:

  • 从命令提示符发出的 net use x: \\server\share 命令。

  • 从 Windows 资源管理器建立的网络驱动器号连接。

  • 直接调用 WNet 函数。

网络重定向程序必须向 MUP 注册才能处理 UNC 名称。 在 MUP 中可以注册多个 UNC 提供程序。 这些 UNC 提供程序可以是以下一个或多个重定向程序:

  • 基于 RDBSS 的网络微型重定向程序,如服务器消息块 (SMB) 重定向程序和 WebDAV 重定向程序。
  • 不基于 RDBSS 的旧版重定向程序。

前缀解析

MUP 确定哪个提供程序可以在基于名称的操作(通常是 IRP_MJ_CREATE 请求)中处理 UNC 路径。 这种判定被称为“前缀解析”。前缀解析操作有两个目的:

  • 导致前缀解析的基于名称的操作将被路由到声称拥有该前缀的提供程序。 如果成功,MUP 可确保后续的基于句柄的操作(例如,IRP_MJ_READ 和 IRP_MJ_WRITE)完全绕过 MUP 转到同一个提供程序。

  • 提供程序及其声明的前缀会被录入 MUP 维护的前缀缓存中。 对于基于名称的后续操作,MUP 使用此前缀缓存来确定提供程序在尝试执行前缀解析之前是否已经声明了前缀。 一旦将前缀缓存中的每个条目添加到缓存中,就会发生超时(称为 TTL)。 此超时到期后,条目将被丢弃,此时 MUP 将对基于名称的后续操作再次执行此前缀的前缀解析。

MUP 通过向注册到 MUP 的网络重定向程序发出 IOCTL_REDIR_QUERY_PATH 请求来执行前缀解析。 IOCTL_REDIR_QUERY_PATH 的输入和输出缓冲区是从非分页池中分配的。

通过验证 IRP 结构的 RequesterMode 成员是否为 KernelMode,网络重定向程序仅允许此 IOCTL 的内核模式发送方。

MUP 使用 QUERY_PATH_REQUEST 结构获取请求信息。

UNC 提供程序为响应信息使用 QUERY_PATH_RESPONSE 结构。

通过调用 FsRtlRegisterUncProvider 向 MUP 注册为 UNC 提供程序的任何旧网络重定向程序(不基于使用 RDBSS)都会接收 IOCTL_REDIR_QUERY_PATH 请求。

表示支持 UNC 提供程序的网络微型重定向程序会接收此前缀声明,就好像它是 IRP_MJ_CREATE 调用一样。 此创建请求类似于将 FILE_CREATE_TREE_CONNECTION 标志设置为打开的用户模式 CreateFile 调用。 网络微型重定向程序不会收到前缀声明作为对 MRxLowIOSubmit[LOWIO_OP_IOCTL] 的调用。 对于前缀声明,RDBSS 会向网络微型重定向程序发送 MRxCreateSrvCall请求,然后调用 MRxSrvCallWinnerNotifyMRxCreateVNetRoot。 当网络微型重定向程序向 RDBSS 注册时,RDBSS 会复制网络微型重定向程序的驱动程序调度表,使其指向 RDBSS 内部入口点。 然后,RDBSS 会在内部接收此 IOCTL_REDIR_QUERY_PATH,用于网络微型重定向程序,并调用 MRxCreateSrvCallMRxSrvCallWinnerNotifyMRxCreateVNetRoot。 原始 IOCTL_REDIR_QUERY_PATH 会包含在传递给 MRxCreateSrvCall 例程的 RX_CONTEXT 结构中。 此外,传递给 MRxCreateSrvCall 的 RX_CONTEXT 中的以下成员会被修改:

  • MajorFunction 成员设置为 IRP_MJ_CREATE,即使原始 IRP 为 IRP_MJ_DEVICE_CONTROL。
  • PrefixClaim.SuppliedPathName.Buffer 成员设置为 QUERY_PATH_REQUEST 结构的 FilePathName 成员。
  • PrefixClaim.SuppliedPathName.Length 成员设置为 QUERY_PATH_REQUEST 结构的 PathNameLength 成员。
  • Create.NtCreateParameters.SecurityContext 成员设置为 QUERY_PATH_REQUEST 结构的 SecurityContext 成员。
  • Create.ThisIsATreeConnectOpen 成员被设置为 TRUE。
  • Create.Flags 成员已设置 RX_CONTEXT_CREATE_FLAG_UNC_NAME 位。

如果网络微型重定向程序希望查看前缀声明的详细信息,则可以在传递给 MRxCreateSrvCall 的 RX_CONTEXT 中读取这些成员。 否则,如果 MRxCreateSrvCall 调用成功,它就可以尝试连接到服务器共享并返回STATUS_SUCCESS。 RDBSS 代表网络微型重定向程序发出前缀声明。

有一种情况是网络微型重定向程序可以直接接收此 IOCTL。 网络微型重定向程序可以在初始化并向 RDBSS 注册之前保存其驱动程序调度表的副本。 在调用 RxRegisterMinirdr 向 RDBSS 注册后,网络微型重定向程序可以保存 RDBSS 安装的新驱动程序调度表入口点的副本,并还原其原始驱动程序调度表。 还原后的驱动程序调度表需要修改,以便在检查接收到的 IRP 中网络微型重定向程序相关的 IRP 后,将调用转发到 RDBSS 驱动程序调度入口点。 当驱动程序初始化 RDBSS 并调用 RxRegisterMinrdr 时,RDBSS 会通过网络微型重定向程序的驱动程序调度表进行复制。 链接到 rdbsslib.lib 的网络微型重定向程序必须在从其 DriverEntry 例程调用 RxDriverEntry 之前保存其原始驱动程序调度表,以初始化 RDBSS 静态库,并在调用 RxRegisterMinrdr 之后还原其驱动程序调度表。 之所以需要这样做,是因为 RDBSS 在 RxDriverEntryRxRegisterMinrdr 例程中都通过网络微型重定向程序调度表进行复制。

REG_SZ ProviderOrder 注册表值控制着在前缀解析过程中查询提供程序的顺序。 此值存储在以下键中:

HKLM\System\CurrentControlSet\Control\NetworkProvider\Order

ProviderOrder 注册表值中的各个提供程序名称用逗号分隔,不带任何前导空格或尾随空格。

例如,此值可以包含以下字符串:

RDPNP,LanmanWorkstation,WebClient

给定 UNC 路径 \\<server>\<share>\<path>,如果在 MUP 前缀缓存中找不到前缀(例如,\\server\share 或 \\server),则 MUP 会发出前缀解析请求。 MUP 按以下顺序向每个提供程序发送前缀解析请求,直到有提供程序声明该前缀,或查询到所有提供程序:

  1. TS 客户端 (RDPNP)

  2. SMB 重定向程序 (LanmanWorkstation)

  3. WebDAV 重定向程序 (WebClient)

对 ProviderOrder 注册表值的更改需要重新启动才能在 MUP 中生效。

MUP 使用列出的每个提供程序名称在以下注册表项下查找提供程序的注册表项:

HKLM\System\CurrentControlSet\Services\<ProviderName>

然后,MUP 读取 NetworkProvider 子项下的 DeviceName 值,以查找提供程序将注册的设备名称。 当提供程序实际注册时,MUP 会将传入的设备名称与已知提供程序的设备名称列表进行匹配。 然后,它会将提供程序列入一个有序列表,以便进行前缀解析。 此列表中的提供程序顺序基于之前讨论的 ProviderOrder 注册表值中指定的顺序。

多提供程序路由器 (MPR) 是一个用户模式 DLL,可根据对 WNet 提供程序的查询建立网络连接,它也会遵守这种提供程序顺序。

MUP 会串行发出前缀解析请求,并在第一个提供程序声明前缀后立即停止。 因此,在上述示例中,如果 RDPNP 声明前缀,MUP 将不会调用 SMB 或 WebDAV 重定向程序。

“串行前缀解析”(相对于并行)可防止具有较低 ProviderOrder 优先级的网络重定向程序导致更高的 ProviderOrder 优先级的网络重定向程序出现性能问题。 例如,假设有一台远程服务器,安装了防火墙,配置为阻止某些类型的 TCP/IP 数据包(例如对 HTTP 的访问),但允许其他类型的数据包(例如,SMB 访问)。 在这种情况下,即使 SMB 网络重定向程序被配置为 ProviderOrder 值中的第一个提供程序并快速声明前缀,WebDAV 重定向程序也可能通过等待 TCP 连接超时来显著延迟前缀解析的完成。