Skip to content

Commit 972b10a

Browse files
authored
fix(transports): filter circuit addresses (#2060)
Use exact matchers for filtering webtransport and webrtc addresses so those transports do not try to dial (for example) p2p-circuit addresses, instead leaving the more specific address to other transports.
1 parent 6640116 commit 972b10a

File tree

9 files changed

+69
-43
lines changed

9 files changed

+69
-43
lines changed

packages/transport-webrtc/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@libp2p/peer-id": "^3.0.2",
5252
"@multiformats/mafmt": "^12.1.2",
5353
"@multiformats/multiaddr": "^12.1.5",
54+
"@multiformats/multiaddr-matcher": "^1.0.1",
5455
"abortable-iterator": "^5.0.1",
5556
"detect-browser": "^5.3.0",
5657
"it-length-prefixed": "^9.0.1",

packages/transport-webrtc/src/private-to-private/transport.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { CodeError } from '@libp2p/interface/errors'
22
import { type CreateListenerOptions, type DialOptions, symbol, type Transport, type Listener, type Upgrader } from '@libp2p/interface/transport'
33
import { logger } from '@libp2p/logger'
44
import { peerIdFromString } from '@libp2p/peer-id'
5-
import { multiaddr, type Multiaddr, protocols } from '@multiformats/multiaddr'
5+
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
6+
import { WebRTC } from '@multiformats/multiaddr-matcher'
67
import { codes } from '../error.js'
78
import { WebRTCMultiaddrConnection } from '../maconn.js'
89
import { cleanup } from '../webrtc/index.js'
@@ -21,7 +22,6 @@ const log = logger('libp2p:webrtc:peer')
2122
const WEBRTC_TRANSPORT = '/webrtc'
2223
const CIRCUIT_RELAY_TRANSPORT = '/p2p-circuit'
2324
const SIGNALING_PROTO_ID = '/webrtc-signaling/0.0.1'
24-
const WEBRTC_CODE = protocols('webrtc').code
2525

2626
export interface WebRTCTransportInit {
2727
rtcConfiguration?: RTCConfiguration
@@ -91,10 +91,7 @@ export class WebRTCTransport implements Transport, Startable {
9191
readonly [symbol] = true
9292

9393
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
94-
return multiaddrs.filter((ma) => {
95-
const codes = ma.protoCodes()
96-
return codes.includes(WEBRTC_CODE)
97-
})
94+
return multiaddrs.filter(WebRTC.exactMatch)
9895
}
9996

10097
/*

packages/transport-webrtc/src/private-to-public/transport.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type CreateListenerOptions, symbol, type Transport, type Listener } fro
33
import { logger } from '@libp2p/logger'
44
import * as p from '@libp2p/peer-id'
55
import { protocols } from '@multiformats/multiaddr'
6+
import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
67
import * as multihashes from 'multihashes'
78
import { concat } from 'uint8arrays/concat'
89
import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'
@@ -95,7 +96,7 @@ export class WebRTCDirectTransport implements Transport {
9596
* Takes a list of `Multiaddr`s and returns only valid addresses for the transport
9697
*/
9798
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
98-
return multiaddrs.filter(validMa)
99+
return multiaddrs.filter(WebRTCDirect.exactMatch)
99100
}
100101

101102
/**
@@ -275,12 +276,3 @@ export class WebRTCDirectTransport implements Transport {
275276
return concat([prefix, local, remote])
276277
}
277278
}
278-
279-
/**
280-
* Determine if a given multiaddr contains a WebRTC Code (280),
281-
* a Certhash Code (466) and a PeerId
282-
*/
283-
function validMa (ma: Multiaddr): boolean {
284-
const codes = ma.protoCodes()
285-
return codes.includes(WEBRTC_CODE) && codes.includes(CERTHASH_CODE) && ma.getPeerId() != null && !codes.includes(protocols('p2p-circuit').code)
286-
}

packages/transport-webrtc/test/peer.browser.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ describe('webrtc filter', () => {
106106
}, {})
107107

108108
const valid = [
109-
multiaddr('/ip4/127.0.0.1/tcp/1234/ws/p2p-circuit/webrtc')
109+
multiaddr('/ip4/127.0.0.1/tcp/1234/ws/p2p/12D3KooWFqpHsdZaL4NW6eVE3yjhoSDNv7HJehPZqj17kjKntAh2/p2p-circuit/webrtc/p2p/12D3KooWF2P1k8SVRL1cV1Z9aNM8EVRwbrMESyRf58ceQkaht4AF')
110110
]
111111

112112
expect(transport.filter(valid)).length(1)

packages/transport-webrtc/test/transport.browser.spec.ts

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import { type CreateListenerOptions, symbol } from '@libp2p/interface/transport'
44
import { mockMetrics, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks'
55
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
6-
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
7-
import { expect, assert } from 'aegir/chai'
6+
import { multiaddr } from '@multiformats/multiaddr'
7+
import { expect } from 'aegir/chai'
88
import { UnimplementedError } from '../src/error.js'
9-
import * as underTest from '../src/private-to-public/transport.js'
9+
import { WebRTCDirectTransport, type WebRTCDirectTransportComponents } from '../src/private-to-public/transport.js'
1010
import { expectError } from './util.js'
1111
import type { Metrics } from '@libp2p/interface/metrics'
1212

@@ -15,9 +15,9 @@ function ignoredDialOption (): CreateListenerOptions {
1515
return { upgrader }
1616
}
1717

18-
describe('WebRTC Transport', () => {
18+
describe('WebRTCDirect Transport', () => {
1919
let metrics: Metrics
20-
let components: underTest.WebRTCDirectTransportComponents
20+
let components: WebRTCDirectTransportComponents
2121

2222
before(async () => {
2323
metrics = mockMetrics()()
@@ -28,21 +28,21 @@ describe('WebRTC Transport', () => {
2828
})
2929

3030
it('can construct', () => {
31-
const t = new underTest.WebRTCDirectTransport(components)
31+
const t = new WebRTCDirectTransport(components)
3232
expect(t.constructor.name).to.equal('WebRTCDirectTransport')
3333
})
3434

3535
it('can dial', async () => {
3636
const ma = multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
37-
const transport = new underTest.WebRTCDirectTransport(components)
37+
const transport = new WebRTCDirectTransport(components)
3838
const options = ignoredDialOption()
3939

4040
// don't await as this isn't an e2e test
4141
transport.dial(ma, options)
4242
})
4343

4444
it('createListner throws', () => {
45-
const t = new underTest.WebRTCDirectTransport(components)
45+
const t = new WebRTCDirectTransport(components)
4646
try {
4747
t.createListener(ignoredDialOption())
4848
expect('Should have thrown').to.equal('but did not')
@@ -52,38 +52,38 @@ describe('WebRTC Transport', () => {
5252
})
5353

5454
it('toString property getter', () => {
55-
const t = new underTest.WebRTCDirectTransport(components)
55+
const t = new WebRTCDirectTransport(components)
5656
const s = t[Symbol.toStringTag]
5757
expect(s).to.equal('@libp2p/webrtc-direct')
5858
})
5959

6060
it('symbol property getter', () => {
61-
const t = new underTest.WebRTCDirectTransport(components)
61+
const t = new WebRTCDirectTransport(components)
6262
const s = t[symbol]
6363
expect(s).to.equal(true)
6464
})
6565

6666
it('transport filter filters out invalid multiaddrs', async () => {
67-
const mas: Multiaddr[] = [
68-
'/ip4/1.2.3.4/udp/1234/webrtc/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ',
69-
'/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd',
70-
'/ip4/1.2.3.4/udp/1234/webrtc-direct/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd',
71-
'/ip4/1.2.3.4/udp/1234/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'
72-
].map((s) => multiaddr(s))
73-
const t = new underTest.WebRTCDirectTransport(components)
74-
const result = t.filter(mas)
75-
const expected =
67+
const valid = [
7668
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
69+
]
70+
const invalid = [
71+
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ'),
72+
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'),
73+
multiaddr('/ip4/1.2.3.4/udp/1234/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
74+
]
7775

78-
assert.isNotNull(result)
79-
expect(result.constructor.name).to.equal('Array')
80-
expect(result).to.have.length(1)
81-
expect(result[0].equals(expected)).to.be.true()
76+
const t = new WebRTCDirectTransport(components)
77+
78+
expect(t.filter([
79+
...valid,
80+
...invalid
81+
])).to.deep.equal(valid)
8282
})
8383

8484
it('throws WebRTC transport error when dialing a multiaddr without a PeerId', async () => {
8585
const ma = multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ')
86-
const transport = new underTest.WebRTCDirectTransport(components)
86+
const transport = new WebRTCDirectTransport(components)
8787

8888
try {
8989
await transport.dial(ma, ignoredDialOption())

packages/transport-webtransport/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"uint8arrays": "^4.0.6"
7373
},
7474
"devDependencies": {
75+
"@libp2p/peer-id-factory": "^3.0.3",
7576
"aegir": "^40.0.8",
7677
"libp2p": "^0.46.11",
7778
"p-defer": "^4.0.0"

packages/transport-webtransport/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { noise } from '@chainsafe/libp2p-noise'
22
import { type Transport, symbol, type CreateListenerOptions, type DialOptions, type Listener } from '@libp2p/interface/transport'
33
import { logger } from '@libp2p/logger'
44
import { type Multiaddr, type AbortOptions } from '@multiformats/multiaddr'
5+
import { WebTransport as WebTransportMatcher } from '@multiformats/multiaddr-matcher'
56
import { webtransportBiDiStreamToStream } from './stream.js'
67
import { inertDuplex } from './utils/inert-duplex.js'
78
import { isSubset } from './utils/is-subset.js'
@@ -329,7 +330,7 @@ class WebTransportTransport implements Transport {
329330
* Takes a list of `Multiaddr`s and returns only valid webtransport addresses.
330331
*/
331332
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
332-
return multiaddrs.filter(ma => ma.protoNames().includes('webtransport'))
333+
return multiaddrs.filter(WebTransportMatcher.exactMatch)
333334
}
334335
}
335336

packages/transport-webtransport/test/browser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ describe('libp2p-webtransport', () => {
8989
const ma = multiaddr(maStrNoCerthash + '/p2p/' + maStrP2p)
9090

9191
await expect(node.dial(ma)).to.eventually.be.rejected()
92-
.with.property('code', 'ERR_INVALID_MULTIADDR')
92+
.with.property('code', 'ERR_NO_VALID_ADDRESSES')
9393
})
9494

9595
it('fails to connect due to an aborted signal', async () => {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* eslint-disable no-console */
2+
/* eslint-env mocha */
3+
4+
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
5+
import { multiaddr } from '@multiformats/multiaddr'
6+
import { expect } from 'aegir/chai'
7+
import { webTransport, type WebTransportComponents } from '../src/index.js'
8+
9+
describe('WebTransport Transport', () => {
10+
let components: WebTransportComponents
11+
12+
beforeEach(async () => {
13+
components = {
14+
peerId: await createEd25519PeerId()
15+
}
16+
})
17+
18+
it('transport filter filters out invalid multiaddrs', async () => {
19+
const valid = [
20+
multiaddr('/ip4/1.2.3.4/udp/1234/quic-v1/webtransport/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
21+
]
22+
const invalid = [
23+
multiaddr('/ip4/1.2.3.4/udp/1234/quic-v1/webtransport/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd/p2p-circuit/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'),
24+
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
25+
]
26+
27+
const t = webTransport()(components)
28+
29+
expect(t.filter([
30+
...valid,
31+
...invalid
32+
])).to.deep.equal(valid)
33+
})
34+
})

0 commit comments

Comments
 (0)