Skip to content

Commit a31b420

Browse files
authored
fix(libp2p): filter out dnsaddrs for different peers (#1954)
Some multiaddrs like `/dnsaddr/bootstrap.ipfs.io` resolve to multiple PeerIds. E.g: ```console % dig _dnsaddr.bootstrap.libp2p.io TXT ; <<>> DiG 9.10.6 <<>> _dnsaddr.bootstrap.libp2p.io TXT ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53473 ;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;_dnsaddr.bootstrap.libp2p.io. IN TXT ;; ANSWER SECTION: _dnsaddr.bootstrap.libp2p.io. 261 IN TXT "dnsaddr=/dnsaddr/am6.bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb" _dnsaddr.bootstrap.libp2p.io. 261 IN TXT "dnsaddr=/dnsaddr/ny5.bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa" _dnsaddr.bootstrap.libp2p.io. 261 IN TXT "dnsaddr=/dnsaddr/sg1.bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt" _dnsaddr.bootstrap.libp2p.io. 261 IN TXT "dnsaddr=/dnsaddr/sv15.bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN" ``` This can cause problems when dialing those addresses with a PeerId since resolving the dnsaddr returns addresses with embedded PeerIds that aren't for the node you are trying to dial so filter those out. The errors these cause are non-fatal but do consume resources dialing nodes we aren't going to be able to connect to.
1 parent 4c1a33b commit a31b420

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

packages/libp2p/src/connection-manager/dial-queue.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,22 @@ export class DialQueue {
309309
))
310310
.flat()
311311

312-
// filter out any multiaddrs that we do not have transports for
313-
const filteredAddrs = resolvedAddresses.filter(addr => Boolean(this.transportManager.transportForMultiaddr(addr.multiaddr)))
312+
const filteredAddrs = resolvedAddresses.filter(addr => {
313+
// filter out any multiaddrs that we do not have transports for
314+
if (this.transportManager.transportForMultiaddr(addr.multiaddr) == null) {
315+
return false
316+
}
317+
318+
// if the resolved multiaddr has a PeerID but it's the wrong one, ignore it
319+
// - this can happen with addresses like bootstrap.libp2p.io that resolve
320+
// to multiple different peers
321+
const addrPeerId = addr.multiaddr.getPeerId()
322+
if (peerId != null && addrPeerId != null) {
323+
return peerId.equals(addrPeerId)
324+
}
325+
326+
return true
327+
})
314328

315329
// deduplicate addresses
316330
const dedupedAddrs = new Map<string, Address>()

packages/libp2p/test/connection-manager/dial-queue.spec.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { mockConnection, mockDuplex, mockMultiaddrConnection } from '@libp2p/interface-compliance-tests/mocks'
44
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
5-
import { multiaddr } from '@multiformats/multiaddr'
5+
import { multiaddr, resolvers } from '@multiformats/multiaddr'
66
import { expect } from 'aegir/chai'
77
import delay from 'delay'
88
import pDefer from 'p-defer'
@@ -280,4 +280,52 @@ describe('dial queue', () => {
280280
// Dial attempt finished without connection
281281
expect(signals['/ip4/127.0.0.1/tcp/1233']).to.have.property('aborted', true)
282282
})
283+
284+
it('should ignore DNS addresses for other peers', async () => {
285+
const remotePeer = await createEd25519PeerId()
286+
const otherRemotePeer = await createEd25519PeerId()
287+
const ma = multiaddr(`/dnsaddr/example.com/p2p/${remotePeer}`)
288+
const maStr = `/ip4/123.123.123.123/tcp/2348/p2p/${remotePeer}`
289+
const resolvedAddresses = [
290+
`/ip4/234.234.234.234/tcp/4213/p2p/${otherRemotePeer}`,
291+
maStr
292+
]
293+
294+
let resolvedDNSAddrs = false
295+
let dialedBadAddress = false
296+
297+
// simulate a DNSAddr that resolves to multiple different peers like
298+
// bootstrap.libp2p.io
299+
resolvers.set('dnsaddr', async (addr) => {
300+
if (addr.equals(ma)) {
301+
resolvedDNSAddrs = true
302+
return resolvedAddresses
303+
}
304+
305+
return []
306+
})
307+
308+
dialer = new DialQueue(components, {
309+
maxParallelDials: 50
310+
})
311+
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
312+
313+
const connection = mockConnection(mockMultiaddrConnection(mockDuplex(), remotePeer))
314+
315+
components.transportManager.dial.callsFake(async (ma, opts = {}) => {
316+
if (ma.toString() === maStr) {
317+
await delay(100)
318+
return connection
319+
}
320+
321+
dialedBadAddress = true
322+
throw new Error('Could not dial address')
323+
})
324+
325+
await expect(dialer.dial(ma)).to.eventually.equal(connection)
326+
expect(resolvedDNSAddrs).to.be.true('Did not resolve DNSAddrs')
327+
expect(dialedBadAddress).to.be.false('Dialed address with wrong peer id')
328+
329+
resolvers.delete('dnsaddr')
330+
})
283331
})

packages/libp2p/test/connection-manager/direct.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ describe('dialing (direct, WebSockets)', () => {
165165

166166
const remotePeerId = peerIdFromString(remoteAddr.getPeerId() ?? '')
167167
await localComponents.peerStore.patch(remotePeerId, {
168-
multiaddrs: Array.from({ length: 11 }, (_, i) => multiaddr(`/ip4/127.0.0.1/tcp/1500${i}/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5`))
168+
multiaddrs: Array.from({ length: 11 }, (_, i) => multiaddr(`/ip4/127.0.0.1/tcp/1500${i}/ws/p2p/${remotePeerId.toString()}`))
169169
})
170170

171171
await expect(connectionManager.openConnection(remotePeerId))

0 commit comments

Comments
 (0)