Skip to content

tangramor/RustNfsSvc

Repository files navigation

RustNfsSvc

English | 中文

A high-performance NFS (Network File System) server for Windows, written in Rust. Supports NFSv3, NFSv4.1, and NFSv4.2, enabling Linux/Unix clients to mount Windows directories transparently.

Features

  • NFSv3 — Full protocol support (MOUNT, PORTMAP, NFSv3 procedures)
  • NFSv4.1 — COMPOUND operations, SEQUENCE, OPEN, CLOSE, READ, WRITE, READDIR, LOCK/LOCKU, SETATTR, and more
  • NFSv4.2 — READ_PLUS, COPY, SEEK, CLONE, plus 9 stub operations per RFC 7862
  • Native Windows Service — Install/uninstall as a Windows Service with automatic startup
  • Dual-stack NFS — Run NFSv3, NFSv4.1, and NFSv4.2 simultaneously on the same port (2049)
  • MOUNT protocol — NFSv3 MOUNT protocol on port 20048
  • PORTMAP — RPC portmapper on port 111 (TCP + UDP)
  • Async I/O — Built on Tokio for high concurrency
  • Flexible configuration — TOML-based config with per-export access control (CIDR)
  • TLS encryption — Built-in TLS support (rustls) for encrypted NFS transport (SEC-015)
  • Structured logging — Rolling log files with configurable level and rotation

Project Structure

RustNfsSvc/
├── src/
│   ├── main.rs              # Entry point: CLI arg parsing (install/uninstall/service/standalone)
│   ├── path_ext.rs          # Windows \\?\ extended-path helper (MAX_PATH fix)
│   ├── service.rs           # Windows Service lifecycle (install/uninstall via sc.exe, run mode)
│   ├── config.rs            # Configuration loading and validation
│   ├── exports.rs           # Export directory management and file handle resolution
│   ├── logging.rs           # Log initialization and rotation
│   └── nfs/
│       ├── mod.rs           # Unified NFS server (TCP + UDP, v3 + v4, TLS)
│       ├── nfs4.rs          # NFSv4.1/4.2 protocol implementation (~4100 lines)
│       ├── protocol.rs      # NFSv3 protocol implementation
│       ├── mount.rs         # MOUNT protocol (v1/v3)
│       └── portmap.rs       # PORTMAP / RPCBIND service
├── build.rs                 # Build script
├── config.example.toml       # Example configuration
├── install.bat               # One-click install script
├── uninstall.bat             # One-click uninstall script
├── Cargo.toml                # Package manifest
├── README_zh.md              # Chinese README
└── README.md                 # This file

Quick Start

Prerequisites

  • Rust 1.70+ (install from rustup.rs)
  • Windows 10/11 or Windows Server 2016+
  • Visual Studio Build Tools (C++ workload)

Build

cargo build --release

The binary is at target/release/rustnfssvc.exe.

Configure

If there is configuration file config.toml just under the same folder of rustnfssvc.exe, it will be used as default config.

Copy the example config and edit it:

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

Edit C:\ProgramData\RustNfsSvc\config.toml to set your export paths and client access rules.

Run

Standalone mode (for testing):

rustnfssvc.exe

As a Windows Service (requires Administrator):

:: Install
install.bat

:: Start
net start rustnfssvc

:: Stop
net stop rustnfssvc

:: Uninstall
uninstall.bat

Configuration

Configuration is loaded from C:\ProgramData\RustNfsSvc\config.toml. See config.example.toml for a complete reference.

[nfs]
listen_address = "0.0.0.0:2049"
enable_v3 = true
enable_v4 = true
threads = 4
bind_ip = "0.0.0.0"                # Bind to specific IP for security
max_connections = 128              # Global concurrent connection limit
max_conn_rate_per_ip = 60          # Per-IP rate limit (connections per 60s window)
enable_udp = true                  # Enable UDP (set false for production with TLS)

[tls]                              # SEC-015: TLS encryption
enabled = false
cert_path = ""                     # PEM certificate path (required when enabled)
key_path = ""                      # PEM private key path (PKCS8 or 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

Export Options

Option Description
rw Read-write access (default)
ro Read-only access
sync Synchronous writes
async Asynchronous writes
no_subtree_check Disable subtree checking (better performance)
insecure Allow connections from ports ≥ 1024
no_root_squash Allow root to access files as root

TLS Configuration

RustNfsSvc supports built-in TLS encryption for NFS traffic over TCP. When enabled, the server uses rustls (ring backend) to encrypt all NFS/MOUNT/PORTMAP TCP connections.

Enabling TLS

  1. Generate certificates — Create a PEM certificate and private key for the server:

    # Using OpenSSL
    openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes \
      -subj "/CN=nfs-server" -addext "subjectAltName=IP:192.168.1.1"
    
    # Convert key to PKCS8 (preferred by rustls)
    openssl pkcs8 -topk8 -nocrypt -in server.key -out server.key.pkcs8
  2. Configure — Edit config.toml:

    [tls]
    enabled = true
    cert_path = "C:/etc/rustnfssvc/server.crt"
    key_path  = "C:/etc/rustnfssvc/server.key"    # PKCS8 or PKCS1 RSA accepted
  3. Disable UDP — TLS only works over TCP. Set enable_udp = false when using TLS.

  4. Restart — Restart the service for TLS to take effect.

Client-side Mount with TLS

Linux NFS clients do not natively support TLS. Use stunnel to create an encrypted tunnel:

On the client (Linux):

  1. Install stunnel:

    sudo apt install stunnel4    # Debian/Ubuntu
    sudo yum install stunnel     # RHEL/CentOS
  2. Create /etc/stunnel/nfs.conf:

    [nfs]
    client = yes
    accept = 127.0.0.1:2049
    connect = <server-ip>:2049
    verifyChain = yes
    CApath = /etc/ssl/certs
    ; Or specify the server cert directly:
    ; CAfile = /path/to/server.crt
  3. Start stunnel:

    sudo systemctl start stunnel4
  4. Mount via the local tunnel:

    sudo mount -t nfs4 -o vers=4,minorversion=1 127.0.0.1:/<alias> /mnt/shared

Note: When using stunnel on both sides, the NFS mount address is always 127.0.0.1 (the local tunnel endpoint), not the server's real IP.

Using stunnel on the Server Side (Alternative)

If you prefer not to use the built-in TLS, you can also run stunnel on the server side to wrap the NFS port:

On the server (Windows):

  1. Download stunnel for Windows.

  2. Create stunnel.conf:

    [nfs]
    accept = 2049
    connect = 127.0.0.1:12049
    cert = C:/etc/rustnfssvc/server.crt
    key = C:/etc/rustnfssvc/server.key
  3. Configure RustNfsSvc to listen on the internal port:

    [nfs]
    listen_address = "127.0.0.1:12049"
  4. Start stunnel, then start RustNfsSvc. Stunnel will encrypt traffic on port 2049 and forward to the internal NFS port.

Client Mount

NFSv4.2 (recommended)

sudo mount -t nfs4 -o vers=4,minorversion=2 <server-ip>:/<alias> /mnt/shared

NFSv4.1

sudo mount -t nfs4 -o vers=4,minorversion=1 <server-ip>:/<alias> /mnt/shared

NFSv3

sudo mount -t nfs -o vers=3 <server-ip>:/<alias> /mnt/shared

Verify

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

Architecture

                        ┌─────────────────────┐
   Linux NFS Client ───│  NFSv4.2 (TCP/2049) │───┐
   Linux NFS Client ───│  NFSv4.1 (TCP/2049) │───┤
   Linux NFS Client ───│  NFSv3  (TCP/2049)  │───┤
   Linux NFS Client ───│  NFSv3  (UDP/2049)  │───┤
                        └─────────────────────┘   │
                        ┌─────────────────────┐   │
   mount.nfs ──────────│  MOUNT  (TCP/20048) │───┤
   mount.nfs ──────────│  MOUNT  (UDP/20048) │───┤
                        └─────────────────────┘   │
                        ┌─────────────────────┐   │
   rpcinfo ────────────│  PORTMAP (TCP/111)  │───┤
   rpcinfo ────────────│  PORTMAP (UDP/111)  │───┤
                        └─────────────────────┘   │
                                                   ▼
                                         ┌─────────────────┐
                                         │  ExportsManager │
                                         │  (C:\exports\...) │
                                         └─────────────────┘
  • Unified listener — A single TCP/UDP listener on port 2049 handles NFSv3, NFSv4.1, and NFSv4.2 requests, dispatching by RPC program version
  • ExportsManager — Manages file handle resolution, directory enumeration, and file I/O against the local Windows filesystem
  • Session management — NFSv4.1/4.2 sessions with slot/sequence tracking for exactly-once semantics

Development

# Run in debug mode
cargo run

# Run tests
cargo test

# Format code
cargo fmt

# Lint
cargo clippy

Protocol Compliance

Protocol RFC Status
NFSv3 RFC 1813 Supported
NFSv4.0 RFC 3010 Partial
NFSv4.1 RFC 5661 Supported
NFSv4.2 RFC 7862 Supported
MOUNT v1 RFC 1094 Supported
MOUNT v3 RFC 1813 Supported
PORTMAP v2 RFC 1057 Supported

NFSv4.2 Operations (RFC 7862)

Operation Opcode Status Description
READ_PLUS 68 ✅ Supported Enhanced read returning data/hole information
COPY 60 ✅ Supported Server-side intra-server file copy
SEEK 69 ✅ Supported Find next data or hole offset in a file
CLONE 71 ✅ Supported Server-side file range clone (read+write)
ALLOCATE 59 Stub Returns NOTSUPP
DEALLOCATE 62 Stub Returns NOTSUPP
IO_ADVISE 63 Stub Returns NOTSUPP
LAYOUTERROR 64 Stub Returns NOTSUPP
LAYOUTSTATS 65 Stub Returns NOTSUPP
OFFLOAD_CANCEL 66 Stub Returns NOTSUPP
OFFLOAD_STATUS 67 Stub Returns NOTSUPP
WRITE_SAME 70 Stub Returns NOTSUPP
COPY_NOTIFY 61 Stub Returns NOTSUPP

Note: Stub operations return NFS4ERR_NOTSUPP. COPY only supports intra-server copy; inter-server copy is not supported. CLONE is implemented as a simplified read+write (no BlockClone API). SEEK uses a simplified model (SEEK4_HOLE returns file size) since Windows does not expose sparse file hole information via standard APIs.

License

GPL-3.0

About

A high-performance NFS (Network File System) server for Windows, written in Rust. Supports both NFSv3 and NFSv4.1, enabling Linux/Unix clients to mount Windows directories transparently.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors