@push.rocks/smartvpn 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_rust/smartvpn_daemon_linux_amd64_musl +0 -0
- package/dist_rust/smartvpn_daemon_linux_amd64_musl.tsrust-build.json +4 -4
- package/dist_rust/smartvpn_daemon_linux_arm64_musl +0 -0
- package/dist_rust/smartvpn_daemon_linux_arm64_musl.tsrust-build.json +4 -4
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/smartvpn.classes.vpnbridge.js +4 -1
- package/dist_ts/smartvpn.classes.vpnclient.d.ts +22 -2
- package/dist_ts/smartvpn.classes.vpnclient.js +74 -2
- package/dist_ts/smartvpn.interfaces.d.ts +96 -0
- package/package.json +3 -3
- package/readme.md +67 -2
- package/ts/00_commitinfo_data.ts +3 -3
- package/ts/smartvpn.classes.vpnbridge.ts +4 -0
- package/ts/smartvpn.classes.vpnclient.ts +87 -1
- package/ts/smartvpn.interfaces.ts +70 -0
|
Binary file
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "tsrust.build-provenance.v2",
|
|
3
|
-
"binarySha256": "
|
|
3
|
+
"binarySha256": "d4e6f89ac9278183338ea8a83fd112ef8b7516576057234f7bab8181291089a1",
|
|
4
4
|
"buildInfo": {
|
|
5
5
|
"projectName": "@push.rocks/smartvpn",
|
|
6
|
-
"projectVersion": "2.
|
|
7
|
-
"gitCommit": "
|
|
6
|
+
"projectVersion": "2.3.1",
|
|
7
|
+
"gitCommit": "a96a22bd5ff5fe870e72c225b51f4715c1b25c40",
|
|
8
8
|
"gitDirty": false,
|
|
9
|
-
"builtAt": "2026-09-
|
|
9
|
+
"builtAt": "2026-09-17T15:20:47.136Z",
|
|
10
10
|
"tsrustVersion": "1.13.0",
|
|
11
11
|
"binary": "smartvpn_daemon",
|
|
12
12
|
"target": "linux_amd64_musl"
|
|
Binary file
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "tsrust.build-provenance.v2",
|
|
3
|
-
"binarySha256": "
|
|
3
|
+
"binarySha256": "9c8bdf211d7bbb9425e7dcf44ead8b39b584e6fd1b18cfdddff07b51133fb16d",
|
|
4
4
|
"buildInfo": {
|
|
5
5
|
"projectName": "@push.rocks/smartvpn",
|
|
6
|
-
"projectVersion": "2.
|
|
7
|
-
"gitCommit": "
|
|
6
|
+
"projectVersion": "2.3.1",
|
|
7
|
+
"gitCommit": "a96a22bd5ff5fe870e72c225b51f4715c1b25c40",
|
|
8
8
|
"gitDirty": false,
|
|
9
|
-
"builtAt": "2026-09-
|
|
9
|
+
"builtAt": "2026-09-17T15:20:47.476Z",
|
|
10
10
|
"tsrustVersion": "1.13.0",
|
|
11
11
|
"binary": "smartvpn_daemon",
|
|
12
12
|
"target": "linux_arm64_musl"
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
|
-
name:
|
|
6
|
-
version:
|
|
7
|
-
description:
|
|
5
|
+
name: "@push.rocks/smartvpn",
|
|
6
|
+
version: "2.3.1",
|
|
7
|
+
description: "A VPN solution with TypeScript control plane and Rust data plane daemon"
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLHlFQUF5RTtDQUN2RixDQUFBIn0=
|
|
@@ -54,6 +54,9 @@ export class VpnBridge extends plugins.events.EventEmitter {
|
|
|
54
54
|
this.bridge.on('management:managed-runtime-invalidated', (data) => {
|
|
55
55
|
this.emit('managed-runtime-invalidated', data);
|
|
56
56
|
});
|
|
57
|
+
this.bridge.on('management:managed-session-state', (data) => {
|
|
58
|
+
this.emit('managed-session-state', data);
|
|
59
|
+
});
|
|
57
60
|
this.bridge.on('management:status', (data) => {
|
|
58
61
|
this.emit('status', data);
|
|
59
62
|
});
|
|
@@ -110,4 +113,4 @@ export class VpnBridge extends plugins.events.EventEmitter {
|
|
|
110
113
|
return this.bridge.running;
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
116
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy52cG5icmlkZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHZwbi5jbGFzc2VzLnZwbmJyaWRnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBQ2pELE9BQU8sS0FBSyxLQUFLLE1BQU0scUJBQXFCLENBQUM7QUFTN0M7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFNBQXlDLFNBQVEsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZO0lBS3ZGLFlBQVksT0FLWDtRQUNDLEtBQUssRUFBRSxDQUFDO1FBRVIsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUFDO1FBQy9DLElBQUksV0FBVyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzlCLElBQUksT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsS0FBSyxPQUFPLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxTQUFTLEtBQUssT0FBTyxFQUFFLENBQUM7Z0JBQzlHLE1BQU0sSUFBSSxLQUFLLENBQUMsNERBQTRELENBQUMsQ0FBQztZQUNoRixDQUFDO1lBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLElBQUksV0FBVyxHQUFHLENBQUMsSUFBSSxXQUFXLEdBQUcsV0FBVyxFQUFFLENBQUM7Z0JBQ25GLE1BQU0sSUFBSSxLQUFLLENBQUMsdUVBQXVFLENBQUMsQ0FBQztZQUMzRixDQUFDO1FBQ0gsQ0FBQztRQUNELE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLElBQUksaUJBQWlCLENBQUM7UUFDM0QsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLFNBQVMsS0FBSyxPQUFPLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxVQUFVLEtBQUssU0FBUztlQUNwRixDQUFDLE9BQU8sT0FBTyxD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
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as plugins from './smartvpn.plugins.js';
|
|
2
|
-
import type { IVpnClientOptions, IVpnClientConfig, IVpnStatus, IVpnStatistics, IVpnConnectionQuality, IVpnMtuInfo, IVpnConnectionResult, IVpnManagedRuntime } from './smartvpn.interfaces.js';
|
|
2
|
+
import type { IVpnClientOptions, IVpnClientConfig, IVpnStatus, IVpnStatistics, IVpnConnectionQuality, IVpnMtuInfo, IVpnConnectionResult, IVpnManagedRuntime, IVpnManagedSessionConfig, IVpnManagedSession } from './smartvpn.interfaces.js';
|
|
3
3
|
/**
|
|
4
4
|
* VPN Client — manages a smartvpn daemon in client mode.
|
|
5
5
|
*/
|
|
@@ -9,9 +9,28 @@ export declare class VpnClient extends plugins.events.EventEmitter {
|
|
|
9
9
|
private bridgeEpoch;
|
|
10
10
|
private managedGeneration?;
|
|
11
11
|
private lastInvalidatedGeneration?;
|
|
12
|
+
private sessionGeneration?;
|
|
13
|
+
private stoppedSessionGeneration?;
|
|
14
|
+
private retiredSessionGeneration?;
|
|
15
|
+
private invalidatedSessionGeneration?;
|
|
12
16
|
constructor(options: IVpnClientOptions);
|
|
17
|
+
private observeSessionEvent;
|
|
13
18
|
private invalidateGeneration;
|
|
14
19
|
private invalidateBridge;
|
|
20
|
+
private checkSession;
|
|
21
|
+
/** Authenticate and retain transport/keepalive without any TUN or route effect. */
|
|
22
|
+
authenticateManaged(config: IVpnManagedSessionConfig): Promise<IVpnManagedSession>;
|
|
23
|
+
/** Create the planned exclusive /32 TUN and split routes with forwarding disabled.
|
|
24
|
+
* Caller must authorize these exact native transitions before calling. */
|
|
25
|
+
prepareManagedTunnel(generation: string): Promise<IVpnManagedSession>;
|
|
26
|
+
/** Reinspect, discard ready pre-enable inputs, then start forwarding. Call only
|
|
27
|
+
* after caller-owned policy is installed and verified against the prepared TUN. */
|
|
28
|
+
enableManagedForwarding(generation: string): Promise<IVpnManagedSession>;
|
|
29
|
+
/** Terminally stop packet I/O and retain the TUN for caller-authorized teardown.
|
|
30
|
+
* This generation cannot forward again. Disconnect then closes its kernel owner. */
|
|
31
|
+
stopManagedForwarding(generation: string): Promise<IVpnManagedSession>;
|
|
32
|
+
inspectManagedSession(generation: string): Promise<IVpnManagedSession>;
|
|
33
|
+
private sessionCommand;
|
|
15
34
|
private checkObservation;
|
|
16
35
|
/**
|
|
17
36
|
* Start the daemon bridge (spawn or connect).
|
|
@@ -46,7 +65,8 @@ export declare class VpnClient extends plugins.events.EventEmitter {
|
|
|
46
65
|
*/
|
|
47
66
|
getMtuInfo(): Promise<IVpnMtuInfo | null>;
|
|
48
67
|
/**
|
|
49
|
-
* Stop
|
|
68
|
+
* Stop and join an owned stdio daemon. Socket mode only closes the bridge;
|
|
69
|
+
* disconnect() must first join the independently owned native session.
|
|
50
70
|
*/
|
|
51
71
|
stop(): Promise<void>;
|
|
52
72
|
/**
|
|
@@ -31,6 +31,20 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
31
31
|
this.bridge.on('managed-runtime-invalidated', (event) => {
|
|
32
32
|
this.invalidateGeneration(event);
|
|
33
33
|
});
|
|
34
|
+
this.bridge.on('managed-session-state', (event) => {
|
|
35
|
+
this.observeSessionEvent(event);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
observeSessionEvent(event) {
|
|
39
|
+
if (event.phase === 'retired') {
|
|
40
|
+
this.retiredSessionGeneration = event.generation;
|
|
41
|
+
if (this.sessionGeneration === event.generation)
|
|
42
|
+
this.sessionGeneration = undefined;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
this.stoppedSessionGeneration = event.generation;
|
|
46
|
+
}
|
|
47
|
+
this.emit('managed-session-state', event);
|
|
34
48
|
}
|
|
35
49
|
invalidateGeneration(event) {
|
|
36
50
|
if (this.lastInvalidatedGeneration === event.generation)
|
|
@@ -44,6 +58,63 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
44
58
|
this.bridgeEpoch++;
|
|
45
59
|
if (this.managedGeneration)
|
|
46
60
|
this.invalidateGeneration({ generation: this.managedGeneration, reason });
|
|
61
|
+
if (this.sessionGeneration) {
|
|
62
|
+
const generation = this.sessionGeneration;
|
|
63
|
+
this.invalidatedSessionGeneration = generation;
|
|
64
|
+
this.sessionGeneration = undefined;
|
|
65
|
+
this.emit('managed-session-invalidated', { generation, reason });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
checkSession(result, epoch, generation) {
|
|
69
|
+
const observed = result.plan.generation;
|
|
70
|
+
if (epoch !== this.bridgeEpoch || observed === this.retiredSessionGeneration
|
|
71
|
+
|| observed === this.invalidatedSessionGeneration
|
|
72
|
+
|| (generation !== undefined && observed !== generation)
|
|
73
|
+
|| (observed === this.stoppedSessionGeneration && result.phase !== 'stopped')) {
|
|
74
|
+
throw new Error('Managed session stopped, retired, or lost observation during the operation');
|
|
75
|
+
}
|
|
76
|
+
if (result.runtime) {
|
|
77
|
+
this.checkObservation(result.runtime, epoch, observed);
|
|
78
|
+
this.managedGeneration = observed;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Authenticate and retain transport/keepalive without any TUN or route effect. */
|
|
82
|
+
async authenticateManaged(config) {
|
|
83
|
+
const epoch = this.bridgeEpoch;
|
|
84
|
+
const result = await this.bridge.sendCommand('authenticateManaged', { config });
|
|
85
|
+
this.checkSession(result, epoch);
|
|
86
|
+
this.sessionGeneration = result.plan.generation;
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/** Create the planned exclusive /32 TUN and split routes with forwarding disabled.
|
|
90
|
+
* Caller must authorize these exact native transitions before calling. */
|
|
91
|
+
prepareManagedTunnel(generation) {
|
|
92
|
+
return this.sessionCommand('prepareManagedTunnel', generation);
|
|
93
|
+
}
|
|
94
|
+
/** Reinspect, discard ready pre-enable inputs, then start forwarding. Call only
|
|
95
|
+
* after caller-owned policy is installed and verified against the prepared TUN. */
|
|
96
|
+
enableManagedForwarding(generation) {
|
|
97
|
+
return this.sessionCommand('enableManagedForwarding', generation);
|
|
98
|
+
}
|
|
99
|
+
/** Terminally stop packet I/O and retain the TUN for caller-authorized teardown.
|
|
100
|
+
* This generation cannot forward again. Disconnect then closes its kernel owner. */
|
|
101
|
+
stopManagedForwarding(generation) {
|
|
102
|
+
return this.sessionCommand('stopManagedForwarding', generation);
|
|
103
|
+
}
|
|
104
|
+
inspectManagedSession(generation) {
|
|
105
|
+
return this.sessionCommand('inspectManagedSession', generation);
|
|
106
|
+
}
|
|
107
|
+
async sessionCommand(method, generation) {
|
|
108
|
+
if (typeof generation !== 'string' || !/^[a-f0-9]{32}$/.test(generation)) {
|
|
109
|
+
throw new Error('Managed session generation must be a native 128-bit identifier');
|
|
110
|
+
}
|
|
111
|
+
if (generation === this.invalidatedSessionGeneration || generation === this.retiredSessionGeneration) {
|
|
112
|
+
throw new Error('Managed session observation is unavailable');
|
|
113
|
+
}
|
|
114
|
+
const epoch = this.bridgeEpoch;
|
|
115
|
+
const result = await this.bridge.sendCommand(method, { generation });
|
|
116
|
+
this.checkSession(result, epoch, generation);
|
|
117
|
+
return result;
|
|
47
118
|
}
|
|
48
119
|
checkObservation(runtime, epoch, generation) {
|
|
49
120
|
if (epoch !== this.bridgeEpoch || runtime.generation === this.lastInvalidatedGeneration
|
|
@@ -116,7 +187,8 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
116
187
|
return this.bridge.sendCommand('getMtuInfo', {});
|
|
117
188
|
}
|
|
118
189
|
/**
|
|
119
|
-
* Stop
|
|
190
|
+
* Stop and join an owned stdio daemon. Socket mode only closes the bridge;
|
|
191
|
+
* disconnect() must first join the independently owned native session.
|
|
120
192
|
*/
|
|
121
193
|
async stop() {
|
|
122
194
|
this.invalidateBridge('Client stop requested');
|
|
@@ -129,4 +201,4 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
129
201
|
return this.bridge.running;
|
|
130
202
|
}
|
|
131
203
|
}
|
|
132
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
204
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnR2cG4uY2xhc3Nlcy52cG5jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHZwbi5jbGFzc2VzLnZwbmNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBQ2pELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQWlCNUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sU0FBVSxTQUFRLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWTtJQVd4RCxZQUFZLE9BQTBCO1FBQ3BDLEtBQUssRUFBRSxDQUFDO1FBVEYsZ0JBQVcsR0FBRyxDQUFDLENBQUM7UUFVdEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLFNBQVMsQ0FBcUI7WUFDOUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTO1lBQzVCLElBQUksRUFBRSxRQUFRO1lBQ2Qsa0JBQWtCLEVBQUUsT0FBTyxDQUFDLGtCQUFrQjtTQUMvQyxDQUFDLENBQUM7UUFFSCx3QkFBd0I7UUFDeEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsY0FBYyxFQUFFLEdBQUcsRUFBRTtZQUNsQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUN6RCxDQUFDLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQW1CLEVBQUUsTUFBcUIsRUFBRSxFQUFFO1lBQ3BFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1lBQzlDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDdEMsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsTUFBTSxDQUFD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
|
|
@@ -407,6 +407,36 @@ export interface IWgPeerInfo {
|
|
|
407
407
|
lastHandshakeTime?: string;
|
|
408
408
|
}
|
|
409
409
|
export type TVpnClientCommands = {
|
|
410
|
+
authenticateManaged: {
|
|
411
|
+
params: {
|
|
412
|
+
config: IVpnManagedSessionConfig;
|
|
413
|
+
};
|
|
414
|
+
result: IVpnManagedSession;
|
|
415
|
+
};
|
|
416
|
+
prepareManagedTunnel: {
|
|
417
|
+
params: {
|
|
418
|
+
generation: string;
|
|
419
|
+
};
|
|
420
|
+
result: IVpnManagedSession;
|
|
421
|
+
};
|
|
422
|
+
enableManagedForwarding: {
|
|
423
|
+
params: {
|
|
424
|
+
generation: string;
|
|
425
|
+
};
|
|
426
|
+
result: IVpnManagedSession;
|
|
427
|
+
};
|
|
428
|
+
stopManagedForwarding: {
|
|
429
|
+
params: {
|
|
430
|
+
generation: string;
|
|
431
|
+
};
|
|
432
|
+
result: IVpnManagedSession;
|
|
433
|
+
};
|
|
434
|
+
inspectManagedSession: {
|
|
435
|
+
params: {
|
|
436
|
+
generation: string;
|
|
437
|
+
};
|
|
438
|
+
result: IVpnManagedSession;
|
|
439
|
+
};
|
|
410
440
|
connect: {
|
|
411
441
|
params: {
|
|
412
442
|
config: IVpnClientConfig;
|
|
@@ -612,6 +642,7 @@ export interface IManagedNetworkNode {
|
|
|
612
642
|
controlAddress: string;
|
|
613
643
|
controlPolicyDomain: string;
|
|
614
644
|
enabled: boolean;
|
|
645
|
+
/** Credential expiry (ISO 8601); renewing only this keeps the node's live session. */
|
|
615
646
|
expiresAt?: string;
|
|
616
647
|
workloadPrefixes: IManagedNetworkPrefix[];
|
|
617
648
|
}
|
|
@@ -661,6 +692,69 @@ export interface IVpnConnectionResult {
|
|
|
661
692
|
/** Present only for an authenticated native managed connection with a real TUN. */
|
|
662
693
|
managedRuntime?: IVpnManagedRuntime;
|
|
663
694
|
}
|
|
695
|
+
/** Linux native client with explicit kernel-effect stages. The caller supplies
|
|
696
|
+
* a conservative deadline from its independently qualified clock authority. */
|
|
697
|
+
export interface IVpnManagedSessionConfig {
|
|
698
|
+
serverUrl: string;
|
|
699
|
+
serverPublicKey: string;
|
|
700
|
+
clientPrivateKey: string;
|
|
701
|
+
clientPublicKey: string;
|
|
702
|
+
transport: 'quic' | 'websocket';
|
|
703
|
+
serverCertHash?: string;
|
|
704
|
+
mtu?: number;
|
|
705
|
+
managedNetwork: IManagedNetworkBinding;
|
|
706
|
+
/** Same native boot; deadline must be future and at most fifteen minutes away.
|
|
707
|
+
* Expiry stops packet I/O even across suspend. It does not delete a held TUN. */
|
|
708
|
+
lease: {
|
|
709
|
+
bootId: string;
|
|
710
|
+
deadlineBoottimeMs: number;
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
/** Authentication returns the full validated assignment and planned exclusive
|
|
714
|
+
* TUN name before creating a device or route. Kernel policy remains caller-owned. */
|
|
715
|
+
export interface IVpnManagedSessionPlan {
|
|
716
|
+
schemaVersion: 1;
|
|
717
|
+
generation: string;
|
|
718
|
+
namespace: {
|
|
719
|
+
device: string;
|
|
720
|
+
inode: string;
|
|
721
|
+
};
|
|
722
|
+
interfaceName: string;
|
|
723
|
+
assignment: {
|
|
724
|
+
assignedIp: string;
|
|
725
|
+
gateway: string;
|
|
726
|
+
subnet: string;
|
|
727
|
+
mtu: number;
|
|
728
|
+
effectiveMtu: number;
|
|
729
|
+
managed: IManagedNetworkAssignment;
|
|
730
|
+
};
|
|
731
|
+
mtu: number;
|
|
732
|
+
remoteIp: string;
|
|
733
|
+
lease: IVpnManagedSessionConfig['lease'];
|
|
734
|
+
}
|
|
735
|
+
export interface IVpnManagedSession {
|
|
736
|
+
plan: IVpnManagedSessionPlan;
|
|
737
|
+
phase: 'authenticated' | 'prepared' | 'forwarding' | 'stopped';
|
|
738
|
+
/** Fresh native inspection when present. Prepared TUN is UP with forwarding
|
|
739
|
+
* disabled. A stopped TUN stays owned until disconnect() joins deletion, or an
|
|
740
|
+
* owned stdio process is joined by stop(). Socket stop() does not delete it. */
|
|
741
|
+
runtime: IVpnManagedRuntime | null;
|
|
742
|
+
}
|
|
743
|
+
/** Stopped means the complete packet I/O future ended; retired means the native
|
|
744
|
+
* session owner ended. Neither proves namespace-wide cleanup, conntrack drain,
|
|
745
|
+
* packets already queued on the network, or safe allocation reuse. */
|
|
746
|
+
export interface IVpnManagedSessionEvent {
|
|
747
|
+
generation: string;
|
|
748
|
+
phase: 'stopped' | 'retired';
|
|
749
|
+
reason: string;
|
|
750
|
+
}
|
|
751
|
+
/** The facade lost observation of this generation. Native packet I/O and TUN
|
|
752
|
+
* ownership may remain alive, especially with an independent socket daemon.
|
|
753
|
+
* This is neither a stopped nor a retired native lifecycle acknowledgement. */
|
|
754
|
+
export interface IVpnManagedSessionInvalidation {
|
|
755
|
+
generation: string;
|
|
756
|
+
reason: string;
|
|
757
|
+
}
|
|
664
758
|
/** A fresh observation of a retained native lifetime, never a transferable or
|
|
665
759
|
* restorable capability. The caller retains VpnClient and listens for invalidation.
|
|
666
760
|
* IPv6, namespace-wide policy/rules, underlay and firewall remain caller-owned. */
|
|
@@ -714,6 +808,8 @@ export interface IVpnServiceUnit {
|
|
|
714
808
|
installPath: string;
|
|
715
809
|
}
|
|
716
810
|
export interface IVpnEventMap {
|
|
811
|
+
'managed-session-state': IVpnManagedSessionEvent;
|
|
812
|
+
'managed-session-invalidated': IVpnManagedSessionInvalidation;
|
|
717
813
|
'managed-runtime-invalidated': IVpnManagedRuntimeInvalidation;
|
|
718
814
|
'status': IVpnStatus;
|
|
719
815
|
'error': {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartvpn",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A VPN solution with TypeScript control plane and Rust data plane daemon",
|
|
6
6
|
"type": "module",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"@git.zone/tsbuild": "^4.4.3",
|
|
32
32
|
"@git.zone/tsrun": "^2.0.6",
|
|
33
33
|
"@git.zone/tsrust": "^1.13.0",
|
|
34
|
-
"@git.zone/tstest": "^6.
|
|
35
|
-
"@types/node": "^26.5.
|
|
34
|
+
"@git.zone/tstest": "^6.1.1",
|
|
35
|
+
"@types/node": "^26.5.1"
|
|
36
36
|
},
|
|
37
37
|
"files": [
|
|
38
38
|
"ts/**/*",
|
package/readme.md
CHANGED
|
@@ -155,6 +155,63 @@ managed TUN creation, allow/deny, reconnect, revocation, route-conflict rollback
|
|
|
155
155
|
and child-termination cleanup. Privileged ARM64 and Pallet integration remain
|
|
156
156
|
separate qualification requirements.
|
|
157
157
|
|
|
158
|
+
### Staged managed client activation
|
|
159
|
+
|
|
160
|
+
`authenticateManaged(config)` is a Linux native client API for a caller that must
|
|
161
|
+
install packet policy before forwarding. Its closed configuration accepts an
|
|
162
|
+
explicit `quic` or `websocket` transport, a matching Noise keypair, server public
|
|
163
|
+
key, `managedNetwork` binding, optional MTU/certificate pin and a native lease.
|
|
164
|
+
Testing mode, automatic transport fallback and extra configuration fields reject.
|
|
165
|
+
|
|
166
|
+
The lease is `{ bootId, deadlineBoottimeMs }`: the actual Linux boot ID and an
|
|
167
|
+
absolute `CLOCK_BOOTTIME` deadline, future and no more than fifteen minutes away.
|
|
168
|
+
The caller derives this conservative deadline from its independently qualified
|
|
169
|
+
authority; SmartVPN does not turn wall-clock credentials into trusted time.
|
|
170
|
+
Native expiry interrupts the whole packet I/O future, including blocked writes,
|
|
171
|
+
and remains effective across suspend. Leases cannot be extended in place.
|
|
172
|
+
|
|
173
|
+
Register `managed-session-state`, `managed-session-invalidated` and
|
|
174
|
+
`managed-runtime-invalidated` listeners before
|
|
175
|
+
starting. Keep the live client owner and use the returned generation for each step:
|
|
176
|
+
|
|
177
|
+
1. `authenticateManaged(config)` authenticates Noise and validates the full server
|
|
178
|
+
assignment. It retains transport and keepalive without creating a TUN or route.
|
|
179
|
+
The returned `plan` includes the actual namespace, remote endpoint, authenticated
|
|
180
|
+
assignment, effective MTU and an exclusive planned TUN name.
|
|
181
|
+
2. Authorize the planned native changes in the caller's namespace/policy owner.
|
|
182
|
+
`prepareManagedTunnel(generation)` then creates that fresh nonpersistent TUN
|
|
183
|
+
with `IFF_TUN_EXCL`, the assigned IPv4 /32 and exact split routes. The interface
|
|
184
|
+
is UP; packet forwarding remains disabled. An existing same-named interface
|
|
185
|
+
causes failure and is never adopted or deleted.
|
|
186
|
+
3. Install and verify caller-owned policy against the fresh returned `runtime`.
|
|
187
|
+
`enableManagedForwarding(generation)` reinspects the native inventory, discards
|
|
188
|
+
already-ready incoming encrypted frames and TUN packets, then starts forwarding.
|
|
189
|
+
Incoming ciphertext is consumed while disabled so Noise nonces stay synchronized.
|
|
190
|
+
Continuous ready input can prevent enable from completing; it cannot enable early.
|
|
191
|
+
4. `stopManagedForwarding(generation)` terminally ends packet I/O while retaining
|
|
192
|
+
the TUN and its monitor. A stopped generation cannot restart. Fence caller-owned
|
|
193
|
+
policy, authorize deletion, then `disconnect()` to close and join the kernel owner.
|
|
194
|
+
`stop()` additionally closes an owned stdio process; socket transport leaves the
|
|
195
|
+
independently owned daemon alive and requires `disconnect()` for native cleanup.
|
|
196
|
+
|
|
197
|
+
`inspectManagedSession(generation)` returns the current phase and a fresh TUN audit
|
|
198
|
+
when a device exists. Prepare/enable repeats inspect the same live generation;
|
|
199
|
+
stale generations reject before effects. A lost reply or timeout does not prove
|
|
200
|
+
that a native transition had no effect: inspect the retained owner and reconcile
|
|
201
|
+
the caller's independent inventory before proceeding. Never use serialized receipts
|
|
202
|
+
to recreate ownership or silently reconnect into an old policy epoch.
|
|
203
|
+
|
|
204
|
+
Transport loss and lease expiry emit a `managed-session-state` event with phase
|
|
205
|
+
`stopped` after packet I/O ends, retaining the kernel device for explicit teardown.
|
|
206
|
+
Changed or restored kernel inventory instead retires the entire native owner and
|
|
207
|
+
closes its TUN even while packet I/O is blocked. Phase `retired` follows native
|
|
208
|
+
owner destruction. Bridge loss instead emits `managed-session-invalidated` and
|
|
209
|
+
invalidates facade observations immediately; the native session may still be
|
|
210
|
+
forwarding in an independently owned socket daemon. These events do not prove global
|
|
211
|
+
policy removal, conntrack drainage, delivery of previously queued network packets,
|
|
212
|
+
or safe allocation reuse. IPv6, underlay, workload links, sysctls, global routes and
|
|
213
|
+
firewall policy remain the caller's responsibility.
|
|
214
|
+
|
|
158
215
|
### Retained managed TUN runtime
|
|
159
216
|
|
|
160
217
|
An authenticated native managed connection with `forwardingMode: 'tun'` returns
|
|
@@ -727,8 +784,16 @@ are never routed back to the hub merely because a grant involves them.
|
|
|
727
784
|
|
|
728
785
|
Invalid preparation preserves active authority. A valid change quarantines and
|
|
729
786
|
cancels only affected node generations, joins their packet work, prepares WG
|
|
730
|
-
crypto and commits the whole snapshot atomically before acknowledging.
|
|
731
|
-
|
|
787
|
+
crypto and commits the whole snapshot atomically before acknowledging. A node is
|
|
788
|
+
affected when it is added or removed, or when its keys, control address or domain,
|
|
789
|
+
`enabled`, workload prefixes, or the grants and routes involving it change.
|
|
790
|
+
Unchanged nodes keep their sessions. A change to `expiresAt` alone does not affect
|
|
791
|
+
a node: its live native or WireGuard session stays connected and follows the
|
|
792
|
+
committed expiry in place. A later expiry keeps the session, an earlier future
|
|
793
|
+
expiry re-arms its deadline, and an expiry that has already passed ends it when
|
|
794
|
+
the snapshot commits. A session whose expiry passed is never revived, so renew
|
|
795
|
+
before expiry; after a late renewal the node can reconnect with its unchanged keys.
|
|
796
|
+
A post-drain failure leaves `state: 'failed'`, its
|
|
732
797
|
`pendingRevision` and bounded `lastError`; old affected admission stays closed.
|
|
733
798
|
Only the exact pending snapshot can retry. An IPC timeout or disconnected caller
|
|
734
799
|
does not cancel the process-owned operation. Inspect status and replay that exact
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* autocreated commitinfo by @push.rocks/commitinfo
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
|
-
name:
|
|
6
|
-
version:
|
|
7
|
-
description:
|
|
5
|
+
name: "@push.rocks/smartvpn",
|
|
6
|
+
version: "2.3.1",
|
|
7
|
+
description: "A VPN solution with TypeScript control plane and Rust data plane daemon"
|
|
8
8
|
}
|
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
TVpnTransportOptions,
|
|
5
5
|
IVpnTransportSocket,
|
|
6
6
|
IVpnManagedRuntimeInvalidation,
|
|
7
|
+
IVpnManagedSessionEvent,
|
|
7
8
|
} from './smartvpn.interfaces.js';
|
|
8
9
|
import type { TCommandMap, IRustBridgeDisconnectedEvent } from '@push.rocks/smartrust';
|
|
9
10
|
|
|
@@ -74,6 +75,9 @@ export class VpnBridge<TCommands extends TCommandMap> extends plugins.events.Eve
|
|
|
74
75
|
this.bridge.on('management:managed-runtime-invalidated', (data: IVpnManagedRuntimeInvalidation) => {
|
|
75
76
|
this.emit('managed-runtime-invalidated', data);
|
|
76
77
|
});
|
|
78
|
+
this.bridge.on('management:managed-session-state', (data: IVpnManagedSessionEvent) => {
|
|
79
|
+
this.emit('managed-session-state', data);
|
|
80
|
+
});
|
|
77
81
|
this.bridge.on('management:status', (data: any) => {
|
|
78
82
|
this.emit('status', data);
|
|
79
83
|
});
|
|
@@ -10,6 +10,9 @@ import type {
|
|
|
10
10
|
IVpnConnectionResult,
|
|
11
11
|
IVpnManagedRuntime,
|
|
12
12
|
IVpnManagedRuntimeInvalidation,
|
|
13
|
+
IVpnManagedSessionConfig,
|
|
14
|
+
IVpnManagedSession,
|
|
15
|
+
IVpnManagedSessionEvent,
|
|
13
16
|
TVpnClientCommands,
|
|
14
17
|
} from './smartvpn.interfaces.js';
|
|
15
18
|
|
|
@@ -22,6 +25,10 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
22
25
|
private bridgeEpoch = 0;
|
|
23
26
|
private managedGeneration?: string;
|
|
24
27
|
private lastInvalidatedGeneration?: string;
|
|
28
|
+
private sessionGeneration?: string;
|
|
29
|
+
private stoppedSessionGeneration?: string;
|
|
30
|
+
private retiredSessionGeneration?: string;
|
|
31
|
+
private invalidatedSessionGeneration?: string;
|
|
25
32
|
|
|
26
33
|
constructor(options: IVpnClientOptions) {
|
|
27
34
|
super();
|
|
@@ -50,6 +57,19 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
50
57
|
this.bridge.on('managed-runtime-invalidated', (event: IVpnManagedRuntimeInvalidation) => {
|
|
51
58
|
this.invalidateGeneration(event);
|
|
52
59
|
});
|
|
60
|
+
this.bridge.on('managed-session-state', (event: IVpnManagedSessionEvent) => {
|
|
61
|
+
this.observeSessionEvent(event);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private observeSessionEvent(event: IVpnManagedSessionEvent): void {
|
|
66
|
+
if (event.phase === 'retired') {
|
|
67
|
+
this.retiredSessionGeneration = event.generation;
|
|
68
|
+
if (this.sessionGeneration === event.generation) this.sessionGeneration = undefined;
|
|
69
|
+
} else {
|
|
70
|
+
this.stoppedSessionGeneration = event.generation;
|
|
71
|
+
}
|
|
72
|
+
this.emit('managed-session-state', event);
|
|
53
73
|
}
|
|
54
74
|
|
|
55
75
|
private invalidateGeneration(event: IVpnManagedRuntimeInvalidation): void {
|
|
@@ -62,6 +82,71 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
62
82
|
private invalidateBridge(reason: string): void {
|
|
63
83
|
this.bridgeEpoch++;
|
|
64
84
|
if (this.managedGeneration) this.invalidateGeneration({ generation: this.managedGeneration, reason });
|
|
85
|
+
if (this.sessionGeneration) {
|
|
86
|
+
const generation = this.sessionGeneration;
|
|
87
|
+
this.invalidatedSessionGeneration = generation;
|
|
88
|
+
this.sessionGeneration = undefined;
|
|
89
|
+
this.emit('managed-session-invalidated', { generation, reason });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private checkSession(result: IVpnManagedSession, epoch: number, generation?: string): void {
|
|
94
|
+
const observed = result.plan.generation;
|
|
95
|
+
if (epoch !== this.bridgeEpoch || observed === this.retiredSessionGeneration
|
|
96
|
+
|| observed === this.invalidatedSessionGeneration
|
|
97
|
+
|| (generation !== undefined && observed !== generation)
|
|
98
|
+
|| (observed === this.stoppedSessionGeneration && result.phase !== 'stopped')) {
|
|
99
|
+
throw new Error('Managed session stopped, retired, or lost observation during the operation');
|
|
100
|
+
}
|
|
101
|
+
if (result.runtime) {
|
|
102
|
+
this.checkObservation(result.runtime, epoch, observed);
|
|
103
|
+
this.managedGeneration = observed;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Authenticate and retain transport/keepalive without any TUN or route effect. */
|
|
108
|
+
public async authenticateManaged(config: IVpnManagedSessionConfig): Promise<IVpnManagedSession> {
|
|
109
|
+
const epoch = this.bridgeEpoch;
|
|
110
|
+
const result = await this.bridge.sendCommand('authenticateManaged', { config });
|
|
111
|
+
this.checkSession(result, epoch);
|
|
112
|
+
this.sessionGeneration = result.plan.generation;
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Create the planned exclusive /32 TUN and split routes with forwarding disabled.
|
|
117
|
+
* Caller must authorize these exact native transitions before calling. */
|
|
118
|
+
public prepareManagedTunnel(generation: string): Promise<IVpnManagedSession> {
|
|
119
|
+
return this.sessionCommand('prepareManagedTunnel', generation);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Reinspect, discard ready pre-enable inputs, then start forwarding. Call only
|
|
123
|
+
* after caller-owned policy is installed and verified against the prepared TUN. */
|
|
124
|
+
public enableManagedForwarding(generation: string): Promise<IVpnManagedSession> {
|
|
125
|
+
return this.sessionCommand('enableManagedForwarding', generation);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Terminally stop packet I/O and retain the TUN for caller-authorized teardown.
|
|
129
|
+
* This generation cannot forward again. Disconnect then closes its kernel owner. */
|
|
130
|
+
public stopManagedForwarding(generation: string): Promise<IVpnManagedSession> {
|
|
131
|
+
return this.sessionCommand('stopManagedForwarding', generation);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public inspectManagedSession(generation: string): Promise<IVpnManagedSession> {
|
|
135
|
+
return this.sessionCommand('inspectManagedSession', generation);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private async sessionCommand(method: 'prepareManagedTunnel' | 'enableManagedForwarding'
|
|
139
|
+
| 'stopManagedForwarding' | 'inspectManagedSession', generation: string): Promise<IVpnManagedSession> {
|
|
140
|
+
if (typeof generation !== 'string' || !/^[a-f0-9]{32}$/.test(generation)) {
|
|
141
|
+
throw new Error('Managed session generation must be a native 128-bit identifier');
|
|
142
|
+
}
|
|
143
|
+
if (generation === this.invalidatedSessionGeneration || generation === this.retiredSessionGeneration) {
|
|
144
|
+
throw new Error('Managed session observation is unavailable');
|
|
145
|
+
}
|
|
146
|
+
const epoch = this.bridgeEpoch;
|
|
147
|
+
const result = await this.bridge.sendCommand(method, { generation });
|
|
148
|
+
this.checkSession(result, epoch, generation);
|
|
149
|
+
return result;
|
|
65
150
|
}
|
|
66
151
|
|
|
67
152
|
private checkObservation(runtime: IVpnManagedRuntime, epoch: number, generation?: string): void {
|
|
@@ -144,7 +229,8 @@ export class VpnClient extends plugins.events.EventEmitter {
|
|
|
144
229
|
}
|
|
145
230
|
|
|
146
231
|
/**
|
|
147
|
-
* Stop
|
|
232
|
+
* Stop and join an owned stdio daemon. Socket mode only closes the bridge;
|
|
233
|
+
* disconnect() must first join the independently owned native session.
|
|
148
234
|
*/
|
|
149
235
|
public async stop(): Promise<void> {
|
|
150
236
|
this.invalidateBridge('Client stop requested');
|
|
@@ -491,6 +491,11 @@ export interface IWgPeerInfo {
|
|
|
491
491
|
// ============================================================================
|
|
492
492
|
|
|
493
493
|
export type TVpnClientCommands = {
|
|
494
|
+
authenticateManaged: { params: { config: IVpnManagedSessionConfig }; result: IVpnManagedSession };
|
|
495
|
+
prepareManagedTunnel: { params: { generation: string }; result: IVpnManagedSession };
|
|
496
|
+
enableManagedForwarding: { params: { generation: string }; result: IVpnManagedSession };
|
|
497
|
+
stopManagedForwarding: { params: { generation: string }; result: IVpnManagedSession };
|
|
498
|
+
inspectManagedSession: { params: { generation: string }; result: IVpnManagedSession };
|
|
494
499
|
connect: { params: { config: IVpnClientConfig }; result: IVpnConnectionResult };
|
|
495
500
|
inspectManagedRuntime: { params: { generation: string }; result: IVpnManagedRuntime };
|
|
496
501
|
disconnect: { params: Record<string, never>; result: void };
|
|
@@ -548,6 +553,7 @@ export interface IManagedNetworkNode {
|
|
|
548
553
|
controlAddress: string;
|
|
549
554
|
controlPolicyDomain: string;
|
|
550
555
|
enabled: boolean;
|
|
556
|
+
/** Credential expiry (ISO 8601); renewing only this keeps the node's live session. */
|
|
551
557
|
expiresAt?: string;
|
|
552
558
|
workloadPrefixes: IManagedNetworkPrefix[];
|
|
553
559
|
}
|
|
@@ -605,6 +611,68 @@ export interface IVpnConnectionResult {
|
|
|
605
611
|
managedRuntime?: IVpnManagedRuntime;
|
|
606
612
|
}
|
|
607
613
|
|
|
614
|
+
/** Linux native client with explicit kernel-effect stages. The caller supplies
|
|
615
|
+
* a conservative deadline from its independently qualified clock authority. */
|
|
616
|
+
export interface IVpnManagedSessionConfig {
|
|
617
|
+
serverUrl: string;
|
|
618
|
+
serverPublicKey: string;
|
|
619
|
+
clientPrivateKey: string;
|
|
620
|
+
clientPublicKey: string;
|
|
621
|
+
transport: 'quic' | 'websocket';
|
|
622
|
+
serverCertHash?: string;
|
|
623
|
+
mtu?: number;
|
|
624
|
+
managedNetwork: IManagedNetworkBinding;
|
|
625
|
+
/** Same native boot; deadline must be future and at most fifteen minutes away.
|
|
626
|
+
* Expiry stops packet I/O even across suspend. It does not delete a held TUN. */
|
|
627
|
+
lease: { bootId: string; deadlineBoottimeMs: number };
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/** Authentication returns the full validated assignment and planned exclusive
|
|
631
|
+
* TUN name before creating a device or route. Kernel policy remains caller-owned. */
|
|
632
|
+
export interface IVpnManagedSessionPlan {
|
|
633
|
+
schemaVersion: 1;
|
|
634
|
+
generation: string;
|
|
635
|
+
namespace: { device: string; inode: string };
|
|
636
|
+
interfaceName: string;
|
|
637
|
+
assignment: {
|
|
638
|
+
assignedIp: string;
|
|
639
|
+
gateway: string;
|
|
640
|
+
subnet: string;
|
|
641
|
+
mtu: number;
|
|
642
|
+
effectiveMtu: number;
|
|
643
|
+
managed: IManagedNetworkAssignment;
|
|
644
|
+
};
|
|
645
|
+
mtu: number;
|
|
646
|
+
remoteIp: string;
|
|
647
|
+
lease: IVpnManagedSessionConfig['lease'];
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
export interface IVpnManagedSession {
|
|
651
|
+
plan: IVpnManagedSessionPlan;
|
|
652
|
+
phase: 'authenticated' | 'prepared' | 'forwarding' | 'stopped';
|
|
653
|
+
/** Fresh native inspection when present. Prepared TUN is UP with forwarding
|
|
654
|
+
* disabled. A stopped TUN stays owned until disconnect() joins deletion, or an
|
|
655
|
+
* owned stdio process is joined by stop(). Socket stop() does not delete it. */
|
|
656
|
+
runtime: IVpnManagedRuntime | null;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/** Stopped means the complete packet I/O future ended; retired means the native
|
|
660
|
+
* session owner ended. Neither proves namespace-wide cleanup, conntrack drain,
|
|
661
|
+
* packets already queued on the network, or safe allocation reuse. */
|
|
662
|
+
export interface IVpnManagedSessionEvent {
|
|
663
|
+
generation: string;
|
|
664
|
+
phase: 'stopped' | 'retired';
|
|
665
|
+
reason: string;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/** The facade lost observation of this generation. Native packet I/O and TUN
|
|
669
|
+
* ownership may remain alive, especially with an independent socket daemon.
|
|
670
|
+
* This is neither a stopped nor a retired native lifecycle acknowledgement. */
|
|
671
|
+
export interface IVpnManagedSessionInvalidation {
|
|
672
|
+
generation: string;
|
|
673
|
+
reason: string;
|
|
674
|
+
}
|
|
675
|
+
|
|
608
676
|
/** A fresh observation of a retained native lifetime, never a transferable or
|
|
609
677
|
* restorable capability. The caller retains VpnClient and listens for invalidation.
|
|
610
678
|
* IPv6, namespace-wide policy/rules, underlay and firewall remain caller-owned. */
|
|
@@ -669,6 +737,8 @@ export interface IVpnServiceUnit {
|
|
|
669
737
|
// ============================================================================
|
|
670
738
|
|
|
671
739
|
export interface IVpnEventMap {
|
|
740
|
+
'managed-session-state': IVpnManagedSessionEvent;
|
|
741
|
+
'managed-session-invalidated': IVpnManagedSessionInvalidation;
|
|
672
742
|
'managed-runtime-invalidated': IVpnManagedRuntimeInvalidation;
|
|
673
743
|
'status': IVpnStatus;
|
|
674
744
|
'error': { message: string; code?: string };
|