@decentnetwork/lan 0.1.149 → 0.1.150
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
|
|
@@ -131,9 +131,17 @@ export class ConnectProxy {
|
|
|
131
131
|
}
|
|
132
132
|
const host = m[1];
|
|
133
133
|
const port = Number(m[2]);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
// Port policy: an EXPLICIT allowConnectPorts restricts to that list; UNSET
|
|
135
|
+
// (the default) allows any port except known-abuse ones (SMTP). The old
|
|
136
|
+
// default of [443,80] silently broke real apps that use non-standard ports
|
|
137
|
+
// (verified: the CCTV/Migu app's uem.migu.cn:18088 got 403'd here while the
|
|
138
|
+
// host itself was perfectly reachable). These are friend-gated private
|
|
139
|
+
// exits, so blanket port blocking bought little and cost app compatibility.
|
|
140
|
+
const DENY_PORTS = new Set([25, 465, 587]); // SMTP — block spam relay abuse
|
|
141
|
+
const allowedPorts = this.opts.allowConnectPorts;
|
|
142
|
+
const portBlocked = allowedPorts ? !allowedPorts.includes(port) : DENY_PORTS.has(port);
|
|
143
|
+
if (portBlocked) {
|
|
144
|
+
this.refuse(clientSocket, src, srcName, `${host}:${port}`, 403, `port ${port} not permitted`);
|
|
137
145
|
return;
|
|
138
146
|
}
|
|
139
147
|
const allowHosts = this.opts.allowHosts ?? [];
|
|
@@ -386,8 +386,14 @@ export function startMultiExitRouter(opts) {
|
|
|
386
386
|
// Unmeasured exits assume the region's median (or a neutral default) so a
|
|
387
387
|
// new exit is tried but doesn't monopolize before it's proven.
|
|
388
388
|
const measuredVals = pool.map((e) => e.speedEwma).filter((v) => v !== null).sort((a, b) => a - b);
|
|
389
|
-
|
|
390
|
-
|
|
389
|
+
// Unmeasured exits get a PESSIMISTIC assumption (the region's slowest proven
|
|
390
|
+
// speed, or a low floor) — NOT the median. A long-lived video tunnel pins to
|
|
391
|
+
// ONE exit for its whole duration, so it must land on a PROVEN-fast exit, not
|
|
392
|
+
// an unproven one that might turn out to be 0.3 Mbps and stall the player.
|
|
393
|
+
// Unproven exits still get overflow traffic once the proven ones fill up,
|
|
394
|
+
// which measures them safely without risking the video.
|
|
395
|
+
const unprovenBps = measuredVals.length > 0 ? measuredVals[0] : 800_000;
|
|
396
|
+
const score = (e) => (e.speedEwma ?? unprovenBps) / (e.active + 1);
|
|
391
397
|
return [...pool].sort((a, b) => score(b) - score(a) || a.served - b.served);
|
|
392
398
|
}
|
|
393
399
|
// Whether ANY exit is configured for a region (healthy or not). Lets us tell
|
|
@@ -399,11 +405,16 @@ export function startMultiExitRouter(opts) {
|
|
|
399
405
|
function forward(exit, target, client, head, onFail) {
|
|
400
406
|
const up = net.connect(exit.port, exit.host);
|
|
401
407
|
let established = false;
|
|
402
|
-
const fail = (why) => {
|
|
408
|
+
const fail = (why, tripExit = true) => {
|
|
403
409
|
if (!established) {
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
|
|
410
|
+
// Only a CONNECTION-level failure (exit unreachable: timeout / conn
|
|
411
|
+
// error) is an EXIT fault → feed the breaker. An UPSTREAM status (the
|
|
412
|
+
// exit answered but the ORIGIN returned 502/403/etc.) is the origin's
|
|
413
|
+
// problem — it fails identically on every exit, so tripping the exit for
|
|
414
|
+
// it churns the whole pool (a single dead host like sdc3.10086.cn or
|
|
415
|
+
// uem.migu.cn was knocking out all 6 China exits). Just fail over.
|
|
416
|
+
if (tripExit)
|
|
417
|
+
recordStall(exit, why);
|
|
407
418
|
up.destroy();
|
|
408
419
|
onFail(why);
|
|
409
420
|
}
|
|
@@ -499,7 +510,8 @@ export function startMultiExitRouter(opts) {
|
|
|
499
510
|
up.on("error", () => client.destroy());
|
|
500
511
|
}
|
|
501
512
|
else {
|
|
502
|
-
|
|
513
|
+
// Exit answered but the ORIGIN errored (502/403/…) — not an exit fault.
|
|
514
|
+
fail(`upstream ${status}`, false);
|
|
503
515
|
}
|
|
504
516
|
};
|
|
505
517
|
up.on("data", onData);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/lan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.150",
|
|
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",
|