Skip to content

webrtc(private-to-private): clarify interaction with DCUtR #583

Closed

Description

@sukunrt

There's some subtle interaction involved between DCUtR and webrtc hole punching especially considering that the dialer initiates the holepunch in webrtc and the receiver initiates the hole punch on DCUtR. I'm documenting some cases here. Sorry this is not too clear right now but I'd like to get other people's inputs.

It seems to me that situation will be simplified if we let the receiver of a relayed connection dial /webrtc addresses.

  1. private non browser -> private non browser
  • When dialing a peer that supports webrtc(private to private), the dialer sees two addresses, the relay address and the /webrtc address.
  • In this case the optimal outcome is to get a holepunched quic connection. This can only happen when the dialer holds off on dialing the /webrtc address, wait for identify and then decide if the peer is a browser node or not depending on the identify information exchanged.
  • This also requires that on the peer while checking for DCUtR connection reversal doesn't dial the /webrtc address. (NOTE: this has implications for webrtc: specify multiaddresses on a browser-to-browser webrtc connection #579, here we do not want to interpret /webrtc as a direct address)
  1. public non browser -> browser node
  • When dialing a browser node that supports webrtc (private to private) a publicly reachable host would prefer that the browser dial back and reverse the connection using webtransport. The dialer needs to hold off on dialing /webrtc
    @achingbrain, does the present js-libp2p implementation support this?
  1. private non browser -> browser node
  • The private non browser dialer should trigger the /webrtc connection after performing identify with the peer and inferring that the peer is a browser node that will not be able to do DCUtR.

Activity

  1. achingbrain commented on Oct 1, 2023

    @achingbrain
    Member

    a publicly reachable host would prefer that the browser dial back and reverse the connection using webtransport

    Until this Chromium bug is resolved it's better for browsers to maximise use of WebRTC because the WebTransport transport can very quickly become unusable when WT sessions start to time out or otherwise error.

    This Firefox bug also needs to be resolved before WebTransport is usable in Firefox for our purposes at all.

    The dialer needs to hold off on dialing /webrtc does the present js-libp2p implementation support this?

    There's no QUIC in node yet ref: nodejs/node#48244 so no WebTransport either - the browser would have to reverse the connection using WebSockets.

    The TLS part of setting up a WebSocket listener seems to be too onerous for most so for node.js at least, until QUIC arrives WebRTC might be the best option.

  2. sukunrt commented on Oct 1, 2023

    @sukunrt
    MemberAuthor

    Thanks @achingbrain, looks like we should trigger /webrtc dial if the peer doesn't support DCUtR.
    I think this simple rule serves all the usecases,

    On an connecting to a peer over relay
    if the connection is outbound: 
    	if peer supports DCUtR:
    		do nothing, let the peer holepunch
    	else if peer has /webrtc address:
    	    dial /webrtc
    else if the connection is inbound:
    	do DCUtR
    

    Implemented here: libp2p/go-libp2p@6325e4e

  3. achingbrain commented on Oct 2, 2023

    @achingbrain
    Member

    I guess the implication here is:

    if the connection is outbound: 
        if peer supports DCUtR and we have non-WebRTC public addresses:
    

    Otherwise it might end up with both peers doing nothing if they both support DCUtR but only listen on WebRTC addresses?

  4. sukunrt commented on Oct 2, 2023

    @sukunrt
    MemberAuthor

    Should we just ensure that the <relay-addr>/p2p-circuit/webrtc addresses are exchanged in DCUtR address exchange step?

  5. reopened this on Oct 2, 2023
  6. achingbrain commented on Oct 4, 2023

    @achingbrain
    Member

    Do you think we might be trying to be too clever with this?

    If the node is instructed to dial WebRTC perhaps it should dial WebRTC, then if/when DCUtR happens, if there's a better transport to be used it could be used and then any open streams could be migrated?

  7. sukunrt commented on Oct 4, 2023

    @sukunrt
    MemberAuthor

    Do you think we might be trying to be too clever with this?

    I agree. This is getting rather complicated and the better solution is to keep upgrading connections to better transports rather than dialing the best transport after looking at all possible addresses. Looking at all possible addresses is getting too involved as this issues shows.

    There is a proposal in go-libp2p along similar lines: libp2p/go-libp2p#2412

    My present problem is probably too go-libp2p specific. If we implement webrtc as it is, it'll almost always connect on the /webrtc address rather than a /quic-v1 holepunched address. This is because, the /webrtc address is the one that's publicly advertised. The /quic-v1 address for a firewalled node needs to be obtained from DCUtR. So the dialer will proceed with establishing the webrtc connection. After the webrtc connection has been established, the dialer will not establish any new connections since it has no concept of upgrading the connection.

  8. sukunrt commented on Oct 22, 2023

    @sukunrt
    MemberAuthor

    On go-libp2p I've decided to holepunch using webrtc private to private when DCUtR fails.
    If the peer doesn't support DCUtR, the initiator just proceeds with the webrtc private to private connection
    If the peer supports DCUtR, if DCUtR fails for some reason, the peer(receiver of the relayed connection) initiates the webrtc private to private connection. It's better to keep this on the receiver because the receiver knows when to give up on DCUtR since it initiates the DCUtR protocol.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions