Skip to content

Commit f28c31d

Browse files
authored
fix: handle router mappings of mixed IP version (#2858)
Handle the case where the router has an external IPv4 address but the internal network is IPv6 only, and vice versa.
1 parent 5ac8c8b commit f28c31d

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

packages/libp2p/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"test:webkit": "aegir test -t browser -- --browser webkit"
8686
},
8787
"dependencies": {
88+
"@chainsafe/is-ip": "^2.0.2",
8889
"@libp2p/crypto": "^5.0.7",
8990
"@libp2p/interface": "^2.2.1",
9091
"@libp2p/interface-internal": "^2.1.1",

packages/libp2p/src/address-manager.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isIPv4 } from '@chainsafe/is-ip'
12
import { peerIdFromString } from '@libp2p/peer-id'
23
import { debounce } from '@libp2p/utils/debounce'
34
import { multiaddr, protocols } from '@multiformats/multiaddr'
@@ -149,7 +150,9 @@ export class AddressManager implements AddressManagerInterface {
149150
this.components.peerStore.patch(this.components.peerId, {
150151
multiaddrs: addrs
151152
})
152-
.catch(err => { this.log.error('error updating addresses', err) })
153+
.catch(err => {
154+
this.log.error('error updating addresses', err)
155+
})
153156
}
154157

155158
/**
@@ -267,6 +270,7 @@ export class AddressManager implements AddressManagerInterface {
267270
}
268271

269272
mappings.forEach(mapping => {
273+
tuples[0][0] = isIPv4(mapping.externalIp) ? CODEC_IP4 : CODEC_IP6
270274
tuples[0][1] = mapping.externalIp
271275
tuples[1][1] = `${mapping.externalPort}`
272276

packages/libp2p/test/addresses/address-manager.spec.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,4 +427,76 @@ describe('Address Manager', () => {
427427
multiaddr(`/ip6/${internalIp}/${protocol}/${internalPort}/p2p/${peerId.toString()}`)
428428
])
429429
})
430+
431+
it('should add a public IPv4 address mapping when only local IPv6 addresses are present', () => {
432+
const transportManager = stubInterface<TransportManager>()
433+
const am = new AddressManager({
434+
peerId,
435+
transportManager,
436+
peerStore,
437+
events,
438+
logger: defaultLogger()
439+
})
440+
441+
const internalIp = '2a00:23c6:14b1:7e00:28b8:30d:944e:27f3'
442+
const internalPort = 4567
443+
const externalIp = '81.12.12.1'
444+
const externalPort = 8910
445+
const protocol = 'tcp'
446+
447+
am.addPublicAddressMapping(internalIp, internalPort, externalIp, externalPort, protocol)
448+
449+
// one loopback, one LAN address
450+
transportManager.getAddrs.returns([
451+
multiaddr(`/ip6/${internalIp}/${protocol}/${internalPort}`)
452+
])
453+
454+
// should have mapped the LAN address to the external IP
455+
expect(am.getAddresses()).to.deep.equal([
456+
multiaddr(`/ip6/${internalIp}/${protocol}/${internalPort}/p2p/${peerId.toString()}`),
457+
multiaddr(`/ip4/${externalIp}/${protocol}/${externalPort}/p2p/${peerId.toString()}`)
458+
])
459+
460+
am.removePublicAddressMapping(internalIp, internalPort, externalIp, externalPort, protocol)
461+
462+
expect(am.getAddresses()).to.deep.equal([
463+
multiaddr(`/ip6/${internalIp}/${protocol}/${internalPort}/p2p/${peerId.toString()}`)
464+
])
465+
})
466+
467+
it('should add a public IPv6 address mapping when only local IPv4 addresses are present', () => {
468+
const transportManager = stubInterface<TransportManager>()
469+
const am = new AddressManager({
470+
peerId,
471+
transportManager,
472+
peerStore,
473+
events,
474+
logger: defaultLogger()
475+
})
476+
477+
const internalIp = '192.168.1.123'
478+
const internalPort = 4567
479+
const externalIp = '2a00:23c6:14b1:7e00:28b8:30d:944e:27f3'
480+
const externalPort = 8910
481+
const protocol = 'tcp'
482+
483+
am.addPublicAddressMapping(internalIp, internalPort, externalIp, externalPort, protocol)
484+
485+
// one loopback, one LAN address
486+
transportManager.getAddrs.returns([
487+
multiaddr(`/ip4/${internalIp}/${protocol}/${internalPort}`)
488+
])
489+
490+
// should have mapped the LAN address to the external IP
491+
expect(am.getAddresses()).to.deep.equal([
492+
multiaddr(`/ip4/${internalIp}/${protocol}/${internalPort}/p2p/${peerId.toString()}`),
493+
multiaddr(`/ip6/${externalIp}/${protocol}/${externalPort}/p2p/${peerId.toString()}`)
494+
])
495+
496+
am.removePublicAddressMapping(internalIp, internalPort, externalIp, externalPort, protocol)
497+
498+
expect(am.getAddresses()).to.deep.equal([
499+
multiaddr(`/ip4/${internalIp}/${protocol}/${internalPort}/p2p/${peerId.toString()}`)
500+
])
501+
})
430502
})

0 commit comments

Comments
 (0)