Skip to content

Commit 4bbcfa7

Browse files
authored
fix: allow overriding mss mode (#2924)
According to the DCUtR spec to complete a holepunch via TCP Simultaneous Connect, the dialer (B) needs to act as a multistream-select server rather than a client, otherwise both sides will try to initiate mss which will fail.
1 parent e2ec7bd commit 4bbcfa7

File tree

5 files changed

+42
-5
lines changed

5 files changed

+42
-5
lines changed

packages/integration-tests/test/dcutr.node.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ describe('dcutr', () => {
120120
})
121121
})
122122

123-
// TODO: how to test this?
123+
// TODO: how to test this? We need to simulate a firewall of some sort
124124
describe.skip('dctur connection upgrade', () => {
125125
beforeEach(async () => {
126126
libp2pA = await createLibp2p(createBaseOptions({
@@ -162,7 +162,7 @@ describe('dcutr', () => {
162162
}
163163
})
164164

165-
it('should perform connection upgrade', async () => {
165+
it('should perform unilateral connection upgrade', async () => {
166166
const relayedAddress = multiaddr(`/ip4/127.0.0.1/tcp/${RELAY_PORT}/p2p/${relay.peerId}/p2p-circuit/p2p/${libp2pB.peerId}`)
167167
const connection = await libp2pA.dial(relayedAddress)
168168

@@ -175,5 +175,19 @@ describe('dcutr', () => {
175175
// should have closed the relayed connection
176176
expect(libp2pA.getConnections(libp2pB.peerId)).to.have.lengthOf(1, 'had multiple connections to remote peer')
177177
})
178+
179+
it('should perform holepunch using TCP Simultaneous Connect', async () => {
180+
const relayedAddress = multiaddr(`/ip4/127.0.0.1/tcp/${RELAY_PORT}/p2p/${relay.peerId}/p2p-circuit/p2p/${libp2pB.peerId}`)
181+
const connection = await libp2pA.dial(relayedAddress)
182+
183+
// connection should be limited
184+
expect(connection).to.have.property('limits').that.is.ok()
185+
186+
// wait for DCUtR TCP Simultaneous Connect upgrade
187+
// TODO: implement me
188+
189+
// should have closed the relayed connection
190+
expect(libp2pA.getConnections(libp2pB.peerId)).to.have.lengthOf(1, 'had multiple connections to remote peer')
191+
})
178192
})
179193
})

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

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ export interface OpenConnectionOptions extends AbortOptions, ProgressOptions<Ope
2020
* @default false
2121
*/
2222
force?: boolean
23+
24+
/**
25+
* By default a newly opened outgoing connection operates in initiator mode
26+
* during negotiation of encryption/muxing protocols using multistream-select.
27+
*
28+
* In some cases such as when the dialer is trying to achieve TCP Simultaneous
29+
* Connect using the DCUtR protocol, it may wish to act in responder mode, if
30+
* so pass `false` here.
31+
*
32+
* @default true
33+
*/
34+
initiator?: boolean
2335
}
2436

2537
export interface ConnectionManager {

packages/interface/src/transport/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export interface UpgraderOptions<ConnectionUpgradeEvents extends ProgressEvent =
122122
skipProtection?: boolean
123123
muxerFactory?: StreamMuxerFactory
124124
limits?: ConnectionLimits
125+
initiator?: boolean
125126
}
126127

127128
export type InboundConnectionUpgradeEvents =

packages/libp2p/src/upgrader.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,14 @@ export class DefaultUpgrader implements Upgrader {
228228
await this.shouldBlockConnection('denyOutboundConnection', remotePeerId, maConn)
229229
}
230230

231-
return await this._performUpgrade(maConn, 'outbound', opts)
231+
let direction: 'inbound' | 'outbound' = 'outbound'
232+
233+
// act as the multistream-select server if we are not to be the initiator
234+
if (opts.initiator === false) {
235+
direction = 'inbound'
236+
}
237+
238+
return await this._performUpgrade(maConn, direction, opts)
232239
} catch (err) {
233240
this.metrics.errors?.increment({
234241
outbound: true

packages/protocol-dcutr/src/dcutr.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,13 @@ export class DefaultDCUtRService implements Startable {
192192
// https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#the-protocol
193193

194194
this.log('B dialing', multiaddrs)
195-
// Upon expiry of the timer, B dials the address to A.
195+
// Upon expiry of the timer, B dials the address to A and acts as the
196+
// multistream-select server
196197
const conn = await this.connectionManager.openConnection(multiaddrs, {
197198
signal: options.signal,
198-
priority: DCUTR_DIAL_PRIORITY
199+
priority: DCUTR_DIAL_PRIORITY,
200+
force: true,
201+
initiator: false
199202
})
200203

201204
this.log('DCUtR to %p succeeded to address %a, closing relayed connection', relayedConnection.remotePeer, conn.remoteAddr)

0 commit comments

Comments
 (0)