Skip to content

Commit 54dbc0e

Browse files
committed
feat: add FTP server and FTPS support
1 parent 861f888 commit 54dbc0e

156 files changed

Lines changed: 19799 additions & 54 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.en.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to `ii` are documented here. The default Chinese version is [CHANGELOG.md](CHANGELOG.md).
44

5+
## 0.3.8 - 2026-08-08
6+
7+
### Added
8+
9+
- Added the `ii ftp [directory]` FTP server: it shares the current directory by default with active-only mode, anonymous login, 100 control connections, and all file operations enabled. It supports credentials, one shared rate limit, a connection limit, individual operation permissions, and active plus passive mode when `--passive-ports` is supplied.
10+
- Added required explicit FTPS with `ii ftp --tls` and legacy implicit FTPS with `--implicit`, which defaults to port `990`; both accept temporary self-signed certificates or PEM `--cert` and `--key` files.
11+
512
## 0.3.7 - 2026-08-07
613

714
### Added

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
本文件记录 `ii` 的重要变更。默认中文版本在这里,英文版本见 [CHANGELOG.en.md](CHANGELOG.en.md)
44

5+
## 0.3.8 - 2026-08-08
6+
7+
### 新增
8+
9+
- 新增 `ii ftp [目录]` FTP 服务端:默认共享当前目录、仅主动模式、匿名登录、100 个控制连接和完整文件操作权限;支持账号密码、共享总限速、连接上限、独立操作权限,以及显式 `--passive-ports` 后的主动加被动模式。
10+
- `ii ftp --tls` 新增强制显式 FTPS;`--implicit` 新增传统隐式 FTPS,默认端口 `990`;两者支持临时自签证书或 `--cert``--key` PEM 证书。
11+
512
## 0.3.7 - 2026-08-07
613

714
### 新增

Cargo.lock

Lines changed: 4 additions & 43 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
[workspace]
22
members = ["gui"]
3-
exclude = ["vendor/iroh", "vendor/suppaftp"]
3+
exclude = [
4+
"vendor/iroh",
5+
"vendor/suppaftp",
6+
"vendor/libunftp",
7+
"vendor/unftp-core",
8+
"vendor/unftp-sbe-fs",
9+
]
410
resolver = "3"
511

612
[workspace.package]
@@ -18,18 +24,21 @@ unused-async = "warn"
1824

1925
[package]
2026
name = "ii"
21-
version = "0.3.7"
27+
version = "0.3.8"
2228
edition.workspace = true
2329
rust-version.workspace = true
2430
license.workspace = true
2531

2632
[dependencies]
33+
async-trait = "0.1"
2734
anyhow = "1"
2835
attohttpc = { version = "0.31", default-features = false, features = ["tls-rustls-webpki-roots-ring"] }
2936
base64 = "0.22"
37+
bytes = "1"
3038
futures-util = "0.3"
3139
glob = "0.3.3"
3240
hmac = "0.12"
41+
libunftp = { path = "vendor/libunftp", default-features = false, features = ["ring"] }
3342
iroh = { path = "vendor/iroh/iroh", default-features = false, features = ["tls-ring", "unstable-net-report"] }
3443
iroh-relay = { path = "vendor/iroh/iroh-relay", default-features = false, features = ["server-minimal"] }
3544
md5 = { package = "md-5", version = "0.10" }
@@ -57,11 +66,11 @@ tokio-util = { version = "0.7", features = ["io"] }
5766
toml = "1.0"
5867
tracing = "0.1"
5968
url = { version = "2.5", features = ["serde"] }
69+
unftp-core = { path = "vendor/unftp-core" }
70+
unftp-sbe-fs = { path = "vendor/unftp-sbe-fs" }
6071

6172
[dev-dependencies]
62-
libunftp = { version = "0.23.0", default-features = false, features = ["ring"] }
6373
serde_json = "1"
64-
unftp-sbe-fs = "0.4.0"
6574

6675
[build-dependencies]
6776
winresource = "0.1"
@@ -74,6 +83,8 @@ panic = "abort"
7483
strip = true
7584

7685
[patch.crates-io]
86+
unftp-core = { path = "vendor/unftp-core" }
87+
unftp-sbe-fs = { path = "vendor/unftp-sbe-fs" }
7788
iroh-base = { path = "vendor/iroh/iroh-base" }
7889
iroh-dns = { path = "vendor/iroh/iroh-dns" }
7990
iroh-relay = { path = "vendor/iroh/iroh-relay" }

README.en.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
- Send files, folders, multiple paths, or piped data. Receives resume, skip matching MD5 files, and overwrite conflicts.
2525
- Compute local checksums, preserve single-file metadata, choose symlink behavior, and run FIFO queues or directory watches.
2626
- Use generic S3, Cloudflare R2, Azure Blob, WebDAV, FTP, or SFTP as optional backends, with cleanup after receiving.
27-
- It also provides LAN web sharing, WebDAV, browser transfer, TCP tunnels, and self-hosted relays.
27+
- It also provides LAN web sharing, WebDAV, an FTP server, browser transfer, TCP tunnels, and self-hosted relays.
2828

2929
## Common Use Cases
3030

@@ -52,6 +52,13 @@
5252
- Use one working directory as a shared asset drive for tablets, phones, and computers.
5353
- Provide a temporary delivery directory that clients or colleagues can access as a network drive without installing `ii`.
5454

55+
### `ii ftp`
56+
57+
- Temporarily share one directory with legacy devices, printers, NAS appliances, or tools that support FTP only.
58+
- Use active mode by default; explicitly configure a passive port range when clients need passive mode behind NAT.
59+
- Combine upload, download, delete, rename, and directory-creation permissions for a temporary file service.
60+
- Keep the default port 21 with explicit TLS for FTPS-capable legacy clients; use `--implicit` and port 990 only for clients that require implicit FTPS.
61+
5562
### `ii socks5`
5663

5764
- Provide a standard SOCKS5 proxy endpoint for browsers, downloaders, and command-line tools.
@@ -289,6 +296,33 @@ ii dav .\shared --port 8443 --username alice --password secret --tls --domain da
289296

290297
`ii web --once` exits only after the first complete ordinary-file `GET 200`. HEAD, Range, directory pages, 404 responses, and uploads do not consume the one-shot lifetime, and `--once` conflicts with `--upload`.
291298

299+
### FTP Server
300+
301+
```powershell
302+
# Share the current directory; listens on 0.0.0.0:21 by default
303+
ii ftp
304+
305+
# Select a directory, credentials, shared bandwidth, and connection limit
306+
ii ftp .\shared --port 2121 --username alice --password secret --rate 8MiB --max 20
307+
308+
# Explicitly enable active and passive modes; advertise this PASV address and port range
309+
ii ftp .\shared --passive-host 192.168.1.20 --passive-ports 49152-49200
310+
311+
# Disable individual operations
312+
ii ftp .\shared --upload false --delete false --rename false
313+
314+
# Explicit FTPS: TLS is required for both control and data channels; without files ii generates a temporary self-signed certificate
315+
ii ftp .\shared --tls
316+
ii ftp .\shared --tls --cert D:\certs\fullchain.pem --key D:\certs\privkey.pem
317+
318+
# Implicit FTPS: start TLS immediately after connecting; defaults to port 990
319+
ii ftp .\shared --tls --implicit
320+
```
321+
322+
`ii ftp` shares the current directory or an existing directory. It defaults to anonymous login, 100 control connections, no rate limit, and allows uploads, downloads, deletion, renames, and directory creation. By default it is active-only and creates no passive data listener. Supplying `--passive-ports [start-end]` enables active and passive modes together; without a range it uses `49152-65535`, and `--passive-host` requires it. `--rate` caps the total shared bandwidth of every upload and download connection. `--delete false` blocks both file and directory deletion, while `--download false` blocks only `RETR`; directory listings and metadata remain available. `0.0.0.0` is bind-only; the terminal prints the primary LAN IPv4 FTP URL and `other:` interface URLs.
323+
324+
`--tls` enables and requires FTPS. Its default is explicit mode: the client receives the plain FTP greeting and then sends `AUTH TLS`, and the default port remains 21. Without `--cert` and `--key`, `ii` generates a self-signed certificate for the current process and the client must accept it. Existing PEM certificate chains and private keys must be supplied together. `--implicit` requires `--tls`; it performs the TLS handshake immediately on connection and defaults to port 990 when `--port` is omitted. `--port 990` alone does not select implicit mode. `-k` is not an FTP server option.
325+
292326
### Lightweight LAN Services
293327

294328
```powershell

README.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
- 发送文件、目录、多文件和管道数据;接收支持断点续传、同 MD5 跳过和冲突覆盖。
2525
- 支持发送端校验和、单文件 metadata 保留、符号链接策略、FIFO 队列和目录监视。
2626
- 可选通用 S3、Cloudflare R2、Azure Blob、WebDAV、FTP、SFTP 中转;传完可删除中转对象。
27-
- 另有局域网网页、WebDAV、浏览器直传、TCP 隧道和自建 relay。
27+
- 另有局域网网页、WebDAV、FTP 服务、浏览器直传、TCP 隧道和自建 relay。
2828

2929
## 典型使用场景
3030

@@ -52,6 +52,13 @@
5252
- 作为跨设备素材盘,让平板、手机和电脑同时访问同一个工作目录。
5353
- 建立临时交付目录,客户或同事以网络盘方式取文件,不需要安装 `ii`
5454

55+
### `ii ftp`
56+
57+
- 在旧设备、打印机、NAS 或只支持 FTP 的工具之间临时共享一个目录。
58+
- 默认只开放主动模式;需要兼容手机、浏览器插件或 NAT 后客户端时,显式配置被动端口范围。
59+
- 按上传、下载、删除、改名和建目录权限组合成临时文件站。
60+
- 对支持 FTPS 的旧客户端,用显式 TLS 保持默认 `21` 端口;只有需要传统隐式 FTPS 的客户端才使用 `--implicit``990` 端口。
61+
5562
### `ii socks5`
5663

5764
- 给浏览器、下载器和命令行工具提供普通 SOCKS5 出口。
@@ -289,6 +296,33 @@ ii dav .\shared --port 8443 --username alice --password secret --tls --domain da
289296

290297
`ii web --once` 只在第一次完整的普通文件 `GET 200` 后退出;HEAD、Range、目录页、404 和上传不会消耗这次机会,且不能和 `--upload` 同用。
291298

299+
### FTP 服务
300+
301+
```powershell
302+
# 共享当前目录,默认监听 0.0.0.0:21
303+
ii ftp
304+
305+
# 指定目录、账号密码、总带宽和连接上限
306+
ii ftp .\shared --port 2121 --username alice --password secret --rate 8MiB --max 20
307+
308+
# 显式开启主动和被动模式;PASV 返回指定地址和端口范围
309+
ii ftp .\shared --passive-host 192.168.1.20 --passive-ports 49152-49200
310+
311+
# 关闭单项操作权限
312+
ii ftp .\shared --upload false --delete false --rename false
313+
314+
# 显式 FTPS:控制和数据通道均强制 TLS;未给证书时生成临时自签证书
315+
ii ftp .\shared --tls
316+
ii ftp .\shared --tls --cert D:\certs\fullchain.pem --key D:\certs\privkey.pem
317+
318+
# 隐式 FTPS:连接后立即 TLS 握手;未指定端口时使用 990
319+
ii ftp .\shared --tls --implicit
320+
```
321+
322+
`ii ftp` 共享当前目录或一个已有目录。默认匿名登录、最大 100 个控制连接、不限速,允许上传、下载、删除、改名和新建目录。默认仅主动模式,不监听被动数据端口;提供 `--passive-ports [start-end]` 后主动和被动模式同时可用,未给范围使用 `49152-65535``--passive-host` 只能与它同用。`--rate` 限制全部上传和下载连接共享的总带宽;`--delete false` 同时禁用文件和目录删除,`--download false` 只禁用 `RETR`,目录浏览和元数据查询仍可用。`0.0.0.0` 仅是监听地址,终端会输出主 LAN IPv4 FTP 地址和 `other:` 网卡地址。
323+
324+
`--tls` 开启并强制 FTPS:默认是显式模式,客户端在明文 FTP 欢迎语后发送 `AUTH TLS`,默认端口仍为 `21`。不提供 `--cert``--key` 时,服务只为当前进程生成自签证书,客户端需要自行接受该证书;已有 PEM 证书链和私钥时必须成对提供。`--implicit` 只能和 `--tls` 一起使用,客户端连接后立即进行 TLS 握手,未指定 `--port` 时使用 `990`。单独指定 `--port 990` 不会切换到隐式模式。`-k` 不是 FTP 服务端参数。
325+
292326
### 轻量局域网服务
293327

294328
```powershell

SIZE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ All measurements use `cargo build -p ii --release --locked` followed by UPX
3737
| Nine low-volume extensions: checksums, metadata, queue/watch, NAT probe, symlink policy, QUIC port, and `web --once` | 6,650,368 | 2,353,152 | -83,456 | `cargo test -p ii --locked` (146 tests), fmt check, diff check, `cargo bloat -p ii --release --crates -n 15`, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t` |
3838
| Path diagnostics, relay selection, resumable web upload, and SOCKS5 | 6,727,168 | 2,377,728 | +24,576 | `cargo test -p ii --locked` (157 tests), fmt check, diff check, `cargo bloat -p ii --release --crates -n 15`, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t` |
3939
| Twelve lightweight network services: HTTP/paste/drop/PAC/speed, proxy/forwarding, and diagnostics | 6,866,432 | 2,576,384 | +198,656 | `cargo test -p ii --locked` (172 tests), fmt check, diff check, packed CLI help smoke test, `cargo bloat -p ii --release --crates -n 15`, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t` |
40+
| FTP server: active mode, optional passive ports, authentication, permissions, connection limit, and shared rate limit | 7,567,872 | 2,606,080 | +29,696 | `cargo test -p ii --locked -- --test-threads=1` (181 tests), fmt check, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t`; local `cargo bloat -p ii --release --crates -n 20` exceeded 10 minutes without a report |
41+
| FTPS initial integration: explicit/implicit mode, self-signed or PEM certificate | 7,572,992 | 2,787,840 | +181,760 | `cargo test -p ii --locked -- --test-threads=1` (184 tests), fmt check, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t` |
42+
| FTPS vendor pruning: remove unused mTLS, session cache, certificate-file parser and TLS option APIs | 7,484,416 | 2,572,288 | -215,552 | `cargo test -p ii --locked -- --test-threads=1` (184 tests), fmt check, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t` |
43+
| FTPS final release after CLI future stack fix | 7,484,416 | 2,756,608 | +184,320 | `cargo fmt --all -- --check`, `git diff --check`, `cargo check -p ii --locked`, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t`; packed `ii.exe version` and `ftp --help` smoke-tested |
4044

4145
Equivalent release rebuilds have varied by up to `3,072` UPX bytes; the latest
4246
measurement is recorded with the pinned `5.1.0` packer.

0 commit comments

Comments
 (0)