Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cfb727b86d | |||
| 1e4b9997f4 | |||
| bb32f23d77 | |||
| 1aa6451dba |
12
changelog.md
12
changelog.md
@@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-03-31 - 11.21.5 - fix(routing)
|
||||
apply VPN route allowlists dynamically after VPN clients load
|
||||
|
||||
- Moves VPN security injection for hardcoded and programmatic routes into RouteConfigManager.applyRoutes() so allowlists are generated from current VPN client state.
|
||||
- Re-applies routes after starting the VPN manager to ensure tag-based ipAllowLists are available once VPN clients are loaded.
|
||||
- Avoids caching constructor routes with stale VPN security baked in while preserving HTTP/3 route augmentation.
|
||||
|
||||
## 2026-03-31 - 11.21.4 - fix(deps)
|
||||
bump @push.rocks/smartvpn to 1.16.4
|
||||
|
||||
- Updates the @push.rocks/smartvpn dependency from 1.16.3 to 1.16.4 in package.json.
|
||||
|
||||
## 2026-03-31 - 11.21.3 - fix(deps)
|
||||
bump @push.rocks/smartvpn to 1.16.3
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@serve.zone/dcrouter",
|
||||
"private": false,
|
||||
"version": "11.21.3",
|
||||
"version": "11.21.5",
|
||||
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
@@ -59,7 +59,7 @@
|
||||
"@push.rocks/smartrx": "^3.0.10",
|
||||
"@push.rocks/smartstate": "^2.3.0",
|
||||
"@push.rocks/smartunique": "^3.0.9",
|
||||
"@push.rocks/smartvpn": "1.16.3",
|
||||
"@push.rocks/smartvpn": "1.16.4",
|
||||
"@push.rocks/taskbuffer": "^8.0.2",
|
||||
"@serve.zone/catalog": "^2.9.0",
|
||||
"@serve.zone/interfaces": "^5.3.0",
|
||||
|
||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -96,8 +96,8 @@ importers:
|
||||
specifier: ^3.0.9
|
||||
version: 3.0.9
|
||||
'@push.rocks/smartvpn':
|
||||
specifier: 1.16.3
|
||||
version: 1.16.3
|
||||
specifier: 1.16.4
|
||||
version: 1.16.4
|
||||
'@push.rocks/taskbuffer':
|
||||
specifier: ^8.0.2
|
||||
version: 8.0.2
|
||||
@@ -1339,8 +1339,8 @@ packages:
|
||||
'@push.rocks/smartversion@3.0.5':
|
||||
resolution: {integrity: sha512-8MZSo1yqyaKxKq0Q5N188l4un++9GFWVbhCAX5mXJwewZHn97ujffTeL+eOQYpWFTEpUhaq1QhL4NhqObBCt1Q==}
|
||||
|
||||
'@push.rocks/smartvpn@1.16.3':
|
||||
resolution: {integrity: sha512-VxUCSutiLU0I+AWohogl/6ncoriJ9umoX1kHLeEwqg9YRN0n0Mg0mpnQ9ZX8jYt3y9pUH34GxmZVGRHyjQoWyw==}
|
||||
'@push.rocks/smartvpn@1.16.4':
|
||||
resolution: {integrity: sha512-ps7NcdBzaaGQFjHcXUN8JC623xZbLNyIYfICxDLJb2BxzzuZa667fW0KxQQCwLtZaB2txN5sMlaOKFi27tXTBA==}
|
||||
|
||||
'@push.rocks/smartwatch@6.4.0':
|
||||
resolution: {integrity: sha512-KDswRgE/siBmZRCsRA07MtW5oF4c9uQEBkwTGPIWneHzksbCDsvs/7agKFEL7WnNifLNwo8w1K1qoiVWkX1fvw==}
|
||||
@@ -6622,7 +6622,7 @@ snapshots:
|
||||
'@types/semver': 7.7.1
|
||||
semver: 7.7.4
|
||||
|
||||
'@push.rocks/smartvpn@1.16.3':
|
||||
'@push.rocks/smartvpn@1.16.4':
|
||||
dependencies:
|
||||
'@push.rocks/smartnftables': 1.1.0
|
||||
'@push.rocks/smartpath': 6.0.0
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '11.21.3',
|
||||
version: '11.21.5',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
@@ -813,12 +813,8 @@ export class DcRouter {
|
||||
logger.log('info', 'HTTP/3: Augmented qualifying HTTPS routes with QUIC/H3 configuration');
|
||||
}
|
||||
|
||||
// VPN route security injection: restrict vpn.required routes to VPN subnet
|
||||
if (this.options.vpnConfig?.enabled) {
|
||||
routes = this.injectVpnSecurity(routes);
|
||||
}
|
||||
|
||||
// Cache constructor routes for RouteConfigManager
|
||||
// Cache constructor routes for RouteConfigManager (without VPN security baked in —
|
||||
// applyRoutes() injects VPN security dynamically so it stays current with client changes)
|
||||
this.constructorRoutes = [...routes];
|
||||
|
||||
// If we have routes or need a basic SmartProxy instance, create it
|
||||
@@ -2142,6 +2138,11 @@ export class DcRouter {
|
||||
});
|
||||
|
||||
await this.vpnManager.start();
|
||||
|
||||
// Re-apply routes now that VPN clients are loaded — ensures hardcoded routes
|
||||
// get correct tag-based ipAllowLists (not possible during setupSmartProxy since
|
||||
// VPN server wasn't ready yet)
|
||||
this.routeConfigManager?.applyRoutes();
|
||||
}
|
||||
|
||||
/** Cache for DNS-resolved IPs of VPN-gated domains. TTL: 5 minutes. */
|
||||
@@ -2166,48 +2167,8 @@ export class DcRouter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject VPN security into routes that have vpn.required === true.
|
||||
* Adds the VPN subnet to security.ipAllowList so only VPN clients can access them.
|
||||
*/
|
||||
private injectVpnSecurity(routes: plugins.smartproxy.IRouteConfig[]): plugins.smartproxy.IRouteConfig[] {
|
||||
const vpnSubnet = this.options.vpnConfig?.subnet || '10.8.0.0/24';
|
||||
let injectedCount = 0;
|
||||
|
||||
const result = routes.map((route) => {
|
||||
const dcrouterRoute = route as import('../ts_interfaces/data/remoteingress.js').IDcRouterRouteConfig;
|
||||
if (dcrouterRoute.vpn?.required) {
|
||||
injectedCount++;
|
||||
const existing = route.security?.ipAllowList || [];
|
||||
|
||||
let vpnAllowList: string[];
|
||||
if (dcrouterRoute.vpn.allowedServerDefinedClientTags?.length && this.vpnManager) {
|
||||
// Tag-based: only specific client IPs
|
||||
vpnAllowList = this.vpnManager.getClientIpsForServerDefinedTags(
|
||||
dcrouterRoute.vpn.allowedServerDefinedClientTags,
|
||||
);
|
||||
} else {
|
||||
// No tags specified: entire VPN subnet
|
||||
vpnAllowList = [vpnSubnet];
|
||||
}
|
||||
|
||||
return {
|
||||
...route,
|
||||
security: {
|
||||
...route.security,
|
||||
ipAllowList: [...existing, ...vpnAllowList],
|
||||
},
|
||||
};
|
||||
}
|
||||
return route;
|
||||
});
|
||||
|
||||
if (injectedCount > 0) {
|
||||
logger.log('info', `VPN: Injected ipAllowList into ${injectedCount} VPN-protected route(s)`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
// VPN security injection is now handled dynamically by RouteConfigManager.applyRoutes()
|
||||
// via the getVpnAllowList callback — no longer a separate method here.
|
||||
|
||||
/**
|
||||
* Set up RADIUS server for network authentication
|
||||
|
||||
@@ -252,41 +252,42 @@ export class RouteConfigManager {
|
||||
|
||||
const enabledRoutes: plugins.smartproxy.IRouteConfig[] = [];
|
||||
|
||||
// Add enabled hardcoded routes (respecting overrides)
|
||||
const http3Config = this.getHttp3Config?.();
|
||||
const vpnAllowList = this.getVpnAllowList;
|
||||
|
||||
// Helper: inject VPN security into a route if vpn.required is set
|
||||
const injectVpn = (route: plugins.smartproxy.IRouteConfig): plugins.smartproxy.IRouteConfig => {
|
||||
if (!vpnAllowList) return route;
|
||||
const dcRoute = route as IDcRouterRouteConfig;
|
||||
if (!dcRoute.vpn?.required) return route;
|
||||
const allowList = vpnAllowList(dcRoute.vpn.allowedServerDefinedClientTags);
|
||||
return {
|
||||
...route,
|
||||
security: {
|
||||
...route.security,
|
||||
ipAllowList: [...(route.security?.ipAllowList || []), ...allowList],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// Add enabled hardcoded routes (respecting overrides, with fresh VPN injection)
|
||||
for (const route of this.getHardcodedRoutes()) {
|
||||
const name = route.name || '';
|
||||
const override = this.overrides.get(name);
|
||||
if (override && !override.enabled) {
|
||||
continue; // Skip disabled hardcoded route
|
||||
}
|
||||
enabledRoutes.push(route);
|
||||
enabledRoutes.push(injectVpn(route));
|
||||
}
|
||||
|
||||
// Add enabled programmatic routes (with HTTP/3 and VPN augmentation)
|
||||
const http3Config = this.getHttp3Config?.();
|
||||
const vpnAllowList = this.getVpnAllowList;
|
||||
for (const stored of this.storedRoutes.values()) {
|
||||
if (stored.enabled) {
|
||||
let route = stored.route;
|
||||
if (http3Config && http3Config.enabled !== false) {
|
||||
route = augmentRouteWithHttp3(route, { enabled: true, ...http3Config });
|
||||
}
|
||||
// Inject VPN security for programmatic routes with vpn.required
|
||||
if (vpnAllowList) {
|
||||
const dcRoute = route as IDcRouterRouteConfig;
|
||||
if (dcRoute.vpn?.required) {
|
||||
const existing = route.security?.ipAllowList || [];
|
||||
const allowList = vpnAllowList(dcRoute.vpn.allowedServerDefinedClientTags);
|
||||
route = {
|
||||
...route,
|
||||
security: {
|
||||
...route.security,
|
||||
ipAllowList: [...existing, ...allowList],
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
enabledRoutes.push(route);
|
||||
enabledRoutes.push(injectVpn(route));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '11.21.3',
|
||||
version: '11.21.5',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user