@decentnetwork/lan 0.1.27 → 0.1.28

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
@@ -218,9 +218,29 @@ export class DaemonServer {
218
218
  // 6. Optional dora (DHCP-style) registration. When enabled and the
219
219
  // server is reachable, dora hands us a virtual IP and tells us
220
220
  // who else is on the network — eliminating the manual ipam.yaml
221
- // sync between operators. On any failure we fall through to the
222
- // IP already loaded from config + ipam.yaml.
221
+ // sync between operators.
222
+ //
223
+ // Fallback policy when dora is unreachable: DON'T use
224
+ // config.network.ip blindly. `agentnet init` defaults every
225
+ // fresh install to 10.86.1.10, so two new peers that can't
226
+ // reach dora will BOTH claim the same fallback and silently
227
+ // collide — symptom seen in the wild as packets going to the
228
+ // wrong daemon and 100% loss to legitimate peers. Use the
229
+ // deterministic-from-userid IP instead (sha256(userid) → last
230
+ // two octets of 10.86.X.Y). That guarantees every peer gets a
231
+ // unique IP keyed off identity, with no shared default to
232
+ // collide on. If dora comes up later, the
233
+ // onAllocatedIpChanged callback swaps the TUN to dora's value.
223
234
  let tunIp = this.config.network.ip;
235
+ const ownUserid = this.peerManager.getPubkey();
236
+ const deterministicFallback = Ipam.deterministicIpForUserid(ownUserid);
237
+ if (tunIp === "10.86.1.10" || !tunIp) {
238
+ // The init-default fallback IP — every fresh decentlan installs with
239
+ // this. Override with a per-identity deterministic value before
240
+ // dora even gets to try.
241
+ tunIp = deterministicFallback;
242
+ this.logger.info(`Using deterministic fallback IP ${tunIp} (derived from userid; avoids the 10.86.1.10 init-default collision)`);
243
+ }
224
244
  if (this.config.dora?.enabled && (this.config.dora.userids?.length ?? 0) > 0) {
225
245
  // Need to be on the Carrier network before dora can talk to its
226
246
  // server. Wait synchronously here — without joinNetwork the
@@ -234,7 +254,11 @@ export class DaemonServer {
234
254
  peerManager: this.peerManager,
235
255
  ipam: this.ipam,
236
256
  nodeName: this.config.node.name,
237
- preferredIp: this.config.network.ip,
257
+ // Hand dora our deterministic fallback as the requestedIp so
258
+ // a successful register returns the same IP across restarts
259
+ // (avoids the dora-stole-someone-else's-IP race that bit us
260
+ // when ubuntu was momentarily offline during reallocation).
261
+ preferredIp: tunIp,
238
262
  // Fires when dora's background retry eventually succeeds
239
263
  // AFTER the initial bootstrap already returned the fallback
240
264
  // IP. At that point the TUN is up on the fallback (e.g.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/lan",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
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",