Browse Source

Add dynamic relay lookup (DDoS relays.syncthing.net!)

Audrius Butkevicius 10 years ago
parent
commit
6cccd9b6fc
3 changed files with 65 additions and 11 deletions
  1. 1 1
      lib/config/config.go
  2. 1 0
      lib/config/config_test.go
  3. 63 10
      lib/relay/relay.go

+ 1 - 1
lib/config/config.go

@@ -219,7 +219,7 @@ type OptionsConfiguration struct {
 	LocalAnnEnabled         bool     `xml:"localAnnounceEnabled" json:"localAnnounceEnabled" default:"true"`
 	LocalAnnPort            int      `xml:"localAnnouncePort" json:"localAnnouncePort" default:"21025"`
 	LocalAnnMCAddr          string   `xml:"localAnnounceMCAddr" json:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
-	RelayServers            []string `xml:"relayServer" json:"relayServers" default:""`
+	RelayServers            []string `xml:"relayServer" json:"relayServers" default:"dynamic+https://relays.syncthing.net"`
 	MaxSendKbps             int      `xml:"maxSendKbps" json:"maxSendKbps"`
 	MaxRecvKbps             int      `xml:"maxRecvKbps" json:"maxRecvKbps"`
 	ReconnectIntervalS      int      `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"`

+ 1 - 0
lib/config/config_test.go

@@ -37,6 +37,7 @@ func TestDefaultValues(t *testing.T) {
 		LocalAnnEnabled:         true,
 		LocalAnnPort:            21025,
 		LocalAnnMCAddr:          "[ff32::5222]:21026",
+		RelayServers:            []string{"dynamic+https://relays.syncthing.net"},
 		MaxSendKbps:             0,
 		MaxRecvKbps:             0,
 		ReconnectIntervalS:      60,

+ 63 - 10
lib/relay/relay.go

@@ -8,7 +8,9 @@ package relay
 
 import (
 	"crypto/tls"
+	"encoding/json"
 	"net"
+	"net/http"
 	"net/url"
 	"time"
 
@@ -82,7 +84,8 @@ func (s *Svc) VerifyConfiguration(from, to config.Configuration) error {
 }
 
 func (s *Svc) CommitConfiguration(from, to config.Configuration) bool {
-	existing := make(map[string]struct{}, len(to.Options.RelayServers))
+	existing := make(map[string]*url.URL, len(to.Options.RelayServers))
+
 	for _, addr := range to.Options.RelayServers {
 		uri, err := url.Parse(addr)
 		if err != nil {
@@ -91,32 +94,74 @@ func (s *Svc) CommitConfiguration(from, to config.Configuration) bool {
 			}
 			continue
 		}
+		existing[uri.String()] = uri
+	}
+
+	// Expand dynamic addresses into a set of relays
+	for key, uri := range existing {
+		if uri.Scheme != "dynamic+http" && uri.Scheme != "dynamic+https" {
+			continue
+		}
+		delete(existing, key)
+
+		uri.Scheme = uri.Scheme[8:]
 
-		existing[uri.String()] = struct{}{}
+		data, err := http.Get(uri.String())
+		if err != nil {
+			if debug {
+				l.Debugln("Failed to lookup dynamic relays", err)
+			}
+			continue
+		}
+
+		var ann dynamicAnnouncement
+		err = json.NewDecoder(data.Body).Decode(&ann)
+		data.Body.Close()
+		if err != nil {
+			if debug {
+				l.Debugln("Failed to lookup dynamic relays", err)
+			}
+			continue
+		}
+		for _, relayAnn := range ann.Relays {
+			ruri, err := url.Parse(relayAnn.URL)
+			if err != nil {
+				if debug {
+					l.Debugln("Failed to parse dynamic relay address", relayAnn.URL, err)
+				}
+				continue
+			}
+			if debug {
+				l.Debugln("Found", ruri, "via", uri)
+			}
+			existing[ruri.String()] = ruri
+		}
+	}
 
-		_, ok := s.tokens[uri.String()]
+	for key, uri := range existing {
+		_, ok := s.tokens[key]
 		if !ok {
 			if debug {
 				l.Debugln("Connecting to relay", uri)
 			}
 			c := client.NewProtocolClient(uri, s.tlsCfg.Certificates, s.invitations)
-			s.tokens[uri.String()] = s.Add(c)
+			s.tokens[key] = s.Add(c)
 			s.mut.Lock()
-			s.clients[uri.String()] = c
+			s.clients[key] = c
 			s.mut.Unlock()
 		}
 	}
 
-	for uri, token := range s.tokens {
-		_, ok := existing[uri]
+	for key, token := range s.tokens {
+		_, ok := existing[key]
 		if !ok {
 			err := s.Remove(token)
-			delete(s.tokens, uri)
+			delete(s.tokens, key)
 			s.mut.Lock()
-			delete(s.clients, uri)
+			delete(s.clients, key)
 			s.mut.Unlock()
 			if debug {
-				l.Debugln("Disconnecting from relay", uri, err)
+				l.Debugln("Disconnecting from relay", key, err)
 			}
 		}
 	}
@@ -195,3 +240,11 @@ func (r *invitationReceiver) Stop() {
 	r.stop <- struct{}{}
 	r.stop = nil
 }
+
+type dynamicAnnouncement struct {
+	Relays []relayAnnouncement `json:"relays"`
+}
+
+type relayAnnouncement struct {
+	URL string `json:"url"`
+}