Improve VPN client connection management
This commit is contained in:
@@ -9,11 +9,46 @@ import { deviceId } from '../../dist/server/services/deviceInventoryService.js';
|
||||
const mac = '00:11:22:33:44:55';
|
||||
const id = deviceId(mac);
|
||||
const device = { ip: '192.168.50.7', mac };
|
||||
const connection = (connectionId, type, host, upload, download, sourceIP = device.ip) => ({
|
||||
const connection = (connectionId, type, host, upload, download, sourceIP = device.ip, chains = ['vpn-out']) => ({
|
||||
id: connectionId,
|
||||
metadata: { type, host, sourceIP },
|
||||
upload,
|
||||
download,
|
||||
chains,
|
||||
});
|
||||
|
||||
test('sing-box route traffic keeps vpn, direct and unknown deltas separate', async () => {
|
||||
let response = { connections: [
|
||||
connection('direct', 'tproxy/tproxy-in', 'one.example', 10, 100, device.ip, ['direct']),
|
||||
connection('vpn', 'tproxy/tproxy-in', 'two.example', 20, 200),
|
||||
connection('unknown', 'tproxy/tproxy-in', 'three.example', 30, 300, device.ip, []),
|
||||
connection('unmapped', 'tproxy/tproxy-in', 'four.example', 40, 400, '192.168.50.99'),
|
||||
] };
|
||||
const service = createDomainTrafficService({
|
||||
observe: async () => response,
|
||||
devices: () => [device],
|
||||
});
|
||||
|
||||
await service.refresh();
|
||||
response = { connections: [
|
||||
connection('direct', 'tproxy/tproxy-in', 'one.example', 15, 110, device.ip, ['direct']),
|
||||
connection('vpn', 'tproxy/tproxy-in', 'two.example', 25, 220, device.ip, ['direct']),
|
||||
connection('unknown', 'tproxy/tproxy-in', 'three.example', 35, 330, device.ip, [null]),
|
||||
connection('unmapped', 'tproxy/tproxy-in', 'four.example', 50, 500, '192.168.50.99'),
|
||||
] };
|
||||
await service.refresh();
|
||||
await service.refresh();
|
||||
|
||||
assert.deepEqual(service.snapshot().routes, [
|
||||
{ deviceId: id, source: 'gateway', outbound: 'direct', uploadBytes: '20', downloadBytes: '130' },
|
||||
{ deviceId: id, source: 'gateway', outbound: 'unknown', uploadBytes: '35', downloadBytes: '330' },
|
||||
{ deviceId: id, source: 'gateway', outbound: 'vpn', uploadBytes: '20', downloadBytes: '200' },
|
||||
]);
|
||||
assert.deepEqual(service.snapshot().tracked, [
|
||||
{ source: 'gateway', outbound: 'direct', uploadBytes: '20', downloadBytes: '130' },
|
||||
{ source: 'gateway', outbound: 'unknown', uploadBytes: '35', downloadBytes: '330' },
|
||||
{ source: 'gateway', outbound: 'vpn', uploadBytes: '70', downloadBytes: '700' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('domain traffic accumulates connection deltas by device, service and source', async () => {
|
||||
@@ -142,6 +177,28 @@ test('domain traffic is bounded and keeps the last good snapshot on source failu
|
||||
assert.equal(service.snapshot().source.error, 'Clash API unavailable');
|
||||
});
|
||||
|
||||
test('an invalid connection rejects the whole snapshot without double-counting a retry', async () => {
|
||||
let response = { connections: [
|
||||
connection('valid', 'tproxy/tproxy-in', 'one.example', 10, 100),
|
||||
{ id: 'invalid', upload: -1, download: 0, metadata: {} },
|
||||
] };
|
||||
const service = createDomainTrafficService({
|
||||
observe: async () => response,
|
||||
devices: () => [device],
|
||||
});
|
||||
|
||||
await assert.rejects(service.refresh(), /невалидный domain traffic counter/);
|
||||
assert.deepEqual(service.snapshot().tracked, []);
|
||||
assert.deepEqual(service.snapshot().routes, []);
|
||||
assert.deepEqual(service.snapshot().series, []);
|
||||
|
||||
response = { connections: [connection('valid', 'tproxy/tproxy-in', 'one.example', 10, 100)] };
|
||||
await service.refresh();
|
||||
assert.equal(service.snapshot().tracked[0].downloadBytes, '100');
|
||||
assert.equal(service.snapshot().routes[0].downloadBytes, '100');
|
||||
assert.equal(service.snapshot().series[0].downloadBytes, '100');
|
||||
});
|
||||
|
||||
test('domain classification normalizes known services and rejects IP or malformed labels', () => {
|
||||
assert.deepEqual(classifyDomain('WWW.YouTube.com.'), { domain: 'youtube.com', service: 'YouTube' });
|
||||
assert.deepEqual(classifyDomain('api.example.org'), { domain: 'api.example.org', service: 'api.example.org' });
|
||||
|
||||
Reference in New Issue
Block a user