You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

791 lines
20 KiB

9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
7 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
7 years ago
8 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
7 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
7 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
8 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
8 years ago
9 years ago
8 years ago
9 years ago
9 years ago
7 years ago
9 years ago
8 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
8 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
8 years ago
9 years ago
8 years ago
9 years ago
8 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
8 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
  1. // Modified for Tendermint
  2. // Originally Copyright (c) 2013-2014 Conformal Systems LLC.
  3. // https://github.com/conformal/btcd/blob/master/LICENSE
  4. package addrbook
  5. import (
  6. "crypto/sha256"
  7. "encoding/binary"
  8. "fmt"
  9. "math"
  10. "math/rand"
  11. "net"
  12. "sync"
  13. "time"
  14. crypto "github.com/tendermint/go-crypto"
  15. cmn "github.com/tendermint/tmlibs/common"
  16. )
  17. const (
  18. bucketTypeNew = 0x01
  19. bucketTypeOld = 0x02
  20. )
  21. // AddrBook is an address book used for tracking peers
  22. // so we can gossip about them to others and select
  23. // peers to dial.
  24. type AddrBook interface {
  25. cmn.Service
  26. // Add and remove an address
  27. AddAddress(addr *NetAddress, src *NetAddress)
  28. RemoveAddress(addr *NetAddress)
  29. // Do we need more peers?
  30. NeedMoreAddrs() bool
  31. // Pick an address to dial
  32. PickAddress(newBias int) *NetAddress
  33. // Mark address
  34. MarkGood(*NetAddress)
  35. MarkAttempt(*Address)
  36. MarkBad(*NetAddress)
  37. // Send a selection of addresses to peers
  38. GetSelection() []*NetAddress
  39. }
  40. // addrBook - concurrency safe peer address manager.
  41. // Implements AddrBook.
  42. type addrBook struct {
  43. cmn.BaseService
  44. // immutable after creation
  45. filePath string
  46. routabilityStrict bool
  47. key string
  48. // accessed concurrently
  49. mtx sync.Mutex
  50. rand *rand.Rand
  51. ourAddrs map[string]*NetAddress
  52. addrLookup map[ID]*knownAddress // new & old
  53. bucketsOld []map[string]*knownAddress
  54. bucketsNew []map[string]*knownAddress
  55. nOld int
  56. nNew int
  57. wg sync.WaitGroup
  58. }
  59. // NewAddrBook creates a new address book.
  60. // Use Start to begin processing asynchronous address updates.
  61. func NewAddrBook(filePath string, routabilityStrict bool) *addrBook {
  62. am := &AddrBook{
  63. rand: rand.New(rand.NewSource(time.Now().UnixNano())),
  64. ourAddrs: make(map[string]*NetAddress),
  65. addrLookup: make(map[ID]*knownAddress),
  66. filePath: filePath,
  67. routabilityStrict: routabilityStrict,
  68. }
  69. am.init()
  70. am.BaseService = *cmn.NewBaseService(nil, "AddrBook", am)
  71. return am
  72. }
  73. // Initialize the buckets.
  74. // When modifying this, don't forget to update loadFromFile()
  75. func (a *addrBook) init() {
  76. a.key = crypto.CRandHex(24) // 24/2 * 8 = 96 bits
  77. // New addr buckets
  78. a.bucketsNew = make([]map[string]*knownAddress, newBucketCount)
  79. for i := range a.bucketsNew {
  80. a.bucketsNew[i] = make(map[string]*knownAddress)
  81. }
  82. // Old addr buckets
  83. a.bucketsOld = make([]map[string]*knownAddress, oldBucketCount)
  84. for i := range a.bucketsOld {
  85. a.bucketsOld[i] = make(map[string]*knownAddress)
  86. }
  87. }
  88. // OnStart implements Service.
  89. func (a *addrBook) OnStart() error {
  90. if err := a.BaseService.OnStart(); err != nil {
  91. return err
  92. }
  93. a.loadFromFile(a.filePath)
  94. // wg.Add to ensure that any invocation of .Wait()
  95. // later on will wait for saveRoutine to terminate.
  96. a.wg.Add(1)
  97. go a.saveRoutine()
  98. return nil
  99. }
  100. // OnStop implements Service.
  101. func (a *addrBook) OnStop() {
  102. a.BaseService.OnStop()
  103. }
  104. func (a *addrBook) Wait() {
  105. a.wg.Wait()
  106. }
  107. // AddOurAddress adds another one of our addresses.
  108. func (a *AddrBook) AddOurAddress(addr *NetAddress) {
  109. a.mtx.Lock()
  110. defer a.mtx.Unlock()
  111. a.Logger.Info("Add our address to book", "addr", addr)
  112. a.ourAddrs[addr.String()] = addr
  113. }
  114. //-------------------------------------------------------
  115. // AddAddress implements AddrBook - adds the given address as received from the given source.
  116. // NOTE: addr must not be nil
  117. func (a *addrBook) AddAddress(addr *NetAddress, src *NetAddress) error {
  118. a.mtx.Lock()
  119. defer a.mtx.Unlock()
  120. return a.addAddress(addr, src)
  121. }
  122. // RemoveAddress implements AddrBook - removes the address from the book.
  123. func (a *addrBook) RemoveAddress(addr *NetAddress) {
  124. a.mtx.Lock()
  125. defer a.mtx.Unlock()
  126. ka := a.addrLookup[addr.ID]
  127. if ka == nil {
  128. return
  129. }
  130. a.Logger.Info("Remove address from book", "addr", ka.Addr, "ID", ka.ID)
  131. a.removeFromAllBuckets(ka)
  132. }
  133. // NeedMoreAddrs implements AddrBook - returns true if there are not have enough addresses in the book.
  134. func (a *addrBook) NeedMoreAddrs() bool {
  135. return a.Size() < needAddressThreshold
  136. }
  137. // PickAddress implements AddrBook. It picks an address to connect to.
  138. // The address is picked randomly from an old or new bucket according
  139. // to the newBias argument, which must be between [0, 100] (or else is truncated to that range)
  140. // and determines how biased we are to pick an address from a new bucket.
  141. // PickAddress returns nil if the AddrBook is empty or if we try to pick
  142. // from an empty bucket.
  143. func (a *addrBook) PickAddress(newBias int) *NetAddress {
  144. a.mtx.Lock()
  145. defer a.mtx.Unlock()
  146. if a.size() == 0 {
  147. return nil
  148. }
  149. if newBias > 100 {
  150. newBias = 100
  151. }
  152. if newBias < 0 {
  153. newBias = 0
  154. }
  155. // Bias between new and old addresses.
  156. oldCorrelation := math.Sqrt(float64(a.nOld)) * (100.0 - float64(newBias))
  157. newCorrelation := math.Sqrt(float64(a.nNew)) * float64(newBias)
  158. // pick a random peer from a random bucket
  159. var bucket map[string]*knownAddress
  160. pickFromOldBucket := (newCorrelation+oldCorrelation)*a.rand.Float64() < oldCorrelation
  161. if (pickFromOldBucket && a.nOld == 0) ||
  162. (!pickFromOldBucket && a.nNew == 0) {
  163. return nil
  164. }
  165. // loop until we pick a random non-empty bucket
  166. for len(bucket) == 0 {
  167. if pickFromOldBucket {
  168. bucket = a.bucketsOld[a.rand.Intn(len(a.bucketsOld))]
  169. } else {
  170. bucket = a.bucketsNew[a.rand.Intn(len(a.bucketsNew))]
  171. }
  172. }
  173. // pick a random index and loop over the map to return that index
  174. randIndex := a.rand.Intn(len(bucket))
  175. for _, ka := range bucket {
  176. if randIndex == 0 {
  177. return ka.Addr
  178. }
  179. randIndex--
  180. }
  181. return nil
  182. }
  183. // MarkGood implements AddrBook - it marks the peer as good and
  184. // moves it into an "old" bucket.
  185. func (a *addrBook) MarkGood(addr *NetAddress) {
  186. a.mtx.Lock()
  187. defer a.mtx.Unlock()
  188. ka := a.addrLookup[addr.ID]
  189. if ka == nil {
  190. return
  191. }
  192. ka.markGood()
  193. if ka.isNew() {
  194. a.moveToOld(ka)
  195. }
  196. }
  197. // MarkAttempt implements AddrBook - it marks that an attempt was made to connect to the address.
  198. func (a *addrBook) MarkAttempt(addr *NetAddress) {
  199. a.mtx.Lock()
  200. defer a.mtx.Unlock()
  201. ka := a.addrLookup[addr.ID]
  202. if ka == nil {
  203. return
  204. }
  205. ka.markAttempt()
  206. }
  207. // MarkBad implements AddrBook. Currently it just ejects the address.
  208. // TODO: black list for some amount of time
  209. func (a *addrBook) MarkBad(addr *NetAddress) {
  210. a.RemoveAddress(addr)
  211. }
  212. // GetSelection implements AddrBook.
  213. // It randomly selects some addresses (old & new). Suitable for peer-exchange protocols.
  214. func (a *addrBook) GetSelection() []*NetAddress {
  215. a.mtx.Lock()
  216. defer a.mtx.Unlock()
  217. if a.size() == 0 {
  218. return nil
  219. }
  220. allAddr := make([]*NetAddress, a.size())
  221. i := 0
  222. for _, ka := range a.addrLookup {
  223. allAddr[i] = ka.Addr
  224. i++
  225. }
  226. numAddresses := cmn.MaxInt(
  227. cmn.MinInt(minGetSelection, len(allAddr)),
  228. len(allAddr)*getSelectionPercent/100)
  229. numAddresses = cmn.MinInt(maxGetSelection, numAddresses)
  230. // Fisher-Yates shuffle the array. We only need to do the first
  231. // `numAddresses' since we are throwing the rest.
  232. // XXX: What's the point of this if we already loop randomly through addrLookup ?
  233. for i := 0; i < numAddresses; i++ {
  234. // pick a number between current index and the end
  235. j := rand.Intn(len(allAddr)-i) + i
  236. allAddr[i], allAddr[j] = allAddr[j], allAddr[i]
  237. }
  238. // slice off the limit we are willing to share.
  239. return allAddr[:numAddresses]
  240. }
  241. // ListOfKnownAddresses returns the new and old addresses.
  242. func (a *AddrBook) ListOfKnownAddresses() []*knownAddress {
  243. a.mtx.Lock()
  244. defer a.mtx.Unlock()
  245. addrs := []*knownAddress{}
  246. for _, addr := range a.addrLookup {
  247. addrs = append(addrs, addr.copy())
  248. }
  249. return addrs
  250. }
  251. /* Loading & Saving */
  252. type addrBookJSON struct {
  253. Key string
  254. Addrs []*knownAddress
  255. }
  256. func (a *AddrBook) saveToFile(filePath string) {
  257. a.Logger.Info("Saving AddrBook to file", "size", a.Size())
  258. }
  259. //------------------------------------------------
  260. // Size returns the number of addresses in the book.
  261. func (a *addrBook) Size() int {
  262. a.mtx.Lock()
  263. defer a.mtx.Unlock()
  264. return a.size()
  265. }
  266. func (a *addrBook) size() int {
  267. return a.nNew + a.nOld
  268. }
  269. //----------------------------------------------------------
  270. func (a *addrBook) saveRoutine() {
  271. defer a.wg.Done()
  272. saveFileTicker := time.NewTicker(dumpAddressInterval)
  273. out:
  274. for {
  275. select {
  276. case <-saveFileTicker.C:
  277. a.saveToFile(a.filePath)
  278. case <-a.Quit:
  279. break out
  280. }
  281. }
  282. saveFileTicker.Stop()
  283. a.saveToFile(a.filePath)
  284. a.Logger.Info("Address handler done")
  285. }
  286. func (a *addrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAddress {
  287. switch bucketType {
  288. case bucketTypeNew:
  289. return a.bucketsNew[bucketIdx]
  290. case bucketTypeOld:
  291. return a.bucketsOld[bucketIdx]
  292. default:
  293. cmn.PanicSanity("Should not happen")
  294. return nil
  295. }
  296. }
  297. // Adds ka to new bucket. Returns false if it couldn't do it cuz buckets full.
  298. // NOTE: currently it always returns true.
  299. func (a *addrBook) addToNewBucket(ka *knownAddress, bucketIdx int) bool {
  300. // Sanity check
  301. if ka.isOld() {
  302. a.Logger.Error(cmn.Fmt("Cannot add address already in old bucket to a new bucket: %v", ka))
  303. return false
  304. }
  305. addrStr := ka.Addr.String()
  306. bucket := a.getBucket(bucketTypeNew, bucketIdx)
  307. // Already exists?
  308. if _, ok := bucket[addrStr]; ok {
  309. return true
  310. }
  311. // Enforce max addresses.
  312. if len(bucket) > newBucketSize {
  313. a.Logger.Info("new bucket is full, expiring old ")
  314. a.expireNew(bucketIdx)
  315. }
  316. // Add to bucket.
  317. bucket[addrStr] = ka
  318. if ka.addBucketRef(bucketIdx) == 1 {
  319. a.nNew++
  320. }
  321. // Ensure in addrLookup
  322. a.addrLookup[ka.ID()] = ka
  323. return true
  324. }
  325. // Adds ka to old bucket. Returns false if it couldn't do it cuz buckets full.
  326. func (a *addrBook) addToOldBucket(ka *knownAddress, bucketIdx int) bool {
  327. // Sanity check
  328. if ka.isNew() {
  329. a.Logger.Error(cmn.Fmt("Cannot add new address to old bucket: %v", ka))
  330. return false
  331. }
  332. if len(ka.Buckets) != 0 {
  333. a.Logger.Error(cmn.Fmt("Cannot add already old address to another old bucket: %v", ka))
  334. return false
  335. }
  336. addrStr := ka.Addr.String()
  337. bucket := a.getBucket(bucketTypeOld, bucketIdx)
  338. // Already exists?
  339. if _, ok := bucket[addrStr]; ok {
  340. return true
  341. }
  342. // Enforce max addresses.
  343. if len(bucket) > oldBucketSize {
  344. return false
  345. }
  346. // Add to bucket.
  347. bucket[addrStr] = ka
  348. if ka.addBucketRef(bucketIdx) == 1 {
  349. a.nOld++
  350. }
  351. // Ensure in addrLookup
  352. a.addrLookup[ka.ID()] = ka
  353. return true
  354. }
  355. func (a *addrBook) removeFromBucket(ka *knownAddress, bucketType byte, bucketIdx int) {
  356. if ka.BucketType != bucketType {
  357. a.Logger.Error(cmn.Fmt("Bucket type mismatch: %v", ka))
  358. return
  359. }
  360. bucket := a.getBucket(bucketType, bucketIdx)
  361. delete(bucket, ka.Addr.String())
  362. if ka.removeBucketRef(bucketIdx) == 0 {
  363. if bucketType == bucketTypeNew {
  364. a.nNew--
  365. } else {
  366. a.nOld--
  367. }
  368. delete(a.addrLookup, ka.ID())
  369. }
  370. }
  371. func (a *addrBook) removeFromAllBuckets(ka *knownAddress) {
  372. for _, bucketIdx := range ka.Buckets {
  373. bucket := a.getBucket(ka.BucketType, bucketIdx)
  374. delete(bucket, ka.Addr.String())
  375. }
  376. ka.Buckets = nil
  377. if ka.BucketType == bucketTypeNew {
  378. a.nNew--
  379. } else {
  380. a.nOld--
  381. }
  382. delete(a.addrLookup, ka.ID())
  383. }
  384. func (a *addrBook) pickOldest(bucketType byte, bucketIdx int) *knownAddress {
  385. bucket := a.getBucket(bucketType, bucketIdx)
  386. var oldest *knownAddress
  387. for _, ka := range bucket {
  388. if oldest == nil || ka.LastAttempt.Before(oldest.LastAttempt) {
  389. oldest = ka
  390. }
  391. }
  392. return oldest
  393. }
  394. func (a *addrBook) addAddress(addr, src *NetAddress) error {
  395. if a.routabilityStrict && !addr.Routable() {
  396. return fmt.Errorf("Cannot add non-routable address %v", addr)
  397. }
  398. if _, ok := a.ourAddrs[addr.String()]; ok {
  399. // Ignore our own listener address.
  400. return fmt.Errorf("Cannot add ourselves with address %v", addr)
  401. }
  402. ka := a.addrLookup[addr.ID]
  403. if ka != nil {
  404. // Already old.
  405. if ka.isOld() {
  406. return nil
  407. }
  408. // Already in max new buckets.
  409. if len(ka.Buckets) == maxNewBucketsPerAddress {
  410. return nil
  411. }
  412. // The more entries we have, the less likely we are to add more.
  413. factor := int32(2 * len(ka.Buckets))
  414. if a.rand.Int31n(factor) != 0 {
  415. return nil
  416. }
  417. } else {
  418. ka = newKnownAddress(addr, src)
  419. }
  420. bucket := a.calcNewBucket(addr, src)
  421. a.addToNewBucket(ka, bucket)
  422. a.Logger.Info("Added new address", "address", addr, "total", a.size())
  423. return nil
  424. }
  425. // Make space in the new buckets by expiring the really bad entries.
  426. // If no bad entries are available we remove the oldest.
  427. func (a *addrBook) expireNew(bucketIdx int) {
  428. for addrStr, ka := range a.bucketsNew[bucketIdx] {
  429. // If an entry is bad, throw it away
  430. if ka.isBad() {
  431. a.Logger.Info(cmn.Fmt("expiring bad address %v", addrStr))
  432. a.removeFromBucket(ka, bucketTypeNew, bucketIdx)
  433. return
  434. }
  435. }
  436. // If we haven't thrown out a bad entry, throw out the oldest entry
  437. oldest := a.pickOldest(bucketTypeNew, bucketIdx)
  438. a.removeFromBucket(oldest, bucketTypeNew, bucketIdx)
  439. }
  440. // Promotes an address from new to old.
  441. // TODO: Move to old probabilistically.
  442. // The better a node is, the less likely it should be evicted from an old bucket.
  443. func (a *addrBook) moveToOld(ka *knownAddress) {
  444. // Sanity check
  445. if ka.isOld() {
  446. a.Logger.Error(cmn.Fmt("Cannot promote address that is already old %v", ka))
  447. return
  448. }
  449. if len(ka.Buckets) == 0 {
  450. a.Logger.Error(cmn.Fmt("Cannot promote address that isn't in any new buckets %v", ka))
  451. return
  452. }
  453. // Remember one of the buckets in which ka is in.
  454. freedBucket := ka.Buckets[0]
  455. // Remove from all (new) buckets.
  456. a.removeFromAllBuckets(ka)
  457. // It's officially old now.
  458. ka.BucketType = bucketTypeOld
  459. // Try to add it to its oldBucket destination.
  460. oldBucketIdx := a.calcOldBucket(ka.Addr)
  461. added := a.addToOldBucket(ka, oldBucketIdx)
  462. if !added {
  463. // No room, must evict something
  464. oldest := a.pickOldest(bucketTypeOld, oldBucketIdx)
  465. a.removeFromBucket(oldest, bucketTypeOld, oldBucketIdx)
  466. // Find new bucket to put oldest in
  467. newBucketIdx := a.calcNewBucket(oldest.Addr, oldest.Src)
  468. added := a.addToNewBucket(oldest, newBucketIdx)
  469. // No space in newBucket either, just put it in freedBucket from above.
  470. if !added {
  471. added := a.addToNewBucket(oldest, freedBucket)
  472. if !added {
  473. a.Logger.Error(cmn.Fmt("Could not migrate oldest %v to freedBucket %v", oldest, freedBucket))
  474. }
  475. }
  476. // Finally, add to bucket again.
  477. added = a.addToOldBucket(ka, oldBucketIdx)
  478. if !added {
  479. a.Logger.Error(cmn.Fmt("Could not re-add ka %v to oldBucketIdx %v", ka, oldBucketIdx))
  480. }
  481. }
  482. }
  483. // doublesha256( key + sourcegroup +
  484. // int64(doublesha256(key + group + sourcegroup))%bucket_per_group ) % num_new_buckets
  485. func (a *addrBook) calcNewBucket(addr, src *NetAddress) int {
  486. data1 := []byte{}
  487. data1 = append(data1, []byte(a.key)...)
  488. data1 = append(data1, []byte(a.groupKey(addr))...)
  489. data1 = append(data1, []byte(a.groupKey(src))...)
  490. hash1 := doubleSha256(data1)
  491. hash64 := binary.BigEndian.Uint64(hash1)
  492. hash64 %= newBucketsPerGroup
  493. var hashbuf [8]byte
  494. binary.BigEndian.PutUint64(hashbuf[:], hash64)
  495. data2 := []byte{}
  496. data2 = append(data2, []byte(a.key)...)
  497. data2 = append(data2, a.groupKey(src)...)
  498. data2 = append(data2, hashbuf[:]...)
  499. hash2 := doubleSha256(data2)
  500. return int(binary.BigEndian.Uint64(hash2) % newBucketCount)
  501. }
  502. // doublesha256( key + group +
  503. // int64(doublesha256(key + addr))%buckets_per_group ) % num_old_buckets
  504. func (a *addrBook) calcOldBucket(addr *NetAddress) int {
  505. data1 := []byte{}
  506. data1 = append(data1, []byte(a.key)...)
  507. data1 = append(data1, []byte(addr.String())...)
  508. hash1 := doubleSha256(data1)
  509. hash64 := binary.BigEndian.Uint64(hash1)
  510. hash64 %= oldBucketsPerGroup
  511. var hashbuf [8]byte
  512. binary.BigEndian.PutUint64(hashbuf[:], hash64)
  513. data2 := []byte{}
  514. data2 = append(data2, []byte(a.key)...)
  515. data2 = append(data2, a.groupKey(addr)...)
  516. data2 = append(data2, hashbuf[:]...)
  517. hash2 := doubleSha256(data2)
  518. return int(binary.BigEndian.Uint64(hash2) % oldBucketCount)
  519. }
  520. // Return a string representing the network group of this address.
  521. // This is the /16 for IPv4, the /32 (/36 for he.net) for IPv6, the string
  522. // "local" for a local address and the string "unroutable" for an unroutable
  523. // address.
  524. func (a *addrBook) groupKey(na *NetAddress) string {
  525. if a.routabilityStrict && na.Local() {
  526. return "local"
  527. }
  528. if a.routabilityStrict && !na.Routable() {
  529. return "unroutable"
  530. }
  531. if ipv4 := na.IP.To4(); ipv4 != nil {
  532. return (&net.IPNet{IP: na.IP, Mask: net.CIDRMask(16, 32)}).String()
  533. }
  534. if na.RFC6145() || na.RFC6052() {
  535. // last four bytes are the ip address
  536. ip := net.IP(na.IP[12:16])
  537. return (&net.IPNet{IP: ip, Mask: net.CIDRMask(16, 32)}).String()
  538. }
  539. if na.RFC3964() {
  540. ip := net.IP(na.IP[2:7])
  541. return (&net.IPNet{IP: ip, Mask: net.CIDRMask(16, 32)}).String()
  542. }
  543. if na.RFC4380() {
  544. // teredo tunnels have the last 4 bytes as the v4 address XOR
  545. // 0xff.
  546. ip := net.IP(make([]byte, 4))
  547. for i, byte := range na.IP[12:16] {
  548. ip[i] = byte ^ 0xff
  549. }
  550. return (&net.IPNet{IP: ip, Mask: net.CIDRMask(16, 32)}).String()
  551. }
  552. // OK, so now we know ourselves to be a IPv6 address.
  553. // bitcoind uses /32 for everything, except for Hurricane Electric's
  554. // (he.net) IP range, which it uses /36 for.
  555. bits := 32
  556. heNet := &net.IPNet{IP: net.ParseIP("2001:470::"),
  557. Mask: net.CIDRMask(32, 128)}
  558. if heNet.Contains(na.IP) {
  559. bits = 36
  560. }
  561. return (&net.IPNet{IP: na.IP, Mask: net.CIDRMask(bits, 128)}).String()
  562. }
  563. //-----------------------------------------------------------------------------
  564. /*
  565. knownAddress
  566. tracks information about a known network address that is used
  567. to determine how viable an address is.
  568. */
  569. type knownAddress struct {
  570. Addr *NetAddress
  571. Src *NetAddress
  572. Attempts int32
  573. LastAttempt time.Time
  574. LastSuccess time.Time
  575. BucketType byte
  576. Buckets []int
  577. }
  578. func newKnownAddress(addr *NetAddress, src *NetAddress) *knownAddress {
  579. return &knownAddress{
  580. Addr: addr,
  581. Src: src,
  582. Attempts: 0,
  583. LastAttempt: time.Now(),
  584. BucketType: bucketTypeNew,
  585. Buckets: nil,
  586. }
  587. }
  588. func (ka *knownAddress) ID() ID {
  589. return ka.Addr.ID
  590. }
  591. func (ka *knownAddress) isOld() bool {
  592. return ka.BucketType == bucketTypeOld
  593. }
  594. func (ka *knownAddress) isNew() bool {
  595. return ka.BucketType == bucketTypeNew
  596. }
  597. func (ka *knownAddress) markAttempt() {
  598. now := time.Now()
  599. ka.LastAttempt = now
  600. ka.Attempts += 1
  601. }
  602. func (ka *knownAddress) markGood() {
  603. now := time.Now()
  604. ka.LastAttempt = now
  605. ka.Attempts = 0
  606. ka.LastSuccess = now
  607. }
  608. func (ka *knownAddress) addBucketRef(bucketIdx int) int {
  609. for _, bucket := range ka.Buckets {
  610. if bucket == bucketIdx {
  611. // TODO refactor to return error?
  612. // log.Warn(Fmt("Bucket already exists in ka.Buckets: %v", ka))
  613. return -1
  614. }
  615. }
  616. ka.Buckets = append(ka.Buckets, bucketIdx)
  617. return len(ka.Buckets)
  618. }
  619. func (ka *knownAddress) removeBucketRef(bucketIdx int) int {
  620. buckets := []int{}
  621. for _, bucket := range ka.Buckets {
  622. if bucket != bucketIdx {
  623. buckets = append(buckets, bucket)
  624. }
  625. }
  626. if len(buckets) != len(ka.Buckets)-1 {
  627. // TODO refactor to return error?
  628. // log.Warn(Fmt("bucketIdx not found in ka.Buckets: %v", ka))
  629. return -1
  630. }
  631. ka.Buckets = buckets
  632. return len(ka.Buckets)
  633. }
  634. /*
  635. An address is bad if the address in question is a New address, has not been tried in the last
  636. minute, and meets one of the following criteria:
  637. 1) It claims to be from the future
  638. 2) It hasn't been seen in over a month
  639. 3) It has failed at least three times and never succeeded
  640. 4) It has failed ten times in the last week
  641. All addresses that meet these criteria are assumed to be worthless and not
  642. worth keeping hold of.
  643. XXX: so a good peer needs us to call MarkGood before the conditions above are reached!
  644. */
  645. func (ka *knownAddress) isBad() bool {
  646. // Is Old --> good
  647. if ka.BucketType == bucketTypeOld {
  648. return false
  649. }
  650. // Has been attempted in the last minute --> good
  651. if ka.LastAttempt.Before(time.Now().Add(-1 * time.Minute)) {
  652. return false
  653. }
  654. // Too old?
  655. // XXX: does this mean if we've kept a connection up for this long we'll disconnect?!
  656. // and shouldn't it be .Before ?
  657. if ka.LastAttempt.After(time.Now().Add(-1 * numMissingDays * time.Hour * 24)) {
  658. return true
  659. }
  660. // Never succeeded?
  661. if ka.LastSuccess.IsZero() && ka.Attempts >= numRetries {
  662. return true
  663. }
  664. // Hasn't succeeded in too long?
  665. // XXX: does this mean if we've kept a connection up for this long we'll disconnect?!
  666. if ka.LastSuccess.Before(time.Now().Add(-1*minBadDays*time.Hour*24)) &&
  667. ka.Attempts >= maxFailures {
  668. return true
  669. }
  670. return false
  671. }
  672. //-----------------------------------------------------------------------------
  673. // doubleSha256 calculates sha256(sha256(b)) and returns the resulting bytes.
  674. func doubleSha256(b []byte) []byte {
  675. hasher := sha256.New()
  676. hasher.Write(b) // nolint: errcheck, gas
  677. sum := hasher.Sum(nil)
  678. hasher.Reset()
  679. hasher.Write(sum) // nolint: errcheck, gas
  680. return hasher.Sum(nil)
  681. }