sing-box/patches.md
Niko Marmeladkov a3404e463f
Some checks are pending
Build / Calculate version (push) Waiting to run
Build / Build binary (push) Blocked by required conditions
Build / Build Darwin binaries (push) Blocked by required conditions
Build / Build Windows binaries (push) Blocked by required conditions
Build / Build Android (push) Blocked by required conditions
Build / Publish Android (push) Blocked by required conditions
Build / Build Apple clients (push) Blocked by required conditions
Build / Upload builds (push) Blocked by required conditions
feat: add universal user_manager service for external auth & traffic tracking
- New UserManager service with HTTPS auth, credential sync, traffic tracking, and kick API
- Integrates into all 10 protocol inbounds (hysteria2, tuic, vless, vmess, trojan,
  shadowsocks, http, socks, mixed, naive)
- Each inbound auto-detects user_manager from service context, falls back to static config
- Auth server contract: POST /api/auth, GET /api/credentials, POST /api/traffic
2026-06-18 15:49:49 +03:00

3.7 KiB

Upstream Changes

UserManager — External Authentication & Traffic Tracking

A new user_manager service that turns sing-box into a universal proxy server for external auth servers.

New files

  • adapter/user_manager.goUserManager interface: Authenticate, GetCredentials, ReportTraffic, GetTraffic, ListTraffic, KickUser
  • option/user_manager.goUserManagerOptions: auth_server, cache_ttl, refresh_interval, report_interval, report_traffic, api_secret, api_listen, timeout
  • service/usermanager/manager.go — full implementation:
    • On-demand HTTPS auth (POST /api/auth) with in-memory TTL cache
    • Periodic credential sync (GET /api/credentials) populates per-protocol user lists
    • Per-user traffic counters (atomic.Int64) reported via POST /api/traffic
    • ConnectionTracker impl wrapping conns with byte counters (RoutedConnection/RoutedPacketConnection)
    • HTTP API on configurable api_listen:
      • GET /traffic — all users traffic
      • GET /traffic/{user} — single user
      • POST /kick/{user} — evict user from auth cache
    • Bearer token auth on all API endpoints via api_secret
  • service/usermanager/registry.go — service registration
  • include/usermanager.go — include build hook
  • constant/proxy.goTypeUserManager constant

Modified files — Protocol inbound integration

All 10 protocol inbounds detect the global user_manager from service context and use it when present:

Protocol Type Approach
hysteria2 Service-based service.UpdateUsers with password credentials, 30s refresh loop
tuic Service-based service.UpdateUsers with UUID+password (format "uuid:password"), 30s refresh loop
vless Service-based service.UpdateUsers with UUID credentials, 30s refresh loop
vmess Service-based service.UpdateUsers with UUID credentials, 30s refresh loop
trojan Service-based service.UpdateUsers with password credentials, 30s refresh loop
shadowsocks (multi) Service-based service.UpdateUsersWithPasswords with password credentials, 30s refresh loop
http Authenticator-based *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop
socks Authenticator-based *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop
mixed Authenticator-based *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop
naive Authenticator-based *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop; skips "missing users" check when user_manager is configured

Each inbound falls back to its original static config when no user_manager service is registered.

Credential format per protocol

Protocol UserInfo.Credential format
hysteria2 password
tuic uuid:password
vless uuid
vmess uuid
trojan password
shadowsocks password (method from static config)
http password (username from UserInfo.Username)
socks password (username from UserInfo.Username)
mixed password (username from UserInfo.Username)
naive password (username from UserInfo.Username)

Auth server API contract

The auth server (auth_server) must implement:

  • POST /api/auth — body {"protocol":"...", "credential":"...", "addr":"..."}, returns {"ok":true, "id":"username"}
  • GET /api/credentials — returns {"credentials":[{"protocol":"...", "credential":"...", "username":"..."}]}
  • POST /api/traffic (optional, when report_traffic=true) — body {"traffic":{"user1":{"tx":123,"rx":456}}}