commit f6cf9a453b0cae189e5ad6b25d57241fe418de91
Author: Cecylia Bocovich <coh...@torproject.org>
Date:   Tue Jun 16 17:10:56 2020 -0400

    Implement NAT discover for go standalone proxies
---
 broker/broker.go              |  2 +-
 common/messages/proxy.go      | 30 +++++++++++++++++++-----------
 common/messages/proxy_test.go | 26 ++++++++++++++++++++++----
 proxy/snowflake.go            | 36 +++++++++++++++++++++++++++++++++++-
 4 files changed, 77 insertions(+), 17 deletions(-)

diff --git a/broker/broker.go b/broker/broker.go
index d9ef111..2d3cd4b 100644
--- a/broker/broker.go
+++ b/broker/broker.go
@@ -170,7 +170,7 @@ func proxyPolls(ctx *BrokerContext, w http.ResponseWriter, 
r *http.Request) {
                return
        }
 
-       sid, proxyType, err := messages.DecodePollRequest(body)
+       sid, proxyType, _, err := messages.DecodePollRequest(body)
        if err != nil {
                w.WriteHeader(http.StatusBadRequest)
                return
diff --git a/common/messages/proxy.go b/common/messages/proxy.go
index 89dd43c..923189b 100644
--- a/common/messages/proxy.go
+++ b/common/messages/proxy.go
@@ -9,15 +9,16 @@ import (
        "strings"
 )
 
-const version = "1.1"
+const version = "1.2"
 
-/* Version 1.1 specification:
+/* Version 1.2 specification:
 
 == ProxyPollRequest ==
 {
   Sid: [generated session id of proxy],
-  Version: 1.1,
+  Version: 1.2,
   Type: ["badge"|"webext"|"standalone"]
+  NAT: ["unknown"|"restricted"|"unrestricted"]
 }
 
 == ProxyPollResponse ==
@@ -44,7 +45,7 @@ HTTP 400 BadRequest
 == ProxyAnswerRequest ==
 {
   Sid: [generated session id of proxy],
-  Version: 1.1,
+  Version: 1.2,
   Answer:
   {
     type: answer,
@@ -76,37 +77,44 @@ type ProxyPollRequest struct {
        Sid     string
        Version string
        Type    string
+       NAT     string
 }
 
-func EncodePollRequest(sid string, proxyType string) ([]byte, error) {
+func EncodePollRequest(sid string, proxyType string, natType string) ([]byte, 
error) {
        return json.Marshal(ProxyPollRequest{
                Sid:     sid,
                Version: version,
                Type:    proxyType,
+               NAT:     natType,
        })
 }
 
 // Decodes a poll message from a snowflake proxy and returns the
 // sid and proxy type of the proxy on success and an error if it failed
-func DecodePollRequest(data []byte) (string, string, error) {
+func DecodePollRequest(data []byte) (string, string, string, error) {
        var message ProxyPollRequest
 
        err := json.Unmarshal(data, &message)
        if err != nil {
-               return "", "", err
+               return "", "", "", err
        }
 
        majorVersion := strings.Split(message.Version, ".")[0]
        if majorVersion != "1" {
-               return "", "", fmt.Errorf("using unknown version")
+               return "", "", "", fmt.Errorf("using unknown version")
        }
 
        // Version 1.x requires an Sid
        if message.Sid == "" {
-               return "", "", fmt.Errorf("no supplied session id")
+               return "", "", "", fmt.Errorf("no supplied session id")
        }
 
-       return message.Sid, message.Type, nil
+       natType := message.NAT
+       if natType == "" {
+               natType = "unknown"
+       }
+
+       return message.Sid, message.Type, natType, nil
 }
 
 type ProxyPollResponse struct {
@@ -159,7 +167,7 @@ type ProxyAnswerRequest struct {
 
 func EncodeAnswerRequest(answer string, sid string) ([]byte, error) {
        return json.Marshal(ProxyAnswerRequest{
-               Version: "1.1",
+               Version: version,
                Sid:     sid,
                Answer:  answer,
        })
diff --git a/common/messages/proxy_test.go b/common/messages/proxy_test.go
index 1570d4f..3aa67fb 100644
--- a/common/messages/proxy_test.go
+++ b/common/messages/proxy_test.go
@@ -13,6 +13,7 @@ func TestDecodeProxyPollRequest(t *testing.T) {
                for _, test := range []struct {
                        sid       string
                        proxyType string
+                       natType   string
                        data      string
                        err       error
                }{
@@ -20,6 +21,7 @@ func TestDecodeProxyPollRequest(t *testing.T) {
                                //Version 1.0 proxy message
                                "ymbcCMto7KHNGYlp",
                                "",
+                               "unknown",
                                `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.0"}`,
                                nil,
                        },
@@ -27,44 +29,59 @@ func TestDecodeProxyPollRequest(t *testing.T) {
                                //Version 1.1 proxy message
                                "ymbcCMto7KHNGYlp",
                                "standalone",
+                               "unknown",
                                
`{"Sid":"ymbcCMto7KHNGYlp","Version":"1.1","Type":"standalone"}`,
                                nil,
                        },
+                       {
+                               //Version 1.2 proxy message
+                               "ymbcCMto7KHNGYlp",
+                               "standalone",
+                               "restricted",
+                               
`{"Sid":"ymbcCMto7KHNGYlp","Version":"1.2","Type":"standalone", 
"NAT":"restricted"}`,
+                               nil,
+                       },
                        {
                                //Version 0.X proxy message:
                                "",
                                "",
-                               "ymbcCMto7KHNGYlp",
+                               "",
+                               "",
                                &json.SyntaxError{},
                        },
                        {
+                               "",
                                "",
                                "",
                                `{"Sid":"ymbcCMto7KHNGYlp"}`,
                                fmt.Errorf(""),
                        },
                        {
+                               "",
                                "",
                                "",
                                "{}",
                                fmt.Errorf(""),
                        },
                        {
+                               "",
                                "",
                                "",
                                `{"Version":"1.0"}`,
                                fmt.Errorf(""),
                        },
                        {
+                               "",
                                "",
                                "",
                                `{"Version":"2.0"}`,
                                fmt.Errorf(""),
                        },
                } {
-                       sid, proxyType, err := 
DecodePollRequest([]byte(test.data))
+                       sid, proxyType, natType, err := 
DecodePollRequest([]byte(test.data))
                        So(sid, ShouldResemble, test.sid)
                        So(proxyType, ShouldResemble, test.proxyType)
+                       So(natType, ShouldResemble, test.natType)
                        So(err, ShouldHaveSameTypeAs, test.err)
                }
 
@@ -73,11 +90,12 @@ func TestDecodeProxyPollRequest(t *testing.T) {
 
 func TestEncodeProxyPollRequests(t *testing.T) {
        Convey("Context", t, func() {
-               b, err := EncodePollRequest("ymbcCMto7KHNGYlp", "standalone")
+               b, err := EncodePollRequest("ymbcCMto7KHNGYlp", "standalone", 
"unknown")
                So(err, ShouldEqual, nil)
-               sid, proxyType, err := DecodePollRequest(b)
+               sid, proxyType, natType, err := DecodePollRequest(b)
                So(sid, ShouldEqual, "ymbcCMto7KHNGYlp")
                So(proxyType, ShouldEqual, "standalone")
+               So(natType, ShouldEqual, "unknown")
                So(err, ShouldEqual, nil)
        })
 }
diff --git a/proxy/snowflake.go b/proxy/snowflake.go
index 4877e6f..ac67748 100644
--- a/proxy/snowflake.go
+++ b/proxy/snowflake.go
@@ -19,6 +19,7 @@ import (
        "time"
 
        "git.torproject.org/pluggable-transports/snowflake.git/common/messages"
+       "git.torproject.org/pluggable-transports/snowflake.git/common/nat"
        "git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
        "git.torproject.org/pluggable-transports/snowflake.git/common/util"
        
"git.torproject.org/pluggable-transports/snowflake.git/common/websocketconn"
@@ -30,6 +31,11 @@ const defaultBrokerURL = 
"https://snowflake-broker.bamsoftware.com/";
 const defaultRelayURL = "wss://snowflake.bamsoftware.com/"
 const defaultSTUNURL = "stun:stun.l.google.com:19302"
 const pollInterval = 5 * time.Second
+const (
+       NATUnknown      = "unknown"
+       NATRestricted   = "restricted"
+       NATUnrestricted = "unrestricted"
+)
 
 //amount of time after sending an SDP answer before the proxy assumes the
 //client is not going to connect
@@ -40,6 +46,8 @@ const readLimit = 100000 //Maximum number of bytes to be read 
from an HTTP reque
 var broker *Broker
 var relayURL string
 
+var currentNATType = NATUnknown
+
 const (
        sessionIDLength = 16
 )
@@ -174,7 +182,7 @@ func (b *Broker) pollOffer(sid string) 
*webrtc.SessionDescription {
                        timeOfNextPoll = now
                }
 
-               body, err := messages.EncodePollRequest(sid, "standalone")
+               body, err := messages.EncodePollRequest(sid, "standalone", 
currentNATType)
                if err != nil {
                        log.Printf("Error encoding poll message: %s", 
err.Error())
                        return nil
@@ -485,9 +493,35 @@ func main() {
                tokens <- true
        }
 
+       // determine NAT type before polling
+       updateNATType(config.ICEServers)
+       log.Printf("NAT type: %s", currentNATType)
+
        for {
                getToken()
                sessionID := genSessionID()
                runSession(sessionID)
        }
 }
+
+// use provided STUN server(s) to determine NAT type
+func updateNATType(servers []webrtc.ICEServer) {
+
+       var restrictedNAT bool
+       var err error
+       for _, server := range servers {
+               addr := strings.TrimPrefix(server.URLs[0], "stun:")
+               restrictedNAT, err = nat.CheckIfRestrictedNAT(addr)
+               if err == nil {
+                       if restrictedNAT {
+                               currentNATType = NATRestricted
+                       } else {
+                               currentNATType = NATUnrestricted
+                       }
+                       break
+               }
+       }
+       if err != nil {
+               currentNATType = NATUnknown
+       }
+}



_______________________________________________
tor-commits mailing list
tor-commits@lists.torproject.org
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to