feat(auth,client-registry): add Noise IK client authentication with managed client registry and per-client ACL controls
This commit is contained in:
@@ -44,7 +44,8 @@ IK is a 2-message handshake (same count as NK), so **the frame protocol stays id
|
||||
|
||||
## Core Interface: `IClientEntry`
|
||||
|
||||
This is the server-side client definition — the central config object:
|
||||
This is the server-side client definition — the central config object.
|
||||
Naming and structure are aligned with SmartProxy's `IRouteConfig` / `IRouteSecurity` patterns.
|
||||
|
||||
```typescript
|
||||
export interface IClientEntry {
|
||||
@@ -56,27 +57,16 @@ export interface IClientEntry {
|
||||
/** Client's WireGuard public key (base64) — for WireGuard transport */
|
||||
wgPublicKey?: string;
|
||||
|
||||
// ── Network ACLs ──────────────────────────────────────────────────────
|
||||
// ── Security (aligned with SmartProxy IRouteSecurity pattern) ─────────
|
||||
|
||||
/** Source IPs/CIDRs the client may connect FROM (empty = any) */
|
||||
allowedFrom?: string[];
|
||||
/** Destination IPs/CIDRs the client is allowed to reach (empty = all) */
|
||||
allowedTo?: string[];
|
||||
/** Blocklist: source IPs denied — overrides allowedFrom */
|
||||
notAllowedFrom?: string[];
|
||||
/** Blocklist: destination IPs denied — overrides allowedTo */
|
||||
notAllowedTo?: string[];
|
||||
security?: IClientSecurity;
|
||||
|
||||
// ── QoS ────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Rate limit in bytes/sec (omit = server default or unlimited) */
|
||||
rateLimitBytesPerSec?: number;
|
||||
/** Burst size in bytes */
|
||||
burstBytes?: number;
|
||||
/** Traffic priority (lower = higher priority, default: 100) */
|
||||
priority?: number;
|
||||
|
||||
// ── Metadata ───────────────────────────────────────────────────────────
|
||||
// ── Metadata (aligned with SmartProxy IRouteConfig pattern) ────────────
|
||||
|
||||
/** Whether this client is enabled (default: true) */
|
||||
enabled?: boolean;
|
||||
@@ -87,16 +77,57 @@ export interface IClientEntry {
|
||||
/** Optional expiry (ISO 8601 timestamp, omit = never expires) */
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Security settings per client — mirrors SmartProxy's IRouteSecurity structure.
|
||||
* Uses the same ipAllowList/ipBlockList naming convention.
|
||||
* Adds VPN-specific destination filtering (destinationAllowList/destinationBlockList).
|
||||
*/
|
||||
export interface IClientSecurity {
|
||||
/** Source IPs/CIDRs the client may connect FROM (empty = any).
|
||||
* Supports: exact IP, CIDR, wildcard (192.168.1.*), ranges (1.1.1.1-1.1.1.5).
|
||||
* Same format as SmartProxy's ipAllowList. */
|
||||
ipAllowList?: string[];
|
||||
/** Source IPs blocked — overrides ipAllowList (deny wins).
|
||||
* Same format as SmartProxy's ipBlockList. */
|
||||
ipBlockList?: string[];
|
||||
/** Destination IPs/CIDRs the client may reach through the VPN (empty = all) */
|
||||
destinationAllowList?: string[];
|
||||
/** Destination IPs blocked — overrides destinationAllowList (deny wins) */
|
||||
destinationBlockList?: string[];
|
||||
/** Max concurrent connections from this client */
|
||||
maxConnections?: number;
|
||||
/** Per-client rate limiting */
|
||||
rateLimit?: IClientRateLimit;
|
||||
}
|
||||
|
||||
export interface IClientRateLimit {
|
||||
/** Max throughput in bytes/sec */
|
||||
bytesPerSec: number;
|
||||
/** Burst allowance in bytes */
|
||||
burstBytes: number;
|
||||
}
|
||||
```
|
||||
|
||||
### SmartProxy Alignment Notes
|
||||
|
||||
| Pattern | SmartProxy | SmartVPN |
|
||||
|---------|-----------|---------|
|
||||
| ACL naming | `ipAllowList` / `ipBlockList` | Same — `ipAllowList` / `ipBlockList` |
|
||||
| Security grouping | `security: IRouteSecurity` sub-object | Same — `security: IClientSecurity` sub-object |
|
||||
| Rate limit structure | `rateLimit: IRouteRateLimit` object | Same pattern — `rateLimit: IClientRateLimit` object |
|
||||
| IP format support | Exact, CIDR, wildcard, ranges | Same formats |
|
||||
| Metadata fields | `priority`, `tags`, `enabled`, `description` | Same fields |
|
||||
| ACL evaluation | Block-first, then allow-list | Same — deny overrides allow |
|
||||
|
||||
### ACL Evaluation Order
|
||||
|
||||
```
|
||||
1. Check notAllowedFrom / notAllowedTo first (explicit deny wins)
|
||||
1. Check ipBlockList / destinationBlockList first (explicit deny wins)
|
||||
2. If denied, DROP
|
||||
3. Check allowedFrom / allowedTo (explicit allow)
|
||||
4. If allowedFrom is empty → allow any source
|
||||
5. If allowedTo is empty → allow all destinations
|
||||
3. Check ipAllowList / destinationAllowList (explicit allow)
|
||||
4. If ipAllowList is empty → allow any source
|
||||
5. If destinationAllowList is empty → allow all destinations
|
||||
```
|
||||
|
||||
---
|
||||
@@ -241,12 +272,7 @@ pub struct ClientEntry {
|
||||
pub client_id: String,
|
||||
pub public_key: String,
|
||||
pub wg_public_key: Option<String>,
|
||||
pub allowed_from: Option<Vec<String>>,
|
||||
pub allowed_to: Option<Vec<String>>,
|
||||
pub not_allowed_from: Option<Vec<String>>,
|
||||
pub not_allowed_to: Option<Vec<String>>,
|
||||
pub rate_limit_bytes_per_sec: Option<u64>,
|
||||
pub burst_bytes: Option<u64>,
|
||||
pub security: Option<ClientSecurity>,
|
||||
pub priority: Option<u32>,
|
||||
pub enabled: Option<bool>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
@@ -255,6 +281,21 @@ pub struct ClientEntry {
|
||||
pub assigned_ip: Option<String>,
|
||||
}
|
||||
|
||||
/// Mirrors IClientSecurity — aligned with SmartProxy's IRouteSecurity
|
||||
pub struct ClientSecurity {
|
||||
pub ip_allow_list: Option<Vec<String>>,
|
||||
pub ip_block_list: Option<Vec<String>>,
|
||||
pub destination_allow_list: Option<Vec<String>>,
|
||||
pub destination_block_list: Option<Vec<String>>,
|
||||
pub max_connections: Option<u32>,
|
||||
pub rate_limit: Option<ClientRateLimit>,
|
||||
}
|
||||
|
||||
pub struct ClientRateLimit {
|
||||
pub bytes_per_sec: u64,
|
||||
pub burst_bytes: u64,
|
||||
}
|
||||
|
||||
pub struct ClientRegistry {
|
||||
entries: HashMap<String, ClientEntry>, // keyed by clientId
|
||||
key_index: HashMap<String, String>, // publicKey → clientId (fast lookup)
|
||||
@@ -269,9 +310,10 @@ Methods: `add`, `remove`, `get_by_id`, `get_by_key`, `update`, `list`, `is_autho
|
||||
**Modify: `rust/src/lib.rs`** — add `pub mod acl;`
|
||||
|
||||
```rust
|
||||
pub fn check_acl(entry: &ClientEntry, src_ip: Ipv4Addr, dst_ip: Ipv4Addr) -> AclResult {
|
||||
// 1. Check notAllowedFrom/notAllowedTo (deny overrides)
|
||||
// 2. Check allowedFrom/allowedTo (explicit allow)
|
||||
/// IP matching supports: exact, CIDR, wildcard, ranges — same as SmartProxy's IpMatcher
|
||||
pub fn check_acl(security: &ClientSecurity, src_ip: Ipv4Addr, dst_ip: Ipv4Addr) -> AclResult {
|
||||
// 1. Check ip_block_list / destination_block_list (deny overrides)
|
||||
// 2. Check ip_allow_list / destination_allow_list (explicit allow)
|
||||
// 3. Empty list = allow all
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user