@libp2p/upnp-nat 2.0.11 → 2.0.12-3650283f7

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,16 +1,15 @@
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
- import type { NatAPI } from '@achingbrain/nat-port-mapper'
5
+ import type { Gateway } from '@achingbrain/nat-port-mapper'
7
6
  import type { AbortOptions, ComponentLogger, Logger, Startable } from '@libp2p/interface'
8
7
  import type { AddressManager } from '@libp2p/interface-internal'
9
8
  import type { RepeatingTask } from '@libp2p/utils/repeating-task'
10
9
  import type { DeferredPromise } from 'p-defer'
11
10
 
12
11
  export interface ExternalAddressCheckerComponents {
13
- client: NatAPI
12
+ gateway: Gateway
14
13
  addressManager: AddressManager
15
14
  logger: ComponentLogger
16
15
  }
@@ -18,7 +17,7 @@ export interface ExternalAddressCheckerComponents {
18
17
  export interface ExternalAddressCheckerInit {
19
18
  interval?: number
20
19
  timeout?: number
21
- autoConfirmAddress?: boolean
20
+ onExternalAddressChange?(newExternalAddress: string): void
22
21
  }
23
22
 
24
23
  export interface ExternalAddress {
@@ -30,19 +29,19 @@ export interface ExternalAddress {
30
29
  */
31
30
  class ExternalAddressChecker implements ExternalAddress, Startable {
32
31
  private readonly log: Logger
33
- private readonly client: NatAPI
32
+ private readonly gateway: Gateway
34
33
  private readonly addressManager: AddressManager
35
34
  private started: boolean
36
35
  private lastPublicIp?: string
37
36
  private readonly lastPublicIpPromise: DeferredPromise<string>
38
37
  private readonly check: RepeatingTask
39
- private readonly autoConfirmAddress: boolean
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
- this.client = components.client
42
+ this.gateway = components.gateway
44
43
  this.addressManager = components.addressManager
45
- this.autoConfirmAddress = init.autoConfirmAddress ?? false
44
+ this.onExternalAddressChange = init.onExternalAddressChange
46
45
  this.started = false
47
46
 
48
47
  this.checkExternalAddress = this.checkExternalAddress.bind(this)
@@ -61,14 +60,11 @@ class ExternalAddressChecker implements ExternalAddress, Startable {
61
60
  }
62
61
 
63
62
  await start(this.check)
64
-
65
- this.check.start()
66
63
  this.started = true
67
64
  }
68
65
 
69
66
  async stop (): Promise<void> {
70
67
  await stop(this.check)
71
-
72
68
  this.started = false
73
69
  }
74
70
 
@@ -87,37 +83,21 @@ class ExternalAddressChecker implements ExternalAddress, Startable {
87
83
 
88
84
  private async checkExternalAddress (options?: AbortOptions): Promise<void> {
89
85
  try {
90
- const externalAddress = await this.client.externalIp(options)
86
+ const externalAddress = await this.gateway.externalIp(options)
91
87
 
92
88
  // check if our public address has changed
93
89
  if (this.lastPublicIp != null && externalAddress !== this.lastPublicIp) {
94
90
  this.log('external address changed from %s to %s', this.lastPublicIp, externalAddress)
95
91
 
96
- for (const ma of this.addressManager.getAddresses()) {
97
- const addrString = ma.toString()
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
- }
92
+ // notify listeners that the address has changed
93
+ this.onExternalAddressChange?.(externalAddress)
116
94
  }
117
95
 
118
96
  this.lastPublicIp = externalAddress
119
97
  this.lastPublicIpPromise.resolve(externalAddress)
120
98
  } catch (err: any) {
99
+ this.log.error('could not resolve external address - %e', err)
100
+
121
101
  if (this.lastPublicIp != null) {
122
102
  // ignore the error if we've previously run successfully
123
103
  return
@@ -128,7 +108,7 @@ class ExternalAddressChecker implements ExternalAddress, Startable {
128
108
  }
129
109
  }
130
110
 
131
- export function dynamicExternalAddress (components: ExternalAddressCheckerComponents, init: ExternalAddressCheckerInit = {}): ExternalAddress {
111
+ export function dynamicExternalAddress (components: ExternalAddressCheckerComponents, init: ExternalAddressCheckerInit): ExternalAddress {
132
112
  return new ExternalAddressChecker(components, init)
133
113
  }
134
114
 
@@ -0,0 +1,3 @@
1
+ export const DEFAULT_PORT_MAPPING_TTL = 720_000
2
+ export const DEFAULT_GATEWAY_SEARCH_TIMEOUT = 60_000
3
+ export const DEFAULT_GATEWAY_SEARCH_INTERVAL = 300_000
@@ -0,0 +1,70 @@
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
+ import type { Gateway, UPnPNAT } from '@achingbrain/nat-port-mapper'
5
+ import type { ComponentLogger, Logger } from '@libp2p/interface'
6
+ import type { RepeatingTask } from '@libp2p/utils/repeating-task'
7
+
8
+ export interface GatewayFinderComponents {
9
+ logger: ComponentLogger
10
+ }
11
+
12
+ export interface GatewayFinderInit {
13
+ portMappingClient: UPnPNAT
14
+ }
15
+
16
+ export interface GatewayFinderEvents {
17
+ 'gateway': CustomEvent<Gateway>
18
+ }
19
+
20
+ export class GatewayFinder extends TypedEventEmitter<GatewayFinderEvents> {
21
+ private readonly log: Logger
22
+ private readonly gateways: Gateway[]
23
+ private readonly findGateways: RepeatingTask
24
+ private readonly portMappingClient: UPnPNAT
25
+ private started: boolean
26
+
27
+ constructor (components: GatewayFinderComponents, init: GatewayFinderInit) {
28
+ super()
29
+
30
+ this.log = components.logger.forComponent('libp2p:upnp-nat')
31
+ this.portMappingClient = init.portMappingClient
32
+ this.started = false
33
+ this.gateways = []
34
+
35
+ // every five minutes, search for network gateways for one minute
36
+ this.findGateways = repeatingTask(async (options) => {
37
+ for await (const gateway of this.portMappingClient.findGateways(options)) {
38
+ if (this.gateways.some(g => g.id === gateway.id)) {
39
+ // already seen this gateway
40
+ continue
41
+ }
42
+
43
+ this.gateways.push(gateway)
44
+ this.safeDispatchEvent('gateway', {
45
+ detail: gateway
46
+ })
47
+ }
48
+ }, DEFAULT_GATEWAY_SEARCH_INTERVAL, {
49
+ runImmediately: true,
50
+ timeout: DEFAULT_GATEWAY_SEARCH_TIMEOUT
51
+ })
52
+ }
53
+
54
+ async start (): Promise<void> {
55
+ if (this.started) {
56
+ return
57
+ }
58
+
59
+ this.started = true
60
+ await start(this.findGateways)
61
+ }
62
+
63
+ /**
64
+ * Stops the NAT manager
65
+ */
66
+ async stop (): Promise<void> {
67
+ await stop(this.findGateways)
68
+ this.started = false
69
+ }
70
+ }
package/src/index.ts CHANGED
@@ -35,11 +35,12 @@
35
35
  * ```
36
36
  */
37
37
 
38
- import { UPnPNAT as UPnPNATClass, type NatAPI, type MapPortOptions } from './upnp-nat.js'
38
+ import { UPnPNAT as UPnPNATClass } from './upnp-nat.js'
39
+ import type { UPnPNAT as UPnPNATClient, MapPortOptions } from '@achingbrain/nat-port-mapper'
39
40
  import type { ComponentLogger, Libp2pEvents, NodeInfo, PeerId, TypedEventTarget } from '@libp2p/interface'
40
41
  import type { AddressManager } from '@libp2p/interface-internal'
41
42
 
42
- export type { NatAPI, MapPortOptions }
43
+ export type { UPnPNATClient, MapPortOptions }
43
44
 
44
45
  export interface PMPOptions {
45
46
  /**
@@ -49,12 +50,6 @@ export interface PMPOptions {
49
50
  }
50
51
 
51
52
  export interface UPnPNATInit {
52
- /**
53
- * Pass a string to hard code the external address, otherwise it will be
54
- * auto-detected
55
- */
56
- externalAddress?: string
57
-
58
53
  /**
59
54
  * Check if the external address has changed this often in ms. Ignored if an
60
55
  * external address is specified.
@@ -71,66 +66,31 @@ export interface UPnPNATInit {
71
66
  */
72
67
  externalAddressCheckTimeout?: number
73
68
 
74
- /**
75
- * Pass a value to use instead of auto-detection
76
- */
77
- localAddress?: string
78
-
79
69
  /**
80
70
  * A string value to use for the port mapping description on the gateway
81
71
  */
82
- description?: string
72
+ portMappingDescription?: string
83
73
 
84
74
  /**
85
- * How long UPnP port mappings should last for in seconds (minimum 1200)
86
- */
87
- ttl?: number
88
-
89
- /**
90
- * Whether to automatically refresh UPnP port mappings when their TTL is reached
91
- */
92
- keepAlive?: boolean
93
-
94
- /**
95
- * Pass a value to use instead of auto-detection
96
- */
97
- gateway?: string
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
75
+ * How long UPnP port mappings should last for in ms
103
76
  *
104
- * @default 10000
77
+ * @default 720_000
105
78
  */
106
- gatewayDetectionTimeout?: number
79
+ portMappingTTL?: number
107
80
 
108
81
  /**
109
- * Ports are mapped when the `self:peer:update` event fires, which happens
110
- * when the node's addresses change. To avoid starting to map ports while
111
- * multiple addresses are being added, the mapping function is debounced by
112
- * this number of ms
82
+ * Whether to automatically refresh UPnP port mappings when their TTL is
83
+ * reached
113
84
  *
114
- * @default 5000
85
+ * @default true
115
86
  */
116
- delay?: number
87
+ portMappingAutoRefresh?: boolean
117
88
 
118
89
  /**
119
90
  * A preconfigured instance of a NatAPI client can be passed as an option,
120
91
  * otherwise one will be created
121
92
  */
122
- 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
93
+ portMappingClient?: UPnPNATClient
134
94
  }
135
95
 
136
96
  export interface UPnPNATComponents {
@@ -142,7 +102,7 @@ export interface UPnPNATComponents {
142
102
  }
143
103
 
144
104
  export interface UPnPNAT {
145
- client: NatAPI
105
+ portMappingClient: UPnPNATClient
146
106
  }
147
107
 
148
108
  export function uPnPNAT (init: UPnPNATInit = {}): (components: UPnPNATComponents) => UPnPNAT {
package/src/upnp-nat.ts CHANGED
@@ -1,84 +1,53 @@
1
1
  import { upnpNat } from '@achingbrain/nat-port-mapper'
2
- import { isIPv4, isIPv6 } from '@chainsafe/is-ip'
3
- import { InvalidParametersError, serviceCapabilities, serviceDependencies, start, stop } from '@libp2p/interface'
2
+ import { serviceCapabilities, 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 { multiaddr } from '@multiformats/multiaddr'
9
- import { QUICV1, TCP, WebSockets, WebSocketsSecure, WebTransport } from '@multiformats/multiaddr-matcher'
10
- import { raceSignal } from 'race-signal'
11
- import { dynamicExternalAddress, staticExternalAddress } from './check-external-address.js'
12
- import { DoubleNATError, InvalidIPAddressError } from './errors.js'
13
- import type { ExternalAddress } from './check-external-address.js'
4
+ import { DEFAULT_PORT_MAPPING_TTL } from './constants.js'
5
+ import { GatewayFinder } from './gateway-finder.js'
6
+ import { UPnPPortMapper } from './upnp-port-mapper.js'
14
7
  import type { UPnPNATComponents, UPnPNATInit, UPnPNAT as UPnPNATInterface } from './index.js'
15
- import type { NatAPI, MapPortOptions } from '@achingbrain/nat-port-mapper'
16
- import type { Libp2pEvents, Logger, Startable, TypedEventTarget } from '@libp2p/interface'
17
- import type { AddressManager } from '@libp2p/interface-internal'
8
+ import type { Gateway, UPnPNAT as UPnPNATClient } from '@achingbrain/nat-port-mapper'
9
+ import type { Logger, Startable } from '@libp2p/interface'
18
10
  import type { DebouncedFunction } from '@libp2p/utils/debounce'
19
- import type { Multiaddr } from '@multiformats/multiaddr'
20
-
21
- const DEFAULT_TTL = 7200
22
-
23
- export type { NatAPI, MapPortOptions }
24
11
 
25
12
  export class UPnPNAT implements Startable, UPnPNATInterface {
26
- public client: NatAPI
27
- private readonly addressManager: AddressManager
28
- private readonly events: TypedEventTarget<Libp2pEvents>
29
- private readonly externalAddress: ExternalAddress
30
- private readonly localAddress?: string
31
- private readonly description: string
32
- private readonly ttl: number
33
- private readonly keepAlive: boolean
34
- private readonly gateway?: string
35
- private started: boolean
36
13
  private readonly log: Logger
37
- private readonly gatewayDetectionTimeout: number
38
- private readonly mappedPorts: Map<number, number>
39
- private readonly onSelfPeerUpdate: DebouncedFunction
40
- private readonly autoConfirmAddress: boolean
14
+ private readonly components: UPnPNATComponents
15
+ private readonly init: UPnPNATInit
16
+ private started: boolean
17
+ public portMappingClient: UPnPNATClient
18
+ private shutdownController?: AbortController
19
+ private readonly mapIpAddressesDebounced: DebouncedFunction
20
+ private readonly gatewayFinder: GatewayFinder
21
+ private readonly portMappers: UPnPPortMapper[]
41
22
 
42
23
  constructor (components: UPnPNATComponents, init: UPnPNATInit) {
43
24
  this.log = components.logger.forComponent('libp2p:upnp-nat')
44
- this.addressManager = components.addressManager
45
- this.events = components.events
25
+ this.components = components
26
+ this.init = init
46
27
  this.started = false
47
- this.localAddress = init.localAddress
48
- this.description = init.description ?? `${components.nodeInfo.name}@${components.nodeInfo.version} ${components.peerId.toString()}`
49
- this.ttl = init.ttl ?? DEFAULT_TTL
50
- this.keepAlive = init.keepAlive ?? true
51
- this.gateway = init.gateway
52
- this.gatewayDetectionTimeout = init.gatewayDetectionTimeout ?? 10000
53
- this.autoConfirmAddress = init.autoConfirmAddress ?? false
54
- this.mappedPorts = new Map()
55
-
56
- if (this.ttl < DEFAULT_TTL) {
57
- throw new InvalidParametersError(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`)
58
- }
28
+ this.portMappers = []
59
29
 
60
- this.client = init.client ?? upnpNat({
61
- description: this.description,
62
- ttl: this.ttl,
63
- keepAlive: this.keepAlive,
64
- gateway: this.gateway
30
+ this.portMappingClient = init.portMappingClient ?? upnpNat({
31
+ description: init.portMappingDescription ?? `${components.nodeInfo.name}@${components.nodeInfo.version} ${components.peerId.toString()}`,
32
+ ttl: init.portMappingTTL ?? DEFAULT_PORT_MAPPING_TTL,
33
+ autoRefresh: init.portMappingAutoRefresh ?? true
65
34
  })
66
35
 
67
- this.onSelfPeerUpdate = debounce(this._onSelfPeerUpdate.bind(this), init.delay ?? 5000)
36
+ // trigger update when our addresses change
37
+ this.mapIpAddressesDebounced = debounce(async () => {
38
+ try {
39
+ await this.mapIpAddresses()
40
+ } catch (err: any) {
41
+ this.log.error('error mapping IP addresses - %e', err)
42
+ }
43
+ }, 5_000)
68
44
 
69
- if (typeof init.externalAddress === 'string') {
70
- this.externalAddress = staticExternalAddress(init.externalAddress)
71
- } else {
72
- this.externalAddress = dynamicExternalAddress({
73
- client: this.client,
74
- addressManager: this.addressManager,
75
- logger: components.logger
76
- }, {
77
- autoConfirmAddress: init.autoConfirmAddress,
78
- interval: init.externalAddressCheckInterval,
79
- timeout: init.externalAddressCheckTimeout
80
- })
81
- }
45
+ // trigger update when we discovery gateways on the network
46
+ this.gatewayFinder = new GatewayFinder(components, {
47
+ portMappingClient: this.portMappingClient
48
+ })
49
+
50
+ this.onGatewayDiscovered = this.onGatewayDiscovered.bind(this)
82
51
  }
83
52
 
84
53
  readonly [Symbol.toStringTag] = '@libp2p/upnp-nat'
@@ -87,16 +56,6 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
87
56
  '@libp2p/nat-traversal'
88
57
  ]
89
58
 
90
- get [serviceDependencies] (): string[] {
91
- if (!this.autoConfirmAddress) {
92
- return [
93
- '@libp2p/autonat'
94
- ]
95
- }
96
-
97
- return []
98
- }
99
-
100
59
  isStarted (): boolean {
101
60
  return this.started
102
61
  }
@@ -107,158 +66,46 @@ export class UPnPNAT implements Startable, UPnPNATInterface {
107
66
  }
108
67
 
109
68
  this.started = true
110
- this.events.addEventListener('self:peer:update', this.onSelfPeerUpdate)
111
- await start(this.externalAddress, this.onSelfPeerUpdate)
69
+ this.shutdownController = new AbortController()
70
+ setMaxListeners(Infinity, this.shutdownController.signal)
71
+ this.components.events.addEventListener('self:peer:update', this.mapIpAddressesDebounced)
72
+ this.gatewayFinder.addEventListener('gateway', this.onGatewayDiscovered)
73
+ await start(this.mapIpAddressesDebounced, this.gatewayFinder, ...this.portMappers)
112
74
  }
113
75
 
114
76
  /**
115
77
  * Stops the NAT manager
116
78
  */
117
79
  async stop (): Promise<void> {
118
- try {
119
- await this.client?.close()
120
- } catch (err: any) {
121
- this.log.error(err)
122
- }
123
-
124
- this.events.removeEventListener('self:peer:update', this.onSelfPeerUpdate)
125
- await stop(this.externalAddress, this.onSelfPeerUpdate)
80
+ this.shutdownController?.abort()
81
+ this.components.events.removeEventListener('self:peer:update', this.mapIpAddressesDebounced)
82
+ this.gatewayFinder.removeEventListener('gateway', this.onGatewayDiscovered)
83
+ await stop(this.mapIpAddressesDebounced, this.gatewayFinder, ...this.portMappers)
126
84
  this.started = false
127
85
  }
128
86
 
129
- _onSelfPeerUpdate (): void {
130
- this.mapIpAddresses()
131
- .catch(err => {
132
- this.log.error('error mapping IP addresses - %e', err)
133
- })
134
- }
135
-
136
- private getUnmappedAddresses (multiaddrs: Multiaddr[], ipType: 4 | 6): Multiaddr[] {
137
- const output: Multiaddr[] = []
138
-
139
- for (const ma of multiaddrs) {
140
- // ignore public addresses
141
- if (!isPrivate(ma)) {
142
- continue
143
- }
144
-
145
- // ignore loopback
146
- if (isLoopback(ma)) {
147
- continue
148
- }
149
-
150
- // only IP based addresses
151
- if (!(
152
- TCP.exactMatch(ma) ||
153
- WebSockets.exactMatch(ma) ||
154
- WebSocketsSecure.exactMatch(ma) ||
155
- QUICV1.exactMatch(ma) ||
156
- WebTransport.exactMatch(ma)
157
- )) {
158
- continue
159
- }
160
-
161
- const { port, family } = ma.toOptions()
162
-
163
- if (family !== ipType) {
164
- continue
165
- }
166
-
167
- if (this.mappedPorts.has(port)) {
168
- continue
169
- }
170
-
171
- output.push(ma)
172
- }
173
-
174
- return output
175
- }
176
-
177
- async mapIpAddresses (): Promise<void> {
178
- if (this.externalAddress == null) {
179
- this.log('discovering public address')
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`
87
+ onGatewayDiscovered (event: CustomEvent<Gateway>): void {
88
+ const mapper = new UPnPPortMapper(this.components, {
89
+ ...this.init,
90
+ gateway: event.detail
188
91
  })
189
92
 
190
- let ipType: 4 | 6 = 4
191
-
192
- if (isIPv4(publicIp)) {
193
- ipType = 4
194
- } else if (isIPv6(publicIp)) {
195
- ipType = 6
196
- } else {
197
- throw new InvalidIPAddressError(`Public address ${publicIp} was not an IPv4 address`)
198
- }
199
-
200
- // filter addresses to get private, non-relay, IP based addresses that we
201
- // haven't mapped yet
202
- const addresses = this.getUnmappedAddresses(this.addressManager.getAddresses(), ipType)
203
-
204
- if (addresses.length === 0) {
205
- this.log('no private, non-relay, unmapped, IP based addresses found')
206
- return
207
- }
208
-
209
- this.log('%s public IP %s', this.externalAddress != null ? 'using configured' : 'discovered', publicIp)
210
-
211
- this.assertNotBehindDoubleNAT(publicIp)
212
-
213
- for (const addr of addresses) {
214
- // try to open uPnP ports for each thin waist address
215
- const { family, host, port, transport } = addr.toOptions()
216
-
217
- if (family === 6) {
218
- // only support IPv4 addresses
219
- continue
220
- }
93
+ this.portMappers.push(mapper)
221
94
 
222
- if (this.mappedPorts.has(port)) {
223
- // already mapped this port
224
- continue
225
- }
226
-
227
- const protocol = transport.toUpperCase()
228
-
229
- this.log(`creating mapping of ${host}:${port}`)
230
-
231
- const mappedPort = await this.client.map(port, {
232
- localAddress: host,
233
- protocol: protocol === 'TCP' ? 'TCP' : 'UDP'
95
+ start(mapper)
96
+ .then(() => {
97
+ this.mapIpAddressesDebounced()
234
98
  })
235
-
236
- this.mappedPorts.set(port, mappedPort)
237
-
238
- const ma = multiaddr(addr.toString().replace(`/ip${family}/${host}/${transport}/${port}`, `/ip${family}/${publicIp}/${transport}/${mappedPort}`))
239
-
240
- this.log(`created mapping of ${publicIp}:${mappedPort} to ${host}:${port} as %a`, ma)
241
-
242
- if (this.autoConfirmAddress) {
243
- this.addressManager.confirmObservedAddr(ma)
244
- } else {
245
- this.addressManager.addObservedAddr(ma)
246
- }
247
- }
99
+ .catch(() => {})
248
100
  }
249
101
 
250
- /**
251
- * Some ISPs have double-NATs, there's not much we can do with them
252
- */
253
- private assertNotBehindDoubleNAT (publicIp: string): void {
254
- const isPrivate = isPrivateIp(publicIp)
255
-
256
- if (isPrivate === true) {
257
- throw new DoubleNATError(`${publicIp} is private - please set config.nat.externalIp to an externally routable IP or ensure you are not behind a double NAT`)
258
- }
259
-
260
- if (isPrivate == null) {
261
- throw new InvalidParametersError(`${publicIp} is not an IP address`)
102
+ async mapIpAddresses (): Promise<void> {
103
+ try {
104
+ await Promise.all(
105
+ this.portMappers.map(async mapper => mapper.mapIpAddresses())
106
+ )
107
+ } catch (err: any) {
108
+ this.log.error('error mapping IP addresses - %e', err)
262
109
  }
263
110
  }
264
111
  }