Add native traffic inspection to Harbor Connect and Gateway
This commit is contained in:
@@ -16,6 +16,40 @@ const connection = (connectionId, type, host, upload, download, sourceIP = devic
|
||||
download,
|
||||
chains,
|
||||
});
|
||||
const nativeConnection = (connectionId, uploadBytes, downloadBytes, overrides = {}) => ({
|
||||
id: connectionId,
|
||||
startedAt: '2026-08-31T10:00:00.000Z',
|
||||
closedAt: null,
|
||||
inbound: { tag: 'tproxy-in', type: 'tproxy' },
|
||||
network: 'tcp',
|
||||
protocol: 'tls',
|
||||
source: { ip: device.ip, port: 54_000 },
|
||||
destination: { domain: 'example.com', ip: null, port: 443, provenance: 'sing-box' },
|
||||
origin: { kind: 'device', id, label: 'MacBook', provenance: 'source-ip' },
|
||||
route: {
|
||||
kind: 'vpn',
|
||||
scope: 'local-sing-box',
|
||||
outbound: 'channel-selector',
|
||||
outboundType: 'selector',
|
||||
chain: ['channel-primary', 'channel-selector'],
|
||||
rule: 'final',
|
||||
},
|
||||
traffic: {
|
||||
uploadBytes,
|
||||
downloadBytes,
|
||||
uploadBytesPerSecond: '0',
|
||||
downloadBytesPerSecond: '0',
|
||||
},
|
||||
...overrides,
|
||||
});
|
||||
const nativeBatch = (connections, overrides = {}) => ({
|
||||
epoch: 'sing-box-100',
|
||||
observedAt: '2026-08-31T10:00:00.000Z',
|
||||
reset: false,
|
||||
connections,
|
||||
closedIds: [],
|
||||
...overrides,
|
||||
});
|
||||
|
||||
test('sing-box route traffic keeps vpn, direct and unknown deltas separate', async () => {
|
||||
let response = { connections: [
|
||||
@@ -238,3 +272,73 @@ test('failover activity is zero-work while disabled and uses the existing connec
|
||||
service.disableActivity();
|
||||
assert.equal(service.activitySnapshot(500), null);
|
||||
});
|
||||
|
||||
test('native lifecycle batches keep decimal precision and dedupe a same-epoch reconnect reset and final tail', () => {
|
||||
let now = new Date('2026-08-31T10:00:00.000Z');
|
||||
const service = createDomainTrafficService({
|
||||
observe: () => ({ connections: [] }),
|
||||
devices: () => [],
|
||||
now: () => now,
|
||||
});
|
||||
const initial = nativeConnection('native', '9007199254740993', '10');
|
||||
service.ingestNative(nativeBatch([initial], { reset: true }));
|
||||
now = new Date('2026-08-31T10:00:01.000Z');
|
||||
service.ingestNative(nativeBatch([initial], {
|
||||
reset: true,
|
||||
observedAt: now.toISOString(),
|
||||
}));
|
||||
|
||||
assert.equal(service.snapshot().series[0].uploadBytes, '9007199254740993');
|
||||
assert.equal(service.snapshot().source.activeConnections, 1);
|
||||
|
||||
service.enableActivity();
|
||||
now = new Date('2026-08-31T10:00:02.000Z');
|
||||
service.ingestNative(nativeBatch([
|
||||
nativeConnection('native', '9007199254740998', '15', { closedAt: now.toISOString() }),
|
||||
], {
|
||||
observedAt: now.toISOString(),
|
||||
closedIds: ['native'],
|
||||
}));
|
||||
|
||||
assert.equal(service.snapshot().series[0].uploadBytes, '9007199254740998');
|
||||
assert.equal(service.snapshot().series[0].downloadBytes, '15');
|
||||
assert.equal(service.snapshot().source.activeConnections, 0);
|
||||
assert.equal(service.activitySnapshot(0).state, 'active');
|
||||
|
||||
now = new Date('2026-08-31T10:00:03.000Z');
|
||||
service.ingestNative(nativeBatch([
|
||||
nativeConnection('native', '9007199254740998', '15'),
|
||||
], {
|
||||
reset: true,
|
||||
observedAt: now.toISOString(),
|
||||
}));
|
||||
|
||||
assert.equal(service.snapshot().series[0].uploadBytes, '9007199254740998');
|
||||
assert.equal(service.snapshot().series[0].downloadBytes, '15');
|
||||
assert.equal(service.snapshot().source.activeConnections, 1);
|
||||
|
||||
now = new Date('2026-08-31T10:00:14.000Z');
|
||||
service.ingestNative(nativeBatch([], { observedAt: now.toISOString() }));
|
||||
assert.equal(service.snapshot().observedAt, now.toISOString());
|
||||
assert.equal(service.snapshot().source.activeConnections, 1);
|
||||
assert.equal(service.activitySnapshot(0).state, 'quiet');
|
||||
});
|
||||
|
||||
test('one native batch accounts every final tail before lifecycle and UI caps', () => {
|
||||
const service = createDomainTrafficService({
|
||||
observe: () => ({ connections: [] }),
|
||||
devices: () => [],
|
||||
});
|
||||
const connections = Array.from({ length: 2_049 }, (_, index) => (
|
||||
nativeConnection(`closed-${index}`, '1', '1', { closedAt: '2026-08-31T10:00:00.000Z' })
|
||||
));
|
||||
|
||||
service.ingestNative(nativeBatch(connections, {
|
||||
reset: true,
|
||||
closedIds: connections.map(({ id: connectionId }) => connectionId),
|
||||
}));
|
||||
|
||||
assert.equal(service.snapshot().series[0].uploadBytes, '2049');
|
||||
assert.equal(service.snapshot().series[0].downloadBytes, '2049');
|
||||
assert.equal(service.snapshot().source.activeConnections, 0);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user