paullouisageneau / violet

Lightweight STUN/TURN server
GNU General Public License v2.0
226 stars 22 forks source link

precalculating and encoding offer/answer in username/cred for stun/turn server #22

Open unicomp21 opened 1 month ago

unicomp21 commented 1 month ago

I realize offer/answer for a datachannel can be handled via simple http request/response, but I'm hitting scenarios where this is cumbersome.

When only using datachannels, could it be possible to precompute the offer/answer in browser/javascript, and send this serded/encoded payload to violet via/piggbacked on the stun|turn login message? And then violet uses the browser/precalculated answer as it's own? I'm thinking a text encoding w/ length/prefixed delimiters would allow putting multiple fields in the username? (ie uname, password, offer sdp, answer sdp)

The goal is a quick/easy datachannel connection w/ the backend server which is running nodejs.

Have a good one! @paullouisageneau

paullouisageneau commented 3 weeks ago

I realize offer/answer for a datachannel can be handled via simple http request/response, but I'm hitting scenarios where this is cumbersome.

Yes indeed, actually the WHIP/WHEP protocols do this.

When only using datachannels, could it be possible to precompute the offer/answer in browser/javascript, and send this serded/encoded payload to violet via/piggbacked on the stun|turn login message? And then violet uses the browser/precalculated answer as it's own? I'm thinking a text encoding w/ length/prefixed delimiters would allow putting multiple fields in the username? (ie uname, password, offer sdp, answer sdp)

I don't really understand why you would do that, as the STUN/TURN server is distinct from your signaling server and remote WebRTC endpoint.

In practice it is not possible: to generate the full offer/answer description, you need local candidates, which are obtained from STUN and TURN servers. Therefore, you can't generate the description before sending a request to the STUN and TURN servers.

unicomp21 commented 3 weeks ago

STUN/TURN server is distinct from your signaling server and remote WebRTC endpoint.

What I'm suggesting is they all reside in the same app/process, specifically to achieve the goal described above.

unicomp21 commented 3 weeks ago

Does anything prevent building violet via emscripten? And running in the browser?

paullouisageneau commented 2 weeks ago

Does anything prevent building violet via emscripten? And running in the browser?

It is not possible since there is no socket API access in the browser. Even if there was, the server would not be on the public Internet so it would be useless.

unicomp21 commented 2 weeks ago

Yes, true, but w/ the goal of calculating both offer/answer in the browser, serde'ing them into the logon message, and using the same offer/answer pair on the remote end (turn/stun/libdatachannel), might be a possible approach?

paullouisageneau commented 4 days ago

The only way to "precalculate" the remote answer is to know everything in advance, certificates, credentials, and ports (Note that it necessarily breaks security). Therefore, the transmission via the TURN username is useless, it is simpler to hack the server so it accepts any incoming peer connection with an approach similar to WebRTC direct.

unicomp21 commented 4 days ago

sorry, I'm confused, webrtc-direct works in browsers?

anyhow, think I've found a way? using a homegrown turn: server w/ short circuit built-in? server side issues the offer and disables fingerprint check for returned answer? then browser can establish datachannel/turn: to backend by simply providing a unique/uuid sessionid in the logon message? rest of sdp is a simple template for offer/answer?

paullouisageneau commented 4 days ago

sorry, I'm confused, webrtc-direct works in browsers?

Yes it does. You don't need exactly WebRTC direct for your use case, anything implementing the same principle would work, but my point is that the TURN server is useless.

unicomp21 commented 4 days ago

What about scenarios where browser is running behind symmetric nat? turn: server is still useless?

paullouisageneau commented 4 days ago

What about scenarios where browser is running behind symmetric nat? turn: server is still useless?

Yes it is useless. The server is open, so the client can always reach it (like it could reach the TURN server).

unicomp21 commented 4 days ago

Meaning udp can hole punch thru a symmetric nat?

---claude--- A TURN server is needed for symmetric NAT scenarios. In symmetric NAT, each outbound connection from the same internal IP:port gets mapped to a different external IP:port. This makes it impossible for peer-to-peer connections to work directly, requiring a TURN server to relay the traffic.

For asymmetric NAT (including full-cone, restricted-cone, and port-restricted cone NAT), STUN servers are usually sufficient since the NAT mapping remains consistent and predictable.

paullouisageneau commented 4 days ago

Meaning udp can hole punch thru a symmetric nat?

It is not even hole-punching in that case. The server is not behind a NAT. If the client can reach the server on its address and port, the server can reach the client following the reverse path. All client-server protocols rely on this, for instance DNS over UDP. NAT mapping type on client side has nothing to do with it.

unicomp21 commented 4 days ago

It is not even hole-punching in that case.

got it, thanks for setting me straight.

unicomp21 commented 4 days ago

is there a working impl somewhere for webrtc-direct w/ browser integ tests?

paullouisageneau commented 4 days ago

libp2p has different implementations with tests: https://github.com/libp2p/specs/pull/412 Again, you don't need exactly WebRTC direct, only the same principle.

unicomp21 commented 4 days ago

if we are looking for IP support from browser (ie no www,https,turns etc.)

libp2p require webtransport? which is not available on ios/safari?

is this related? https://github.com/murat-dogan/node-datachannel/pull/256

paullouisageneau commented 4 days ago

if we are looking for IP support from browser (ie no www,https,turns etc.)

There is no socket API access in the browser.

libp2p require webtransport? which is not available on ios/safari?

No, libp2p uses WebRTC in browsers. That's the whole point of WebRTC direct.

is this related? murat-dogan/node-datachannel#256

This PR indeed exposes overrides that are needed to implement peer connections without signaling, for instance WebRTC direct.

unicomp21 commented 3 days ago

This PR indeed exposes overrides that are needed to implement peer connections without signaling, for instance WebRTC direct.

Which means there is not an existing impl yet? Which can do peer connections w/o signaling (ie browser -> server)?

paullouisageneau commented 3 days ago

Which means there is not an existing impl yet? Which can do peer connections w/o signaling (ie browser -> server)?

There is one in libp2p. For libdatachannel, you need to either hack it by yourself (hardcode what you need to be able to precalculate descriptions, ignore certificate validation, allow the server to receive connections, etc) or wait for the necessary overrides to be merged. Peer connections without signaling is not a use case WebRTC supports by default, you need to break a few things for it to work.

unicomp21 commented 3 days ago

Got it, thx! Does this look about right for the precalculated descriptions? When using libdatachannel w/ browser on other end?

const minimalOffer = {
  type: 'offer',
  sdp: 'v=0\r\n' +
    'o=- 0 0 IN IP4 127.0.0.1\r\n' +
    's=-\r\n' +
    't=0 0\r\n' +
    'a=ice-lite\r\n' +
    'm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n' +
    'c=IN IP4 0.0.0.0\r\n' +
    'a=ice-ufrag:lite\r\n' +
    'a=ice-pwd:lite\r\n' +
    'a=fingerprint:sha-256 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00\r\n' +
    'a=setup:actpass\r\n' +
    'a=mid:data\r\n' +
    'a=sctp-port:5000\r\n'
};

const minimalAnswer = {
  type: 'answer',
  sdp: 'v=0\r\n' +
    'o=- 0 0 IN IP4 127.0.0.1\r\n' +
    's=-\r\n' +
    't=0 0\r\n' +
    'm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\n' +
    'c=IN IP4 0.0.0.0\r\n' +
    'a=ice-ufrag:lite\r\n' +
    'a=ice-pwd:lite\r\n' +
    'a=fingerprint:sha-256 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00\r\n' +
    'a=setup:passive\r\n' +
    'a=mid:data\r\n' +
    'a=sctp-port:5000\r\n'
};

// need to support ios/safari and android/chrome
paullouisageneau commented 3 days ago

You can't set entirely dummy descriptions. You need at least a candidate on browser side so it can connect to the server. Also, you can't set an invalid fingerprint in the browser remote description because it will check the remote certificate.

unicomp21 commented 3 days ago

On a tangent, does libdatachannel use same cert/fingerprint across all peerconnections? Or does each pc get a new cert?

paullouisageneau commented 3 days ago

On a tangent, does libdatachannel use same cert/fingerprint across all peerconnections? Or does each pc get a new cert?

Peer connections with the same certificate type share the same certificate.