Просмотр исходного кода

Use file modification time as psinet timestamp

Rod Hynes 7 лет назад
Родитель
Сommit
46a7d60a80

+ 1 - 1
psiphon/common/osl/osl.go

@@ -260,7 +260,7 @@ func NewConfig(filename string) (*Config, error) {
 	config.ReloadableFile = common.NewReloadableFile(
 		filename,
 		true,
-		func(fileContent []byte) error {
+		func(fileContent []byte, _ time.Time) error {
 			newConfig, err := LoadConfig(fileContent)
 			if err != nil {
 				return common.ContextError(err)

+ 15 - 6
psiphon/common/reloader.go

@@ -25,6 +25,7 @@ import (
 	"io/ioutil"
 	"os"
 	"sync"
+	"time"
 )
 
 // Reloader represents a read-only, in-memory reloadable data object. For example,
@@ -53,9 +54,9 @@ type Reloader interface {
 // ReloadableFile has a multi-reader mutex for synchronization. Its Reload() function
 // will obtain a write lock before reloading the data structures. The actual reloading
 // action is to be provided via the reloadAction callback, which receives the content
-// of reloaded files and must process the new data (for example, unmarshall the contents
-// into data structures). All read access to the data structures should be guarded by
-// RLocks on the ReloadableFile mutex.
+// of reloaded files, along with file modification time, and must process the new data
+// (for example, unmarshall the contents into data structures). All read access to the
+// data structures should be guarded by RLocks on the ReloadableFile mutex.
 //
 // reloadAction must ensure that data structures revert to their previous state when
 // a reload fails.
@@ -65,7 +66,7 @@ type ReloadableFile struct {
 	filename        string
 	loadFileContent bool
 	checksum        uint64
-	reloadAction    func([]byte) error
+	reloadAction    func([]byte, time.Time) error
 }
 
 // NewReloadableFile initializes a new ReloadableFile.
@@ -77,7 +78,7 @@ type ReloadableFile struct {
 func NewReloadableFile(
 	filename string,
 	loadFileContent bool,
-	reloadAction func([]byte) error) ReloadableFile {
+	reloadAction func([]byte, time.Time) error) ReloadableFile {
 
 	return ReloadableFile{
 		filename:        filename,
@@ -122,6 +123,14 @@ func (reloadable *ReloadableFile) Reload() (bool, error) {
 	previousChecksum := reloadable.checksum
 	reloadable.RUnlock()
 
+	// Record the file modification time _before_ loading, as reload actions will
+	// assume that the content is at least as fresh as the modification time.
+	fileInfo, err := os.Stat(filename)
+	if err != nil {
+		return false, ContextError(err)
+	}
+	fileModTime := fileInfo.ModTime()
+
 	file, err := os.Open(filename)
 	if err != nil {
 		return false, ContextError(err)
@@ -165,7 +174,7 @@ func (reloadable *ReloadableFile) Reload() (bool, error) {
 	reloadable.Lock()
 	defer reloadable.Unlock()
 
-	err = reloadable.reloadAction(content)
+	err = reloadable.reloadAction(content, fileModTime)
 	if err != nil {
 		return false, ContextError(err)
 	}

+ 2 - 1
psiphon/common/reloader_test.go

@@ -25,6 +25,7 @@ import (
 	"os"
 	"path/filepath"
 	"testing"
+	"time"
 )
 
 func TestReloader(t *testing.T) {
@@ -48,7 +49,7 @@ func TestReloader(t *testing.T) {
 	file.ReloadableFile = NewReloadableFile(
 		filename,
 		true,
-		func(fileContent []byte) error {
+		func(fileContent []byte, _ time.Time) error {
 			file.contents = fileContent
 			return nil
 		})

+ 1 - 1
psiphon/common/tactics/tactics.go

@@ -437,7 +437,7 @@ func NewServer(
 	server.ReloadableFile = common.NewReloadableFile(
 		configFilename,
 		true,
-		func(fileContent []byte) error {
+		func(fileContent []byte, _ time.Time) error {
 
 			var newServer Server
 			err := json.Unmarshal(fileContent, &newServer)

+ 2 - 1
psiphon/server/blocklist.go

@@ -26,6 +26,7 @@ import (
 	"net"
 	"os"
 	"sync/atomic"
+	"time"
 
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 )
@@ -72,7 +73,7 @@ func NewBlocklist(filename string) (*Blocklist, error) {
 	blocklist.ReloadableFile = common.NewReloadableFile(
 		filename,
 		false,
-		func(_ []byte) error {
+		func(_ []byte, _ time.Time) error {
 
 			newData, err := loadBlocklistFromFile(filename)
 			if err != nil {

+ 1 - 1
psiphon/server/dns.go

@@ -79,7 +79,7 @@ func NewDNSResolver(defaultResolver string) (*DNSResolver, error) {
 	dns.ReloadableFile = common.NewReloadableFile(
 		DNS_SYSTEM_CONFIG_FILENAME,
 		true,
-		func(fileContent []byte) error {
+		func(fileContent []byte, _ time.Time) error {
 
 			resolvers, err := parseResolveConf(fileContent)
 			if err != nil {

+ 1 - 1
psiphon/server/geoip.go

@@ -100,7 +100,7 @@ func NewGeoIPService(
 		database.ReloadableFile = common.NewReloadableFile(
 			filename,
 			false,
-			func(_ []byte) error {
+			func(_ []byte, _ time.Time) error {
 
 				// In order to safely mmap the database file, a temporary copy
 				// is made and that copy is mmapped. The original file may be

+ 5 - 4
psiphon/server/psinet/psinet.go

@@ -46,13 +46,14 @@ const (
 type Database struct {
 	common.ReloadableFile
 
-	Timestamp            time.Time                  `json:"timestamp"`
 	Hosts                map[string]Host            `json:"hosts"`
 	Servers              []Server                   `json:"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"`
+
+	fileModTime time.Time
 }
 
 type Host struct {
@@ -139,7 +140,7 @@ func NewDatabase(filename string) (*Database, error) {
 	database.ReloadableFile = common.NewReloadableFile(
 		filename,
 		true,
-		func(fileContent []byte) error {
+		func(fileContent []byte, fileModTime time.Time) error {
 			var newDatabase Database
 			err := json.Unmarshal(fileContent, &newDatabase)
 			if err != nil {
@@ -147,13 +148,13 @@ func NewDatabase(filename string) (*Database, error) {
 			}
 			// Note: an unmarshal directly into &database would fail
 			// to reset to zero value fields not present in the JSON.
-			database.Timestamp = newDatabase.Timestamp
 			database.Hosts = newDatabase.Hosts
 			database.Servers = newDatabase.Servers
 			database.Sponsors = newDatabase.Sponsors
 			database.Versions = newDatabase.Versions
 			database.DefaultSponsorID = newDatabase.DefaultSponsorID
 			database.ValidServerEntryTags = newDatabase.ValidServerEntryTags
+			database.fileModTime = fileModTime
 
 			return nil
 		})
@@ -567,7 +568,7 @@ func (db *Database) IsValidServerEntryTag(serverEntryTag string) bool {
 	// issue with updating the database.
 
 	if len(db.ValidServerEntryTags) == 0 ||
-		db.Timestamp.Add(MAX_DATABASE_AGE_FOR_SERVER_ENTRY_VALIDITY).Before(time.Now()) {
+		db.fileModTime.Add(MAX_DATABASE_AGE_FOR_SERVER_ENTRY_VALIDITY).Before(time.Now()) {
 		return true
 	}
 

+ 0 - 2
psiphon/server/server_test.go

@@ -1528,7 +1528,6 @@ func pavePsinetDatabaseFile(
 
 	psinetJSONFormat := `
     {
-        "timestamp" : "%s",
         "default_sponsor_id" : "%s",
         "sponsors": {
             "%s": {
@@ -1558,7 +1557,6 @@ func pavePsinetDatabaseFile(
 
 	psinetJSON := fmt.Sprintf(
 		psinetJSONFormat,
-		common.GetCurrentTimestamp(),
 		defaultSponsorID,
 		sponsorID,
 		expectedHomepageURL,

+ 2 - 1
psiphon/server/trafficRules.go

@@ -24,6 +24,7 @@ import (
 	"errors"
 	"fmt"
 	"net"
+	"time"
 
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 )
@@ -258,7 +259,7 @@ func NewTrafficRulesSet(filename string) (*TrafficRulesSet, error) {
 	set.ReloadableFile = common.NewReloadableFile(
 		filename,
 		true,
-		func(fileContent []byte) error {
+		func(fileContent []byte, _ time.Time) error {
 			var newSet TrafficRulesSet
 			err := json.Unmarshal(fileContent, &newSet)
 			if err != nil {