This is an automated email from the git hooks/post-receive script.
shelikhoo pushed a commit to branch main in repository pluggable-transports/snowflake.
commit f789dce6d2b5e6e7d02eef6b168c31ed2ddd149e Author: Shelikhoo xiaokangwang@outlook.com AuthorDate: Tue May 17 15:53:15 2022 +0100
Represent Bridge Fingerprint As String --- broker/bridge-list.go | 22 +++++++++++----------- broker/bridge-list_test.go | 9 +++++++-- broker/broker.go | 5 +++-- broker/ipc.go | 17 ++++++++++++++--- broker/snowflake-broker_test.go | 2 +- common/bridgefingerprint/fingerprint.go | 30 ++++++++++++++++++++++++++++++ common/messages/client.go | 5 +++-- 7 files changed, 69 insertions(+), 21 deletions(-)
diff --git a/broker/bridge-list.go b/broker/bridge-list.go index e77db65..ca2c041 100644 --- a/broker/bridge-list.go +++ b/broker/bridge-list.go @@ -2,27 +2,26 @@ package main
import ( "bufio" - "encoding/hex" "encoding/json" "errors" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" "io" "sync" )
var ErrBridgeNotFound = errors.New("bridge not found") -var ErrBridgeFingerprintInvalid = errors.New("bridge fingerprint invalid")
func NewBridgeListHolder() BridgeListHolderFileBased { return &bridgeListHolder{} }
type bridgeListHolder struct { - bridgeInfo map[[20]byte]BridgeInfo + bridgeInfo map[bridgefingerprint.Fingerprint]BridgeInfo accessBridgeInfo sync.RWMutex }
type BridgeListHolder interface { - GetBridgeInfo(fingerprint [20]byte) (BridgeInfo, error) + GetBridgeInfo(bridgefingerprint.Fingerprint) (BridgeInfo, error) }
type BridgeListHolderFileBased interface { @@ -36,7 +35,7 @@ type BridgeInfo struct { Fingerprint string `json:"fingerprint"` }
-func (h *bridgeListHolder) GetBridgeInfo(fingerprint [20]byte) (BridgeInfo, error) { +func (h *bridgeListHolder) GetBridgeInfo(fingerprint bridgefingerprint.Fingerprint) (BridgeInfo, error) { h.accessBridgeInfo.RLock() defer h.accessBridgeInfo.RUnlock() if bridgeInfo, ok := h.bridgeInfo[fingerprint]; ok { @@ -46,7 +45,7 @@ func (h *bridgeListHolder) GetBridgeInfo(fingerprint [20]byte) (BridgeInfo, erro }
func (h *bridgeListHolder) LoadBridgeInfo(reader io.Reader) error { - bridgeInfoMap := map[[20]byte]BridgeInfo{} + bridgeInfoMap := map[bridgefingerprint.Fingerprint]BridgeInfo{} inputScanner := bufio.NewScanner(reader) for inputScanner.Scan() { inputLine := inputScanner.Bytes() @@ -54,13 +53,14 @@ func (h *bridgeListHolder) LoadBridgeInfo(reader io.Reader) error { if err := json.Unmarshal(inputLine, &bridgeInfo); err != nil { return err } - var bridgeHash [20]byte - if n, err := hex.Decode(bridgeHash[:], []byte(bridgeInfo.Fingerprint)); err != nil { + + var bridgeFingerprint bridgefingerprint.Fingerprint + var err error + if bridgeFingerprint, err = bridgefingerprint.FingerprintFromHexString(bridgeInfo.Fingerprint); err != nil { return err - } else if n != 20 { - return ErrBridgeFingerprintInvalid } - bridgeInfoMap[bridgeHash] = bridgeInfo + + bridgeInfoMap[bridgeFingerprint] = bridgeInfo } h.accessBridgeInfo.Lock() defer h.accessBridgeInfo.Unlock() diff --git a/broker/bridge-list_test.go b/broker/bridge-list_test.go index 73da43c..4b53821 100644 --- a/broker/bridge-list_test.go +++ b/broker/bridge-list_test.go @@ -3,6 +3,7 @@ package main import ( "bytes" "encoding/hex" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" . "github.com/smartystreets/goconvey/convey" "testing" ) @@ -34,7 +35,9 @@ func TestBridgeLoad(t *testing.T) { So(n, ShouldEqual, 20) So(err, ShouldBeNil) } - bridgeInfo, err := bridgeList.GetBridgeInfo(bridgeFingerprint) + Fingerprint, err := bridgefingerprint.FingerprintFromBytes(bridgeFingerprint[:]) + So(err, ShouldBeNil) + bridgeInfo, err := bridgeList.GetBridgeInfo(Fingerprint) So(err, ShouldBeNil) So(bridgeInfo.DisplayName, ShouldEqual, "default") So(bridgeInfo.WebSocketAddress, ShouldEqual, "wss://snowflake.torproject.org") @@ -50,7 +53,9 @@ func TestBridgeLoad(t *testing.T) { So(n, ShouldEqual, 20) So(err, ShouldBeNil) } - bridgeInfo, err := bridgeList.GetBridgeInfo(bridgeFingerprint) + Fingerprint, err := bridgefingerprint.FingerprintFromBytes(bridgeFingerprint[:]) + So(err, ShouldBeNil) + bridgeInfo, err := bridgeList.GetBridgeInfo(Fingerprint) So(err, ShouldBeNil) So(bridgeInfo.DisplayName, ShouldEqual, "imaginary-8") So(bridgeInfo.WebSocketAddress, ShouldEqual, "wss://imaginary-8-snowflake.torproject.org") diff --git a/broker/broker.go b/broker/broker.go index 8ca0120..9162370 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -10,6 +10,7 @@ import ( "container/heap" "crypto/tls" "flag" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" "io" "log" "net/http" @@ -44,7 +45,7 @@ type BrokerContext struct { presumedPatternForLegacyClient string }
-func (ctx *BrokerContext) GetBridgeInfo(fingerprint [20]byte) (BridgeInfo, error) { +func (ctx *BrokerContext) GetBridgeInfo(fingerprint bridgefingerprint.Fingerprint) (BridgeInfo, error) { return ctx.bridgeList.GetBridgeInfo(fingerprint) }
@@ -178,7 +179,7 @@ func (ctx *BrokerContext) CheckProxyRelayPattern(pattern string, nonSupported bo type ClientOffer struct { natType string sdp []byte - fingerprint [20]byte + fingerprint []byte }
func main() { diff --git a/broker/ipc.go b/broker/ipc.go index c86d1a7..f5d4747 100644 --- a/broker/ipc.go +++ b/broker/ipc.go @@ -4,6 +4,7 @@ import ( "container/heap" "encoding/hex" "fmt" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" "log" "net" "time" @@ -130,7 +131,11 @@ func (i *IPC) ProxyPolls(arg messages.Arg, response *[]byte) error {
i.ctx.metrics.promMetrics.ProxyPollTotal.With(prometheus.Labels{"nat": natType, "status": "matched"}).Inc() var relayURL string - if info, err := i.ctx.bridgeList.GetBridgeInfo(offer.fingerprint); err != nil { + bridgeFingerprint, err := bridgefingerprint.FingerprintFromBytes(offer.fingerprint) + if err != nil { + return messages.ErrBadRequest + } + if info, err := i.ctx.bridgeList.GetBridgeInfo(bridgeFingerprint); err != nil { return err } else { relayURL = info.WebSocketAddress @@ -172,12 +177,18 @@ func (i *IPC) ClientOffers(arg messages.Arg, response *[]byte) error { if err != nil { return sendClientResponse(&messages.ClientPollResponse{Error: err.Error()}, response) } - copy(offer.fingerprint[:], fingerprint)
- if _, err := i.ctx.GetBridgeInfo(offer.fingerprint); err != nil { + BridgeFingerprint, err := bridgefingerprint.FingerprintFromBytes(fingerprint) + if err != nil { + return sendClientResponse(&messages.ClientPollResponse{Error: err.Error()}, response) + } + + if _, err := i.ctx.GetBridgeInfo(BridgeFingerprint); err != nil { return err }
+ offer.fingerprint = BridgeFingerprint.ToBytes() + // Only hand out known restricted snowflakes to unrestricted clients var snowflakeHeap *SnowflakeHeap if offer.natType == NATUnrestricted { diff --git a/broker/snowflake-broker_test.go b/broker/snowflake-broker_test.go index aee8578..a72f3ac 100644 --- a/broker/snowflake-broker_test.go +++ b/broker/snowflake-broker_test.go @@ -258,7 +258,7 @@ func TestBroker(t *testing.T) { // Pass a fake client offer to this proxy p := <-ctx.proxyPolls So(p.id, ShouldEqual, "ymbcCMto7KHNGYlp") - p.offerChannel <- &ClientOffer{sdp: []byte("fake offer"), fingerprint: defaultBridge} + p.offerChannel <- &ClientOffer{sdp: []byte("fake offer"), fingerprint: defaultBridge[:]} <-done So(w.Code, ShouldEqual, http.StatusOK) So(w.Body.String(), ShouldEqual, `{"Status":"client match","Offer":"fake offer","NAT":"","RelayURL":"wss://snowflake.torproject.net/"}`) diff --git a/common/bridgefingerprint/fingerprint.go b/common/bridgefingerprint/fingerprint.go new file mode 100644 index 0000000..1a89773 --- /dev/null +++ b/common/bridgefingerprint/fingerprint.go @@ -0,0 +1,30 @@ +package bridgefingerprint + +import ( + "encoding/hex" + "errors" +) + +type Fingerprint string + +var ErrBridgeFingerprintInvalid = errors.New("bridge fingerprint invalid") + +func FingerprintFromBytes(bytes []byte) (Fingerprint, error) { + n := len(bytes) + if n != 20 && n != 32 { + return Fingerprint(""), ErrBridgeFingerprintInvalid + } + return Fingerprint(bytes), nil +} + +func FingerprintFromHexString(hexString string) (Fingerprint, error) { + decoded, err := hex.DecodeString(hexString) + if err != nil { + return "", err + } + return FingerprintFromBytes(decoded) +} + +func (f Fingerprint) ToBytes() []byte { + return []byte(f) +} diff --git a/common/messages/client.go b/common/messages/client.go index 96f8ed8..af63e08 100644 --- a/common/messages/client.go +++ b/common/messages/client.go @@ -5,9 +5,9 @@ package messages
import ( "bytes" - "encoding/hex" "encoding/json" "fmt" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint"
"git.torproject.org/pluggable-transports/snowflake.git/v2/common/nat" ) @@ -106,7 +106,8 @@ func DecodeClientPollRequest(data []byte) (*ClientPollRequest, error) { if message.Fingerprint == "" { message.Fingerprint = defaultBridgeFingerprint } - if hex.DecodedLen(len(message.Fingerprint)) != 20 { + + if _, err := bridgefingerprint.FingerprintFromHexString(message.Fingerprint); err != nil { return nil, fmt.Errorf("cannot decode fingerprint") }