@libp2p/upnp-nat 2.0.12-b248eefc0 → 2.0.12-bc90b4fd5
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/src/check-external-address.d.ts +2 -2
- package/dist/src/check-external-address.d.ts.map +1 -1
- package/dist/src/check-external-address.js +6 -22
- package/dist/src/check-external-address.js.map +1 -1
- package/dist/src/index.d.ts +0 -18
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/upnp-nat.d.ts +7 -5
- package/dist/src/upnp-nat.d.ts.map +1 -1
- package/dist/src/upnp-nat.js +43 -49
- package/dist/src/upnp-nat.js.map +1 -1
- package/package.json +7 -7
- package/src/check-external-address.ts +7 -26
- package/src/index.ts +0 -20
- package/src/upnp-nat.ts +55 -56
|
@@ -9,11 +9,11 @@ export interface ExternalAddressCheckerComponents {
|
|
|
9
9
|
export interface ExternalAddressCheckerInit {
|
|
10
10
|
interval?: number;
|
|
11
11
|
timeout?: number;
|
|
12
|
-
|
|
12
|
+
onExternalAddressChange?(newExternalAddress: string): void;
|
|
13
13
|
}
|
|
14
14
|
export interface ExternalAddress {
|
|
15
15
|
getPublicIp(options?: AbortOptions): Promise<string> | string;
|
|
16
16
|
}
|
|
17
|
-
export declare function dynamicExternalAddress(components: ExternalAddressCheckerComponents, init
|
|
17
|
+
export declare function dynamicExternalAddress(components: ExternalAddressCheckerComponents, init: ExternalAddressCheckerInit): ExternalAddress;
|
|
18
18
|
export declare function staticExternalAddress(address: string): ExternalAddress;
|
|
19
19
|
//# sourceMappingURL=check-external-address.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-external-address.d.ts","sourceRoot":"","sources":["../../src/check-external-address.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check-external-address.d.ts","sourceRoot":"","sources":["../../src/check-external-address.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAqB,MAAM,mBAAmB,CAAA;AACzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAIhE,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,cAAc,CAAA;IAC9B,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uBAAuB,CAAC,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3D;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;CAC/D;AAuFD,wBAAgB,sBAAsB,CAAE,UAAU,EAAE,gCAAgC,EAAE,IAAI,EAAE,0BAA0B,GAAG,eAAe,CAEvI;AAED,wBAAgB,qBAAqB,CAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAIvE"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { NotStartedError, start, stop } from '@libp2p/interface';
|
|
2
2
|
import { repeatingTask } from '@libp2p/utils/repeating-task';
|
|
3
|
-
import { multiaddr } from '@multiformats/multiaddr';
|
|
4
3
|
import pDefer from 'p-defer';
|
|
5
4
|
import { raceSignal } from 'race-signal';
|
|
6
5
|
/**
|
|
@@ -14,12 +13,12 @@ class ExternalAddressChecker {
|
|
|
14
13
|
lastPublicIp;
|
|
15
14
|
lastPublicIpPromise;
|
|
16
15
|
check;
|
|
17
|
-
|
|
18
|
-
constructor(components, init
|
|
16
|
+
onExternalAddressChange;
|
|
17
|
+
constructor(components, init) {
|
|
19
18
|
this.log = components.logger.forComponent('libp2p:upnp-nat:external-address-check');
|
|
20
19
|
this.client = components.client;
|
|
21
20
|
this.addressManager = components.addressManager;
|
|
22
|
-
this.
|
|
21
|
+
this.onExternalAddressChange = init.onExternalAddressChange;
|
|
23
22
|
this.started = false;
|
|
24
23
|
this.checkExternalAddress = this.checkExternalAddress.bind(this);
|
|
25
24
|
this.lastPublicIpPromise = pDefer();
|
|
@@ -57,23 +56,8 @@ class ExternalAddressChecker {
|
|
|
57
56
|
// check if our public address has changed
|
|
58
57
|
if (this.lastPublicIp != null && externalAddress !== this.lastPublicIp) {
|
|
59
58
|
this.log('external address changed from %s to %s', this.lastPublicIp, externalAddress);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (!addrString.includes(this.lastPublicIp)) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
// create a new version of the multiaddr with the new public IP
|
|
66
|
-
const newAddress = multiaddr(addrString.replace(this.lastPublicIp, externalAddress));
|
|
67
|
-
// remove the old address and add the new one
|
|
68
|
-
this.addressManager.removeObservedAddr(ma);
|
|
69
|
-
this.addressManager.confirmObservedAddr(newAddress);
|
|
70
|
-
if (this.autoConfirmAddress) {
|
|
71
|
-
this.addressManager.confirmObservedAddr(newAddress);
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
this.addressManager.addObservedAddr(newAddress);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
59
|
+
// notify listeners that the address has changed
|
|
60
|
+
this.onExternalAddressChange?.(externalAddress);
|
|
77
61
|
}
|
|
78
62
|
this.lastPublicIp = externalAddress;
|
|
79
63
|
this.lastPublicIpPromise.resolve(externalAddress);
|
|
@@ -87,7 +71,7 @@ class ExternalAddressChecker {
|
|
|
87
71
|
}
|
|
88
72
|
}
|
|
89
73
|
}
|
|
90
|
-
export function dynamicExternalAddress(components, init
|
|
74
|
+
export function dynamicExternalAddress(components, init) {
|
|
91
75
|
return new ExternalAddressChecker(components, init);
|
|
92
76
|
}
|
|
93
77
|
export function staticExternalAddress(address) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-external-address.js","sourceRoot":"","sources":["../../src/check-external-address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,
|
|
1
|
+
{"version":3,"file":"check-external-address.js","sourceRoot":"","sources":["../../src/check-external-address.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -84,14 +84,6 @@ export interface UPnPNATInit {
|
|
|
84
84
|
* Pass a value to use instead of auto-detection
|
|
85
85
|
*/
|
|
86
86
|
gateway?: string;
|
|
87
|
-
/**
|
|
88
|
-
* How long in ms to wait before giving up trying to auto-detect a
|
|
89
|
-
* `urn:schemas-upnp-org:device:InternetGatewayDevice:1` device on the local
|
|
90
|
-
* network
|
|
91
|
-
*
|
|
92
|
-
* @default 10000
|
|
93
|
-
*/
|
|
94
|
-
gatewayDetectionTimeout?: number;
|
|
95
87
|
/**
|
|
96
88
|
* Ports are mapped when the `self:peer:update` event fires, which happens
|
|
97
89
|
* when the node's addresses change. To avoid starting to map ports while
|
|
@@ -106,16 +98,6 @@ export interface UPnPNATInit {
|
|
|
106
98
|
* otherwise one will be created
|
|
107
99
|
*/
|
|
108
100
|
client?: NatAPI;
|
|
109
|
-
/**
|
|
110
|
-
* Any mapped addresses are added to the observed address list. These
|
|
111
|
-
* addresses require additional verification by the `@libp2p/autonat` protocol
|
|
112
|
-
* or similar before they are trusted.
|
|
113
|
-
*
|
|
114
|
-
* To skip this verification and trust them immediately pass `true` here
|
|
115
|
-
*
|
|
116
|
-
* @default false
|
|
117
|
-
*/
|
|
118
|
-
autoConfirmAddress?: boolean;
|
|
119
101
|
}
|
|
120
102
|
export interface UPnPNATComponents {
|
|
121
103
|
peerId: PeerId;
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAA2B,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AACzF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC1G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;AAEtC,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAA;IAErC;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAA;IAEpC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAA2B,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AACzF,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC1G,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;AAEtC,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAA;IAErC;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAA;IAEpC;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IAEd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,QAAQ,CAAA;IAClB,MAAM,EAAE,eAAe,CAAA;IACvB,cAAc,EAAE,cAAc,CAAA;IAC9B,MAAM,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;CACvC;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,OAAO,CAAE,IAAI,GAAE,WAAgB,GAAG,CAAC,UAAU,EAAE,iBAAiB,KAAK,OAAO,CAI3F"}
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAoC,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAoC,MAAM,eAAe,CAAA;AA0FzF,MAAM,UAAU,OAAO,CAAE,OAAoB,EAAE;IAC7C,OAAO,CAAC,UAA6B,EAAE,EAAE;QACvC,OAAO,IAAI,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;IAC3C,CAAC,CAAA;AACH,CAAC"}
|
package/dist/src/upnp-nat.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { serviceCapabilities
|
|
1
|
+
import { serviceCapabilities } from '@libp2p/interface';
|
|
2
2
|
import type { UPnPNATComponents, UPnPNATInit, UPnPNAT as UPnPNATInterface } from './index.js';
|
|
3
3
|
import type { NatAPI, MapPortOptions } from '@achingbrain/nat-port-mapper';
|
|
4
4
|
import type { Startable } from '@libp2p/interface';
|
|
@@ -8,21 +8,18 @@ export declare class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
8
8
|
private readonly addressManager;
|
|
9
9
|
private readonly events;
|
|
10
10
|
private readonly externalAddress;
|
|
11
|
-
private readonly localAddress?;
|
|
12
11
|
private readonly description;
|
|
13
12
|
private readonly ttl;
|
|
14
13
|
private readonly keepAlive;
|
|
15
14
|
private readonly gateway?;
|
|
16
15
|
private started;
|
|
17
16
|
private readonly log;
|
|
18
|
-
private readonly gatewayDetectionTimeout;
|
|
19
17
|
private readonly mappedPorts;
|
|
20
18
|
private readonly onSelfPeerUpdate;
|
|
21
|
-
private
|
|
19
|
+
private shutdownController?;
|
|
22
20
|
constructor(components: UPnPNATComponents, init: UPnPNATInit);
|
|
23
21
|
readonly [Symbol.toStringTag] = "@libp2p/upnp-nat";
|
|
24
22
|
readonly [serviceCapabilities]: string[];
|
|
25
|
-
get [serviceDependencies](): string[];
|
|
26
23
|
isStarted(): boolean;
|
|
27
24
|
start(): Promise<void>;
|
|
28
25
|
/**
|
|
@@ -36,5 +33,10 @@ export declare class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
36
33
|
* Some ISPs have double-NATs, there's not much we can do with them
|
|
37
34
|
*/
|
|
38
35
|
private assertNotBehindDoubleNAT;
|
|
36
|
+
/**
|
|
37
|
+
* Update the local address mappings when the gateway's external interface
|
|
38
|
+
* address changes
|
|
39
|
+
*/
|
|
40
|
+
private remapPorts;
|
|
39
41
|
}
|
|
40
42
|
//# sourceMappingURL=upnp-nat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upnp-nat.d.ts","sourceRoot":"","sources":["../../src/upnp-nat.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,mBAAmB,
|
|
1
|
+
{"version":3,"file":"upnp-nat.d.ts","sourceRoot":"","sources":["../../src/upnp-nat.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,mBAAmB,EAAgC,MAAM,mBAAmB,CAAA;AAS7G,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7F,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC1E,OAAO,KAAK,EAAwB,SAAS,EAAoB,MAAM,mBAAmB,CAAA;AAO1F,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;AAOtC,qBAAa,OAAQ,YAAW,SAAS,EAAE,gBAAgB;IAClD,MAAM,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiB;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAQ;IACjC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA0B;IACtD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,kBAAkB,CAAC,CAAiB;gBAE/B,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE,WAAW;IAuC7D,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,sBAAqB;IAElD,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAEvC;IAED,SAAS,IAAK,OAAO;IAIf,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAY7B;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;IAa5B,iBAAiB,IAAK,IAAI;IAO1B,OAAO,CAAC,oBAAoB;IAyCtB,cAAc,IAAK,OAAO,CAAC,IAAI,CAAC;IAgEtC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAYhC;;;OAGG;IACH,OAAO,CAAC,UAAU;CAYnB"}
|
package/dist/src/upnp-nat.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { upnpNat } from '@achingbrain/nat-port-mapper';
|
|
2
2
|
import { isIPv4, isIPv6 } from '@chainsafe/is-ip';
|
|
3
|
-
import { InvalidParametersError, serviceCapabilities,
|
|
3
|
+
import { InvalidParametersError, serviceCapabilities, setMaxListeners, start, stop } from '@libp2p/interface';
|
|
4
4
|
import { debounce } from '@libp2p/utils/debounce';
|
|
5
5
|
import { isLoopback } from '@libp2p/utils/multiaddr/is-loopback';
|
|
6
6
|
import { isPrivate } from '@libp2p/utils/multiaddr/is-private';
|
|
7
7
|
import { isPrivateIp } from '@libp2p/utils/private-ip';
|
|
8
|
-
import { multiaddr } from '@multiformats/multiaddr';
|
|
9
8
|
import { QUICV1, TCP, WebSockets, WebSocketsSecure, WebTransport } from '@multiformats/multiaddr-matcher';
|
|
10
|
-
import { raceSignal } from 'race-signal';
|
|
11
9
|
import { dynamicExternalAddress, staticExternalAddress } from './check-external-address.js';
|
|
12
10
|
import { DoubleNATError, InvalidIPAddressError } from './errors.js';
|
|
13
11
|
const DEFAULT_TTL = 7200;
|
|
@@ -16,29 +14,24 @@ export class UPnPNAT {
|
|
|
16
14
|
addressManager;
|
|
17
15
|
events;
|
|
18
16
|
externalAddress;
|
|
19
|
-
localAddress;
|
|
20
17
|
description;
|
|
21
18
|
ttl;
|
|
22
19
|
keepAlive;
|
|
23
20
|
gateway;
|
|
24
21
|
started;
|
|
25
22
|
log;
|
|
26
|
-
gatewayDetectionTimeout;
|
|
27
23
|
mappedPorts;
|
|
28
24
|
onSelfPeerUpdate;
|
|
29
|
-
|
|
25
|
+
shutdownController;
|
|
30
26
|
constructor(components, init) {
|
|
31
27
|
this.log = components.logger.forComponent('libp2p:upnp-nat');
|
|
32
28
|
this.addressManager = components.addressManager;
|
|
33
29
|
this.events = components.events;
|
|
34
30
|
this.started = false;
|
|
35
|
-
this.localAddress = init.localAddress;
|
|
36
31
|
this.description = init.description ?? `${components.nodeInfo.name}@${components.nodeInfo.version} ${components.peerId.toString()}`;
|
|
37
32
|
this.ttl = init.ttl ?? DEFAULT_TTL;
|
|
38
33
|
this.keepAlive = init.keepAlive ?? true;
|
|
39
34
|
this.gateway = init.gateway;
|
|
40
|
-
this.gatewayDetectionTimeout = init.gatewayDetectionTimeout ?? 10000;
|
|
41
|
-
this.autoConfirmAddress = init.autoConfirmAddress ?? false;
|
|
42
35
|
this.mappedPorts = new Map();
|
|
43
36
|
if (this.ttl < DEFAULT_TTL) {
|
|
44
37
|
throw new InvalidParametersError(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`);
|
|
@@ -59,9 +52,9 @@ export class UPnPNAT {
|
|
|
59
52
|
addressManager: this.addressManager,
|
|
60
53
|
logger: components.logger
|
|
61
54
|
}, {
|
|
62
|
-
autoConfirmAddress: init.autoConfirmAddress,
|
|
63
55
|
interval: init.externalAddressCheckInterval,
|
|
64
|
-
timeout: init.externalAddressCheckTimeout
|
|
56
|
+
timeout: init.externalAddressCheckTimeout,
|
|
57
|
+
onExternalAddressChange: this.remapPorts.bind(this)
|
|
65
58
|
});
|
|
66
59
|
}
|
|
67
60
|
}
|
|
@@ -69,14 +62,6 @@ export class UPnPNAT {
|
|
|
69
62
|
[serviceCapabilities] = [
|
|
70
63
|
'@libp2p/nat-traversal'
|
|
71
64
|
];
|
|
72
|
-
get [serviceDependencies]() {
|
|
73
|
-
if (!this.autoConfirmAddress) {
|
|
74
|
-
return [
|
|
75
|
-
'@libp2p/autonat'
|
|
76
|
-
];
|
|
77
|
-
}
|
|
78
|
-
return [];
|
|
79
|
-
}
|
|
80
65
|
isStarted() {
|
|
81
66
|
return this.started;
|
|
82
67
|
}
|
|
@@ -85,6 +70,8 @@ export class UPnPNAT {
|
|
|
85
70
|
return;
|
|
86
71
|
}
|
|
87
72
|
this.started = true;
|
|
73
|
+
this.shutdownController = new AbortController();
|
|
74
|
+
setMaxListeners(Infinity, this.shutdownController.signal);
|
|
88
75
|
this.events.addEventListener('self:peer:update', this.onSelfPeerUpdate);
|
|
89
76
|
await start(this.externalAddress, this.onSelfPeerUpdate);
|
|
90
77
|
}
|
|
@@ -98,6 +85,7 @@ export class UPnPNAT {
|
|
|
98
85
|
catch (err) {
|
|
99
86
|
this.log.error(err);
|
|
100
87
|
}
|
|
88
|
+
this.shutdownController?.abort();
|
|
101
89
|
this.events.removeEventListener('self:peer:update', this.onSelfPeerUpdate);
|
|
102
90
|
await stop(this.externalAddress, this.onSelfPeerUpdate);
|
|
103
91
|
this.started = false;
|
|
@@ -127,11 +115,11 @@ export class UPnPNAT {
|
|
|
127
115
|
WebTransport.exactMatch(ma))) {
|
|
128
116
|
continue;
|
|
129
117
|
}
|
|
130
|
-
const { port, family } = ma.toOptions();
|
|
118
|
+
const { port, host, family, transport } = ma.toOptions();
|
|
131
119
|
if (family !== ipType) {
|
|
132
120
|
continue;
|
|
133
121
|
}
|
|
134
|
-
if (this.mappedPorts.has(port)) {
|
|
122
|
+
if (this.mappedPorts.has(`${host}-${port}-${transport}`)) {
|
|
135
123
|
continue;
|
|
136
124
|
}
|
|
137
125
|
output.push(ma);
|
|
@@ -139,24 +127,18 @@ export class UPnPNAT {
|
|
|
139
127
|
return output;
|
|
140
128
|
}
|
|
141
129
|
async mapIpAddresses() {
|
|
142
|
-
|
|
143
|
-
this.
|
|
144
|
-
}
|
|
145
|
-
const publicIp = await this.externalAddress.getPublicIp({
|
|
146
|
-
signal: AbortSignal.timeout(this.gatewayDetectionTimeout)
|
|
147
|
-
});
|
|
148
|
-
this.externalAddress ?? await raceSignal(this.client.externalIp(), AbortSignal.timeout(this.gatewayDetectionTimeout), {
|
|
149
|
-
errorMessage: `Did not discover a "urn:schemas-upnp-org:device:InternetGatewayDevice:1" device on the local network after ${this.gatewayDetectionTimeout}ms - UPnP may not be configured on your router correctly`
|
|
130
|
+
const externalHost = await this.externalAddress.getPublicIp({
|
|
131
|
+
signal: this.shutdownController?.signal
|
|
150
132
|
});
|
|
151
133
|
let ipType = 4;
|
|
152
|
-
if (isIPv4(
|
|
134
|
+
if (isIPv4(externalHost)) {
|
|
153
135
|
ipType = 4;
|
|
154
136
|
}
|
|
155
|
-
else if (isIPv6(
|
|
137
|
+
else if (isIPv6(externalHost)) {
|
|
156
138
|
ipType = 6;
|
|
157
139
|
}
|
|
158
140
|
else {
|
|
159
|
-
throw new InvalidIPAddressError(`Public address ${
|
|
141
|
+
throw new InvalidIPAddressError(`Public address ${externalHost} was not an IPv4 address`);
|
|
160
142
|
}
|
|
161
143
|
// filter addresses to get private, non-relay, IP based addresses that we
|
|
162
144
|
// haven't mapped yet
|
|
@@ -165,8 +147,8 @@ export class UPnPNAT {
|
|
|
165
147
|
this.log('no private, non-relay, unmapped, IP based addresses found');
|
|
166
148
|
return;
|
|
167
149
|
}
|
|
168
|
-
this.log('%s public IP %s', this.externalAddress != null ? 'using configured' : 'discovered',
|
|
169
|
-
this.assertNotBehindDoubleNAT(
|
|
150
|
+
this.log('%s public IP %s', this.externalAddress != null ? 'using configured' : 'discovered', externalHost);
|
|
151
|
+
this.assertNotBehindDoubleNAT(externalHost);
|
|
170
152
|
for (const addr of addresses) {
|
|
171
153
|
// try to open uPnP ports for each thin waist address
|
|
172
154
|
const { family, host, port, transport } = addr.toOptions();
|
|
@@ -174,24 +156,25 @@ export class UPnPNAT {
|
|
|
174
156
|
// only support IPv4 addresses
|
|
175
157
|
continue;
|
|
176
158
|
}
|
|
177
|
-
if (this.mappedPorts.has(port)) {
|
|
159
|
+
if (this.mappedPorts.has(`${host}-${port}-${transport}`)) {
|
|
178
160
|
// already mapped this port
|
|
179
161
|
continue;
|
|
180
162
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
this.
|
|
163
|
+
try {
|
|
164
|
+
this.log(`creating mapping of %s:%s key ${host}-${port}-${transport}`, host, port);
|
|
165
|
+
const externalPort = await this.client.map(port, {
|
|
166
|
+
localAddress: host,
|
|
167
|
+
protocol: transport === 'tcp' ? 'TCP' : 'UDP'
|
|
168
|
+
});
|
|
169
|
+
this.mappedPorts.set(`${host}-${port}-${transport}`, {
|
|
170
|
+
externalHost,
|
|
171
|
+
externalPort
|
|
172
|
+
});
|
|
173
|
+
this.log('created mapping of %s:%s to %s:%s', externalHost, externalPort, host, port);
|
|
174
|
+
this.addressManager.addPublicAddressMapping(host, port, externalHost, externalPort, transport === 'tcp' ? 'tcp' : 'udp');
|
|
192
175
|
}
|
|
193
|
-
|
|
194
|
-
this.
|
|
176
|
+
catch (err) {
|
|
177
|
+
this.log.error('failed to create mapping of %s:%s - %e', host, port, err);
|
|
195
178
|
}
|
|
196
179
|
}
|
|
197
180
|
}
|
|
@@ -201,11 +184,22 @@ export class UPnPNAT {
|
|
|
201
184
|
assertNotBehindDoubleNAT(publicIp) {
|
|
202
185
|
const isPrivate = isPrivateIp(publicIp);
|
|
203
186
|
if (isPrivate === true) {
|
|
204
|
-
throw new DoubleNATError(`${publicIp} is private - please set
|
|
187
|
+
throw new DoubleNATError(`${publicIp} is private - please init uPnPNAT with 'externalAddress' set to an externally routable IP or ensure you are not behind a double NAT`);
|
|
205
188
|
}
|
|
206
189
|
if (isPrivate == null) {
|
|
207
190
|
throw new InvalidParametersError(`${publicIp} is not an IP address`);
|
|
208
191
|
}
|
|
209
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Update the local address mappings when the gateway's external interface
|
|
195
|
+
* address changes
|
|
196
|
+
*/
|
|
197
|
+
remapPorts(newExternalHost) {
|
|
198
|
+
for (const [key, { externalHost, externalPort }] of this.mappedPorts.entries()) {
|
|
199
|
+
const [host, port, transport] = key.split('-');
|
|
200
|
+
this.addressManager.removePublicAddressMapping(host, parseInt(port), externalHost, externalPort, transport === 'tcp' ? 'tcp' : 'udp');
|
|
201
|
+
this.addressManager.addPublicAddressMapping(host, parseInt(port), newExternalHost, externalPort, transport === 'tcp' ? 'tcp' : 'udp');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
210
204
|
}
|
|
211
205
|
//# sourceMappingURL=upnp-nat.js.map
|
package/dist/src/upnp-nat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upnp-nat.js","sourceRoot":"","sources":["../../src/upnp-nat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,
|
|
1
|
+
{"version":3,"file":"upnp-nat.js","sourceRoot":"","sources":["../../src/upnp-nat.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/upnp-nat",
|
|
3
|
-
"version": "2.0.12-
|
|
3
|
+
"version": "2.0.12-bc90b4fd5",
|
|
4
4
|
"description": "UPnP NAT hole punching",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/upnp-nat#readme",
|
|
@@ -52,18 +52,18 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@achingbrain/nat-port-mapper": "^2.0.1",
|
|
54
54
|
"@chainsafe/is-ip": "^2.0.2",
|
|
55
|
-
"@libp2p/interface": "2.2.1-
|
|
56
|
-
"@libp2p/interface-internal": "2.1.1-
|
|
57
|
-
"@libp2p/utils": "6.2.1-
|
|
55
|
+
"@libp2p/interface": "2.2.1-bc90b4fd5",
|
|
56
|
+
"@libp2p/interface-internal": "2.1.1-bc90b4fd5",
|
|
57
|
+
"@libp2p/utils": "6.2.1-bc90b4fd5",
|
|
58
58
|
"@multiformats/multiaddr": "^12.2.3",
|
|
59
59
|
"@multiformats/multiaddr-matcher": "^1.4.0",
|
|
60
60
|
"p-defer": "^4.0.1",
|
|
61
61
|
"race-signal": "^1.1.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@libp2p/crypto": "5.0.7-
|
|
65
|
-
"@libp2p/logger": "5.1.4-
|
|
66
|
-
"@libp2p/peer-id": "5.0.8-
|
|
64
|
+
"@libp2p/crypto": "5.0.7-bc90b4fd5",
|
|
65
|
+
"@libp2p/logger": "5.1.4-bc90b4fd5",
|
|
66
|
+
"@libp2p/peer-id": "5.0.8-bc90b4fd5",
|
|
67
67
|
"aegir": "^44.0.1",
|
|
68
68
|
"sinon-ts": "^2.0.0"
|
|
69
69
|
},
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { NotStartedError, start, stop } from '@libp2p/interface'
|
|
2
2
|
import { repeatingTask } from '@libp2p/utils/repeating-task'
|
|
3
|
-
import { multiaddr } from '@multiformats/multiaddr'
|
|
4
3
|
import pDefer from 'p-defer'
|
|
5
4
|
import { raceSignal } from 'race-signal'
|
|
6
5
|
import type { NatAPI } from '@achingbrain/nat-port-mapper'
|
|
@@ -18,7 +17,7 @@ export interface ExternalAddressCheckerComponents {
|
|
|
18
17
|
export interface ExternalAddressCheckerInit {
|
|
19
18
|
interval?: number
|
|
20
19
|
timeout?: number
|
|
21
|
-
|
|
20
|
+
onExternalAddressChange?(newExternalAddress: string): void
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
export interface ExternalAddress {
|
|
@@ -36,13 +35,13 @@ class ExternalAddressChecker implements ExternalAddress, Startable {
|
|
|
36
35
|
private lastPublicIp?: string
|
|
37
36
|
private readonly lastPublicIpPromise: DeferredPromise<string>
|
|
38
37
|
private readonly check: RepeatingTask
|
|
39
|
-
private readonly
|
|
38
|
+
private readonly onExternalAddressChange?: (newExternalAddress: string) => void
|
|
40
39
|
|
|
41
|
-
constructor (components: ExternalAddressCheckerComponents, init: ExternalAddressCheckerInit
|
|
40
|
+
constructor (components: ExternalAddressCheckerComponents, init: ExternalAddressCheckerInit) {
|
|
42
41
|
this.log = components.logger.forComponent('libp2p:upnp-nat:external-address-check')
|
|
43
42
|
this.client = components.client
|
|
44
43
|
this.addressManager = components.addressManager
|
|
45
|
-
this.
|
|
44
|
+
this.onExternalAddressChange = init.onExternalAddressChange
|
|
46
45
|
this.started = false
|
|
47
46
|
|
|
48
47
|
this.checkExternalAddress = this.checkExternalAddress.bind(this)
|
|
@@ -93,26 +92,8 @@ class ExternalAddressChecker implements ExternalAddress, Startable {
|
|
|
93
92
|
if (this.lastPublicIp != null && externalAddress !== this.lastPublicIp) {
|
|
94
93
|
this.log('external address changed from %s to %s', this.lastPublicIp, externalAddress)
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (!addrString.includes(this.lastPublicIp)) {
|
|
100
|
-
continue
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// create a new version of the multiaddr with the new public IP
|
|
104
|
-
const newAddress = multiaddr(addrString.replace(this.lastPublicIp, externalAddress))
|
|
105
|
-
|
|
106
|
-
// remove the old address and add the new one
|
|
107
|
-
this.addressManager.removeObservedAddr(ma)
|
|
108
|
-
this.addressManager.confirmObservedAddr(newAddress)
|
|
109
|
-
|
|
110
|
-
if (this.autoConfirmAddress) {
|
|
111
|
-
this.addressManager.confirmObservedAddr(newAddress)
|
|
112
|
-
} else {
|
|
113
|
-
this.addressManager.addObservedAddr(newAddress)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
95
|
+
// notify listeners that the address has changed
|
|
96
|
+
this.onExternalAddressChange?.(externalAddress)
|
|
116
97
|
}
|
|
117
98
|
|
|
118
99
|
this.lastPublicIp = externalAddress
|
|
@@ -128,7 +109,7 @@ class ExternalAddressChecker implements ExternalAddress, Startable {
|
|
|
128
109
|
}
|
|
129
110
|
}
|
|
130
111
|
|
|
131
|
-
export function dynamicExternalAddress (components: ExternalAddressCheckerComponents, init: ExternalAddressCheckerInit
|
|
112
|
+
export function dynamicExternalAddress (components: ExternalAddressCheckerComponents, init: ExternalAddressCheckerInit): ExternalAddress {
|
|
132
113
|
return new ExternalAddressChecker(components, init)
|
|
133
114
|
}
|
|
134
115
|
|
package/src/index.ts
CHANGED
|
@@ -96,15 +96,6 @@ export interface UPnPNATInit {
|
|
|
96
96
|
*/
|
|
97
97
|
gateway?: string
|
|
98
98
|
|
|
99
|
-
/**
|
|
100
|
-
* How long in ms to wait before giving up trying to auto-detect a
|
|
101
|
-
* `urn:schemas-upnp-org:device:InternetGatewayDevice:1` device on the local
|
|
102
|
-
* network
|
|
103
|
-
*
|
|
104
|
-
* @default 10000
|
|
105
|
-
*/
|
|
106
|
-
gatewayDetectionTimeout?: number
|
|
107
|
-
|
|
108
99
|
/**
|
|
109
100
|
* Ports are mapped when the `self:peer:update` event fires, which happens
|
|
110
101
|
* when the node's addresses change. To avoid starting to map ports while
|
|
@@ -120,17 +111,6 @@ export interface UPnPNATInit {
|
|
|
120
111
|
* otherwise one will be created
|
|
121
112
|
*/
|
|
122
113
|
client?: NatAPI
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Any mapped addresses are added to the observed address list. These
|
|
126
|
-
* addresses require additional verification by the `@libp2p/autonat` protocol
|
|
127
|
-
* or similar before they are trusted.
|
|
128
|
-
*
|
|
129
|
-
* To skip this verification and trust them immediately pass `true` here
|
|
130
|
-
*
|
|
131
|
-
* @default false
|
|
132
|
-
*/
|
|
133
|
-
autoConfirmAddress?: boolean
|
|
134
114
|
}
|
|
135
115
|
|
|
136
116
|
export interface UPnPNATComponents {
|
package/src/upnp-nat.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { upnpNat } from '@achingbrain/nat-port-mapper'
|
|
2
2
|
import { isIPv4, isIPv6 } from '@chainsafe/is-ip'
|
|
3
|
-
import { InvalidParametersError, serviceCapabilities,
|
|
3
|
+
import { InvalidParametersError, serviceCapabilities, setMaxListeners, start, stop } from '@libp2p/interface'
|
|
4
4
|
import { debounce } from '@libp2p/utils/debounce'
|
|
5
5
|
import { isLoopback } from '@libp2p/utils/multiaddr/is-loopback'
|
|
6
6
|
import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
|
|
7
7
|
import { isPrivateIp } from '@libp2p/utils/private-ip'
|
|
8
|
-
import { multiaddr } from '@multiformats/multiaddr'
|
|
9
8
|
import { QUICV1, TCP, WebSockets, WebSocketsSecure, WebTransport } from '@multiformats/multiaddr-matcher'
|
|
10
|
-
import { raceSignal } from 'race-signal'
|
|
11
9
|
import { dynamicExternalAddress, staticExternalAddress } from './check-external-address.js'
|
|
12
10
|
import { DoubleNATError, InvalidIPAddressError } from './errors.js'
|
|
13
11
|
import type { ExternalAddress } from './check-external-address.js'
|
|
@@ -22,35 +20,35 @@ const DEFAULT_TTL = 7200
|
|
|
22
20
|
|
|
23
21
|
export type { NatAPI, MapPortOptions }
|
|
24
22
|
|
|
23
|
+
interface PortMapping {
|
|
24
|
+
externalHost: string
|
|
25
|
+
externalPort: number
|
|
26
|
+
}
|
|
27
|
+
|
|
25
28
|
export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
26
29
|
public client: NatAPI
|
|
27
30
|
private readonly addressManager: AddressManager
|
|
28
31
|
private readonly events: TypedEventTarget<Libp2pEvents>
|
|
29
32
|
private readonly externalAddress: ExternalAddress
|
|
30
|
-
private readonly localAddress?: string
|
|
31
33
|
private readonly description: string
|
|
32
34
|
private readonly ttl: number
|
|
33
35
|
private readonly keepAlive: boolean
|
|
34
36
|
private readonly gateway?: string
|
|
35
37
|
private started: boolean
|
|
36
38
|
private readonly log: Logger
|
|
37
|
-
private readonly
|
|
38
|
-
private readonly mappedPorts: Map<number, number>
|
|
39
|
+
private readonly mappedPorts: Map<string, PortMapping>
|
|
39
40
|
private readonly onSelfPeerUpdate: DebouncedFunction
|
|
40
|
-
private
|
|
41
|
+
private shutdownController?: AbortController
|
|
41
42
|
|
|
42
43
|
constructor (components: UPnPNATComponents, init: UPnPNATInit) {
|
|
43
44
|
this.log = components.logger.forComponent('libp2p:upnp-nat')
|
|
44
45
|
this.addressManager = components.addressManager
|
|
45
46
|
this.events = components.events
|
|
46
47
|
this.started = false
|
|
47
|
-
this.localAddress = init.localAddress
|
|
48
48
|
this.description = init.description ?? `${components.nodeInfo.name}@${components.nodeInfo.version} ${components.peerId.toString()}`
|
|
49
49
|
this.ttl = init.ttl ?? DEFAULT_TTL
|
|
50
50
|
this.keepAlive = init.keepAlive ?? true
|
|
51
51
|
this.gateway = init.gateway
|
|
52
|
-
this.gatewayDetectionTimeout = init.gatewayDetectionTimeout ?? 10000
|
|
53
|
-
this.autoConfirmAddress = init.autoConfirmAddress ?? false
|
|
54
52
|
this.mappedPorts = new Map()
|
|
55
53
|
|
|
56
54
|
if (this.ttl < DEFAULT_TTL) {
|
|
@@ -74,9 +72,9 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
74
72
|
addressManager: this.addressManager,
|
|
75
73
|
logger: components.logger
|
|
76
74
|
}, {
|
|
77
|
-
autoConfirmAddress: init.autoConfirmAddress,
|
|
78
75
|
interval: init.externalAddressCheckInterval,
|
|
79
|
-
timeout: init.externalAddressCheckTimeout
|
|
76
|
+
timeout: init.externalAddressCheckTimeout,
|
|
77
|
+
onExternalAddressChange: this.remapPorts.bind(this)
|
|
80
78
|
})
|
|
81
79
|
}
|
|
82
80
|
}
|
|
@@ -87,16 +85,6 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
87
85
|
'@libp2p/nat-traversal'
|
|
88
86
|
]
|
|
89
87
|
|
|
90
|
-
get [serviceDependencies] (): string[] {
|
|
91
|
-
if (!this.autoConfirmAddress) {
|
|
92
|
-
return [
|
|
93
|
-
'@libp2p/autonat'
|
|
94
|
-
]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return []
|
|
98
|
-
}
|
|
99
|
-
|
|
100
88
|
isStarted (): boolean {
|
|
101
89
|
return this.started
|
|
102
90
|
}
|
|
@@ -107,6 +95,8 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
107
95
|
}
|
|
108
96
|
|
|
109
97
|
this.started = true
|
|
98
|
+
this.shutdownController = new AbortController()
|
|
99
|
+
setMaxListeners(Infinity, this.shutdownController.signal)
|
|
110
100
|
this.events.addEventListener('self:peer:update', this.onSelfPeerUpdate)
|
|
111
101
|
await start(this.externalAddress, this.onSelfPeerUpdate)
|
|
112
102
|
}
|
|
@@ -121,6 +111,7 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
121
111
|
this.log.error(err)
|
|
122
112
|
}
|
|
123
113
|
|
|
114
|
+
this.shutdownController?.abort()
|
|
124
115
|
this.events.removeEventListener('self:peer:update', this.onSelfPeerUpdate)
|
|
125
116
|
await stop(this.externalAddress, this.onSelfPeerUpdate)
|
|
126
117
|
this.started = false
|
|
@@ -158,13 +149,13 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
158
149
|
continue
|
|
159
150
|
}
|
|
160
151
|
|
|
161
|
-
const { port, family } = ma.toOptions()
|
|
152
|
+
const { port, host, family, transport } = ma.toOptions()
|
|
162
153
|
|
|
163
154
|
if (family !== ipType) {
|
|
164
155
|
continue
|
|
165
156
|
}
|
|
166
157
|
|
|
167
|
-
if (this.mappedPorts.has(port)) {
|
|
158
|
+
if (this.mappedPorts.has(`${host}-${port}-${transport}`)) {
|
|
168
159
|
continue
|
|
169
160
|
}
|
|
170
161
|
|
|
@@ -175,26 +166,18 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
175
166
|
}
|
|
176
167
|
|
|
177
168
|
async mapIpAddresses (): Promise<void> {
|
|
178
|
-
|
|
179
|
-
this.
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const publicIp = await this.externalAddress.getPublicIp({
|
|
183
|
-
signal: AbortSignal.timeout(this.gatewayDetectionTimeout)
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
this.externalAddress ?? await raceSignal(this.client.externalIp(), AbortSignal.timeout(this.gatewayDetectionTimeout), {
|
|
187
|
-
errorMessage: `Did not discover a "urn:schemas-upnp-org:device:InternetGatewayDevice:1" device on the local network after ${this.gatewayDetectionTimeout}ms - UPnP may not be configured on your router correctly`
|
|
169
|
+
const externalHost = await this.externalAddress.getPublicIp({
|
|
170
|
+
signal: this.shutdownController?.signal
|
|
188
171
|
})
|
|
189
172
|
|
|
190
173
|
let ipType: 4 | 6 = 4
|
|
191
174
|
|
|
192
|
-
if (isIPv4(
|
|
175
|
+
if (isIPv4(externalHost)) {
|
|
193
176
|
ipType = 4
|
|
194
|
-
} else if (isIPv6(
|
|
177
|
+
} else if (isIPv6(externalHost)) {
|
|
195
178
|
ipType = 6
|
|
196
179
|
} else {
|
|
197
|
-
throw new InvalidIPAddressError(`Public address ${
|
|
180
|
+
throw new InvalidIPAddressError(`Public address ${externalHost} was not an IPv4 address`)
|
|
198
181
|
}
|
|
199
182
|
|
|
200
183
|
// filter addresses to get private, non-relay, IP based addresses that we
|
|
@@ -206,9 +189,9 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
206
189
|
return
|
|
207
190
|
}
|
|
208
191
|
|
|
209
|
-
this.log('%s public IP %s', this.externalAddress != null ? 'using configured' : 'discovered',
|
|
192
|
+
this.log('%s public IP %s', this.externalAddress != null ? 'using configured' : 'discovered', externalHost)
|
|
210
193
|
|
|
211
|
-
this.assertNotBehindDoubleNAT(
|
|
194
|
+
this.assertNotBehindDoubleNAT(externalHost)
|
|
212
195
|
|
|
213
196
|
for (const addr of addresses) {
|
|
214
197
|
// try to open uPnP ports for each thin waist address
|
|
@@ -219,30 +202,29 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
219
202
|
continue
|
|
220
203
|
}
|
|
221
204
|
|
|
222
|
-
if (this.mappedPorts.has(port)) {
|
|
205
|
+
if (this.mappedPorts.has(`${host}-${port}-${transport}`)) {
|
|
223
206
|
// already mapped this port
|
|
224
207
|
continue
|
|
225
208
|
}
|
|
226
209
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
this.log(`creating mapping of ${host}:${port}`)
|
|
210
|
+
try {
|
|
211
|
+
this.log(`creating mapping of %s:%s key ${host}-${port}-${transport}`, host, port)
|
|
230
212
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
213
|
+
const externalPort = await this.client.map(port, {
|
|
214
|
+
localAddress: host,
|
|
215
|
+
protocol: transport === 'tcp' ? 'TCP' : 'UDP'
|
|
216
|
+
})
|
|
235
217
|
|
|
236
|
-
|
|
218
|
+
this.mappedPorts.set(`${host}-${port}-${transport}`, {
|
|
219
|
+
externalHost,
|
|
220
|
+
externalPort
|
|
221
|
+
})
|
|
237
222
|
|
|
238
|
-
|
|
223
|
+
this.log('created mapping of %s:%s to %s:%s', externalHost, externalPort, host, port)
|
|
239
224
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
this.addressManager.confirmObservedAddr(ma)
|
|
244
|
-
} else {
|
|
245
|
-
this.addressManager.addObservedAddr(ma)
|
|
225
|
+
this.addressManager.addPublicAddressMapping(host, port, externalHost, externalPort, transport === 'tcp' ? 'tcp' : 'udp')
|
|
226
|
+
} catch (err) {
|
|
227
|
+
this.log.error('failed to create mapping of %s:%s - %e', host, port, err)
|
|
246
228
|
}
|
|
247
229
|
}
|
|
248
230
|
}
|
|
@@ -254,11 +236,28 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
|
|
|
254
236
|
const isPrivate = isPrivateIp(publicIp)
|
|
255
237
|
|
|
256
238
|
if (isPrivate === true) {
|
|
257
|
-
throw new DoubleNATError(`${publicIp} is private - please set
|
|
239
|
+
throw new DoubleNATError(`${publicIp} is private - please init uPnPNAT with 'externalAddress' set to an externally routable IP or ensure you are not behind a double NAT`)
|
|
258
240
|
}
|
|
259
241
|
|
|
260
242
|
if (isPrivate == null) {
|
|
261
243
|
throw new InvalidParametersError(`${publicIp} is not an IP address`)
|
|
262
244
|
}
|
|
263
245
|
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Update the local address mappings when the gateway's external interface
|
|
249
|
+
* address changes
|
|
250
|
+
*/
|
|
251
|
+
private remapPorts (newExternalHost: string): void {
|
|
252
|
+
for (const [key, { externalHost, externalPort }] of this.mappedPorts.entries()) {
|
|
253
|
+
const [
|
|
254
|
+
host,
|
|
255
|
+
port,
|
|
256
|
+
transport
|
|
257
|
+
] = key.split('-')
|
|
258
|
+
|
|
259
|
+
this.addressManager.removePublicAddressMapping(host, parseInt(port), externalHost, externalPort, transport === 'tcp' ? 'tcp' : 'udp')
|
|
260
|
+
this.addressManager.addPublicAddressMapping(host, parseInt(port), newExternalHost, externalPort, transport === 'tcp' ? 'tcp' : 'udp')
|
|
261
|
+
}
|
|
262
|
+
}
|
|
264
263
|
}
|