github.com/number571/tendermint@v0.34.11-gost/internal/p2p/pex/addrbook.go (about) 1 // Modified for Tendermint 2 // Originally Copyright (c) 2013-2014 Conformal Systems LLC. 3 // https://github.com/conformal/btcd/blob/master/LICENSE 4 5 package pex 6 7 import ( 8 "encoding/binary" 9 "fmt" 10 "hash" 11 "math" 12 mrand "math/rand" 13 "net" 14 "sync" 15 "time" 16 17 "github.com/number571/tendermint/crypto" 18 tmsync "github.com/number571/tendermint/internal/libs/sync" 19 "github.com/number571/tendermint/internal/p2p" 20 tmmath "github.com/number571/tendermint/libs/math" 21 tmrand "github.com/number571/tendermint/libs/rand" 22 "github.com/number571/tendermint/libs/service" 23 "github.com/number571/tendermint/types" 24 "github.com/minio/highwayhash" 25 ) 26 27 const ( 28 bucketTypeNew = 0x01 29 bucketTypeOld = 0x02 30 ) 31 32 // AddrBook is an address book used for tracking peers 33 // so we can gossip about them to others and select 34 // peers to dial. 35 // TODO: break this up? 36 type AddrBook interface { 37 service.Service 38 39 // Add our own addresses so we don't later add ourselves 40 AddOurAddress(*p2p.NetAddress) 41 // Check if it is our address 42 OurAddress(*p2p.NetAddress) bool 43 44 AddPrivateIDs([]string) 45 46 // Add and remove an address 47 AddAddress(addr *p2p.NetAddress, src *p2p.NetAddress) error 48 RemoveAddress(*p2p.NetAddress) 49 50 // Check if the address is in the book 51 HasAddress(*p2p.NetAddress) bool 52 53 // Do we need more peers? 54 NeedMoreAddrs() bool 55 // Is Address Book Empty? Answer should not depend on being in your own 56 // address book, or private peers 57 Empty() bool 58 59 // Pick an address to dial 60 PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress 61 62 // Mark address 63 MarkGood(types.NodeID) 64 MarkAttempt(*p2p.NetAddress) 65 MarkBad(*p2p.NetAddress, time.Duration) // Move peer to bad peers list 66 // Add bad peers back to addrBook 67 ReinstateBadPeers() 68 69 IsGood(*p2p.NetAddress) bool 70 IsBanned(*p2p.NetAddress) bool 71 72 // Send a selection of addresses to peers 73 GetSelection() []*p2p.NetAddress 74 // Send a selection of addresses with bias 75 GetSelectionWithBias(biasTowardsNewAddrs int) []*p2p.NetAddress 76 77 Size() int 78 79 // Persist to disk 80 Save() 81 } 82 83 var _ AddrBook = (*addrBook)(nil) 84 85 // addrBook - concurrency safe peer address manager. 86 // Implements AddrBook. 87 type addrBook struct { 88 service.BaseService 89 90 // accessed concurrently 91 mtx tmsync.Mutex 92 ourAddrs map[string]struct{} 93 privateIDs map[types.NodeID]struct{} 94 addrLookup map[types.NodeID]*knownAddress // new & old 95 badPeers map[types.NodeID]*knownAddress // blacklisted peers 96 bucketsOld []map[string]*knownAddress 97 bucketsNew []map[string]*knownAddress 98 nOld int 99 nNew int 100 101 // immutable after creation 102 filePath string 103 key string // random prefix for bucket placement 104 routabilityStrict bool 105 hasher hash.Hash64 106 107 wg sync.WaitGroup 108 } 109 110 func mustNewHasher() hash.Hash64 { 111 key := crypto.CRandBytes(highwayhash.Size) 112 hasher, err := highwayhash.New64(key) 113 if err != nil { 114 panic(err) 115 } 116 return hasher 117 } 118 119 // NewAddrBook creates a new address book. 120 // Use Start to begin processing asynchronous address updates. 121 func NewAddrBook(filePath string, routabilityStrict bool) AddrBook { 122 am := &addrBook{ 123 ourAddrs: make(map[string]struct{}), 124 privateIDs: make(map[types.NodeID]struct{}), 125 addrLookup: make(map[types.NodeID]*knownAddress), 126 badPeers: make(map[types.NodeID]*knownAddress), 127 filePath: filePath, 128 routabilityStrict: routabilityStrict, 129 } 130 am.init() 131 am.BaseService = *service.NewBaseService(nil, "AddrBook", am) 132 return am 133 } 134 135 // Initialize the buckets. 136 // When modifying this, don't forget to update loadFromFile() 137 func (a *addrBook) init() { 138 a.key = crypto.CRandHex(24) // 24/2 * 8 = 96 bits 139 // New addr buckets 140 a.bucketsNew = make([]map[string]*knownAddress, newBucketCount) 141 for i := range a.bucketsNew { 142 a.bucketsNew[i] = make(map[string]*knownAddress) 143 } 144 // Old addr buckets 145 a.bucketsOld = make([]map[string]*knownAddress, oldBucketCount) 146 for i := range a.bucketsOld { 147 a.bucketsOld[i] = make(map[string]*knownAddress) 148 } 149 a.hasher = mustNewHasher() 150 } 151 152 // OnStart implements Service. 153 func (a *addrBook) OnStart() error { 154 if err := a.BaseService.OnStart(); err != nil { 155 return err 156 } 157 a.loadFromFile(a.filePath) 158 159 // wg.Add to ensure that any invocation of .Wait() 160 // later on will wait for saveRoutine to terminate. 161 a.wg.Add(1) 162 go a.saveRoutine() 163 164 return nil 165 } 166 167 // OnStop implements Service. 168 func (a *addrBook) OnStop() { 169 a.BaseService.OnStop() 170 } 171 172 func (a *addrBook) Wait() { 173 a.wg.Wait() 174 } 175 176 func (a *addrBook) FilePath() string { 177 return a.filePath 178 } 179 180 //------------------------------------------------------- 181 182 // AddOurAddress one of our addresses. 183 func (a *addrBook) AddOurAddress(addr *p2p.NetAddress) { 184 a.mtx.Lock() 185 defer a.mtx.Unlock() 186 187 a.Logger.Info("Add our address to book", "addr", addr) 188 a.ourAddrs[addr.String()] = struct{}{} 189 } 190 191 // OurAddress returns true if it is our address. 192 func (a *addrBook) OurAddress(addr *p2p.NetAddress) bool { 193 a.mtx.Lock() 194 defer a.mtx.Unlock() 195 196 _, ok := a.ourAddrs[addr.String()] 197 return ok 198 } 199 200 func (a *addrBook) AddPrivateIDs(ids []string) { 201 a.mtx.Lock() 202 defer a.mtx.Unlock() 203 204 for _, id := range ids { 205 a.privateIDs[types.NodeID(id)] = struct{}{} 206 } 207 } 208 209 // AddAddress implements AddrBook 210 // Add address to a "new" bucket. If it's already in one, only add it probabilistically. 211 // Returns error if the addr is non-routable. Does not add self. 212 // NOTE: addr must not be nil 213 func (a *addrBook) AddAddress(addr *p2p.NetAddress, src *p2p.NetAddress) error { 214 a.mtx.Lock() 215 defer a.mtx.Unlock() 216 217 return a.addAddress(addr, src) 218 } 219 220 // RemoveAddress implements AddrBook - removes the address from the book. 221 func (a *addrBook) RemoveAddress(addr *p2p.NetAddress) { 222 a.mtx.Lock() 223 defer a.mtx.Unlock() 224 225 a.removeAddress(addr) 226 } 227 228 // IsGood returns true if peer was ever marked as good and haven't 229 // done anything wrong since then. 230 func (a *addrBook) IsGood(addr *p2p.NetAddress) bool { 231 a.mtx.Lock() 232 defer a.mtx.Unlock() 233 234 return a.addrLookup[addr.ID].isOld() 235 } 236 237 // IsBanned returns true if the peer is currently banned 238 func (a *addrBook) IsBanned(addr *p2p.NetAddress) bool { 239 a.mtx.Lock() 240 _, ok := a.badPeers[addr.ID] 241 a.mtx.Unlock() 242 243 return ok 244 } 245 246 // HasAddress returns true if the address is in the book. 247 func (a *addrBook) HasAddress(addr *p2p.NetAddress) bool { 248 a.mtx.Lock() 249 defer a.mtx.Unlock() 250 251 ka := a.addrLookup[addr.ID] 252 return ka != nil 253 } 254 255 // NeedMoreAddrs implements AddrBook - returns true if there are not have enough addresses in the book. 256 func (a *addrBook) NeedMoreAddrs() bool { 257 return a.Size() < needAddressThreshold 258 } 259 260 // Empty implements AddrBook - returns true if there are no addresses in the address book. 261 // Does not count the peer appearing in its own address book, or private peers. 262 func (a *addrBook) Empty() bool { 263 return a.Size() == 0 264 } 265 266 // PickAddress implements AddrBook. It picks an address to connect to. 267 // The address is picked randomly from an old or new bucket according 268 // to the biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to that range) 269 // and determines how biased we are to pick an address from a new bucket. 270 // PickAddress returns nil if the AddrBook is empty or if we try to pick 271 // from an empty bucket. 272 // nolint:gosec // G404: Use of weak random number generator 273 func (a *addrBook) PickAddress(biasTowardsNewAddrs int) *p2p.NetAddress { 274 a.mtx.Lock() 275 defer a.mtx.Unlock() 276 277 bookSize := a.size() 278 if bookSize <= 0 { 279 if bookSize < 0 { 280 panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld)) 281 } 282 return nil 283 } 284 if biasTowardsNewAddrs > 100 { 285 biasTowardsNewAddrs = 100 286 } 287 if biasTowardsNewAddrs < 0 { 288 biasTowardsNewAddrs = 0 289 } 290 291 // Bias between new and old addresses. 292 oldCorrelation := math.Sqrt(float64(a.nOld)) * (100.0 - float64(biasTowardsNewAddrs)) 293 newCorrelation := math.Sqrt(float64(a.nNew)) * float64(biasTowardsNewAddrs) 294 295 // pick a random peer from a random bucket 296 var bucket map[string]*knownAddress 297 pickFromOldBucket := (newCorrelation+oldCorrelation)*mrand.Float64() < oldCorrelation 298 if (pickFromOldBucket && a.nOld == 0) || 299 (!pickFromOldBucket && a.nNew == 0) { 300 return nil 301 } 302 // loop until we pick a random non-empty bucket 303 for len(bucket) == 0 { 304 if pickFromOldBucket { 305 bucket = a.bucketsOld[mrand.Intn(len(a.bucketsOld))] 306 } else { 307 bucket = a.bucketsNew[mrand.Intn(len(a.bucketsNew))] 308 } 309 } 310 // pick a random index and loop over the map to return that index 311 randIndex := mrand.Intn(len(bucket)) 312 for _, ka := range bucket { 313 if randIndex == 0 { 314 return ka.Addr 315 } 316 randIndex-- 317 } 318 return nil 319 } 320 321 // MarkGood implements AddrBook - it marks the peer as good and 322 // moves it into an "old" bucket. 323 func (a *addrBook) MarkGood(id types.NodeID) { 324 a.mtx.Lock() 325 defer a.mtx.Unlock() 326 327 ka := a.addrLookup[id] 328 if ka == nil { 329 return 330 } 331 ka.markGood() 332 if ka.isNew() { 333 if err := a.moveToOld(ka); err != nil { 334 a.Logger.Error("Error moving address to old", "err", err) 335 } 336 } 337 } 338 339 // MarkAttempt implements AddrBook - it marks that an attempt was made to connect to the address. 340 func (a *addrBook) MarkAttempt(addr *p2p.NetAddress) { 341 a.mtx.Lock() 342 defer a.mtx.Unlock() 343 344 ka := a.addrLookup[addr.ID] 345 if ka == nil { 346 return 347 } 348 ka.markAttempt() 349 } 350 351 // MarkBad implements AddrBook. Kicks address out from book, places 352 // the address in the badPeers pool. 353 func (a *addrBook) MarkBad(addr *p2p.NetAddress, banTime time.Duration) { 354 a.mtx.Lock() 355 defer a.mtx.Unlock() 356 357 if a.addBadPeer(addr, banTime) { 358 a.removeAddress(addr) 359 } 360 } 361 362 // ReinstateBadPeers removes bad peers from ban list and places them into a new 363 // bucket. 364 func (a *addrBook) ReinstateBadPeers() { 365 a.mtx.Lock() 366 defer a.mtx.Unlock() 367 368 for _, ka := range a.badPeers { 369 if ka.isBanned() { 370 continue 371 } 372 373 bucket, err := a.calcNewBucket(ka.Addr, ka.Src) 374 if err != nil { 375 a.Logger.Error("Failed to calculate new bucket (bad peer won't be reinstantiated)", 376 "addr", ka.Addr, "err", err) 377 continue 378 } 379 380 if err := a.addToNewBucket(ka, bucket); err != nil { 381 a.Logger.Error("Error adding peer to new bucket", "err", err) 382 } 383 delete(a.badPeers, ka.ID()) 384 385 a.Logger.Info("Reinstated address", "addr", ka.Addr) 386 } 387 } 388 389 // GetSelection implements AddrBook. 390 // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols. 391 // Must never return a nil address. 392 func (a *addrBook) GetSelection() []*p2p.NetAddress { 393 a.mtx.Lock() 394 defer a.mtx.Unlock() 395 396 bookSize := a.size() 397 if bookSize <= 0 { 398 if bookSize < 0 { 399 panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld)) 400 } 401 return nil 402 } 403 404 numAddresses := tmmath.MaxInt( 405 tmmath.MinInt(minGetSelection, bookSize), 406 bookSize*getSelectionPercent/100) 407 numAddresses = tmmath.MinInt(maxGetSelection, numAddresses) 408 409 // XXX: instead of making a list of all addresses, shuffling, and slicing a random chunk, 410 // could we just select a random numAddresses of indexes? 411 allAddr := make([]*p2p.NetAddress, bookSize) 412 i := 0 413 for _, ka := range a.addrLookup { 414 allAddr[i] = ka.Addr 415 i++ 416 } 417 418 // Fisher-Yates shuffle the array. We only need to do the first 419 // `numAddresses' since we are throwing the rest. 420 for i := 0; i < numAddresses; i++ { 421 // pick a number between current index and the end 422 // nolint:gosec // G404: Use of weak random number generator 423 j := mrand.Intn(len(allAddr)-i) + i 424 allAddr[i], allAddr[j] = allAddr[j], allAddr[i] 425 } 426 427 // slice off the limit we are willing to share. 428 return allAddr[:numAddresses] 429 } 430 431 func percentageOfNum(p, n int) int { 432 return int(math.Round((float64(p) / float64(100)) * float64(n))) 433 } 434 435 // GetSelectionWithBias implements AddrBook. 436 // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols. 437 // Must never return a nil address. 438 // 439 // Each address is picked randomly from an old or new bucket according to the 440 // biasTowardsNewAddrs argument, which must be between [0, 100] (or else is truncated to 441 // that range) and determines how biased we are to pick an address from a new 442 // bucket. 443 func (a *addrBook) GetSelectionWithBias(biasTowardsNewAddrs int) []*p2p.NetAddress { 444 a.mtx.Lock() 445 defer a.mtx.Unlock() 446 447 bookSize := a.size() 448 if bookSize <= 0 { 449 if bookSize < 0 { 450 panic(fmt.Sprintf("Addrbook size %d (new: %d + old: %d) is less than 0", a.nNew+a.nOld, a.nNew, a.nOld)) 451 } 452 return nil 453 } 454 455 if biasTowardsNewAddrs > 100 { 456 biasTowardsNewAddrs = 100 457 } 458 if biasTowardsNewAddrs < 0 { 459 biasTowardsNewAddrs = 0 460 } 461 462 numAddresses := tmmath.MaxInt( 463 tmmath.MinInt(minGetSelection, bookSize), 464 bookSize*getSelectionPercent/100) 465 numAddresses = tmmath.MinInt(maxGetSelection, numAddresses) 466 467 // number of new addresses that, if possible, should be in the beginning of the selection 468 // if there are no enough old addrs, will choose new addr instead. 469 numRequiredNewAdd := tmmath.MaxInt(percentageOfNum(biasTowardsNewAddrs, numAddresses), numAddresses-a.nOld) 470 selection := a.randomPickAddresses(bucketTypeNew, numRequiredNewAdd) 471 selection = append(selection, a.randomPickAddresses(bucketTypeOld, numAddresses-len(selection))...) 472 return selection 473 } 474 475 //------------------------------------------------ 476 477 // Size returns the number of addresses in the book. 478 func (a *addrBook) Size() int { 479 a.mtx.Lock() 480 defer a.mtx.Unlock() 481 482 return a.size() 483 } 484 485 func (a *addrBook) size() int { 486 return a.nNew + a.nOld 487 } 488 489 //---------------------------------------------------------- 490 491 // Save persists the address book to disk. 492 func (a *addrBook) Save() { 493 a.saveToFile(a.filePath) // thread safe 494 } 495 496 func (a *addrBook) saveRoutine() { 497 defer a.wg.Done() 498 499 saveFileTicker := time.NewTicker(dumpAddressInterval) 500 out: 501 for { 502 select { 503 case <-saveFileTicker.C: 504 a.saveToFile(a.filePath) 505 case <-a.Quit(): 506 break out 507 } 508 } 509 saveFileTicker.Stop() 510 a.saveToFile(a.filePath) 511 } 512 513 //---------------------------------------------------------- 514 515 func (a *addrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAddress { 516 switch bucketType { 517 case bucketTypeNew: 518 return a.bucketsNew[bucketIdx] 519 case bucketTypeOld: 520 return a.bucketsOld[bucketIdx] 521 default: 522 panic("Invalid bucket type") 523 } 524 } 525 526 // Adds ka to new bucket. Returns false if it couldn't do it cuz buckets full. 527 // NOTE: currently it always returns true. 528 func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) error { 529 // Consistency check to ensure we don't add an already known address 530 if ka.isOld() { 531 return errAddrBookOldAddressNewBucket{ka.Addr, bucketIdx} 532 } 533 534 addrStr := ka.Addr.String() 535 bucket := a.getBucket(bucketTypeNew, bucketIdx) 536 537 // Already exists? 538 if _, ok := bucket[addrStr]; ok { 539 return nil 540 } 541 542 // Enforce max addresses. 543 if len(bucket) > newBucketSize { 544 a.Logger.Info("new bucket is full, expiring new") 545 a.expireNew(bucketIdx) 546 } 547 548 // Add to bucket. 549 bucket[addrStr] = ka 550 // increment nNew if the peer doesnt already exist in a bucket 551 if ka.addBucketRef(bucketIdx) == 1 { 552 a.nNew++ 553 } 554 555 // Add it to addrLookup 556 a.addrLookup[ka.ID()] = ka 557 return nil 558 } 559 560 // Adds ka to old bucket. Returns false if it couldn't do it cuz buckets full. 561 func (a *addrBook) addToOldBucket(ka *knownAddress, bucketIdx int) bool { 562 // Sanity check 563 if ka.isNew() { 564 a.Logger.Error(fmt.Sprintf("Cannot add new address to old bucket: %v", ka)) 565 return false 566 } 567 if len(ka.Buckets) != 0 { 568 a.Logger.Error(fmt.Sprintf("Cannot add already old address to another old bucket: %v", ka)) 569 return false 570 } 571 572 addrStr := ka.Addr.String() 573 bucket := a.getBucket(bucketTypeOld, bucketIdx) 574 575 // Already exists? 576 if _, ok := bucket[addrStr]; ok { 577 return true 578 } 579 580 // Enforce max addresses. 581 if len(bucket) > oldBucketSize { 582 return false 583 } 584 585 // Add to bucket. 586 bucket[addrStr] = ka 587 if ka.addBucketRef(bucketIdx) == 1 { 588 a.nOld++ 589 } 590 591 // Ensure in addrLookup 592 a.addrLookup[ka.ID()] = ka 593 594 return true 595 } 596 597 func (a *addrBook) removeFromBucket(ka *knownAddress, bucketType byte, bucketIdx int) { 598 if ka.BucketType != bucketType { 599 a.Logger.Error(fmt.Sprintf("Bucket type mismatch: %v", ka)) 600 return 601 } 602 bucket := a.getBucket(bucketType, bucketIdx) 603 delete(bucket, ka.Addr.String()) 604 if ka.removeBucketRef(bucketIdx) == 0 { 605 if bucketType == bucketTypeNew { 606 a.nNew-- 607 } else { 608 a.nOld-- 609 } 610 delete(a.addrLookup, ka.ID()) 611 } 612 } 613 614 func (a *addrBook) removeFromAllBuckets(ka *knownAddress) { 615 for _, bucketIdx := range ka.Buckets { 616 bucket := a.getBucket(ka.BucketType, bucketIdx) 617 delete(bucket, ka.Addr.String()) 618 } 619 ka.Buckets = nil 620 if ka.BucketType == bucketTypeNew { 621 a.nNew-- 622 } else { 623 a.nOld-- 624 } 625 delete(a.addrLookup, ka.ID()) 626 } 627 628 //---------------------------------------------------------- 629 630 func (a *addrBook) pickOldest(bucketType byte, bucketIdx int) *knownAddress { 631 bucket := a.getBucket(bucketType, bucketIdx) 632 var oldest *knownAddress 633 for _, ka := range bucket { 634 if oldest == nil || ka.LastAttempt.Before(oldest.LastAttempt) { 635 oldest = ka 636 } 637 } 638 return oldest 639 } 640 641 // adds the address to a "new" bucket. if its already in one, 642 // it only adds it probabilistically 643 func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error { 644 if addr == nil || src == nil { 645 return ErrAddrBookNilAddr{addr, src} 646 } 647 648 if err := addr.Valid(); err != nil { 649 return ErrAddrBookInvalidAddr{Addr: addr, AddrErr: err} 650 } 651 652 if _, ok := a.badPeers[addr.ID]; ok { 653 return ErrAddressBanned{addr} 654 } 655 656 if _, ok := a.privateIDs[addr.ID]; ok { 657 return ErrAddrBookPrivate{addr} 658 } 659 660 if _, ok := a.privateIDs[src.ID]; ok { 661 return ErrAddrBookPrivateSrc{src} 662 } 663 664 // TODO: we should track ourAddrs by ID and by IP:PORT and refuse both. 665 if _, ok := a.ourAddrs[addr.String()]; ok { 666 return ErrAddrBookSelf{addr} 667 } 668 669 if a.routabilityStrict && !addr.Routable() { 670 return ErrAddrBookNonRoutable{addr} 671 } 672 673 ka := a.addrLookup[addr.ID] 674 if ka != nil { 675 // If its already old and the address ID's are the same, ignore it. 676 // Thereby avoiding issues with a node on the network attempting to change 677 // the IP of a known node ID. (Which could yield an eclipse attack on the node) 678 if ka.isOld() && ka.Addr.ID == addr.ID { 679 return nil 680 } 681 // Already in max new buckets. 682 if len(ka.Buckets) == maxNewBucketsPerAddress { 683 return nil 684 } 685 // The more entries we have, the less likely we are to add more. 686 factor := int32(2 * len(ka.Buckets)) 687 // nolint:gosec // G404: Use of weak random number generator 688 if mrand.Int31n(factor) != 0 { 689 return nil 690 } 691 } else { 692 ka = newKnownAddress(addr, src) 693 } 694 695 bucket, err := a.calcNewBucket(addr, src) 696 if err != nil { 697 return err 698 } 699 return a.addToNewBucket(ka, bucket) 700 } 701 702 func (a *addrBook) randomPickAddresses(bucketType byte, num int) []*p2p.NetAddress { 703 var buckets []map[string]*knownAddress 704 switch bucketType { 705 case bucketTypeNew: 706 buckets = a.bucketsNew 707 case bucketTypeOld: 708 buckets = a.bucketsOld 709 default: 710 panic("unexpected bucketType") 711 } 712 total := 0 713 for _, bucket := range buckets { 714 total += len(bucket) 715 } 716 addresses := make([]*knownAddress, 0, total) 717 for _, bucket := range buckets { 718 for _, ka := range bucket { 719 addresses = append(addresses, ka) 720 } 721 } 722 selection := make([]*p2p.NetAddress, 0, num) 723 chosenSet := make(map[string]bool, num) 724 rand := tmrand.NewRand() 725 rand.Shuffle(total, func(i, j int) { 726 addresses[i], addresses[j] = addresses[j], addresses[i] 727 }) 728 for _, addr := range addresses { 729 if chosenSet[addr.Addr.String()] { 730 continue 731 } 732 chosenSet[addr.Addr.String()] = true 733 selection = append(selection, addr.Addr) 734 if len(selection) >= num { 735 return selection 736 } 737 } 738 return selection 739 } 740 741 // Make space in the new buckets by expiring the really bad entries. 742 // If no bad entries are available we remove the oldest. 743 func (a *addrBook) expireNew(bucketIdx int) { 744 for addrStr, ka := range a.bucketsNew[bucketIdx] { 745 // If an entry is bad, throw it away 746 if ka.isBad() { 747 a.Logger.Info(fmt.Sprintf("expiring bad address %v", addrStr)) 748 a.removeFromBucket(ka, bucketTypeNew, bucketIdx) 749 return 750 } 751 } 752 753 // If we haven't thrown out a bad entry, throw out the oldest entry 754 oldest := a.pickOldest(bucketTypeNew, bucketIdx) 755 a.removeFromBucket(oldest, bucketTypeNew, bucketIdx) 756 } 757 758 // Promotes an address from new to old. If the destination bucket is full, 759 // demote the oldest one to a "new" bucket. 760 // TODO: Demote more probabilistically? 761 func (a *addrBook) moveToOld(ka *knownAddress) error { 762 // Sanity check 763 if ka.isOld() { 764 a.Logger.Error(fmt.Sprintf("Cannot promote address that is already old %v", ka)) 765 return nil 766 } 767 if len(ka.Buckets) == 0 { 768 a.Logger.Error(fmt.Sprintf("Cannot promote address that isn't in any new buckets %v", ka)) 769 return nil 770 } 771 772 // Remove from all (new) buckets. 773 a.removeFromAllBuckets(ka) 774 // It's officially old now. 775 ka.BucketType = bucketTypeOld 776 777 // Try to add it to its oldBucket destination. 778 oldBucketIdx, err := a.calcOldBucket(ka.Addr) 779 if err != nil { 780 return err 781 } 782 added := a.addToOldBucket(ka, oldBucketIdx) 783 if !added { 784 // No room; move the oldest to a new bucket 785 oldest := a.pickOldest(bucketTypeOld, oldBucketIdx) 786 a.removeFromBucket(oldest, bucketTypeOld, oldBucketIdx) 787 newBucketIdx, err := a.calcNewBucket(oldest.Addr, oldest.Src) 788 if err != nil { 789 return err 790 } 791 if err := a.addToNewBucket(oldest, newBucketIdx); err != nil { 792 a.Logger.Error("Error adding peer to old bucket", "err", err) 793 } 794 795 // Finally, add our ka to old bucket again. 796 added = a.addToOldBucket(ka, oldBucketIdx) 797 if !added { 798 a.Logger.Error(fmt.Sprintf("Could not re-add ka %v to oldBucketIdx %v", ka, oldBucketIdx)) 799 } 800 } 801 return nil 802 } 803 804 func (a *addrBook) removeAddress(addr *p2p.NetAddress) { 805 ka := a.addrLookup[addr.ID] 806 if ka == nil { 807 return 808 } 809 a.Logger.Info("Remove address from book", "addr", addr) 810 a.removeFromAllBuckets(ka) 811 } 812 813 func (a *addrBook) addBadPeer(addr *p2p.NetAddress, banTime time.Duration) bool { 814 // check it exists in addrbook 815 ka := a.addrLookup[addr.ID] 816 // check address is not already there 817 if ka == nil { 818 return false 819 } 820 821 if _, alreadyBadPeer := a.badPeers[addr.ID]; !alreadyBadPeer { 822 // add to bad peer list 823 ka.ban(banTime) 824 a.badPeers[addr.ID] = ka 825 a.Logger.Info("Add address to blacklist", "addr", addr) 826 } 827 return true 828 } 829 830 //--------------------------------------------------------------------- 831 // calculate bucket placements 832 833 // hash(key + sourcegroup + int64(hash(key + group + sourcegroup)) % bucket_per_group) % num_new_buckets 834 func (a *addrBook) calcNewBucket(addr, src *p2p.NetAddress) (int, error) { 835 data1 := []byte{} 836 data1 = append(data1, []byte(a.key)...) 837 data1 = append(data1, []byte(a.groupKey(addr))...) 838 data1 = append(data1, []byte(a.groupKey(src))...) 839 hash1, err := a.hash(data1) 840 if err != nil { 841 return 0, err 842 } 843 hash64 := binary.BigEndian.Uint64(hash1) 844 hash64 %= newBucketsPerGroup 845 var hashbuf [8]byte 846 binary.BigEndian.PutUint64(hashbuf[:], hash64) 847 data2 := []byte{} 848 data2 = append(data2, []byte(a.key)...) 849 data2 = append(data2, a.groupKey(src)...) 850 data2 = append(data2, hashbuf[:]...) 851 852 hash2, err := a.hash(data2) 853 if err != nil { 854 return 0, err 855 } 856 result := int(binary.BigEndian.Uint64(hash2) % newBucketCount) 857 return result, nil 858 } 859 860 // hash(key + group + int64(hash(key + addr)) % buckets_per_group) % num_old_buckets 861 func (a *addrBook) calcOldBucket(addr *p2p.NetAddress) (int, error) { 862 data1 := []byte{} 863 data1 = append(data1, []byte(a.key)...) 864 data1 = append(data1, []byte(addr.String())...) 865 hash1, err := a.hash(data1) 866 if err != nil { 867 return 0, err 868 } 869 hash64 := binary.BigEndian.Uint64(hash1) 870 hash64 %= oldBucketsPerGroup 871 var hashbuf [8]byte 872 binary.BigEndian.PutUint64(hashbuf[:], hash64) 873 data2 := []byte{} 874 data2 = append(data2, []byte(a.key)...) 875 data2 = append(data2, a.groupKey(addr)...) 876 data2 = append(data2, hashbuf[:]...) 877 878 hash2, err := a.hash(data2) 879 if err != nil { 880 return 0, err 881 } 882 result := int(binary.BigEndian.Uint64(hash2) % oldBucketCount) 883 return result, nil 884 } 885 886 // Return a string representing the network group of this address. 887 // This is the /16 for IPv4 (e.g. 1.2.0.0), the /32 (/36 for he.net) for IPv6, the string 888 // "local" for a local address and the string "unroutable" for an unroutable 889 // address. 890 func (a *addrBook) groupKey(na *p2p.NetAddress) string { 891 return groupKeyFor(na, a.routabilityStrict) 892 } 893 894 func groupKeyFor(na *p2p.NetAddress, routabilityStrict bool) string { 895 if routabilityStrict && na.Local() { 896 return "local" 897 } 898 if routabilityStrict && !na.Routable() { 899 return "unroutable" 900 } 901 902 if ipv4 := na.IP.To4(); ipv4 != nil { 903 return na.IP.Mask(net.CIDRMask(16, 32)).String() 904 } 905 906 if na.RFC6145() || na.RFC6052() { 907 // last four bytes are the ip address 908 ip := na.IP[12:16] 909 return ip.Mask(net.CIDRMask(16, 32)).String() 910 } 911 912 if na.RFC3964() { 913 ip := na.IP[2:6] 914 return ip.Mask(net.CIDRMask(16, 32)).String() 915 } 916 917 if na.RFC4380() { 918 // teredo tunnels have the last 4 bytes as the v4 address XOR 919 // 0xff. 920 ip := net.IP(make([]byte, 4)) 921 for i, byte := range na.IP[12:16] { 922 ip[i] = byte ^ 0xff 923 } 924 return ip.Mask(net.CIDRMask(16, 32)).String() 925 } 926 927 if na.OnionCatTor() { 928 // group is keyed off the first 4 bits of the actual onion key. 929 return fmt.Sprintf("tor:%d", na.IP[6]&((1<<4)-1)) 930 } 931 932 // OK, so now we know ourselves to be a IPv6 address. 933 // bitcoind uses /32 for everything, except for Hurricane Electric's 934 // (he.net) IP range, which it uses /36 for. 935 bits := 32 936 heNet := &net.IPNet{IP: net.ParseIP("2001:470::"), Mask: net.CIDRMask(32, 128)} 937 if heNet.Contains(na.IP) { 938 bits = 36 939 } 940 ipv6Mask := net.CIDRMask(bits, 128) 941 return na.IP.Mask(ipv6Mask).String() 942 } 943 944 func (a *addrBook) hash(b []byte) ([]byte, error) { 945 a.hasher.Reset() 946 a.hasher.Write(b) 947 return a.hasher.Sum(nil), nil 948 }