Add package functions to define and set the rendezvous method

Add exported functions to the snowflake client library to allow calling
programs to define and set their own custom broker rendezvous methods.
This commit is contained in:
Cecylia Bocovich 2021-09-09 12:54:31 -04:00
parent 624750d5a8
commit 99887cd05d
5 changed files with 71 additions and 14 deletions

View file

@ -26,21 +26,20 @@ const (
readLimit = 100000 //Maximum number of bytes to be read from an HTTP response readLimit = 100000 //Maximum number of bytes to be read from an HTTP response
) )
// rendezvousMethod represents a way of communicating with the broker: sending // RendezvousMethod represents a way of communicating with the broker: sending
// an encoded client poll request (SDP offer) and receiving an encoded client // an encoded client poll request (SDP offer) and receiving an encoded client
// poll response (SDP answer) in return. rendezvousMethod is used by // poll response (SDP answer) in return. RendezvousMethod is used by
// BrokerChannel, which is in charge of encoding and decoding, and all other // BrokerChannel, which is in charge of encoding and decoding, and all other
// tasks that are independent of the rendezvous method. // tasks that are independent of the rendezvous method.
type rendezvousMethod interface { type RendezvousMethod interface {
Exchange([]byte) ([]byte, error) Exchange([]byte) ([]byte, error)
} }
// BrokerChannel contains a rendezvousMethod, as well as data that is not // BrokerChannel uses a RendezvousMethod to communicate with the Snowflake broker.
// specific to any rendezvousMethod. BrokerChannel has the responsibility of // The BrokerChannel is responsible for encoding and decoding SDP offers and answers;
// encoding and decoding SDP offers and answers; rendezvousMethod is responsible // RendezvousMethod is responsible for the exchange of encoded information.
// for the exchange of encoded information.
type BrokerChannel struct { type BrokerChannel struct {
rendezvous rendezvousMethod Rendezvous RendezvousMethod
keepLocalAddresses bool keepLocalAddresses bool
natType string natType string
lock sync.Mutex lock sync.Mutex
@ -68,7 +67,7 @@ func NewBrokerChannel(broker, ampCache, front string, keepLocalAddresses bool) (
log.Println("Domain fronting using:", front) log.Println("Domain fronting using:", front)
} }
var rendezvous rendezvousMethod var rendezvous RendezvousMethod
var err error var err error
if ampCache != "" { if ampCache != "" {
rendezvous, err = newAMPCacheRendezvous(broker, ampCache, front, createBrokerTransport()) rendezvous, err = newAMPCacheRendezvous(broker, ampCache, front, createBrokerTransport())
@ -80,7 +79,7 @@ func NewBrokerChannel(broker, ampCache, front string, keepLocalAddresses bool) (
} }
return &BrokerChannel{ return &BrokerChannel{
rendezvous: rendezvous, Rendezvous: rendezvous,
keepLocalAddresses: keepLocalAddresses, keepLocalAddresses: keepLocalAddresses,
natType: nat.NATUnknown, natType: nat.NATUnknown,
}, nil }, nil
@ -118,8 +117,8 @@ func (bc *BrokerChannel) Negotiate(offer *webrtc.SessionDescription) (
return nil, err return nil, err
} }
// Do the exchange using our rendezvousMethod. // Do the exchange using our RendezvousMethod.
encResp, err := bc.rendezvous.Exchange(encReq) encResp, err := bc.Rendezvous.Exchange(encReq)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -11,7 +11,7 @@ import (
"git.torproject.org/pluggable-transports/snowflake.git/common/amp" "git.torproject.org/pluggable-transports/snowflake.git/common/amp"
) )
// ampCacheRendezvous is a rendezvousMethod that communicates with the // ampCacheRendezvous is a RendezvousMethod that communicates with the
// .../amp/client route of the broker, optionally over an AMP cache proxy, and // .../amp/client route of the broker, optionally over an AMP cache proxy, and
// with optional domain fronting. // with optional domain fronting.
type ampCacheRendezvous struct { type ampCacheRendezvous struct {

View file

@ -10,7 +10,7 @@ import (
"net/url" "net/url"
) )
// httpRendezvous is a rendezvousMethod that communicates with the .../client // httpRendezvous is a RendezvousMethod that communicates with the .../client
// route of the broker over HTTP or HTTPS, with optional domain fronting. // route of the broker over HTTP or HTTPS, with optional domain fronting.
type httpRendezvous struct { type httpRendezvous struct {
brokerURL *url.URL brokerURL *url.URL

View file

@ -132,6 +132,10 @@ func (t *Transport) Dial() (net.Conn, error) {
return &SnowflakeConn{Stream: stream, sess: sess, pconn: pconn, snowflakes: snowflakes}, nil return &SnowflakeConn{Stream: stream, sess: sess, pconn: pconn, snowflakes: snowflakes}, nil
} }
func (t *Transport) SetRendezvousMethod(r RendezvousMethod) {
t.dialer.Rendezvous = r
}
type SnowflakeConn struct { type SnowflakeConn struct {
*smux.Stream *smux.Stream
sess *smux.Session sess *smux.Session

View file

@ -38,6 +38,60 @@ func main() {
} }
``` ```
#### Using your own rendezvous method
You can define and use your own rendezvous method to communicate with a Snowflake broker by implementing the `RendezvousMethod` interface.
```Golang
package main
import (
"log"
sf "git.torproject.org/pluggable-transports/snowflake.git/client/lib"
)
type StubMethod struct {
}
func (m *StubMethod) Exchange(pollReq []byte) ([]byte, error) {
var brokerResponse []byte
var err error
//Implement the logic you need to communicate with the Snowflake broker here
return brokerResponse, err
}
func main() {
config := sf.ClientConfig{
ICEAddresses: []string{
"stun:stun.voip.blackberry.com:3478",
"stun:stun.stunprotocol.org:3478"},
}
transport, err := sf.NewSnowflakeClient(config)
if err != nil {
log.Fatal("Failed to start snowflake transport: ", err)
}
// custom rendezvous methods can be set with `SetRendezvousMethod`
rendezvous := &StubMethod{}
transport.SetRendezvousMethod(rendezvous)
// transport implements the ClientFactory interface and returns a net.Conn
conn, err := transport.Dial()
if err != nil {
log.Printf("dial error: %s", err)
return
}
defer conn.Close()
// ...
}
```
### Server library ### Server library
The Snowflake server library contains functions for running a Snowflake server. The Snowflake server library contains functions for running a Snowflake server.