RustNfsSvc - Windows下的 NFS4 服务器

RustNfsSvc - Windows下的 NFS4 服务器

RustNfsSvc 是一个高性能的 Windows NFS(网络文件系统)服务器,使用 Rust 编写。支持 NFSv3、NFSv4.1 和 NFSv4.2,使 Linux/Unix 客户端能够透明挂载 Windows 目录。

功能特性

  • NFSv3— 完整协议支持(MOUNT、PORTMAP、NFSv3 过程)
  • NFSv4.1— COMPOUND 操作、SEQUENCE、OPEN、CLOSE、READ、WRITE、READDIR、LOCK/LOCKU、SETATTR 等
  • NFSv4.2— READ_PLUS、COPY、SEEK、CLONE,以及 RFC 7862 定义的 9 个 stub 操作
  • 原生 Windows 服务— 可安装/卸载为 Windows 服务,支持开机自启
  • 双栈 NFS— 在同一端口(2049)上同时运行 NFSv3、NFSv4.1 和 NFSv4.2
  • MOUNT 协议— NFSv3 MOUNT 协议,端口 20048
  • PORTMAP— RPC 端口映射服务,端口 111(TCP + UDP)
  • 异步 I/O— 基于 Tokio 构建,支持高并发
  • 灵活配置— 基于 TOML 的配置文件,支持按导出目录的访问控制(CIDR)
  • TLS 加密— 内置 TLS 支持(rustls),加密 NFS 传输流量(SEC-015)
  • 结构化日志— 滚动日志文件,可配置日志级别和轮转策略

项目结构

RustNfsSvc/ ├── src/ │ ├── main.rs # 入口:CLI 参数解析(install/uninstall/service/独立运行) │ ├── path_ext.rs # Windows \\?\ 扩展路径辅助(MAX_PATH 修复) │ ├── service.rs # Windows 服务生命周期(通过 sc.exe 安装/卸载,运行模式) │ ├── config.rs # 配置加载与验证 │ ├── exports.rs # 导出目录管理与文件句柄解析 │ ├── logging.rs # 日志初始化与轮转 │ └── nfs/ │ ├── mod.rs # 统一 NFS 服务器(TCP + UDP,v3 + v4,TLS) │ ├── nfs4.rs # NFSv4.1/4.2 协议实现(约 4100 行) │ ├── protocol.rs # NFSv3 协议实现 │ ├── mount.rs # MOUNT 协议(v1/v3) │ └── portmap.rs # PORTMAP / RPCBIND 服务 ├── build.rs # 构建脚本 ├── config.example.toml # 配置示例 ├── install.bat # 一键安装脚本 ├── uninstall.bat # 一键卸载脚本 ├── Cargo.toml # 包清单 ├── README_zh.md # 中文说明文档 └── README.md # 英文说明文档

快速开始

前置要求

  • Rust 1.70+(从 rustup.rs 安装)
  • Windows 10/11 或 Windows Server 2016+
  • Visual Studio Build Tools(C++ 工作负载)

构建

cargobuild--release

编译产物位于target/release/rustnfssvc.exe

配置

如果在rustnfssvc.exe同目录下存在config.toml,将作为默认配置使用。

复制示例配置并编辑:

copy config.example.toml"C:\ProgramData\RustNfsSvc\config.toml"

编辑C:\ProgramData\RustNfsSvc\config.toml,设置导出路径和客户端访问规则。

运行

独立运行模式(用于测试):

rustnfssvc.exe

作为 Windows 服务运行(需要管理员权限):

:: 安装 install.bat :: 启动 net start rustnfssvc :: 停止 net stop rustnfssvc :: 卸载 uninstall.bat

配置说明

配置文件从C:\ProgramData\RustNfsSvc\config.toml加载。完整配置参考见config.example.toml

[nfs] listen_address = "0.0.0.0:2049" enable_v3 = true enable_v4 = true threads = 4 bind_ip = "0.0.0.0" # 绑定到特定 IP 以增强安全性 max_connections = 128 # 全局并发连接上限 max_conn_rate_per_ip = 60 # 单 IP 连接速率限制(每 60s 窗口) enable_udp = true # 启用 UDP(使用 TLS 时建议设为 false) [tls] # SEC-015:TLS 加密 enabled = false cert_path = "" # PEM 证书路径(启用时必填) key_path = "" # PEM 私钥路径(PKCS8 或 PKCS1 RSA 均可) [[exports.entries]] path = "C:\\Shared" alias = "shared" allowed_clients = ["192.168.1.0/24"] options = ["rw", "sync", "no_subtree_check"] [logging] level = "info" file = "C:\\ProgramData\\RustNfsSvc\\logs\\rustnfssvc.log" max_log_size_mb = 100 max_log_files = 10

导出选项

选项说明
rw读写访问(默认)
ro只读访问
sync同步写入
async异步写入
no_subtree_check禁用子树检查(性能更好)
insecure允许来自 ≥ 1024 端口的连接
no_root_squash允许 root 用户以 root 身份访问文件

TLS 加密配置

RustNfsSvc 支持内置 TLS 加密 NFS TCP 流量。启用后,服务器使用rustls(ring 后端)加密所有 NFS/MOUNT/PORTMAP TCP 连接。

启用 TLS
  1. 生成证书— 为服务器创建 PEM 格式的证书和私钥:

    # 使用 OpenSSLopenssl req-x509-newkeyrsa:2048-keyoutserver.key-outserver.crt-days365-nodes\-subj"/CN=nfs-server"-addext"subjectAltName=IP:192.168.1.1"# 将密钥转为 PKCS8 格式(rustls 推荐)openssl pkcs8-topk8-nocrypt-inserver.key-outserver.key.pkcs8
  2. 配置— 编辑config.toml

    [tls] enabled = true cert_path = "C:/etc/rustnfssvc/server.crt" key_path = "C:/etc/rustnfssvc/server.key" # 接受 PKCS8 或 PKCS1 RSA 格式
  3. 禁用 UDP— TLS 仅支持 TCP。启用 TLS 时设置enable_udp = false

  4. 重启服务— 重启使 TLS 生效。

客户端使用 stunnel 挂载

Linux NFS 客户端原生不支持 TLS。使用stunnel建立加密隧道:

在客户端(Linux)上:

  1. 安装 stunnel:

    sudoaptinstallstunnel4# Debian/Ubuntusudoyuminstallstunnel# RHEL/CentOS
  2. 创建/etc/stunnel/nfs.conf

    [nfs] client = yes accept = 127.0.0.1:2049 connect = <服务器IP>:2049 verifyChain = yes CApath = /etc/ssl/certs ; 或直接指定服务器证书: ; CAfile = /path/to/server.crt
  3. 启动 stunnel:

    sudosystemctl start stunnel4
  4. 通过本地隧道挂载:

    sudomount-tnfs4-overs=4,minorversion=1127.0.0.1:/<别名>/mnt/shared

注意:使用 stunnel 时,NFS 挂载地址始终是127.0.0.1(本地隧道端点),而非服务器的真实 IP。

服务器端使用 stunnel(替代方案)

如果不使用内置 TLS,也可以在服务器端运行 stunnel 来包装 NFS 端口:

在服务器(Windows)上:

  1. 从 stunnel 官网 下载 Windows 版本。

  2. 创建stunnel.conf

    [nfs] accept = 2049 connect = 127.0.0.1:12049 cert = C:/etc/rustnfssvc/server.crt key = C:/etc/rustnfssvc/server.key
  3. 配置 RustNfsSvc 监听内部端口:

    [nfs] listen_address = "127.0.0.1:12049"
  4. 先启动 stunnel,再启动 RustNfsSvc。stunnel 将加密端口 2049 上的流量,并转发到内部 NFS 端口。

客户端挂载

NFSv4.2(推荐)

sudomount-tnfs4-overs=4,minorversion=2<服务器IP>:/<别名>/mnt/shared

NFSv4.1

sudomount-tnfs4-overs=4,minorversion=1<服务器IP>:/<别名>/mnt/shared

NFSv3

sudomount-tnfs-overs=3<服务器IP>:/<别名>/mnt/shared

验证

ls/mnt/sharedecho"hello from NFS">/mnt/shared/test.txt

架构

┌─────────────────────┐ Linux NFS 客户端 ───│ NFSv4.2 (TCP/2049) │───┐ Linux NFS 客户端 ───│ NFSv4.1 (TCP/2049) │───┤ Linux NFS 客户端 ───│ NFSv3 (TCP/2049) │───┤ Linux NFS 客户端 ───│ NFSv3 (UDP/2049) │───┤ └─────────────────────┘ │ ┌─────────────────────┐ │ mount.nfs ──────────│ MOUNT (TCP/20048) │───┤ mount.nfs ──────────│ MOUNT (UDP/20048) │───┤ └─────────────────────┘ │ ┌─────────────────────┐ │ rpcinfo ────────────│ PORTMAP (TCP/111) │───┤ rpcinfo ────────────│ PORTMAP (UDP/111) │───┤ └─────────────────────┘ │ ▼ ┌─────────────────┐ │ ExportsManager │ │ (C:\exports\...) │ └─────────────────┘
  • 统一监听器— 在端口 2049 上通过单个 TCP/UDP 监听器同时处理 NFSv3、NFSv4.1 和 NFSv4.2 请求,按 RPC 程序版本分发
  • ExportsManager— 管理文件句柄解析、目录枚举和针对本地 Windows 文件系统的文件 I/O
  • 会话管理— NFSv4.1/4.2 会话使用槽位/序列跟踪,实现恰好一次语义

开发

# 以调试模式运行cargorun# 运行测试cargotest# 格式化代码cargofmt# 代码检查cargoclippy

协议合规性

协议RFC状态
NFSv3RFC 1813已支持
NFSv4.0RFC 3010部分支持
NFSv4.1RFC 5661已支持
NFSv4.2RFC 7862已支持
MOUNT v1RFC 1094已支持
MOUNT v3RFC 1813已支持
PORTMAP v2RFC 1057已支持

NFSv4.2 操作(RFC 7862)

操作操作码状态说明
READ_PLUS68✅ 已支持增强读取,返回数据/空洞信息
COPY60✅ 已支持服务器端文件复制(仅同服务器)
SEEK69✅ 已支持查找文件中下一个数据或空洞偏移
CLONE71✅ 已支持服务器端文件范围克隆(读+写)
ALLOCATE59Stub返回 NOTSUPP
DEALLOCATE62Stub返回 NOTSUPP
IO_ADVISE63Stub返回 NOTSUPP
LAYOUTERROR64Stub返回 NOTSUPP
LAYOUTSTATS65Stub返回 NOTSUPP
OFFLOAD_CANCEL66Stub返回 NOTSUPP
OFFLOAD_STATUS67Stub返回 NOTSUPP
WRITE_SAME70Stub返回 NOTSUPP
COPY_NOTIFY61Stub返回 NOTSUPP

注意:Stub 操作返回NFS4ERR_NOTSUPP。COPY 仅支持同服务器内复制,不支持跨服务器复制。CLONE 为简化的 read+write 实现(未使用 BlockClone API)。SEEK 使用简化模型(SEEK4_HOLE 返回文件大小),因为 Windows 不通过标准 API 暴露稀疏文件空洞信息。

许可证

GPL-3.0