Randomly select front domain from comma-separated list

This commmit changes the command-line and Bridge line arguments to take
a comma-separated list of front domains. The change is backwards
compatible with old Bridge and ClientTransportPlugin lines. At
rendezvous time, a front domain will be randomly chosen from the list.
This commit is contained in:
Cecylia Bocovich 2023-09-23 10:46:46 -04:00
parent 5cdf52c813
commit 9fdfb3d1b5
No known key found for this signature in database
GPG key ID: 009DE379FD9B7B90
7 changed files with 65 additions and 48 deletions

View file

@ -64,8 +64,8 @@ func createBrokerTransport() http.RoundTripper {
func newBrokerChannelFromConfig(config ClientConfig) (*BrokerChannel, error) { func newBrokerChannelFromConfig(config ClientConfig) (*BrokerChannel, error) {
log.Println("Rendezvous using Broker at:", config.BrokerURL) log.Println("Rendezvous using Broker at:", config.BrokerURL)
if config.FrontDomain != "" { if len(config.FrontDomains) != 0 {
log.Println("Domain fronting using:", config.FrontDomain) log.Printf("Domain fronting using a randomly selected domain from: %v", config.FrontDomains)
} }
brokerTransport := createBrokerTransport() brokerTransport := createBrokerTransport()
@ -86,11 +86,11 @@ func newBrokerChannelFromConfig(config ClientConfig) (*BrokerChannel, error) {
if config.AmpCacheURL != "" { if config.AmpCacheURL != "" {
log.Println("Through AMP cache at:", config.AmpCacheURL) log.Println("Through AMP cache at:", config.AmpCacheURL)
rendezvous, err = newAMPCacheRendezvous( rendezvous, err = newAMPCacheRendezvous(
config.BrokerURL, config.AmpCacheURL, config.FrontDomain, config.BrokerURL, config.AmpCacheURL, config.FrontDomains,
brokerTransport) brokerTransport)
} else { } else {
rendezvous, err = newHTTPRendezvous( rendezvous, err = newHTTPRendezvous(
config.BrokerURL, config.FrontDomain, brokerTransport) config.BrokerURL, config.FrontDomains, brokerTransport)
} }
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -5,8 +5,10 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
"math/rand"
"net/http" "net/http"
"net/url" "net/url"
"time"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/amp" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/amp"
) )
@ -17,7 +19,7 @@ import (
type ampCacheRendezvous struct { type ampCacheRendezvous struct {
brokerURL *url.URL brokerURL *url.URL
cacheURL *url.URL // Optional AMP cache URL. cacheURL *url.URL // Optional AMP cache URL.
front string // Optional front domain to replace url.Host in requests. fronts []string // Optional front domains to replace url.Host in requests.
transport http.RoundTripper // Used to make all requests. transport http.RoundTripper // Used to make all requests.
} }
@ -25,7 +27,7 @@ type ampCacheRendezvous struct {
// broker at the given URL, optionally proxying through an AMP cache, and with // broker at the given URL, optionally proxying through an AMP cache, and with
// an optional front domain. transport is the http.RoundTripper used to make all // an optional front domain. transport is the http.RoundTripper used to make all
// requests. // requests.
func newAMPCacheRendezvous(broker, cache, front string, transport http.RoundTripper) (*ampCacheRendezvous, error) { func newAMPCacheRendezvous(broker, cache string, fronts []string, transport http.RoundTripper) (*ampCacheRendezvous, error) {
brokerURL, err := url.Parse(broker) brokerURL, err := url.Parse(broker)
if err != nil { if err != nil {
return nil, err return nil, err
@ -41,7 +43,7 @@ func newAMPCacheRendezvous(broker, cache, front string, transport http.RoundTrip
return &ampCacheRendezvous{ return &ampCacheRendezvous{
brokerURL: brokerURL, brokerURL: brokerURL,
cacheURL: cacheURL, cacheURL: cacheURL,
front: front, fronts: fronts,
transport: transport, transport: transport,
}, nil }, nil
} }
@ -50,7 +52,6 @@ func (r *ampCacheRendezvous) Exchange(encPollReq []byte) ([]byte, error) {
log.Println("Negotiating via AMP cache rendezvous...") log.Println("Negotiating via AMP cache rendezvous...")
log.Println("Broker URL:", r.brokerURL) log.Println("Broker URL:", r.brokerURL)
log.Println("AMP cache URL:", r.cacheURL) log.Println("AMP cache URL:", r.cacheURL)
log.Println("Front domain:", r.front)
// We cannot POST a body through an AMP cache, so instead we GET and // We cannot POST a body through an AMP cache, so instead we GET and
// encode the client poll request message into the URL. // encode the client poll request message into the URL.
@ -72,11 +73,14 @@ func (r *ampCacheRendezvous) Exchange(encPollReq []byte) ([]byte, error) {
return nil, err return nil, err
} }
if r.front != "" { if len(r.fronts) != 0 {
// Do domain fronting. Replace the domain in the URL's with the // Do domain fronting. Replace the domain in the URL's with a randomly
// front, and store the original domain the HTTP Host header. // selected front, and store the original domain the HTTP Host header.
rand.Seed(time.Now().UnixNano())
front := r.fronts[rand.Intn(len(r.fronts))]
log.Println("Front domain:", front)
req.Host = req.URL.Host req.Host = req.URL.Host
req.URL.Host = r.front req.URL.Host = front
} }
resp, err := r.transport.RoundTrip(req) resp, err := r.transport.RoundTrip(req)

View file

@ -6,29 +6,31 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
"math/rand"
"net/http" "net/http"
"net/url" "net/url"
"time"
) )
// 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
front string // Optional front domain to replace url.Host in requests. fronts []string // Optional front domain to replace url.Host in requests.
transport http.RoundTripper // Used to make all requests. transport http.RoundTripper // Used to make all requests.
} }
// newHTTPRendezvous creates a new httpRendezvous that contacts the broker at // newHTTPRendezvous creates a new httpRendezvous that contacts the broker at
// the given URL, with an optional front domain. transport is the // the given URL, with an optional front domain. transport is the
// http.RoundTripper used to make all requests. // http.RoundTripper used to make all requests.
func newHTTPRendezvous(broker, front string, transport http.RoundTripper) (*httpRendezvous, error) { func newHTTPRendezvous(broker string, fronts []string, transport http.RoundTripper) (*httpRendezvous, error) {
brokerURL, err := url.Parse(broker) brokerURL, err := url.Parse(broker)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &httpRendezvous{ return &httpRendezvous{
brokerURL: brokerURL, brokerURL: brokerURL,
front: front, fronts: fronts,
transport: transport, transport: transport,
}, nil }, nil
} }
@ -36,7 +38,6 @@ func newHTTPRendezvous(broker, front string, transport http.RoundTripper) (*http
func (r *httpRendezvous) Exchange(encPollReq []byte) ([]byte, error) { func (r *httpRendezvous) Exchange(encPollReq []byte) ([]byte, error) {
log.Println("Negotiating via HTTP rendezvous...") log.Println("Negotiating via HTTP rendezvous...")
log.Println("Target URL: ", r.brokerURL.Host) log.Println("Target URL: ", r.brokerURL.Host)
log.Println("Front URL: ", r.front)
// Suffix the path with the broker's client registration handler. // Suffix the path with the broker's client registration handler.
reqURL := r.brokerURL.ResolveReference(&url.URL{Path: "client"}) reqURL := r.brokerURL.ResolveReference(&url.URL{Path: "client"})
@ -45,11 +46,14 @@ func (r *httpRendezvous) Exchange(encPollReq []byte) ([]byte, error) {
return nil, err return nil, err
} }
if r.front != "" { if len(r.fronts) != 0 {
// Do domain fronting. Replace the domain in the URL's with the // Do domain fronting. Replace the domain in the URL's with a randomly
// front, and store the original domain the HTTP Host header. // selected front, and store the original domain the HTTP Host header.
rand.Seed(time.Now().UnixNano())
front := r.fronts[rand.Intn(len(r.fronts))]
log.Println("Front URL: ", front)
req.Host = req.URL.Host req.Host = req.URL.Host
req.URL.Host = r.front req.URL.Host = front
} }
resp, err := r.transport.RoundTrip(req) resp, err := r.transport.RoundTrip(req)

View file

@ -71,21 +71,21 @@ func TestHTTPRendezvous(t *testing.T) {
Convey("HTTP rendezvous", t, func() { Convey("HTTP rendezvous", t, func() {
Convey("Construct httpRendezvous with no front domain", func() { Convey("Construct httpRendezvous with no front domain", func() {
transport := &mockTransport{http.StatusOK, []byte{}} transport := &mockTransport{http.StatusOK, []byte{}}
rend, err := newHTTPRendezvous("http://test.broker", "", transport) rend, err := newHTTPRendezvous("http://test.broker", []string{}, transport)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(rend.brokerURL, ShouldNotBeNil) So(rend.brokerURL, ShouldNotBeNil)
So(rend.brokerURL.Host, ShouldResemble, "test.broker") So(rend.brokerURL.Host, ShouldResemble, "test.broker")
So(rend.front, ShouldResemble, "") So(rend.fronts, ShouldEqual, []string{})
So(rend.transport, ShouldEqual, transport) So(rend.transport, ShouldEqual, transport)
}) })
Convey("Construct httpRendezvous *with* front domain", func() { Convey("Construct httpRendezvous *with* front domain", func() {
transport := &mockTransport{http.StatusOK, []byte{}} transport := &mockTransport{http.StatusOK, []byte{}}
rend, err := newHTTPRendezvous("http://test.broker", "front", transport) rend, err := newHTTPRendezvous("http://test.broker", []string{"front"}, transport)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(rend.brokerURL, ShouldNotBeNil) So(rend.brokerURL, ShouldNotBeNil)
So(rend.brokerURL.Host, ShouldResemble, "test.broker") So(rend.brokerURL.Host, ShouldResemble, "test.broker")
So(rend.front, ShouldResemble, "front") So(rend.fronts, ShouldContain, "front")
So(rend.transport, ShouldEqual, transport) So(rend.transport, ShouldEqual, transport)
}) })
@ -94,7 +94,7 @@ func TestHTTPRendezvous(t *testing.T) {
`{"answer": "{\"type\":\"answer\",\"sdp\":\"fake\"}" }`, `{"answer": "{\"type\":\"answer\",\"sdp\":\"fake\"}" }`,
"", "",
) )
rend, err := newHTTPRendezvous("http://test.broker", "", rend, err := newHTTPRendezvous("http://test.broker", []string{},
&mockTransport{http.StatusOK, fakeEncPollResp}) &mockTransport{http.StatusOK, fakeEncPollResp})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -107,7 +107,7 @@ func TestHTTPRendezvous(t *testing.T) {
"", "",
`{"error": "no snowflake proxies currently available"}`, `{"error": "no snowflake proxies currently available"}`,
) )
rend, err := newHTTPRendezvous("http://test.broker", "", rend, err := newHTTPRendezvous("http://test.broker", []string{},
&mockTransport{http.StatusOK, fakeEncPollResp}) &mockTransport{http.StatusOK, fakeEncPollResp})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -116,7 +116,7 @@ func TestHTTPRendezvous(t *testing.T) {
}) })
Convey("httpRendezvous.Exchange fails with unexpected HTTP status code", func() { Convey("httpRendezvous.Exchange fails with unexpected HTTP status code", func() {
rend, err := newHTTPRendezvous("http://test.broker", "", rend, err := newHTTPRendezvous("http://test.broker", []string{},
&mockTransport{http.StatusInternalServerError, []byte{}}) &mockTransport{http.StatusInternalServerError, []byte{}})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -127,7 +127,7 @@ func TestHTTPRendezvous(t *testing.T) {
Convey("httpRendezvous.Exchange fails with error", func() { Convey("httpRendezvous.Exchange fails with error", func() {
transportErr := errors.New("error") transportErr := errors.New("error")
rend, err := newHTTPRendezvous("http://test.broker", "", rend, err := newHTTPRendezvous("http://test.broker", []string{},
&errorTransport{err: transportErr}) &errorTransport{err: transportErr})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -136,7 +136,7 @@ func TestHTTPRendezvous(t *testing.T) {
}) })
Convey("httpRendezvous.Exchange fails with large read", func() { Convey("httpRendezvous.Exchange fails with large read", func() {
rend, err := newHTTPRendezvous("http://test.broker", "", rend, err := newHTTPRendezvous("http://test.broker", []string{},
&mockTransport{http.StatusOK, make([]byte, readLimit+1)}) &mockTransport{http.StatusOK, make([]byte, readLimit+1)})
So(err, ShouldBeNil) So(err, ShouldBeNil)
_, err = rend.Exchange(fakeEncPollReq) _, err = rend.Exchange(fakeEncPollReq)
@ -166,47 +166,47 @@ func TestAMPCacheRendezvous(t *testing.T) {
Convey("AMP cache rendezvous", t, func() { Convey("AMP cache rendezvous", t, func() {
Convey("Construct ampCacheRendezvous with no cache and no front domain", func() { Convey("Construct ampCacheRendezvous with no cache and no front domain", func() {
transport := &mockTransport{http.StatusOK, []byte{}} transport := &mockTransport{http.StatusOK, []byte{}}
rend, err := newAMPCacheRendezvous("http://test.broker", "", "", transport) rend, err := newAMPCacheRendezvous("http://test.broker", "", []string{}, transport)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(rend.brokerURL, ShouldNotBeNil) So(rend.brokerURL, ShouldNotBeNil)
So(rend.brokerURL.String(), ShouldResemble, "http://test.broker") So(rend.brokerURL.String(), ShouldResemble, "http://test.broker")
So(rend.cacheURL, ShouldBeNil) So(rend.cacheURL, ShouldBeNil)
So(rend.front, ShouldResemble, "") So(rend.fronts, ShouldResemble, []string{})
So(rend.transport, ShouldEqual, transport) So(rend.transport, ShouldEqual, transport)
}) })
Convey("Construct ampCacheRendezvous with cache and no front domain", func() { Convey("Construct ampCacheRendezvous with cache and no front domain", func() {
transport := &mockTransport{http.StatusOK, []byte{}} transport := &mockTransport{http.StatusOK, []byte{}}
rend, err := newAMPCacheRendezvous("http://test.broker", "https://amp.cache/", "", transport) rend, err := newAMPCacheRendezvous("http://test.broker", "https://amp.cache/", []string{}, transport)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(rend.brokerURL, ShouldNotBeNil) So(rend.brokerURL, ShouldNotBeNil)
So(rend.brokerURL.String(), ShouldResemble, "http://test.broker") So(rend.brokerURL.String(), ShouldResemble, "http://test.broker")
So(rend.cacheURL, ShouldNotBeNil) So(rend.cacheURL, ShouldNotBeNil)
So(rend.cacheURL.String(), ShouldResemble, "https://amp.cache/") So(rend.cacheURL.String(), ShouldResemble, "https://amp.cache/")
So(rend.front, ShouldResemble, "") So(rend.fronts, ShouldResemble, []string{})
So(rend.transport, ShouldEqual, transport) So(rend.transport, ShouldEqual, transport)
}) })
Convey("Construct ampCacheRendezvous with no cache and front domain", func() { Convey("Construct ampCacheRendezvous with no cache and front domain", func() {
transport := &mockTransport{http.StatusOK, []byte{}} transport := &mockTransport{http.StatusOK, []byte{}}
rend, err := newAMPCacheRendezvous("http://test.broker", "", "front", transport) rend, err := newAMPCacheRendezvous("http://test.broker", "", []string{"front"}, transport)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(rend.brokerURL, ShouldNotBeNil) So(rend.brokerURL, ShouldNotBeNil)
So(rend.brokerURL.String(), ShouldResemble, "http://test.broker") So(rend.brokerURL.String(), ShouldResemble, "http://test.broker")
So(rend.cacheURL, ShouldBeNil) So(rend.cacheURL, ShouldBeNil)
So(rend.front, ShouldResemble, "front") So(rend.fronts, ShouldContain, "front")
So(rend.transport, ShouldEqual, transport) So(rend.transport, ShouldEqual, transport)
}) })
Convey("Construct ampCacheRendezvous with cache and front domain", func() { Convey("Construct ampCacheRendezvous with cache and front domain", func() {
transport := &mockTransport{http.StatusOK, []byte{}} transport := &mockTransport{http.StatusOK, []byte{}}
rend, err := newAMPCacheRendezvous("http://test.broker", "https://amp.cache/", "front", transport) rend, err := newAMPCacheRendezvous("http://test.broker", "https://amp.cache/", []string{"front"}, transport)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(rend.brokerURL, ShouldNotBeNil) So(rend.brokerURL, ShouldNotBeNil)
So(rend.brokerURL.String(), ShouldResemble, "http://test.broker") So(rend.brokerURL.String(), ShouldResemble, "http://test.broker")
So(rend.cacheURL, ShouldNotBeNil) So(rend.cacheURL, ShouldNotBeNil)
So(rend.cacheURL.String(), ShouldResemble, "https://amp.cache/") So(rend.cacheURL.String(), ShouldResemble, "https://amp.cache/")
So(rend.front, ShouldResemble, "front") So(rend.fronts, ShouldContain, "front")
So(rend.transport, ShouldEqual, transport) So(rend.transport, ShouldEqual, transport)
}) })
@ -215,7 +215,7 @@ func TestAMPCacheRendezvous(t *testing.T) {
`{"answer": "{\"type\":\"answer\",\"sdp\":\"fake\"}" }`, `{"answer": "{\"type\":\"answer\",\"sdp\":\"fake\"}" }`,
"", "",
) )
rend, err := newAMPCacheRendezvous("http://test.broker", "", "", rend, err := newAMPCacheRendezvous("http://test.broker", "", []string{},
&mockTransport{http.StatusOK, ampArmorEncode(fakeEncPollResp)}) &mockTransport{http.StatusOK, ampArmorEncode(fakeEncPollResp)})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -228,7 +228,7 @@ func TestAMPCacheRendezvous(t *testing.T) {
"", "",
`{"error": "no snowflake proxies currently available"}`, `{"error": "no snowflake proxies currently available"}`,
) )
rend, err := newAMPCacheRendezvous("http://test.broker", "", "", rend, err := newAMPCacheRendezvous("http://test.broker", "", []string{},
&mockTransport{http.StatusOK, ampArmorEncode(fakeEncPollResp)}) &mockTransport{http.StatusOK, ampArmorEncode(fakeEncPollResp)})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -237,7 +237,7 @@ func TestAMPCacheRendezvous(t *testing.T) {
}) })
Convey("ampCacheRendezvous.Exchange fails with unexpected HTTP status code", func() { Convey("ampCacheRendezvous.Exchange fails with unexpected HTTP status code", func() {
rend, err := newAMPCacheRendezvous("http://test.broker", "", "", rend, err := newAMPCacheRendezvous("http://test.broker", "", []string{},
&mockTransport{http.StatusInternalServerError, []byte{}}) &mockTransport{http.StatusInternalServerError, []byte{}})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -248,7 +248,7 @@ func TestAMPCacheRendezvous(t *testing.T) {
Convey("ampCacheRendezvous.Exchange fails with error", func() { Convey("ampCacheRendezvous.Exchange fails with error", func() {
transportErr := errors.New("error") transportErr := errors.New("error")
rend, err := newAMPCacheRendezvous("http://test.broker", "", "", rend, err := newAMPCacheRendezvous("http://test.broker", "", []string{},
&errorTransport{err: transportErr}) &errorTransport{err: transportErr})
So(err, ShouldBeNil) So(err, ShouldBeNil)
answer, err := rend.Exchange(fakeEncPollReq) answer, err := rend.Exchange(fakeEncPollReq)
@ -261,7 +261,7 @@ func TestAMPCacheRendezvous(t *testing.T) {
// encoded bytes. Encode readLimit bytes—the encoded // encoded bytes. Encode readLimit bytes—the encoded
// size will be larger—and try to read the body. It // size will be larger—and try to read the body. It
// should fail. // should fail.
rend, err := newAMPCacheRendezvous("http://test.broker", "", "", rend, err := newAMPCacheRendezvous("http://test.broker", "", []string{},
&mockTransport{http.StatusOK, ampArmorEncode(make([]byte, readLimit))}) &mockTransport{http.StatusOK, ampArmorEncode(make([]byte, readLimit))})
So(err, ShouldBeNil) So(err, ShouldBeNil)
_, err = rend.Exchange(fakeEncPollReq) _, err = rend.Exchange(fakeEncPollReq)

View file

@ -85,11 +85,14 @@ type ClientConfig struct {
// AmpCacheURL is the full URL of a valid AMP cache. A nonzero value indicates // AmpCacheURL is the full URL of a valid AMP cache. A nonzero value indicates
// that AMP cache will be used as the rendezvous method with the broker. // that AMP cache will be used as the rendezvous method with the broker.
AmpCacheURL string AmpCacheURL string
// FrontDomain is a the full URL of an optional front domain that can be used with either // FrontDomain is the full URL of an optional front domain that can be used with either
// the AMP cache or HTTP domain fronting rendezvous method. // the AMP cache or HTTP domain fronting rendezvous method.
FrontDomain string FrontDomain string
// ICEAddresses are a slice of ICE server URLs that will be used for NAT traversal and // ICEAddresses are a slice of ICE server URLs that will be used for NAT traversal and
// the creation of the client's WebRTC SDP offer. // the creation of the client's WebRTC SDP offer.
FrontDomains []string
// ICEAddresses are a slice of ICE server URLs that will be used for NAT traversal and
// the creation of the client's WebRTC SDP offer.
ICEAddresses []string ICEAddresses []string
// KeepLocalAddresses is an optional setting that will prevent the removal of local or // KeepLocalAddresses is an optional setting that will prevent the removal of local or
// invalid addresses from the client's SDP offer. This is useful for local deployments // invalid addresses from the client's SDP offer. This is useful for local deployments
@ -134,6 +137,11 @@ func NewSnowflakeClient(config ClientConfig) (*Transport, error) {
log.Printf("url: %v", strings.Join(server.URLs, " ")) log.Printf("url: %v", strings.Join(server.URLs, " "))
} }
// Maintain backwards compatability with old FrontDomain field of ClientConfig
if (len(config.FrontDomains) == 0) && (config.FrontDomain != "") {
config.FrontDomains = []string{config.FrontDomain}
}
// Rendezvous with broker using the given parameters. // Rendezvous with broker using the given parameters.
broker, err := newBrokerChannelFromConfig(config) broker, err := newBrokerChannelFromConfig(config)
if err != nil { if err != nil {

View file

@ -81,7 +81,7 @@ func socksAcceptLoop(ln *pt.SocksListener, config sf.ClientConfig, shutdown chan
config.AmpCacheURL = arg config.AmpCacheURL = arg
} }
if arg, ok := conn.Req.Args.Get("front"); ok { if arg, ok := conn.Req.Args.Get("front"); ok {
config.FrontDomain = arg config.FrontDomains = strings.Split(strings.TrimSpace(arg), ",")
} }
if arg, ok := conn.Req.Args.Get("ice"); ok { if arg, ok := conn.Req.Args.Get("ice"); ok {
config.ICEAddresses = strings.Split(strings.TrimSpace(arg), ",") config.ICEAddresses = strings.Split(strings.TrimSpace(arg), ",")
@ -151,7 +151,7 @@ func socksAcceptLoop(ln *pt.SocksListener, config sf.ClientConfig, shutdown chan
func main() { func main() {
iceServersCommas := flag.String("ice", "", "comma-separated list of ICE servers") iceServersCommas := flag.String("ice", "", "comma-separated list of ICE servers")
brokerURL := flag.String("url", "", "URL of signaling broker") brokerURL := flag.String("url", "", "URL of signaling broker")
frontDomain := flag.String("front", "", "front domain") frontDomainsCommas := flag.String("front", "", "comma-separated list of front domains")
ampCacheURL := flag.String("ampcache", "", "URL of AMP cache to use as a proxy for signaling") ampCacheURL := flag.String("ampcache", "", "URL of AMP cache to use as a proxy for signaling")
logFilename := flag.String("log", "", "name of log file") logFilename := flag.String("log", "", "name of log file")
logToStateDir := flag.Bool("log-to-state-dir", false, "resolve the log file relative to tor's pt state dir") logToStateDir := flag.Bool("log-to-state-dir", false, "resolve the log file relative to tor's pt state dir")
@ -206,11 +206,12 @@ func main() {
log.Printf("snowflake-client %s\n", version.GetVersion()) log.Printf("snowflake-client %s\n", version.GetVersion())
iceAddresses := strings.Split(strings.TrimSpace(*iceServersCommas), ",") iceAddresses := strings.Split(strings.TrimSpace(*iceServersCommas), ",")
frontDomains := strings.Split(strings.TrimSpace(*frontDomainsCommas), ",")
config := sf.ClientConfig{ config := sf.ClientConfig{
BrokerURL: *brokerURL, BrokerURL: *brokerURL,
AmpCacheURL: *ampCacheURL, AmpCacheURL: *ampCacheURL,
FrontDomain: *frontDomain, FrontDomains: frontDomains,
ICEAddresses: iceAddresses, ICEAddresses: iceAddresses,
KeepLocalAddresses: *keepLocalAddresses || *oldKeepLocalAddresses, KeepLocalAddresses: *keepLocalAddresses || *oldKeepLocalAddresses,
Max: *max, Max: *max,

View file

@ -3,7 +3,7 @@ DataDirectory datadir
ClientTransportPlugin snowflake exec ./client -log snowflake.log ClientTransportPlugin snowflake exec ./client -log snowflake.log
Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=foursquare.com,github.githubassets.com ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn
Bridge snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=cdn.sstatic.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn Bridge snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://snowflake-broker.torproject.net.global.prod.fastly.net/ front=foursquare.com,github.githubassets.com ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn
SocksPort auto SocksPort auto