diff -Nru snowflake-2.2.0/broker/bridge-list.go snowflake-2.3.1/broker/bridge-list.go --- snowflake-2.2.0/broker/bridge-list.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/broker/bridge-list.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,94 @@ +/* (*BridgeListHolderFileBased).LoadBridgeInfo loads a Snowflake Server bridge info description file, + its format is as follows: + + This file should be in newline-delimited JSON format(https://jsonlines.org/). + For each line, the format of json data should be in the format of: + {"displayName":"default", "webSocketAddress":"wss://snowflake.torproject.net/", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80A72"} + + displayName:string is the name of this bridge. This value is not currently used programmatically. + + webSocketAddress:string is the WebSocket URL of this bridge. + This will be the address proxy used to connect to this snowflake server. + + fingerprint:string is the identifier of the bridge. + This will be used by a client to identify the bridge it wishes to connect to. + + The existence of ANY other fields is NOT permitted. + + The file will be considered invalid if there is at least one invalid json record. + In this case, an error will be returned, and none of the records will be loaded. +*/ + +package main + +import ( + "bufio" + "bytes" + "encoding/json" + "errors" + "io" + "sync" + + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" +) + +var ErrBridgeNotFound = errors.New("bridge not found") + +func NewBridgeListHolder() BridgeListHolderFileBased { + return &bridgeListHolder{} +} + +type bridgeListHolder struct { + bridgeInfo map[bridgefingerprint.Fingerprint]BridgeInfo + accessBridgeInfo sync.RWMutex +} + +type BridgeListHolder interface { + GetBridgeInfo(bridgefingerprint.Fingerprint) (BridgeInfo, error) +} + +type BridgeListHolderFileBased interface { + BridgeListHolder + LoadBridgeInfo(reader io.Reader) error +} + +type BridgeInfo struct { + DisplayName string `json:"displayName"` + WebSocketAddress string `json:"webSocketAddress"` + Fingerprint string `json:"fingerprint"` +} + +func (h *bridgeListHolder) GetBridgeInfo(fingerprint bridgefingerprint.Fingerprint) (BridgeInfo, error) { + h.accessBridgeInfo.RLock() + defer h.accessBridgeInfo.RUnlock() + if bridgeInfo, ok := h.bridgeInfo[fingerprint]; ok { + return bridgeInfo, nil + } + return BridgeInfo{}, ErrBridgeNotFound +} + +func (h *bridgeListHolder) LoadBridgeInfo(reader io.Reader) error { + bridgeInfoMap := map[bridgefingerprint.Fingerprint]BridgeInfo{} + inputScanner := bufio.NewScanner(reader) + for inputScanner.Scan() { + inputLine := inputScanner.Bytes() + bridgeInfo := BridgeInfo{} + decoder := json.NewDecoder(bytes.NewReader(inputLine)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&bridgeInfo); err != nil { + return err + } + + var bridgeFingerprint bridgefingerprint.Fingerprint + var err error + if bridgeFingerprint, err = bridgefingerprint.FingerprintFromHexString(bridgeInfo.Fingerprint); err != nil { + return err + } + + bridgeInfoMap[bridgeFingerprint] = bridgeInfo + } + h.accessBridgeInfo.Lock() + defer h.accessBridgeInfo.Unlock() + h.bridgeInfo = bridgeInfoMap + return nil +} diff -Nru snowflake-2.2.0/broker/bridge-list_test.go snowflake-2.3.1/broker/bridge-list_test.go --- snowflake-2.2.0/broker/bridge-list_test.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/broker/bridge-list_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,64 @@ +package main + +import ( + "bytes" + "encoding/hex" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" + . "github.com/smartystreets/goconvey/convey" + "testing" +) + +const DefaultBridges = `{"displayName":"default", "webSocketAddress":"wss://snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80A72"} +` + +const ImaginaryBridges = `{"displayName":"default", "webSocketAddress":"wss://snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80A72"} +{"displayName":"imaginary-1", "webSocketAddress":"wss://imaginary-1-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B00"} +{"displayName":"imaginary-2", "webSocketAddress":"wss://imaginary-2-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B01"} +{"displayName":"imaginary-3", "webSocketAddress":"wss://imaginary-3-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B02"} +{"displayName":"imaginary-4", "webSocketAddress":"wss://imaginary-4-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B03"} +{"displayName":"imaginary-5", "webSocketAddress":"wss://imaginary-5-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B04"} +{"displayName":"imaginary-6", "webSocketAddress":"wss://imaginary-6-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B05"} +{"displayName":"imaginary-7", "webSocketAddress":"wss://imaginary-7-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B06"} +{"displayName":"imaginary-8", "webSocketAddress":"wss://imaginary-8-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B07"} +{"displayName":"imaginary-9", "webSocketAddress":"wss://imaginary-9-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B08"} +{"displayName":"imaginary-10", "webSocketAddress":"wss://imaginary-10-snowflake.torproject.org", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80B09"} +` + +func TestBridgeLoad(t *testing.T) { + Convey("load default list", t, func() { + bridgeList := NewBridgeListHolder() + So(bridgeList.LoadBridgeInfo(bytes.NewReader([]byte(DefaultBridges))), ShouldBeNil) + { + bridgeFingerprint := [20]byte{} + { + n, err := hex.Decode(bridgeFingerprint[:], []byte("2B280B23E1107BB62ABFC40DDCC8824814F80A72")) + So(n, ShouldEqual, 20) + So(err, ShouldBeNil) + } + 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") + } + }) + Convey("load imaginary list", t, func() { + bridgeList := NewBridgeListHolder() + So(bridgeList.LoadBridgeInfo(bytes.NewReader([]byte(ImaginaryBridges))), ShouldBeNil) + { + bridgeFingerprint := [20]byte{} + { + n, err := hex.Decode(bridgeFingerprint[:], []byte("2B280B23E1107BB62ABFC40DDCC8824814F80B07")) + So(n, ShouldEqual, 20) + So(err, ShouldBeNil) + } + 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 -Nru snowflake-2.2.0/broker/broker.go snowflake-2.3.1/broker/broker.go --- snowflake-2.2.0/broker/broker.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/broker/broker.go 2022-09-23 12:08:13.000000000 +0000 @@ -6,9 +6,13 @@ package main import ( + "bytes" "container/heap" "crypto/tls" "flag" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/ipsetsink" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/ipsetsink/sinkcluster" "io" "log" "net/http" @@ -19,6 +23,7 @@ "syscall" "time" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/namematcher" "git.torproject.org/pluggable-transports/snowflake.git/v2/common/safelog" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -36,6 +41,14 @@ snowflakeLock sync.Mutex proxyPolls chan *ProxyPoll metrics *Metrics + + bridgeList BridgeListHolderFileBased + allowedRelayPattern string + presumedPatternForLegacyClient string +} + +func (ctx *BrokerContext) GetBridgeInfo(fingerprint bridgefingerprint.Fingerprint) (BridgeInfo, error) { + return ctx.bridgeList.GetBridgeInfo(fingerprint) } func NewBrokerContext(metricsLogger *log.Logger) *BrokerContext { @@ -53,12 +66,19 @@ panic("Failed to create metrics") } + bridgeListHolder := NewBridgeListHolder() + + const DefaultBridges = `{"displayName":"default", "webSocketAddress":"wss://snowflake.torproject.net/", "fingerprint":"2B280B23E1107BB62ABFC40DDCC8824814F80A72"} +` + bridgeListHolder.LoadBridgeInfo(bytes.NewReader([]byte(DefaultBridges))) + return &BrokerContext{ snowflakes: snowflakes, restrictedSnowflakes: rSnowflakes, idToSnowflake: make(map[string]*Snowflake), proxyPolls: make(chan *ProxyPoll), metrics: metrics, + bridgeList: bridgeListHolder, } } @@ -134,16 +154,34 @@ heap.Push(ctx.restrictedSnowflakes, snowflake) } ctx.metrics.promMetrics.AvailableProxies.With(prometheus.Labels{"nat": natType, "type": proxyType}).Inc() - ctx.snowflakeLock.Unlock() ctx.idToSnowflake[id] = snowflake + ctx.snowflakeLock.Unlock() return snowflake } +func (ctx *BrokerContext) InstallBridgeListProfile(reader io.Reader, relayPattern, presumedPatternForLegacyClient string) error { + if err := ctx.bridgeList.LoadBridgeInfo(reader); err != nil { + return err + } + ctx.allowedRelayPattern = relayPattern + ctx.presumedPatternForLegacyClient = presumedPatternForLegacyClient + return nil +} + +func (ctx *BrokerContext) CheckProxyRelayPattern(pattern string, nonSupported bool) bool { + if nonSupported { + pattern = ctx.presumedPatternForLegacyClient + } + proxyPattern := namematcher.NewNameMatcher(pattern) + brokerPattern := namematcher.NewNameMatcher(ctx.allowedRelayPattern) + return proxyPattern.IsSupersetOf(brokerPattern) +} + // Client offer contains an SDP, bridge fingerprint and the NAT type of the client type ClientOffer struct { natType string sdp []byte - fingerprint [20]byte + fingerprint []byte } func main() { @@ -153,10 +191,13 @@ var addr string var geoipDatabase string var geoip6Database string + var bridgeListFilePath, allowedRelayPattern, presumedPatternForLegacyClient string var disableTLS bool var certFilename, keyFilename string var disableGeoip bool var metricsFilename string + var ipCountFilename, ipCountMaskingKey string + var ipCountInterval time.Duration var unsafeLogging bool flag.StringVar(&acmeEmail, "acme-email", "", "optional contact email for Let's Encrypt notifications") @@ -167,9 +208,15 @@ flag.StringVar(&addr, "addr", ":443", "address to listen on") flag.StringVar(&geoipDatabase, "geoipdb", "/usr/share/tor/geoip", "path to correctly formatted geoip database mapping IPv4 address ranges to country codes") flag.StringVar(&geoip6Database, "geoip6db", "/usr/share/tor/geoip6", "path to correctly formatted geoip database mapping IPv6 address ranges to country codes") + flag.StringVar(&bridgeListFilePath, "bridge-list-path", "", "file path for bridgeListFile") + flag.StringVar(&allowedRelayPattern, "allowed-relay-pattern", "", "allowed pattern for relay host name") + flag.StringVar(&presumedPatternForLegacyClient, "default-relay-pattern", "", "presumed pattern for legacy client") flag.BoolVar(&disableTLS, "disable-tls", false, "don't use HTTPS") flag.BoolVar(&disableGeoip, "disable-geoip", false, "don't use geoip for stats collection") flag.StringVar(&metricsFilename, "metrics-log", "", "path to metrics logging output") + flag.StringVar(&ipCountFilename, "ip-count-log", "", "path to ip count logging output") + flag.StringVar(&ipCountMaskingKey, "ip-count-mask", "", "masking key for ip count logging") + flag.DurationVar(&ipCountInterval, "ip-count-interval", time.Hour, "time interval between each chunk") flag.BoolVar(&unsafeLogging, "unsafe-logging", false, "prevent logs from being scrubbed") flag.Parse() @@ -199,6 +246,17 @@ ctx := NewBrokerContext(metricsLogger) + if bridgeListFilePath != "" { + bridgeListFile, err := os.Open(bridgeListFilePath) + if err != nil { + log.Fatal(err.Error()) + } + err = ctx.InstallBridgeListProfile(bridgeListFile, allowedRelayPattern, presumedPatternForLegacyClient) + if err != nil { + log.Fatal(err.Error()) + } + } + if !disableGeoip { err = ctx.metrics.LoadGeoipDatabases(geoipDatabase, geoip6Database) if err != nil { @@ -206,6 +264,16 @@ } } + if ipCountFilename != "" { + ipCountFile, err := os.OpenFile(ipCountFilename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + + if err != nil { + log.Fatal(err.Error()) + } + ipSetSink := ipsetsink.NewIPSetSink(ipCountMaskingKey) + ctx.metrics.distinctIPWriter = sinkcluster.NewClusterWriter(ipCountFile, ipCountInterval, ipSetSink) + } + go ctx.Broker() i := &IPC{ctx} diff -Nru snowflake-2.2.0/broker/http.go snowflake-2.3.1/broker/http.go --- snowflake-2.2.0/broker/http.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/broker/http.go 2022-09-23 12:08:13.000000000 +0000 @@ -94,7 +94,7 @@ func proxyPolls(i *IPC, w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit)) if err != nil { - log.Println("Invalid data.") + log.Println("Invalid data.", err.Error()) w.WriteHeader(http.StatusBadRequest) return } @@ -204,7 +204,7 @@ func proxyAnswers(i *IPC, w http.ResponseWriter, r *http.Request) { body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit)) if err != nil { - log.Println("Invalid data.") + log.Println("Invalid data.", err.Error()) w.WriteHeader(http.StatusBadRequest) return } diff -Nru snowflake-2.2.0/broker/ipc.go snowflake-2.3.1/broker/ipc.go --- snowflake-2.2.0/broker/ipc.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/broker/ipc.go 2022-09-23 12:08:13.000000000 +0000 @@ -4,6 +4,7 @@ "container/heap" "encoding/hex" "fmt" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/bridgefingerprint" "log" "net" "time" @@ -66,11 +67,38 @@ } func (i *IPC) ProxyPolls(arg messages.Arg, response *[]byte) error { - sid, proxyType, natType, clients, err := messages.DecodeProxyPollRequest(arg.Body) + sid, proxyType, natType, clients, relayPattern, relayPatternSupported, err := messages.DecodeProxyPollRequestWithRelayPrefix(arg.Body) if err != nil { return messages.ErrBadRequest } + if !relayPatternSupported { + i.ctx.metrics.lock.Lock() + i.ctx.metrics.proxyPollWithoutRelayURLExtension++ + i.ctx.metrics.promMetrics.ProxyPollWithoutRelayURLExtensionTotal.With(prometheus.Labels{"nat": natType, "type": proxyType}).Inc() + i.ctx.metrics.lock.Unlock() + } else { + i.ctx.metrics.lock.Lock() + i.ctx.metrics.proxyPollWithRelayURLExtension++ + i.ctx.metrics.promMetrics.ProxyPollWithRelayURLExtensionTotal.With(prometheus.Labels{"nat": natType, "type": proxyType}).Inc() + i.ctx.metrics.lock.Unlock() + } + + if !i.ctx.CheckProxyRelayPattern(relayPattern, !relayPatternSupported) { + i.ctx.metrics.lock.Lock() + i.ctx.metrics.proxyPollRejectedWithRelayURLExtension++ + i.ctx.metrics.promMetrics.ProxyPollRejectedForRelayURLExtensionTotal.With(prometheus.Labels{"nat": natType, "type": proxyType}).Inc() + i.ctx.metrics.lock.Unlock() + + log.Printf("bad request: rejected relay pattern from proxy = %v", messages.ErrBadRequest) + b, err := messages.EncodePollResponseWithRelayURL("", false, "", "", "incorrect relay pattern") + *response = b + if err != nil { + return messages.ErrInternal + } + return nil + } + // Log geoip stats remoteIP, _, err := net.SplitHostPort(arg.RemoteAddr) if err != nil { @@ -78,6 +106,7 @@ } else { i.ctx.metrics.lock.Lock() i.ctx.metrics.UpdateCountryStats(remoteIP, proxyType, natType) + i.ctx.metrics.RecordIPAddress(remoteIP) i.ctx.metrics.lock.Unlock() } @@ -102,7 +131,17 @@ } i.ctx.metrics.promMetrics.ProxyPollTotal.With(prometheus.Labels{"nat": natType, "status": "matched"}).Inc() - b, err = messages.EncodePollResponse(string(offer.sdp), true, offer.natType) + var relayURL string + 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 + } + b, err = messages.EncodePollResponseWithRelayURL(string(offer.sdp), true, offer.natType, relayURL, "") if err != nil { return messages.ErrInternal } @@ -139,21 +178,22 @@ if err != nil { return sendClientResponse(&messages.ClientPollResponse{Error: err.Error()}, response) } - copy(offer.fingerprint[:], fingerprint) - // Only hand out known restricted snowflakes to unrestricted clients - var snowflakeHeap *SnowflakeHeap - if offer.natType == NATUnrestricted { - snowflakeHeap = i.ctx.restrictedSnowflakes - } else { - snowflakeHeap = i.ctx.snowflakes + BridgeFingerprint, err := bridgefingerprint.FingerprintFromBytes(fingerprint) + if err != nil { + return sendClientResponse(&messages.ClientPollResponse{Error: err.Error()}, response) } - // Immediately fail if there are no snowflakes available. - i.ctx.snowflakeLock.Lock() - numSnowflakes := snowflakeHeap.Len() - i.ctx.snowflakeLock.Unlock() - if numSnowflakes <= 0 { + if _, err := i.ctx.GetBridgeInfo(BridgeFingerprint); err != nil { + return err + } + + offer.fingerprint = BridgeFingerprint.ToBytes() + + snowflake := i.matchSnowflake(offer.natType) + if snowflake != nil { + snowflake.offerChannel <- offer + } else { i.ctx.metrics.lock.Lock() i.ctx.metrics.clientDeniedCount++ i.ctx.metrics.promMetrics.ClientPollTotal.With(prometheus.Labels{"nat": offer.natType, "status": "denied"}).Inc() @@ -167,13 +207,6 @@ return sendClientResponse(resp, response) } - // Otherwise, find the most available snowflake proxy, and pass the offer to it. - // Delete must be deferred in order to correctly process answer request later. - i.ctx.snowflakeLock.Lock() - snowflake := heap.Pop(snowflakeHeap).(*Snowflake) - i.ctx.snowflakeLock.Unlock() - snowflake.offerChannel <- offer - // Wait for the answer to be returned on the channel or timeout. select { case answer := <-snowflake.answerChannel: @@ -199,6 +232,25 @@ return err } +func (i *IPC) matchSnowflake(natType string) *Snowflake { + // Only hand out known restricted snowflakes to unrestricted clients + var snowflakeHeap *SnowflakeHeap + if natType == NATUnrestricted { + snowflakeHeap = i.ctx.restrictedSnowflakes + } else { + snowflakeHeap = i.ctx.snowflakes + } + + i.ctx.snowflakeLock.Lock() + defer i.ctx.snowflakeLock.Unlock() + + if snowflakeHeap.Len() > 0 { + return heap.Pop(snowflakeHeap).(*Snowflake) + } else { + return nil + } +} + func (i *IPC) ProxyAnswers(arg messages.Arg, response *[]byte) error { answer, id, err := messages.DecodeAnswerRequest(arg.Body) if err != nil || answer == "" { diff -Nru snowflake-2.2.0/broker/metrics.go snowflake-2.3.1/broker/metrics.go --- snowflake-2.2.0/broker/metrics.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/broker/metrics.go 2022-09-23 12:08:13.000000000 +0000 @@ -14,6 +14,7 @@ "sync" "time" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/ipsetsink/sinkcluster" "git.torproject.org/pluggable-transports/snowflake.git/v2/common/messages" "github.com/prometheus/client_golang/prometheus" "gitlab.torproject.org/tpo/anti-censorship/geoip" @@ -41,6 +42,8 @@ logger *log.Logger geoipdb *geoip.Geoip + distinctIPWriter *sinkcluster.ClusterWriter + countryStats CountryStats clientRoundtripEstimate time.Duration proxyIdleCount uint @@ -49,6 +52,10 @@ clientUnrestrictedDeniedCount uint clientProxyMatchCount uint + proxyPollWithRelayURLExtension uint + proxyPollWithoutRelayURLExtension uint + proxyPollRejectedWithRelayURLExtension uint + // synchronization for access to snowflake metrics lock sync.Mutex @@ -163,7 +170,7 @@ m.logger = metricsLogger m.promMetrics = initPrometheus() - // Write to log file every hour with updated metrics + // Write to log file every day with updated metrics go m.logMetrics() return m, nil @@ -189,6 +196,9 @@ } m.logger.Println("snowflake-ips-total", total) m.logger.Println("snowflake-idle-count", binCount(m.proxyIdleCount)) + m.logger.Println("snowflake-proxy-poll-with-relay-url-count", binCount(m.proxyPollWithRelayURLExtension)) + m.logger.Println("snowflake-proxy-poll-without-relay-url-count", binCount(m.proxyPollWithoutRelayURLExtension)) + m.logger.Println("snowflake-proxy-rejected-for-relay-url-count", binCount(m.proxyPollRejectedWithRelayURLExtension)) m.logger.Println("client-denied-count", binCount(m.clientDeniedCount)) m.logger.Println("client-restricted-denied-count", binCount(m.clientRestrictedDeniedCount)) m.logger.Println("client-unrestricted-denied-count", binCount(m.clientUnrestrictedDeniedCount)) @@ -205,6 +215,9 @@ m.clientDeniedCount = 0 m.clientRestrictedDeniedCount = 0 m.clientUnrestrictedDeniedCount = 0 + m.proxyPollRejectedWithRelayURLExtension = 0 + m.proxyPollWithRelayURLExtension = 0 + m.proxyPollWithoutRelayURLExtension = 0 m.clientProxyMatchCount = 0 m.countryStats.counts = make(map[string]int) for pType := range m.countryStats.proxies { @@ -227,6 +240,11 @@ ProxyPollTotal *RoundedCounterVec ClientPollTotal *RoundedCounterVec AvailableProxies *prometheus.GaugeVec + + ProxyPollWithRelayURLExtensionTotal *RoundedCounterVec + ProxyPollWithoutRelayURLExtensionTotal *RoundedCounterVec + + ProxyPollRejectedForRelayURLExtensionTotal *RoundedCounterVec } // Initialize metrics for prometheus exporter @@ -262,6 +280,33 @@ []string{"nat", "status"}, ) + promMetrics.ProxyPollWithRelayURLExtensionTotal = NewRoundedCounterVec( + prometheus.CounterOpts{ + Namespace: prometheusNamespace, + Name: "rounded_proxy_poll_with_relay_url_extension_total", + Help: "The number of snowflake proxy polls with Relay URL Extension, rounded up to a multiple of 8", + }, + []string{"nat", "type"}, + ) + + promMetrics.ProxyPollWithoutRelayURLExtensionTotal = NewRoundedCounterVec( + prometheus.CounterOpts{ + Namespace: prometheusNamespace, + Name: "rounded_proxy_poll_without_relay_url_extension_total", + Help: "The number of snowflake proxy polls without Relay URL Extension, rounded up to a multiple of 8", + }, + []string{"nat", "type"}, + ) + + promMetrics.ProxyPollRejectedForRelayURLExtensionTotal = NewRoundedCounterVec( + prometheus.CounterOpts{ + Namespace: prometheusNamespace, + Name: "rounded_proxy_poll_rejected_relay_url_extension_total", + Help: "The number of snowflake proxy polls rejected by Relay URL Extension, rounded up to a multiple of 8", + }, + []string{"nat", "type"}, + ) + promMetrics.ClientPollTotal = NewRoundedCounterVec( prometheus.CounterOpts{ Namespace: prometheusNamespace, @@ -275,7 +320,20 @@ promMetrics.registry.MustRegister( promMetrics.ClientPollTotal, promMetrics.ProxyPollTotal, promMetrics.ProxyTotal, promMetrics.AvailableProxies, + promMetrics.ProxyPollWithRelayURLExtensionTotal, + promMetrics.ProxyPollWithoutRelayURLExtensionTotal, + promMetrics.ProxyPollRejectedForRelayURLExtensionTotal, ) return promMetrics } + +func (m *Metrics) RecordIPAddress(ip string) { + if m.distinctIPWriter != nil { + m.distinctIPWriter.AddIPToSet(ip) + } +} + +func (m *Metrics) SetIPAddressRecorder(recorder *sinkcluster.ClusterWriter) { + m.distinctIPWriter = recorder +} diff -Nru snowflake-2.2.0/broker/snowflake-broker_test.go snowflake-2.3.1/broker/snowflake-broker_test.go --- snowflake-2.2.0/broker/snowflake-broker_test.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/broker/snowflake-broker_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -3,6 +3,7 @@ import ( "bytes" "container/heap" + "encoding/hex" "io" "io/ioutil" "log" @@ -36,6 +37,10 @@ func TestBroker(t *testing.T) { + defaultBridgeValue, _ := hex.DecodeString("2B280B23E1107BB62ABFC40DDCC8824814F80A72") + var defaultBridge [20]byte + copy(defaultBridge[:], defaultBridgeValue) + Convey("Context", t, func() { ctx := NewBrokerContext(NullLogger()) i := &IPC{ctx} @@ -253,10 +258,10 @@ // Pass a fake client offer to this proxy p := <-ctx.proxyPolls So(p.id, ShouldEqual, "ymbcCMto7KHNGYlp") - p.offerChannel <- &ClientOffer{sdp: []byte("fake offer")} + 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":""}`) + So(w.Body.String(), ShouldEqual, `{"Status":"client match","Offer":"fake offer","NAT":"","RelayURL":"wss://snowflake.torproject.net/"}`) }) Convey("return empty 200 OK when no client offer is available.", func() { @@ -269,7 +274,7 @@ // nil means timeout p.offerChannel <- nil <-done - So(w.Body.String(), ShouldEqual, `{"Status":"no match","Offer":"","NAT":""}`) + So(w.Body.String(), ShouldEqual, `{"Status":"no match","Offer":"","NAT":"","RelayURL":""}`) So(w.Code, ShouldEqual, http.StatusOK) }) }) @@ -412,7 +417,7 @@ <-polled So(wP.Code, ShouldEqual, http.StatusOK) - So(wP.Body.String(), ShouldResemble, `{"Status":"client match","Offer":"fake","NAT":"unknown"}`) + So(wP.Body.String(), ShouldResemble, `{"Status":"client match","Offer":"fake","NAT":"unknown","RelayURL":"wss://snowflake.torproject.net/"}`) So(ctx.idToSnowflake["ymbcCMto7KHNGYlp"], ShouldNotBeNil) // Follow up with the answer request afterwards wA := httptest.NewRecorder() @@ -555,7 +560,7 @@ So(metricsStr, ShouldContainSubstring, "\nsnowflake-ips-standalone 1\n") So(metricsStr, ShouldContainSubstring, "\nsnowflake-ips-badge 1\n") So(metricsStr, ShouldContainSubstring, "\nsnowflake-ips-webext 1\n") - So(metricsStr, ShouldEndWith, "\nsnowflake-ips-total 4\nsnowflake-idle-count 8\nclient-denied-count 0\nclient-restricted-denied-count 0\nclient-unrestricted-denied-count 0\nclient-snowflake-match-count 0\nsnowflake-ips-nat-restricted 0\nsnowflake-ips-nat-unrestricted 0\nsnowflake-ips-nat-unknown 1\n") + So(metricsStr, ShouldEndWith, "\nsnowflake-ips-total 4\nsnowflake-idle-count 8\nsnowflake-proxy-poll-with-relay-url-count 0\nsnowflake-proxy-poll-without-relay-url-count 8\nsnowflake-proxy-rejected-for-relay-url-count 0\nclient-denied-count 0\nclient-restricted-denied-count 0\nclient-unrestricted-denied-count 0\nclient-snowflake-match-count 0\nsnowflake-ips-nat-restricted 0\nsnowflake-ips-nat-unrestricted 0\nsnowflake-ips-nat-unknown 1\n") }) //Test addition of client failures @@ -579,7 +584,7 @@ So(buf.String(), ShouldContainSubstring, "\nsnowflake-ips-standalone 0\n") So(buf.String(), ShouldContainSubstring, "\nsnowflake-ips-badge 0\n") So(buf.String(), ShouldContainSubstring, "\nsnowflake-ips-webext 0\n") - So(buf.String(), ShouldContainSubstring, "\nsnowflake-ips-total 0\nsnowflake-idle-count 0\nclient-denied-count 0\nclient-restricted-denied-count 0\nclient-unrestricted-denied-count 0\nclient-snowflake-match-count 0\nsnowflake-ips-nat-restricted 0\nsnowflake-ips-nat-unrestricted 0\nsnowflake-ips-nat-unknown 0\n") + So(buf.String(), ShouldContainSubstring, "\nsnowflake-ips-total 0\nsnowflake-idle-count 0\nsnowflake-proxy-poll-with-relay-url-count 0\nsnowflake-proxy-poll-without-relay-url-count 0\nsnowflake-proxy-rejected-for-relay-url-count 0\nclient-denied-count 0\nclient-restricted-denied-count 0\nclient-unrestricted-denied-count 0\nclient-snowflake-match-count 0\nsnowflake-ips-nat-restricted 0\nsnowflake-ips-nat-unrestricted 0\nsnowflake-ips-nat-unknown 0\n") }) //Test addition of client matches Convey("for client-proxy match", func() { diff -Nru snowflake-2.2.0/ChangeLog snowflake-2.3.1/ChangeLog --- snowflake-2.2.0/ChangeLog 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/ChangeLog 2022-09-23 12:08:13.000000000 +0000 @@ -1,3 +1,10 @@ +Changes in version v2.3.0 - 2022-06-23 +- Issue 40146: Avoid performing two NAT probe tests at startup +- Issue 40134: Log messages from client NAT check failures are confusing +- Issue 34075: Implement metrics to measure snowflake churn +- Issue 28651: Prepare all pieces of the snowflake pipeline for a second snowflake bridge +- Issue 40129: Distributed Snowflake Server Support + Changes in version v2.2.0 - 2022-05-25 - Issue 40099: Initialize SnowflakeListener.closed diff -Nru snowflake-2.2.0/client/lib/snowflake.go snowflake-2.3.1/client/lib/snowflake.go --- snowflake-2.2.0/client/lib/snowflake.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/client/lib/snowflake.go 2022-09-23 12:08:13.000000000 +0000 @@ -237,7 +237,7 @@ } // loop through all provided STUN servers until we exhaust the list or find -// one that is compatable with RFC 5780 +// one that is compatible with RFC 5780 func updateNATType(servers []webrtc.ICEServer, broker *BrokerChannel) { var restrictedNAT bool @@ -245,7 +245,10 @@ for _, server := range servers { addr := strings.TrimPrefix(server.URLs[0], "stun:") restrictedNAT, err = nat.CheckIfRestrictedNAT(addr) - if err == nil { + + if err != nil { + log.Printf("Warning: NAT checking failed for server at %s: %s", addr, err) + } else { if restrictedNAT { broker.SetNATType(nat.NATRestricted) } else { diff -Nru snowflake-2.2.0/common/amp/armor_test.go snowflake-2.3.1/common/amp/armor_test.go --- snowflake-2.2.0/common/amp/armor_test.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/common/amp/armor_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -1,9 +1,9 @@ package amp import ( - "crypto/rand" "io" "io/ioutil" + "math/rand" "strings" "testing" ) diff -Nru snowflake-2.2.0/common/bridgefingerprint/fingerprint.go snowflake-2.3.1/common/bridgefingerprint/fingerprint.go --- snowflake-2.2.0/common/bridgefingerprint/fingerprint.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/bridgefingerprint/fingerprint.go 2022-09-23 12:08:13.000000000 +0000 @@ -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 -Nru snowflake-2.2.0/common/ipsetsink/sinkcluster/common.go snowflake-2.3.1/common/ipsetsink/sinkcluster/common.go --- snowflake-2.2.0/common/ipsetsink/sinkcluster/common.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/ipsetsink/sinkcluster/common.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,24 @@ +package sinkcluster + +/* ClusterWriter, and (ClusterCountResult).Count output a streamed IP set journal file to remember distinct IP address + + its format is as follows: + + This file should be in newline-delimited JSON format(https://jsonlines.org/). + For each line, the format of json data should be in the format of: + {"recordingStart":"2022-05-30T14:38:44.678610091Z","recordingEnd":"2022-05-30T14:39:48.157630926Z","recorded":""} + + recordingStart:datetime is the time this chunk of recording start. + + recordingEnd:datetime is the time this chunk of recording end. + + recorded is the checkpoint data generated by hyperloglog. +*/ + +import "time" + +type SinkEntry struct { + RecordingStart time.Time `json:"recordingStart"` + RecordingEnd time.Time `json:"recordingEnd"` + Recorded []byte `json:"recorded"` +} diff -Nru snowflake-2.2.0/common/ipsetsink/sinkcluster/reader.go snowflake-2.3.1/common/ipsetsink/sinkcluster/reader.go --- snowflake-2.2.0/common/ipsetsink/sinkcluster/reader.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/ipsetsink/sinkcluster/reader.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,60 @@ +package sinkcluster + +import ( + "bufio" + "encoding/json" + "github.com/clarkduvall/hyperloglog" + "io" + "time" +) + +func NewClusterCounter(from time.Time, to time.Time) *ClusterCounter { + return &ClusterCounter{from: from, to: to} +} + +type ClusterCounter struct { + from time.Time + to time.Time +} + +type ClusterCountResult struct { + Sum uint64 + ChunkIncluded int64 +} + +func (c ClusterCounter) Count(reader io.Reader) (*ClusterCountResult, error) { + result := ClusterCountResult{} + counter, err := hyperloglog.NewPlus(18) + if err != nil { + return nil, err + } + inputScanner := bufio.NewScanner(reader) + for inputScanner.Scan() { + inputLine := inputScanner.Bytes() + sinkInfo := SinkEntry{} + if err := json.Unmarshal(inputLine, &sinkInfo); err != nil { + return nil, err + } + + if (sinkInfo.RecordingStart.Before(c.from) && !sinkInfo.RecordingStart.Equal(c.from)) || + sinkInfo.RecordingEnd.After(c.to) { + continue + } + + restoredCounter, err := hyperloglog.NewPlus(18) + if err != nil { + return nil, err + } + err = restoredCounter.GobDecode(sinkInfo.Recorded) + if err != nil { + return nil, err + } + result.ChunkIncluded++ + err = counter.Merge(restoredCounter) + if err != nil { + return nil, err + } + } + result.Sum = counter.Count() + return &result, nil +} diff -Nru snowflake-2.2.0/common/ipsetsink/sinkcluster/writer.go snowflake-2.3.1/common/ipsetsink/sinkcluster/writer.go --- snowflake-2.2.0/common/ipsetsink/sinkcluster/writer.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/ipsetsink/sinkcluster/writer.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,68 @@ +package sinkcluster + +import ( + "bytes" + "encoding/json" + "io" + "log" + "time" + + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/ipsetsink" +) + +func NewClusterWriter(writer WriteSyncer, writeInterval time.Duration, sink *ipsetsink.IPSetSink) *ClusterWriter { + c := &ClusterWriter{ + writer: writer, + lastWriteTime: time.Now(), + writeInterval: writeInterval, + current: sink, + } + return c +} + +type ClusterWriter struct { + writer WriteSyncer + lastWriteTime time.Time + writeInterval time.Duration + current *ipsetsink.IPSetSink +} + +type WriteSyncer interface { + Sync() error + io.Writer +} + +func (c *ClusterWriter) WriteIPSetToDisk() { + currentTime := time.Now() + data, err := c.current.Dump() + if err != nil { + log.Println("unable able to write ipset to file:", err) + return + } + entry := &SinkEntry{ + RecordingStart: c.lastWriteTime, + RecordingEnd: currentTime, + Recorded: data, + } + jsonData, err := json.Marshal(entry) + if err != nil { + log.Println("unable able to write ipset to file:", err) + return + } + jsonData = append(jsonData, byte('\n')) + _, err = io.Copy(c.writer, bytes.NewReader(jsonData)) + if err != nil { + log.Println("unable able to write ipset to file:", err) + return + } + c.writer.Sync() + c.lastWriteTime = currentTime + c.current.Reset() +} + +func (c *ClusterWriter) AddIPToSet(ipAddress string) { + if c.lastWriteTime.Add(c.writeInterval).Before(time.Now()) { + c.WriteIPSetToDisk() + } + c.current.AddIPToSet(ipAddress) +} diff -Nru snowflake-2.2.0/common/ipsetsink/sinkcluster/writer_test.go snowflake-2.3.1/common/ipsetsink/sinkcluster/writer_test.go --- snowflake-2.2.0/common/ipsetsink/sinkcluster/writer_test.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/ipsetsink/sinkcluster/writer_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,33 @@ +package sinkcluster + +import ( + "bytes" + "io" + "testing" + "time" + + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/ipsetsink" + + . "github.com/smartystreets/goconvey/convey" +) + +type writerStub struct { + io.Writer +} + +func (w writerStub) Sync() error { + return nil +} + +func TestSinkWriter(t *testing.T) { + + Convey("Context", t, func() { + buffer := bytes.NewBuffer(nil) + writerStubInst := &writerStub{buffer} + sink := ipsetsink.NewIPSetSink("demo") + clusterWriter := NewClusterWriter(writerStubInst, time.Minute, sink) + clusterWriter.AddIPToSet("1") + clusterWriter.WriteIPSetToDisk() + So(buffer.Bytes(), ShouldNotBeNil) + }) +} diff -Nru snowflake-2.2.0/common/ipsetsink/sink.go snowflake-2.3.1/common/ipsetsink/sink.go --- snowflake-2.2.0/common/ipsetsink/sink.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/ipsetsink/sink.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,55 @@ +package ipsetsink + +import ( + "bytes" + "crypto/hmac" + "encoding/binary" + "hash" + + "github.com/clarkduvall/hyperloglog" + "golang.org/x/crypto/sha3" +) + +func NewIPSetSink(maskingKey string) *IPSetSink { + countDistinct, _ := hyperloglog.NewPlus(18) + return &IPSetSink{ + ipMaskingKey: maskingKey, + countDistinct: countDistinct, + } +} + +type IPSetSink struct { + ipMaskingKey string + countDistinct *hyperloglog.HyperLogLogPlus +} + +func (s *IPSetSink) maskIPAddress(ipAddress string) []byte { + hmacIPMasker := hmac.New(func() hash.Hash { + return sha3.New256() + }, []byte(s.ipMaskingKey)) + hmacIPMasker.Write([]byte(ipAddress)) + return hmacIPMasker.Sum(nil) +} + +func (s *IPSetSink) AddIPToSet(ipAddress string) { + s.countDistinct.Add(truncatedHash64FromBytes{hashValue(s.maskIPAddress(ipAddress))}) +} + +func (s *IPSetSink) Dump() ([]byte, error) { + return s.countDistinct.GobEncode() +} + +func (s *IPSetSink) Reset() { + s.countDistinct.Clear() +} + +type hashValue []byte +type truncatedHash64FromBytes struct { + hashValue +} + +func (c truncatedHash64FromBytes) Sum64() uint64 { + var value uint64 + binary.Read(bytes.NewReader(c.hashValue), binary.BigEndian, &value) + return value +} diff -Nru snowflake-2.2.0/common/ipsetsink/sink_test.go snowflake-2.3.1/common/ipsetsink/sink_test.go --- snowflake-2.2.0/common/ipsetsink/sink_test.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/ipsetsink/sink_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,47 @@ +package ipsetsink + +import ( + "fmt" + "github.com/clarkduvall/hyperloglog" + "testing" +) +import . "github.com/smartystreets/goconvey/convey" + +func TestSinkInit(t *testing.T) { + Convey("Context", t, func() { + sink := NewIPSetSink("demo") + sink.AddIPToSet("test1") + sink.AddIPToSet("test2") + data, err := sink.Dump() + So(err, ShouldBeNil) + structure, err := hyperloglog.NewPlus(18) + So(err, ShouldBeNil) + err = structure.GobDecode(data) + So(err, ShouldBeNil) + count := structure.Count() + So(count, ShouldBeBetweenOrEqual, 1, 3) + }) +} + +func TestSinkCounting(t *testing.T) { + Convey("Context", t, func() { + for itemCount := 300; itemCount <= 10000; itemCount += 200 { + sink := NewIPSetSink("demo") + for i := 0; i <= itemCount; i++ { + sink.AddIPToSet(fmt.Sprintf("demo%v", i)) + } + for i := 0; i <= itemCount; i++ { + sink.AddIPToSet(fmt.Sprintf("demo%v", i)) + } + data, err := sink.Dump() + So(err, ShouldBeNil) + structure, err := hyperloglog.NewPlus(18) + So(err, ShouldBeNil) + err = structure.GobDecode(data) + So(err, ShouldBeNil) + count := structure.Count() + So((float64(count)/float64(itemCount))-1.0, ShouldAlmostEqual, 0, 0.01) + } + + }) +} diff -Nru snowflake-2.2.0/common/messages/client.go snowflake-2.3.1/common/messages/client.go --- snowflake-2.2.0/common/messages/client.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/common/messages/client.go 2022-09-23 12:08:13.000000000 +0000 @@ -5,9 +5,9 @@ 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 @@ 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") } diff -Nru snowflake-2.2.0/common/messages/ipc.go snowflake-2.3.1/common/messages/ipc.go --- snowflake-2.2.0/common/messages/ipc.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/common/messages/ipc.go 2022-09-23 12:08:13.000000000 +0000 @@ -12,6 +12,7 @@ var ( ErrBadRequest = errors.New("bad request") ErrInternal = errors.New("internal error") + ErrExtraInfo = errors.New("client sent extra info") StrTimedOut = "timed out waiting for answer!" StrNoProxies = "no snowflake proxies currently available" diff -Nru snowflake-2.2.0/common/messages/messages_test.go snowflake-2.3.1/common/messages/messages_test.go --- snowflake-2.2.0/common/messages/messages_test.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/common/messages/messages_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -17,90 +17,103 @@ clients int data string err error + + acceptedRelayPattern string }{ { //Version 1.0 proxy message - "ymbcCMto7KHNGYlp", - "unknown", - "unknown", - 0, - `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.0"}`, - nil, + sid: "ymbcCMto7KHNGYlp", + proxyType: "unknown", + natType: "unknown", + clients: 0, + data: `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.0"}`, + err: nil, }, { //Version 1.1 proxy message - "ymbcCMto7KHNGYlp", - "standalone", - "unknown", - 0, - `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.1","Type":"standalone"}`, - nil, + sid: "ymbcCMto7KHNGYlp", + proxyType: "standalone", + natType: "unknown", + clients: 0, + data: `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.1","Type":"standalone"}`, + err: nil, }, { //Version 1.2 proxy message - "ymbcCMto7KHNGYlp", - "standalone", - "restricted", - 0, - `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.2","Type":"standalone", "NAT":"restricted"}`, - nil, + sid: "ymbcCMto7KHNGYlp", + proxyType: "standalone", + natType: "restricted", + clients: 0, + data: `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.2","Type":"standalone", "NAT":"restricted"}`, + err: nil, }, { //Version 1.2 proxy message with clients - "ymbcCMto7KHNGYlp", - "standalone", - "restricted", - 24, - `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.2","Type":"standalone", "NAT":"restricted","Clients":24}`, - nil, + sid: "ymbcCMto7KHNGYlp", + proxyType: "standalone", + natType: "restricted", + clients: 24, + data: `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.2","Type":"standalone", "NAT":"restricted","Clients":24}`, + err: nil, + }, + { + //Version 1.3 proxy message with clients and proxyURL + sid: "ymbcCMto7KHNGYlp", + proxyType: "standalone", + natType: "restricted", + clients: 24, + acceptedRelayPattern: "snowfalke.torproject.org", + data: `{"Sid":"ymbcCMto7KHNGYlp","Version":"1.2","Type":"standalone", "NAT":"restricted","Clients":24, "AcceptedRelayPattern":"snowfalke.torproject.org"}`, + err: nil, }, { //Version 0.X proxy message: - "", - "", - "", - 0, - "", - &json.SyntaxError{}, - }, - { - "", - "", - "", - 0, - `{"Sid":"ymbcCMto7KHNGYlp"}`, - fmt.Errorf(""), - }, - { - "", - "", - "", - 0, - "{}", - fmt.Errorf(""), - }, - { - "", - "", - "", - 0, - `{"Version":"1.0"}`, - fmt.Errorf(""), - }, - { - "", - "", - "", - 0, - `{"Version":"2.0"}`, - fmt.Errorf(""), + sid: "", + proxyType: "", + natType: "", + clients: 0, + data: "", + err: &json.SyntaxError{}, + }, + { + sid: "", + proxyType: "", + natType: "", + clients: 0, + data: `{"Sid":"ymbcCMto7KHNGYlp"}`, + err: fmt.Errorf(""), + }, + { + sid: "", + proxyType: "", + natType: "", + clients: 0, + data: "{}", + err: fmt.Errorf(""), + }, + { + sid: "", + proxyType: "", + natType: "", + clients: 0, + data: `{"Version":"1.0"}`, + err: fmt.Errorf(""), + }, + { + sid: "", + proxyType: "", + natType: "", + clients: 0, + data: `{"Version":"2.0"}`, + err: fmt.Errorf(""), }, } { - sid, proxyType, natType, clients, err := DecodeProxyPollRequest([]byte(test.data)) + sid, proxyType, natType, clients, relayPattern, _, err := DecodeProxyPollRequestWithRelayPrefix([]byte(test.data)) So(sid, ShouldResemble, test.sid) So(proxyType, ShouldResemble, test.proxyType) So(natType, ShouldResemble, test.natType) So(clients, ShouldEqual, test.clients) + So(relayPattern, ShouldResemble, test.acceptedRelayPattern) So(err, ShouldHaveSameTypeAs, test.err) } @@ -123,34 +136,42 @@ func TestDecodeProxyPollResponse(t *testing.T) { Convey("Context", t, func() { for _, test := range []struct { - offer string - data string - err error + offer string + data string + relayURL string + err error }{ { - "fake offer", - `{"Status":"client match","Offer":"fake offer","NAT":"unknown"}`, - nil, + offer: "fake offer", + data: `{"Status":"client match","Offer":"fake offer","NAT":"unknown"}`, + err: nil, + }, + { + offer: "fake offer", + data: `{"Status":"client match","Offer":"fake offer","NAT":"unknown", "RelayURL":"wss://snowflake.torproject.org/proxy"}`, + relayURL: "wss://snowflake.torproject.org/proxy", + err: nil, }, { - "", - `{"Status":"no match"}`, - nil, + offer: "", + data: `{"Status":"no match"}`, + err: nil, }, { - "", - `{"Status":"client match"}`, - fmt.Errorf("no supplied offer"), + offer: "", + data: `{"Status":"client match"}`, + err: fmt.Errorf("no supplied offer"), }, { - "", - `{"Test":"test"}`, - fmt.Errorf(""), + offer: "", + data: `{"Test":"test"}`, + err: fmt.Errorf(""), }, } { - offer, _, err := DecodePollResponse([]byte(test.data)) + offer, _, relayURL, err := DecodePollResponseWithRelayURL([]byte(test.data)) So(err, ShouldHaveSameTypeAs, test.err) So(offer, ShouldResemble, test.offer) + So(relayURL, ShouldResemble, test.relayURL) } }) @@ -173,6 +194,34 @@ So(err, ShouldEqual, nil) }) } + +func TestEncodeProxyPollResponseWithProxyURL(t *testing.T) { + Convey("Context", t, func() { + b, err := EncodePollResponseWithRelayURL("fake offer", true, "restricted", "wss://test/", "") + So(err, ShouldBeNil) + offer, natType, err := DecodePollResponse(b) + So(err, ShouldNotBeNil) + + offer, natType, relay, err := DecodePollResponseWithRelayURL(b) + So(offer, ShouldEqual, "fake offer") + So(natType, ShouldEqual, "restricted") + So(relay, ShouldEqual, "wss://test/") + So(err, ShouldBeNil) + + b, err = EncodePollResponse("", false, "unknown") + So(err, ShouldBeNil) + offer, natType, relay, err = DecodePollResponseWithRelayURL(b) + So(offer, ShouldEqual, "") + So(natType, ShouldEqual, "unknown") + So(err, ShouldBeNil) + + b, err = EncodePollResponseWithRelayURL("fake offer", false, "restricted", "wss://test/", "test error reason") + So(err, ShouldBeNil) + offer, natType, relay, err = DecodePollResponseWithRelayURL(b) + So(err, ShouldNotBeNil) + So(err.Error(), ShouldContainSubstring, "test error reason") + }) +} func TestDecodeProxyAnswerRequest(t *testing.T) { Convey("Context", t, func() { for _, test := range []struct { diff -Nru snowflake-2.2.0/common/messages/proxy.go snowflake-2.3.1/common/messages/proxy.go --- snowflake-2.2.0/common/messages/proxy.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/common/messages/proxy.go 2022-09-23 12:08:13.000000000 +0000 @@ -5,6 +5,7 @@ import ( "encoding/json" + "errors" "fmt" "strings" @@ -12,7 +13,7 @@ ) const ( - version = "1.2" + version = "1.3" ProxyUnknown = "unknown" ) @@ -23,15 +24,16 @@ "iptproxy": true, } -/* Version 1.2 specification: +/* Version 1.3 specification: == ProxyPollRequest == { Sid: [generated session id of proxy], - Version: 1.2, + Version: 1.3, Type: ["badge"|"webext"|"standalone"], NAT: ["unknown"|"restricted"|"unrestricted"], - Clients: [number of current clients, rounded down to multiples of 8] + Clients: [number of current clients, rounded down to multiples of 8], + AcceptedRelayPattern: [a pattern representing accepted set of relay domains] } == ProxyPollResponse == @@ -43,7 +45,8 @@ type: offer, sdp: [WebRTC SDP] }, - NAT: ["unknown"|"restricted"|"unrestricted"] + NAT: ["unknown"|"restricted"|"unrestricted"], + RelayURL: [the WebSocket URL proxy should connect to relay Snowflake traffic] } 2) If a client is not matched: @@ -59,7 +62,7 @@ == ProxyAnswerRequest == { Sid: [generated session id of proxy], - Version: 1.2, + Version: 1.3, Answer: { type: answer, @@ -93,22 +96,39 @@ Type string NAT string Clients int + + AcceptedRelayPattern *string } func EncodeProxyPollRequest(sid string, proxyType string, natType string, clients int) ([]byte, error) { + return EncodeProxyPollRequestWithRelayPrefix(sid, proxyType, natType, clients, "") +} + +func EncodeProxyPollRequestWithRelayPrefix(sid string, proxyType string, natType string, clients int, relayPattern string) ([]byte, error) { return json.Marshal(ProxyPollRequest{ - Sid: sid, - Version: version, - Type: proxyType, - NAT: natType, - Clients: clients, + Sid: sid, + Version: version, + Type: proxyType, + NAT: natType, + Clients: clients, + AcceptedRelayPattern: &relayPattern, }) } +func DecodeProxyPollRequest(data []byte) (sid string, proxyType string, natType string, clients int, err error) { + var relayPrefix string + sid, proxyType, natType, clients, relayPrefix, _, err = DecodeProxyPollRequestWithRelayPrefix(data) + if relayPrefix != "" { + return "", "", "", 0, ErrExtraInfo + } + return +} + // Decodes a poll message from a snowflake proxy and returns the // sid, proxy type, nat type and clients of the proxy on success // and an error if it failed -func DecodeProxyPollRequest(data []byte) (sid string, proxyType string, natType string, clients int, err error) { +func DecodeProxyPollRequestWithRelayPrefix(data []byte) ( + sid string, proxyType string, natType string, clients int, relayPrefix string, relayPrefixAware bool, err error) { var message ProxyPollRequest err = json.Unmarshal(data, &message) @@ -144,49 +164,71 @@ if !KnownProxyTypes[message.Type] { message.Type = ProxyUnknown } - - return message.Sid, message.Type, message.NAT, message.Clients, nil + var acceptedRelayPattern = "" + if message.AcceptedRelayPattern != nil { + acceptedRelayPattern = *message.AcceptedRelayPattern + } + return message.Sid, message.Type, message.NAT, message.Clients, + acceptedRelayPattern, message.AcceptedRelayPattern != nil, nil } type ProxyPollResponse struct { Status string Offer string NAT string + + RelayURL string } func EncodePollResponse(offer string, success bool, natType string) ([]byte, error) { + return EncodePollResponseWithRelayURL(offer, success, natType, "", "no match") +} + +func EncodePollResponseWithRelayURL(offer string, success bool, natType, relayURL, failReason string) ([]byte, error) { if success { return json.Marshal(ProxyPollResponse{ - Status: "client match", - Offer: offer, - NAT: natType, + Status: "client match", + Offer: offer, + NAT: natType, + RelayURL: relayURL, }) } return json.Marshal(ProxyPollResponse{ - Status: "no match", + Status: failReason, }) } +func DecodePollResponse(data []byte) (string, string, error) { + offer, natType, relayURL, err := DecodePollResponseWithRelayURL(data) + if relayURL != "" { + return "", "", ErrExtraInfo + } + return offer, natType, err +} // Decodes a poll response from the broker and returns an offer and the client's NAT type // If there is a client match, the returned offer string will be non-empty -func DecodePollResponse(data []byte) (string, string, error) { +func DecodePollResponseWithRelayURL(data []byte) (string, string, string, error) { var message ProxyPollResponse err := json.Unmarshal(data, &message) if err != nil { - return "", "", err + return "", "", "", err } if message.Status == "" { - return "", "", fmt.Errorf("received invalid data") + return "", "", "", fmt.Errorf("received invalid data") } + err = nil if message.Status == "client match" { if message.Offer == "" { - return "", "", fmt.Errorf("no supplied offer") + return "", "", "", fmt.Errorf("no supplied offer") } } else { message.Offer = "" + if message.Status != "no match" { + err = errors.New(message.Status) + } } natType := message.NAT @@ -194,7 +236,7 @@ natType = "unknown" } - return message.Offer, natType, nil + return message.Offer, natType, message.RelayURL, err } type ProxyAnswerRequest struct { diff -Nru snowflake-2.2.0/common/namematcher/matcher.go snowflake-2.3.1/common/namematcher/matcher.go --- snowflake-2.2.0/common/namematcher/matcher.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/namematcher/matcher.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,31 @@ +package namematcher + +import "strings" + +func NewNameMatcher(rule string) NameMatcher { + rule = strings.TrimSuffix(rule, "$") + return NameMatcher{suffix: strings.TrimPrefix(rule, "^"), exact: strings.HasPrefix(rule, "^")} +} + +func IsValidRule(rule string) bool { + return strings.HasSuffix(rule, "$") +} + +type NameMatcher struct { + exact bool + suffix string +} + +func (m *NameMatcher) IsSupersetOf(matcher NameMatcher) bool { + if m.exact { + return matcher.exact && m.suffix == matcher.suffix + } + return strings.HasSuffix(matcher.suffix, m.suffix) +} + +func (m *NameMatcher) IsMember(s string) bool { + if m.exact { + return s == m.suffix + } + return strings.HasSuffix(s, m.suffix) +} diff -Nru snowflake-2.2.0/common/namematcher/matcher_test.go snowflake-2.3.1/common/namematcher/matcher_test.go --- snowflake-2.2.0/common/namematcher/matcher_test.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/common/namematcher/matcher_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,55 @@ +package namematcher + +import "testing" + +import . "github.com/smartystreets/goconvey/convey" + +func TestMatchMember(t *testing.T) { + testingVector := []struct { + matcher string + target string + expects bool + }{ + {matcher: "", target: "", expects: true}, + {matcher: "^snowflake.torproject.net$", target: "snowflake.torproject.net", expects: true}, + {matcher: "^snowflake.torproject.net$", target: "faketorproject.net", expects: false}, + {matcher: "snowflake.torproject.net$", target: "faketorproject.net", expects: false}, + {matcher: "snowflake.torproject.net$", target: "snowflake.torproject.net", expects: true}, + {matcher: "snowflake.torproject.net$", target: "imaginary-01-snowflake.torproject.net", expects: true}, + {matcher: "snowflake.torproject.net$", target: "imaginary-aaa-snowflake.torproject.net", expects: true}, + {matcher: "snowflake.torproject.net$", target: "imaginary-aaa-snowflake.faketorproject.net", expects: false}, + } + for _, v := range testingVector { + t.Run(v.matcher+"<>"+v.target, func(t *testing.T) { + Convey("test", t, func() { + matcher := NewNameMatcher(v.matcher) + So(matcher.IsMember(v.target), ShouldEqual, v.expects) + }) + }) + } +} + +func TestMatchSubset(t *testing.T) { + testingVector := []struct { + matcher string + target string + expects bool + }{ + {matcher: "", target: "", expects: true}, + {matcher: "^snowflake.torproject.net$", target: "^snowflake.torproject.net$", expects: true}, + {matcher: "snowflake.torproject.net$", target: "^snowflake.torproject.net$", expects: true}, + {matcher: "snowflake.torproject.net$", target: "snowflake.torproject.net$", expects: true}, + {matcher: "snowflake.torproject.net$", target: "testing-snowflake.torproject.net$", expects: true}, + {matcher: "snowflake.torproject.net$", target: "^testing-snowflake.torproject.net$", expects: true}, + {matcher: "snowflake.torproject.net$", target: "", expects: false}, + } + for _, v := range testingVector { + t.Run(v.matcher+"<>"+v.target, func(t *testing.T) { + Convey("test", t, func() { + matcher := NewNameMatcher(v.matcher) + target := NewNameMatcher(v.target) + So(matcher.IsSupersetOf(target), ShouldEqual, v.expects) + }) + }) + } +} diff -Nru snowflake-2.2.0/common/nat/nat.go snowflake-2.3.1/common/nat/nat.go --- snowflake-2.2.0/common/nat/nat.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/common/nat/nat.go 2022-09-23 12:08:13.000000000 +0000 @@ -49,8 +49,7 @@ mapTestConn, err := connect(addrStr) if err != nil { - log.Printf("Error creating STUN connection: %s", err.Error()) - return false, err + return false, fmt.Errorf("Error creating STUN connection: %w", err) } defer mapTestConn.Close() @@ -59,48 +58,34 @@ message := stun.MustBuild(stun.TransactionID, stun.BindingRequest) resp, err := mapTestConn.RoundTrip(message, mapTestConn.PrimaryAddr) - if err == ErrTimedOut { - log.Printf("Error: no response from server") - return false, err - } if err != nil { - log.Printf("Error receiving response from server: %s", err.Error()) - return false, err + return false, fmt.Errorf("Error completing roundtrip map test: %w", err) } // Decoding XOR-MAPPED-ADDRESS attribute from message. if err = xorAddr1.GetFrom(resp); err != nil { - log.Printf("Error retrieving XOR-MAPPED-ADDRESS resonse: %s", err.Error()) - return false, err + return false, fmt.Errorf("Error retrieving XOR-MAPPED-ADDRESS resonse: %w", err) } // Decoding OTHER-ADDRESS attribute from message. var otherAddr stun.OtherAddress if err = otherAddr.GetFrom(resp); err != nil { - log.Println("NAT discovery feature not supported by this server") - return false, err + return false, fmt.Errorf("NAT discovery feature not supported: %w", err) } if err = mapTestConn.AddOtherAddr(otherAddr.String()); err != nil { - log.Printf("Failed to resolve address %s\t", otherAddr.String()) - return false, err + return false, fmt.Errorf("Error resolving address %s: %w", otherAddr.String(), err) } // Test II: Send binding request to other address resp, err = mapTestConn.RoundTrip(message, mapTestConn.OtherAddr) - if err == ErrTimedOut { - log.Printf("Error: no response from server") - return false, err - } if err != nil { - log.Printf("Error retrieving server response: %s", err.Error()) - return false, err + return false, fmt.Errorf("Error retrieveing server response: %w", err) } // Decoding XOR-MAPPED-ADDRESS attribute from message. if err = xorAddr2.GetFrom(resp); err != nil { - log.Printf("Error retrieving XOR-MAPPED-ADDRESS resonse: %s", err.Error()) - return false, err + return false, fmt.Errorf("Error retrieving XOR-MAPPED-ADDRESS resonse: %w", err) } return xorAddr1.String() != xorAddr2.String(), nil diff -Nru snowflake-2.2.0/common/utls/roundtripper_test.go snowflake-2.3.1/common/utls/roundtripper_test.go --- snowflake-2.2.0/common/utls/roundtripper_test.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/common/utls/roundtripper_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -1,12 +1,12 @@ package utls import ( - "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "math/big" + "math/rand" "net/http" "testing" "time" @@ -26,7 +26,15 @@ Convey("[Test]Set up http servers", t, func(c C) { c.Convey("[Test]Generate Self-Signed Cert", func(c C) { // Ported from https://gist.github.com/samuel/8b500ddd3f6118d052b5e6bc16bc4c09 - priv, err := rsa.GenerateKey(rand.Reader, 4096) + + // note that we use the insecure math/rand here because some platforms + // fail the test suite at build time in Debian, due to entropy starvation. + // since that's not a problem at test time, we do *not* use a secure + // mechanism for key generation. + // + // DO NOT REUSE THIS CODE IN PRODUCTION, IT IS DANGEROUS + insecureRandReader := rand.New(rand.NewSource(1337)) + priv, err := rsa.GenerateKey(insecureRandReader, 4096) c.So(err, ShouldBeNil) template := x509.Certificate{ SerialNumber: big.NewInt(1), @@ -40,7 +48,7 @@ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv) + derBytes, err := x509.CreateCertificate(insecureRandReader, &template, &template, priv.Public(), priv) c.So(err, ShouldBeNil) selfSignedPrivateKey = priv selfSignedCert = derBytes diff -Nru snowflake-2.2.0/debian/changelog snowflake-2.3.1/debian/changelog --- snowflake-2.2.0/debian/changelog 2022-06-24 12:14:42.000000000 +0000 +++ snowflake-2.3.1/debian/changelog 2022-11-14 13:12:58.000000000 +0000 @@ -1,3 +1,10 @@ +snowflake (2.3.1-1) unstable; urgency=medium + + * New upstream release. + * Remove the vendored code. + + -- Ruben Pollan Mon, 14 Nov 2022 14:12:58 +0100 + snowflake (2.2.0-4) unstable; urgency=medium * Team upload. diff -Nru snowflake-2.2.0/debian/control snowflake-2.3.1/debian/control --- snowflake-2.2.0/debian/control 2022-06-17 15:17:23.000000000 +0000 +++ snowflake-2.3.1/debian/control 2022-11-14 13:12:58.000000000 +0000 @@ -22,7 +22,7 @@ golang-goptlib-dev (>= 1.2.0), golang-refraction-networking-utls-dev, golang-github-pion-webrtc.v3-dev -Standards-Version: 4.6.0 +Standards-Version: 4.6.1 Vcs-Browser: https://salsa.debian.org/pkg-privacy-team/snowflake Vcs-Git: https://salsa.debian.org/pkg-privacy-team/snowflake.git Homepage: https://snowflake.torproject.org diff -Nru snowflake-2.2.0/debian/copyright snowflake-2.3.1/debian/copyright --- snowflake-2.2.0/debian/copyright 2022-06-17 14:52:10.000000000 +0000 +++ snowflake-2.3.1/debian/copyright 2022-11-14 13:12:58.000000000 +0000 @@ -17,10 +17,6 @@ License: BSD-3-clause Comment: Debian packaging is licensed under the same terms as upstream -Files: debian/vendor/gitlab.torproject.org/tpo/* -Copyright: 2021-2022 The Tor Project, Ink -License: BSD-3-clause - License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff -Nru snowflake-2.2.0/debian/patches/0002-Don-t-use-entropy-for-test.patch snowflake-2.3.1/debian/patches/0002-Don-t-use-entropy-for-test.patch --- snowflake-2.2.0/debian/patches/0002-Don-t-use-entropy-for-test.patch 2022-06-17 14:34:27.000000000 +0000 +++ snowflake-2.3.1/debian/patches/0002-Don-t-use-entropy-for-test.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -From f38c91f906af5b806f463e790eddc134961abf1f Mon Sep 17 00:00:00 2001 -From: meskio -Date: Thu, 2 Jun 2022 11:19:47 +0200 -Subject: [PATCH] Don't use entropy for test - -Use math/rand instead of crypto/rand, so entropy is not a blocker when -running the tests. ---- - common/amp/armor_test.go | 2 +- - common/utls/roundtripper_test.go | 14 +++++++++++--- - 2 files changed, 12 insertions(+), 4 deletions(-) - -diff --git a/common/amp/armor_test.go b/common/amp/armor_test.go -index 594ae65..fc7561e 100644 ---- a/common/amp/armor_test.go -+++ b/common/amp/armor_test.go -@@ -1,9 +1,9 @@ - package amp - - import ( -- "crypto/rand" - "io" - "io/ioutil" -+ "math/rand" - "strings" - "testing" - ) -diff --git a/common/utls/roundtripper_test.go b/common/utls/roundtripper_test.go -index 6a91385..bccb799 100644 ---- a/common/utls/roundtripper_test.go -+++ b/common/utls/roundtripper_test.go -@@ -1,12 +1,12 @@ - package utls - - import ( -- "crypto/rand" - "crypto/rsa" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "math/big" -+ "math/rand" - "net/http" - "testing" - "time" -@@ -26,7 +26,15 @@ func TestRoundTripper(t *testing.T) { - Convey("[Test]Set up http servers", t, func(c C) { - c.Convey("[Test]Generate Self-Signed Cert", func(c C) { - // Ported from https://gist.github.com/samuel/8b500ddd3f6118d052b5e6bc16bc4c09 -- priv, err := rsa.GenerateKey(rand.Reader, 4096) -+ -+ // note that we use the insecure math/rand here because some platforms -+ // fail the test suite at build time in Debian, due to entropy starvation. -+ // since that's not a problem at test time, we do *not* use a secure -+ // mechanism for key generation. -+ // -+ // DO NOT REUSE THIS CODE IN PRODUCTION, IT IS DANGEROUS -+ insecureRandReader := rand.New(rand.NewSource(1337)) -+ priv, err := rsa.GenerateKey(insecureRandReader, 4096) - c.So(err, ShouldBeNil) - template := x509.Certificate{ - SerialNumber: big.NewInt(1), -@@ -40,7 +48,7 @@ func TestRoundTripper(t *testing.T) { - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } -- derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv) -+ derBytes, err := x509.CreateCertificate(insecureRandReader, &template, &template, priv.Public(), priv) - c.So(err, ShouldBeNil) - selfSignedPrivateKey = priv - selfSignedCert = derBytes --- -2.36.1 - diff -Nru snowflake-2.2.0/debian/patches/series snowflake-2.3.1/debian/patches/series --- snowflake-2.2.0/debian/patches/series 2022-06-17 14:34:27.000000000 +0000 +++ snowflake-2.3.1/debian/patches/series 2022-11-14 13:12:58.000000000 +0000 @@ -1,2 +1 @@ 0001-Adapt-tests-to-work-with-devian-version-of-goconvey.patch -0002-Don-t-use-entropy-for-test.patch diff -Nru snowflake-2.2.0/debian/rules snowflake-2.3.1/debian/rules --- snowflake-2.2.0/debian/rules 2022-06-17 15:19:20.000000000 +0000 +++ snowflake-2.3.1/debian/rules 2022-11-14 13:12:58.000000000 +0000 @@ -1,12 +1,9 @@ #!/usr/bin/make -f -export DH_GOLANG_EXCLUDES := broker probetest server +export DH_GOLANG_EXCLUDES := broker probetest server common/ipsetsink distinctcounter %: dh $@ --builddirectory=_build --buildsystem=golang --with=golang -execute_before_dh_auto_configure: - cp -av debian/vendor ./ - override_dh_missing-indep: dh_missing --list-missing diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/geoip.go snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/geoip.go --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/geoip.go 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/geoip.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,272 +0,0 @@ -/* -This code is for loading database data that maps ip addresses to countries -for collecting and presenting statistics on snowflake use that might alert us -to censorship events. - -The functions here are heavily based off of how tor maintains and searches their -geoip database - -The tables used for geoip data must be structured as follows: - -Recognized line format for IPv4 is: - INTIPLOW,INTIPHIGH,CC - where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as big-endian 4-byte unsigned - integers, and CC is a country code. - -Note that the IPv4 line format - "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME" -is not currently supported. - -Recognized line format for IPv6 is: - IPV6LOW,IPV6HIGH,CC - where IPV6LOW and IPV6HIGH are IPv6 addresses and CC is a country code. - -It also recognizes, and skips over, blank lines and lines that start -with '#' (comments). - -*/ -package geoip - -import ( - "bufio" - "bytes" - "crypto/sha1" - "encoding/hex" - "fmt" - "io" - "log" - "net" - "os" - "sort" - "strconv" - "strings" - "sync" -) - -type Geoip struct { - tableV4 *geoIPv4Table - tableV6 *geoIPv6Table -} - -// New creates a new Geoip struct loading the content of the files at geoIPv4DBpath and -// geoIPv6DBpath -func New(geoIPv4DBpath, geoIPv6DBpath string) (*Geoip, error) { - tableV4 := new(geoIPv4Table) - err := geoIPLoadFile(tableV4, geoIPv4DBpath) - if err != nil { - return nil, err - } - - tableV6 := new(geoIPv6Table) - err = geoIPLoadFile(tableV6, geoIPv6DBpath) - if err != nil { - return nil, err - } - - return &Geoip{tableV4, tableV6}, nil -} - -// GetCountryByAddr returns the country location of an IP address, and a boolean value -// that indicates whether the IP address was present in the geoip database -func (g *Geoip) GetCountryByAddr(ip net.IP) (string, bool) { - if ip.To4() != nil { - return getCountryByAddr(g.tableV4, ip) - } - return getCountryByAddr(g.tableV6, ip) -} - -type geoIPTable interface { - parseEntry(string) (*geoIPEntry, error) - Len() int - Append(geoIPEntry) - ElementAt(int) geoIPEntry - Lock() - Unlock() -} - -type geoIPEntry struct { - ipLow net.IP - ipHigh net.IP - country string -} - -type geoIPv4Table struct { - table []geoIPEntry - - lock sync.Mutex // synchronization for geoip table accesses and reloads -} - -type geoIPv6Table struct { - table []geoIPEntry - - lock sync.Mutex // synchronization for geoip table accesses and reloads -} - -func (table *geoIPv4Table) Len() int { return len(table.table) } -func (table *geoIPv6Table) Len() int { return len(table.table) } - -func (table *geoIPv4Table) Append(entry geoIPEntry) { - (*table).table = append(table.table, entry) -} -func (table *geoIPv6Table) Append(entry geoIPEntry) { - (*table).table = append(table.table, entry) -} - -func (table *geoIPv4Table) ElementAt(i int) geoIPEntry { return table.table[i] } -func (table *geoIPv6Table) ElementAt(i int) geoIPEntry { return table.table[i] } - -func (table *geoIPv4Table) Lock() { (*table).lock.Lock() } -func (table *geoIPv6Table) Lock() { (*table).lock.Lock() } - -func (table *geoIPv4Table) Unlock() { (*table).lock.Unlock() } -func (table *geoIPv6Table) Unlock() { (*table).lock.Unlock() } - -// Convert a geoip IP address represented as a big-endian unsigned integer to net.IP -func geoipStringToIP(ipStr string) (net.IP, error) { - ip, err := strconv.ParseUint(ipStr, 10, 32) - if err != nil { - return net.IPv4(0, 0, 0, 0), fmt.Errorf("error parsing IP %s", ipStr) - } - var bytes [4]byte - bytes[0] = byte(ip & 0xFF) - bytes[1] = byte((ip >> 8) & 0xFF) - bytes[2] = byte((ip >> 16) & 0xFF) - bytes[3] = byte((ip >> 24) & 0xFF) - - return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0]), nil -} - -//Parses a line in the provided geoip file that corresponds -//to an address range and a two character country code -func (table *geoIPv4Table) parseEntry(candidate string) (*geoIPEntry, error) { - - if candidate[0] == '#' { - return nil, nil - } - - parsedCandidate := strings.Split(candidate, ",") - - if len(parsedCandidate) != 3 { - return nil, fmt.Errorf("provided geoip file is incorrectly formatted. Could not parse line:\n%s", parsedCandidate) - } - - low, err := geoipStringToIP(parsedCandidate[0]) - if err != nil { - return nil, err - } - high, err := geoipStringToIP(parsedCandidate[1]) - if err != nil { - return nil, err - } - - geoipEntry := &geoIPEntry{ - ipLow: low, - ipHigh: high, - country: parsedCandidate[2], - } - - return geoipEntry, nil -} - -//Parses a line in the provided geoip file that corresponds -//to an address range and a two character country code -func (table *geoIPv6Table) parseEntry(candidate string) (*geoIPEntry, error) { - - if candidate[0] == '#' { - return nil, nil - } - - parsedCandidate := strings.Split(candidate, ",") - - if len(parsedCandidate) != 3 { - return nil, fmt.Errorf("") - } - - low := net.ParseIP(parsedCandidate[0]) - if low == nil { - return nil, fmt.Errorf("") - } - high := net.ParseIP(parsedCandidate[1]) - if high == nil { - return nil, fmt.Errorf("") - } - - geoipEntry := &geoIPEntry{ - ipLow: low, - ipHigh: high, - country: parsedCandidate[2], - } - - return geoipEntry, nil -} - -//Loads provided geoip file into our tables -//Entries are stored in a table -func geoIPLoadFile(table geoIPTable, pathname string) error { - //open file - geoipFile, err := os.Open(pathname) - if err != nil { - return err - } - defer geoipFile.Close() - - hash := sha1.New() - - table.Lock() - defer table.Unlock() - - hashedFile := io.TeeReader(geoipFile, hash) - - //read in strings and call parse function - scanner := bufio.NewScanner(hashedFile) - for scanner.Scan() { - entry, err := table.parseEntry(scanner.Text()) - if err != nil { - return fmt.Errorf("provided geoip file is incorrectly formatted. Line is: %+q", scanner.Text()) - } - - if entry != nil { - table.Append(*entry) - } - - } - if err := scanner.Err(); err != nil { - return err - } - - sha1Hash := hex.EncodeToString(hash.Sum(nil)) - log.Println("Using geoip file ", pathname, " with checksum", sha1Hash) - log.Println("Loaded ", table.Len(), " entries into table") - - return nil -} - -//Returns the country location of an IPv4 or IPv6 address, and a boolean value -//that indicates whether the IP address was present in the geoip database -func getCountryByAddr(table geoIPTable, ip net.IP) (string, bool) { - - table.Lock() - defer table.Unlock() - - //look IP up in database - index := sort.Search(table.Len(), func(i int) bool { - entry := table.ElementAt(i) - return (bytes.Compare(ip.To16(), entry.ipHigh.To16()) <= 0) - }) - - if index == table.Len() { - return "", false - } - - // check to see if addr is in the range specified by the returned index - // search on IPs in invalid ranges (e.g., 127.0.0.0/8) will return the - //country code of the next highest range - entry := table.ElementAt(index) - if !(bytes.Compare(ip.To16(), entry.ipLow.To16()) >= 0 && - bytes.Compare(ip.To16(), entry.ipHigh.To16()) <= 0) { - return "", false - } - - return table.ElementAt(index).country, true - -} diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/.gitlab-ci.yml snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/.gitlab-ci.yml --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/.gitlab-ci.yml 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/.gitlab-ci.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -test: - image: golang:bullseye - script: - - test -z "$(go fmt ./...)" - - go vet ./... - - go test -v ./... diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.mod snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.mod --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.mod 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.mod 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -module gitlab.torproject.org/tpo/anti-censorship/geoip - -go 1.15 - -require github.com/smartystreets/goconvey v1.6.4 diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.sum snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.sum --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.sum 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/go.sum 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -git.torproject.org/pluggable-transports/snowflake.git v1.1.0 h1:rl/LloEeBG1sqdZdVxdW1Gmb/c3ZjdvT5o3RV8iaDg4= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/LICENSE snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/LICENSE --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/LICENSE 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ - This file contains the license for "geoip" - -================================================================================ -Copyright (c) 2021, The Tor Project, Inc - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - - * Neither the names of the copyright owners nor the names of its -contributors may be used to endorse or promote products derived from this -software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -================================================================================ diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/README.md snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/README.md --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/README.md 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/README.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# geoip go library - -Get the country code for an IP address using the tor's geoip database. - -### example - -Needs the path of the geoip database in the initialization. For example in -debian it is provided by `tor-geoipdb` and the path is `/usr/share/tor/geoip` -and `/usr/share/tor/geoip6`. - -```go -geo, err := geoip.New("/usr/share/tor/geoip", "/usr/share/tor/geoip6") -if err != nil { - // Handle error -} - -ip := net.ParseIP("12.13.14.15") -country, ok := geo.GetCountryByAddr(ip) -if !ok { - fmt.Println("Not found any country for the IP") -} else { - fmt.Println("The ip corresponds to the country:", country) -} -``` diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip 1970-01-01 00:00:00.000000000 +0000 @@ -1,1236 +0,0 @@ -# Last updated based on February 7 2018 Maxmind GeoLite2 Country -# wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz -# gunzip GeoLite2-Country.mmdb.gz -# python mmdb-convert.py GeoLite2-Country.mmdb -16777216,16777471,AU -16777472,16778239,CN -16778240,16779263,AU -16779264,16781311,CN -16781312,16785407,JP -16785408,16793599,CN -16793600,16809983,JP -16809984,16842751,TH -16842752,16843007,CN -16843008,16843263,AU -16843264,16859135,CN -16859136,16875519,JP -16875520,16908287,TH -16908288,16909055,CN -16909056,16909311,US -16909312,16941055,CN -16941056,16973823,TH -16973824,17039359,CN -17039360,17039615,AU -2111307776,2111832063,CN -2111832064,2112487423,TW -2112487424,2112618495,VN -2112618496,2112880639,NZ -2112880640,2113560063,KR -2113560064,2113560319,SG -2113560320,2113683455,KR -2113683456,2113684607,JP -2113684608,2113684671,TW -2113684672,2113685663,JP -2113685664,2113685695,SG -2113685696,2113687999,JP -2113688000,2113688031,AU -2113688032,2113688959,JP -2113688960,2113688991,SG -2113688992,2113691135,JP -2113691136,2113691391,SG -2113691392,2113692415,JP -2113692416,2113692671,HK -2113692672,2113693599,JP -2113693600,2113693615,HK -2113693616,2113693879,JP -2113693880,2113693887,AU -2113693888,2113693951,JP -2113693952,2113694207,HK -2113694208,2113695279,JP -2113695280,2113695287,SG -2113695288,2113716223,JP -2113716224,2113724927,SG -2113724928,2113725183,IN -2113725184,2113728511,SG -2113728512,2113732607,JP -2113732608,2113761279,AU -2113761280,2113765375,VN -2113765376,2113798143,HK -2113798144,2113811455,AU -2113811456,2113812479,GB -2113812480,2113813503,JP -2113813504,2113830911,AU -2113830912,2113863679,CN -2113863680,2113929215,AU -2113929216,2130706431,JP -2147483648,2147483903,NL -2147483904,2147484671,RO -2147484672,2147485695,TR -2147485696,2147487743,DK -2147487744,2147489791,NO -2147489792,2147491839,RU -2147491840,2147494911,DE -2147494912,2147495167,RO -2147495168,2147495423,DE -2147495424,2147496959,RO -2147496960,2147497215,ES -2147497216,2147497471,RO -2147497472,2147497727,PL -2147497728,2147498239,DE -2147498240,2147498495,RO -2147498496,2147500031,DE -2147500032,2147501055,NL -2147501056,2147501311,SK -2147501312,2147501567,NL -2147501568,2147501823,GL -2147501824,2147502079,US -2147502080,2147504127,DK -2147504128,2147508223,RU -2147508224,2147510271,DE -2147510272,2147510783,UA -2147510784,2147511039,RU -2147511040,2147512319,CY -2147512320,2147514879,DE -2147514880,2147516415,IT -2147516416,2147520511,RU -2147520512,2147524607,DE -2147524608,2147526655,RU -2147526656,2147528703,UA -2147528704,2147532799,CZ -2147532800,2147534847,DE -2147534848,2147549183,CY -2147549184,2147557375,US -2147557376,2147557631,TW -2147557632,2147557887,SG -2147557888,2147558143,DE -2147558144,2147558399,TH -2147558400,2147558655,KR -2147558656,2147558911,TW -2147558912,2147559167,SG -2147559168,2147559423,TH -2147559424,2147559679,SG -2147559680,2147559935,US -2147559936,2147560191,DE -2147560192,2147560447,RU -2147560448,2147560703,TH -2147560704,2147560959,TW -2147560960,2147562239,US -2147562240,2147562495,RU -2147562496,2147563263,US -2147563264,2147563519,RU -2147563520,2147564287,US -2147564288,2147564543,AE -2147564544,2147564799,US -2147564800,2147565055,SG -2147565056,2147565311,HK -2147565312,2147565999,TW -2147566000,2147566047,JP -2147566048,2147566079,TW -2147566080,2147569407,US -2147569408,2147569663,TH -2147569664,2147570431,US -2147570432,2147570687,JP -2147570688,2147571455,US -2147571456,2147571711,SG -2147571712,2147573503,US -2147573504,2147573759,SG -2147573760,2147575039,US -2147575040,2147575551,TW -2147575552,2147575807,SG -2147575808,2147576575,US -2147576576,2147576831,TW -2147576832,2147577087,TH -2147577088,2147577599,ID -2147577600,2147579647,US -2147579648,2147579903,ID -2147579904,2147580927,US -2147580928,2147581183,ID -2147581184,2147581439,TH -2147581440,2147592703,US -2147592704,2147592959,HK -2147592960,2147600127,US -2147600128,2147600383,SG -2147600384,2147603711,US -2147603712,2147603967,IN -2147603968,2147942399,US -2147942400,2148007935,DE -2148007936,2148220515,US -2148220516,2148220535,AU -2148220536,2148229151,US -2148229152,2148229183,CA -2148229184,2148459007,US -2148459008,2148459519,TW -2148459520,2148532223,US -2148532224,2148597759,GB -2148597760,2148925439,US -2148925440,2148990975,JP -2148990976,2149253119,US -2149253120,2149384191,JP -2149384192,2150039551,US -2150039552,2150105087,NO -2150105088,2150203391,GB -2150203392,2150236159,AF -2150236160,2150301695,US -2150301696,2150367231,CA -2150367232,2150432767,US -2150432768,2150498303,IT -2150498304,2150957055,US -2150957056,2151022591,JP -2151022592,2151743487,US -2151743488,2151759871,BY -2151759872,2151768063,US -2151768064,2151770111,GB -2151770112,2151772159,BA -2151772160,2151776255,IT -2151776256,2151778303,AT -2151778304,2151780351,RU -2151780352,2151782399,DE -2151782400,2151784447,ES -2151784448,2151792639,IR -2151792640,2151794687,CH -2151794688,2151796735,IT -2151796736,2151800831,DE -2151800832,2151809023,PT -2151809024,2151940095,IT -2151940096,2152464383,RU -2152464384,2152529919,DK -2152529920,2152562687,NO -2152562688,2152595455,DK -2152595456,2152726527,FR -2152726528,2153119743,US -2153119744,2153185279,GB -2153185280,2153250815,SE -2153250816,2153381887,US -2153381888,2153382143,JP -2153382144,2153383679,US -2153383680,2153383935,HK -2153383936,2153384447,US -2153384448,2153385471,GB -2153385472,2153385599,AT -2153385600,2153385663,CZ -2153385664,2153385727,FI -2153385728,2153385791,PL -2153385792,2153385855,PT -2153385856,2153385919,TR -2153385920,2153385983,US -2153385984,2153387007,GB -2153387008,2153387263,CH -2153387264,2153387519,IS -2153387520,2153387775,IE -2153387776,2153388031,CH -2153388032,2153388287,ES -2153388288,2153388543,PL -2153388544,2153391615,US -2153391616,2153391871,HK -2153391872,2153394431,US -2153394432,2153394943,SG -2153394944,2153395455,US -2153395456,2153395711,VN -2153395712,2153396991,US -2153396992,2153397247,IL -2153397248,2153397503,IN -2153397504,2153397759,SA -2153397760,2153398015,QA -2153398016,2153398271,BH -2153398272,2153398783,JP -2153398784,2153399551,US -2153399552,2153399807,KR -2153399808,2153400319,HK -2153400320,2153401087,TW -2153401088,2153401599,MO -2153401600,2153402111,VN -2153402112,2153402367,PH -2153402368,2153403135,KR -2153403136,2153406463,US -2153406464,2153407487,JP -2153407488,2153407743,HK -2153407744,2153407999,AE -2153408000,2153408511,BR -2153408512,2153408767,AU -2153408768,2153409023,PA -2153409024,2153409279,AR -2153409280,2153409535,CR -2153409536,2153409791,CO -2153409792,2153410047,MX -2153410048,2153410303,CA -2153410304,2153410559,TW -2153410560,2153410815,PA -2153410816,2153411071,AR -2153411072,2153411327,CR -2153411328,2153411583,CO -2153411584,2153411839,MX -2153411840,2153412095,SV -2153412096,2153412351,TW -2153412352,2153412607,UY -2153412608,2153413119,AU -2153413120,2153413631,BR -2153413632,2153578495,US -2153578496,2153644031,FR -2153644032,2153906175,US -2153906176,2153971711,GB -2153971712,2154037247,US -2154037248,2154102783,CA -2154102784,2154430463,US -2154430464,2154495999,SG -2154496000,2154561535,US -2154561536,2154627071,CN -2154627072,2155610111,US -2155610112,2155675647,UA -2155675648,2155806719,US -2155806720,2155808767,IT -2155810816,2155812863,FR -2155812864,2155814911,GB -2155814912,2155819007,NL -2155819008,2155819519,DE -2155819520,2155821055,CH -2155821056,2155823103,IT -2155823104,2155825151,DE -2155825152,2155827199,AE -2155827200,2155831295,PL -2155831296,2155833343,RU -2155833344,2155833855,SE -2155833856,2155834623,NL -2155834624,2155834879,LU -2155834880,2155835391,NL -2155835392,2155839487,RO -2155839488,2155843583,FR -2155843584,2155845631,RU -2155845632,2155847679,DE -2155847680,2155849727,ES -2155849728,2155851775,TR -2155853824,2155855871,SE -2155855872,2155872255,SA -2155872256,2156003327,US -2156003328,2156134399,AT -2156134400,2156265471,US -2156265472,2156331007,KR -2156331008,2156593151,US -2156593152,2156658687,IL -2156658688,2156691455,IR -2156691456,2156697599,FR -2156697600,2156699647,GR -2156699648,2156703743,RU -2156703744,2156707839,BG -2156707840,2156709887,RU -2156709888,2156711935,ES -2156711936,2156713983,DE -2156713984,2156716031,NL -2156716032,2156718079,RO -2156718080,2156720127,IS -2156720128,2156724223,BY -2156724224,2156855295,CH -2156855296,2156920831,US -2156920832,2156986367,CA -2156986368,2159017983,US -2159017984,2159083519,DE -2159083520,2159149055,US -2159149056,2159280127,CH -2159280128,2159542271,US -2159542272,2159607807,AU -2159607808,2159673343,IN -2159673344,2159869951,US -2159869952,2159935487,CA -2159935488,2160525311,US -2160525312,2160533503,SG -2160533504,2160541695,NL -2160541696,2160590847,SG -2160590848,2160656383,US -2160656384,2160657407,BR -2160657408,2160658431,HN -2160658432,2160661503,BR -2160661504,2160662527,AR -2160662528,2160664575,BR -2160664576,2160666623,CL -2160666624,2160676863,BR -2160676864,2160677887,AR -2160677888,2160678911,BR -2160678912,2160679935,GF -2160679936,2160684031,BR -2160684032,2160685055,AR -2160685056,2160686079,DO -2160686080,2160687103,CL -2160687104,2160690175,BR -2160690176,2160691199,AR -2160691200,2160693247,BR -2160693248,2160694271,CR -2160694272,2160697343,BR -2160697344,2160698367,EC -2160698368,2160699391,BR -2160699392,2160700415,AR -2160700416,2160713727,BR -2160713728,2160714751,CL -2160714752,2160716799,BR -2160716800,2160717823,AR -2160717824,2160721919,BR -2160721920,2160852991,US -2160852992,2160885759,RU -2160885760,2160893951,AT -2160893952,2160902143,RU -2160902144,2160906239,NL -2160906240,2160908287,FR -2160908288,2160910335,PL -2160910336,2160914431,NL -2160914432,2160918527,SA -2160918528,2161508351,US -2161508352,2161573887,FI -2161573888,2162687999,US -2162688000,2162753535,GB -2162753536,2162819071,CA -2162819072,2162884607,SA -2162884608,2163212287,US -2163212288,2163277823,GB -2163277824,2163408895,US -2163408896,2163474431,GB -2163474432,2163605503,US -2163605504,2163638271,DE -2163638272,2163638527,US -2163638528,2163671039,DE -2163671040,2163867647,US -2163867648,2163933183,AU -2163933184,2164260863,US -2164260864,2164326399,CM -2164326400,2164981759,US -2164981760,2165112831,GB -2165112832,2165178367,DE -2165178368,2165309439,US -2165309440,2165374975,SE -2165374976,2165440511,US -2165440512,2165506047,NG -2165506048,2165571583,US -2165571584,2165637119,FR -2165637120,2165964799,US -2165964800,2166030335,DE -2166030336,2166095871,AT -2166095872,2166161407,CN -2166161408,2166292479,US -2166292480,2166358015,GB -2166358016,2166562559,US -2166562560,2166562815,FI -2166562816,2166571007,US -2166571008,2166575103,GB -2166575104,2166594559,US -2166594560,2166594815,PL -2166594816,2166729471,US -2166729472,2166729727,CA -2166729728,2167209983,US -2167209984,2167242751,DZ -2167242752,2167275519,BF -2167275520,2167930879,US -2167930880,2167996415,NG -2167996416,2168193023,US -2168193024,2168258559,JP -2168258560,2168651775,US -2168651776,2168717311,GB -2168717312,2168782847,US -2168782848,2168913919,DE -2168913920,2169372671,US -2169372672,2169438207,AU -2169438208,2170028031,US -2170028032,2170093567,FR -2170093568,2170159103,US -2170159104,2170224639,VE -2170224640,2170421247,US -2170421248,2170486783,AU -2170486784,2170552319,US -2170552320,2170617855,AU -2170617856,2170683391,CA -2170683392,2170814463,US -2170814464,2170879999,CA -2170880000,2170945535,US -2170945536,2171011071,FR -3652593408,3652593471,ES -3652593472,3652593511,FR -3652593512,3652593519,ES -3652593520,3652593631,FR -3652593632,3652593663,PT -3652593664,3652593943,FR -3652593944,3652593951,ES -3652593952,3652595007,FR -3652595008,3652595071,DE -3652595072,3652595167,FR -3652595168,3652595183,ES -3652595184,3652595871,FR -3652595872,3652595935,PL -3652595936,3652596351,FR -3652596352,3652596415,IT -3652596416,3652596479,FR -3652596480,3652596543,ES -3652596544,3652596799,FR -3652596800,3652596831,CZ -3652596832,3652597183,FR -3652597184,3652597247,DE -3652597248,3652597375,FR -3652597376,3652597383,ES -3652597384,3652597407,FR -3652597408,3652597439,PL -3652597440,3652597887,FR -3652597888,3652597903,GB -3652597904,3652599569,FR -3652599570,3652599570,PT -3652599571,3652599679,FR -3652599680,3652599743,IT -3652599744,3652601855,FR -3652601856,3652603903,PL -3652603904,3652608191,FR -3652608192,3652608223,PT -3652608224,3652608255,FR -3652608256,3652608511,GB -3652608512,3652608639,FR -3652608640,3652608767,GB -3652608768,3652609023,FR -3652609024,3652609279,GB -3652609280,3652609503,FR -3652609504,3652609535,FI -3652609536,3652609727,FR -3652609728,3652609759,PL -3652609760,3652609791,CZ -3652609792,3652609823,FR -3652609824,3652609855,CZ -3652609856,3652609919,FR -3652609920,3652609983,ES -3652609984,3652610047,BE -3652610048,3652611135,FR -3652611136,3652611199,ES -3652611200,3652611231,FR -3652611232,3652611263,PT -3652611264,3652611679,FR -3652611680,3652611711,PT -3652611712,3652611775,NL -3652611776,3652612223,FR -3652612224,3652612287,ES -3652612288,3652612351,FR -3652612352,3652612479,GB -3652612480,3652612543,IE -3652612544,3652612607,NL -3652612608,3652613335,FR -3652613336,3652613343,ES -3652613344,3652613375,FR -3652613376,3652613407,FI -3652613408,3652613615,FR -3652613616,3652613623,ES -3652613624,3652613679,FR -3652613680,3652613695,LT -3652613696,3652614015,FR -3652614016,3652614079,BE -3652614080,3652615871,FR -3652615872,3652615935,DE -3652615936,3652620639,FR -3652620640,3652620671,CZ -3652620672,3652620735,PT -3652620736,3652620799,FR -3652620800,3652620831,PT -3652620832,3652621247,FR -3652621248,3652621311,DE -3652621312,3652621375,FR -3652621376,3652621439,ES -3652621440,3652621503,FR -3652621504,3652621567,IT -3652621568,3652621631,FR -3652621632,3652621663,PT -3652621664,3652621823,FR -3652621824,3652621951,IE -3652621952,3652622271,FR -3652622272,3652622335,GB -3652622336,3652622879,FR -3652622880,3652622911,CZ -3652622912,3652623679,FR -3652623680,3652623807,NL -3652623808,3652624191,FR -3652624192,3652624319,IT -3652624320,3652628479,FR -3652628480,3652628543,IT -3652628544,3652628607,FR -3652628608,3652628639,PL -3652628640,3652628855,FR -3652628856,3652628863,ES -3652628864,3652629743,FR -3652629744,3652629759,ES -3652629760,3652630015,FR -3652630016,3652630031,ES -3652630032,3652630079,FR -3652630080,3652630111,PL -3652630112,3652631295,FR -3652631296,3652631359,BE -3652631360,3652631391,FR -3652631392,3652631407,CH -3652631408,3652631423,FR -3652631424,3652631455,PL -3652631456,3652631551,FR -3652631552,3652631583,CZ -3652631584,3652631807,FR -3652631808,3652631823,GB -3652631824,3652632031,FR -3652632032,3652632063,PT -3652632064,3652632303,FR -3652632304,3652632311,ES -3652632312,3652633599,FR -3652633600,3652634623,DE -3652634624,3652635647,PL -3652635648,3652638655,FR -3652638656,3652638719,ES -3652638720,3652638815,FR -3652638816,3652638847,FI -3652638848,3652638975,GB -3652638976,3652639359,FR -3652639360,3652639423,DE -3652639424,3652639679,FR -3652639680,3652639807,NL -3652639808,3652640575,FR -3652640576,3652640703,GB -3652640704,3652640711,FR -3652640712,3652640719,ES -3652640720,3652640767,FR -3652640768,3652640831,ES -3652640832,3652641727,FR -3652641728,3652641791,GB -3652641792,3652642111,FR -3652642112,3652642175,IE -3652642176,3652642239,FR -3652642240,3652642303,DE -3652642304,3652642367,FR -3652642368,3652642431,GB -3652642432,3652642719,FR -3652642720,3652642751,PT -3652642752,3652642975,FR -3652642976,3652643007,IE -3652643008,3652643375,FR -3652643376,3652643379,ES -3652643380,3652643519,FR -3652643520,3652643583,NL -3652643584,3652643647,ES -3652643648,3652644031,FR -3652644032,3652644063,BE -3652644064,3652644199,FR -3652644200,3652644215,ES -3652644216,3652644223,FR -3652644224,3652644239,NL -3652644240,3652644247,FR -3652644248,3652644255,ES -3652644256,3652644351,FR -3652644352,3652644383,FI -3652644384,3652644415,PL -3652644416,3652644575,FR -3652644576,3652644607,DE -3652644608,3652645119,FR -3652645120,3652645503,GB -3652645504,3652645663,FR -3652645664,3652645695,FI -3652645696,3652645887,FR -3652645888,3652646015,NL -3652646016,3652646079,ES -3652646080,3652646111,FR -3652646112,3652646143,CZ -3652646144,3652646271,NL -3652646272,3652646655,FR -3652646656,3652646719,ES -3652646720,3652646799,FR -3652646800,3652646815,PL -3652646816,3652646847,FR -3652646848,3652646863,FI -3652646864,3652648847,FR -3652648848,3652648863,LT -3652648864,3652648895,FI -3652648896,3652648959,DE -3652648960,3652714495,IE -3652714496,3653238783,DE -3653238784,3653369855,CH -3653369856,3653373951,IT -3653373952,3653378047,NL -3653378048,3653382143,DE -3653382144,3653386239,CH -3653386240,3653390335,DE -3653390336,3653394431,FR -3653394432,3653402623,NL -3653402624,3653406557,GB -3653406558,3653406558,GN -3653406559,3653406617,GB -3653406618,3653406618,GN -3653406619,3653407103,GB -3653407104,3653407111,UG -3653407112,3653408071,GB -3653408072,3653408079,NG -3653408080,3653408231,GB -3653408232,3653408239,KE -3653408240,3653410815,GB -3653410816,3653414911,CZ -3653414912,3653419007,IT -3653419008,3653423103,IL -3653423104,3653427199,GB -3653427200,3653431295,DE -3653431296,3653435391,RU -3653435392,3653439487,DE -3653439488,3653443583,FR -3653443584,3653447679,DE -3653447680,3653451775,LV -3653451776,3653464063,RU -3653464064,3653468159,NL -3653468160,3653472255,GR -3653476352,3653480447,CZ -3653480448,3653484543,DK -3653484544,3653488639,TR -3653488640,3653492735,RU -3653492736,3653500927,NL -3653500928,3653505023,GB -3653505024,3653509119,KZ -3653509120,3653513215,NL -3653513216,3653517311,NO -3653517312,3653525503,AT -3653525504,3653529599,RU -3653529600,3653533695,CZ -3653533696,3653537791,IT -3653537792,3653541887,AT -3653541888,3653545983,UA -3653545984,3653550079,CH -3653550080,3653554175,MK -3653554176,3653558271,CZ -3653558272,3653566463,GB -3653566464,3653570559,RU -3653570560,3653574655,ES -3653574656,3653578751,CZ -3653578752,3653582847,SE -3653582848,3653586943,PL -3653586944,3653591039,DE -3653591040,3653595135,LU -3653595136,3653599231,RU -3653599232,3653601279,CH -3653601280,3653603327,BA -3653603328,3653607423,CZ -3653611520,3653615615,HU -3653615616,3653619711,RU -3653619712,3653623807,CH -3653623808,3653636095,RU -3653636096,3653640191,NL -3653640192,3653648383,GB -3653648384,3653652479,SE -3653652480,3653656575,RU -3653656576,3653660671,GB -3653660672,3653664767,CZ -3653664768,3653668863,DE -3653668864,3653672959,SE -3653672960,3653681151,RU -3653681152,3653685247,ES -3653685248,3653689343,DK -3653689344,3653693439,LV -3653693440,3653697535,DE -3653697536,3653705727,IT -3653705728,3653708331,NO -3653708332,3653708332,FI -3653708333,3653713919,NO -3653713920,3653718015,DE -3653718016,3653722111,AT -3653722112,3653730303,LV -3653730304,3653734399,BA -3653734400,3653738495,KE -3653738496,3653746687,GB -3653746688,3653750783,DE -3653750784,3653754879,RU -3653754880,3653758975,UA -3653758976,3653763071,RU -3653763072,3654025215,IT -3654025216,3654287359,GB -3654287360,3654608404,SE -3654608405,3654608405,NO -3654608406,3654608895,SE -3654608896,3654609919,NO -3654609920,3654610431,SE -3654610432,3654610943,FR -3654610944,3654610951,SE -3654610952,3654610959,DE -3654610960,3654612231,SE -3654612232,3654612239,AT -3654612240,3654612271,SE -3654612272,3654612287,AT -3654612288,3654614047,SE -3654614048,3654614063,GB -3654614064,3654614079,SE -3654614080,3654614271,FI -3654614272,3654811647,SE -3654811648,3654942719,ES -3654942720,3655073791,IR -3655073792,3655335935,IT -3655335936,3657433087,DE -3657433088,3659415455,CN -3659415456,3659415487,SG -3659415488,3659530239,CN -3659530240,3659595775,TW -3659595776,3659628543,ID -3659628544,3659661311,JP -3659661312,3659792383,TW -3659792384,3660054527,KR -3660054528,3660578815,JP -3660578816,3661103103,KR -3661103104,3663986687,CN -3663986688,3663987711,AU -3663987712,3663987967,ID -3663987968,3663989247,JP -3663989248,3663989503,VN -3663989504,3663989759,ID -3663989760,3663990271,AU -3663990272,3663990527,VN -3663990528,3663990783,JP -3663990784,3663991295,HK -3663991296,3663991551,MY -3663991552,3663991807,AU -3663992064,3663992319,NZ -3663992320,3663992575,MY -3663992576,3663993599,NZ -3663993600,3663996159,ID -3663996160,3663996415,AU -3663996416,3663996671,TH -3663996672,3663997183,AU -3663997184,3663997439,ID -3663997440,3663997695,JP -3663997696,3663997951,AU -3663997952,3663998207,MY -3663998208,3663998463,JP -3663998464,3663998975,TH -3663998976,3663999487,IN -3663999488,3663999743,AU -3664000000,3664000767,AU -3664000768,3664001023,ID -3664001024,3664001279,NZ -3664001280,3664001535,LK -3664001536,3664001791,MY -3664002048,3664002303,VN -3664002304,3664002559,LK -3664002560,3664003327,ID -3664003328,3664003583,NZ -3664003584,3664003839,TH -3664003840,3664004095,JP -3664004352,3664004607,MY -3664004864,3664005119,KH -3664005120,3664005887,ID -3664005888,3664006143,MY -3664006144,3664006399,AU -3664006400,3664006655,PF -3664006656,3664006911,AU -3664007168,3664008191,AU -3664008192,3664008447,MN -3664008448,3664008703,PK -3664008960,3664010239,AU -3664010240,3664052223,CN -3664052224,3664084991,NZ -3664084992,3664117759,KR -3664117760,3664248831,HK -3664248832,3664642047,CN -3664642048,3664707583,JP -3664707584,3664773119,MY -3664773120,3666870271,JP -3666870272,3666960455,KR -3666960456,3666960456,US -3666960457,3667918847,KR -3667918848,3668967423,TW -3668967424,3669491711,JP -3669491712,3669557247,TW -3669557248,3669590015,AU -3669590016,3669606399,JP -3669606400,3669614591,CN -3669614592,3669616639,NZ -3669616640,3669618687,AU -3669618688,3669620735,CN -3669620736,3669622783,IN -3669622784,3669688319,SG -3669688320,3669753855,TW -3669753856,3670015999,HK -3670016000,3671064575,CN -3671064576,3671130111,MY -3671130112,3671195647,KR -3671195648,3671326719,TW -3671326720,3671392255,SG -3671392256,3671457791,HK -3671457792,3671588863,AU -3671588864,3672637439,JP -3672637440,3673161727,KR -3673161728,3673686015,CN -3673686016,3673751551,IN -3673751552,3673817087,CN -3673817088,3673882623,HK -3673882624,3673948159,JP -3673948160,3674210303,HK -3674210304,3678404607,JP -3678404608,3678535679,IN -3678535680,3678666751,JP -3678666752,3678928895,TW -3678928896,3678994431,CN -3678994432,3679027199,HK -3679027200,3679059967,JP -3679059968,3679158271,SG -3679158272,3679191039,JP -3679191040,3679453183,HK -3679453184,3679584255,TW -3679584256,3679649791,CN -3679649792,3679682559,ID -3679682560,3679715327,CN -3679715328,3679977471,TW -3679977472,3680108543,NZ -3680108544,3680124927,TW -3680124928,3680125951,IN -3680125952,3680129023,CN -3680129024,3680133119,PH -3680133120,3680137215,IN -3680137216,3680141311,HK -3680141312,3680174079,AU -3680174080,3680206847,TW -3680206848,3680239615,IN -3680239616,3680403455,MY -3680403456,3680436223,JP -3680436224,3680501759,MY -3680501760,3682598911,JP -3682598912,3684575268,CN -3684575269,3684575269,HK -3684575270,3684696063,CN -3684696064,3688366079,JP -3688366080,3689938943,CN -3689938944,3690070015,KR -3690070016,3690463231,CN -3690463232,3690987519,KR -3690987520,3695181823,JP -3695181824,3697278975,KR -3697278976,3697573887,JP -3697573888,3697582079,GB -3697582080,3697586175,SG -3697586176,3697606655,JP -3697606656,3697655807,AU -3697655808,3697672191,CN -3697672192,3697737727,JP -3697737728,3697803263,KR -3697803264,3698327551,JP -3698327552,3698589695,CN -3698589696,3699376127,KR -3699376128,3700424703,TW -3700424704,3700752383,JP -3700752384,3700817919,KR -3700817920,3700981759,JP -3700981760,3701014527,CN -3701014528,3701080063,JP -3701080064,3701211135,CN -3701211136,3701252095,JP -3701252096,3701256191,NC -3701256192,3701258239,SG -3701258240,3701260287,IN -3701260288,3701293055,JP -3701293056,3701301247,AU -3701301248,3701305343,ID -3701305344,3701309439,TW -3701309440,3701374975,JP -3701374976,3701375999,IN -3701376000,3701377023,HK -3701377024,3701380095,IN -3701380096,3701381119,KH -3701381120,3701390335,IN -3701390336,3701391359,AU -3701391360,3701392383,IN -3701392384,3701393407,HK -3701393408,3701394431,MY -3701394432,3701395455,BD -3701395456,3701396479,MY -3701396480,3701397247,NZ -3701397248,3701397503,AU -3701397504,3701398527,JP -3701398528,3701399551,MV -3701399552,3701400575,HK -3701400576,3701401599,TW -3701401600,3701402623,BD -3701402624,3701403647,BT -3701403648,3701404671,CN -3701404672,3701405695,HK -3701405696,3701406719,JP -3701406720,3701407743,HK -3701407744,3701473279,JP -3701473280,3704619007,CN -3704619008,3705667583,JP -3705667584,3705929727,IN -3705929728,3706060799,TW -3706060800,3706126335,KR -3706126336,3706142719,CN -3706142720,3706159103,VN -3706159104,3706191871,CN -3706191872,3706207107,SG -3706207108,3706207108,US -3706207109,3706208255,SG -3706208256,3706224639,CN -3706224640,3706225663,HK -3706225664,3706226687,JP -3706226688,3706231807,HK -3706231808,3706232831,JP -3706232832,3706233343,HK -3706233344,3706234367,JP -3706234368,3706237951,HK -3706237952,3706238975,JP -3706238976,3706244095,HK -3706244096,3706244863,JP -3706244864,3706245887,HK -3706245888,3706246143,JP -3706246144,3706253823,HK -3706253824,3706254335,JP -3706254336,3706256895,HK -3706256896,3706257151,JP -3706257152,3706257407,HK -3706257408,3706322943,AU -3706322944,3706388479,CN -3706388480,3706781695,AU -3706781696,3706847231,HK -3706847232,3706978303,CN -3706978304,3707109375,AU -3707109376,3707174911,HK -3707174912,3707207679,JP -3707207680,3707208703,BD -3707208704,3707209727,NZ -3707209728,3707211775,CN -3707211776,3707215871,NP -3707215872,3707217919,BD -3707217920,3707219967,ID -3707219968,3707222015,AU -3707222016,3707224063,JP -3707224064,3707240447,LK -3707240448,3707568127,CN -3707568128,3707633663,AU -3707633664,3707699199,JP -3707699200,3707764735,SG -3707764736,3708600319,CN -3708600320,3708616703,JP -3708616704,3708813311,CN -3708813312,3715629055,JP -3715629056,3715653631,TW -3715653632,3715655679,BD -3715655680,3715657727,IN -3715657728,3715661823,SG -3715661824,3715670015,AU -3715670016,3715671039,KH -3715671040,3715672063,AU -3715672064,3715674111,JP -3715674112,3715678207,HK -3715678208,3715694591,PK -3715694592,3715710975,VN -3715710976,3715719167,AU -3715719168,3715727359,PH -3715727360,3715729151,AU -3715729152,3715729407,NZ -3715729408,3715735551,AU -3715735552,3715741695,JP -3715741696,3715743743,PH -3715743744,3715760127,JP -3715760128,3715891199,CN -3715891200,3716153343,HK -3716153344,3716170239,SG -3716170240,3716170494,TH -3716170495,3716171519,SG -3716171520,3716171775,JP -3716171776,3716172031,SG -3716172032,3716172287,JP -3716172288,3716173055,SG -3716173056,3716173311,JP -3716173312,3716173567,SG -3716173568,3716173823,JP -3716173824,3716174079,SG -3716174080,3716174083,TH -3716174084,3716174335,JP -3716174336,3716175615,SG -3716175616,3716176895,JP -3716176896,3716178175,SG -3716178176,3716178943,JP -3716178944,3716179967,SG -3716179968,3716181759,JP -3716181760,3716182783,SG -3716182784,3716183295,JP -3716183296,3716183551,SG -3716183552,3716184063,JP -3716184064,3716184319,SG -3716184320,3716184575,JP -3716184576,3716184831,SG -3716184832,3716185087,JP -3716185088,3716186111,SG -3716186112,3716415487,CN -3716415488,3716431871,VN -3716431872,3716440063,KR -3716440064,3716444159,JP -3716444160,3716446207,PK -3716446208,3716464639,JP -3716464640,3716481023,ID -3716481024,3716489215,VN -3716489216,3716493311,MY -3716493312,3716497407,KR -3716497408,3716513791,JP -3716513792,3716530175,KR -3716530176,3716538367,AU -3716538368,3716546559,CN -3716546560,3716677631,IN -3716677632,3716808703,CN -3716808704,3718840319,KR -3718840320,3718905855,TW -3718905856,3719036927,JP -3719036928,3719823359,CN -3719823360,3720347647,JP -3720347648,3720859647,CN -3720859648,3720863743,AU -3720863744,3723493375,CN -3723493376,3725590527,JP -3725590528,3730833407,CN -3730833408,3732602879,KR -3732602880,3732668415,TH -3732668416,3732733951,ID -3732733952,3732799487,CN -3732799488,3732832255,PH -3732832256,3732865023,CN -3732865024,3732930559,PH -3732930560,3733979135,CN -3733979136,3734503423,JP -3734503424,3734765567,NZ -3734765568,3734896639,TW -3734896640,3735027711,JP -3735027712,3735289855,CN -3735289856,3735388159,SG -3735388160,3735404543,LK -3735404544,3735420927,ID -3735420928,3735551999,HK -3735552000,3739222015,CN -3739222016,3739570175,JP -3739570176,3739572223,ID -3739572224,3739574271,AU -3739574272,3739680767,JP -3739680768,3739697151,KR -3739697152,3739746303,JP -3739746304,3740270591,KR -3740270592,3740925951,CN -3740925952,3741024255,TW -3741024256,3741057023,KR -3741057024,3741319167,VN -3741319168,3742367743,CN -3742367744,3742629887,HK -3742629888,3742760959,CN -3742760960,3742892031,TW -3742892032,3742957567,TH -3742957568,3742973951,PH -3742973952,3742982143,SG -3742982144,3742986239,ID -3742986240,3742988287,AU -3742988288,3742990335,VU -3742990336,3743006719,JP -3743006720,3743014911,TH -3743014912,3743016959,AU -3743016960,3743019007,SG -3743019008,3743022079,MY -3743022080,3743023103,BD -3743023104,3743027199,TW -3743027200,3743028223,IN -3743028224,3743029247,AF -3743029248,3743030271,NZ -3743030272,3743035391,IN -3743035392,3743039487,HK -3743039488,3743055871,TW -3743055872,3743088639,KR -3743088640,3743093647,AU -3743093648,3743093648,NZ -3743093649,3743096831,AU -3743096832,3743105023,TW -3743105024,3743106047,AU -3743106048,3743109119,JP -3743109120,3743113215,BD -3743113216,3743115263,AU -3743115264,3743117311,VN -3743117312,3743118335,BD -3743118336,3743119359,JP -3743119360,3743120383,IN -3743120384,3743121407,JP -3743121408,3743125503,MY -3743125504,3743129599,ID -3743129600,3743130623,HK -3743130624,3743130879,SG -3743130880,3743131135,HK -3743131136,3743133695,SG -3743133696,3743134719,AU -3743134720,3743135743,JP -3743135744,3743136767,CN -3743136768,3743137791,MY -3743137792,3743154175,TH -3743154176,3743186943,MY -3743186944,3743219711,KR -3743219712,3743252479,JP -3743252480,3743264767,NC -3743264768,3743268863,JP -3743268864,3743272959,IN -3743272960,3743273983,CN -3743273984,3743275007,BD -3743275008,3743276031,HK -3743276032,3743277055,IN -3743277056,3743281151,PK -3743281152,3743282175,AU -3743282176,3743283199,JP -3743283200,3743284223,HK -3743284224,3743285247,CN -3743285248,3743416319,IN -3743416320,3745513471,KR -3745513472,3749052415,CN -3749052416,3749183487,HK -3749183488,3749838847,CN -3749838848,3749839871,SG -3749839872,3749840895,IN -3749840896,3749841919,CN -3749841920,3749842943,AU -3749842944,3749843967,PH -3749843968,3749844991,ID -3749844992,3749846015,AU -3749846016,3749847039,IN -3749847040,3749855231,HK -3749855232,3749969919,KR -3749969920,3750232063,JP -3750232064,3750756351,TW -3750756352,3752067071,CN -3752067072,3752132607,ID -3752132608,3752133631,BD -3752133632,3752134655,ID -3752134656,3752136703,TW -3752136704,3752137727,NZ -3752137728,3752138751,JP -3752138752,3752140799,IN -3752140800,3752148991,JP -3752148992,3752153087,NZ -3752153088,3752157183,JP -3752157184,3752165375,AU -3752165376,3752198143,KR -3752198144,3752329215,CN -3752329216,3752853503,KR -3752853504,3753902079,IN -3753902080,3754033151,CN -3754033152,3754164223,KR -3754164224,3754229759,IN -3754229760,3754295295,HK -3754295296,3754426367,CN -3754426368,3754491903,TW -3754491904,3754688511,CN -3754688512,3754950655,TH -3754950656,3755474943,CN -3755474944,3755737087,JP -3755737088,3755868159,CN -3755868160,3755933695,KR -3755933696,3755966463,JP -3755966464,3755974655,IN -3755974656,3755976703,JP -3755976704,3755978751,KH -3755978752,3755986943,CN -3755986944,3755988991,JP -3755988992,3755990015,HK -3755990016,3755991039,SG -3755991040,3755999231,JP -3755999232,3757047807,IN -3757047808,3757834239,CN -3757834240,3757850623,AU -3757850624,3757858815,JP -3757858816,3757862911,AU -3757862912,3757867007,JP -3757867008,3757875519,CN -3757875520,3757875583,HK -3757875584,3757899775,CN -3757899776,3757965311,KR -3757965312,3758063615,CN -3758063616,3758079999,HK -3758080000,3758088191,KR -3758088192,3758090239,ID -3758090240,3758091263,AU -3758091264,3758092287,CN -3758092288,3758093311,HK -3758093312,3758094335,IN -3758094336,3758095359,HK -3758095360,3758095871,CN -3758095872,3758096127,SG -3758096128,3758096383,AU diff -Nru snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip6 snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip6 --- snowflake-2.2.0/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip6 2022-06-15 05:16:33.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/gitlab.torproject.org/tpo/anti-censorship/geoip/test_geoip6 1970-01-01 00:00:00.000000000 +0000 @@ -1,693 +0,0 @@ -# Last updated based on February 7 2018 Maxmind GeoLite2 Country -# wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz -# gunzip GeoLite2-Country.mmdb.gz -# python mmdb-convert.py GeoLite2-Country.mmdb -600:8801:9400:5a1:948b:ab15:dde3:61a3,600:8801:9400:5a1:948b:ab15:dde3:61a3,US -2001:200::,2001:200:ffff:ffff:ffff:ffff:ffff:ffff,JP -2001:208::,2001:208:ffff:ffff:ffff:ffff:ffff:ffff,SG -2001:218::,2001:218:ffff:ffff:ffff:ffff:ffff:ffff,JP -2001:220::,2001:220:ffff:ffff:ffff:ffff:ffff:ffff,KR -2001:230::,2001:230:ffff:ffff:ffff:ffff:ffff:ffff,KR -2001:238::,2001:238:ffff:ffff:ffff:ffff:ffff:ffff,TW -2001:240::,2001:240:ffff:ffff:ffff:ffff:ffff:ffff,JP -2620:21:2000::,2620:21:2000:ffff:ffff:ffff:ffff:ffff,US -2620:21:4000::,2620:21:4000:ffff:ffff:ffff:ffff:ffff,US -2620:21:6000::,2620:21:600f:ffff:ffff:ffff:ffff:ffff,US -2620:21:8000::,2620:21:8000:ffff:ffff:ffff:ffff:ffff,US -2620:21:a000::,2620:21:a000:ffff:ffff:ffff:ffff:ffff,US -2620:21:c000::,2620:21:c000:ffff:ffff:ffff:ffff:ffff,CA -2620:21:e000::,2620:21:e000:ffff:ffff:ffff:ffff:ffff,US -2620:22::,2620:22::ffff:ffff:ffff:ffff:ffff,US -2620:22:2000::,2620:22:2000:ffff:ffff:ffff:ffff:ffff,US -2620:22:4000::,2620:22:4000:ffff:ffff:ffff:ffff:ffff,CA -2620:22:6000::,2620:22:6000:ffff:ffff:ffff:ffff:ffff,US -2620:c2:8000::,2620:c2:8000:ffff:ffff:ffff:ffff:ffff,US -2620:c2:c000::,2620:c2:c000:ffff:ffff:ffff:ffff:ffff,US -2620:c3::,2620:c3::ffff:ffff:ffff:ffff:ffff,US -2620:c3:4000::,2620:c3:4000:ffff:ffff:ffff:ffff:ffff,US -2620:c3:8000::,2620:c3:8000:ffff:ffff:ffff:ffff:ffff,US -2620:c3:c000::,2620:c3:c00f:ffff:ffff:ffff:ffff:ffff,US -2620:c4::,2620:c4::ffff:ffff:ffff:ffff:ffff,US -2620:c4:4000::,2620:c4:4000:ffff:ffff:ffff:ffff:ffff,US -2620:c4:8000::,2620:c4:8000:ffff:ffff:ffff:ffff:ffff,US -2620:c4:c000::,2620:c4:c000:ffff:ffff:ffff:ffff:ffff,CA -2620:c5::,2620:c5::ffff:ffff:ffff:ffff:ffff,US -2620:c5:4000::,2620:c5:4000:ffff:ffff:ffff:ffff:ffff,US -2620:c5:c000::,2620:c5:c000:ffff:ffff:ffff:ffff:ffff,US -2620:c6::,2620:c6::ffff:ffff:ffff:ffff:ffff,US -2620:c6:4000::,2620:c6:4000:ffff:ffff:ffff:ffff:ffff,US -2620:c6:8000::,2620:c6:8000:ffff:ffff:ffff:ffff:ffff,US -2620:c6:c000::,2620:c6:c000:ffff:ffff:ffff:ffff:ffff,US -2620:c7::,2620:c7::ffff:ffff:ffff:ffff:ffff,US -2620:c7:4000::,2620:c7:4000:ffff:ffff:ffff:ffff:ffff,US -2620:c7:8000::,2620:c7:8000:ffff:ffff:ffff:ffff:ffff,US -2620:c7:c000::,2620:c7:c000:ffff:ffff:ffff:ffff:ffff,US -2620:c8::,2620:c8::ffff:ffff:ffff:ffff:ffff,US -2620:c8:4000::,2620:c8:4000:ffff:ffff:ffff:ffff:ffff,US -2620:c8:c000::,2620:c8:c00f:ffff:ffff:ffff:ffff:ffff,US -2620:c9::,2620:c9::ffff:ffff:ffff:ffff:ffff,US -2620:c9:4000::,2620:c9:4000:ffff:ffff:ffff:ffff:ffff,US -2620:c9:8000::,2620:c9:8000:ffff:ffff:ffff:ffff:ffff,US -2620:c9:c000::,2620:c9:c000:ffff:ffff:ffff:ffff:ffff,US -2620:ca::,2620:ca::ffff:ffff:ffff:ffff:ffff,US -2620:ca:4000::,2620:ca:4000:ffff:ffff:ffff:ffff:ffff,US -2620:ca:8000::,2620:ca:8000:ffff:ffff:ffff:ffff:ffff,US -2620:ca:c000::,2620:ca:c000:ffff:ffff:ffff:ffff:ffff,US -2620:cb::,2620:cb:f:ffff:ffff:ffff:ffff:ffff,US -2620:cb:4000::,2620:cb:4000:ffff:ffff:ffff:ffff:ffff,US -2620:cb:8000::,2620:cb:8000:ffff:ffff:ffff:ffff:ffff,US -2620:cb:c000::,2620:cb:c000:ffff:ffff:ffff:ffff:ffff,US -2620:cc::,2620:cc::ffff:ffff:ffff:ffff:ffff,US -2620:cc:4000::,2620:cc:4000:ffff:ffff:ffff:ffff:ffff,US -2620:cc:8000::,2620:cc:8000:ffff:ffff:ffff:ffff:ffff,US -2620:cc:c000::,2620:cc:c000:ffff:ffff:ffff:ffff:ffff,US -2620:cd::,2620:cd::ffff:ffff:ffff:ffff:ffff,US -2620:cd:4000::,2620:cd:4000:ffff:ffff:ffff:ffff:ffff,US -2620:cd:8000::,2620:cd:8000:ffff:ffff:ffff:ffff:ffff,US -2620:cd:c000::,2620:cd:c000:ffff:ffff:ffff:ffff:ffff,US -2620:ce::,2620:ce::ffff:ffff:ffff:ffff:ffff,US -2620:ce:4000::,2620:ce:4000:ffff:ffff:ffff:ffff:ffff,US -2620:ce:8000::,2620:ce:8000:ffff:ffff:ffff:ffff:ffff,US -2620:ce:c000::,2620:ce:c000:ffff:ffff:ffff:ffff:ffff,US -2620:cf:4000::,2620:cf:4000:ffff:ffff:ffff:ffff:ffff,US -2620:cf:8000::,2620:cf:8000:ffff:ffff:ffff:ffff:ffff,US -2620:cf:c000::,2620:cf:c00f:ffff:ffff:ffff:ffff:ffff,US -2620:d0::,2620:d0::ffff:ffff:ffff:ffff:ffff,US -2620:d0:4000::,2620:d0:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d0:8000::,2620:d0:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d0:c000::,2620:d0:c000:ffff:ffff:ffff:ffff:ffff,US -2620:d1::,2620:d1::ffff:ffff:ffff:ffff:ffff,US -2620:d1:4000::,2620:d1:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d1:8000::,2620:d1:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d1:c000::,2620:d1:c000:ffff:ffff:ffff:ffff:ffff,US -2620:d2::,2620:d2::ffff:ffff:ffff:ffff:ffff,US -2620:d2:4000::,2620:d2:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d2:8000::,2620:d2:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d2:c000::,2620:d2:c000:ffff:ffff:ffff:ffff:ffff,CA -2620:d3:4000::,2620:d3:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d3:8000::,2620:d3:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d3:c000::,2620:d3:c000:ffff:ffff:ffff:ffff:ffff,US -2620:d4::,2620:d4::ffff:ffff:ffff:ffff:ffff,US -2620:d4:4000::,2620:d4:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d4:8000::,2620:d4:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d5::,2620:d5::ffff:ffff:ffff:ffff:ffff,US -2620:d5:4000::,2620:d5:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d5:8000::,2620:d5:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d5:c000::,2620:d5:c000:ffff:ffff:ffff:ffff:ffff,US -2620:d6::,2620:d6::ffff:ffff:ffff:ffff:ffff,US -2620:d6:4000::,2620:d6:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d6:8000::,2620:d6:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d6:c000::,2620:d6:c000:ffff:ffff:ffff:ffff:ffff,US -2620:d7::,2620:d7::ffff:ffff:ffff:ffff:ffff,US -2620:d7:4000::,2620:d7:4000:ffff:ffff:ffff:ffff:ffff,CA -2620:d7:8000::,2620:d7:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d7:c000::,2620:d7:c000:ffff:ffff:ffff:ffff:ffff,US -2620:d8::,2620:d8::ffff:ffff:ffff:ffff:ffff,US -2620:d8:4000::,2620:d8:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d8:8000::,2620:d8:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d8:c000::,2620:d8:c000:ffff:ffff:ffff:ffff:ffff,US -2620:d9::,2620:d9::ffff:ffff:ffff:ffff:ffff,US -2620:d9:4000::,2620:d9:4000:ffff:ffff:ffff:ffff:ffff,US -2620:d9:8000::,2620:d9:8000:ffff:ffff:ffff:ffff:ffff,US -2620:d9:c000::,2620:d9:c000:ffff:ffff:ffff:ffff:ffff,US -2620:da::,2620:da::ffff:ffff:ffff:ffff:ffff,US -2620:da:4000::,2620:da:4000:ffff:ffff:ffff:ffff:ffff,US -2620:da:c000::,2620:da:c000:ffff:ffff:ffff:ffff:ffff,US -2620:db::,2620:db::ffff:ffff:ffff:ffff:ffff,US -2620:db:4000::,2620:db:4000:ffff:ffff:ffff:ffff:ffff,CA -2620:db:8000::,2620:db:8000:ffff:ffff:ffff:ffff:ffff,US -2620:db:c000::,2620:db:c000:ffff:ffff:ffff:ffff:ffff,US -2620:dc::,2620:dc::ffff:ffff:ffff:ffff:ffff,US -2620:dc:8::,2620:dc:8:ffff:ffff:ffff:ffff:ffff,US -2620:dc:4000::,2620:dc:40ff:ffff:ffff:ffff:ffff:ffff,US -2620:dc:8000::,2620:dc:8000:ffff:ffff:ffff:ffff:ffff,CA -2620:dc:c000::,2620:dc:c000:ffff:ffff:ffff:ffff:ffff,US -2620:dd::,2620:dd::ffff:ffff:ffff:ffff:ffff,CA -2620:dd:4000::,2620:dd:4000:ffff:ffff:ffff:ffff:ffff,US -2620:dd:8000::,2620:dd:8000:ffff:ffff:ffff:ffff:ffff,US -2620:dd:c000::,2620:dd:c000:ffff:ffff:ffff:ffff:ffff,US -2620:de::,2620:de::ffff:ffff:ffff:ffff:ffff,US -2620:de:4000::,2620:de:4000:ffff:ffff:ffff:ffff:ffff,US -2620:de:8000::,2620:de:8000:ffff:ffff:ffff:ffff:ffff,US -2620:de:c000::,2620:de:c000:ffff:ffff:ffff:ffff:ffff,US -2620:df::,2620:df::ffff:ffff:ffff:ffff:ffff,US -2620:df:4000::,2620:df:400f:ffff:ffff:ffff:ffff:ffff,US -2620:df:8000::,2620:df:8000:ffff:ffff:ffff:ffff:ffff,US -2620:df:c000::,2620:df:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e0::,2620:e0::ffff:ffff:ffff:ffff:ffff,US -2620:e0:4000::,2620:e0:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e0:8000::,2620:e0:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e0:c000::,2620:e0:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e1::,2620:e1::ffff:ffff:ffff:ffff:ffff,US -2620:e1:4000::,2620:e1:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e1:8000::,2620:e1:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e1:c000::,2620:e1:c000:ffff:ffff:ffff:ffff:ffff,VG -2620:e2::,2620:e2::ffff:ffff:ffff:ffff:ffff,US -2620:e2:4000::,2620:e2:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e2:8000::,2620:e2:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e2:c000::,2620:e2:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e3::,2620:e3::ffff:ffff:ffff:ffff:ffff,US -2620:e3:4000::,2620:e3:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e3:8000::,2620:e3:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e3:c000::,2620:e3:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e4::,2620:e4::ffff:ffff:ffff:ffff:ffff,US -2620:e4:4000::,2620:e4:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e4:8000::,2620:e4:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e4:c000::,2620:e4:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e5::,2620:e5::ffff:ffff:ffff:ffff:ffff,US -2620:e5:4000::,2620:e5:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e5:8000::,2620:e5:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e5:c000::,2620:e5:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e6::,2620:e6::ffff:ffff:ffff:ffff:ffff,US -2620:e6:4000::,2620:e6:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e6:8000::,2620:e6:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e6:c000::,2620:e6:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e7::,2620:e7::ffff:ffff:ffff:ffff:ffff,US -2620:e7:4000::,2620:e7:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e7:8000::,2620:e7:8000:ffff:ffff:ffff:ffff:ffff,CA -2620:e7:c000::,2620:e7:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e8::,2620:e8::ffff:ffff:ffff:ffff:ffff,US -2620:e8:4000::,2620:e8:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e8:8000::,2620:e8:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e8:c000::,2620:e8:c000:ffff:ffff:ffff:ffff:ffff,US -2620:e9::,2620:e9::ffff:ffff:ffff:ffff:ffff,US -2620:e9:4000::,2620:e9:4000:ffff:ffff:ffff:ffff:ffff,US -2620:e9:8000::,2620:e9:8000:ffff:ffff:ffff:ffff:ffff,US -2620:e9:c000::,2620:e9:c000:ffff:ffff:ffff:ffff:ffff,US -2620:ea::,2620:ea:f:ffff:ffff:ffff:ffff:ffff,US -2620:ea:4000::,2620:ea:4000:ffff:ffff:ffff:ffff:ffff,US -2620:ea:8000::,2620:ea:8000:ffff:ffff:ffff:ffff:ffff,US -2620:eb::,2620:eb::ffff:ffff:ffff:ffff:ffff,US -2620:eb:4000::,2620:eb:4000:ffff:ffff:ffff:ffff:ffff,US -2620:eb:8000::,2620:eb:8000:ffff:ffff:ffff:ffff:ffff,US -2620:eb:c000::,2620:eb:c000:ffff:ffff:ffff:ffff:ffff,US -2620:ec::,2620:ec::ffff:ffff:ffff:ffff:ffff,US -2620:ec:4000::,2620:ec:4000:ffff:ffff:ffff:ffff:ffff,US -2620:ec:8000::,2620:ec:8000:ffff:ffff:ffff:ffff:ffff,US -2620:ec:c000::,2620:ec:c000:ffff:ffff:ffff:ffff:ffff,US -2620:ed::,2620:ed::ffff:ffff:ffff:ffff:ffff,US -2620:ed:4000::,2620:ed:4000:ffff:ffff:ffff:ffff:ffff,CA -2620:ed:8000::,2620:ed:8000:ffff:ffff:ffff:ffff:ffff,US -2620:ed:c000::,2620:ed:c000:ffff:ffff:ffff:ffff:ffff,US -2620:ee::,2620:ee::ffff:ffff:ffff:ffff:ffff,US -2620:ee:4000::,2620:ee:4000:ffff:ffff:ffff:ffff:ffff,US -2620:ee:8000::,2620:ee:8000:ffff:ffff:ffff:ffff:ffff,US -2620:ee:c000::,2620:ee:c00f:ffff:ffff:ffff:ffff:ffff,US -2620:ef:4000::,2620:ef:4000:ffff:ffff:ffff:ffff:ffff,US -2620:ef:8000::,2620:ef:8000:ffff:ffff:ffff:ffff:ffff,US -2620:ef:c000::,2620:ef:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f0::,2620:f0::ffff:ffff:ffff:ffff:ffff,US -2620:f0:4000::,2620:f0:400f:ffff:ffff:ffff:ffff:ffff,US -2620:f0:8000::,2620:f0:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f0:c000::,2620:f0:c002:ffff:ffff:ffff:ffff:ffff,US -2620:f0:c003::,2620:f0:c003:ffff:ffff:ffff:ffff:ffff,NL -2620:f0:c004::,2620:f0:c004:ffff:ffff:ffff:ffff:ffff,US -2620:f0:c005::,2620:f0:c005:ffff:ffff:ffff:ffff:ffff,SG -2620:f0:c006::,2620:f0:c009:ffff:ffff:ffff:ffff:ffff,US -2620:f0:c00a::,2620:f0:c00a:ffff:ffff:ffff:ffff:ffff,CA -2620:f0:c00b::,2620:f0:c00f:ffff:ffff:ffff:ffff:ffff,US -2620:f1:4000::,2620:f1:4000:ffff:ffff:ffff:ffff:ffff,CA -2620:f1:8000::,2620:f1:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f1:c000::,2620:f1:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f2::,2620:f2::ffff:ffff:ffff:ffff:ffff,CA -2620:f2:4000::,2620:f2:4000:ffff:ffff:ffff:ffff:ffff,US -2620:f2:8000::,2620:f2:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f2:c000::,2620:f2:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f3::,2620:f3::ffff:ffff:ffff:ffff:ffff,US -2620:f3:4000::,2620:f3:4000:ffff:ffff:ffff:ffff:ffff,US -2620:f3:8000::,2620:f3:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f3:c000::,2620:f3:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f4::,2620:f4::ffff:ffff:ffff:ffff:ffff,US -2620:f4:4000::,2620:f4:40ff:ffff:ffff:ffff:ffff:ffff,US -2620:f4:8000::,2620:f4:8000:ffff:ffff:ffff:ffff:ffff,CA -2620:f4:c000::,2620:f4:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f5::,2620:f5::ffff:ffff:ffff:ffff:ffff,US -2620:f5:4000::,2620:f5:4000:ffff:ffff:ffff:ffff:ffff,US -2620:f5:8000::,2620:f5:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f5:c000::,2620:f5:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f6::,2620:f6::ffff:ffff:ffff:ffff:ffff,CA -2620:f6:4000::,2620:f6:400f:ffff:ffff:ffff:ffff:ffff,US -2620:f6:8000::,2620:f6:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f6:c000::,2620:f6:c000:ffff:ffff:ffff:ffff:ffff,CA -2620:f7::,2620:f7::ffff:ffff:ffff:ffff:ffff,US -2620:f7:4000::,2620:f7:4000:ffff:ffff:ffff:ffff:ffff,US -2620:f7:8000::,2620:f7:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f7:c000::,2620:f7:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f8::,2620:f8::ffff:ffff:ffff:ffff:ffff,US -2620:f8:4000::,2620:f8:4000:ffff:ffff:ffff:ffff:ffff,US -2620:f8:8000::,2620:f8:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f8:c000::,2620:f8:c000:ffff:ffff:ffff:ffff:ffff,US -2620:f9::,2620:f9:f:ffff:ffff:ffff:ffff:ffff,US -2620:f9:4000::,2620:f9:4000:ffff:ffff:ffff:ffff:ffff,US -2620:f9:8000::,2620:f9:8000:ffff:ffff:ffff:ffff:ffff,US -2620:f9:c000::,2620:f9:c000:ffff:ffff:ffff:ffff:ffff,US -2620:fa::,2620:fa::ffff:ffff:ffff:ffff:ffff,US -2620:fa:4000::,2620:fa:4000:ffff:ffff:ffff:ffff:ffff,US -2620:fa:8000::,2620:fa:8000:ffff:ffff:ffff:ffff:ffff,CA -2620:fa:c000::,2620:fa:c000:ffff:ffff:ffff:ffff:ffff,US -2620:fb::,2620:fb::ffff:ffff:ffff:ffff:ffff,US -2620:fb:4000::,2620:fb:4000:ffff:ffff:ffff:ffff:ffff,US -2620:fb:8000::,2620:fb:8000:ffff:ffff:ffff:ffff:ffff,US -2620:fc::,2620:fc::ffff:ffff:ffff:ffff:ffff,CA -2620:fc:4000::,2620:fc:4000:ffff:ffff:ffff:ffff:ffff,CA -2620:fc:8000::,2620:fc:8000:ffff:ffff:ffff:ffff:ffff,US -2620:fc:c000::,2620:fc:c000:ffff:ffff:ffff:ffff:ffff,US -2620:fd::,2620:fd::ffff:ffff:ffff:ffff:ffff,CA -2620:fd:4000::,2620:fd:4000:ffff:ffff:ffff:ffff:ffff,US -2620:fd:8000::,2620:fd:8000:ffff:ffff:ffff:ffff:ffff,US -2620:fd:c000::,2620:fd:c000:ffff:ffff:ffff:ffff:ffff,CA -2620:fe::,2620:fe::ffff:ffff:ffff:ffff:ffff,US -2620:fe:2040::,2620:fe:2040:ffff:ffff:ffff:ffff:ffff,US -2620:fe:8000::,2620:fe:8000:ffff:ffff:ffff:ffff:ffff,US -2620:fe:c000::,2620:fe:c000:ffff:ffff:ffff:ffff:ffff,US -2620:ff::,2620:ff::ffff:ffff:ffff:ffff:ffff,US -2620:ff:4000::,2620:ff:4000:ffff:ffff:ffff:ffff:ffff,US -2620:ff:8000::,2620:ff:8000:ffff:ffff:ffff:ffff:ffff,US -2620:ff:c000::,2620:ff:c000:ffff:ffff:ffff:ffff:ffff,US -2620:100::,2620:100:f:ffff:ffff:ffff:ffff:ffff,US -2620:100:3000::,2620:100:3007:ffff:ffff:ffff:ffff:ffff,US -2620:100:4000::,2620:100:403f:ffff:ffff:ffff:ffff:ffff,US -2620:100:5000::,2620:100:5007:ffff:ffff:ffff:ffff:ffff,US -2620:100:6000::,2620:100:60ff:ffff:ffff:ffff:ffff:ffff,US -2620:100:7000::,2620:100:700f:ffff:ffff:ffff:ffff:ffff,US -2620:100:8000::,2620:100:8003:ffff:ffff:ffff:ffff:ffff,US -2620:100:9000::,2620:100:900f:ffff:ffff:ffff:ffff:ffff,US -2620:100:a000::,2620:100:a00f:ffff:ffff:ffff:ffff:ffff,US -2620:100:c000::,2620:100:c03f:ffff:ffff:ffff:ffff:ffff,US -2620:100:d000::,2620:100:d00f:ffff:ffff:ffff:ffff:ffff,US -2620:100:e000::,2620:100:e00f:ffff:ffff:ffff:ffff:ffff,US -2620:100:f000::,2620:100:f00f:ffff:ffff:ffff:ffff:ffff,US -2620:101::,2620:101:3:ffff:ffff:ffff:ffff:ffff,US -2620:101:1000::,2620:101:103f:ffff:ffff:ffff:ffff:ffff,US -2620:101:2000::,2620:101:201f:ffff:ffff:ffff:ffff:ffff,US -2620:101:3000::,2620:101:303f:ffff:ffff:ffff:ffff:ffff,US -2620:101:4000::,2620:101:403f:ffff:ffff:ffff:ffff:ffff,US -2620:101:5000::,2620:101:503f:ffff:ffff:ffff:ffff:ffff,US -2620:101:6000::,2620:101:6001:ffff:ffff:ffff:ffff:ffff,US -2620:101:7000::,2620:101:7001:ffff:ffff:ffff:ffff:ffff,US -2620:101:8000::,2620:101:80f1:ffff:ffff:ffff:ffff:ffff,US -2620:101:80f2::,2620:101:80f2:7fff:ffff:ffff:ffff:ffff,CA -2620:101:80f2:8000::,2620:101:80ff:ffff:ffff:ffff:ffff:ffff,US -2620:101:9000::,2620:101:900f:ffff:ffff:ffff:ffff:ffff,US -2620:101:b000::,2620:101:b07f:ffff:ffff:ffff:ffff:ffff,US -2620:101:c000::,2620:101:c0ff:ffff:ffff:ffff:ffff:ffff,CA -2620:101:d000::,2620:101:d007:ffff:ffff:ffff:ffff:ffff,US -2620:101:e000::,2620:101:e00f:ffff:ffff:ffff:ffff:ffff,US -2620:101:f000::,2620:101:f001:ffff:ffff:ffff:ffff:ffff,CA -2620:102::,2620:102:f:ffff:ffff:ffff:ffff:ffff,US -2620:102:2000::,2620:102:200f:ffff:ffff:ffff:ffff:ffff,US -2620:102:3000::,2620:102:300f:ffff:ffff:ffff:ffff:ffff,US -2620:102:4000::,2620:102:403f:ffff:ffff:ffff:ffff:ffff,US -2a07:14c0::,2a07:14c7:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:1500::,2a07:1507:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:1540::,2a07:1547:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:1580::,2a07:1587:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:15c0::,2a07:15c7:ffff:ffff:ffff:ffff:ffff:ffff,TR -2a07:1600::,2a07:1607:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:1640::,2a07:1647:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:1680::,2a07:1687:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:16c0::,2a07:16c7:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:1700::,2a07:1707:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:1740::,2a07:1747:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:1780::,2a07:1787:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:17c0::,2a07:17c7:ffff:ffff:ffff:ffff:ffff:ffff,UA -2a07:1800::,2a07:1807:ffff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1840::,2a07:1847:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:1880::,2a07:1887:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:18c0::,2a07:18c7:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:1900::,2a07:1907:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:1940::,2a07:1947:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:1980::,2a07:1987:ffff:ffff:ffff:ffff:ffff:ffff,IL -2a07:19c0::,2a07:19c7:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:1a00::,2a07:1a07:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:1a40::,2a07:1a47:ffff:ffff:ffff:ffff:ffff:ffff,PL -2a07:1a80::,2a07:1a80:6fff:ffff:ffff:ffff:ffff:ffff,SE -2a07:1a80:7000::,2a07:1a80:70ff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1a80:7100::,2a07:1a87:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:1ac0::,2a07:1ac7:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:1b00::,2a07:1b07:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:1b40::,2a07:1b47:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:1b80::,2a07:1b87:ffff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1bc0::,2a07:1bc7:ffff:ffff:ffff:ffff:ffff:ffff,PL -2a07:1c00::,2a07:1c07:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:1c40::,2a07:1c44:3ff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:400::,2a07:1c44:4ff:ffff:ffff:ffff:ffff:ffff,DE -2a07:1c44:500::,2a07:1c44:609:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:60a::,2a07:1c44:60a:ffff:ffff:ffff:ffff:ffff,DE -2a07:1c44:60b::,2a07:1c44:619:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:61a::,2a07:1c44:61a:ffff:ffff:ffff:ffff:ffff,KR -2a07:1c44:61b::,2a07:1c44:67f:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:680::,2a07:1c44:6bf:ffff:ffff:ffff:ffff:ffff,KR -2a07:1c44:6c0::,2a07:1c44:6ff:ffff:ffff:ffff:ffff:ffff,DE -2a07:1c44:700::,2a07:1c44:70f:ffff:ffff:ffff:ffff:ffff,US -2a07:1c44:710::,2a07:1c44:1800:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:1801::,2a07:1c44:1802:ffff:ffff:ffff:ffff:ffff,US -2a07:1c44:1803::,2a07:1c44:35ff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:3600::,2a07:1c44:36ff:ffff:ffff:ffff:ffff:ffff,GB -2a07:1c44:3700::,2a07:1c44:3fff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:4000::,2a07:1c44:40ff:ffff:ffff:ffff:ffff:ffff,US -2a07:1c44:4100::,2a07:1c44:42ff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:4300::,2a07:1c44:43ff:ffff:ffff:ffff:ffff:ffff,HR -2a07:1c44:4400::,2a07:1c44:4fff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c44:5000::,2a07:1c44:51ff:ffff:ffff:ffff:ffff:ffff,US -2a07:1c44:5200::,2a07:1c47:ffff:ffff:ffff:ffff:ffff:ffff,AT -2a07:1c80::,2a07:1c87:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:1cc0::,2a07:1cc7:ffff:ffff:ffff:ffff:ffff:ffff,PL -2a07:1d00::,2a07:1d07:ffff:ffff:ffff:ffff:ffff:ffff,IR -2a07:1d40::,2a07:1d47:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:1d80::,2a07:1d87:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:1dc0::,2a07:1dc7:ffff:ffff:ffff:ffff:ffff:ffff,PL -2a07:1e00::,2a07:1e07:ffff:ffff:ffff:ffff:ffff:ffff,KZ -2a07:1e40::,2a07:1e47:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:1e80::,2a07:1e87:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:1ec0::,2a07:1ec7:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:1f00::,2a07:1f07:ffff:ffff:ffff:ffff:ffff:ffff,CH -2a07:1f40::,2a07:1f47:ffff:ffff:ffff:ffff:ffff:ffff,CZ -2a07:1f80::,2a07:1f87:ffff:ffff:ffff:ffff:ffff:ffff,US -2a07:1fc0::,2a07:1fc7:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:2000::,2a07:2007:ffff:ffff:ffff:ffff:ffff:ffff,IQ -2a07:2040::,2a07:2047:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:2080::,2a07:2087:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:20c0::,2a07:20c7:ffff:ffff:ffff:ffff:ffff:ffff,CZ -2a07:2100::,2a07:2107:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2140::,2a07:2147:ffff:ffff:ffff:ffff:ffff:ffff,CH -2a07:2180::,2a07:2187:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:21c0::,2a07:21c7:ffff:ffff:ffff:ffff:ffff:ffff,TR -2a07:2200::,2a07:2207:ffff:ffff:ffff:ffff:ffff:ffff,IR -2a07:2240::,2a07:2247:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:2280::,2a07:2287:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:2300::,2a07:2307:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:2340::,2a07:2347:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:2380::,2a07:2387:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:23c0::,2a07:23c7:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:2400::,2a07:2407:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:2440::,2a07:2447:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:2480::,2a07:2487:ffff:ffff:ffff:ffff:ffff:ffff,IR -2a07:24c0::,2a07:24c7:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:2500::,2a07:2507:ffff:ffff:ffff:ffff:ffff:ffff,DK -2a07:2540::,2a07:2547:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2580::,2a07:2587:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:25c0::,2a07:25c7:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:2600::,2a07:2607:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:2640::,2a07:2647:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:2680::,2a07:2687:ffff:ffff:ffff:ffff:ffff:ffff,DK -2a07:26c0::,2a07:26c7:ffff:ffff:ffff:ffff:ffff:ffff,BE -2a07:2700::,2a07:2707:ffff:ffff:ffff:ffff:ffff:ffff,TR -2a07:2740::,2a07:2747:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:2780::,2a07:2787:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:27c0::,2a07:27c7:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:2800::,2a07:2807:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2840::,2a07:2847:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:2880::,2a07:2887:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:28c0::,2a07:28c7:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:2900::,2a07:291f:ffff:ffff:ffff:ffff:ffff:ffff,CH -2a07:2a00::,2a07:2a07:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:2a40::,2a07:2a47:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2a80::,2a07:2a87:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:2ac0::,2a07:2ac7:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2b00::,2a07:2b07:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:2b40::,2a07:2b47:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:2b80::,2a07:2b87:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:2bc0::,2a07:2bc7:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:2c00::,2a07:2c07:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:2c40::,2a07:2c47:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2c80::,2a07:2c87:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2cc0::,2a07:2cc7:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:2d00::,2a07:2d07:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2d40::,2a07:2d47:ffff:ffff:ffff:ffff:ffff:ffff,CH -2a07:2d80::,2a07:2d87:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:2dc0::,2a07:2dc7:ffff:ffff:ffff:ffff:ffff:ffff,FI -2a07:2e00::,2a07:2e07:ffff:ffff:ffff:ffff:ffff:ffff,CH -2a07:2e40::,2a07:2e47:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:2e80::,2a07:2e87:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:2ec0::,2a07:2ec7:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2f00::,2a07:2f07:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:2f40::,2a07:2f47:ffff:ffff:ffff:ffff:ffff:ffff,UA -2a07:2f80::,2a07:2f87:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:2fc0::,2a07:2fc7:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:3000::,2a07:3007:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:3040::,2a07:3047:ffff:ffff:ffff:ffff:ffff:ffff,PL -2a07:3080::,2a07:3087:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:30c0::,2a07:30c7:ffff:ffff:ffff:ffff:ffff:ffff,CZ -2a07:3100::,2a07:3107:ffff:ffff:ffff:ffff:ffff:ffff,RO -2a07:3140::,2a07:3147:ffff:ffff:ffff:ffff:ffff:ffff,BE -2a07:3180::,2a07:3187:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:31c0::,2a07:31c7:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3200::,2a07:3207:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3240::,2a07:3247:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:3280::,2a07:3287:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:32c0::,2a07:32c7:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:3300::,2a07:3307:ffff:ffff:ffff:ffff:ffff:ffff,TR -2a07:3340::,2a07:3347:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:3380::,2a07:3387:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:33c0::,2a07:33c7:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:3400::,2a07:3407:ffff:ffff:ffff:ffff:ffff:ffff,UA -2a07:3440::,2a07:3447:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3480::,2a07:3487:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:3500::,2a07:3507:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3540::,2a07:3547:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:3580::,2a07:3587:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:35c0::,2a07:35c7:ffff:ffff:ffff:ffff:ffff:ffff,UA -2a07:3600::,2a07:3607:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:3640::,2a07:3647:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3680::,2a07:3687:ffff:ffff:ffff:ffff:ffff:ffff,LB -2a07:36c0::,2a07:36c7:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3700::,2a07:3707:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:3740::,2a07:3747:ffff:ffff:ffff:ffff:ffff:ffff,AT -2a07:3780::,2a07:3787:ffff:ffff:ffff:ffff:ffff:ffff,IS -2a07:37c0::,2a07:37c7:ffff:ffff:ffff:ffff:ffff:ffff,BE -2a07:3800::,2a07:3807:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:3840::,2a07:3847:ffff:ffff:ffff:ffff:ffff:ffff,HR -2a07:3880::,2a07:3887:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:38c0::,2a07:38c7:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:3900::,2a07:3907:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:3940::,2a07:3947:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:3980::,2a07:3987:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:39c0::,2a07:39c7:ffff:ffff:ffff:ffff:ffff:ffff,DK -2a07:3a00::,2a07:3a07:ffff:ffff:ffff:ffff:ffff:ffff,ES -2a07:3a80::,2a07:3a87:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:3ac0::,2a07:3ac7:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:3b00::,2a07:3b07:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:3b40::,2a07:3b47:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:3b80::,2a07:3b87:ffff:ffff:ffff:ffff:ffff:ffff,GI -2a07:3bc0::,2a07:3bc7:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3c00::,2a07:3c07:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3c40::,2a07:3c47:ffff:ffff:ffff:ffff:ffff:ffff,DE -2a07:3c80::,2a07:3c87:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:3d00::,2a07:3d07:ffff:ffff:ffff:ffff:ffff:ffff,IT -2a07:3d80::,2a07:3d87:ffff:ffff:ffff:ffff:ffff:ffff,CZ -2a07:3dc0::,2a07:3dc7:ffff:ffff:ffff:ffff:ffff:ffff,DK -2a07:3e00::,2a07:3e07:ffff:ffff:ffff:ffff:ffff:ffff,CH -2a07:3e40::,2a07:3e47:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:3e80::,2a07:3e87:ffff:ffff:ffff:ffff:ffff:ffff,NL -2a07:3ec0::,2a07:3ec7:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:3f00::,2a07:3f07:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:3f40::,2a07:3f47:ffff:ffff:ffff:ffff:ffff:ffff,IE -2a07:3f80::,2a07:3f87:ffff:ffff:ffff:ffff:ffff:ffff,SK -2a07:3fc0::,2a07:3fc7:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:4000::,2a07:4007:ffff:ffff:ffff:ffff:ffff:ffff,NO -2a07:4040::,2a07:4047:ffff:ffff:ffff:ffff:ffff:ffff,SE -2a07:4080::,2a07:4087:ffff:ffff:ffff:ffff:ffff:ffff,AT -2a07:40c0::,2a07:40c7:ffff:ffff:ffff:ffff:ffff:ffff,IL -2a07:4100::,2a07:4107:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:4140::,2a07:4147:ffff:ffff:ffff:ffff:ffff:ffff,MD -2a07:4180::,2a07:4187:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:41c0::,2a07:41c7:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:4200::,2a07:4207:ffff:ffff:ffff:ffff:ffff:ffff,FR -2a07:4240::,2a07:4247:ffff:ffff:ffff:ffff:ffff:ffff,RU -2a07:4280::,2a07:4287:ffff:ffff:ffff:ffff:ffff:ffff,GB -2a07:42c0::,2a07:42c7:ffff:ffff:ffff:ffff:ffff:ffff,DK -2a07:4340::,2a07:4347:ffff:ffff:ffff:ffff:ffff:ffff,AE -2a0c:af80::,2a0c:af87:ffff:ffff:ffff:ffff:ffff:ffff,GB -2c0f:f950::,2c0f:f950:ffff:ffff:ffff:ffff:ffff:ffff,SS -2c0f:f958::,2c0f:f958:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:f960::,2c0f:f960:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:f968::,2c0f:f968:ffff:ffff:ffff:ffff:ffff:ffff,MZ -2c0f:f970::,2c0f:f970:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:f978::,2c0f:f978:ffff:ffff:ffff:ffff:ffff:ffff,CD -2c0f:f980::,2c0f:f980:ffff:ffff:ffff:ffff:ffff:ffff,NA -2c0f:f988::,2c0f:f988:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:f990::,2c0f:f990:ffff:ffff:ffff:ffff:ffff:ffff,GN -2c0f:f998::,2c0f:f998:ffff:ffff:ffff:ffff:ffff:ffff,MR -2c0f:f9a0::,2c0f:f9a0:ffff:ffff:ffff:ffff:ffff:ffff,MW -2c0f:f9a8::,2c0f:f9a8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:f9b0::,2c0f:f9b0:ffff:ffff:ffff:ffff:ffff:ffff,GA -2c0f:f9b8::,2c0f:f9b8:1:ffff:ffff:ffff:ffff:ffff,MU -2c0f:f9b8:2::,2c0f:f9b8:2:ffff:ffff:ffff:ffff:ffff,US -2c0f:f9b8:3::,2c0f:f9b8:ffff:ffff:ffff:ffff:ffff:ffff,MU -2c0f:f9c0::,2c0f:f9c0:ffff:ffff:ffff:ffff:ffff:ffff,BW -2c0f:f9c8::,2c0f:f9c8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:f9d0::,2c0f:f9d0:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:f9d8::,2c0f:f9d8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:f9e0::,2c0f:f9e0:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:f9e8::,2c0f:f9e8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:f9f0::,2c0f:f9f0:ffff:ffff:ffff:ffff:ffff:ffff,MG -2c0f:f9f8::,2c0f:f9f8:ffff:ffff:ffff:ffff:ffff:ffff,BJ -2c0f:fa00::,2c0f:fa00:ffff:ffff:ffff:ffff:ffff:ffff,GH -2c0f:fa08::,2c0f:fa08:ffff:ffff:ffff:ffff:ffff:ffff,CD -2c0f:fa10::,2c0f:fa10:fffc:ffff:ffff:ffff:ffff:ffff,MU -2c0f:fa10:fffd::,2c0f:fa10:fffd:7fff:ffff:ffff:ffff:ffff,ZM -2c0f:fa10:fffd:8000::,2c0f:fa10:ffff:ffff:ffff:ffff:ffff:ffff,MU -2c0f:fa18::,2c0f:fa18:ffff:ffff:ffff:ffff:ffff:ffff,MA -2c0f:fa20::,2c0f:fa20:ffff:ffff:ffff:ffff:ffff:ffff,SS -2c0f:fa28::,2c0f:fa28:ffff:ffff:ffff:ffff:ffff:ffff,MG -2c0f:fa38::,2c0f:fa38:ffff:ffff:ffff:ffff:ffff:ffff,AO -2c0f:fa40::,2c0f:fa40:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fa48::,2c0f:fa48:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fa58::,2c0f:fa58:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fa60::,2c0f:fa60:ffff:ffff:ffff:ffff:ffff:ffff,AO -2c0f:fa68::,2c0f:fa68:ffff:ffff:ffff:ffff:ffff:ffff,GH -2c0f:fa70::,2c0f:fa70:ffff:ffff:ffff:ffff:ffff:ffff,AO -2c0f:fa78::,2c0f:fa78:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fa80::,2c0f:fa80:ffff:ffff:ffff:ffff:ffff:ffff,AO -2c0f:fa88::,2c0f:fa88:ffff:ffff:ffff:ffff:ffff:ffff,ST -2c0f:fa90::,2c0f:fa90:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fa98::,2c0f:fa98:ffff:ffff:ffff:ffff:ffff:ffff,ZW -2c0f:faa0::,2c0f:faa7:ffff:ffff:ffff:ffff:ffff:ffff,SD -2c0f:fab0::,2c0f:fabf:ffff:ffff:ffff:ffff:ffff:ffff,TN -2c0f:fac0::,2c0f:fac0:ffff:ffff:ffff:ffff:ffff:ffff,MW -2c0f:fac8::,2c0f:fac8:ffff:ffff:ffff:ffff:ffff:ffff,BW -2c0f:fad8::,2c0f:fad8:ffff:ffff:ffff:ffff:ffff:ffff,CM -2c0f:fae0::,2c0f:fae0:ffff:ffff:ffff:ffff:ffff:ffff,CM -2c0f:fae8::,2c0f:fae8:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:faf0::,2c0f:faf0:ffff:ffff:ffff:ffff:ffff:ffff,AO -2c0f:faf8::,2c0f:faf8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fb00::,2c0f:fb00:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:fb08::,2c0f:fb08:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fb10::,2c0f:fb10:ffff:ffff:ffff:ffff:ffff:ffff,LY -2c0f:fb18::,2c0f:fb18:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fb20::,2c0f:fb20:ffff:ffff:ffff:ffff:ffff:ffff,MA -2c0f:fb30::,2c0f:fb30:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fb38::,2c0f:fb38:ffff:ffff:ffff:ffff:ffff:ffff,SO -2c0f:fb40::,2c0f:fb40:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fb48::,2c0f:fb48:ffff:ffff:ffff:ffff:ffff:ffff,MZ -2c0f:fb50::,2c0f:fb50:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fb58::,2c0f:fb58:ffff:ffff:ffff:ffff:ffff:ffff,AO -2c0f:fb60::,2c0f:fb60:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fb68::,2c0f:fb68:ffff:ffff:ffff:ffff:ffff:ffff,LS -2c0f:fb70::,2c0f:fb70:ffff:ffff:ffff:ffff:ffff:ffff,AO -2c0f:fb78::,2c0f:fb78:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fb80::,2c0f:fb80:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fb88::,2c0f:fb88:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fb90::,2c0f:fb90:ffff:ffff:ffff:ffff:ffff:ffff,MZ -2c0f:fb98::,2c0f:fb98:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fba0::,2c0f:fba0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fba8::,2c0f:fba8:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fbb0::,2c0f:fbb0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fbb8::,2c0f:fbb8:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fbc0::,2c0f:fbc0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fbc8::,2c0f:fbc8:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:fbd0::,2c0f:fbd0:ffff:ffff:ffff:ffff:ffff:ffff,GN -2c0f:fbd8::,2c0f:fbd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fbe0::,2c0f:fc1f:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fc40::,2c0f:fc40:ffff:ffff:ffff:ffff:ffff:ffff,EG -2c0f:fc48::,2c0f:fc48:ffff:ffff:ffff:ffff:ffff:ffff,MW -2c0f:fc58::,2c0f:fc58:ffff:ffff:ffff:ffff:ffff:ffff,MW -2c0f:fc60::,2c0f:fc61:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fc68::,2c0f:fc68:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fc70::,2c0f:fc70:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fc80::,2c0f:fc80:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fc88::,2c0f:fc89:ffff:ffff:ffff:ffff:ffff:ffff,EG -2c0f:fc90::,2c0f:fc90:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fc98::,2c0f:fc98:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fca0::,2c0f:fca0:ffff:ffff:ffff:ffff:ffff:ffff,GH -2c0f:fca8::,2c0f:fca8:ffff:ffff:ffff:ffff:ffff:ffff,GH -2c0f:fcb0::,2c0f:fcb0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fcb8::,2c0f:fcb8:ffff:ffff:ffff:ffff:ffff:ffff,GM -2c0f:fcc8::,2c0f:fcc8:ffff:ffff:ffff:ffff:ffff:ffff,ZM -2c0f:fcd0::,2c0f:fcd0:ffff:ffff:ffff:ffff:ffff:ffff,ZM -2c0f:fcd8::,2c0f:fcd8:ffff:ffff:ffff:ffff:ffff:ffff,SO -2c0f:fce0::,2c0f:fce0:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fce8::,2c0f:fce8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fcf0::,2c0f:fcf0:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fcf8::,2c0f:fcf8:ffff:ffff:ffff:ffff:ffff:ffff,GH -2c0f:fd00::,2c0f:fd00:ffff:ffff:ffff:ffff:ffff:ffff,LS -2c0f:fd08::,2c0f:fd08:ffff:ffff:ffff:ffff:ffff:ffff,GM -2c0f:fd10::,2c0f:fd10:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fd18::,2c0f:fd18:ffff:ffff:ffff:ffff:ffff:ffff,SC -2c0f:fd20::,2c0f:fd20:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fd28::,2c0f:fd28:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fd30::,2c0f:fd30:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fd38::,2c0f:fd38:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fd40::,2c0f:fd40:ffff:ffff:ffff:ffff:ffff:ffff,ZM -2c0f:fd48::,2c0f:fd48:ffff:ffff:ffff:ffff:ffff:ffff,ZW -2c0f:fd50::,2c0f:fd50:ffff:ffff:ffff:ffff:ffff:ffff,MW -2c0f:fd58::,2c0f:fd58:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fd60::,2c0f:fd60:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:fd68::,2c0f:fd68:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fd78::,2c0f:fd78:ffff:ffff:ffff:ffff:ffff:ffff,BI -2c0f:fd80::,2c0f:fd80:ffff:ffff:ffff:ffff:ffff:ffff,BF -2c0f:fd88::,2c0f:fd88:ffff:ffff:ffff:ffff:ffff:ffff,GH -2c0f:fd90::,2c0f:fd90:ffff:ffff:ffff:ffff:ffff:ffff,ZM -2c0f:fd98::,2c0f:fd98:ffff:ffff:ffff:ffff:ffff:ffff,ZM -2c0f:fda0::,2c0f:fda0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fda8::,2c0f:fda8:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fdb0::,2c0f:fdb0:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fdb8::,2c0f:fdb8:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:fdc0::,2c0f:fdc0:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fdc8::,2c0f:fdc8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fdd0::,2c0f:fdd0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fdd8::,2c0f:fdd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fde8::,2c0f:fde8:ffff:ffff:ffff:ffff:ffff:ffff,MW -2c0f:fdf0::,2c0f:fdf0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fdf8::,2c0f:fdf8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fe08::,2c0f:fe08:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fe10::,2c0f:fe10:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:fe18::,2c0f:fe18:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fe20::,2c0f:fe20:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fe28::,2c0f:fe28:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fe30::,2c0f:fe30:ffff:ffff:ffff:ffff:ffff:ffff,MU -2c0f:fe38::,2c0f:fe38:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fe40::,2c0f:fe40:8001:f:ffff:ffff:ffff:ffff,MU -2c0f:fe40:8001:10::,2c0f:fe40:8001:10:ffff:ffff:ffff:ffff,KE -2c0f:fe40:8001:11::,2c0f:fe40:80fe:ffff:ffff:ffff:ffff:ffff,MU -2c0f:fe40:80ff::,2c0f:fe40:80ff:7fff:ffff:ffff:ffff:ffff,KE -2c0f:fe40:80ff:8000::,2c0f:fe40:ffff:ffff:ffff:ffff:ffff:ffff,MU -2c0f:fe50::,2c0f:fe50:ffff:ffff:ffff:ffff:ffff:ffff,DZ -2c0f:fe58::,2c0f:fe58:ffff:ffff:ffff:ffff:ffff:ffff,LS -2c0f:fe60::,2c0f:fe60:ffff:ffff:ffff:ffff:ffff:ffff,RW -2c0f:fe68::,2c0f:fe68:ffff:ffff:ffff:ffff:ffff:ffff,MU -2c0f:fe70::,2c0f:fe70:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:fe78::,2c0f:fe78:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fe88::,2c0f:fe88:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:fe90::,2c0f:fe90:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fe98::,2c0f:fe98:ffff:ffff:ffff:ffff:ffff:ffff,TZ -2c0f:fea0::,2c0f:fea0:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fea8::,2c0f:fea8:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:feb0::,2c0f:feb0:16:ffff:ffff:ffff:ffff:ffff,MU -2c0f:feb0:17::,2c0f:feb0:17:7fff:ffff:ffff:ffff:ffff,KE -2c0f:feb0:17:8000::,2c0f:feb0:1e:ffff:ffff:ffff:ffff:ffff,MU -2c0f:feb0:1f::,2c0f:feb0:1f:7fff:ffff:ffff:ffff:ffff,ZA -2c0f:feb0:1f:8000::,2c0f:feb0:1f:ffff:ffff:ffff:ffff:ffff,MU -2c0f:feb0:20::,2c0f:feb0:20:7fff:ffff:ffff:ffff:ffff,ZA -2c0f:feb0:20:8000::,2c0f:feb0:2f:7fff:ffff:ffff:ffff:ffff,MU -2c0f:feb0:2f:8000::,2c0f:feb0:2f:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:feb0:30::,2c0f:feb1:ffff:ffff:ffff:ffff:ffff:ffff,MU -2c0f:feb8::,2c0f:feb8:ffff:ffff:ffff:ffff:ffff:ffff,ZM -2c0f:fec0::,2c0f:fec0:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:fec8::,2c0f:fec8:ffff:ffff:ffff:ffff:ffff:ffff,SD -2c0f:fed8::,2c0f:fed8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:fee0::,2c0f:fee0:ffff:ffff:ffff:ffff:ffff:ffff,EG -2c0f:fef0::,2c0f:fef0:ffff:ffff:ffff:ffff:ffff:ffff,SC -2c0f:fef8::,2c0f:fef8:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:ff00::,2c0f:ff00:ffff:ffff:ffff:ffff:ffff:ffff,BW -2c0f:ff08::,2c0f:ff08:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:ff10::,2c0f:ff10:ffff:ffff:ffff:ffff:ffff:ffff,CD -2c0f:ff18::,2c0f:ff18:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:ff20::,2c0f:ff20:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:ff28::,2c0f:ff28:ffff:ffff:ffff:ffff:ffff:ffff,SD -2c0f:ff30::,2c0f:ff30:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:ff40::,2c0f:ff80:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:ff88::,2c0f:ff88:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:ff90::,2c0f:ff90:ffff:ffff:ffff:ffff:ffff:ffff,KE -2c0f:ff98::,2c0f:ff98:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:ffa0::,2c0f:ffa0:ffff:ffff:ffff:ffff:ffff:ffff,UG -2c0f:ffa8::,2c0f:ffa8:ffff:ffff:ffff:ffff:ffff:ffff,LS -2c0f:ffb0::,2c0f:ffb0:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:ffb8::,2c0f:ffb8:ffff:ffff:ffff:ffff:ffff:ffff,SD -2c0f:ffc0::,2c0f:ffc0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:ffc8::,2c0f:ffc8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:ffd0::,2c0f:ffd0:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:ffd8::,2c0f:ffd8:ffff:ffff:ffff:ffff:ffff:ffff,ZA -2c0f:ffe8::,2c0f:ffe8:ffff:ffff:ffff:ffff:ffff:ffff,NG -2c0f:fff0::,2c0f:fff0:ffff:ffff:ffff:ffff:ffff:ffff,NG diff -Nru snowflake-2.2.0/debian/vendor/modules.txt snowflake-2.3.1/debian/vendor/modules.txt --- snowflake-2.2.0/debian/vendor/modules.txt 2022-06-17 14:52:06.000000000 +0000 +++ snowflake-2.3.1/debian/vendor/modules.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -gitlab.torproject.org/tpo/anti-censorship/geoip diff -Nru snowflake-2.2.0/distinctcounter/counter.go snowflake-2.3.1/distinctcounter/counter.go --- snowflake-2.2.0/distinctcounter/counter.go 1970-01-01 00:00:00.000000000 +0000 +++ snowflake-2.3.1/distinctcounter/counter.go 2022-09-23 12:08:13.000000000 +0000 @@ -0,0 +1,37 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "time" + + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/ipsetsink/sinkcluster" +) + +func main() { + inputFile := flag.String("in", "", "") + start := flag.String("from", "", "") + end := flag.String("to", "", "") + flag.Parse() + startTime, err := time.Parse(time.RFC3339, *start) + if err != nil { + log.Fatal("unable to parse start time:", err) + } + endTime, err := time.Parse(time.RFC3339, *end) + if err != nil { + log.Fatal("unable to parse end time:", err) + } + fd, err := os.Open(*inputFile) + if err != nil { + log.Fatal("unable to open input file:", err) + } + counter := sinkcluster.NewClusterCounter(startTime, endTime) + result, err := counter.Count(fd) + if err != nil { + log.Fatal("unable to count:", err) + } + fmt.Printf("sum = %v\n", result.Sum) + fmt.Printf("chunkIncluded = %v\n", result.ChunkIncluded) +} diff -Nru snowflake-2.2.0/doc/broker-spec.txt snowflake-2.3.1/doc/broker-spec.txt --- snowflake-2.2.0/doc/broker-spec.txt 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/doc/broker-spec.txt 2022-09-23 12:08:13.000000000 +0000 @@ -100,6 +100,24 @@ A count of the total number of unique IP addresses of snowflake proxies that have an unknown NAT type. + "snowflake-proxy-poll-with-relay-url-count" NUM NL + [At most once.] + + A count of snowflake proxy polls with relay url extension present. + This means this proxy understands relay url, and is sending its + allowed prefix. + "snowflake-proxy-poll-without-relay-url-count" NUM NL + [At most once.] + + A count of snowflake proxy polls with relay url extension absent. + This means this proxy is not yet updated. + "snowflake-proxy-rejected-for-relay-url-count" NUM NL + [At most once.] + + A count of snowflake proxy polls with relay url extension rejected + based on broker's relay url extension policy. + This means an incompatible allowed relay pattern is included in the + proxy poll message. 2. Broker messaging specification and endpoints The broker facilitates the connection of snowflake clients and snowflake proxies @@ -177,10 +195,11 @@ { Sid: [generated session id of proxy], - Version: 1.1, + Version: 1.3, Type: ["badge"|"webext"|"standalone"|"mobile"], NAT: ["unknown"|"restricted"|"unrestricted"], - Clients: [number of current clients, rounded down to multiples of 8] + Clients: [number of current clients, rounded down to multiples of 8], + AcceptedRelayPattern: [a pattern representing accepted set of relay domains] } ``` @@ -195,7 +214,8 @@ { type: offer, sdp: [WebRTC SDP] - } + }, + RelayURL: [the WebSocket URL proxy should connect to relay Snowflake traffic] } ``` @@ -220,7 +240,7 @@ { Sid: [generated session id of proxy], - Version: 1.1, + Version: 1.3, Answer: { type: answer, diff -Nru snowflake-2.2.0/.gitlab-ci.yml snowflake-2.3.1/.gitlab-ci.yml --- snowflake-2.2.0/.gitlab-ci.yml 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/.gitlab-ci.yml 2022-09-23 12:08:13.000000000 +0000 @@ -139,22 +139,22 @@ - go get golang.org/x/mobile/bind - gomobile bind -v -target=android $REPRODUCIBLE_FLAGS . -go-1.15: - image: golang:1.15-stretch +go-1.16: + image: golang:1.16-stretch <<: *golang-docker-debian-template <<: *test-template script: - *go-test -go-1.16: - image: golang:1.16-stretch +go-1.17: + image: golang:1.17-stretch <<: *golang-docker-debian-template <<: *test-template script: - *go-test -go-1.17: - image: golang:1.17-stretch +go-1.18: + image: golang:1.18-stretch <<: *golang-docker-debian-template <<: *test-template script: diff -Nru snowflake-2.2.0/go.mod snowflake-2.3.1/go.mod --- snowflake-2.2.0/go.mod 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/go.mod 2022-09-23 12:08:13.000000000 +0000 @@ -4,6 +4,7 @@ require ( git.torproject.org/pluggable-transports/goptlib.git v1.1.0 + github.com/clarkduvall/hyperloglog v0.0.0-20171127014514-a0107a5d8004 // indirect github.com/gorilla/websocket v1.4.1 github.com/pion/ice/v2 v2.2.6 github.com/pion/sdp/v3 v3.0.5 diff -Nru snowflake-2.2.0/go.sum snowflake-2.3.1/go.sum --- snowflake-2.2.0/go.sum 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/go.sum 2022-09-23 12:08:13.000000000 +0000 @@ -32,6 +32,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clarkduvall/hyperloglog v0.0.0-20171127014514-a0107a5d8004 h1:mK6JroY6bLiPS3s6QCYOSjRyErFc2iHNkhhmRfF0nHo= +github.com/clarkduvall/hyperloglog v0.0.0-20171127014514-a0107a5d8004/go.mod h1:drodPoQNro6QBO6TJ/MpMZbz8Bn2eSDtRN6jpG4VGw8= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= diff -Nru snowflake-2.2.0/proxy/lib/proxy-go_test.go snowflake-2.3.1/proxy/lib/proxy-go_test.go --- snowflake-2.2.0/proxy/lib/proxy-go_test.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/proxy/lib/proxy-go_test.go 2022-09-23 12:08:13.000000000 +0000 @@ -365,7 +365,7 @@ b, } - sdp := broker.pollOffer(sampleOffer, DefaultProxyType, nil) + sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "", nil) expectedSDP, _ := strconv.Unquote(sampleSDP) So(sdp.SDP, ShouldResemble, expectedSDP) }) @@ -379,7 +379,7 @@ b, } - sdp := broker.pollOffer(sampleOffer, DefaultProxyType, nil) + sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "", nil) So(sdp, ShouldBeNil) }) Convey("sends answer to broker", func() { diff -Nru snowflake-2.2.0/proxy/lib/snowflake.go snowflake-2.3.1/proxy/lib/snowflake.go --- snowflake-2.2.0/proxy/lib/snowflake.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/proxy/lib/snowflake.go 2022-09-23 12:08:13.000000000 +0000 @@ -42,6 +42,7 @@ "git.torproject.org/pluggable-transports/snowflake.git/v2/common/event" "git.torproject.org/pluggable-transports/snowflake.git/v2/common/messages" + "git.torproject.org/pluggable-transports/snowflake.git/v2/common/namematcher" "git.torproject.org/pluggable-transports/snowflake.git/v2/common/task" "git.torproject.org/pluggable-transports/snowflake.git/v2/common/util" "git.torproject.org/pluggable-transports/snowflake.git/v2/common/websocketconn" @@ -112,6 +113,13 @@ KeepLocalAddresses bool // RelayURL is the URL of the Snowflake server that all traffic will be relayed to RelayURL string + // RelayDomainNamePattern is the pattern specify allowed domain name for relay + // If the pattern starts with ^ then an exact match is required. + // The rest of pattern is the suffix of domain name. + // There is no look ahead assertion when matching domain name suffix, + // thus the string prepend the suffix does not need to be empty or ends with a dot. + RelayDomainNamePattern string + AllowNonTLSRelay bool // NATProbeURL is the URL of the probe service we use for NAT checks NATProbeURL string // NATTypeMeasurementInterval is time before NAT type is retested @@ -188,7 +196,7 @@ return limitedRead(resp.Body, readLimit) } -func (s *SignalingServer) pollOffer(sid string, proxyType string, shutdown chan struct{}) *webrtc.SessionDescription { +func (s *SignalingServer) pollOffer(sid string, proxyType string, acceptedRelayPattern string, shutdown chan struct{}) (*webrtc.SessionDescription, string) { brokerPath := s.url.ResolveReference(&url.URL{Path: "proxy"}) ticker := time.NewTicker(pollInterval) @@ -198,38 +206,38 @@ for ; true; <-ticker.C { select { case <-shutdown: - return nil + return nil, "" default: numClients := int((tokens.count() / 8) * 8) // Round down to 8 currentNATTypeLoaded := getCurrentNATType() - body, err := messages.EncodeProxyPollRequest(sid, proxyType, currentNATTypeLoaded, numClients) + body, err := messages.EncodeProxyPollRequestWithRelayPrefix(sid, proxyType, currentNATTypeLoaded, numClients, acceptedRelayPattern) if err != nil { log.Printf("Error encoding poll message: %s", err.Error()) - return nil + return nil, "" } resp, err := s.Post(brokerPath.String(), bytes.NewBuffer(body)) if err != nil { log.Printf("error polling broker: %s", err.Error()) } - offer, _, err := messages.DecodePollResponse(resp) + offer, _, relayURL, err := messages.DecodePollResponseWithRelayURL(resp) if err != nil { log.Printf("Error reading broker response: %s", err.Error()) log.Printf("body: %s", resp) - return nil + return nil, "" } if offer != "" { offer, err := util.DeserializeSessionDescription(offer) if err != nil { log.Printf("Error processing session description: %s", err.Error()) - return nil + return nil, "" } - return offer + return offer, relayURL } } } - return nil + return nil, "" } func (s *SignalingServer) sendAnswer(sid string, pc *webrtc.PeerConnection) error { @@ -295,11 +303,14 @@ // conn.RemoteAddr() inside this function, as a workaround for a hang that // otherwise occurs inside of conn.pc.RemoteDescription() (called by // RemoteAddr). https://bugs.torproject.org/18628#comment:8 -func (sf *SnowflakeProxy) datachannelHandler(conn *webRTCConn, remoteAddr net.Addr) { +func (sf *SnowflakeProxy) datachannelHandler(conn *webRTCConn, remoteAddr net.Addr, relayURL string) { defer conn.Close() defer tokens.ret() - u, err := url.Parse(sf.RelayURL) + if relayURL == "" { + relayURL = sf.RelayURL + } + u, err := url.Parse(relayURL) if err != nil { log.Fatalf("invalid relay url: %s", err) } @@ -316,16 +327,25 @@ ws, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { - log.Printf("error dialing relay: %s", err) + log.Printf("error dialing relay: %s = %s", u.String(), err) return } wsConn := websocketconn.New(ws) - log.Printf("connected to relay") + log.Printf("connected to relay: %v", relayURL) defer wsConn.Close() copyLoop(conn, wsConn, sf.shutdown) log.Printf("datachannelHandler ends") } +type dataChannelHandlerWithRelayURL struct { + RelayURL string + sf *SnowflakeProxy +} + +func (d dataChannelHandlerWithRelayURL) datachannelHandler(conn *webRTCConn, remoteAddr net.Addr) { + d.sf.datachannelHandler(conn, remoteAddr, d.RelayURL) +} + // Create a PeerConnection from an SDP offer. Blocks until the gathering of ICE // candidates is complete and the answer is available in LocalDescription. // Installs an OnDataChannel callback that creates a webRTCConn and passes it to @@ -470,14 +490,27 @@ } func (sf *SnowflakeProxy) runSession(sid string) { - offer := broker.pollOffer(sid, sf.ProxyType, sf.shutdown) + offer, relayURL := broker.pollOffer(sid, sf.ProxyType, sf.RelayDomainNamePattern, sf.shutdown) if offer == nil { log.Printf("bad offer from broker") tokens.ret() return } + matcher := namematcher.NewNameMatcher(sf.RelayDomainNamePattern) + parsedRelayURL, err := url.Parse(relayURL) + if err != nil { + log.Printf("bad offer from broker: bad Relay URL %v", err.Error()) + tokens.ret() + return + } + if relayURL != "" && (!matcher.IsMember(parsedRelayURL.Hostname()) || (!sf.AllowNonTLSRelay && parsedRelayURL.Scheme != "wss")) { + log.Printf("bad offer from broker: rejected Relay URL") + tokens.ret() + return + } dataChan := make(chan struct{}) - pc, err := sf.makePeerConnectionFromOffer(offer, config, dataChan, sf.datachannelHandler) + dataChannelAdaptor := dataChannelHandlerWithRelayURL{RelayURL: relayURL, sf: sf} + pc, err := sf.makePeerConnectionFromOffer(offer, config, dataChan, dataChannelAdaptor.datachannelHandler) if err != nil { log.Printf("error making WebRTC connection: %s", err) tokens.ret() @@ -549,6 +582,10 @@ return fmt.Errorf("invalid relay url: %s", err) } + if !namematcher.IsValidRule(sf.RelayDomainNamePattern) { + return fmt.Errorf("invalid relay domain name pattern") + } + config = webrtc.Configuration{ ICEServers: []webrtc.ICEServer{ { @@ -574,7 +611,7 @@ } if sf.NATTypeMeasurementInterval != 0 { - NatRetestTask.Start() + NatRetestTask.WaitThenStart() defer NatRetestTask.Close() } diff -Nru snowflake-2.2.0/proxy/main.go snowflake-2.3.1/proxy/main.go --- snowflake-2.2.0/proxy/main.go 2022-05-25 16:17:54.000000000 +0000 +++ snowflake-2.3.1/proxy/main.go 2022-09-23 12:08:13.000000000 +0000 @@ -21,6 +21,8 @@ unsafeLogging := flag.Bool("unsafe-logging", false, "prevent logs from being scrubbed") keepLocalAddresses := flag.Bool("keep-local-addresses", false, "keep local LAN address ICE candidates") relayURL := flag.String("relay", sf.DefaultRelayURL, "websocket relay URL") + allowedRelayHostNamePattern := flag.String("allowed-relay-hostname-pattern", "snowflake.torproject.net$", "a pattern to specify allowed hostname pattern for relay URL.") + allowNonTLSRelay := flag.Bool("allow-non-tls-relay", false, "allow relay without tls encryption") NATTypeMeasurementInterval := flag.Duration("nat-retest-interval", time.Hour*24, "the time interval in second before NAT type is retested, 0s disables retest. Valid time units are \"s\", \"m\", \"h\". ") SummaryInterval := flag.Duration("summary-interval", time.Hour, @@ -40,6 +42,9 @@ NATTypeMeasurementInterval: *NATTypeMeasurementInterval, EventDispatcher: eventLogger, + + RelayDomainNamePattern: *allowedRelayHostNamePattern, + AllowNonTLSRelay: *allowNonTLSRelay, } var logOutput io.Writer = os.Stderr