Преглед изворни кода

Support multiple "own" server entries

Rod Hynes пре 6 година
родитељ
комит
ef8c9caf12
3 измењених фајлова са 31 додато и 27 уклоњено
  1. 14 8
      psiphon/server/api.go
  2. 14 17
      psiphon/server/psinet/psinet.go
  3. 3 2
      psiphon/serverApi.go

+ 14 - 8
psiphon/server/api.go

@@ -295,8 +295,16 @@ func handshakeAPIRequestHandler(
 	// When the client indicates that it used an unsigned server entry for this
 	// connection, return a signed copy of the server entry for the client to
 	// upgrade to. See also: comment in psiphon.doHandshakeRequest.
-	if getOptionalBooleanFlagRequestParam(params, "missing_server_entry_signature") {
-		ownServerEntry, ok := db.OwnServerEntry()
+	//
+	// The missing_server_entry_signature parameter value is a server entry tag,
+	// which is used to select the correct server entry for servers with multiple
+	// entries. Identifying the server entries tags instead of server IPs prevents
+	// an enumeration attack, where a malicious client can abuse this facilty to
+	// check if an arbitrary IP address is a Psiphon server.
+	serverEntryTag, ok := getOptionalStringRequestParam(
+		params, "missing_server_entry_signature")
+	if ok {
+		ownServerEntry, ok := db.OwnServerEntry(serverEntryTag)
 		if ok {
 			encodedServerList = append(encodedServerList, ownServerEntry)
 		}
@@ -1020,17 +1028,15 @@ func makeSpeedTestSamplesLogField(samples []interface{}) []interface{} {
 	return logSamples
 }
 
-// getOptionalBooleanFlagRequestParam returns true only if the field exists,
-// and is a true flag value, "1". Otherwise, it returns false.
-func getOptionalBooleanFlagRequestParam(params common.APIParameters, name string) bool {
+func getOptionalStringRequestParam(params common.APIParameters, name string) (string, bool) {
 	if params[name] == nil {
-		return false
+		return "", false
 	}
 	value, ok := params[name].(string)
 	if !ok {
-		return false
+		return "", false
 	}
-	return value == "1"
+	return value, true
 }
 
 func getStringRequestParam(params common.APIParameters, name string) (string, error) {

+ 14 - 17
psiphon/server/psinet/psinet.go

@@ -44,12 +44,12 @@ const (
 type Database struct {
 	common.ReloadableFile
 
-	Sponsors              map[string]*Sponsor        `json:"sponsors"`
-	Versions              map[string][]ClientVersion `json:"client_versions"`
-	DefaultSponsorID      string                     `json:"default_sponsor_id"`
-	ValidServerEntryTags  map[string]bool            `json:"valid_server_entry_tags"`
-	OwnEncodedServerEntry string                     `json:"own_encoded_server_entry"`
-	DiscoveryServers      []*DiscoveryServer         `json:"discovery_servers`
+	Sponsors                map[string]*Sponsor        `json:"sponsors"`
+	Versions                map[string][]ClientVersion `json:"client_versions"`
+	DefaultSponsorID        string                     `json:"default_sponsor_id"`
+	ValidServerEntryTags    map[string]bool            `json:"valid_server_entry_tags"`
+	OwnEncodedServerEntries map[string]string          `json:"own_encoded_server_entries"`
+	DiscoveryServers        []*DiscoveryServer         `json:"discovery_servers`
 
 	fileModTime time.Time
 }
@@ -116,7 +116,7 @@ func NewDatabase(filename string) (*Database, error) {
 			database.Versions = newDatabase.Versions
 			database.DefaultSponsorID = newDatabase.DefaultSponsorID
 			database.ValidServerEntryTags = newDatabase.ValidServerEntryTags
-			database.OwnEncodedServerEntry = newDatabase.OwnEncodedServerEntry
+			database.OwnEncodedServerEntries = newDatabase.OwnEncodedServerEntries
 			database.DiscoveryServers = newDatabase.DiscoveryServers
 			database.fileModTime = fileModTime
 
@@ -256,22 +256,19 @@ func (db *Database) GetHttpsRequestRegexes(sponsorID string) []map[string]string
 	return regexes
 }
 
-// OwnServerEntry returns the server's own server entry. This is returned, in
-// the handshake, to clients that don't yet have a signed copy of this server
-// entry.
+// OwnServerEntry returns one of the server's own server entries, as
+// identified by the server entry tag. This is returned, in the handshake, to
+// clients that don't yet have a signed copy of this server entry.
 //
 // For purposed of compartmentalization, each server stores only its own
-// server entry, along with the discovery server entries necessary for the
+// server entries, along with the discovery server entries necessary for the
 // discovery feature.
-func (db *Database) OwnServerEntry() (string, bool) {
+func (db *Database) OwnServerEntry(serverEntryTag string) (string, bool) {
 	db.ReloadableFile.RLock()
 	defer db.ReloadableFile.RUnlock()
 
-	if db.OwnEncodedServerEntry != "" {
-		return db.OwnEncodedServerEntry, true
-	}
-
-	return "", false
+	serverEntry, ok := db.OwnEncodedServerEntries[serverEntryTag]
+	return serverEntry, ok
 }
 
 // DiscoverServers selects new encoded server entries to be "discovered" by

+ 3 - 2
psiphon/serverApi.go

@@ -117,7 +117,7 @@ func (serverContext *ServerContext) doHandshakeRequest(
 	params := serverContext.getBaseAPIParameters()
 
 	// The server will return a signed copy of its own server entry when the
-	// client specifies this 'missing_server_entry_signature' flag.
+	// client specifies this 'missing_server_entry_signature' parameter.
 	//
 	// The purpose of this mechanism is to rapidly upgrade client local storage
 	// from unsigned to signed server entries, and to ensure that the client has
@@ -127,7 +127,8 @@ func (serverContext *ServerContext) doHandshakeRequest(
 	// The server entry will be included in handshakeResponse.EncodedServerList,
 	// along side discovery servers.
 	if !serverContext.tunnel.dialParams.ServerEntry.HasSignature() {
-		params["missing_server_entry_signature"] = "1"
+		params["missing_server_entry_signature"] =
+			serverContext.tunnel.dialParams.ServerEntry.Tag
 	}
 
 	doTactics := !serverContext.tunnel.config.DisableTactics