Skip to content

Commit

Permalink
fix(transports): filter circuit addresses (#2060)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
achingbrain authored Sep 22, 2023
1 parent 6640116 commit 972b10a
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 43 deletions.
1 change: 1 addition & 0 deletions packages/transport-webrtc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@libp2p/peer-id": "^3.0.2",
"@multiformats/mafmt": "^12.1.2",
"@multiformats/multiaddr": "^12.1.5",
"@multiformats/multiaddr-matcher": "^1.0.1",
"abortable-iterator": "^5.0.1",
"detect-browser": "^5.3.0",
"it-length-prefixed": "^9.0.1",
Expand Down
9 changes: 3 additions & 6 deletions packages/transport-webrtc/src/private-to-private/transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { CodeError } from '@libp2p/interface/errors'
import { type CreateListenerOptions, type DialOptions, symbol, type Transport, type Listener, type Upgrader } from '@libp2p/interface/transport'
import { logger } from '@libp2p/logger'
import { peerIdFromString } from '@libp2p/peer-id'
import { multiaddr, type Multiaddr, protocols } from '@multiformats/multiaddr'
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
import { WebRTC } from '@multiformats/multiaddr-matcher'
import { codes } from '../error.js'
import { WebRTCMultiaddrConnection } from '../maconn.js'
import { cleanup } from '../webrtc/index.js'
Expand All @@ -21,7 +22,6 @@ const log = logger('libp2p:webrtc:peer')
const WEBRTC_TRANSPORT = '/webrtc'
const CIRCUIT_RELAY_TRANSPORT = '/p2p-circuit'
const SIGNALING_PROTO_ID = '/webrtc-signaling/0.0.1'
const WEBRTC_CODE = protocols('webrtc').code

export interface WebRTCTransportInit {
rtcConfiguration?: RTCConfiguration
Expand Down Expand Up @@ -91,10 +91,7 @@ export class WebRTCTransport implements Transport, Startable {
readonly [symbol] = true

filter (multiaddrs: Multiaddr[]): Multiaddr[] {
return multiaddrs.filter((ma) => {
const codes = ma.protoCodes()
return codes.includes(WEBRTC_CODE)
})
return multiaddrs.filter(WebRTC.exactMatch)
}

/*
Expand Down
12 changes: 2 additions & 10 deletions packages/transport-webrtc/src/private-to-public/transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { type CreateListenerOptions, symbol, type Transport, type Listener } fro
import { logger } from '@libp2p/logger'
import * as p from '@libp2p/peer-id'
import { protocols } from '@multiformats/multiaddr'
import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
import * as multihashes from 'multihashes'
import { concat } from 'uint8arrays/concat'
import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'
Expand Down Expand Up @@ -95,7 +96,7 @@ export class WebRTCDirectTransport implements Transport {
* Takes a list of `Multiaddr`s and returns only valid addresses for the transport
*/
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
return multiaddrs.filter(validMa)
return multiaddrs.filter(WebRTCDirect.exactMatch)
}

/**
Expand Down Expand Up @@ -275,12 +276,3 @@ export class WebRTCDirectTransport implements Transport {
return concat([prefix, local, remote])
}
}

/**
* Determine if a given multiaddr contains a WebRTC Code (280),
* a Certhash Code (466) and a PeerId
*/
function validMa (ma: Multiaddr): boolean {
const codes = ma.protoCodes()
return codes.includes(WEBRTC_CODE) && codes.includes(CERTHASH_CODE) && ma.getPeerId() != null && !codes.includes(protocols('p2p-circuit').code)
}
2 changes: 1 addition & 1 deletion packages/transport-webrtc/test/peer.browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('webrtc filter', () => {
}, {})

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

expect(transport.filter(valid)).length(1)
Expand Down
48 changes: 24 additions & 24 deletions packages/transport-webrtc/test/transport.browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import { type CreateListenerOptions, symbol } from '@libp2p/interface/transport'
import { mockMetrics, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks'
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
import { expect, assert } from 'aegir/chai'
import { multiaddr } from '@multiformats/multiaddr'
import { expect } from 'aegir/chai'
import { UnimplementedError } from '../src/error.js'
import * as underTest from '../src/private-to-public/transport.js'
import { WebRTCDirectTransport, type WebRTCDirectTransportComponents } from '../src/private-to-public/transport.js'
import { expectError } from './util.js'
import type { Metrics } from '@libp2p/interface/metrics'

Expand All @@ -15,9 +15,9 @@ function ignoredDialOption (): CreateListenerOptions {
return { upgrader }
}

describe('WebRTC Transport', () => {
describe('WebRTCDirect Transport', () => {
let metrics: Metrics
let components: underTest.WebRTCDirectTransportComponents
let components: WebRTCDirectTransportComponents

before(async () => {
metrics = mockMetrics()()
Expand All @@ -28,21 +28,21 @@ describe('WebRTC Transport', () => {
})

it('can construct', () => {
const t = new underTest.WebRTCDirectTransport(components)
const t = new WebRTCDirectTransport(components)
expect(t.constructor.name).to.equal('WebRTCDirectTransport')
})

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

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

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

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

it('symbol property getter', () => {
const t = new underTest.WebRTCDirectTransport(components)
const t = new WebRTCDirectTransport(components)
const s = t[symbol]
expect(s).to.equal(true)
})

it('transport filter filters out invalid multiaddrs', async () => {
const mas: Multiaddr[] = [
'/ip4/1.2.3.4/udp/1234/webrtc/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ',
'/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd',
'/ip4/1.2.3.4/udp/1234/webrtc-direct/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd',
'/ip4/1.2.3.4/udp/1234/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'
].map((s) => multiaddr(s))
const t = new underTest.WebRTCDirectTransport(components)
const result = t.filter(mas)
const expected =
const valid = [
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
]
const invalid = [
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ'),
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'),
multiaddr('/ip4/1.2.3.4/udp/1234/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
]

assert.isNotNull(result)
expect(result.constructor.name).to.equal('Array')
expect(result).to.have.length(1)
expect(result[0].equals(expected)).to.be.true()
const t = new WebRTCDirectTransport(components)

expect(t.filter([
...valid,
...invalid
])).to.deep.equal(valid)
})

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

try {
await transport.dial(ma, ignoredDialOption())
Expand Down
1 change: 1 addition & 0 deletions packages/transport-webtransport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"uint8arrays": "^4.0.6"
},
"devDependencies": {
"@libp2p/peer-id-factory": "^3.0.3",
"aegir": "^40.0.8",
"libp2p": "^0.46.11",
"p-defer": "^4.0.0"
Expand Down
3 changes: 2 additions & 1 deletion packages/transport-webtransport/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { noise } from '@chainsafe/libp2p-noise'
import { type Transport, symbol, type CreateListenerOptions, type DialOptions, type Listener } from '@libp2p/interface/transport'
import { logger } from '@libp2p/logger'
import { type Multiaddr, type AbortOptions } from '@multiformats/multiaddr'
import { WebTransport as WebTransportMatcher } from '@multiformats/multiaddr-matcher'
import { webtransportBiDiStreamToStream } from './stream.js'
import { inertDuplex } from './utils/inert-duplex.js'
import { isSubset } from './utils/is-subset.js'
Expand Down Expand Up @@ -329,7 +330,7 @@ class WebTransportTransport implements Transport {
* Takes a list of `Multiaddr`s and returns only valid webtransport addresses.
*/
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
return multiaddrs.filter(ma => ma.protoNames().includes('webtransport'))
return multiaddrs.filter(WebTransportMatcher.exactMatch)
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/transport-webtransport/test/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('libp2p-webtransport', () => {
const ma = multiaddr(maStrNoCerthash + '/p2p/' + maStrP2p)

await expect(node.dial(ma)).to.eventually.be.rejected()
.with.property('code', 'ERR_INVALID_MULTIADDR')
.with.property('code', 'ERR_NO_VALID_ADDRESSES')
})

it('fails to connect due to an aborted signal', async () => {
Expand Down
34 changes: 34 additions & 0 deletions packages/transport-webtransport/test/transport.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* eslint-disable no-console */
/* eslint-env mocha */

import { createEd25519PeerId } from '@libp2p/peer-id-factory'
import { multiaddr } from '@multiformats/multiaddr'
import { expect } from 'aegir/chai'
import { webTransport, type WebTransportComponents } from '../src/index.js'

describe('WebTransport Transport', () => {
let components: WebTransportComponents

beforeEach(async () => {
components = {
peerId: await createEd25519PeerId()
}
})

it('transport filter filters out invalid multiaddrs', async () => {
const valid = [
multiaddr('/ip4/1.2.3.4/udp/1234/quic-v1/webtransport/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
]
const invalid = [
multiaddr('/ip4/1.2.3.4/udp/1234/quic-v1/webtransport/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd/p2p-circuit/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd'),
multiaddr('/ip4/1.2.3.4/udp/1234/webrtc-direct/certhash/uEiAUqV7kzvM1wI5DYDc1RbcekYVmXli_Qprlw3IkiEg6tQ/p2p/12D3KooWGDMwwqrpcYKpKCgxuKT2NfqPqa94QnkoBBpqvCaiCzWd')
]

const t = webTransport()(components)

expect(t.filter([
...valid,
...invalid
])).to.deep.equal(valid)
})
})

0 comments on commit 972b10a

Please sign in to comment.