Skip to content

Commit c824323

Browse files
authored
fix: support validating asymmetric addresses (#2515)
Some transports can listen on addresses that validate differently to ones that they dial. For example WebTransport requires cert hashes to dial but can generate them and add them to the listened-on address when listening. Splits the `.filter` method into `dialFilter` and `listenFilter`.
1 parent 3d7a9da commit c824323

File tree

29 files changed

+855
-88
lines changed

29 files changed

+855
-88
lines changed

packages/interface-compliance-tests/src/transport/dial-test.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
1717
describe('dial', () => {
1818
let upgrader: Upgrader
1919
let registrar: Registrar
20-
let addrs: Multiaddr[]
20+
let listenAddrs: Multiaddr[]
21+
let dialAddrs: Multiaddr[]
2122
let transport: Transport
2223
let connector: Connector
2324
let listener: Listener
@@ -29,7 +30,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
2930
events: new TypedEventEmitter()
3031
});
3132

32-
({ addrs, transport, connector } = await common.setup())
33+
({ listenAddrs, dialAddrs, transport, connector } = await common.setup())
3334
})
3435

3536
after(async () => {
@@ -40,7 +41,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
4041
listener = transport.createListener({
4142
upgrader
4243
})
43-
await listener.listen(addrs[0])
44+
await listener.listen(listenAddrs[0])
4445
})
4546

4647
afterEach(async () => {
@@ -61,7 +62,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
6162
})
6263

6364
const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
64-
const conn = await transport.dial(addrs[0], {
65+
const conn = await transport.dial(dialAddrs[0], {
6566
upgrader
6667
})
6768

@@ -77,7 +78,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
7778

7879
it('can close connections', async () => {
7980
const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
80-
const conn = await transport.dial(addrs[0], {
81+
const conn = await transport.dial(dialAddrs[0], {
8182
upgrader
8283
})
8384

@@ -90,7 +91,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
9091
it('to non existent listener', async () => {
9192
const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
9293

93-
await expect(transport.dial(addrs[1], {
94+
await expect(transport.dial(dialAddrs[1], {
9495
upgrader
9596
})).to.eventually.be.rejected()
9697
expect(upgradeSpy.callCount).to.equal(0)
@@ -100,7 +101,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
100101
const upgradeSpy = sinon.spy(upgrader, 'upgradeOutbound')
101102
const controller = new AbortController()
102103
controller.abort()
103-
const conn = transport.dial(addrs[0], { signal: controller.signal, upgrader })
104+
const conn = transport.dial(dialAddrs[0], { signal: controller.signal, upgrader })
104105

105106
await expect(conn).to.eventually.be.rejected().with.property('code', AbortError.code)
106107
expect(upgradeSpy.callCount).to.equal(0)
@@ -113,7 +114,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
113114
connector.delay(100)
114115

115116
const controller = new AbortController()
116-
const conn = transport.dial(addrs[0], { signal: controller.signal, upgrader })
117+
const conn = transport.dial(dialAddrs[0], { signal: controller.signal, upgrader })
117118
setTimeout(() => { controller.abort() }, 50)
118119

119120
await expect(conn).to.eventually.be.rejected().with.property('code', AbortError.code)

packages/interface-compliance-tests/src/transport/filter-test.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,26 @@ import type { Multiaddr } from '@multiformats/multiaddr'
66

77
export default (common: TestSetup<TransportTestFixtures>): void => {
88
describe('filter', () => {
9-
let addrs: Multiaddr[]
9+
let listenAddrs: Multiaddr[]
10+
let dialAddrs: Multiaddr[]
1011
let transport: Transport
1112

1213
before(async () => {
13-
({ addrs, transport } = await common.setup())
14+
({ listenAddrs, dialAddrs, transport } = await common.setup())
1415
})
1516

1617
after(async () => {
1718
await common.teardown()
1819
})
1920

20-
it('filters addresses', () => {
21-
const filteredAddrs = transport.filter(addrs)
22-
expect(filteredAddrs).to.eql(addrs)
21+
it('filters listen addresses', () => {
22+
const filteredAddrs = transport.listenFilter(listenAddrs)
23+
expect(filteredAddrs).to.eql(listenAddrs)
24+
})
25+
26+
it('filters dial addresses', () => {
27+
const filteredAddrs = transport.dialFilter(dialAddrs)
28+
expect(filteredAddrs).to.eql(dialAddrs)
2329
})
2430
})
2531
}

packages/interface-compliance-tests/src/transport/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ export interface Connector {
1111
}
1212

1313
export interface TransportTestFixtures {
14-
addrs: Multiaddr[]
14+
listenAddrs: Multiaddr[]
15+
dialAddrs: Multiaddr[]
1516
transport: Transport
1617
connector: Connector
1718
}

packages/interface-compliance-tests/src/transport/listen-test.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import type { Multiaddr } from '@multiformats/multiaddr'
1818
export default (common: TestSetup<TransportTestFixtures>): void => {
1919
describe('listen', () => {
2020
let upgrader: Upgrader
21-
let addrs: Multiaddr[]
21+
let listenAddrs: Multiaddr[]
22+
let dialAddrs: Multiaddr[]
2223
let transport: Transport
2324
let registrar: Registrar
2425

@@ -29,7 +30,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
2930
events: new TypedEventEmitter()
3031
});
3132

32-
({ transport, addrs } = await common.setup())
33+
({ transport, listenAddrs, dialAddrs } = await common.setup())
3334
})
3435

3536
after(async () => {
@@ -44,7 +45,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
4445
const listener = transport.createListener({
4546
upgrader
4647
})
47-
await listener.listen(addrs[0])
48+
await listener.listen(listenAddrs[0])
4849
await listener.close()
4950
})
5051

@@ -65,14 +66,14 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
6566
})
6667

6768
// Listen
68-
await listener.listen(addrs[0])
69+
await listener.listen(listenAddrs[0])
6970

7071
// Create two connections to the listener
7172
const [conn1] = await Promise.all([
72-
transport.dial(addrs[0], {
73+
transport.dial(dialAddrs[0], {
7374
upgrader
7475
}),
75-
transport.dial(addrs[0], {
76+
transport.dial(dialAddrs[0], {
7677
upgrader
7778
})
7879
])
@@ -112,10 +113,10 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
112113
})
113114

114115
// Listen
115-
await listener.listen(addrs[0])
116+
await listener.listen(listenAddrs[0])
116117

117118
// Create a connection to the listener
118-
const conn = await transport.dial(addrs[0], {
119+
const conn = await transport.dial(dialAddrs[0], {
119120
upgrader
120121
})
121122

@@ -138,8 +139,8 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
138139
})
139140

140141
void (async () => {
141-
await listener.listen(addrs[0])
142-
await transport.dial(addrs[0], {
142+
await listener.listen(listenAddrs[0])
143+
await transport.dial(dialAddrs[0], {
143144
upgrader
144145
})
145146
})()
@@ -158,7 +159,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
158159
listener.addEventListener('listening', () => {
159160
listener.close().then(done, done)
160161
})
161-
void listener.listen(addrs[0])
162+
void listener.listen(listenAddrs[0])
162163
})
163164

164165
it('error', (done) => {
@@ -181,7 +182,7 @@ export default (common: TestSetup<TransportTestFixtures>): void => {
181182
listener.addEventListener('close', () => { done() })
182183

183184
void (async () => {
184-
await listener.listen(addrs[0])
185+
await listener.listen(listenAddrs[0])
185186
await listener.close()
186187
})()
187188
})

packages/interface-internal/src/transport-manager/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,15 @@ export interface TransportManager {
3131
getListeners(): Listener[]
3232

3333
/**
34-
* Get the transport for a given multiaddr, if one has been configured
34+
* Get the transport to dial a given multiaddr, if one has been configured
3535
*/
36-
transportForMultiaddr(ma: Multiaddr): Transport | undefined
36+
dialTransportForMultiaddr(ma: Multiaddr): Transport | undefined
37+
38+
/**
39+
* Get the transport to listen on a given multiaddr, if one has been
40+
* configured
41+
*/
42+
listenTransportForMultiaddr(ma: Multiaddr): Transport | undefined
3743

3844
/**
3945
* Listen on the passed multiaddrs

packages/interface/src/transport/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,16 @@ export interface Transport {
6868
createListener(options: CreateListenerOptions): Listener
6969

7070
/**
71-
* Takes a list of `Multiaddr`s and returns only valid addresses for the transport
71+
* Takes a list of `Multiaddr`s and returns only addresses that are valid for
72+
* the transport to listen on
7273
*/
73-
filter: MultiaddrFilter
74+
listenFilter: MultiaddrFilter
75+
76+
/**
77+
* Takes a list of `Multiaddr`s and returns only addresses that are vali for
78+
* the transport to dial
79+
*/
80+
dialFilter: MultiaddrFilter
7481
}
7582

7683
export function isTransport (other: any): other is Transport {

packages/libp2p/src/connection-manager/dial-queue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ export class DialQueue {
398398

399399
const filteredAddrs = resolvedAddresses.filter(addr => {
400400
// filter out any multiaddrs that we do not have transports for
401-
if (this.components.transportManager.transportForMultiaddr(addr.multiaddr) == null) {
401+
if (this.components.transportManager.dialTransportForMultiaddr(addr.multiaddr) == null) {
402402
return false
403403
}
404404

packages/libp2p/src/transport-manager.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export class DefaultTransportManager implements TransportManager, Startable {
106106
* Dials the given Multiaddr over it's supported transport
107107
*/
108108
async dial (ma: Multiaddr, options?: AbortOptions): Promise<Connection> {
109-
const transport = this.transportForMultiaddr(ma)
109+
const transport = this.dialTransportForMultiaddr(ma)
110110

111111
if (transport == null) {
112112
throw new CodeError(`No transport available for address ${String(ma)}`, codes.ERR_TRANSPORT_UNAVAILABLE)
@@ -156,9 +156,22 @@ export class DefaultTransportManager implements TransportManager, Startable {
156156
/**
157157
* Finds a transport that matches the given Multiaddr
158158
*/
159-
transportForMultiaddr (ma: Multiaddr): Transport | undefined {
159+
dialTransportForMultiaddr (ma: Multiaddr): Transport | undefined {
160160
for (const transport of this.transports.values()) {
161-
const addrs = transport.filter([ma])
161+
const addrs = transport.dialFilter([ma])
162+
163+
if (addrs.length > 0) {
164+
return transport
165+
}
166+
}
167+
}
168+
169+
/**
170+
* Finds a transport that matches the given Multiaddr
171+
*/
172+
listenTransportForMultiaddr (ma: Multiaddr): Transport | undefined {
173+
for (const transport of this.transports.values()) {
174+
const addrs = transport.listenFilter([ma])
162175

163176
if (addrs.length > 0) {
164177
return transport
@@ -182,7 +195,7 @@ export class DefaultTransportManager implements TransportManager, Startable {
182195
const couldNotListen = []
183196

184197
for (const [key, transport] of this.transports.entries()) {
185-
const supportedAddrs = transport.filter(addrs)
198+
const supportedAddrs = transport.listenFilter(addrs)
186199
const tasks = []
187200

188201
// For each supported multiaddr, create a listener

packages/libp2p/test/connection-manager/dial-queue.spec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('dial queue', () => {
5757
'/ip4/127.0.0.1/tcp/1233': async () => deferredConn.promise
5858
}
5959

60-
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
60+
components.transportManager.dialTransportForMultiaddr.returns(stubInterface<Transport>())
6161
components.transportManager.dial.callsFake(async ma => {
6262
const maStr = ma.toString()
6363
const action = actions[maStr]
@@ -97,7 +97,7 @@ describe('dial queue', () => {
9797
]
9898
})
9999

100-
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
100+
components.transportManager.dialTransportForMultiaddr.returns(stubInterface<Transport>())
101101
components.transportManager.dial.withArgs(matchMultiaddr(ma.encapsulate(`/p2p/${peerId}`))).resolves(connection)
102102

103103
dialer = new DialQueue(components)
@@ -124,7 +124,7 @@ describe('dial queue', () => {
124124
]
125125
})
126126

127-
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
127+
components.transportManager.dialTransportForMultiaddr.returns(stubInterface<Transport>())
128128
components.transportManager.dial.withArgs(matchMultiaddr(ma.encapsulate(`/p2p/${peerId}`))).resolves(connection)
129129

130130
dialer = new DialQueue(components)
@@ -141,7 +141,7 @@ describe('dial queue', () => {
141141
'/ip4/127.0.0.1/tcp/1233': async () => deferredConn.promise
142142
}
143143

144-
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
144+
components.transportManager.dialTransportForMultiaddr.returns(stubInterface<Transport>())
145145
components.transportManager.dial.callsFake(async ma => {
146146
const maStr = ma.toString()
147147
const action = actions[maStr]
@@ -178,7 +178,7 @@ describe('dial queue', () => {
178178
maxParallelDials: 2
179179
})
180180

181-
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
181+
components.transportManager.dialTransportForMultiaddr.returns(stubInterface<Transport>())
182182
components.transportManager.dial.callsFake(async ma => {
183183
const maStr = ma.toString()
184184
const action = actions[maStr]
@@ -218,7 +218,7 @@ describe('dial queue', () => {
218218
maxParallelDials: 2
219219
})
220220

221-
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
221+
components.transportManager.dialTransportForMultiaddr.returns(stubInterface<Transport>())
222222
components.transportManager.dial.callsFake(async ma => {
223223
const maStr = ma.toString()
224224
const action = actions[maStr]
@@ -267,7 +267,7 @@ describe('dial queue', () => {
267267
dialer = new DialQueue(components, {
268268
maxParallelDials: 50
269269
})
270-
components.transportManager.transportForMultiaddr.returns(stubInterface<Transport>())
270+
components.transportManager.dialTransportForMultiaddr.returns(stubInterface<Transport>())
271271

272272
const connection = mockConnection(mockMultiaddrConnection(mockDuplex(), remotePeer))
273273

@@ -294,7 +294,7 @@ describe('dial queue', () => {
294294
const ma = multiaddr(`/ip4/123.123.123.123/tcp/123/ws/p2p/${relayPeer}/p2p-circuit/webrtc`)
295295
const maWithPeer = `${ma}/p2p/${remotePeer}`
296296

297-
components.transportManager.transportForMultiaddr.callsFake(ma => {
297+
components.transportManager.dialTransportForMultiaddr.callsFake(ma => {
298298
if (WebRTC.exactMatch(ma)) {
299299
return stubInterface<Transport>()
300300
}

packages/libp2p/test/connection-manager/direct.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ describe('libp2p.dialer (direct, WebSockets)', () => {
507507

508508
it('should limit the maximum dial queue size', async () => {
509509
const transport = stubInterface<Transport>({
510-
filter: (ma) => ma,
510+
dialFilter: (ma) => ma,
511511
dial: async () => {
512512
await delay(1000)
513513
return stubInterface<Connection>()

0 commit comments

Comments
 (0)