mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-16 11:03:41 -04:00
Merge branch 'dev-snowflake-udp-rebase-extradata' into 'main'
Draft: Unreliable+unordered WebRTC data channel transport for Snowflake rev2 See merge request tpo/anti-censorship/pluggable-transports/snowflake!315
This commit is contained in:
commit
aae444478d
17 changed files with 506 additions and 91 deletions
61
client/lib/connwrapper.go
Normal file
61
client/lib/connwrapper.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
package snowflake_client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ReadWriteCloserPreservesBoundary interface {
|
||||
io.ReadWriteCloser
|
||||
MessageBoundaryPreserved()
|
||||
}
|
||||
|
||||
var errENOSYS = errors.New("not implemented")
|
||||
|
||||
func newPacketConnWrapper(localAddr, remoteAddr net.Addr, rwc ReadWriteCloserPreservesBoundary) net.PacketConn {
|
||||
return &packetConnWrapper{
|
||||
ReadWriteCloserPreservesBoundary: rwc,
|
||||
remoteAddr: remoteAddr,
|
||||
localAddr: localAddr,
|
||||
}
|
||||
}
|
||||
|
||||
type packetConnWrapper struct {
|
||||
ReadWriteCloserPreservesBoundary
|
||||
remoteAddr net.Addr
|
||||
localAddr net.Addr
|
||||
}
|
||||
|
||||
func (pcw *packetConnWrapper) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
n, err = pcw.Read(p)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
return n, pcw.remoteAddr, nil
|
||||
}
|
||||
|
||||
func (pcw *packetConnWrapper) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
return pcw.Write(p)
|
||||
}
|
||||
|
||||
func (pcw *packetConnWrapper) Close() error {
|
||||
return pcw.ReadWriteCloserPreservesBoundary.Close()
|
||||
}
|
||||
|
||||
func (pcw *packetConnWrapper) LocalAddr() net.Addr {
|
||||
return pcw.localAddr
|
||||
}
|
||||
|
||||
func (pcw *packetConnWrapper) SetDeadline(t time.Time) error {
|
||||
return errENOSYS
|
||||
}
|
||||
|
||||
func (pcw *packetConnWrapper) SetReadDeadline(t time.Time) error {
|
||||
return errENOSYS
|
||||
}
|
||||
|
||||
func (pcw *packetConnWrapper) SetWriteDeadline(t time.Time) error {
|
||||
return errENOSYS
|
||||
}
|
|
@ -21,6 +21,7 @@ import (
|
|||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/event"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/messages"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/nat"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/turbotunnel"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/util"
|
||||
)
|
||||
|
||||
|
@ -251,6 +252,7 @@ type WebRTCDialer struct {
|
|||
|
||||
eventLogger event.SnowflakeEventReceiver
|
||||
proxy *url.URL
|
||||
clientID turbotunnel.ClientID
|
||||
}
|
||||
|
||||
// Deprecated: Use NewWebRTCDialerWithNatPolicyAndEventsAndProxy instead
|
||||
|
@ -281,7 +283,6 @@ func NewWebRTCDialerWithEventsAndProxy(broker *BrokerChannel, iceServers []webrt
|
|||
)
|
||||
}
|
||||
|
||||
// NewWebRTCDialerWithNatPolicyAndEventsAndProxy constructs a new WebRTCDialer.
|
||||
func NewWebRTCDialerWithNatPolicyAndEventsAndProxy(
|
||||
broker *BrokerChannel,
|
||||
natPolicy *NATPolicy,
|
||||
|
@ -289,6 +290,27 @@ func NewWebRTCDialerWithNatPolicyAndEventsAndProxy(
|
|||
max int,
|
||||
eventLogger event.SnowflakeEventReceiver,
|
||||
proxy *url.URL,
|
||||
) *WebRTCDialer {
|
||||
return newWebRTCDialerWithNatPolicyAndEventsAndProxyAndClientID(
|
||||
broker,
|
||||
natPolicy,
|
||||
iceServers,
|
||||
max,
|
||||
eventLogger,
|
||||
proxy,
|
||||
turbotunnel.NewClientID(),
|
||||
)
|
||||
}
|
||||
|
||||
// NewWebRTCDialerWithNatPolicyAndEventsAndProxy constructs a new WebRTCDialer.
|
||||
func newWebRTCDialerWithNatPolicyAndEventsAndProxyAndClientID(
|
||||
broker *BrokerChannel,
|
||||
natPolicy *NATPolicy,
|
||||
iceServers []webrtc.ICEServer,
|
||||
max int,
|
||||
eventLogger event.SnowflakeEventReceiver,
|
||||
proxy *url.URL,
|
||||
clientID turbotunnel.ClientID,
|
||||
) *WebRTCDialer {
|
||||
config := webrtc.Configuration{
|
||||
ICEServers: iceServers,
|
||||
|
@ -302,6 +324,7 @@ func NewWebRTCDialerWithNatPolicyAndEventsAndProxy(
|
|||
|
||||
eventLogger: eventLogger,
|
||||
proxy: proxy,
|
||||
clientID: clientID,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,9 +332,7 @@ func NewWebRTCDialerWithNatPolicyAndEventsAndProxy(
|
|||
func (w WebRTCDialer) Catch() (*WebRTCPeer, error) {
|
||||
// TODO: [#25591] Fetch ICE server information from Broker.
|
||||
// TODO: [#25596] Consider TURN servers here too.
|
||||
return NewWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
w.webrtcConfig, w.BrokerChannel, w.natPolicy, w.eventLogger, w.proxy,
|
||||
)
|
||||
return NewWebRTCPeerWithNatPolicyAndEventsProxyAndClientID(w.webrtcConfig, w.BrokerChannel, w.natPolicy, w.eventLogger, w.proxy, w.clientID)
|
||||
}
|
||||
|
||||
// GetMax returns the maximum number of snowflakes to collect.
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -42,6 +43,7 @@ import (
|
|||
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/event"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/nat"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/packetpadding"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/turbotunnel"
|
||||
)
|
||||
|
||||
|
@ -163,7 +165,10 @@ func NewSnowflakeClient(config ClientConfig) (*Transport, error) {
|
|||
max = config.Max
|
||||
}
|
||||
eventsLogger := event.NewSnowflakeEventDispatcher()
|
||||
transport := &Transport{dialer: NewWebRTCDialerWithNatPolicyAndEventsAndProxy(broker, natPolicy, iceServers, max, eventsLogger, config.CommunicationProxy), eventDispatcher: eventsLogger}
|
||||
transport := &Transport{
|
||||
dialer: NewWebRTCDialerWithNatPolicyAndEventsAndProxy(broker, natPolicy, iceServers, max, eventsLogger, config.CommunicationProxy),
|
||||
eventDispatcher: eventsLogger,
|
||||
}
|
||||
|
||||
return transport, nil
|
||||
}
|
||||
|
@ -324,13 +329,11 @@ func parseIceServers(addresses []string) []webrtc.ICEServer {
|
|||
// over. The net.PacketConn successively connects through Snowflake proxies
|
||||
// pulled from snowflakes.
|
||||
func newSession(snowflakes SnowflakeCollector) (net.PacketConn, *smux.Session, error) {
|
||||
clientID := turbotunnel.NewClientID()
|
||||
|
||||
// We build a persistent KCP session on a sequence of ephemeral WebRTC
|
||||
// connections. This dialContext tells RedialPacketConn how to get a new
|
||||
// WebRTC connection when the previous one dies. Inside each WebRTC
|
||||
// connection, we use encapsulationPacketConn to encode packets into a
|
||||
// stream.
|
||||
// connection, KCP packets are sent and received, one-to-one, in data
|
||||
// channel messages.
|
||||
dialContext := func(ctx context.Context) (net.PacketConn, error) {
|
||||
log.Printf("redialing on same connection")
|
||||
// Obtain an available WebRTC remote. May block.
|
||||
|
@ -339,17 +342,12 @@ func newSession(snowflakes SnowflakeCollector) (net.PacketConn, *smux.Session, e
|
|||
return nil, errors.New("handler: Received invalid Snowflake")
|
||||
}
|
||||
log.Println("---- Handler: snowflake assigned ----")
|
||||
// Send the magic Turbo Tunnel token.
|
||||
_, err := conn.Write(turbotunnel.Token[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Send ClientID prefix.
|
||||
_, err = conn.Write(clientID[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newEncapsulationPacketConn(dummyAddr{}, dummyAddr{}, conn), nil
|
||||
|
||||
packetConnWrapper := newPacketConnWrapper(dummyAddr{}, dummyAddr{},
|
||||
packetpadding.NewPaddableConnection(conn,
|
||||
packetpadding.New()))
|
||||
|
||||
return packetConnWrapper, nil
|
||||
}
|
||||
pconn := turbotunnel.NewRedialPacketConn(dummyAddr{}, dummyAddr{}, dialContext)
|
||||
|
||||
|
@ -375,6 +373,14 @@ func newSession(snowflakes SnowflakeCollector) (net.PacketConn, *smux.Session, e
|
|||
0, // default resend
|
||||
1, // nc=1 => congestion window off
|
||||
)
|
||||
if os.Getenv("SNOWFLAKE_TEST_KCP_FAST3MODE") == "1" {
|
||||
conn.SetNoDelay(
|
||||
1,
|
||||
10,
|
||||
2,
|
||||
1,
|
||||
)
|
||||
}
|
||||
// On the KCP connection we overlay an smux session and stream.
|
||||
smuxConfig := smux.DefaultConfig()
|
||||
smuxConfig.Version = 2
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/messages"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
|
@ -18,6 +19,7 @@ import (
|
|||
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/event"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/proxy"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/turbotunnel"
|
||||
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/util"
|
||||
)
|
||||
|
||||
|
@ -43,46 +45,63 @@ type WebRTCPeer struct {
|
|||
bytesLogger bytesLogger
|
||||
eventsLogger event.SnowflakeEventReceiver
|
||||
proxy *url.URL
|
||||
|
||||
clientID turbotunnel.ClientID
|
||||
}
|
||||
|
||||
// Deprecated: Use NewWebRTCPeerWithNatPolicyAndEventsAndProxy Instead.
|
||||
func NewWebRTCPeer(
|
||||
func newWebRTCPeer(
|
||||
config *webrtc.Configuration, broker *BrokerChannel,
|
||||
) (*WebRTCPeer, error) {
|
||||
return NewWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
return newWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
config, broker, nil, nil, nil,
|
||||
)
|
||||
}
|
||||
|
||||
// Deprecated: Use NewWebRTCPeerWithNatPolicyAndEventsAndProxy Instead.
|
||||
func NewWebRTCPeerWithEvents(
|
||||
func newWebRTCPeerWithEvents(
|
||||
config *webrtc.Configuration, broker *BrokerChannel,
|
||||
eventsLogger event.SnowflakeEventReceiver,
|
||||
) (*WebRTCPeer, error) {
|
||||
return NewWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
return newWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
config, broker, nil, eventsLogger, nil,
|
||||
)
|
||||
}
|
||||
|
||||
// Deprecated: Use NewWebRTCPeerWithNatPolicyAndEventsAndProxy Instead.
|
||||
func NewWebRTCPeerWithEventsAndProxy(
|
||||
func newWebRTCPeerWithEventsAndProxy(
|
||||
config *webrtc.Configuration, broker *BrokerChannel,
|
||||
eventsLogger event.SnowflakeEventReceiver, proxy *url.URL,
|
||||
) (*WebRTCPeer, error) {
|
||||
return NewWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
return newWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
config, broker, nil, eventsLogger, proxy,
|
||||
)
|
||||
}
|
||||
|
||||
func newWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
config *webrtc.Configuration,
|
||||
broker *BrokerChannel, natPolicy *NATPolicy, eventsLogger event.SnowflakeEventReceiver, proxy *url.URL,
|
||||
) (*WebRTCPeer, error) {
|
||||
return NewWebRTCPeerWithNatPolicyAndEventsProxyAndClientID(
|
||||
config,
|
||||
broker,
|
||||
natPolicy,
|
||||
eventsLogger,
|
||||
proxy,
|
||||
turbotunnel.ClientID{},
|
||||
)
|
||||
}
|
||||
|
||||
// NewWebRTCPeerWithNatPolicyAndEventsAndProxy constructs
|
||||
// a WebRTC PeerConnection to a snowflake proxy.
|
||||
//
|
||||
// The creation of the peer handles the signaling to the Snowflake broker, including
|
||||
// the exchange of SDP information, the creation of a PeerConnection, and the establishment
|
||||
// of a DataChannel to the Snowflake proxy.
|
||||
func NewWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
||||
config *webrtc.Configuration, broker *BrokerChannel, natPolicy *NATPolicy,
|
||||
eventsLogger event.SnowflakeEventReceiver, proxy *url.URL,
|
||||
// clientID is the hinted ID for the connection.
|
||||
func NewWebRTCPeerWithNatPolicyAndEventsProxyAndClientID(config *webrtc.Configuration,
|
||||
broker *BrokerChannel, natPolicy *NATPolicy, eventsLogger event.SnowflakeEventReceiver, proxy *url.URL,
|
||||
clientID turbotunnel.ClientID,
|
||||
) (*WebRTCPeer, error) {
|
||||
if eventsLogger == nil {
|
||||
eventsLogger = event.NewSnowflakeEventDispatcher()
|
||||
|
@ -106,6 +125,7 @@ func NewWebRTCPeerWithNatPolicyAndEventsAndProxy(
|
|||
|
||||
connection.eventsLogger = eventsLogger
|
||||
connection.proxy = proxy
|
||||
connection.clientID = clientID
|
||||
|
||||
err := connection.connect(config, broker, natPolicy)
|
||||
if err != nil {
|
||||
|
@ -296,9 +316,18 @@ func (c *WebRTCPeer) preparePeerConnection(
|
|||
log.Printf("NewPeerConnection ERROR: %s", err)
|
||||
return err
|
||||
}
|
||||
ordered := true
|
||||
ordered := false
|
||||
var maxRetransmission uint16 = 0
|
||||
connectionMetadata := messages.ClientConnectionMetadata{ClientID: c.clientID[:]}
|
||||
encodedMetadata, err := connectionMetadata.EncodeConnectionMetadata()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
protocol := encodedMetadata
|
||||
dataChannelOptions := &webrtc.DataChannelInit{
|
||||
Ordered: &ordered,
|
||||
Ordered: &ordered,
|
||||
Protocol: &protocol,
|
||||
MaxRetransmits: &maxRetransmission,
|
||||
}
|
||||
// We must create the data channel before creating an offer
|
||||
// https://github.com/pion/webrtc/wiki/Release-WebRTC@v3.0.0#a-data-channel-is-no-longer-implicitly-created-with-a-peerconnection
|
||||
|
@ -383,3 +412,5 @@ func (c *WebRTCPeer) cleanup() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *WebRTCPeer) MessageBoundaryPreserved() {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue