Skip to content

Commit d51c21f

Browse files
authored
fix: use addresses with metadata to map ports (#2878)
To map ports for later verification by autonat, use addresses with metadata to get unverified addresses.
1 parent 1729fca commit d51c21f

File tree

2 files changed

+87
-36
lines changed

2 files changed

+87
-36
lines changed

packages/upnp-nat/src/upnp-port-mapper.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import { DoubleNATError } from './errors.js'
1111
import type { ExternalAddress } from './check-external-address.js'
1212
import type { Gateway } from '@achingbrain/nat-port-mapper'
1313
import type { ComponentLogger, Logger } from '@libp2p/interface'
14-
import type { AddressManager } from '@libp2p/interface-internal'
14+
import type { AddressManager, NodeAddress } from '@libp2p/interface-internal'
1515
import type { Multiaddr } from '@multiformats/multiaddr'
1616

17+
const MAX_DATE = 8_640_000_000_000_000
18+
1719
export interface UPnPPortMapperInit {
1820
gateway: Gateway
1921
externalAddressCheckInterval?: number
@@ -104,10 +106,15 @@ export class UPnPPortMapper {
104106
/**
105107
* Return any eligible multiaddrs that are not mapped on the detected gateway
106108
*/
107-
private getUnmappedAddresses (multiaddrs: Multiaddr[], publicAddresses: string[]): Multiaddr[] {
109+
private getUnmappedAddresses (multiaddrs: NodeAddress[], publicAddresses: string[]): Multiaddr[] {
108110
const output: Multiaddr[] = []
109111

110-
for (const ma of multiaddrs) {
112+
for (const { multiaddr: ma, type } of multiaddrs) {
113+
// only consider transport addresses, ignore mapped/observed addrs
114+
if (type !== 'transport') {
115+
continue
116+
}
117+
111118
const stringTuples = ma.stringTuples()
112119
const address = `${stringTuples[0][1]}`
113120

@@ -132,13 +139,7 @@ export class UPnPPortMapper {
132139
}
133140

134141
// only IP based addresses
135-
if (!(
136-
TCP.exactMatch(ma) ||
137-
WebSockets.exactMatch(ma) ||
138-
WebSocketsSecure.exactMatch(ma) ||
139-
QUICV1.exactMatch(ma) ||
140-
WebTransport.exactMatch(ma)
141-
)) {
142+
if (!this.isIPAddress(ma)) {
142143
continue
143144
}
144145

@@ -160,7 +161,7 @@ export class UPnPPortMapper {
160161

161162
// filter addresses to get private, non-relay, IP based addresses that we
162163
// haven't mapped yet
163-
const addresses = this.getUnmappedAddresses(this.addressManager.getAddresses(), [externalHost])
164+
const addresses = this.getUnmappedAddresses(this.addressManager.getAddressesWithMetadata(), [externalHost])
164165

165166
if (addresses.length === 0) {
166167
this.log('no private, non-relay, unmapped, IP based addresses found')
@@ -203,7 +204,9 @@ export class UPnPPortMapper {
203204
if (options?.autoConfirmAddress === true) {
204205
const ma = multiaddr(`/ip${family}/${host}/${transport}/${port}`)
205206
this.log('auto-confirming IP address %a', ma)
206-
this.addressManager.confirmObservedAddr(ma)
207+
this.addressManager.confirmObservedAddr(ma, {
208+
ttl: MAX_DATE - Date.now()
209+
})
207210
}
208211
} catch (err) {
209212
this.log.error('failed to create mapping for %s:%d for protocol - %e', host, port, transport, err)
@@ -228,4 +231,12 @@ export class UPnPPortMapper {
228231
throw new InvalidParametersError(`${publicIp} is not an IP address`)
229232
}
230233
}
234+
235+
private isIPAddress (ma: Multiaddr): boolean {
236+
return TCP.exactMatch(ma) ||
237+
WebSockets.exactMatch(ma) ||
238+
WebSocketsSecure.exactMatch(ma) ||
239+
QUICV1.exactMatch(ma) ||
240+
WebTransport.exactMatch(ma)
241+
}
231242
}

packages/upnp-nat/test/index.spec.ts

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,17 @@ describe('UPnP NAT (TCP)', () => {
8181

8282
gateway.externalIp.resolves(externalHost)
8383

84-
components.addressManager.getAddresses.returns([
85-
multiaddr('/ip4/127.0.0.1/tcp/4002'),
86-
multiaddr(`/ip4/${internalHost}/tcp/${internalPort}`)
87-
])
84+
components.addressManager.getAddressesWithMetadata.returns([{
85+
multiaddr: multiaddr('/ip4/127.0.0.1/tcp/4002'),
86+
verified: true,
87+
type: 'transport',
88+
expires: Date.now() + 10_000
89+
}, {
90+
multiaddr: multiaddr(`/ip4/${internalHost}/tcp/${internalPort}`),
91+
verified: true,
92+
type: 'transport',
93+
expires: Date.now() + 10_000
94+
}])
8895

8996
gateway.map.withArgs(internalPort, internalHost).resolves({
9097
internalHost,
@@ -120,10 +127,17 @@ describe('UPnP NAT (TCP)', () => {
120127

121128
gateway.externalIp.resolves(externalHost)
122129

123-
components.addressManager.getAddresses.returns([
124-
multiaddr('/ip4/127.0.0.1/tcp/4002'),
125-
multiaddr(`/ip4/${internalHost}/tcp/${internalPort}`)
126-
])
130+
components.addressManager.getAddressesWithMetadata.returns([{
131+
multiaddr: multiaddr('/ip4/127.0.0.1/tcp/4002'),
132+
verified: true,
133+
type: 'transport',
134+
expires: Date.now() + 10_000
135+
}, {
136+
multiaddr: multiaddr(`/ip4/${internalHost}/tcp/${internalPort}`),
137+
verified: true,
138+
type: 'transport',
139+
expires: Date.now() + 10_000
140+
}])
127141

128142
gateway.map.withArgs(internalPort, internalHost).resolves({
129143
internalHost,
@@ -153,10 +167,17 @@ describe('UPnP NAT (TCP)', () => {
153167

154168
gateway.externalIp.resolves('192.168.1.1')
155169

156-
components.addressManager.getAddresses.returns([
157-
multiaddr('/ip4/127.0.0.1/tcp/4002'),
158-
multiaddr('/ip4/192.168.1.12/tcp/4002')
159-
])
170+
components.addressManager.getAddressesWithMetadata.returns([{
171+
multiaddr: multiaddr('/ip4/127.0.0.1/tcp/4002'),
172+
verified: true,
173+
type: 'transport',
174+
expires: Date.now() + 10_000
175+
}, {
176+
multiaddr: multiaddr('/ip4/192.168.1.12/tcp/4002'),
177+
verified: true,
178+
type: 'transport',
179+
expires: Date.now() + 10_000
180+
}])
160181

161182
await start(natManager)
162183
await natManager.mapIpAddresses()
@@ -177,6 +198,13 @@ describe('UPnP NAT (TCP)', () => {
177198
multiaddr('/ip6/fe80::9400:67ff:fe19:2a0f/tcp/0')
178199
])
179200

201+
components.addressManager.getAddressesWithMetadata.returns([{
202+
multiaddr: multiaddr('/ip6/fe80::9400:67ff:fe19:2a0f/tcp/0'),
203+
verified: true,
204+
type: 'transport',
205+
expires: Date.now() + 10_000
206+
}])
207+
180208
await start(natManager)
181209
await natManager.mapIpAddresses()
182210

@@ -192,9 +220,12 @@ describe('UPnP NAT (TCP)', () => {
192220

193221
gateway.externalIp.resolves('82.3.1.5')
194222

195-
components.addressManager.getAddresses.returns([
196-
multiaddr('/ip6/::1/tcp/0')
197-
])
223+
components.addressManager.getAddressesWithMetadata.returns([{
224+
multiaddr: multiaddr('/ip6/::1/tcp/0'),
225+
verified: true,
226+
type: 'transport',
227+
expires: Date.now() + 10_000
228+
}])
198229

199230
await start(natManager)
200231
await natManager.mapIpAddresses()
@@ -211,9 +242,12 @@ describe('UPnP NAT (TCP)', () => {
211242

212243
gateway.externalIp.resolves('82.3.1.5')
213244

214-
components.addressManager.getAddresses.returns([
215-
multiaddr('/ip4/192.168.1.12/udp/4001')
216-
])
245+
components.addressManager.getAddressesWithMetadata.returns([{
246+
multiaddr: multiaddr('/ip4/192.168.1.12/udp/4001'),
247+
verified: true,
248+
type: 'transport',
249+
expires: Date.now() + 10_000
250+
}])
217251

218252
await start(natManager)
219253
await natManager.mapIpAddresses()
@@ -230,9 +264,12 @@ describe('UPnP NAT (TCP)', () => {
230264

231265
gateway.externalIp.resolves('82.3.1.5')
232266

233-
components.addressManager.getAddresses.returns([
234-
multiaddr('/ip4/127.0.0.1/tcp/4001')
235-
])
267+
components.addressManager.getAddressesWithMetadata.returns([{
268+
multiaddr: multiaddr('/ip4/127.0.0.1/tcp/4001'),
269+
verified: true,
270+
type: 'transport',
271+
expires: Date.now() + 10_000
272+
}])
236273

237274
await start(natManager)
238275
await natManager.mapIpAddresses()
@@ -249,9 +286,12 @@ describe('UPnP NAT (TCP)', () => {
249286

250287
gateway.externalIp.resolves('82.3.1.5')
251288

252-
components.addressManager.getAddresses.returns([
253-
multiaddr('/ip4/127.0.0.1/tcp/4001/sctp/0')
254-
])
289+
components.addressManager.getAddressesWithMetadata.returns([{
290+
multiaddr: multiaddr('/ip4/127.0.0.1/tcp/4001/sctp/0'),
291+
verified: true,
292+
type: 'transport',
293+
expires: Date.now() + 10_000
294+
}])
255295

256296
await start(natManager)
257297
await natManager.mapIpAddresses()

0 commit comments

Comments
 (0)