Add per-device VPN and direct routing policies
Build and Deploy Gateway / build-and-push (push) Successful in 10s
Build and Deploy Gateway / deploy (push) Successful in 16s

This commit is contained in:
2026-08-07 16:18:31 +03:00
parent 307ad02cd7
commit 560c243047
20 changed files with 1090 additions and 114 deletions
+41
View File
@@ -6,6 +6,7 @@ import { createSingboxRuntime } from './singboxRuntime.js';
import { buildVersionInfo } from './version.js';
import { readNeighborSnapshot } from './adapters/neighbors.js';
import { createDeviceTrafficService } from './services/deviceTrafficService.js';
import { createDevicePolicyService } from './services/devicePolicyService.js';
const socketPath = settings.dataplaneSocket;
const runtime = createSingboxRuntime({
@@ -20,8 +21,40 @@ const traffic = createDeviceTrafficService({
downloadChain: settings.trafficDownloadChain,
bypassCidrs: settings.bypassCidrs,
});
const devicePolicy = createDevicePolicyService({
chain: settings.devicePolicyChain,
tproxyPort: settings.tproxyPort,
tproxyMark: settings.tproxyMark,
});
let ready = false;
let trafficTimer = null;
const MAX_POLICY_BODY_BYTES = 256 * 1024;
function readJson(req) {
return new Promise((resolve, reject) => {
const chunks = [];
let size = 0;
let tooLarge = false;
req.on('data', (chunk) => {
size += chunk.length;
if (!tooLarge && size > MAX_POLICY_BODY_BYTES) {
tooLarge = true;
reject(new Error('Device policy request слишком большой'));
return;
}
if (!tooLarge) chunks.push(chunk);
});
req.on('end', () => {
if (tooLarge) return;
try {
resolve(JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}'));
} catch {
reject(new Error('Device policy request содержит невалидный JSON'));
}
});
req.on('error', reject);
});
}
function sendJson(res, statusCode, payload) {
res.writeHead(statusCode, { 'content-type': 'application/json; charset=utf-8' });
@@ -35,6 +68,7 @@ const server = http.createServer(async (req, res) => {
...await runtime.refresh(),
gatewayBackendVersion: versionInfo.components.gatewayBackend,
singBoxVersion: versionInfo.runtime.singBox,
devicePolicy: devicePolicy.snapshot(),
ready,
});
}
@@ -44,6 +78,13 @@ const server = http.createServer(async (req, res) => {
if (req.method === 'GET' && req.url === '/device-traffic') {
return sendJson(res, 200, traffic.snapshot());
}
if (req.method === 'GET' && req.url === '/device-policy') {
return sendJson(res, 200, devicePolicy.snapshot());
}
if (req.method === 'PUT' && req.url === '/device-policy') {
const body = await readJson(req);
return sendJson(res, 200, await devicePolicy.apply(body.devices));
}
if (req.method === 'POST' && req.url === '/apply') {
return sendJson(res, 200, await runtime.apply());
}