@decentnetwork/lan 0.1.81 → 0.1.82
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.
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/daemon/server.d.ts
CHANGED
|
@@ -42,6 +42,15 @@ export declare class DaemonServer {
|
|
|
42
42
|
private pidFile?;
|
|
43
43
|
private configDir;
|
|
44
44
|
constructor(opts: DaemonOptions);
|
|
45
|
+
/**
|
|
46
|
+
* Swap the live TUN to a new IP without restarting the daemon. Called when
|
|
47
|
+
* dora's background registration allocates an IP different from the
|
|
48
|
+
* deterministic fallback the TUN started on. Idempotent (no-op if already at
|
|
49
|
+
* newIp). ORDER MATTERS: close the TunDevice FIRST so the helper subprocess
|
|
50
|
+
* exits and releases the device — otherwise routeManager.cleanup's tuntap
|
|
51
|
+
* del races the kernel (EBUSY) and the respawn leaves the daemon TUN-less.
|
|
52
|
+
*/
|
|
53
|
+
private reconfigureTunTo;
|
|
45
54
|
start(): Promise<void>;
|
|
46
55
|
stop(): Promise<void>;
|
|
47
56
|
/**
|
package/dist/daemon/server.js
CHANGED
|
@@ -66,6 +66,49 @@ export class DaemonServer {
|
|
|
66
66
|
this.configDir = opts.configDir ?? ConfigLoader.defaultConfigDir();
|
|
67
67
|
this.logger = new Logger({ prefix: "Daemon" });
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Swap the live TUN to a new IP without restarting the daemon. Called when
|
|
71
|
+
* dora's background registration allocates an IP different from the
|
|
72
|
+
* deterministic fallback the TUN started on. Idempotent (no-op if already at
|
|
73
|
+
* newIp). ORDER MATTERS: close the TunDevice FIRST so the helper subprocess
|
|
74
|
+
* exits and releases the device — otherwise routeManager.cleanup's tuntap
|
|
75
|
+
* del races the kernel (EBUSY) and the respawn leaves the daemon TUN-less.
|
|
76
|
+
*/
|
|
77
|
+
async reconfigureTunTo(newIp) {
|
|
78
|
+
if (!this.tunDevice || !this.routeManager)
|
|
79
|
+
return;
|
|
80
|
+
const currentIp = this.tunDevice.getConfig().ip;
|
|
81
|
+
if (currentIp === newIp)
|
|
82
|
+
return;
|
|
83
|
+
this.logger.info(`Reconfiguring TUN: allocated IP changed ${currentIp} -> ${newIp}`);
|
|
84
|
+
const ifname = this.tunDevice.getInterface();
|
|
85
|
+
try {
|
|
86
|
+
await this.tunDevice.close();
|
|
87
|
+
await this.routeManager.cleanup(ifname, this.config.network.subnet, currentIp);
|
|
88
|
+
this.tunDevice = new TunDevice({
|
|
89
|
+
config: {
|
|
90
|
+
name: this.config.network.interface,
|
|
91
|
+
ip: newIp,
|
|
92
|
+
subnet: this.config.network.subnet,
|
|
93
|
+
},
|
|
94
|
+
mockMode: this.useMockTun,
|
|
95
|
+
});
|
|
96
|
+
await this.tunDevice.open();
|
|
97
|
+
if (!this.useMockTun) {
|
|
98
|
+
await this.routeManager.configureTun({
|
|
99
|
+
...this.tunDevice.getConfig(),
|
|
100
|
+
name: this.tunDevice.getInterface(),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Re-attach the packet-router's TUN listener — it was bound to the old
|
|
104
|
+
// TunDevice instance.
|
|
105
|
+
this.packetRouter?.swapTunDevice(this.tunDevice);
|
|
106
|
+
this.logger.info(`TUN now at ${newIp}`);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
this.logger.error(`Failed to reconfigure TUN to ${newIp}: ${err instanceof Error ? err.message : err}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
69
112
|
async start() {
|
|
70
113
|
if (this.isRunning) {
|
|
71
114
|
throw new Error("Daemon already running");
|
|
@@ -340,56 +383,20 @@ export class DaemonServer {
|
|
|
340
383
|
// at 10.86.1.15 — other peers route to .15, our kernel
|
|
341
384
|
// doesn't recognize it as local, packets drop. Rebuild
|
|
342
385
|
// the TUN at the new IP so traffic actually reaches us.
|
|
343
|
-
onAllocatedIpChanged:
|
|
344
|
-
if (!this.tunDevice || !this.routeManager)
|
|
345
|
-
return;
|
|
346
|
-
const currentIp = this.tunDevice.getConfig().ip;
|
|
347
|
-
if (currentIp === newIp)
|
|
348
|
-
return;
|
|
349
|
-
this.logger.info(`Reconfiguring TUN: dora-allocated IP changed ${currentIp} -> ${newIp}`);
|
|
350
|
-
const ifname = this.tunDevice.getInterface();
|
|
351
|
-
try {
|
|
352
|
-
// ORDER MATTERS: close TunDevice FIRST so the helper
|
|
353
|
-
// subprocess fully exits and releases agentnet0.
|
|
354
|
-
// routeManager.cleanup's `ip tuntap del` would otherwise
|
|
355
|
-
// fail with EBUSY and the subsequent helper spawn would
|
|
356
|
-
// race the kernel for the device name, exit code=1, and
|
|
357
|
-
// leave the daemon TUN-less. tunDevice.close() now waits
|
|
358
|
-
// for actual process exit.
|
|
359
|
-
await this.tunDevice.close();
|
|
360
|
-
await this.routeManager.cleanup(ifname, this.config.network.subnet, currentIp);
|
|
361
|
-
this.tunDevice = new TunDevice({
|
|
362
|
-
config: {
|
|
363
|
-
name: this.config.network.interface,
|
|
364
|
-
ip: newIp,
|
|
365
|
-
subnet: this.config.network.subnet,
|
|
366
|
-
},
|
|
367
|
-
mockMode: this.useMockTun,
|
|
368
|
-
});
|
|
369
|
-
await this.tunDevice.open();
|
|
370
|
-
if (!this.useMockTun) {
|
|
371
|
-
await this.routeManager.configureTun({
|
|
372
|
-
...this.tunDevice.getConfig(),
|
|
373
|
-
name: this.tunDevice.getInterface(),
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
// Re-attach the packet-router's TUN listener — the
|
|
377
|
-
// listener was bound to the old TunDevice instance.
|
|
378
|
-
this.packetRouter?.swapTunDevice(this.tunDevice);
|
|
379
|
-
this.logger.info(`TUN now at ${newIp}`);
|
|
380
|
-
}
|
|
381
|
-
catch (err) {
|
|
382
|
-
this.logger.error(`Failed to reconfigure TUN to ${newIp}: ${err instanceof Error ? err.message : err}`);
|
|
383
|
-
}
|
|
384
|
-
},
|
|
386
|
+
onAllocatedIpChanged: (newIp) => this.reconfigureTunTo(newIp),
|
|
385
387
|
});
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
388
|
+
// Do NOT block the data plane on dora. The TUN opens immediately on the
|
|
389
|
+
// deterministic fallback IP (step 7 below); dora registration runs in
|
|
390
|
+
// the background (started after the TUN is up) and swaps the TUN to its
|
|
391
|
+
// allocated IP via reconfigureTunTo when/if it answers. Previously this
|
|
392
|
+
// awaited up to a 30s dora-reachability timeout BEFORE opening the TUN,
|
|
393
|
+
// so a node on a slow path (the exact China→abroad case we exist for)
|
|
394
|
+
// had no data plane for half a minute on every start.
|
|
391
395
|
}
|
|
392
|
-
// 7. Setup TUN device + routing
|
|
396
|
+
// 7. Setup TUN device + routing immediately on the deterministic
|
|
397
|
+
// fallback IP — the data plane must NOT wait on dora. If dora later
|
|
398
|
+
// hands us a different IP, the backgrounded bootstrap below swaps the
|
|
399
|
+
// TUN via reconfigureTunTo.
|
|
393
400
|
this.routeManager = new RouteManager();
|
|
394
401
|
this.tunDevice = new TunDevice({
|
|
395
402
|
config: {
|
|
@@ -411,6 +418,21 @@ export class DaemonServer {
|
|
|
411
418
|
name: actualName,
|
|
412
419
|
});
|
|
413
420
|
}
|
|
421
|
+
// Data plane is now LIVE on the fallback IP. Kick dora registration in
|
|
422
|
+
// the background — it never blocks startup. When it answers (initial
|
|
423
|
+
// register or a later retry), reconfigureTunTo swaps the TUN to dora's
|
|
424
|
+
// allocated IP. A slow/unreachable dora just means we keep the
|
|
425
|
+
// deterministic fallback, which is already routable.
|
|
426
|
+
if (this.doraIntegration) {
|
|
427
|
+
const fallbackIp = tunIp;
|
|
428
|
+
void this.doraIntegration
|
|
429
|
+
.bootstrap()
|
|
430
|
+
.then(async (doraIp) => {
|
|
431
|
+
if (doraIp && doraIp !== fallbackIp)
|
|
432
|
+
await this.reconfigureTunTo(doraIp);
|
|
433
|
+
})
|
|
434
|
+
.catch((err) => this.logger.warn(`dora bootstrap (background): ${err instanceof Error ? err.message : err}`));
|
|
435
|
+
}
|
|
414
436
|
// Live friend-request handling. The daemon stays up and accepts
|
|
415
437
|
// (or queues) every incoming request — no `friend-accept --wait`
|
|
416
438
|
// ceremony where the operator has to stop the daemon. Default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/lan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.82",
|
|
4
4
|
"description": "Private virtual LAN for self-hosted services and AI agents, built on Elastos Carrier. NAT-traversal, name service, ACL, all over a peer-to-peer mesh — no public IP required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"@decentnetwork/dora": "^0.1.6",
|
|
80
|
-
"@decentnetwork/peer": "^0.1.
|
|
80
|
+
"@decentnetwork/peer": "^0.1.36",
|
|
81
81
|
"js-yaml": "^4.1.0",
|
|
82
82
|
"yargs": "^17.7.2"
|
|
83
83
|
},
|