Skip to content

Commit 29eb610

Browse files
authored
refactor: extract DCUtR utils (#2184)
In order to get a better view on testing DCUtR, split the utility functions out to test them separately starting with `isPublicAndDialable`.
1 parent 24ff6e9 commit 29eb610

File tree

3 files changed

+75
-35
lines changed

3 files changed

+75
-35
lines changed

packages/libp2p/src/dcutr/dcutr.ts

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import { CodeError } from '@libp2p/interface/errors'
22
import { logger } from '@libp2p/logger'
33
import { type Multiaddr, multiaddr } from '@multiformats/multiaddr'
4-
import { Circuit, IP, DNS } from '@multiformats/multiaddr-matcher'
54
import delay from 'delay'
65
import { pbStream } from 'it-protobuf-stream'
7-
import isPrivate from 'private-ip'
86
import { codes } from '../errors.js'
97
import { HolePunch } from './pb/message.js'
8+
import { isPublicAndDialable } from './utils.js'
109
import { multicodec } from './index.js'
1110
import type { DCUtRServiceComponents, DCUtRServiceInit } from './index.js'
1211
import type { Connection, Stream } from '@libp2p/interface/connection'
@@ -242,7 +241,7 @@ export class DefaultDCUtRService implements Startable {
242241
return ma
243242
})
244243
.filter(ma => {
245-
return this.isPublicAndDialable(ma)
244+
return isPublicAndDialable(ma, this.transportManager)
246245
})
247246

248247
if (publicAddresses.length > 0) {
@@ -366,7 +365,7 @@ export class DefaultDCUtRService implements Startable {
366365
try {
367366
const ma = multiaddr(addr)
368367

369-
if (!this.isPublicAndDialable(ma)) {
368+
if (!isPublicAndDialable(ma, this.transportManager)) {
370369
continue
371370
}
372371

@@ -376,35 +375,4 @@ export class DefaultDCUtRService implements Startable {
376375

377376
return output
378377
}
379-
380-
/**
381-
* Returns true if the passed multiaddr is public, not relayed and we have a
382-
* transport that can dial it
383-
*/
384-
isPublicAndDialable (ma: Multiaddr): boolean {
385-
// ignore circuit relay
386-
if (Circuit.matches(ma)) {
387-
return false
388-
}
389-
390-
// dns addresses are probably public?
391-
if (DNS.matches(ma)) {
392-
return true
393-
}
394-
395-
// ensure we have only IPv4/IPv6 addresses
396-
if (!IP.matches(ma)) {
397-
return false
398-
}
399-
400-
const transport = this.transportManager.transportForMultiaddr(ma)
401-
402-
if (transport == null) {
403-
return false
404-
}
405-
406-
const options = ma.toOptions()
407-
408-
return isPrivate(options.host) === false
409-
}
410378
}

packages/libp2p/src/dcutr/utils.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { type Multiaddr } from '@multiformats/multiaddr'
2+
import { Circuit, IP, DNS } from '@multiformats/multiaddr-matcher'
3+
import isPrivate from 'private-ip'
4+
import type { TransportManager } from '@libp2p/interface-internal/src/transport-manager'
5+
6+
/**
7+
* Returns true if the passed multiaddr is public, not relayed and we have a
8+
* transport that can dial it
9+
*/
10+
export function isPublicAndDialable (ma: Multiaddr, transportManager: TransportManager): boolean {
11+
// ignore circuit relay
12+
if (Circuit.matches(ma)) {
13+
return false
14+
}
15+
16+
const transport = transportManager.transportForMultiaddr(ma)
17+
18+
if (transport == null) {
19+
return false
20+
}
21+
22+
// dns addresses are probably public?
23+
if (DNS.matches(ma)) {
24+
return true
25+
}
26+
27+
// ensure we have only IPv4/IPv6 addresses
28+
if (!IP.matches(ma)) {
29+
return false
30+
}
31+
32+
return isPrivate(ma.toOptions().host) === false
33+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* eslint-env mocha */
2+
3+
import { multiaddr } from '@multiformats/multiaddr'
4+
import { expect } from 'aegir/chai'
5+
import { stubInterface } from 'sinon-ts'
6+
import { isPublicAndDialable } from '../../src/dcutr/utils.js'
7+
import type { Transport } from '@libp2p/interface/transport'
8+
import type { TransportManager } from '@libp2p/interface-internal/transport-manager'
9+
10+
describe('dcutr utils', () => {
11+
describe('isPublicAndDialable', () => {
12+
const testCases = {
13+
// good addresses
14+
'/ip4/123.123.123.123/tcp/80/p2p/12D3KooWbtp1AcgweFSArD7dbKWYpAr8MZR1tofwNwLFLjeNGLWa': true,
15+
'/dnsaddr/example.com/p2p/12D3KooWbtp1AcgweFSArD7dbKWYpAr8MZR1tofwNwLFLjeNGLWa': true,
16+
'/ip4/123.123.123.123/tcp/80/p2p/12D3KooWbtp1AcgweFSArD7dbKWYpAr8MZR1tofwNwLFLjeNGLWa/p2p-circuit/webrtc/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN': true,
17+
18+
// bad addresses
19+
'/dnsaddr/example.com/p2p/12D3KooWbtp1AcgweFSArD7dbKWYpAr8MZR1tofwNwLFLjeNGLWa/p2p-circuit/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN': false,
20+
'/ip4/10.0.0.1/tcp/123/p2p/12D3KooWbtp1AcgweFSArD7dbKWYpAr8MZR1tofwNwLFLjeNGLWa': false
21+
}
22+
23+
for (const [key, value] of Object.entries(testCases)) {
24+
it(`should ${value ? '' : 'not '}allow ${key}`, () => {
25+
const transportManager = stubInterface<TransportManager>({
26+
transportForMultiaddr: stubInterface<Transport>()
27+
})
28+
29+
expect(isPublicAndDialable(multiaddr(key), transportManager)).to.equal(value)
30+
})
31+
}
32+
33+
it('should not allow addresses for which there is no transport', () => {
34+
const transportManager = stubInterface<TransportManager>()
35+
36+
expect(isPublicAndDialable(multiaddr('/ip4/123.123.123.123/p2p/12D3KooWbtp1AcgweFSArD7dbKWYpAr8MZR1tofwNwLFLjeNGLWa'), transportManager)).to.be.false()
37+
})
38+
})
39+
})

0 commit comments

Comments
 (0)