@decentnetwork/peer 0.1.65 → 0.1.67

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.
Files changed (2) hide show
  1. package/dist/peer.js +22 -8
  2. package/package.json +1 -1
package/dist/peer.js CHANGED
@@ -1647,15 +1647,19 @@ export class Peer {
1647
1647
  }
1648
1648
  else {
1649
1649
  // Adopt the source as our send endpoint — but NEVER downgrade from a
1650
- // same-LAN (physical) path to a non-LAN source (a hairpin packet via
1651
- // the peer's public / Tailscale-exit endpoint must not knock us off
1650
+ // locked same-LAN (physical) path to a non-LAN source (a hairpin packet
1651
+ // via the peer's public / Tailscale-exit endpoint must not knock us off
1652
1652
  // the direct LAN path, which is strictly better).
1653
- const cur = state.remote?.host;
1654
- const onSameLanAlready = !!cur && !cur.startsWith("tcp:") && isPrivateAddress(cur) && !isCgnatAddress(cur) &&
1655
- getPhysicalLanSubnets().some((s) => isInIpv4Subnet(cur, s));
1656
- const incomingSameLan = isPrivateAddress(remote.address) && !isCgnatAddress(remote.address) &&
1657
- getPhysicalLanSubnets().some((s) => isInIpv4Subnet(remote.address, s));
1658
- if (incomingSameLan || !onSameLanAlready) {
1653
+ //
1654
+ // CCTV-safe: the LAN decision (which needs a networkInterfaces() syscall)
1655
+ // is made ONLY in the periodic offer/maintenance paths, which record the
1656
+ // locked peer LAN host in state.lanRemoteHost. Here in the per-packet hot
1657
+ // path we do a single string compare — NO interface syscall — so a
1658
+ // high-rate stream (CCTV: thousands of packets/sec) never pays for it.
1659
+ // (The per-packet getPhysicalLanSubnets() call this replaces was the
1660
+ // CCTV CPU regression.)
1661
+ const lockedOnLan = !!state.lanRemoteHost && state.remote?.host === state.lanRemoteHost;
1662
+ if (!lockedOnLan || remote.address === state.lanRemoteHost) {
1659
1663
  state.remote = { host: remote.address, port: remote.port };
1660
1664
  }
1661
1665
  if (!state.lastUdpRecvMs) {
@@ -3423,6 +3427,9 @@ export class Peer {
3423
3427
  if (!onSameLanAlready) {
3424
3428
  session.remote = { host: lanHost, port: lanPort };
3425
3429
  }
3430
+ // Record the locked LAN host so the per-packet receive path can refuse a
3431
+ // public/hairpin downgrade with a plain string compare (no syscall).
3432
+ session.lanRemoteHost = lanHost;
3426
3433
  if (session.established) {
3427
3434
  void this.#sendMessengerPacket(friendId, PACKET_ID_ALIVE, new Uint8Array()).catch(() => undefined);
3428
3435
  }
@@ -4057,6 +4064,12 @@ export class Peer {
4057
4064
  const r = session.remote;
4058
4065
  const remoteIsSameLan = !!r && isPrivateAddress(r.host) && !isCgnatAddress(r.host) &&
4059
4066
  getPhysicalLanSubnets().some((s) => isInIpv4Subnet(r.host, s));
4067
+ if (remoteIsSameLan) {
4068
+ // Already on a physical-LAN path (e.g. the session established directly
4069
+ // over LAN). Lock it so the per-packet hot path's cheap string-compare
4070
+ // guard refuses any later public/hairpin downgrade — no syscall there.
4071
+ session.lanRemoteHost = r.host;
4072
+ }
4060
4073
  if (!remoteIsSameLan) {
4061
4074
  // If we ALREADY hold a same-LAN candidate for this peer (learned from
4062
4075
  // an earlier offer), switch the session onto it NOW — don't wait to
@@ -4069,6 +4082,7 @@ export class Peer {
4069
4082
  getPhysicalLanSubnets().some((s) => isInIpv4Subnet(c.host, s)));
4070
4083
  if (lanCand) {
4071
4084
  session.remote = { host: lanCand.host, port: lanCand.port };
4085
+ session.lanRemoteHost = lanCand.host;
4072
4086
  void this.#sendMessengerPacket(friendId, PACKET_ID_ALIVE, new Uint8Array()).catch(() => undefined);
4073
4087
  }
4074
4088
  void this.#sendUdpEndpointOffer(friendId).catch(() => undefined);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.65",
3
+ "version": "0.1.67",
4
4
  "description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",