github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/dataStore.go (about) 1 /* 2 * Copyright (c) 2015, Psiphon Inc. 3 * All rights reserved. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package psiphon 21 22 import ( 23 "bytes" 24 "context" 25 "encoding/json" 26 "io" 27 "math" 28 "os" 29 "strings" 30 "sync" 31 "time" 32 33 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 34 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 35 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters" 36 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" 37 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol" 38 ) 39 40 var ( 41 datastoreServerEntriesBucket = []byte("serverEntries") 42 datastoreServerEntryTagsBucket = []byte("serverEntryTags") 43 datastoreServerEntryTombstoneTagsBucket = []byte("serverEntryTombstoneTags") 44 datastoreUrlETagsBucket = []byte("urlETags") 45 datastoreKeyValueBucket = []byte("keyValues") 46 datastoreRemoteServerListStatsBucket = []byte("remoteServerListStats") 47 datastoreFailedTunnelStatsBucket = []byte("failedTunnelStats") 48 datastoreSLOKsBucket = []byte("SLOKs") 49 datastoreTacticsBucket = []byte("tactics") 50 datastoreSpeedTestSamplesBucket = []byte("speedTestSamples") 51 datastoreDialParametersBucket = []byte("dialParameters") 52 datastoreLastConnectedKey = "lastConnected" 53 datastoreLastServerEntryFilterKey = []byte("lastServerEntryFilter") 54 datastoreAffinityServerEntryIDKey = []byte("affinityServerEntryID") 55 datastorePersistentStatTypeRemoteServerList = string(datastoreRemoteServerListStatsBucket) 56 datastorePersistentStatTypeFailedTunnel = string(datastoreFailedTunnelStatsBucket) 57 datastoreServerEntryFetchGCThreshold = 10 58 59 datastoreReferenceCountMutex sync.RWMutex 60 datastoreReferenceCount int64 61 datastoreMutex sync.RWMutex 62 activeDatastoreDB *datastoreDB 63 ) 64 65 // OpenDataStore opens and initializes the singleton datastore instance. 66 // 67 // Nested Open/CloseDataStore calls are supported: OpenDataStore will succeed 68 // when called when the datastore is initialized. Every call to OpenDataStore 69 // must be paired with a corresponding call to CloseDataStore to ensure the 70 // datastore is closed. 71 func OpenDataStore(config *Config) error { 72 return openDataStore(config, true) 73 } 74 75 // OpenDataStoreWithoutRetry performs an OpenDataStore but does not retry or 76 // reset the datastore file in case of failures. Use 77 // OpenDataStoreWithoutRetry when the datastore is expected to be locked by 78 // another process and faster failure is preferred. 79 func OpenDataStoreWithoutRetry(config *Config) error { 80 return openDataStore(config, false) 81 } 82 83 func openDataStore(config *Config, retryAndReset bool) error { 84 85 // The datastoreReferenceCountMutex/datastoreMutex mutex pair allow for: 86 // 87 // _Nested_ OpenDataStore/CloseDataStore calls to not block when a 88 // datastoreView is in progress (for example, a GetDialParameters call while 89 // a slow ScanServerEntries is running). In this case the nested 90 // OpenDataStore/CloseDataStore calls will lock only 91 // datastoreReferenceCountMutex and not datastoreMutex. 92 // 93 // Synchronized access, for OpenDataStore/CloseDataStore, to 94 // activeDatastoreDB based on a consistent view of datastoreReferenceCount 95 // via locking first datastoreReferenceCount and then datastoreMutex while 96 // holding datastoreReferenceCount. 97 // 98 // Concurrent access, for datastoreView/datastoreUpdate, to activeDatastoreDB 99 // via datastoreMutex read locks. 100 // 101 // Exclusive access, for OpenDataStore/CloseDataStore, to activeDatastoreDB, 102 // with no running datastoreView/datastoreUpdate, by aquiring a 103 // datastoreMutex write lock. 104 105 datastoreReferenceCountMutex.Lock() 106 107 if datastoreReferenceCount < 0 || datastoreReferenceCount == math.MaxInt64 { 108 datastoreReferenceCountMutex.Unlock() 109 return errors.Tracef( 110 "invalid datastore reference count: %d", datastoreReferenceCount) 111 } 112 113 if datastoreReferenceCount > 0 { 114 115 // For this sanity check, we need only the read-only lock; and must use the 116 // read-only lock to allow concurrent datastoreView calls. 117 118 datastoreMutex.RLock() 119 isNil := activeDatastoreDB == nil 120 datastoreMutex.RUnlock() 121 if isNil { 122 return errors.TraceNew("datastore unexpectedly closed") 123 } 124 125 // Add a reference to the open datastore. 126 127 datastoreReferenceCount += 1 128 datastoreReferenceCountMutex.Unlock() 129 return nil 130 } 131 132 // Only lock datastoreMutex now that it's necessary. 133 // datastoreReferenceCountMutex remains locked. 134 datastoreMutex.Lock() 135 136 if activeDatastoreDB != nil { 137 datastoreMutex.Unlock() 138 datastoreReferenceCountMutex.Unlock() 139 return errors.TraceNew("datastore unexpectedly open") 140 } 141 142 // datastoreReferenceCount is 0, so open the datastore. 143 144 newDB, err := datastoreOpenDB( 145 config.GetDataStoreDirectory(), retryAndReset) 146 if err != nil { 147 datastoreMutex.Unlock() 148 datastoreReferenceCountMutex.Unlock() 149 return errors.Trace(err) 150 } 151 152 datastoreReferenceCount = 1 153 activeDatastoreDB = newDB 154 datastoreMutex.Unlock() 155 datastoreReferenceCountMutex.Unlock() 156 157 _ = resetAllPersistentStatsToUnreported() 158 159 return nil 160 } 161 162 // CloseDataStore closes the singleton datastore instance, if open. 163 func CloseDataStore() { 164 165 datastoreReferenceCountMutex.Lock() 166 defer datastoreReferenceCountMutex.Unlock() 167 168 if datastoreReferenceCount <= 0 { 169 NoticeWarning( 170 "invalid datastore reference count: %d", datastoreReferenceCount) 171 return 172 } 173 datastoreReferenceCount -= 1 174 if datastoreReferenceCount > 0 { 175 return 176 } 177 178 // Only lock datastoreMutex now that it's necessary. 179 // datastoreReferenceCountMutex remains locked. 180 datastoreMutex.Lock() 181 defer datastoreMutex.Unlock() 182 183 if activeDatastoreDB == nil { 184 return 185 } 186 187 err := activeDatastoreDB.close() 188 if err != nil { 189 NoticeWarning("failed to close datastore: %s", errors.Trace(err)) 190 } 191 192 activeDatastoreDB = nil 193 } 194 195 // GetDataStoreMetrics returns a string logging datastore metrics. 196 func GetDataStoreMetrics() string { 197 datastoreMutex.RLock() 198 defer datastoreMutex.RUnlock() 199 200 if activeDatastoreDB == nil { 201 return "" 202 } 203 204 return activeDatastoreDB.getDataStoreMetrics() 205 } 206 207 // datastoreView runs a read-only transaction, making datastore buckets and 208 // values available to the supplied function. 209 // 210 // Bucket value slices are only valid for the duration of the transaction and 211 // _must_ not be referenced directly outside the transaction. 212 func datastoreView(fn func(tx *datastoreTx) error) error { 213 214 datastoreMutex.RLock() 215 defer datastoreMutex.RUnlock() 216 217 if activeDatastoreDB == nil { 218 return errors.TraceNew("datastore not open") 219 } 220 221 err := activeDatastoreDB.view(fn) 222 if err != nil { 223 err = errors.Trace(err) 224 } 225 return err 226 } 227 228 // datastoreUpdate runs a read-write transaction, making datastore buckets and 229 // values available to the supplied function. 230 // 231 // Bucket value slices are only valid for the duration of the transaction and 232 // _must_ not be referenced directly outside the transaction. 233 func datastoreUpdate(fn func(tx *datastoreTx) error) error { 234 235 datastoreMutex.RLock() 236 defer datastoreMutex.RUnlock() 237 238 if activeDatastoreDB == nil { 239 return errors.TraceNew("database not open") 240 } 241 242 err := activeDatastoreDB.update(fn) 243 if err != nil { 244 err = errors.Trace(err) 245 } 246 return err 247 } 248 249 // StoreServerEntry adds the server entry to the datastore. 250 // 251 // When a server entry already exists for a given server, it will be 252 // replaced only if replaceIfExists is set or if the the ConfigurationVersion 253 // field of the new entry is strictly higher than the existing entry. 254 // 255 // If the server entry data is malformed, an alert notice is issued and 256 // the entry is skipped; no error is returned. 257 func StoreServerEntry(serverEntryFields protocol.ServerEntryFields, replaceIfExists bool) error { 258 259 // TODO: call serverEntryFields.VerifySignature. At this time, we do not do 260 // this as not all server entries have an individual signature field. All 261 // StoreServerEntry callers either call VerifySignature or obtain server 262 // entries from a trusted source (embedded in a signed client, or in a signed 263 // authenticated package). 264 265 // Server entries should already be validated before this point, 266 // so instead of skipping we fail with an error. 267 err := protocol.ValidateServerEntryFields(serverEntryFields) 268 if err != nil { 269 return errors.Tracef("invalid server entry: %s", err) 270 } 271 272 // BoltDB implementation note: 273 // For simplicity, we don't maintain indexes on server entry 274 // region or supported protocols. Instead, we perform full-bucket 275 // scans with a filter. With a small enough database (thousands or 276 // even tens of thousand of server entries) and common enough 277 // values (e.g., many servers support all protocols), performance 278 // is expected to be acceptable. 279 280 err = datastoreUpdate(func(tx *datastoreTx) error { 281 282 serverEntries := tx.bucket(datastoreServerEntriesBucket) 283 serverEntryTags := tx.bucket(datastoreServerEntryTagsBucket) 284 serverEntryTombstoneTags := tx.bucket(datastoreServerEntryTombstoneTagsBucket) 285 286 serverEntryID := []byte(serverEntryFields.GetIPAddress()) 287 288 // Check not only that the entry exists, but is valid. This 289 // will replace in the rare case where the data is corrupt. 290 existingConfigurationVersion := -1 291 existingData := serverEntries.get(serverEntryID) 292 if existingData != nil { 293 var existingServerEntry *protocol.ServerEntry 294 err := json.Unmarshal(existingData, &existingServerEntry) 295 if err == nil { 296 existingConfigurationVersion = existingServerEntry.ConfigurationVersion 297 } 298 } 299 300 exists := existingConfigurationVersion > -1 301 newer := exists && existingConfigurationVersion < serverEntryFields.GetConfigurationVersion() 302 update := !exists || replaceIfExists || newer 303 304 if !update { 305 return nil 306 } 307 308 serverEntryTag := serverEntryFields.GetTag() 309 310 // Generate a derived tag when the server entry has no tag. 311 if serverEntryTag == "" { 312 313 serverEntryTag = protocol.GenerateServerEntryTag( 314 serverEntryFields.GetIPAddress(), 315 serverEntryFields.GetWebServerSecret()) 316 317 serverEntryFields.SetTag(serverEntryTag) 318 } 319 320 serverEntryTagBytes := []byte(serverEntryTag) 321 322 // Ignore the server entry if it was previously pruned and a tombstone is 323 // set. 324 // 325 // This logic is enforced only for embedded server entries, as all other 326 // sources are considered to be definitive and non-stale. These exceptions 327 // intentionally allow the scenario where a server is temporarily deleted 328 // and then restored; in this case, it's desired for pruned server entries 329 // to be restored. 330 if serverEntryFields.GetLocalSource() == protocol.SERVER_ENTRY_SOURCE_EMBEDDED { 331 if serverEntryTombstoneTags.get(serverEntryTagBytes) != nil { 332 return nil 333 } 334 } 335 336 data, err := json.Marshal(serverEntryFields) 337 if err != nil { 338 return errors.Trace(err) 339 } 340 341 err = serverEntries.put(serverEntryID, data) 342 if err != nil { 343 return errors.Trace(err) 344 } 345 346 err = serverEntryTags.put(serverEntryTagBytes, serverEntryID) 347 if err != nil { 348 return errors.Trace(err) 349 } 350 351 NoticeInfo("updated server %s", serverEntryFields.GetDiagnosticID()) 352 353 return nil 354 }) 355 if err != nil { 356 return errors.Trace(err) 357 } 358 359 return nil 360 } 361 362 // StoreServerEntries stores a list of server entries. 363 // There is an independent transaction for each entry insert/update. 364 func StoreServerEntries( 365 config *Config, 366 serverEntries []protocol.ServerEntryFields, 367 replaceIfExists bool) error { 368 369 for _, serverEntryFields := range serverEntries { 370 err := StoreServerEntry(serverEntryFields, replaceIfExists) 371 if err != nil { 372 return errors.Trace(err) 373 } 374 } 375 376 return nil 377 } 378 379 // StreamingStoreServerEntries stores a list of server entries. There is an 380 // independent transaction for each entry insert/update. 381 // StreamingStoreServerEntries stops early and returns an error if ctx becomes 382 // done; any server entries stored up to that point are retained. 383 func StreamingStoreServerEntries( 384 ctx context.Context, 385 config *Config, 386 serverEntries *protocol.StreamingServerEntryDecoder, 387 replaceIfExists bool) error { 388 389 // Note: both StreamingServerEntryDecoder.Next and StoreServerEntry 390 // allocate temporary memory buffers for hex/JSON decoding/encoding, 391 // so this isn't true constant-memory streaming (it depends on garbage 392 // collection). 393 394 n := 0 395 for { 396 397 select { 398 case <-ctx.Done(): 399 return errors.Trace(ctx.Err()) 400 default: 401 } 402 403 serverEntry, err := serverEntries.Next() 404 if err != nil { 405 return errors.Trace(err) 406 } 407 408 if serverEntry == nil { 409 // No more server entries 410 return nil 411 } 412 413 err = StoreServerEntry(serverEntry, replaceIfExists) 414 if err != nil { 415 return errors.Trace(err) 416 } 417 418 n += 1 419 if n == datastoreServerEntryFetchGCThreshold { 420 DoGarbageCollection() 421 n = 0 422 } 423 } 424 425 return nil 426 } 427 428 // ImportEmbeddedServerEntries loads, decodes, and stores a list of server 429 // entries. If embeddedServerEntryListFilename is not empty, 430 // embeddedServerEntryList will be ignored and the encoded server entry list 431 // will be loaded from the specified file. The import process stops early if 432 // ctx becomes done; any server entries imported up to that point are 433 // retained. 434 func ImportEmbeddedServerEntries( 435 ctx context.Context, 436 config *Config, 437 embeddedServerEntryListFilename string, 438 embeddedServerEntryList string) error { 439 440 var reader io.Reader 441 442 if embeddedServerEntryListFilename != "" { 443 444 file, err := os.Open(embeddedServerEntryListFilename) 445 if err != nil { 446 return errors.Trace(err) 447 } 448 defer file.Close() 449 450 reader = file 451 452 } else { 453 454 reader = strings.NewReader(embeddedServerEntryList) 455 } 456 457 err := StreamingStoreServerEntries( 458 ctx, 459 config, 460 protocol.NewStreamingServerEntryDecoder( 461 reader, 462 common.TruncateTimestampToHour(common.GetCurrentTimestamp()), 463 protocol.SERVER_ENTRY_SOURCE_EMBEDDED), 464 false) 465 if err != nil { 466 return errors.Trace(err) 467 } 468 469 return nil 470 } 471 472 // PromoteServerEntry sets the server affinity server entry ID to the 473 // specified server entry IP address. 474 func PromoteServerEntry(config *Config, ipAddress string) error { 475 err := datastoreUpdate(func(tx *datastoreTx) error { 476 477 serverEntryID := []byte(ipAddress) 478 479 // Ensure the corresponding server entry exists before 480 // setting server affinity. 481 bucket := tx.bucket(datastoreServerEntriesBucket) 482 data := bucket.get(serverEntryID) 483 if data == nil { 484 NoticeWarning( 485 "PromoteServerEntry: ignoring unknown server entry: %s", 486 ipAddress) 487 return nil 488 } 489 490 bucket = tx.bucket(datastoreKeyValueBucket) 491 err := bucket.put(datastoreAffinityServerEntryIDKey, serverEntryID) 492 if err != nil { 493 return errors.Trace(err) 494 } 495 496 // Store the current server entry filter (e.g, region, etc.) that 497 // was in use when the entry was promoted. This is used to detect 498 // when the top ranked server entry was promoted under a different 499 // filter. 500 501 currentFilter, err := makeServerEntryFilterValue(config) 502 if err != nil { 503 return errors.Trace(err) 504 } 505 506 err = bucket.put(datastoreLastServerEntryFilterKey, currentFilter) 507 if err != nil { 508 return errors.Trace(err) 509 } 510 511 return nil 512 }) 513 514 if err != nil { 515 return errors.Trace(err) 516 } 517 return nil 518 } 519 520 // DeleteServerEntryAffinity clears server affinity if set to the specified 521 // server. 522 func DeleteServerEntryAffinity(ipAddress string) error { 523 err := datastoreUpdate(func(tx *datastoreTx) error { 524 525 serverEntryID := []byte(ipAddress) 526 527 bucket := tx.bucket(datastoreKeyValueBucket) 528 529 affinityServerEntryID := bucket.get(datastoreAffinityServerEntryIDKey) 530 531 if bytes.Equal(affinityServerEntryID, serverEntryID) { 532 err := bucket.delete(datastoreAffinityServerEntryIDKey) 533 if err != nil { 534 return errors.Trace(err) 535 } 536 err = bucket.delete(datastoreLastServerEntryFilterKey) 537 if err != nil { 538 return errors.Trace(err) 539 } 540 } 541 542 return nil 543 }) 544 545 if err != nil { 546 return errors.Trace(err) 547 } 548 return nil 549 } 550 551 func makeServerEntryFilterValue(config *Config) ([]byte, error) { 552 553 // Currently, only a change of EgressRegion will "break" server affinity. 554 // If the tunnel protocol filter changes, any existing affinity server 555 // either passes the new filter, or it will be skipped anyway. 556 557 return []byte(config.EgressRegion), nil 558 } 559 560 func hasServerEntryFilterChanged(config *Config) (bool, error) { 561 562 currentFilter, err := makeServerEntryFilterValue(config) 563 if err != nil { 564 return false, errors.Trace(err) 565 } 566 567 changed := false 568 err = datastoreView(func(tx *datastoreTx) error { 569 570 bucket := tx.bucket(datastoreKeyValueBucket) 571 previousFilter := bucket.get(datastoreLastServerEntryFilterKey) 572 573 // When not found, previousFilter will be nil; ensures this 574 // results in "changed", even if currentFilter is len(0). 575 if previousFilter == nil || 576 !bytes.Equal(previousFilter, currentFilter) { 577 changed = true 578 } 579 return nil 580 }) 581 if err != nil { 582 return false, errors.Trace(err) 583 } 584 585 return changed, nil 586 } 587 588 // ServerEntryIterator is used to iterate over 589 // stored server entries in rank order. 590 type ServerEntryIterator struct { 591 config *Config 592 applyServerAffinity bool 593 serverEntryIDs [][]byte 594 serverEntryIndex int 595 isTacticsServerEntryIterator bool 596 isTargetServerEntryIterator bool 597 hasNextTargetServerEntry bool 598 targetServerEntry *protocol.ServerEntry 599 } 600 601 // NewServerEntryIterator creates a new ServerEntryIterator. 602 // 603 // The boolean return value indicates whether to treat the first server(s) 604 // as affinity servers or not. When the server entry selection filter changes 605 // such as from a specific region to any region, or when there was no previous 606 // filter/iterator, the the first server(s) are arbitrary and should not be 607 // given affinity treatment. 608 // 609 // NewServerEntryIterator and any returned ServerEntryIterator are not 610 // designed for concurrent use as not all related datastore operations are 611 // performed in a single transaction. 612 // 613 func NewServerEntryIterator(config *Config) (bool, *ServerEntryIterator, error) { 614 615 // When configured, this target server entry is the only candidate 616 if config.TargetServerEntry != "" { 617 return newTargetServerEntryIterator(config, false) 618 } 619 620 filterChanged, err := hasServerEntryFilterChanged(config) 621 if err != nil { 622 return false, nil, errors.Trace(err) 623 } 624 625 applyServerAffinity := !filterChanged 626 627 iterator := &ServerEntryIterator{ 628 config: config, 629 applyServerAffinity: applyServerAffinity, 630 } 631 632 err = iterator.reset(true) 633 if err != nil { 634 return false, nil, errors.Trace(err) 635 } 636 637 return applyServerAffinity, iterator, nil 638 } 639 640 func NewTacticsServerEntryIterator(config *Config) (*ServerEntryIterator, error) { 641 642 // When configured, this target server entry is the only candidate 643 if config.TargetServerEntry != "" { 644 _, iterator, err := newTargetServerEntryIterator(config, true) 645 return iterator, err 646 } 647 648 iterator := &ServerEntryIterator{ 649 config: config, 650 isTacticsServerEntryIterator: true, 651 } 652 653 err := iterator.reset(true) 654 if err != nil { 655 return nil, errors.Trace(err) 656 } 657 658 return iterator, nil 659 } 660 661 // newTargetServerEntryIterator is a helper for initializing the TargetServerEntry case 662 func newTargetServerEntryIterator(config *Config, isTactics bool) (bool, *ServerEntryIterator, error) { 663 664 serverEntry, err := protocol.DecodeServerEntry( 665 config.TargetServerEntry, config.loadTimestamp, protocol.SERVER_ENTRY_SOURCE_TARGET) 666 if err != nil { 667 return false, nil, errors.Trace(err) 668 } 669 670 if serverEntry.Tag == "" { 671 serverEntry.Tag = protocol.GenerateServerEntryTag( 672 serverEntry.IpAddress, serverEntry.WebServerSecret) 673 } 674 675 if isTactics { 676 677 if len(serverEntry.GetSupportedTacticsProtocols()) == 0 { 678 return false, nil, errors.TraceNew("TargetServerEntry does not support tactics protocols") 679 } 680 681 } else { 682 683 if config.EgressRegion != "" && serverEntry.Region != config.EgressRegion { 684 return false, nil, errors.TraceNew("TargetServerEntry does not support EgressRegion") 685 } 686 687 p := config.GetParameters().Get() 688 limitTunnelProtocols := p.TunnelProtocols(parameters.LimitTunnelProtocols) 689 limitTunnelDialPortNumbers := protocol.TunnelProtocolPortLists( 690 p.TunnelProtocolPortLists(parameters.LimitTunnelDialPortNumbers)) 691 limitQUICVersions := p.QUICVersions(parameters.LimitQUICVersions) 692 693 if len(limitTunnelProtocols) > 0 { 694 // At the ServerEntryIterator level, only limitTunnelProtocols is applied; 695 // excludeIntensive is handled higher up. 696 if len(serverEntry.GetSupportedProtocols( 697 conditionallyEnabledComponents{}, 698 config.UseUpstreamProxy(), 699 limitTunnelProtocols, 700 limitTunnelDialPortNumbers, 701 limitQUICVersions, 702 false)) == 0 { 703 return false, nil, errors.Tracef( 704 "TargetServerEntry does not support LimitTunnelProtocols: %v", limitTunnelProtocols) 705 } 706 } 707 } 708 709 iterator := &ServerEntryIterator{ 710 isTacticsServerEntryIterator: isTactics, 711 isTargetServerEntryIterator: true, 712 hasNextTargetServerEntry: true, 713 targetServerEntry: serverEntry, 714 } 715 716 NoticeInfo("using TargetServerEntry: %s", serverEntry.GetDiagnosticID()) 717 718 return false, iterator, nil 719 } 720 721 // Reset a NewServerEntryIterator to the start of its cycle. The next 722 // call to Next will return the first server entry. 723 func (iterator *ServerEntryIterator) Reset() error { 724 return iterator.reset(false) 725 } 726 727 func (iterator *ServerEntryIterator) reset(isInitialRound bool) error { 728 iterator.Close() 729 730 if iterator.isTargetServerEntryIterator { 731 iterator.hasNextTargetServerEntry = true 732 return nil 733 } 734 735 // Support stand-alone GetTactics operation. See TacticsStorer for more 736 // details. 737 if iterator.isTacticsServerEntryIterator { 738 err := OpenDataStoreWithoutRetry(iterator.config) 739 if err != nil { 740 return errors.Trace(err) 741 } 742 defer CloseDataStore() 743 } 744 745 // BoltDB implementation note: 746 // We don't keep a transaction open for the duration of the iterator 747 // because this would expose the following semantics to consumer code: 748 // 749 // Read-only transactions and read-write transactions ... generally 750 // shouldn't be opened simultaneously in the same goroutine. This can 751 // cause a deadlock as the read-write transaction needs to periodically 752 // re-map the data file but it cannot do so while a read-only 753 // transaction is open. 754 // (https://github.com/boltdb/bolt) 755 // 756 // So the underlying serverEntriesBucket could change after the serverEntryIDs 757 // list is built. 758 759 var serverEntryIDs [][]byte 760 761 err := datastoreView(func(tx *datastoreTx) error { 762 763 bucket := tx.bucket(datastoreKeyValueBucket) 764 765 serverEntryIDs = make([][]byte, 0) 766 shuffleHead := 0 767 768 var affinityServerEntryID []byte 769 770 // In the first round only, move any server affinity candiate to the 771 // very first position. 772 773 if isInitialRound && 774 iterator.applyServerAffinity { 775 776 affinityServerEntryID = bucket.get(datastoreAffinityServerEntryIDKey) 777 if affinityServerEntryID != nil { 778 serverEntryIDs = append(serverEntryIDs, append([]byte(nil), affinityServerEntryID...)) 779 shuffleHead = 1 780 } 781 } 782 783 bucket = tx.bucket(datastoreServerEntriesBucket) 784 cursor := bucket.cursor() 785 for key := cursor.firstKey(); key != nil; key = cursor.nextKey() { 786 if affinityServerEntryID != nil { 787 if bytes.Equal(affinityServerEntryID, key) { 788 continue 789 } 790 } 791 serverEntryIDs = append(serverEntryIDs, append([]byte(nil), key...)) 792 } 793 cursor.close() 794 795 // Randomly shuffle the entire list of server IDs, excluding the 796 // server affinity candidate. 797 798 for i := len(serverEntryIDs) - 1; i > shuffleHead-1; i-- { 799 j := prng.Intn(i+1-shuffleHead) + shuffleHead 800 serverEntryIDs[i], serverEntryIDs[j] = serverEntryIDs[j], serverEntryIDs[i] 801 } 802 803 // In the first round, or with some probability, move _potential_ replay 804 // candidates to the front of the list (excepting the server affinity slot, 805 // if any). This move is post-shuffle so the order is still randomized. To 806 // save the memory overhead of unmarshalling all dial parameters, this 807 // operation just moves any server with a dial parameter record to the 808 // front. Whether the dial parameter remains valid for replay -- TTL, 809 // tactics/config unchanged, etc. --- is checked later. 810 // 811 // TODO: move only up to parameters.ReplayCandidateCount to front? 812 813 p := iterator.config.GetParameters().Get() 814 815 if (isInitialRound || p.WeightedCoinFlip(parameters.ReplayLaterRoundMoveToFrontProbability)) && 816 p.Int(parameters.ReplayCandidateCount) != 0 { 817 818 networkID := []byte(iterator.config.GetNetworkID()) 819 820 dialParamsBucket := tx.bucket(datastoreDialParametersBucket) 821 i := shuffleHead 822 j := len(serverEntryIDs) - 1 823 for { 824 for ; i < j; i++ { 825 key := makeDialParametersKey(serverEntryIDs[i], networkID) 826 if dialParamsBucket.get(key) == nil { 827 break 828 } 829 } 830 for ; i < j; j-- { 831 key := makeDialParametersKey(serverEntryIDs[j], networkID) 832 if dialParamsBucket.get(key) != nil { 833 break 834 } 835 } 836 if i < j { 837 serverEntryIDs[i], serverEntryIDs[j] = serverEntryIDs[j], serverEntryIDs[i] 838 i++ 839 j-- 840 } else { 841 break 842 } 843 } 844 } 845 846 return nil 847 }) 848 if err != nil { 849 return errors.Trace(err) 850 } 851 852 iterator.serverEntryIDs = serverEntryIDs 853 iterator.serverEntryIndex = 0 854 855 return nil 856 } 857 858 // Close cleans up resources associated with a ServerEntryIterator. 859 func (iterator *ServerEntryIterator) Close() { 860 iterator.serverEntryIDs = nil 861 iterator.serverEntryIndex = 0 862 } 863 864 // Next returns the next server entry, by rank, for a ServerEntryIterator. 865 // Returns nil with no error when there is no next item. 866 func (iterator *ServerEntryIterator) Next() (*protocol.ServerEntry, error) { 867 868 var serverEntry *protocol.ServerEntry 869 var err error 870 871 defer func() { 872 if err != nil { 873 iterator.Close() 874 } 875 }() 876 877 if iterator.isTargetServerEntryIterator { 878 if iterator.hasNextTargetServerEntry { 879 iterator.hasNextTargetServerEntry = false 880 return MakeCompatibleServerEntry(iterator.targetServerEntry), nil 881 } 882 return nil, nil 883 } 884 885 // Support stand-alone GetTactics operation. See TacticsStorer for more 886 // details. 887 if iterator.isTacticsServerEntryIterator { 888 err := OpenDataStoreWithoutRetry(iterator.config) 889 if err != nil { 890 return nil, errors.Trace(err) 891 } 892 defer CloseDataStore() 893 } 894 895 // There are no region/protocol indexes for the server entries bucket. 896 // Loop until we have the next server entry that matches the iterator 897 // filter requirements. 898 for { 899 if iterator.serverEntryIndex >= len(iterator.serverEntryIDs) { 900 // There is no next item 901 return nil, nil 902 } 903 904 serverEntryID := iterator.serverEntryIDs[iterator.serverEntryIndex] 905 iterator.serverEntryIndex += 1 906 907 serverEntry = nil 908 doDeleteServerEntry := false 909 910 err = datastoreView(func(tx *datastoreTx) error { 911 serverEntries := tx.bucket(datastoreServerEntriesBucket) 912 value := serverEntries.get(serverEntryID) 913 if value == nil { 914 return nil 915 } 916 917 // When the server entry has a signature and the signature verification 918 // public key is configured, perform a signature verification, which will 919 // detect data corruption of most server entry fields. When the check 920 // fails, the server entry is deleted and skipped and iteration continues. 921 // 922 // This prevents wasteful, time-consuming dials in cases where the server 923 // entry is intact except for a bit flip in the obfuscation key, for 924 // example. A delete is triggered also in the case where the server entry 925 // record fails to unmarshal. 926 927 if iterator.config.ServerEntrySignaturePublicKey != "" { 928 929 var serverEntryFields protocol.ServerEntryFields 930 err = json.Unmarshal(value, &serverEntryFields) 931 if err != nil { 932 doDeleteServerEntry = true 933 NoticeWarning( 934 "ServerEntryIterator.Next: unmarshal failed: %s", 935 errors.Trace(err)) 936 937 // Do not stop iterating. 938 return nil 939 } 940 941 if serverEntryFields.HasSignature() { 942 err = serverEntryFields.VerifySignature( 943 iterator.config.ServerEntrySignaturePublicKey) 944 if err != nil { 945 doDeleteServerEntry = true 946 NoticeWarning( 947 "ServerEntryIterator.Next: verify signature failed: %s", 948 errors.Trace(err)) 949 950 // Do not stop iterating. 951 return nil 952 } 953 } 954 } 955 956 // Must unmarshal here as slice is only valid within transaction. 957 err = json.Unmarshal(value, &serverEntry) 958 959 if err != nil { 960 serverEntry = nil 961 doDeleteServerEntry = true 962 NoticeWarning( 963 "ServerEntryIterator.Next: unmarshal failed: %s", 964 errors.Trace(err)) 965 966 // Do not stop iterating. 967 return nil 968 } 969 970 return nil 971 }) 972 if err != nil { 973 return nil, errors.Trace(err) 974 } 975 976 if doDeleteServerEntry { 977 deleteServerEntry(iterator.config, serverEntryID) 978 continue 979 } 980 981 if serverEntry == nil { 982 // In case of data corruption or a bug causing this condition, 983 // do not stop iterating. 984 NoticeWarning("ServerEntryIterator.Next: unexpected missing server entry") 985 continue 986 } 987 988 // Generate a derived server entry tag for server entries with no tag. Store 989 // back the updated server entry so that (a) the tag doesn't need to be 990 // regenerated; (b) the server entry can be looked up by tag (currently used 991 // in the status request prune case). 992 // 993 // This is a distinct transaction so as to avoid the overhead of regular 994 // write transactions in the iterator; once tags have been stored back, most 995 // iterator transactions will remain read-only. 996 if serverEntry.Tag == "" { 997 998 serverEntry.Tag = protocol.GenerateServerEntryTag( 999 serverEntry.IpAddress, serverEntry.WebServerSecret) 1000 1001 err = datastoreUpdate(func(tx *datastoreTx) error { 1002 1003 serverEntries := tx.bucket(datastoreServerEntriesBucket) 1004 serverEntryTags := tx.bucket(datastoreServerEntryTagsBucket) 1005 1006 // We must reload and store back the server entry _fields_ to preserve any 1007 // currently unrecognized fields, for future compatibility. 1008 1009 value := serverEntries.get(serverEntryID) 1010 if value == nil { 1011 return nil 1012 } 1013 1014 var serverEntryFields protocol.ServerEntryFields 1015 err := json.Unmarshal(value, &serverEntryFields) 1016 if err != nil { 1017 return errors.Trace(err) 1018 } 1019 1020 // As there is minor race condition between loading/checking serverEntry 1021 // and reloading/modifying serverEntryFields, this transaction references 1022 // only the freshly loaded fields when checking and setting the tag. 1023 1024 serverEntryTag := serverEntryFields.GetTag() 1025 1026 if serverEntryTag != "" { 1027 return nil 1028 } 1029 1030 serverEntryTag = protocol.GenerateServerEntryTag( 1031 serverEntryFields.GetIPAddress(), 1032 serverEntryFields.GetWebServerSecret()) 1033 1034 serverEntryFields.SetTag(serverEntryTag) 1035 1036 jsonServerEntryFields, err := json.Marshal(serverEntryFields) 1037 if err != nil { 1038 return errors.Trace(err) 1039 } 1040 1041 serverEntries.put(serverEntryID, jsonServerEntryFields) 1042 if err != nil { 1043 return errors.Trace(err) 1044 } 1045 1046 serverEntryTags.put([]byte(serverEntryTag), serverEntryID) 1047 if err != nil { 1048 return errors.Trace(err) 1049 } 1050 1051 return nil 1052 }) 1053 1054 if err != nil { 1055 // Do not stop. 1056 NoticeWarning( 1057 "ServerEntryIterator.Next: update server entry failed: %s", 1058 errors.Trace(err)) 1059 } 1060 } 1061 1062 if iterator.serverEntryIndex%datastoreServerEntryFetchGCThreshold == 0 { 1063 DoGarbageCollection() 1064 } 1065 1066 // Check filter requirements 1067 1068 if iterator.isTacticsServerEntryIterator { 1069 1070 // Tactics doesn't filter by egress region. 1071 if len(serverEntry.GetSupportedTacticsProtocols()) > 0 { 1072 break 1073 } 1074 1075 } else { 1076 1077 if iterator.config.EgressRegion == "" || 1078 serverEntry.Region == iterator.config.EgressRegion { 1079 break 1080 } 1081 } 1082 } 1083 1084 return MakeCompatibleServerEntry(serverEntry), nil 1085 } 1086 1087 // MakeCompatibleServerEntry provides backwards compatibility with old server entries 1088 // which have a single meekFrontingDomain and not a meekFrontingAddresses array. 1089 // By copying this one meekFrontingDomain into meekFrontingAddresses, this client effectively 1090 // uses that single value as legacy clients do. 1091 func MakeCompatibleServerEntry(serverEntry *protocol.ServerEntry) *protocol.ServerEntry { 1092 if len(serverEntry.MeekFrontingAddresses) == 0 && serverEntry.MeekFrontingDomain != "" { 1093 serverEntry.MeekFrontingAddresses = 1094 append(serverEntry.MeekFrontingAddresses, serverEntry.MeekFrontingDomain) 1095 } 1096 1097 return serverEntry 1098 } 1099 1100 // PruneServerEntry deletes the server entry, along with associated data, 1101 // corresponding to the specified server entry tag. Pruning is subject to an 1102 // age check. In the case of an error, a notice is emitted. 1103 func PruneServerEntry(config *Config, serverEntryTag string) { 1104 err := pruneServerEntry(config, serverEntryTag) 1105 if err != nil { 1106 NoticeWarning( 1107 "PruneServerEntry failed: %s: %s", 1108 serverEntryTag, errors.Trace(err)) 1109 return 1110 } 1111 NoticePruneServerEntry(serverEntryTag) 1112 } 1113 1114 func pruneServerEntry(config *Config, serverEntryTag string) error { 1115 1116 minimumAgeForPruning := config.GetParameters().Get().Duration( 1117 parameters.ServerEntryMinimumAgeForPruning) 1118 1119 return datastoreUpdate(func(tx *datastoreTx) error { 1120 1121 serverEntries := tx.bucket(datastoreServerEntriesBucket) 1122 serverEntryTags := tx.bucket(datastoreServerEntryTagsBucket) 1123 serverEntryTombstoneTags := tx.bucket(datastoreServerEntryTombstoneTagsBucket) 1124 keyValues := tx.bucket(datastoreKeyValueBucket) 1125 dialParameters := tx.bucket(datastoreDialParametersBucket) 1126 1127 serverEntryTagBytes := []byte(serverEntryTag) 1128 1129 serverEntryID := serverEntryTags.get(serverEntryTagBytes) 1130 if serverEntryID == nil { 1131 return errors.TraceNew("server entry tag not found") 1132 } 1133 1134 serverEntryJson := serverEntries.get(serverEntryID) 1135 if serverEntryJson == nil { 1136 return errors.TraceNew("server entry not found") 1137 } 1138 1139 var serverEntry *protocol.ServerEntry 1140 err := json.Unmarshal(serverEntryJson, &serverEntry) 1141 if err != nil { 1142 errors.Trace(err) 1143 } 1144 1145 // Only prune sufficiently old server entries. This mitigates the case where 1146 // stale data in psiphond will incorrectly identify brand new servers as 1147 // being invalid/deleted. 1148 serverEntryLocalTimestamp, err := time.Parse(time.RFC3339, serverEntry.LocalTimestamp) 1149 if err != nil { 1150 errors.Trace(err) 1151 } 1152 if serverEntryLocalTimestamp.Add(minimumAgeForPruning).After(time.Now()) { 1153 return nil 1154 } 1155 1156 // Handle the server IP recycle case where multiple serverEntryTags records 1157 // refer to the same server IP. Only delete the server entry record when its 1158 // tag matches the pruned tag. Otherwise, the server entry record is 1159 // associated with another tag. The pruned tag is still deleted. 1160 doDeleteServerEntry := (serverEntry.Tag == serverEntryTag) 1161 1162 err = serverEntryTags.delete(serverEntryTagBytes) 1163 if err != nil { 1164 errors.Trace(err) 1165 } 1166 1167 if doDeleteServerEntry { 1168 1169 err = deleteServerEntryHelper( 1170 config, 1171 serverEntryID, 1172 serverEntries, 1173 keyValues, 1174 dialParameters) 1175 if err != nil { 1176 errors.Trace(err) 1177 } 1178 } 1179 1180 // Tombstones prevent reimporting pruned server entries. Tombstone 1181 // identifiers are tags, which are derived from the web server secret in 1182 // addition to the server IP, so tombstones will not clobber recycled server 1183 // IPs as long as new web server secrets are generated in the recycle case. 1184 // 1185 // Tombstones are set only for embedded server entries, as all other sources 1186 // are expected to provide valid server entries; this also provides a fail- 1187 // safe mechanism to restore pruned server entries through all non-embedded 1188 // sources. 1189 if serverEntry.LocalSource == protocol.SERVER_ENTRY_SOURCE_EMBEDDED { 1190 err = serverEntryTombstoneTags.put(serverEntryTagBytes, []byte{1}) 1191 if err != nil { 1192 return errors.Trace(err) 1193 } 1194 } 1195 1196 return nil 1197 }) 1198 } 1199 1200 // DeleteServerEntry deletes the specified server entry and associated data. 1201 func DeleteServerEntry(config *Config, ipAddress string) { 1202 1203 serverEntryID := []byte(ipAddress) 1204 1205 // For notices, we cannot assume we have a valid server entry tag value to 1206 // log, as DeleteServerEntry is called when a server entry fails to unmarshal 1207 // or fails signature verification. 1208 1209 err := deleteServerEntry(config, serverEntryID) 1210 if err != nil { 1211 NoticeWarning("DeleteServerEntry failed: %s", errors.Trace(err)) 1212 return 1213 } 1214 NoticeInfo("Server entry deleted") 1215 } 1216 1217 func deleteServerEntry(config *Config, serverEntryID []byte) error { 1218 1219 return datastoreUpdate(func(tx *datastoreTx) error { 1220 1221 serverEntries := tx.bucket(datastoreServerEntriesBucket) 1222 serverEntryTags := tx.bucket(datastoreServerEntryTagsBucket) 1223 keyValues := tx.bucket(datastoreKeyValueBucket) 1224 dialParameters := tx.bucket(datastoreDialParametersBucket) 1225 1226 err := deleteServerEntryHelper( 1227 config, 1228 serverEntryID, 1229 serverEntries, 1230 keyValues, 1231 dialParameters) 1232 if err != nil { 1233 errors.Trace(err) 1234 } 1235 1236 // Remove any tags pointing to the deleted server entry. 1237 cursor := serverEntryTags.cursor() 1238 defer cursor.close() 1239 for key, value := cursor.first(); key != nil; key, value = cursor.next() { 1240 if bytes.Equal(value, serverEntryID) { 1241 err := serverEntryTags.delete(key) 1242 if err != nil { 1243 return errors.Trace(err) 1244 } 1245 } 1246 } 1247 1248 return nil 1249 }) 1250 } 1251 1252 func deleteServerEntryHelper( 1253 config *Config, 1254 serverEntryID []byte, 1255 serverEntries *datastoreBucket, 1256 keyValues *datastoreBucket, 1257 dialParameters *datastoreBucket) error { 1258 1259 err := serverEntries.delete(serverEntryID) 1260 if err != nil { 1261 errors.Trace(err) 1262 } 1263 1264 affinityServerEntryID := keyValues.get(datastoreAffinityServerEntryIDKey) 1265 if bytes.Equal(affinityServerEntryID, serverEntryID) { 1266 err = keyValues.delete(datastoreAffinityServerEntryIDKey) 1267 if err != nil { 1268 return errors.Trace(err) 1269 } 1270 err = keyValues.delete(datastoreLastServerEntryFilterKey) 1271 if err != nil { 1272 return errors.Trace(err) 1273 } 1274 } 1275 1276 // TODO: expose boltdb Seek functionality to skip to first matching record. 1277 cursor := dialParameters.cursor() 1278 defer cursor.close() 1279 foundFirstMatch := false 1280 for key, _ := cursor.first(); key != nil; key, _ = cursor.next() { 1281 // Dial parameters key has serverID as a prefix; see makeDialParametersKey. 1282 if bytes.HasPrefix(key, serverEntryID) { 1283 foundFirstMatch = true 1284 err := dialParameters.delete(key) 1285 if err != nil { 1286 return errors.Trace(err) 1287 } 1288 } else if foundFirstMatch { 1289 break 1290 } 1291 } 1292 1293 return nil 1294 } 1295 1296 // ScanServerEntries iterates over all stored server entries, unmarshals each, 1297 // and passes it to callback for processing. If callback returns false, the 1298 // iteration is cancelled and an error is returned. 1299 // 1300 // ScanServerEntries may be slow to execute, particularly for older devices 1301 // and/or very large server lists. Callers should avoid blocking on 1302 // ScanServerEntries where possible; and use the canel option to interrupt 1303 // scans that are no longer required. 1304 func ScanServerEntries(callback func(*protocol.ServerEntry) bool) error { 1305 1306 // TODO: this operation can be sped up (by a factor of ~2x, in one test 1307 // scenario) by using a faster JSON implementation 1308 // (https://github.com/json-iterator/go) and increasing 1309 // datastoreServerEntryFetchGCThreshold. 1310 // 1311 // json-iterator increases the binary code size significantly, which affects 1312 // memory limit accounting on some platforms, so it's not clear we can use it 1313 // universally. Similarly, tuning datastoreServerEntryFetchGCThreshold has a 1314 // memory limit tradeoff. 1315 // 1316 // Since ScanServerEntries is now called asynchronously and doesn't block 1317 // establishment at all, we can tolerate its slower performance. Other 1318 // bulk-JSON operations such as [Streaming]StoreServerEntries also benefit 1319 // from using a faster JSON implementation, but the relative performance 1320 // increase is far smaller as import times are dominated by data store write 1321 // transaction overhead. Other operations such as ServerEntryIterator 1322 // amortize the cost of JSON unmarshalling over many other operations. 1323 1324 err := datastoreView(func(tx *datastoreTx) error { 1325 1326 bucket := tx.bucket(datastoreServerEntriesBucket) 1327 cursor := bucket.cursor() 1328 n := 0 1329 1330 for key, value := cursor.first(); key != nil; key, value = cursor.next() { 1331 1332 var serverEntry *protocol.ServerEntry 1333 err := json.Unmarshal(value, &serverEntry) 1334 if err != nil { 1335 // In case of data corruption or a bug causing this condition, 1336 // do not stop iterating. 1337 NoticeWarning("ScanServerEntries: %s", errors.Trace(err)) 1338 continue 1339 } 1340 1341 if !callback(serverEntry) { 1342 cursor.close() 1343 return errors.TraceNew("scan cancelled") 1344 } 1345 1346 n += 1 1347 if n == datastoreServerEntryFetchGCThreshold { 1348 DoGarbageCollection() 1349 n = 0 1350 } 1351 } 1352 cursor.close() 1353 return nil 1354 }) 1355 1356 if err != nil { 1357 return errors.Trace(err) 1358 } 1359 1360 return nil 1361 } 1362 1363 // HasServerEntries returns a bool indicating if the data store contains at 1364 // least one server entry. This is a faster operation than CountServerEntries. 1365 // On failure, HasServerEntries returns false. 1366 func HasServerEntries() bool { 1367 1368 hasServerEntries := false 1369 1370 err := datastoreView(func(tx *datastoreTx) error { 1371 bucket := tx.bucket(datastoreServerEntriesBucket) 1372 cursor := bucket.cursor() 1373 key, _ := cursor.first() 1374 hasServerEntries = (key != nil) 1375 cursor.close() 1376 return nil 1377 }) 1378 1379 if err != nil { 1380 NoticeWarning("HasServerEntries failed: %s", errors.Trace(err)) 1381 return false 1382 } 1383 1384 return hasServerEntries 1385 } 1386 1387 // CountServerEntries returns a count of stored server entries. On failure, 1388 // CountServerEntries returns 0. 1389 func CountServerEntries() int { 1390 1391 count := 0 1392 1393 err := datastoreView(func(tx *datastoreTx) error { 1394 bucket := tx.bucket(datastoreServerEntriesBucket) 1395 cursor := bucket.cursor() 1396 for key, _ := cursor.first(); key != nil; key, _ = cursor.next() { 1397 count += 1 1398 } 1399 cursor.close() 1400 return nil 1401 }) 1402 1403 if err != nil { 1404 NoticeWarning("CountServerEntries failed: %s", err) 1405 return 0 1406 } 1407 1408 return count 1409 } 1410 1411 // SetUrlETag stores an ETag for the specfied URL. 1412 // Note: input URL is treated as a string, and is not 1413 // encoded or decoded or otherwise canonicalized. 1414 func SetUrlETag(url, etag string) error { 1415 1416 err := datastoreUpdate(func(tx *datastoreTx) error { 1417 bucket := tx.bucket(datastoreUrlETagsBucket) 1418 err := bucket.put([]byte(url), []byte(etag)) 1419 if err != nil { 1420 return errors.Trace(err) 1421 } 1422 return nil 1423 }) 1424 1425 if err != nil { 1426 return errors.Trace(err) 1427 } 1428 return nil 1429 } 1430 1431 // GetUrlETag retrieves a previously stored an ETag for the 1432 // specfied URL. If not found, it returns an empty string value. 1433 func GetUrlETag(url string) (string, error) { 1434 1435 var etag string 1436 1437 err := datastoreView(func(tx *datastoreTx) error { 1438 bucket := tx.bucket(datastoreUrlETagsBucket) 1439 etag = string(bucket.get([]byte(url))) 1440 return nil 1441 }) 1442 1443 if err != nil { 1444 return "", errors.Trace(err) 1445 } 1446 return etag, nil 1447 } 1448 1449 // SetKeyValue stores a key/value pair. 1450 func SetKeyValue(key, value string) error { 1451 1452 err := datastoreUpdate(func(tx *datastoreTx) error { 1453 bucket := tx.bucket(datastoreKeyValueBucket) 1454 err := bucket.put([]byte(key), []byte(value)) 1455 if err != nil { 1456 return errors.Trace(err) 1457 } 1458 return nil 1459 }) 1460 1461 if err != nil { 1462 return errors.Trace(err) 1463 } 1464 return nil 1465 } 1466 1467 // GetKeyValue retrieves the value for a given key. If not found, 1468 // it returns an empty string value. 1469 func GetKeyValue(key string) (string, error) { 1470 1471 var value string 1472 1473 err := datastoreView(func(tx *datastoreTx) error { 1474 bucket := tx.bucket(datastoreKeyValueBucket) 1475 value = string(bucket.get([]byte(key))) 1476 return nil 1477 }) 1478 1479 if err != nil { 1480 return "", errors.Trace(err) 1481 } 1482 return value, nil 1483 } 1484 1485 // Persistent stat records in the persistentStatStateUnreported 1486 // state are available for take out. 1487 // 1488 // Records in the persistentStatStateReporting have been taken 1489 // out and are pending either deletion (for a successful request) 1490 // or change to StateUnreported (for a failed request). 1491 // 1492 // All persistent stat records are reverted to StateUnreported 1493 // when the datastore is initialized at start up. 1494 1495 var persistentStatStateUnreported = []byte("0") 1496 var persistentStatStateReporting = []byte("1") 1497 1498 var persistentStatTypes = []string{ 1499 datastorePersistentStatTypeRemoteServerList, 1500 datastorePersistentStatTypeFailedTunnel, 1501 } 1502 1503 // StorePersistentStat adds a new persistent stat record, which 1504 // is set to StateUnreported and is an immediate candidate for 1505 // reporting. 1506 // 1507 // The stat is a JSON byte array containing fields as 1508 // required by the Psiphon server API. It's assumed that the 1509 // JSON value contains enough unique information for the value to 1510 // function as a key in the key/value datastore. 1511 // 1512 // Only up to PersistentStatsMaxStoreRecords are stored. Once this 1513 // limit is reached, new records are discarded. 1514 func StorePersistentStat(config *Config, statType string, stat []byte) error { 1515 1516 if !common.Contains(persistentStatTypes, statType) { 1517 return errors.Tracef("invalid persistent stat type: %s", statType) 1518 } 1519 1520 maxStoreRecords := config.GetParameters().Get().Int( 1521 parameters.PersistentStatsMaxStoreRecords) 1522 1523 err := datastoreUpdate(func(tx *datastoreTx) error { 1524 bucket := tx.bucket([]byte(statType)) 1525 1526 count := 0 1527 cursor := bucket.cursor() 1528 for key, _ := cursor.first(); key != nil; key, _ = cursor.next() { 1529 count++ 1530 } 1531 cursor.close() 1532 1533 // TODO: assuming newer metrics are more useful, replace oldest record 1534 // instead of discarding? 1535 1536 if count >= maxStoreRecords { 1537 // Silently discard. 1538 return nil 1539 } 1540 1541 err := bucket.put(stat, persistentStatStateUnreported) 1542 if err != nil { 1543 return errors.Trace(err) 1544 } 1545 1546 return nil 1547 }) 1548 1549 if err != nil { 1550 return errors.Trace(err) 1551 } 1552 1553 return nil 1554 } 1555 1556 // CountUnreportedPersistentStats returns the number of persistent 1557 // stat records in StateUnreported. 1558 func CountUnreportedPersistentStats() int { 1559 1560 unreported := 0 1561 1562 err := datastoreView(func(tx *datastoreTx) error { 1563 1564 for _, statType := range persistentStatTypes { 1565 1566 bucket := tx.bucket([]byte(statType)) 1567 cursor := bucket.cursor() 1568 for key, value := cursor.first(); key != nil; key, value = cursor.next() { 1569 if bytes.Equal(value, persistentStatStateUnreported) { 1570 unreported++ 1571 } 1572 } 1573 cursor.close() 1574 } 1575 return nil 1576 }) 1577 1578 if err != nil { 1579 NoticeWarning("CountUnreportedPersistentStats failed: %s", err) 1580 return 0 1581 } 1582 1583 return unreported 1584 } 1585 1586 // TakeOutUnreportedPersistentStats returns persistent stats records that are 1587 // in StateUnreported. At least one record, if present, will be returned and 1588 // then additional records up to PersistentStatsMaxSendBytes. The records are 1589 // set to StateReporting. If the records are successfully reported, clear them 1590 // with ClearReportedPersistentStats. If the records are not successfully 1591 // reported, restore them with PutBackUnreportedPersistentStats. 1592 func TakeOutUnreportedPersistentStats(config *Config) (map[string][][]byte, error) { 1593 1594 stats := make(map[string][][]byte) 1595 1596 maxSendBytes := config.GetParameters().Get().Int( 1597 parameters.PersistentStatsMaxSendBytes) 1598 1599 err := datastoreUpdate(func(tx *datastoreTx) error { 1600 1601 sendBytes := 0 1602 1603 for _, statType := range persistentStatTypes { 1604 1605 bucket := tx.bucket([]byte(statType)) 1606 cursor := bucket.cursor() 1607 for key, value := cursor.first(); key != nil; key, value = cursor.next() { 1608 1609 // Perform a test JSON unmarshaling. In case of data corruption or a bug, 1610 // delete and skip the record. 1611 var jsonData interface{} 1612 err := json.Unmarshal(key, &jsonData) 1613 if err != nil { 1614 NoticeWarning( 1615 "Invalid key in TakeOutUnreportedPersistentStats: %s: %s", 1616 string(key), err) 1617 bucket.delete(key) 1618 continue 1619 } 1620 1621 if bytes.Equal(value, persistentStatStateUnreported) { 1622 // Must make a copy as slice is only valid within transaction. 1623 data := make([]byte, len(key)) 1624 copy(data, key) 1625 1626 if stats[statType] == nil { 1627 stats[statType] = make([][]byte, 0) 1628 } 1629 1630 stats[statType] = append(stats[statType], data) 1631 1632 sendBytes += len(data) 1633 if sendBytes >= maxSendBytes { 1634 break 1635 } 1636 } 1637 1638 } 1639 cursor.close() 1640 1641 for _, key := range stats[statType] { 1642 err := bucket.put(key, persistentStatStateReporting) 1643 if err != nil { 1644 return errors.Trace(err) 1645 } 1646 } 1647 1648 } 1649 return nil 1650 }) 1651 1652 if err != nil { 1653 return nil, errors.Trace(err) 1654 } 1655 1656 return stats, nil 1657 } 1658 1659 // PutBackUnreportedPersistentStats restores a list of persistent 1660 // stat records to StateUnreported. 1661 func PutBackUnreportedPersistentStats(stats map[string][][]byte) error { 1662 1663 err := datastoreUpdate(func(tx *datastoreTx) error { 1664 1665 for _, statType := range persistentStatTypes { 1666 1667 bucket := tx.bucket([]byte(statType)) 1668 for _, key := range stats[statType] { 1669 err := bucket.put(key, persistentStatStateUnreported) 1670 if err != nil { 1671 return errors.Trace(err) 1672 } 1673 } 1674 } 1675 1676 return nil 1677 }) 1678 1679 if err != nil { 1680 return errors.Trace(err) 1681 } 1682 1683 return nil 1684 } 1685 1686 // ClearReportedPersistentStats deletes a list of persistent 1687 // stat records that were successfully reported. 1688 func ClearReportedPersistentStats(stats map[string][][]byte) error { 1689 1690 err := datastoreUpdate(func(tx *datastoreTx) error { 1691 1692 for _, statType := range persistentStatTypes { 1693 1694 bucket := tx.bucket([]byte(statType)) 1695 for _, key := range stats[statType] { 1696 err := bucket.delete(key) 1697 if err != nil { 1698 return err 1699 } 1700 } 1701 } 1702 1703 return nil 1704 }) 1705 1706 if err != nil { 1707 return errors.Trace(err) 1708 } 1709 1710 return nil 1711 } 1712 1713 // resetAllPersistentStatsToUnreported sets all persistent stat 1714 // records to StateUnreported. This reset is called when the 1715 // datastore is initialized at start up, as we do not know if 1716 // persistent records in StateReporting were reported or not. 1717 func resetAllPersistentStatsToUnreported() error { 1718 1719 err := datastoreUpdate(func(tx *datastoreTx) error { 1720 1721 for _, statType := range persistentStatTypes { 1722 1723 bucket := tx.bucket([]byte(statType)) 1724 resetKeys := make([][]byte, 0) 1725 cursor := bucket.cursor() 1726 for key := cursor.firstKey(); key != nil; key = cursor.nextKey() { 1727 resetKeys = append(resetKeys, key) 1728 } 1729 cursor.close() 1730 // TODO: data mutation is done outside cursor. Is this 1731 // strictly necessary in this case? As is, this means 1732 // all stats need to be loaded into memory at once. 1733 // https://godoc.org/github.com/boltdb/bolt#Cursor 1734 for _, key := range resetKeys { 1735 err := bucket.put(key, persistentStatStateUnreported) 1736 if err != nil { 1737 return errors.Trace(err) 1738 } 1739 } 1740 } 1741 1742 return nil 1743 }) 1744 1745 if err != nil { 1746 return errors.Trace(err) 1747 } 1748 1749 return nil 1750 } 1751 1752 // CountSLOKs returns the total number of SLOK records. 1753 func CountSLOKs() int { 1754 1755 count := 0 1756 1757 err := datastoreView(func(tx *datastoreTx) error { 1758 bucket := tx.bucket(datastoreSLOKsBucket) 1759 cursor := bucket.cursor() 1760 for key := cursor.firstKey(); key != nil; key = cursor.nextKey() { 1761 count++ 1762 } 1763 cursor.close() 1764 return nil 1765 }) 1766 1767 if err != nil { 1768 NoticeWarning("CountSLOKs failed: %s", err) 1769 return 0 1770 } 1771 1772 return count 1773 } 1774 1775 // DeleteSLOKs deletes all SLOK records. 1776 func DeleteSLOKs() error { 1777 1778 err := datastoreUpdate(func(tx *datastoreTx) error { 1779 return tx.clearBucket(datastoreSLOKsBucket) 1780 }) 1781 1782 if err != nil { 1783 return errors.Trace(err) 1784 } 1785 1786 return nil 1787 } 1788 1789 // SetSLOK stores a SLOK key, referenced by its ID. The bool 1790 // return value indicates whether the SLOK was already stored. 1791 func SetSLOK(id, slok []byte) (bool, error) { 1792 1793 var duplicate bool 1794 1795 err := datastoreUpdate(func(tx *datastoreTx) error { 1796 bucket := tx.bucket(datastoreSLOKsBucket) 1797 duplicate = bucket.get(id) != nil 1798 err := bucket.put(id, slok) 1799 if err != nil { 1800 return errors.Trace(err) 1801 } 1802 return nil 1803 }) 1804 1805 if err != nil { 1806 return false, errors.Trace(err) 1807 } 1808 1809 return duplicate, nil 1810 } 1811 1812 // GetSLOK returns a SLOK key for the specified ID. The return 1813 // value is nil if the SLOK is not found. 1814 func GetSLOK(id []byte) ([]byte, error) { 1815 1816 var slok []byte 1817 1818 err := datastoreView(func(tx *datastoreTx) error { 1819 bucket := tx.bucket(datastoreSLOKsBucket) 1820 value := bucket.get(id) 1821 if value != nil { 1822 // Must make a copy as slice is only valid within transaction. 1823 slok = make([]byte, len(value)) 1824 copy(slok, value) 1825 } 1826 return nil 1827 }) 1828 1829 if err != nil { 1830 return nil, errors.Trace(err) 1831 } 1832 1833 return slok, nil 1834 } 1835 1836 func makeDialParametersKey(serverIPAddress, networkID []byte) []byte { 1837 // TODO: structured key? 1838 return append(append([]byte(nil), serverIPAddress...), networkID...) 1839 } 1840 1841 // SetDialParameters stores dial parameters associated with the specified 1842 // server/network ID. 1843 func SetDialParameters(serverIPAddress, networkID string, dialParams *DialParameters) error { 1844 1845 key := makeDialParametersKey([]byte(serverIPAddress), []byte(networkID)) 1846 1847 data, err := json.Marshal(dialParams) 1848 if err != nil { 1849 return errors.Trace(err) 1850 } 1851 1852 return setBucketValue(datastoreDialParametersBucket, key, data) 1853 } 1854 1855 // GetDialParameters fetches any dial parameters associated with the specified 1856 // server/network ID. Returns nil, nil when no record is found. 1857 func GetDialParameters( 1858 config *Config, serverIPAddress, networkID string) (*DialParameters, error) { 1859 1860 // Support stand-alone GetTactics operation. See TacticsStorer for more 1861 // details. 1862 err := OpenDataStoreWithoutRetry(config) 1863 if err != nil { 1864 return nil, errors.Trace(err) 1865 } 1866 defer CloseDataStore() 1867 1868 key := makeDialParametersKey([]byte(serverIPAddress), []byte(networkID)) 1869 1870 var dialParams *DialParameters 1871 1872 err = getBucketValue( 1873 datastoreDialParametersBucket, 1874 key, 1875 func(value []byte) error { 1876 if value == nil { 1877 return nil 1878 } 1879 1880 // Note: unlike with server entries, this record is not deleted when the 1881 // unmarshal fails, as the caller should proceed with the dial without dial 1882 // parameters; and when when the dial succeeds, new dial parameters will be 1883 // written over this record. 1884 1885 err := json.Unmarshal(value, &dialParams) 1886 if err != nil { 1887 return errors.Trace(err) 1888 } 1889 1890 return nil 1891 }) 1892 if err != nil { 1893 return nil, errors.Trace(err) 1894 } 1895 1896 return dialParams, nil 1897 } 1898 1899 // DeleteDialParameters clears any dial parameters associated with the 1900 // specified server/network ID. 1901 func DeleteDialParameters(serverIPAddress, networkID string) error { 1902 1903 key := makeDialParametersKey([]byte(serverIPAddress), []byte(networkID)) 1904 1905 return deleteBucketValue(datastoreDialParametersBucket, key) 1906 } 1907 1908 // TacticsStorer implements tactics.Storer. 1909 // 1910 // Each TacticsStorer datastore operation is wrapped with 1911 // OpenDataStoreWithoutRetry/CloseDataStore, which enables a limited degree of 1912 // multiprocess datastore synchronization: 1913 // 1914 // One process runs a Controller. Another process runs a stand-alone operation 1915 // which accesses tactics via GetTactics. For example, SendFeedback. 1916 // 1917 // When the Controller is running, it holds an exclusive lock on the datastore 1918 // and TacticsStorer operations in GetTactics in another process will fail. 1919 // The stand-alone operation should proceed without tactics. In many cases, 1920 // this is acceptable since any stand-alone operation network traffic will be 1921 // tunneled. 1922 // 1923 // When the Controller is not running, the TacticsStorer operations in 1924 // GetTactics in another process will succeed, with no operation holding a 1925 // datastore lock for longer than the handful of milliseconds required to 1926 // perform a single datastore operation. 1927 // 1928 // If the Controller is started while the stand-alone operation is in 1929 // progress, the Controller start will not be blocked for long by the brief 1930 // TacticsStorer datastore locks; the bolt Open call, in particular, has a 1 1931 // second lock aquisition timeout and OpenDataStore will retry when the 1932 // datastore file is locked. 1933 // 1934 // In this scheme, no attempt is made to detect interleaving datastore writes; 1935 // that is, if a different process writes tactics in between GetTactics calls 1936 // to GetTacticsRecord and then SetTacticsRecord. This is because all tactics 1937 // writes are considered fresh and valid. 1938 // 1939 // Using OpenDataStoreWithoutRetry ensures that the GetTactics attempt in the 1940 // non-Controller operation will quickly fail if the datastore is locked. 1941 type TacticsStorer struct { 1942 config *Config 1943 } 1944 1945 func (t *TacticsStorer) SetTacticsRecord(networkID string, record []byte) error { 1946 err := OpenDataStoreWithoutRetry(t.config) 1947 if err != nil { 1948 return errors.Trace(err) 1949 } 1950 defer CloseDataStore() 1951 err = setBucketValue(datastoreTacticsBucket, []byte(networkID), record) 1952 if err != nil { 1953 return errors.Trace(err) 1954 } 1955 return nil 1956 } 1957 1958 func (t *TacticsStorer) GetTacticsRecord(networkID string) ([]byte, error) { 1959 err := OpenDataStoreWithoutRetry(t.config) 1960 if err != nil { 1961 return nil, errors.Trace(err) 1962 } 1963 defer CloseDataStore() 1964 value, err := copyBucketValue(datastoreTacticsBucket, []byte(networkID)) 1965 if err != nil { 1966 return nil, errors.Trace(err) 1967 } 1968 return value, nil 1969 } 1970 1971 func (t *TacticsStorer) SetSpeedTestSamplesRecord(networkID string, record []byte) error { 1972 err := OpenDataStoreWithoutRetry(t.config) 1973 if err != nil { 1974 return errors.Trace(err) 1975 } 1976 defer CloseDataStore() 1977 err = setBucketValue(datastoreSpeedTestSamplesBucket, []byte(networkID), record) 1978 if err != nil { 1979 return errors.Trace(err) 1980 } 1981 return nil 1982 } 1983 1984 func (t *TacticsStorer) GetSpeedTestSamplesRecord(networkID string) ([]byte, error) { 1985 err := OpenDataStoreWithoutRetry(t.config) 1986 if err != nil { 1987 return nil, errors.Trace(err) 1988 } 1989 defer CloseDataStore() 1990 value, err := copyBucketValue(datastoreSpeedTestSamplesBucket, []byte(networkID)) 1991 if err != nil { 1992 return nil, errors.Trace(err) 1993 } 1994 return value, nil 1995 } 1996 1997 // GetTacticsStorer creates a TacticsStorer. 1998 func GetTacticsStorer(config *Config) *TacticsStorer { 1999 return &TacticsStorer{config: config} 2000 } 2001 2002 // GetAffinityServerEntryAndDialParameters fetches the current affinity server 2003 // entry value and any corresponding dial parameters for the specified network 2004 // ID. An error is returned when no affinity server is available. The 2005 // DialParameter output may be nil when a server entry is found but has no 2006 // dial parameters. 2007 func GetAffinityServerEntryAndDialParameters( 2008 networkID string) (protocol.ServerEntryFields, *DialParameters, error) { 2009 2010 var serverEntryFields protocol.ServerEntryFields 2011 var dialParams *DialParameters 2012 2013 err := datastoreView(func(tx *datastoreTx) error { 2014 2015 keyValues := tx.bucket(datastoreKeyValueBucket) 2016 serverEntries := tx.bucket(datastoreServerEntriesBucket) 2017 dialParameters := tx.bucket(datastoreDialParametersBucket) 2018 2019 affinityServerEntryID := keyValues.get(datastoreAffinityServerEntryIDKey) 2020 if affinityServerEntryID == nil { 2021 return errors.TraceNew("no affinity server available") 2022 } 2023 2024 serverEntryRecord := serverEntries.get(affinityServerEntryID) 2025 if serverEntryRecord == nil { 2026 return errors.TraceNew("affinity server entry not found") 2027 } 2028 2029 err := json.Unmarshal( 2030 serverEntryRecord, 2031 &serverEntryFields) 2032 if err != nil { 2033 return errors.Trace(err) 2034 } 2035 2036 dialParamsKey := makeDialParametersKey( 2037 []byte(serverEntryFields.GetIPAddress()), 2038 []byte(networkID)) 2039 2040 dialParamsRecord := dialParameters.get(dialParamsKey) 2041 if dialParamsRecord != nil { 2042 err := json.Unmarshal(dialParamsRecord, &dialParams) 2043 if err != nil { 2044 return errors.Trace(err) 2045 } 2046 } 2047 2048 return nil 2049 }) 2050 if err != nil { 2051 return nil, nil, errors.Trace(err) 2052 } 2053 2054 return serverEntryFields, dialParams, nil 2055 } 2056 2057 func setBucketValue(bucket, key, value []byte) error { 2058 2059 err := datastoreUpdate(func(tx *datastoreTx) error { 2060 bucket := tx.bucket(bucket) 2061 err := bucket.put(key, value) 2062 if err != nil { 2063 return errors.Trace(err) 2064 } 2065 return nil 2066 }) 2067 2068 if err != nil { 2069 return errors.Trace(err) 2070 } 2071 2072 return nil 2073 } 2074 2075 func getBucketValue(bucket, key []byte, valueCallback func([]byte) error) error { 2076 2077 err := datastoreView(func(tx *datastoreTx) error { 2078 bucket := tx.bucket(bucket) 2079 value := bucket.get(key) 2080 return valueCallback(value) 2081 }) 2082 2083 if err != nil { 2084 return errors.Trace(err) 2085 } 2086 2087 return nil 2088 } 2089 2090 func deleteBucketValue(bucket, key []byte) error { 2091 2092 err := datastoreUpdate(func(tx *datastoreTx) error { 2093 bucket := tx.bucket(bucket) 2094 return bucket.delete(key) 2095 }) 2096 2097 if err != nil { 2098 return errors.Trace(err) 2099 } 2100 2101 return nil 2102 } 2103 2104 func copyBucketValue(bucket, key []byte) ([]byte, error) { 2105 var valueCopy []byte 2106 err := getBucketValue(bucket, key, func(value []byte) error { 2107 if value != nil { 2108 // Must make a copy as slice is only valid within transaction. 2109 valueCopy = make([]byte, len(value)) 2110 copy(valueCopy, value) 2111 } 2112 return nil 2113 }) 2114 return valueCopy, err 2115 }