Skip to content

Commit af723b3

Browse files
authored
fix: do not allow dial to large number of multiaddrs (#954)
1 parent 13cf476 commit af723b3

File tree

5 files changed

+34
-1
lines changed

5 files changed

+34
-1
lines changed

doc/CONFIGURATION.md

+2
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ Dialing in libp2p can be configured to limit the rate of dialing, and how long d
525525
| Name | Type | Description |
526526
|------|------|-------------|
527527
| maxParallelDials | `number` | How many multiaddrs we can dial in parallel. |
528+
| maxAddrsToDial | `number` | How many multiaddrs is the dial allowed to dial for a single peer. |
528529
| maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. |
529530
| dialTimeout | `number` | Second dial timeout per peer in ms. |
530531
| resolvers | `object` | Dial [Resolvers](https://github.com/multiformats/js-multiaddr/blob/master/src/resolvers/index.js) for resolving multiaddrs |
@@ -549,6 +550,7 @@ const node = await Libp2p.create({
549550
},
550551
dialer: {
551552
maxParallelDials: 100,
553+
maxAddrsToDial: 25,
552554
maxDialsPerPeer: 4,
553555
dialTimeout: 30e3,
554556
resolvers: {

src/constants.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module.exports = {
44
DIAL_TIMEOUT: 30e3, // How long in ms a dial attempt is allowed to take
55
MAX_PARALLEL_DIALS: 100, // Maximum allowed concurrent dials
66
MAX_PER_PEER_DIALS: 4, // Allowed parallel dials per DialRequest
7+
MAX_ADDRS_TO_DIAL: 25, // Maximum number of allowed addresses to attempt to dial
78
METRICS: {
89
computeThrottleMaxQueueSize: 1000,
910
computeThrottleTimeout: 2000,

src/dialer/index.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const { codes } = require('../errors')
1919
const {
2020
DIAL_TIMEOUT,
2121
MAX_PARALLEL_DIALS,
22-
MAX_PER_PEER_DIALS
22+
MAX_PER_PEER_DIALS,
23+
MAX_ADDRS_TO_DIAL
2324
} = require('../constants')
2425

2526
/**
@@ -40,6 +41,7 @@ const {
4041
* @typedef {Object} DialerOptions
4142
* @property {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial.
4243
* @property {number} [maxParallelDials = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
44+
* @property {number} [maxAddrsToDial = MAX_ADDRS_TO_DIAL] - Number of max addresses to dial for a given peer.
4345
* @property {number} [maxDialsPerPeer = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
4446
* @property {number} [dialTimeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
4547
* @property {Record<string, Resolver>} [resolvers = {}] - multiaddr resolvers to use when dialing
@@ -65,6 +67,7 @@ class Dialer {
6567
peerStore,
6668
addressSorter = publicAddressesFirst,
6769
maxParallelDials = MAX_PARALLEL_DIALS,
70+
maxAddrsToDial = MAX_ADDRS_TO_DIAL,
6871
dialTimeout = DIAL_TIMEOUT,
6972
maxDialsPerPeer = MAX_PER_PEER_DIALS,
7073
resolvers = {}
@@ -73,6 +76,7 @@ class Dialer {
7376
this.peerStore = peerStore
7477
this.addressSorter = addressSorter
7578
this.maxParallelDials = maxParallelDials
79+
this.maxAddrsToDial = maxAddrsToDial
7680
this.timeout = dialTimeout
7781
this.maxDialsPerPeer = maxDialsPerPeer
7882
this.tokens = [...new Array(maxParallelDials)].map((_, index) => index)
@@ -198,6 +202,11 @@ class Dialer {
198202
// Multiaddrs not supported by the available transports will be filtered out.
199203
const supportedAddrs = addrs.filter(a => this.transportManager.transportForMultiaddr(a))
200204

205+
if (supportedAddrs.length > this.maxAddrsToDial) {
206+
this.peerStore.delete(id)
207+
throw errCode(new Error('dial with more addresses than allowed'), codes.ERR_TOO_MANY_ADDRESSES)
208+
}
209+
201210
return {
202211
id: id.toB58String(),
203212
addrs: supportedAddrs

src/errors.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ exports.codes = {
1616
ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED',
1717
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
1818
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
19+
ERR_TOO_MANY_ADDRESSES: 'ERR_TOO_MANY_ADDRESSES',
1920
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
2021
ERR_RELAYED_DIAL: 'ERR_RELAYED_DIAL',
2122
ERR_DIALED_SELF: 'ERR_DIALED_SELF',

test/dialing/direct.spec.js

+20
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,26 @@ describe('Dialing (direct, WebSockets)', () => {
177177
.and.to.have.property('code', ErrorCodes.ERR_TIMEOUT)
178178
})
179179

180+
it('should throw when a peer advertises more than the allowed number of peers', async () => {
181+
const spy = sinon.spy()
182+
const dialer = new Dialer({
183+
transportManager: localTM,
184+
maxAddrsToDial: 10,
185+
peerStore: {
186+
delete: spy,
187+
addressBook: {
188+
add: () => { },
189+
getMultiaddrsForPeer: () => Array.from({ length: 11 }, (_, i) => new Multiaddr(`/ip4/127.0.0.1/tcp/1500${i}/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5`))
190+
}
191+
}
192+
})
193+
194+
await expect(dialer.connectToPeer(remoteAddr))
195+
.to.eventually.be.rejected()
196+
.and.to.have.property('code', ErrorCodes.ERR_TOO_MANY_ADDRESSES)
197+
expect(spy.calledOnce).to.be.true()
198+
})
199+
180200
it('should sort addresses on dial', async () => {
181201
const peerMultiaddrs = [
182202
new Multiaddr('/ip4/127.0.0.1/tcp/15001/ws'),

0 commit comments

Comments
 (0)