|
|
|
|
@@ -77,10 +77,13 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
|
|
### 🔐 VPN Access Control (powered by [smartvpn](https://code.foss.global/push.rocks/smartvpn))
|
|
|
|
|
- **WireGuard + native transports** — standard WireGuard clients (iOS, Android, macOS, Windows, Linux) plus custom WebSocket/QUIC tunnels
|
|
|
|
|
- **Route-level VPN gating** — mark any route with `vpn: { required: true }` to restrict access to VPN clients only
|
|
|
|
|
- **Rootless operation** — auto-detects privileges: kernel TUN when running as root, userspace NAT (smoltcp) when not
|
|
|
|
|
- **Client management** — create, enable, disable, rotate keys, export WireGuard `.conf` files via OpsServer API
|
|
|
|
|
- **Tag-based access control** — assign `serverDefinedClientTags` to clients and restrict routes with `allowedServerDefinedClientTags`
|
|
|
|
|
- **Constructor-defined clients** — pre-define VPN clients with tags in config for declarative, code-driven setup
|
|
|
|
|
- **Rootless operation** — uses userspace NAT (smoltcp) with no root required
|
|
|
|
|
- **Destination policy** — configurable `forceTarget`, `block`, or `allow` with allowList/blockList for granular traffic control
|
|
|
|
|
- **Client management** — create, enable, disable, rotate keys, export WireGuard/SmartVPN configs via OpsServer API and dashboard
|
|
|
|
|
- **IP-based enforcement** — VPN clients get IPs from a configurable subnet; SmartProxy enforces `ipAllowList` per route
|
|
|
|
|
- **PROXY protocol v2** — in socket mode, the NAT engine sends PP v2 on outbound connections to preserve VPN client identity
|
|
|
|
|
- **PROXY protocol v2** — the NAT engine sends PP v2 on outbound connections to preserve VPN client identity
|
|
|
|
|
|
|
|
|
|
### ⚡ High Performance
|
|
|
|
|
- **Rust-powered proxy engine** via SmartProxy for maximum throughput
|
|
|
|
|
@@ -261,7 +264,9 @@ const router = new DcRouter({
|
|
|
|
|
vpnConfig: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
serverEndpoint: 'vpn.example.com',
|
|
|
|
|
wgListenPort: 51820,
|
|
|
|
|
clients: [
|
|
|
|
|
{ clientId: 'dev-laptop', serverDefinedClientTags: ['engineering'] },
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Persistent storage
|
|
|
|
|
@@ -456,7 +461,17 @@ interface IDcRouterOptions {
|
|
|
|
|
wgListenPort?: number; // default: 51820
|
|
|
|
|
dns?: string[]; // DNS servers pushed to VPN clients
|
|
|
|
|
serverEndpoint?: string; // Hostname in generated client configs
|
|
|
|
|
forwardingMode?: 'tun' | 'socket'; // default: auto-detect (root → tun, else socket)
|
|
|
|
|
clients?: Array<{ // Pre-defined VPN clients
|
|
|
|
|
clientId: string;
|
|
|
|
|
serverDefinedClientTags?: string[];
|
|
|
|
|
description?: string;
|
|
|
|
|
}>;
|
|
|
|
|
destinationPolicy?: { // Traffic routing policy
|
|
|
|
|
default: 'forceTarget' | 'block' | 'allow';
|
|
|
|
|
target?: string; // IP for forceTarget (default: '127.0.0.1')
|
|
|
|
|
allowList?: string[]; // Pass through directly
|
|
|
|
|
blockList?: string[]; // Always block (overrides allowList)
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ── HTTP/3 (QUIC) ────────────────────────────────────────────
|
|
|
|
|
@@ -1014,17 +1029,33 @@ DcRouter integrates [`@push.rocks/smartvpn`](https://code.foss.global/push.rocks
|
|
|
|
|
|
|
|
|
|
1. **SmartVPN daemon** runs inside dcrouter with a Rust data plane (WireGuard via `boringtun`, custom protocol via Noise IK)
|
|
|
|
|
2. Clients connect and get assigned an IP from the VPN subnet (e.g. `10.8.0.0/24`)
|
|
|
|
|
3. Routes with `vpn: { required: true }` get `security.ipAllowList` automatically injected with the VPN subnet
|
|
|
|
|
4. SmartProxy enforces the allowlist — only VPN-sourced traffic is accepted on those routes
|
|
|
|
|
3. Routes with `vpn: { required: true }` get `security.ipAllowList` automatically injected
|
|
|
|
|
4. When `allowedServerDefinedClientTags` is set, only matching client IPs are injected (not the whole subnet)
|
|
|
|
|
5. SmartProxy enforces the allowlist — only authorized VPN clients can access protected routes
|
|
|
|
|
6. All VPN traffic is forced through SmartProxy via userspace NAT with PROXY protocol v2 — no root required
|
|
|
|
|
|
|
|
|
|
### Two Operating Modes
|
|
|
|
|
### Destination Policy
|
|
|
|
|
|
|
|
|
|
| Mode | Root Required? | How It Works |
|
|
|
|
|
|------|---------------|-------------|
|
|
|
|
|
| **TUN** (`forwardingMode: 'tun'`) | Yes | Kernel TUN device — VPN traffic enters the network stack with real VPN IPs |
|
|
|
|
|
| **Socket** (`forwardingMode: 'socket'`) | No | Userspace NAT via smoltcp — outbound connections send PROXY protocol v2 to preserve VPN client IPs |
|
|
|
|
|
By default, VPN client traffic is redirected to localhost (SmartProxy) via `forceTarget`. You can customize this with a destination policy:
|
|
|
|
|
|
|
|
|
|
DcRouter auto-detects: if running as root, it uses TUN mode; otherwise, it falls back to socket mode. You can override this with the `forwardingMode` option.
|
|
|
|
|
```typescript
|
|
|
|
|
// Default: all traffic → SmartProxy
|
|
|
|
|
destinationPolicy: { default: 'forceTarget', target: '127.0.0.1' }
|
|
|
|
|
|
|
|
|
|
// Allow direct access to a backend subnet
|
|
|
|
|
destinationPolicy: {
|
|
|
|
|
default: 'forceTarget',
|
|
|
|
|
target: '127.0.0.1',
|
|
|
|
|
allowList: ['192.168.190.*'], // direct access to this subnet
|
|
|
|
|
blockList: ['192.168.190.1'], // except the gateway
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Block everything except specific IPs
|
|
|
|
|
destinationPolicy: {
|
|
|
|
|
default: 'block',
|
|
|
|
|
allowList: ['10.0.0.*', '192.168.1.*'],
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Configuration
|
|
|
|
|
|
|
|
|
|
@@ -1032,26 +1063,47 @@ DcRouter auto-detects: if running as root, it uses TUN mode; otherwise, it falls
|
|
|
|
|
const router = new DcRouter({
|
|
|
|
|
vpnConfig: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
subnet: '10.8.0.0/24', // VPN client IP pool (default)
|
|
|
|
|
wgListenPort: 51820, // WireGuard UDP port (default)
|
|
|
|
|
subnet: '10.8.0.0/24', // VPN client IP pool (default)
|
|
|
|
|
wgListenPort: 51820, // WireGuard UDP port (default)
|
|
|
|
|
serverEndpoint: 'vpn.example.com', // Hostname in generated client configs
|
|
|
|
|
dns: ['1.1.1.1', '8.8.8.8'], // DNS servers pushed to clients
|
|
|
|
|
// forwardingMode: 'socket', // Override auto-detection
|
|
|
|
|
dns: ['1.1.1.1', '8.8.8.8'], // DNS servers pushed to clients
|
|
|
|
|
|
|
|
|
|
// Pre-define VPN clients with server-defined tags
|
|
|
|
|
clients: [
|
|
|
|
|
{ clientId: 'alice-laptop', serverDefinedClientTags: ['engineering'], description: 'Dev laptop' },
|
|
|
|
|
{ clientId: 'bob-phone', serverDefinedClientTags: ['engineering', 'mobile'] },
|
|
|
|
|
{ clientId: 'carol-desktop', serverDefinedClientTags: ['finance'] },
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// Optional: customize destination policy (default: forceTarget → localhost)
|
|
|
|
|
// destinationPolicy: { default: 'forceTarget', target: '127.0.0.1', allowList: ['192.168.1.*'] },
|
|
|
|
|
},
|
|
|
|
|
smartProxyConfig: {
|
|
|
|
|
routes: [
|
|
|
|
|
// This route is VPN-only — non-VPN clients are blocked
|
|
|
|
|
// 🔐 VPN-only: any VPN client can access
|
|
|
|
|
{
|
|
|
|
|
name: 'admin-panel',
|
|
|
|
|
match: { domains: ['admin.example.com'], ports: [443] },
|
|
|
|
|
name: 'internal-app',
|
|
|
|
|
match: { domains: ['internal.example.com'], ports: [443] },
|
|
|
|
|
action: {
|
|
|
|
|
type: 'forward',
|
|
|
|
|
targets: [{ host: '192.168.1.50', port: 8080 }],
|
|
|
|
|
tls: { mode: 'terminate', certificate: 'auto' },
|
|
|
|
|
},
|
|
|
|
|
vpn: { required: true }, // 🔐 Only VPN clients can access this
|
|
|
|
|
vpn: { required: true },
|
|
|
|
|
},
|
|
|
|
|
// This route is public — anyone can access it
|
|
|
|
|
// 🔐 VPN + tag-restricted: only 'engineering' tagged clients
|
|
|
|
|
{
|
|
|
|
|
name: 'eng-dashboard',
|
|
|
|
|
match: { domains: ['eng.example.com'], ports: [443] },
|
|
|
|
|
action: {
|
|
|
|
|
type: 'forward',
|
|
|
|
|
targets: [{ host: '192.168.1.51', port: 8080 }],
|
|
|
|
|
tls: { mode: 'terminate', certificate: 'auto' },
|
|
|
|
|
},
|
|
|
|
|
vpn: { required: true, allowedServerDefinedClientTags: ['engineering'] },
|
|
|
|
|
// → alice + bob can access, carol cannot
|
|
|
|
|
},
|
|
|
|
|
// 🌐 Public: no VPN required
|
|
|
|
|
{
|
|
|
|
|
name: 'public-site',
|
|
|
|
|
match: { domains: ['example.com'], ports: [443] },
|
|
|
|
|
@@ -1066,17 +1118,29 @@ const router = new DcRouter({
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Client Management via OpsServer API
|
|
|
|
|
### Client Tags
|
|
|
|
|
|
|
|
|
|
Once the VPN server is running, you can manage clients through the OpsServer dashboard or API:
|
|
|
|
|
SmartVPN distinguishes between two types of client tags:
|
|
|
|
|
|
|
|
|
|
| Tag Type | Set By | Purpose |
|
|
|
|
|
|----------|--------|---------|
|
|
|
|
|
| `serverDefinedClientTags` | Admin (via config or API) | **Trusted** — used for route access control |
|
|
|
|
|
| `clientDefinedClientTags` | Connecting client | **Informational** — displayed in dashboard, never used for security |
|
|
|
|
|
|
|
|
|
|
Routes with `allowedServerDefinedClientTags` only permit VPN clients whose admin-assigned tags match. Clients cannot influence their own server-defined tags.
|
|
|
|
|
|
|
|
|
|
### Client Management via OpsServer
|
|
|
|
|
|
|
|
|
|
The OpsServer dashboard and API provide full VPN client lifecycle management:
|
|
|
|
|
|
|
|
|
|
- **Create client** — generates WireGuard keypairs, assigns IP, returns a ready-to-use `.conf` file
|
|
|
|
|
- **Enable / Disable** — toggle client access without deleting
|
|
|
|
|
- **Rotate keys** — generate fresh keypairs (invalidates old ones)
|
|
|
|
|
- **Export config** — re-export in WireGuard or SmartVPN format
|
|
|
|
|
- **Export config** — download in WireGuard (`.conf`) or SmartVPN (`.json`) format
|
|
|
|
|
- **Telemetry** — per-client bytes sent/received, keepalives, rate limiting
|
|
|
|
|
- **Delete** — remove a client and revoke access
|
|
|
|
|
|
|
|
|
|
Standard WireGuard clients on any platform (iOS, Android, macOS, Windows, Linux) can connect using the generated `.conf` file or QR code — no custom VPN software needed.
|
|
|
|
|
Standard WireGuard clients on any platform (iOS, Android, macOS, Windows, Linux) can connect using the generated `.conf` file — no custom VPN software needed.
|
|
|
|
|
|
|
|
|
|
## Certificate Management
|
|
|
|
|
|
|
|
|
|
|