termify-agent 1.0.32 → 1.0.34
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/agent.d.ts +13 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +236 -0
- package/dist/agent.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +184 -15
- package/dist/index.js.map +1 -1
- package/dist/network/backends/windows-wireguard-backend.d.ts +29 -0
- package/dist/network/backends/windows-wireguard-backend.d.ts.map +1 -0
- package/dist/network/backends/windows-wireguard-backend.js +190 -0
- package/dist/network/backends/windows-wireguard-backend.js.map +1 -0
- package/dist/network/key-rotation.d.ts +55 -0
- package/dist/network/key-rotation.d.ts.map +1 -0
- package/dist/network/key-rotation.js +105 -0
- package/dist/network/key-rotation.js.map +1 -0
- package/dist/network/nat-traversal.d.ts +27 -0
- package/dist/network/nat-traversal.d.ts.map +1 -0
- package/dist/network/nat-traversal.js +76 -0
- package/dist/network/nat-traversal.js.map +1 -0
- package/dist/network/uapi-client.d.ts +50 -0
- package/dist/network/uapi-client.d.ts.map +1 -0
- package/dist/network/uapi-client.js +260 -0
- package/dist/network/uapi-client.js.map +1 -0
- package/dist/network/wireguard-backend.d.ts +60 -0
- package/dist/network/wireguard-backend.d.ts.map +1 -0
- package/dist/network/wireguard-backend.js +9 -0
- package/dist/network/wireguard-backend.js.map +1 -0
- package/dist/network/wireguard-installer.d.ts +24 -0
- package/dist/network/wireguard-installer.d.ts.map +1 -0
- package/dist/network/wireguard-installer.js +362 -0
- package/dist/network/wireguard-installer.js.map +1 -0
- package/dist/network/wireguard-manager.d.ts +92 -0
- package/dist/network/wireguard-manager.d.ts.map +1 -0
- package/dist/network/wireguard-manager.js +575 -0
- package/dist/network/wireguard-manager.js.map +1 -0
- package/dist/network/wireguard-state-store.d.ts +55 -0
- package/dist/network/wireguard-state-store.d.ts.map +1 -0
- package/dist/network/wireguard-state-store.js +196 -0
- package/dist/network/wireguard-state-store.js.map +1 -0
- package/dist/ssh-manager.d.ts +5 -0
- package/dist/ssh-manager.d.ts.map +1 -1
- package/dist/ssh-manager.js +104 -0
- package/dist/ssh-manager.js.map +1 -1
- package/dist/tunnel-manager.d.ts +65 -0
- package/dist/tunnel-manager.d.ts.map +1 -0
- package/dist/tunnel-manager.js +267 -0
- package/dist/tunnel-manager.js.map +1 -0
- package/dist/ws-client.d.ts +145 -0
- package/dist/ws-client.d.ts.map +1 -1
- package/dist/ws-client.js +136 -1
- package/dist/ws-client.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +100 -35
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
export interface KeyRotationConfig {
|
|
3
|
+
/** Interval between key rotations in ms (default: 24 hours) */
|
|
4
|
+
rotationIntervalMs: number;
|
|
5
|
+
/** Random jitter to prevent thundering herd (default: up to 1 hour) */
|
|
6
|
+
jitterMs: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Manages periodic key rotation for WireGuard.
|
|
10
|
+
*
|
|
11
|
+
* Flow:
|
|
12
|
+
* 1. Timer fires -> emits 'rotate-needed' event
|
|
13
|
+
* 2. WireGuardManager generates new keypair
|
|
14
|
+
* 3. Agent sends agent.wg.rotate.propose to server
|
|
15
|
+
* 4. Server distributes update to peers
|
|
16
|
+
* 5. Peers ACK with agent.wg.rotate.applied
|
|
17
|
+
* 6. Server sends server.wg.rotate.commit to agent
|
|
18
|
+
* 7. Agent applies the new key on its interface
|
|
19
|
+
*
|
|
20
|
+
* Events:
|
|
21
|
+
* - 'rotate-needed' : time to rotate
|
|
22
|
+
* - 'rotate-committed' : { keyVersion } -- rotation confirmed by server
|
|
23
|
+
*/
|
|
24
|
+
export declare class KeyRotation extends EventEmitter {
|
|
25
|
+
private config;
|
|
26
|
+
private rotationTimer;
|
|
27
|
+
private _currentVersion;
|
|
28
|
+
private _pendingVersion;
|
|
29
|
+
private _isRotating;
|
|
30
|
+
constructor(config?: Partial<KeyRotationConfig>);
|
|
31
|
+
get currentVersion(): number;
|
|
32
|
+
get isRotating(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Start the rotation timer.
|
|
35
|
+
*/
|
|
36
|
+
start(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Stop the rotation timer.
|
|
39
|
+
*/
|
|
40
|
+
stop(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Called when the agent initiates a rotation (increments version, marks rotating).
|
|
43
|
+
*/
|
|
44
|
+
proposeRotation(): number;
|
|
45
|
+
/**
|
|
46
|
+
* Called when server confirms the rotation is committed.
|
|
47
|
+
*/
|
|
48
|
+
confirmRotation(keyVersion: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Force an immediate rotation (for security incidents).
|
|
51
|
+
*/
|
|
52
|
+
forceRotation(): void;
|
|
53
|
+
private scheduleNextRotation;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=key-rotation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-rotation.d.ts","sourceRoot":"","sources":["../../src/network/key-rotation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,WAAW,CAAkB;gBAEzB,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAK/C,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,IAAI,IAAI,IAAI;IASZ;;OAEG;IACH,eAAe,IAAI,MAAM;IAOzB;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAWzC;;OAEG;IACH,aAAa,IAAI,IAAI;IAQrB,OAAO,CAAC,oBAAoB;CAgB7B"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
const DEFAULT_CONFIG = {
|
|
4
|
+
rotationIntervalMs: 24 * 60 * 60 * 1000, // 24 hours
|
|
5
|
+
jitterMs: 60 * 60 * 1000, // 1 hour jitter
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Manages periodic key rotation for WireGuard.
|
|
9
|
+
*
|
|
10
|
+
* Flow:
|
|
11
|
+
* 1. Timer fires -> emits 'rotate-needed' event
|
|
12
|
+
* 2. WireGuardManager generates new keypair
|
|
13
|
+
* 3. Agent sends agent.wg.rotate.propose to server
|
|
14
|
+
* 4. Server distributes update to peers
|
|
15
|
+
* 5. Peers ACK with agent.wg.rotate.applied
|
|
16
|
+
* 6. Server sends server.wg.rotate.commit to agent
|
|
17
|
+
* 7. Agent applies the new key on its interface
|
|
18
|
+
*
|
|
19
|
+
* Events:
|
|
20
|
+
* - 'rotate-needed' : time to rotate
|
|
21
|
+
* - 'rotate-committed' : { keyVersion } -- rotation confirmed by server
|
|
22
|
+
*/
|
|
23
|
+
export class KeyRotation extends EventEmitter {
|
|
24
|
+
config;
|
|
25
|
+
rotationTimer = null;
|
|
26
|
+
_currentVersion = 0;
|
|
27
|
+
_pendingVersion = null;
|
|
28
|
+
_isRotating = false;
|
|
29
|
+
constructor(config) {
|
|
30
|
+
super();
|
|
31
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
32
|
+
}
|
|
33
|
+
get currentVersion() {
|
|
34
|
+
return this._currentVersion;
|
|
35
|
+
}
|
|
36
|
+
get isRotating() {
|
|
37
|
+
return this._isRotating;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Start the rotation timer.
|
|
41
|
+
*/
|
|
42
|
+
start() {
|
|
43
|
+
if (this.rotationTimer)
|
|
44
|
+
return;
|
|
45
|
+
this.scheduleNextRotation();
|
|
46
|
+
logger.info(`[KeyRotation] Started with interval=${this.config.rotationIntervalMs}ms, jitter=${this.config.jitterMs}ms`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Stop the rotation timer.
|
|
50
|
+
*/
|
|
51
|
+
stop() {
|
|
52
|
+
if (this.rotationTimer) {
|
|
53
|
+
clearTimeout(this.rotationTimer);
|
|
54
|
+
this.rotationTimer = null;
|
|
55
|
+
}
|
|
56
|
+
this._isRotating = false;
|
|
57
|
+
this._pendingVersion = null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Called when the agent initiates a rotation (increments version, marks rotating).
|
|
61
|
+
*/
|
|
62
|
+
proposeRotation() {
|
|
63
|
+
this._currentVersion++;
|
|
64
|
+
this._pendingVersion = this._currentVersion;
|
|
65
|
+
this._isRotating = true;
|
|
66
|
+
return this._currentVersion;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Called when server confirms the rotation is committed.
|
|
70
|
+
*/
|
|
71
|
+
confirmRotation(keyVersion) {
|
|
72
|
+
if (this._pendingVersion === keyVersion) {
|
|
73
|
+
this._isRotating = false;
|
|
74
|
+
this._pendingVersion = null;
|
|
75
|
+
this.emit('rotate-committed', { keyVersion });
|
|
76
|
+
logger.info(`[KeyRotation] Rotation committed: v${keyVersion}`);
|
|
77
|
+
// Schedule next rotation
|
|
78
|
+
this.scheduleNextRotation();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Force an immediate rotation (for security incidents).
|
|
83
|
+
*/
|
|
84
|
+
forceRotation() {
|
|
85
|
+
if (this._isRotating) {
|
|
86
|
+
logger.warn('[KeyRotation] Already rotating, ignoring force');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.emit('rotate-needed');
|
|
90
|
+
}
|
|
91
|
+
scheduleNextRotation() {
|
|
92
|
+
if (this.rotationTimer) {
|
|
93
|
+
clearTimeout(this.rotationTimer);
|
|
94
|
+
}
|
|
95
|
+
const jitter = Math.floor(Math.random() * this.config.jitterMs);
|
|
96
|
+
const delay = this.config.rotationIntervalMs + jitter;
|
|
97
|
+
this.rotationTimer = setTimeout(() => {
|
|
98
|
+
if (!this._isRotating) {
|
|
99
|
+
this.emit('rotate-needed');
|
|
100
|
+
}
|
|
101
|
+
}, delay);
|
|
102
|
+
logger.debug(`[KeyRotation] Next rotation in ${Math.round(delay / 1000 / 60)} minutes`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=key-rotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-rotation.js","sourceRoot":"","sources":["../../src/network/key-rotation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAS5C,MAAM,cAAc,GAAsB;IACxC,kBAAkB,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,WAAW;IACpD,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAkB,gBAAgB;CAC3D,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,WAAY,SAAQ,YAAY;IACnC,MAAM,CAAoB;IAC1B,aAAa,GAA0B,IAAI,CAAC;IAC5C,eAAe,GAAW,CAAC,CAAC;IAC5B,eAAe,GAAkB,IAAI,CAAC;IACtC,WAAW,GAAY,KAAK,CAAC;IAErC,YAAY,MAAmC;QAC7C,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;IACjD,CAAC;IAED,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,aAAa;YAAE,OAAO;QAC/B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,uCAAuC,IAAI,CAAC,MAAM,CAAC,kBAAkB,cAAc,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;IAC3H,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC5B,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,eAAe;QACb,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;QAC5C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,UAAkB;QAChC,IAAI,IAAI,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;YACxC,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;YACzB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YAC9C,MAAM,CAAC,IAAI,CAAC,sCAAsC,UAAU,EAAE,CAAC,CAAC;YAChE,yBAAyB;YACzB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa;QACX,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC7B,CAAC;IAEO,oBAAoB;QAC1B,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,kBAAkB,GAAG,MAAM,CAAC;QAEtD,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAC;QAEV,MAAM,CAAC,KAAK,CAAC,kCAAkC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;IAC1F,CAAC;CACF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
export interface NatProbeConfig {
|
|
3
|
+
token: string;
|
|
4
|
+
servers: Array<{
|
|
5
|
+
host: string;
|
|
6
|
+
port: number;
|
|
7
|
+
id: 'a' | 'b';
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Handles NAT traversal probing from the agent side.
|
|
12
|
+
* Uses the WireGuard listen port to send UDP probes to discovery servers.
|
|
13
|
+
*/
|
|
14
|
+
export declare class NatTraversal extends EventEmitter {
|
|
15
|
+
private listenPort;
|
|
16
|
+
private probeSocket;
|
|
17
|
+
private probeTimeout;
|
|
18
|
+
setListenPort(port: number): void;
|
|
19
|
+
/**
|
|
20
|
+
* Execute a NAT probe: send UDP datagrams to both discovery servers
|
|
21
|
+
* from the WG listen port. Probe datagram format: "TERMIFY_PROBE:<token>"
|
|
22
|
+
*/
|
|
23
|
+
probe(config: NatProbeConfig): Promise<void>;
|
|
24
|
+
cleanup(): void;
|
|
25
|
+
shutdown(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=nat-traversal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nat-traversal.d.ts","sourceRoot":"","sources":["../../src/network/nat-traversal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,GAAG,GAAG,GAAG,CAAA;KAAE,CAAC,CAAC;CAC/D;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,YAAY,CAA+B;IAEnD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIjC;;;OAGG;IACG,KAAK,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAyClD,OAAO,IAAI,IAAI;IAWf,QAAQ,IAAI,IAAI;CAGjB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createSocket } from 'node:dgram';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
/**
|
|
5
|
+
* Handles NAT traversal probing from the agent side.
|
|
6
|
+
* Uses the WireGuard listen port to send UDP probes to discovery servers.
|
|
7
|
+
*/
|
|
8
|
+
export class NatTraversal extends EventEmitter {
|
|
9
|
+
listenPort = null;
|
|
10
|
+
probeSocket = null;
|
|
11
|
+
probeTimeout = null;
|
|
12
|
+
setListenPort(port) {
|
|
13
|
+
this.listenPort = port;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Execute a NAT probe: send UDP datagrams to both discovery servers
|
|
17
|
+
* from the WG listen port. Probe datagram format: "TERMIFY_PROBE:<token>"
|
|
18
|
+
*/
|
|
19
|
+
async probe(config) {
|
|
20
|
+
if (!this.listenPort) {
|
|
21
|
+
logger.warn('[NAT] Cannot probe: listen port not set');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Create UDP socket, try to bind to WG listen port with SO_REUSEADDR
|
|
25
|
+
try {
|
|
26
|
+
this.probeSocket = createSocket({ type: 'udp4', reuseAddr: true });
|
|
27
|
+
await new Promise((resolve, reject) => {
|
|
28
|
+
this.probeSocket.bind(this.listenPort, () => resolve());
|
|
29
|
+
this.probeSocket.once('error', reject);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Fallback: ephemeral port (less accurate but still useful)
|
|
34
|
+
logger.warn('[NAT] Could not bind to WG port, using ephemeral port');
|
|
35
|
+
this.probeSocket = createSocket({ type: 'udp4' });
|
|
36
|
+
}
|
|
37
|
+
const message = Buffer.from(`TERMIFY_PROBE:${config.token}`);
|
|
38
|
+
for (const server of config.servers) {
|
|
39
|
+
try {
|
|
40
|
+
await new Promise((resolve, reject) => {
|
|
41
|
+
this.probeSocket.send(message, 0, message.length, server.port, server.host, (err) => {
|
|
42
|
+
if (err)
|
|
43
|
+
reject(err);
|
|
44
|
+
else
|
|
45
|
+
resolve();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
logger.debug(`[NAT] Probe sent to ${server.id} (${server.host}:${server.port})`);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
logger.error(`[NAT] Failed to send probe to ${server.id}:`, err);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Close socket after packets are sent
|
|
55
|
+
this.probeTimeout = setTimeout(() => {
|
|
56
|
+
this.cleanup();
|
|
57
|
+
}, 2000);
|
|
58
|
+
}
|
|
59
|
+
cleanup() {
|
|
60
|
+
if (this.probeTimeout) {
|
|
61
|
+
clearTimeout(this.probeTimeout);
|
|
62
|
+
this.probeTimeout = null;
|
|
63
|
+
}
|
|
64
|
+
if (this.probeSocket) {
|
|
65
|
+
try {
|
|
66
|
+
this.probeSocket.close();
|
|
67
|
+
}
|
|
68
|
+
catch { /* already closed */ }
|
|
69
|
+
this.probeSocket = null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
shutdown() {
|
|
73
|
+
this.cleanup();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=nat-traversal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nat-traversal.js","sourceRoot":"","sources":["../../src/network/nat-traversal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WireGuard UAPI (Userspace API) client.
|
|
3
|
+
*
|
|
4
|
+
* Communicates with wireguard-go via its Unix domain socket at
|
|
5
|
+
* /var/run/wireguard/<iface>.sock using the UAPI text protocol.
|
|
6
|
+
*
|
|
7
|
+
* This eliminates the need for the `wg` CLI tool when using wireguard-go,
|
|
8
|
+
* enabling a fully self-contained agent (same model as Tailscale).
|
|
9
|
+
*
|
|
10
|
+
* Protocol spec: https://www.wireguard.com/xplatform/#configuration-protocol
|
|
11
|
+
*/
|
|
12
|
+
import type { WgHealthSnapshot } from './wireguard-backend.js';
|
|
13
|
+
/**
|
|
14
|
+
* Convert a WireGuard base64 key to hex (UAPI requires hex-encoded keys).
|
|
15
|
+
*/
|
|
16
|
+
export declare function wgKeyToHex(base64Key: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Convert a hex-encoded key back to WireGuard base64 format.
|
|
19
|
+
*/
|
|
20
|
+
export declare function hexToWgKey(hexKey: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Configure the WireGuard interface (private key + listen port).
|
|
23
|
+
* Equivalent to: wg set <iface> private-key <path> listen-port <port>
|
|
24
|
+
*/
|
|
25
|
+
export declare function uapiSetInterface(iface: string, privateKeyBase64: string, listenPort: number): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Add or update a peer.
|
|
28
|
+
* Equivalent to: wg set <iface> peer <pubkey> allowed-ips <ips> endpoint <ep> persistent-keepalive <ka>
|
|
29
|
+
*/
|
|
30
|
+
export declare function uapiAddPeer(iface: string, publicKeyBase64: string, allowedIps: string, persistentKeepalive: number, endpoint?: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Remove a peer by its public key.
|
|
33
|
+
* Equivalent to: wg set <iface> peer <pubkey> remove
|
|
34
|
+
*/
|
|
35
|
+
export declare function uapiRemovePeer(iface: string, publicKeyBase64: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Update only the endpoint of an existing peer.
|
|
38
|
+
* Equivalent to: wg set <iface> peer <pubkey> endpoint <ep>
|
|
39
|
+
*/
|
|
40
|
+
export declare function uapiUpdatePeerEndpoint(iface: string, publicKeyBase64: string, endpoint: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Get the full interface status (self + all peers).
|
|
43
|
+
* Equivalent to: wg show <iface> dump
|
|
44
|
+
*
|
|
45
|
+
* Note: UAPI GET response contains private_key and listen_port for the
|
|
46
|
+
* interface section, then each peer starts with a public_key line.
|
|
47
|
+
* The interface's own public key is derived from the private key.
|
|
48
|
+
*/
|
|
49
|
+
export declare function uapiGetStatus(iface: string): Promise<WgHealthSnapshot>;
|
|
50
|
+
//# sourceMappingURL=uapi-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uapi-client.d.ts","sourceRoot":"","sources":["../../src/network/uapi-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,wBAAwB,CAAC;AAM7E;;GAEG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AA+DD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+H5E"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WireGuard UAPI (Userspace API) client.
|
|
3
|
+
*
|
|
4
|
+
* Communicates with wireguard-go via its Unix domain socket at
|
|
5
|
+
* /var/run/wireguard/<iface>.sock using the UAPI text protocol.
|
|
6
|
+
*
|
|
7
|
+
* This eliminates the need for the `wg` CLI tool when using wireguard-go,
|
|
8
|
+
* enabling a fully self-contained agent (same model as Tailscale).
|
|
9
|
+
*
|
|
10
|
+
* Protocol spec: https://www.wireguard.com/xplatform/#configuration-protocol
|
|
11
|
+
*/
|
|
12
|
+
import { createConnection } from 'node:net';
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Key encoding helpers
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
/**
|
|
18
|
+
* Convert a WireGuard base64 key to hex (UAPI requires hex-encoded keys).
|
|
19
|
+
*/
|
|
20
|
+
export function wgKeyToHex(base64Key) {
|
|
21
|
+
return Buffer.from(base64Key, 'base64').toString('hex');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert a hex-encoded key back to WireGuard base64 format.
|
|
25
|
+
*/
|
|
26
|
+
export function hexToWgKey(hexKey) {
|
|
27
|
+
return Buffer.from(hexKey, 'hex').toString('base64');
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Socket communication
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
const SOCKET_DIR = '/var/run/wireguard';
|
|
33
|
+
function socketPath(iface) {
|
|
34
|
+
return `${SOCKET_DIR}/${iface}.sock`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Send a UAPI request and read the full response.
|
|
38
|
+
* Returns the raw response string.
|
|
39
|
+
*/
|
|
40
|
+
async function uapiRequest(iface, request) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const sock = createConnection(socketPath(iface));
|
|
43
|
+
let response = '';
|
|
44
|
+
sock.on('connect', () => {
|
|
45
|
+
sock.write(request);
|
|
46
|
+
});
|
|
47
|
+
sock.on('data', (data) => {
|
|
48
|
+
response += data.toString();
|
|
49
|
+
});
|
|
50
|
+
sock.on('end', () => {
|
|
51
|
+
resolve(response);
|
|
52
|
+
});
|
|
53
|
+
sock.on('error', (err) => {
|
|
54
|
+
reject(new Error(`UAPI socket error (${iface}): ${err.message}`));
|
|
55
|
+
});
|
|
56
|
+
// Safety timeout
|
|
57
|
+
sock.setTimeout(5000, () => {
|
|
58
|
+
sock.destroy();
|
|
59
|
+
reject(new Error(`UAPI socket timeout (${iface})`));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Parse errno from UAPI response. Returns 0 on success, throws on error.
|
|
65
|
+
*/
|
|
66
|
+
function checkErrno(response, operation) {
|
|
67
|
+
const match = /^errno=(\d+)$/m.exec(response);
|
|
68
|
+
if (!match) {
|
|
69
|
+
throw new Error(`UAPI ${operation}: no errno in response`);
|
|
70
|
+
}
|
|
71
|
+
const errno = parseInt(match[1], 10);
|
|
72
|
+
if (errno !== 0) {
|
|
73
|
+
throw new Error(`UAPI ${operation} failed: errno=${errno}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Public API
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
/**
|
|
80
|
+
* Configure the WireGuard interface (private key + listen port).
|
|
81
|
+
* Equivalent to: wg set <iface> private-key <path> listen-port <port>
|
|
82
|
+
*/
|
|
83
|
+
export async function uapiSetInterface(iface, privateKeyBase64, listenPort) {
|
|
84
|
+
const request = `set=1\n` +
|
|
85
|
+
`private_key=${wgKeyToHex(privateKeyBase64)}\n` +
|
|
86
|
+
`listen_port=${listenPort}\n` +
|
|
87
|
+
`\n`;
|
|
88
|
+
const response = await uapiRequest(iface, request);
|
|
89
|
+
checkErrno(response, 'setInterface');
|
|
90
|
+
logger.debug('[UAPI] Interface configured: port=' + listenPort);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Add or update a peer.
|
|
94
|
+
* Equivalent to: wg set <iface> peer <pubkey> allowed-ips <ips> endpoint <ep> persistent-keepalive <ka>
|
|
95
|
+
*/
|
|
96
|
+
export async function uapiAddPeer(iface, publicKeyBase64, allowedIps, persistentKeepalive, endpoint) {
|
|
97
|
+
let request = `set=1\n` +
|
|
98
|
+
`public_key=${wgKeyToHex(publicKeyBase64)}\n`;
|
|
99
|
+
if (endpoint) {
|
|
100
|
+
request += `endpoint=${endpoint}\n`;
|
|
101
|
+
}
|
|
102
|
+
// allowed_ips: each CIDR on its own line
|
|
103
|
+
const ips = allowedIps.split(',').map((s) => s.trim());
|
|
104
|
+
for (const ip of ips) {
|
|
105
|
+
request += `allowed_ip=${ip}\n`;
|
|
106
|
+
}
|
|
107
|
+
request += `persistent_keepalive_interval=${persistentKeepalive}\n`;
|
|
108
|
+
request += `\n`;
|
|
109
|
+
const response = await uapiRequest(iface, request);
|
|
110
|
+
checkErrno(response, 'addPeer');
|
|
111
|
+
logger.debug('[UAPI] Peer added: ' + publicKeyBase64.slice(0, 8) + '...');
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Remove a peer by its public key.
|
|
115
|
+
* Equivalent to: wg set <iface> peer <pubkey> remove
|
|
116
|
+
*/
|
|
117
|
+
export async function uapiRemovePeer(iface, publicKeyBase64) {
|
|
118
|
+
const request = `set=1\n` +
|
|
119
|
+
`public_key=${wgKeyToHex(publicKeyBase64)}\n` +
|
|
120
|
+
`remove=true\n` +
|
|
121
|
+
`\n`;
|
|
122
|
+
const response = await uapiRequest(iface, request);
|
|
123
|
+
checkErrno(response, 'removePeer');
|
|
124
|
+
logger.debug('[UAPI] Peer removed: ' + publicKeyBase64.slice(0, 8) + '...');
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Update only the endpoint of an existing peer.
|
|
128
|
+
* Equivalent to: wg set <iface> peer <pubkey> endpoint <ep>
|
|
129
|
+
*/
|
|
130
|
+
export async function uapiUpdatePeerEndpoint(iface, publicKeyBase64, endpoint) {
|
|
131
|
+
const request = `set=1\n` +
|
|
132
|
+
`public_key=${wgKeyToHex(publicKeyBase64)}\n` +
|
|
133
|
+
`endpoint=${endpoint}\n` +
|
|
134
|
+
`\n`;
|
|
135
|
+
const response = await uapiRequest(iface, request);
|
|
136
|
+
checkErrno(response, 'updatePeerEndpoint');
|
|
137
|
+
logger.debug('[UAPI] Endpoint updated for peer ' + publicKeyBase64.slice(0, 8) + '...');
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the full interface status (self + all peers).
|
|
141
|
+
* Equivalent to: wg show <iface> dump
|
|
142
|
+
*
|
|
143
|
+
* Note: UAPI GET response contains private_key and listen_port for the
|
|
144
|
+
* interface section, then each peer starts with a public_key line.
|
|
145
|
+
* The interface's own public key is derived from the private key.
|
|
146
|
+
*/
|
|
147
|
+
export async function uapiGetStatus(iface) {
|
|
148
|
+
const request = `get=1\n\n`;
|
|
149
|
+
let response;
|
|
150
|
+
try {
|
|
151
|
+
response = await uapiRequest(iface, request);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return {
|
|
155
|
+
interfaceUp: false,
|
|
156
|
+
publicKey: '',
|
|
157
|
+
listenPort: 0,
|
|
158
|
+
peers: [],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
checkErrno(response, 'getStatus');
|
|
162
|
+
const lines = response.trim().split('\n');
|
|
163
|
+
let privateKeyHex = '';
|
|
164
|
+
let listenPort = 0;
|
|
165
|
+
const peers = [];
|
|
166
|
+
let currentPeer = null;
|
|
167
|
+
for (const line of lines) {
|
|
168
|
+
if (line.startsWith('errno='))
|
|
169
|
+
continue;
|
|
170
|
+
const eqIdx = line.indexOf('=');
|
|
171
|
+
if (eqIdx === -1)
|
|
172
|
+
continue;
|
|
173
|
+
const key = line.substring(0, eqIdx);
|
|
174
|
+
const value = line.substring(eqIdx + 1);
|
|
175
|
+
switch (key) {
|
|
176
|
+
case 'private_key':
|
|
177
|
+
privateKeyHex = value;
|
|
178
|
+
break;
|
|
179
|
+
case 'listen_port':
|
|
180
|
+
if (!currentPeer) {
|
|
181
|
+
listenPort = parseInt(value, 10);
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
case 'public_key':
|
|
185
|
+
// Every public_key line in UAPI GET marks the start of a new peer
|
|
186
|
+
if (currentPeer) {
|
|
187
|
+
peers.push(currentPeer);
|
|
188
|
+
}
|
|
189
|
+
currentPeer = {
|
|
190
|
+
publicKey: hexToWgKey(value),
|
|
191
|
+
allowedIps: '',
|
|
192
|
+
transferRx: 0,
|
|
193
|
+
transferTx: 0,
|
|
194
|
+
};
|
|
195
|
+
break;
|
|
196
|
+
case 'endpoint':
|
|
197
|
+
if (currentPeer && value && value !== '(none)') {
|
|
198
|
+
currentPeer.endpoint = value;
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
case 'allowed_ip':
|
|
202
|
+
if (currentPeer) {
|
|
203
|
+
currentPeer.allowedIps = currentPeer.allowedIps
|
|
204
|
+
? currentPeer.allowedIps + ',' + value
|
|
205
|
+
: value;
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
208
|
+
case 'last_handshake_time_sec': {
|
|
209
|
+
if (currentPeer) {
|
|
210
|
+
const epoch = parseInt(value, 10);
|
|
211
|
+
if (epoch > 0) {
|
|
212
|
+
currentPeer.latestHandshake = new Date(epoch * 1000);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
case 'rx_bytes':
|
|
218
|
+
if (currentPeer) {
|
|
219
|
+
currentPeer.transferRx = parseInt(value, 10);
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
case 'tx_bytes':
|
|
223
|
+
if (currentPeer) {
|
|
224
|
+
currentPeer.transferTx = parseInt(value, 10);
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
default:
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Push last peer
|
|
232
|
+
if (currentPeer) {
|
|
233
|
+
peers.push(currentPeer);
|
|
234
|
+
}
|
|
235
|
+
// Derive public key from private key using X25519
|
|
236
|
+
let publicKey = '';
|
|
237
|
+
if (privateKeyHex) {
|
|
238
|
+
try {
|
|
239
|
+
const { createPublicKey, createPrivateKey } = await import('node:crypto');
|
|
240
|
+
// Build PKCS#8 DER: 16-byte header + 32-byte raw private key
|
|
241
|
+
const privRaw = Buffer.from(privateKeyHex, 'hex');
|
|
242
|
+
const pkcs8Header = Buffer.from('302e020100300506032b656e04220420', 'hex');
|
|
243
|
+
const pkcs8Der = Buffer.concat([pkcs8Header, privRaw]);
|
|
244
|
+
const privKeyObj = createPrivateKey({ key: pkcs8Der, format: 'der', type: 'pkcs8' });
|
|
245
|
+
const pubKeyObj = createPublicKey(privKeyObj);
|
|
246
|
+
const spkiDer = pubKeyObj.export({ type: 'spki', format: 'der' });
|
|
247
|
+
publicKey = spkiDer.subarray(12).toString('base64');
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
// If derivation fails, leave empty — caller can fill from state store
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
interfaceUp: true,
|
|
255
|
+
publicKey,
|
|
256
|
+
listenPort,
|
|
257
|
+
peers,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=uapi-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uapi-client.js","sourceRoot":"","sources":["../../src/network/uapi-client.ts"],"names":[],"mappings":"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"}
|