fix: do not allow dial to large number of multiaddrs (#954)

This commit is contained in:
Vasco Santos 2021-07-09 08:46:24 +02:00 committed by GitHub
parent 13cf476148
commit af723b355e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 1 deletions

View File

@ -525,6 +525,7 @@ Dialing in libp2p can be configured to limit the rate of dialing, and how long d
| Name | Type | Description | | Name | Type | Description |
|------|------|-------------| |------|------|-------------|
| maxParallelDials | `number` | How many multiaddrs we can dial in parallel. | | maxParallelDials | `number` | How many multiaddrs we can dial in parallel. |
| maxAddrsToDial | `number` | How many multiaddrs is the dial allowed to dial for a single peer. |
| maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. | | maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. |
| dialTimeout | `number` | Second dial timeout per peer in ms. | | dialTimeout | `number` | Second dial timeout per peer in ms. |
| resolvers | `object` | Dial [Resolvers](https://github.com/multiformats/js-multiaddr/blob/master/src/resolvers/index.js) for resolving multiaddrs | | 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({
}, },
dialer: { dialer: {
maxParallelDials: 100, maxParallelDials: 100,
maxAddrsToDial: 25,
maxDialsPerPeer: 4, maxDialsPerPeer: 4,
dialTimeout: 30e3, dialTimeout: 30e3,
resolvers: { resolvers: {

View File

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

View File

@ -19,7 +19,8 @@ const { codes } = require('../errors')
const { const {
DIAL_TIMEOUT, DIAL_TIMEOUT,
MAX_PARALLEL_DIALS, MAX_PARALLEL_DIALS,
MAX_PER_PEER_DIALS MAX_PER_PEER_DIALS,
MAX_ADDRS_TO_DIAL
} = require('../constants') } = require('../constants')
/** /**
@ -40,6 +41,7 @@ const {
* @typedef {Object} DialerOptions * @typedef {Object} DialerOptions
* @property {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial. * @property {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial.
* @property {number} [maxParallelDials = MAX_PARALLEL_DIALS] - Number of max concurrent dials. * @property {number} [maxParallelDials = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
* @property {number} [maxAddrsToDial = MAX_ADDRS_TO_DIAL] - Number of max addresses to dial for a given peer.
* @property {number} [maxDialsPerPeer = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer. * @property {number} [maxDialsPerPeer = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
* @property {number} [dialTimeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take. * @property {number} [dialTimeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
* @property {Record<string, Resolver>} [resolvers = {}] - multiaddr resolvers to use when dialing * @property {Record<string, Resolver>} [resolvers = {}] - multiaddr resolvers to use when dialing
@ -65,6 +67,7 @@ class Dialer {
peerStore, peerStore,
addressSorter = publicAddressesFirst, addressSorter = publicAddressesFirst,
maxParallelDials = MAX_PARALLEL_DIALS, maxParallelDials = MAX_PARALLEL_DIALS,
maxAddrsToDial = MAX_ADDRS_TO_DIAL,
dialTimeout = DIAL_TIMEOUT, dialTimeout = DIAL_TIMEOUT,
maxDialsPerPeer = MAX_PER_PEER_DIALS, maxDialsPerPeer = MAX_PER_PEER_DIALS,
resolvers = {} resolvers = {}
@ -73,6 +76,7 @@ class Dialer {
this.peerStore = peerStore this.peerStore = peerStore
this.addressSorter = addressSorter this.addressSorter = addressSorter
this.maxParallelDials = maxParallelDials this.maxParallelDials = maxParallelDials
this.maxAddrsToDial = maxAddrsToDial
this.timeout = dialTimeout this.timeout = dialTimeout
this.maxDialsPerPeer = maxDialsPerPeer this.maxDialsPerPeer = maxDialsPerPeer
this.tokens = [...new Array(maxParallelDials)].map((_, index) => index) this.tokens = [...new Array(maxParallelDials)].map((_, index) => index)
@ -198,6 +202,11 @@ class Dialer {
// Multiaddrs not supported by the available transports will be filtered out. // Multiaddrs not supported by the available transports will be filtered out.
const supportedAddrs = addrs.filter(a => this.transportManager.transportForMultiaddr(a)) const supportedAddrs = addrs.filter(a => this.transportManager.transportForMultiaddr(a))
if (supportedAddrs.length > this.maxAddrsToDial) {
this.peerStore.delete(id)
throw errCode(new Error('dial with more addresses than allowed'), codes.ERR_TOO_MANY_ADDRESSES)
}
return { return {
id: id.toB58String(), id: id.toB58String(),
addrs: supportedAddrs addrs: supportedAddrs

View File

@ -16,6 +16,7 @@ exports.codes = {
ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED', ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED',
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED', ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED', ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
ERR_TOO_MANY_ADDRESSES: 'ERR_TOO_MANY_ADDRESSES',
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES', ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
ERR_RELAYED_DIAL: 'ERR_RELAYED_DIAL', ERR_RELAYED_DIAL: 'ERR_RELAYED_DIAL',
ERR_DIALED_SELF: 'ERR_DIALED_SELF', ERR_DIALED_SELF: 'ERR_DIALED_SELF',

View File

@ -177,6 +177,26 @@ describe('Dialing (direct, WebSockets)', () => {
.and.to.have.property('code', ErrorCodes.ERR_TIMEOUT) .and.to.have.property('code', ErrorCodes.ERR_TIMEOUT)
}) })
it('should throw when a peer advertises more than the allowed number of peers', async () => {
const spy = sinon.spy()
const dialer = new Dialer({
transportManager: localTM,
maxAddrsToDial: 10,
peerStore: {
delete: spy,
addressBook: {
add: () => { },
getMultiaddrsForPeer: () => Array.from({ length: 11 }, (_, i) => new Multiaddr(`/ip4/127.0.0.1/tcp/1500${i}/ws/p2p/12D3KooWHFKTMzwerBtsVmtz4ZZEQy2heafxzWw6wNn5PPYkBxJ5`))
}
}
})
await expect(dialer.connectToPeer(remoteAddr))
.to.eventually.be.rejected()
.and.to.have.property('code', ErrorCodes.ERR_TOO_MANY_ADDRESSES)
expect(spy.calledOnce).to.be.true()
})
it('should sort addresses on dial', async () => { it('should sort addresses on dial', async () => {
const peerMultiaddrs = [ const peerMultiaddrs = [
new Multiaddr('/ip4/127.0.0.1/tcp/15001/ws'), new Multiaddr('/ip4/127.0.0.1/tcp/15001/ws'),