Partially reliable and/or unordered WebRTC data channels

Shelikhoo brought up an interesting point at today's meeting. Snowflake uses WebRTC data channels on the client–proxy link. Data channels are SCTP in DTLS. They are by default fully reliable and in-order, like TCP, and that is the way we currently use them. But SCTP and in turn WebRTC data channels also have "partial reliability" and "unordered" options that might be a better fit for our uses. http://meetbot.debian.net/tor-meeting/2023/tor-meeting.2023-03-16-15.57.log.... 16:25:29 <shelikhoo> webrtc(SCTP to be specific) can be set to not retransmit packet 16:25:34 <shelikhoo> and deliver packet out of order 16:25:43 <shelikhoo> to application 16:26:14 <dcf1> I did not know about that. Do we use it that way in Snowflake? 16:27:28 <shelikhoo> it is called "unreliable mode" https://pkg.go.dev/github.com/pion/webrtc/v3#DataChannel.MaxRetransmits 16:29:28 <dcf1> Ok. I might have missed an issue, is that mode used in Snowflake? Or could it be? 16:30:27 <shelikhoo> https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowf... 16:30:54 <shelikhoo> https://pkg.go.dev/github.com/pion/webrtc/v3#DataChannelInit 16:31:18 <shelikhoo> Maybe no...? but we can enable "unreliable mode" ## Background The specification of WebRTC data channels, RFC 8831, requires the SCTP implementation to support limiting transmissions by either time or number. https://www.rfc-editor.org/rfc/rfc8831
Orthogonal to reliability, the SCTP implementation must support ordered or unordered delivery of messages. https://www.rfc-editor.org/rfc/rfc8831#name-sctp-protocol-consideration
Removing retransmissions and ordering restrictions makes a data channel into a datagram delivery service that preserves message boundaries, but not ordering, and does not guarantee delivery. https://www.rfc-editor.org/rfc/rfc8831#name-sctp-protocol-consideration
The WebRTC Data Channel Establishment Protocol's DATA_CHANNEL_OPEN message is where the ordering and retransmission limits are specified. (Note partial reliability and ordering are two separate concepts, and that you can only limit retransmissions by time or number, not both.) https://www.rfc-editor.org/rfc/rfc8832.html#name-data_channel_open-message
Though in SCTP the unordered flag (U) may vary per DATA chunk, data channels can only be entirely ordered or entirely unordered. https://www.rfc-editor.org/rfc/rfc9260#name-ordered-and-unordered-deliv The JavaScript API exposes these settings in the RTCPeerConnection.createDataChannel method: https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createDat...
Similar options are exposed in Pion PeerConnection.CreateDataChannel and the DataChannelInit struct: https://pkg.go.dev/github.com/pion/webrtc/v3#DataChannelInit
## Possibilities for Snowflake Currently in Snowflake, we treat the data channel as if it were a TCP stream: we ignore message boundaries and concatenate all messages in order. What we transmit over this stream, though, is a sequence of discrete KCP packets (and possible padding), delimited using length prefixes: https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowf... The boundaries of encapsulated KCP packets do not necessarily correspond to SCTP/data channel message boundaries. We may be able to increase efficiency by using data channel messages directly, one KCP packet per message. Because KCP has its own retransmission and reordering facilities, we could completely turn off reliability and ordering at the data channel layer. One of the reasons we use the packet encapsulation we use now is to permit shaping the size of network packets. But matching data channel messages 1:1 with KCP packet does not necessarily negatively affect traffic shaping capability. We could put a simple length prefix at the head of each message that indicates the effective payload length, with the rest being padding. If the traffic schedule calls for a payload smaller than an immediately available packet, an all-padding message can be sent. Such a change would require changes at the proxy. Proxies would need a second mode to take message boundaries directly from the data channel, rather than concatenating messages and decoding message boundaries from the joined-up stream. Proxies could backward-compatibly forward the messages to the bridge over WebSocket, applying the packet encapsulation at the proxy rather than the client. Or (requiring a change at the bridge too), we could use WebRTC on the proxy–bridge link and similarly send packets with unordered and unreliable data channels.
participants (1)
-
David Fifield