@libp2p/upnp-nat 2.0.12-bc90b4fd5 → 2.0.12-d19974d93

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.
@@ -1,8 +1,8 @@
1
- import type { NatAPI } from '@achingbrain/nat-port-mapper';
1
+ import type { Gateway } from '@achingbrain/nat-port-mapper';
2
2
  import type { AbortOptions, ComponentLogger } from '@libp2p/interface';
3
3
  import type { AddressManager } from '@libp2p/interface-internal';
4
4
  export interface ExternalAddressCheckerComponents {
5
- client: NatAPI;
5
+ gateway: Gateway;
6
6
  addressManager: AddressManager;
7
7
  logger: ComponentLogger;
8
8
  }
@@ -1 +1 @@
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
+ {"version":3,"file":"check-external-address.d.ts","sourceRoot":"","sources":["../../src/check-external-address.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAC3D,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,OAAO,EAAE,OAAO,CAAA;IAChB,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;AAsFD,wBAAgB,sBAAsB,CAAE,UAAU,EAAE,gCAAgC,EAAE,IAAI,EAAE,0BAA0B,GAAG,eAAe,CAEvI;AAED,wBAAgB,qBAAqB,CAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAIvE"}
@@ -7,7 +7,7 @@ import { raceSignal } from 'race-signal';
7
7
  */
8
8
  class ExternalAddressChecker {
9
9
  log;
10
- client;
10
+ gateway;
11
11
  addressManager;
12
12
  started;
13
13
  lastPublicIp;
@@ -16,7 +16,7 @@ class ExternalAddressChecker {
16
16
  onExternalAddressChange;
17
17
  constructor(components, init) {
18
18
  this.log = components.logger.forComponent('libp2p:upnp-nat:external-address-check');
19
- this.client = components.client;
19
+ this.gateway = components.gateway;
20
20
  this.addressManager = components.addressManager;
21
21
  this.onExternalAddressChange = init.onExternalAddressChange;
22
22
  this.started = false;
@@ -32,7 +32,6 @@ class ExternalAddressChecker {
32
32
  return;
33
33
  }
34
34
  await start(this.check);
35
- this.check.start();
36
35
  this.started = true;
37
36
  }
38
37
  async stop() {
@@ -52,7 +51,7 @@ class ExternalAddressChecker {
52
51
  }
53
52
  async checkExternalAddress(options) {
54
53
  try {
55
- const externalAddress = await this.client.externalIp(options);
54
+ const externalAddress = await this.gateway.externalIp(options);
56
55
  // check if our public address has changed
57
56
  if (this.lastPublicIp != null && externalAddress !== this.lastPublicIp) {
58
57
  this.log('external address changed from %s to %s', this.lastPublicIp, externalAddress);
@@ -63,6 +62,7 @@ class ExternalAddressChecker {
63
62
  this.lastPublicIpPromise.resolve(externalAddress);
64
63
  }
65
64
  catch (err) {
65
+ this.log.error('could not resolve external address - %e', err);
66
66
  if (this.lastPublicIp != null) {
67
67
  // ignore the error if we've previously run successfully
68
68
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"check-external-address.js","sourceRoot":"","sources":["../../src/check-external-address.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"check-external-address.js","sourceRoot":"","sources":["../../src/check-external-address.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const DEFAULT_GATEWAY_SEARCH_TIMEOUT = 60000;
2
+ export declare const DEFAULT_GATEWAY_SEARCH_INTERVAL = 300000;
3
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,8BAA8B,QAAS,CAAA;AACpD,eAAO,MAAM,+BAA+B,SAAU,CAAA"}
@@ -0,0 +1,3 @@
1
+ export const DEFAULT_GATEWAY_SEARCH_TIMEOUT = 60_000;
2
+ export const DEFAULT_GATEWAY_SEARCH_INTERVAL = 300_000;
3
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,8BAA8B,GAAG,MAAM,CAAA;AACpD,MAAM,CAAC,MAAM,+BAA+B,GAAG,OAAO,CAAA"}
@@ -0,0 +1,26 @@
1
+ import { TypedEventEmitter } from '@libp2p/interface';
2
+ import type { Gateway, UPnPNAT } from '@achingbrain/nat-port-mapper';
3
+ import type { ComponentLogger } from '@libp2p/interface';
4
+ export interface GatewayFinderComponents {
5
+ logger: ComponentLogger;
6
+ }
7
+ export interface GatewayFinderInit {
8
+ portMappingClient: UPnPNAT;
9
+ }
10
+ export interface GatewayFinderEvents {
11
+ 'gateway': CustomEvent<Gateway>;
12
+ }
13
+ export declare class GatewayFinder extends TypedEventEmitter<GatewayFinderEvents> {
14
+ private readonly log;
15
+ private readonly gateways;
16
+ private readonly findGateways;
17
+ private readonly portMappingClient;
18
+ private started;
19
+ constructor(components: GatewayFinderComponents, init: GatewayFinderInit);
20
+ start(): Promise<void>;
21
+ /**
22
+ * Stops the NAT manager
23
+ */
24
+ stop(): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=gateway-finder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-finder.d.ts","sourceRoot":"","sources":["../../src/gateway-finder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAe,MAAM,mBAAmB,CAAA;AAGlE,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,eAAe,EAAU,MAAM,mBAAmB,CAAA;AAGhE,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,CAAA;CAChC;AAED,qBAAa,aAAc,SAAQ,iBAAiB,CAAC,mBAAmB,CAAC;IACvE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,OAAO,CAAS;gBAEX,UAAU,EAAE,uBAAuB,EAAE,IAAI,EAAE,iBAAiB;IAgCnE,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAS7B;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;CAI7B"}
@@ -0,0 +1,53 @@
1
+ import { TypedEventEmitter, start, stop } from '@libp2p/interface';
2
+ import { repeatingTask } from '@libp2p/utils/repeating-task';
3
+ import { DEFAULT_GATEWAY_SEARCH_INTERVAL, DEFAULT_GATEWAY_SEARCH_TIMEOUT } from './constants.js';
4
+ export class GatewayFinder extends TypedEventEmitter {
5
+ log;
6
+ gateways;
7
+ findGateways;
8
+ portMappingClient;
9
+ started;
10
+ constructor(components, init) {
11
+ super();
12
+ this.log = components.logger.forComponent('libp2p:upnp-nat');
13
+ this.portMappingClient = init.portMappingClient;
14
+ this.started = false;
15
+ this.gateways = [];
16
+ // every five minutes, search for network gateways for one minute
17
+ this.findGateways = repeatingTask(async (options) => {
18
+ for await (const gateway of this.portMappingClient.findGateways({
19
+ ...options,
20
+ searchInterval: 10000
21
+ })) {
22
+ if (this.gateways.some(g => {
23
+ return g.id === gateway.id && g.family === gateway.family;
24
+ })) {
25
+ // already seen this gateway
26
+ continue;
27
+ }
28
+ this.gateways.push(gateway);
29
+ this.safeDispatchEvent('gateway', {
30
+ detail: gateway
31
+ });
32
+ }
33
+ }, DEFAULT_GATEWAY_SEARCH_INTERVAL, {
34
+ runImmediately: true,
35
+ timeout: DEFAULT_GATEWAY_SEARCH_TIMEOUT
36
+ });
37
+ }
38
+ async start() {
39
+ if (this.started) {
40
+ return;
41
+ }
42
+ this.started = true;
43
+ await start(this.findGateways);
44
+ }
45
+ /**
46
+ * Stops the NAT manager
47
+ */
48
+ async stop() {
49
+ await stop(this.findGateways);
50
+ this.started = false;
51
+ }
52
+ }
53
+ //# sourceMappingURL=gateway-finder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-finder.js","sourceRoot":"","sources":["../../src/gateway-finder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,EAAE,+BAA+B,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAA;AAiBhG,MAAM,OAAO,aAAc,SAAQ,iBAAsC;IACtD,GAAG,CAAQ;IACX,QAAQ,CAAW;IACnB,YAAY,CAAe;IAC3B,iBAAiB,CAAS;IACnC,OAAO,CAAS;IAExB,YAAa,UAAmC,EAAE,IAAuB;QACvE,KAAK,EAAE,CAAA;QAEP,IAAI,CAAC,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAA;QAC5D,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAA;QAC/C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACpB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAA;QAElB,iEAAiE;QACjE,IAAI,CAAC,YAAY,GAAG,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YAClD,IAAI,KAAK,EAAE,MAAM,OAAO,IAAI,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC;gBAC9D,GAAG,OAAO;gBACV,cAAc,EAAE,KAAK;aACtB,CAAC,EAAE,CAAC;gBACH,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;oBACzB,OAAO,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,CAAA;gBAC3D,CAAC,CAAC,EAAE,CAAC;oBACH,4BAA4B;oBAC5B,SAAQ;gBACV,CAAC;gBAED,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBAC3B,IAAI,CAAC,iBAAiB,CAAC,SAAS,EAAE;oBAChC,MAAM,EAAE,OAAO;iBAChB,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,EAAE,+BAA+B,EAAE;YAClC,cAAc,EAAE,IAAI;YACpB,OAAO,EAAE,8BAA8B;SACxC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAM;QACR,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA;QACnB,MAAM,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAChC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QAC7B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;IACtB,CAAC;CACF"}
@@ -34,10 +34,10 @@
34
34
  * })
35
35
  * ```
36
36
  */
37
- import { type NatAPI, type MapPortOptions } from './upnp-nat.js';
37
+ import type { UPnPNAT as UPnPNATClient, MapPortOptions } from '@achingbrain/nat-port-mapper';
38
38
  import type { ComponentLogger, Libp2pEvents, NodeInfo, PeerId, TypedEventTarget } from '@libp2p/interface';
39
39
  import type { AddressManager } from '@libp2p/interface-internal';
40
- export type { NatAPI, MapPortOptions };
40
+ export type { UPnPNATClient, MapPortOptions };
41
41
  export interface PMPOptions {
42
42
  /**
43
43
  * Whether to enable PMP as well as UPnP
@@ -45,11 +45,6 @@ export interface PMPOptions {
45
45
  enabled?: boolean;
46
46
  }
47
47
  export interface UPnPNATInit {
48
- /**
49
- * Pass a string to hard code the external address, otherwise it will be
50
- * auto-detected
51
- */
52
- externalAddress?: string;
53
48
  /**
54
49
  * Check if the external address has changed this often in ms. Ignored if an
55
50
  * external address is specified.
@@ -64,40 +59,44 @@ export interface UPnPNATInit {
64
59
  * @default 10000
65
60
  */
66
61
  externalAddressCheckTimeout?: number;
67
- /**
68
- * Pass a value to use instead of auto-detection
69
- */
70
- localAddress?: string;
71
62
  /**
72
63
  * A string value to use for the port mapping description on the gateway
73
64
  */
74
- description?: string;
75
- /**
76
- * How long UPnP port mappings should last for in seconds (minimum 1200)
77
- */
78
- ttl?: number;
65
+ portMappingDescription?: string;
79
66
  /**
80
- * Whether to automatically refresh UPnP port mappings when their TTL is reached
67
+ * How long UPnP port mappings should last for in ms
68
+ *
69
+ * @default 720_000
81
70
  */
82
- keepAlive?: boolean;
71
+ portMappingTTL?: number;
83
72
  /**
84
- * Pass a value to use instead of auto-detection
73
+ * Whether to automatically refresh UPnP port mappings when their TTL is
74
+ * reached
75
+ *
76
+ * @default true
85
77
  */
86
- gateway?: string;
78
+ portMappingAutoRefresh?: boolean;
87
79
  /**
88
- * Ports are mapped when the `self:peer:update` event fires, which happens
89
- * when the node's addresses change. To avoid starting to map ports while
90
- * multiple addresses are being added, the mapping function is debounced by
91
- * this number of ms
80
+ * How long before a port mapping expires to refresh it in ms
92
81
  *
93
- * @default 5000
82
+ * @default 60_000
94
83
  */
95
- delay?: number;
84
+ portMappingRefreshThreshold?: number;
96
85
  /**
97
86
  * A preconfigured instance of a NatAPI client can be passed as an option,
98
87
  * otherwise one will be created
99
88
  */
100
- client?: NatAPI;
89
+ portMappingClient?: UPnPNATClient;
90
+ /**
91
+ * Any mapped addresses are added to the observed address list. These
92
+ * addresses require additional verification by the `@libp2p/autonat` protocol
93
+ * or similar before they are trusted.
94
+ *
95
+ * To skip this verification and trust them immediately pass `true` here
96
+ *
97
+ * @default false
98
+ */
99
+ autoConfirmAddress?: boolean;
101
100
  }
102
101
  export interface UPnPNATComponents {
103
102
  peerId: PeerId;
@@ -107,7 +106,7 @@ export interface UPnPNATComponents {
107
106
  events: TypedEventTarget<Libp2pEvents>;
108
107
  }
109
108
  export interface UPnPNAT {
110
- client: NatAPI;
109
+ portMappingClient: UPnPNATClient;
111
110
  }
112
111
  export declare function uPnPNAT(init?: UPnPNATInit): (components: UPnPNATComponents) => UPnPNAT;
113
112
  //# sourceMappingURL=index.d.ts.map
@@ -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;;;;;;;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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC5F,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,aAAa,EAAE,cAAc,EAAE,CAAA;AAE7C,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAA;IAErC;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAA;IAEpC;;OAEG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAE/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAEhC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,MAAM,CAAA;IAEpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,aAAa,CAAA;IAEjC;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;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,iBAAiB,EAAE,aAAa,CAAA;CACjC;AAED,wBAAgB,OAAO,CAAE,IAAI,GAAE,WAAgB,GAAG,CAAC,UAAU,EAAE,iBAAiB,KAAK,OAAO,CAI3F"}
@@ -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;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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,eAAe,CAAA;AAwFvD,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"}
@@ -1,42 +1,29 @@
1
- import { serviceCapabilities } from '@libp2p/interface';
1
+ import { serviceCapabilities, serviceDependencies } from '@libp2p/interface';
2
2
  import type { UPnPNATComponents, UPnPNATInit, UPnPNAT as UPnPNATInterface } from './index.js';
3
- import type { NatAPI, MapPortOptions } from '@achingbrain/nat-port-mapper';
3
+ import type { Gateway, UPnPNAT as UPnPNATClient } from '@achingbrain/nat-port-mapper';
4
4
  import type { Startable } from '@libp2p/interface';
5
- export type { NatAPI, MapPortOptions };
6
5
  export declare class UPnPNAT implements Startable, UPnPNATInterface {
7
- client: NatAPI;
8
- private readonly addressManager;
9
- private readonly events;
10
- private readonly externalAddress;
11
- private readonly description;
12
- private readonly ttl;
13
- private readonly keepAlive;
14
- private readonly gateway?;
15
- private started;
16
6
  private readonly log;
17
- private readonly mappedPorts;
18
- private readonly onSelfPeerUpdate;
7
+ private readonly components;
8
+ private readonly init;
9
+ private started;
10
+ portMappingClient: UPnPNATClient;
19
11
  private shutdownController?;
12
+ private readonly mapIpAddressesDebounced;
13
+ private readonly gatewayFinder;
14
+ private readonly portMappers;
15
+ private readonly autoConfirmAddress;
20
16
  constructor(components: UPnPNATComponents, init: UPnPNATInit);
21
17
  readonly [Symbol.toStringTag] = "@libp2p/upnp-nat";
22
18
  readonly [serviceCapabilities]: string[];
19
+ get [serviceDependencies](): string[];
23
20
  isStarted(): boolean;
24
21
  start(): Promise<void>;
25
22
  /**
26
23
  * Stops the NAT manager
27
24
  */
28
25
  stop(): Promise<void>;
29
- _onSelfPeerUpdate(): void;
30
- private getUnmappedAddresses;
26
+ onGatewayDiscovered(event: CustomEvent<Gateway>): void;
31
27
  mapIpAddresses(): Promise<void>;
32
- /**
33
- * Some ISPs have double-NATs, there's not much we can do with them
34
- */
35
- private assertNotBehindDoubleNAT;
36
- /**
37
- * Update the local address mappings when the gateway's external interface
38
- * address changes
39
- */
40
- private remapPorts;
41
28
  }
42
29
  //# 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,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"}
1
+ {"version":3,"file":"upnp-nat.d.ts","sourceRoot":"","sources":["../../src/upnp-nat.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAgC,MAAM,mBAAmB,CAAA;AAI1G,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7F,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,8BAA8B,CAAA;AACrF,OAAO,KAAK,EAAU,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAG1D,qBAAa,OAAQ,YAAW,SAAS,EAAE,gBAAgB;IACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,OAAO,CAAS;IACjB,iBAAiB,EAAE,aAAa,CAAA;IACvC,OAAO,CAAC,kBAAkB,CAAC,CAAiB;IAC5C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAmB;IAC3D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAkB;IAC9C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;gBAE/B,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE,WAAW;IAgC7D,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,sBAAqB;IAElD,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAEvC;IAED,IAAI,CAAC,mBAAmB,CAAC,IAAK,MAAM,EAAE,CAQrC;IAED,SAAS,IAAK,OAAO;IAIf,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAa7B;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;IAQ5B,mBAAmB,CAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAejD,cAAc,IAAK,OAAO,CAAC,IAAI,CAAC;CAWvC"}
@@ -1,67 +1,59 @@
1
1
  import { upnpNat } from '@achingbrain/nat-port-mapper';
2
- import { isIPv4, isIPv6 } from '@chainsafe/is-ip';
3
- import { InvalidParametersError, serviceCapabilities, setMaxListeners, start, stop } from '@libp2p/interface';
2
+ import { serviceCapabilities, serviceDependencies, setMaxListeners, start, stop } from '@libp2p/interface';
4
3
  import { debounce } from '@libp2p/utils/debounce';
5
- import { isLoopback } from '@libp2p/utils/multiaddr/is-loopback';
6
- import { isPrivate } from '@libp2p/utils/multiaddr/is-private';
7
- import { isPrivateIp } from '@libp2p/utils/private-ip';
8
- import { QUICV1, TCP, WebSockets, WebSocketsSecure, WebTransport } from '@multiformats/multiaddr-matcher';
9
- import { dynamicExternalAddress, staticExternalAddress } from './check-external-address.js';
10
- import { DoubleNATError, InvalidIPAddressError } from './errors.js';
11
- const DEFAULT_TTL = 7200;
4
+ import { GatewayFinder } from './gateway-finder.js';
5
+ import { UPnPPortMapper } from './upnp-port-mapper.js';
12
6
  export class UPnPNAT {
13
- client;
14
- addressManager;
15
- events;
16
- externalAddress;
17
- description;
18
- ttl;
19
- keepAlive;
20
- gateway;
21
- started;
22
7
  log;
23
- mappedPorts;
24
- onSelfPeerUpdate;
8
+ components;
9
+ init;
10
+ started;
11
+ portMappingClient;
25
12
  shutdownController;
13
+ mapIpAddressesDebounced;
14
+ gatewayFinder;
15
+ portMappers;
16
+ autoConfirmAddress;
26
17
  constructor(components, init) {
27
18
  this.log = components.logger.forComponent('libp2p:upnp-nat');
28
- this.addressManager = components.addressManager;
29
- this.events = components.events;
19
+ this.components = components;
20
+ this.init = init;
30
21
  this.started = false;
31
- this.description = init.description ?? `${components.nodeInfo.name}@${components.nodeInfo.version} ${components.peerId.toString()}`;
32
- this.ttl = init.ttl ?? DEFAULT_TTL;
33
- this.keepAlive = init.keepAlive ?? true;
34
- this.gateway = init.gateway;
35
- this.mappedPorts = new Map();
36
- if (this.ttl < DEFAULT_TTL) {
37
- throw new InvalidParametersError(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`);
38
- }
39
- this.client = init.client ?? upnpNat({
40
- description: this.description,
41
- ttl: this.ttl,
42
- keepAlive: this.keepAlive,
43
- gateway: this.gateway
22
+ this.portMappers = [];
23
+ this.autoConfirmAddress = init.autoConfirmAddress ?? false;
24
+ this.portMappingClient = init.portMappingClient ?? upnpNat({
25
+ description: init.portMappingDescription ?? `${components.nodeInfo.name}@${components.nodeInfo.version} ${components.peerId.toString()}`,
26
+ ttl: init.portMappingTTL,
27
+ autoRefresh: init.portMappingAutoRefresh,
28
+ refreshThreshold: init.portMappingRefreshThreshold
44
29
  });
45
- this.onSelfPeerUpdate = debounce(this._onSelfPeerUpdate.bind(this), init.delay ?? 5000);
46
- if (typeof init.externalAddress === 'string') {
47
- this.externalAddress = staticExternalAddress(init.externalAddress);
48
- }
49
- else {
50
- this.externalAddress = dynamicExternalAddress({
51
- client: this.client,
52
- addressManager: this.addressManager,
53
- logger: components.logger
54
- }, {
55
- interval: init.externalAddressCheckInterval,
56
- timeout: init.externalAddressCheckTimeout,
57
- onExternalAddressChange: this.remapPorts.bind(this)
58
- });
59
- }
30
+ // trigger update when our addresses change
31
+ this.mapIpAddressesDebounced = debounce(async () => {
32
+ try {
33
+ await this.mapIpAddresses();
34
+ }
35
+ catch (err) {
36
+ this.log.error('error mapping IP addresses - %e', err);
37
+ }
38
+ }, 5_000);
39
+ // trigger update when we discovery gateways on the network
40
+ this.gatewayFinder = new GatewayFinder(components, {
41
+ portMappingClient: this.portMappingClient
42
+ });
43
+ this.onGatewayDiscovered = this.onGatewayDiscovered.bind(this);
60
44
  }
61
45
  [Symbol.toStringTag] = '@libp2p/upnp-nat';
62
46
  [serviceCapabilities] = [
63
47
  '@libp2p/nat-traversal'
64
48
  ];
49
+ get [serviceDependencies]() {
50
+ if (!this.autoConfirmAddress) {
51
+ return [
52
+ '@libp2p/autonat'
53
+ ];
54
+ }
55
+ return [];
56
+ }
65
57
  isStarted() {
66
58
  return this.started;
67
59
  }
@@ -72,133 +64,40 @@ export class UPnPNAT {
72
64
  this.started = true;
73
65
  this.shutdownController = new AbortController();
74
66
  setMaxListeners(Infinity, this.shutdownController.signal);
75
- this.events.addEventListener('self:peer:update', this.onSelfPeerUpdate);
76
- await start(this.externalAddress, this.onSelfPeerUpdate);
67
+ this.components.events.addEventListener('self:peer:update', this.mapIpAddressesDebounced);
68
+ this.gatewayFinder.addEventListener('gateway', this.onGatewayDiscovered);
69
+ await start(this.mapIpAddressesDebounced, this.gatewayFinder, ...this.portMappers);
77
70
  }
78
71
  /**
79
72
  * Stops the NAT manager
80
73
  */
81
74
  async stop() {
82
- try {
83
- await this.client?.close();
84
- }
85
- catch (err) {
86
- this.log.error(err);
87
- }
88
75
  this.shutdownController?.abort();
89
- this.events.removeEventListener('self:peer:update', this.onSelfPeerUpdate);
90
- await stop(this.externalAddress, this.onSelfPeerUpdate);
76
+ this.components.events.removeEventListener('self:peer:update', this.mapIpAddressesDebounced);
77
+ this.gatewayFinder.removeEventListener('gateway', this.onGatewayDiscovered);
78
+ await stop(this.mapIpAddressesDebounced, this.gatewayFinder, ...this.portMappers);
91
79
  this.started = false;
92
80
  }
93
- _onSelfPeerUpdate() {
94
- this.mapIpAddresses()
95
- .catch(err => {
96
- this.log.error('error mapping IP addresses - %e', err);
81
+ onGatewayDiscovered(event) {
82
+ const mapper = new UPnPPortMapper(this.components, {
83
+ ...this.init,
84
+ gateway: event.detail
97
85
  });
98
- }
99
- getUnmappedAddresses(multiaddrs, ipType) {
100
- const output = [];
101
- for (const ma of multiaddrs) {
102
- // ignore public addresses
103
- if (!isPrivate(ma)) {
104
- continue;
105
- }
106
- // ignore loopback
107
- if (isLoopback(ma)) {
108
- continue;
109
- }
110
- // only IP based addresses
111
- if (!(TCP.exactMatch(ma) ||
112
- WebSockets.exactMatch(ma) ||
113
- WebSocketsSecure.exactMatch(ma) ||
114
- QUICV1.exactMatch(ma) ||
115
- WebTransport.exactMatch(ma))) {
116
- continue;
117
- }
118
- const { port, host, family, transport } = ma.toOptions();
119
- if (family !== ipType) {
120
- continue;
121
- }
122
- if (this.mappedPorts.has(`${host}-${port}-${transport}`)) {
123
- continue;
124
- }
125
- output.push(ma);
126
- }
127
- return output;
86
+ this.portMappers.push(mapper);
87
+ start(mapper)
88
+ .then(() => {
89
+ this.mapIpAddressesDebounced();
90
+ })
91
+ .catch(() => { });
128
92
  }
129
93
  async mapIpAddresses() {
130
- const externalHost = await this.externalAddress.getPublicIp({
131
- signal: this.shutdownController?.signal
132
- });
133
- let ipType = 4;
134
- if (isIPv4(externalHost)) {
135
- ipType = 4;
136
- }
137
- else if (isIPv6(externalHost)) {
138
- ipType = 6;
139
- }
140
- else {
141
- throw new InvalidIPAddressError(`Public address ${externalHost} was not an IPv4 address`);
142
- }
143
- // filter addresses to get private, non-relay, IP based addresses that we
144
- // haven't mapped yet
145
- const addresses = this.getUnmappedAddresses(this.addressManager.getAddresses(), ipType);
146
- if (addresses.length === 0) {
147
- this.log('no private, non-relay, unmapped, IP based addresses found');
148
- return;
149
- }
150
- this.log('%s public IP %s', this.externalAddress != null ? 'using configured' : 'discovered', externalHost);
151
- this.assertNotBehindDoubleNAT(externalHost);
152
- for (const addr of addresses) {
153
- // try to open uPnP ports for each thin waist address
154
- const { family, host, port, transport } = addr.toOptions();
155
- if (family === 6) {
156
- // only support IPv4 addresses
157
- continue;
158
- }
159
- if (this.mappedPorts.has(`${host}-${port}-${transport}`)) {
160
- // already mapped this port
161
- continue;
162
- }
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');
175
- }
176
- catch (err) {
177
- this.log.error('failed to create mapping of %s:%s - %e', host, port, err);
178
- }
179
- }
180
- }
181
- /**
182
- * Some ISPs have double-NATs, there's not much we can do with them
183
- */
184
- assertNotBehindDoubleNAT(publicIp) {
185
- const isPrivate = isPrivateIp(publicIp);
186
- if (isPrivate === true) {
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`);
188
- }
189
- if (isPrivate == null) {
190
- throw new InvalidParametersError(`${publicIp} is not an IP address`);
94
+ try {
95
+ await Promise.all(this.portMappers.map(async (mapper) => mapper.mapIpAddresses({
96
+ autoConfirmAddress: this.autoConfirmAddress
97
+ })));
191
98
  }
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');
99
+ catch (err) {
100
+ this.log.error('error mapping IP addresses - %e', err);
202
101
  }
203
102
  }
204
103
  }