addrmgr: Always use a 50% chance between tried and new entries.

This change was suggested as Countermeasure 2 in
Eclipse Attacks on Bitcoin's Peer-to-Peer Network, Ethan
Heilman, Alison Kendler, Aviv Zohar, Sharon Goldberg. ePrint Archive
Report 2015/263. March 2015.

This mimics Bitcoin Core commit c6a63ceeb4956933588995bcf01dc3095aaeb1fc
This commit is contained in:
David Hill 2015-04-06 12:13:00 -04:00
parent 320ecea6a0
commit 0eef96e1c8
3 changed files with 9 additions and 26 deletions

View file

@ -12,7 +12,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"math"
"math/rand" "math/rand"
"net" "net"
"os" "os"
@ -741,7 +740,7 @@ func NetAddressKey(na *wire.NetAddress) string {
// random one from the possible addresses with preference given to ones that // random one from the possible addresses with preference given to ones that
// have not been used recently and should not pick 'close' addresses // have not been used recently and should not pick 'close' addresses
// consecutively. // consecutively.
func (a *AddrManager) GetAddress(class string, newBias int) *KnownAddress { func (a *AddrManager) GetAddress(class string) *KnownAddress {
// Protect concurrent access. // Protect concurrent access.
a.mtx.Lock() a.mtx.Lock()
defer a.mtx.Unlock() defer a.mtx.Unlock()
@ -750,20 +749,8 @@ func (a *AddrManager) GetAddress(class string, newBias int) *KnownAddress {
return nil return nil
} }
if newBias > 100 { // Use a 50% chance for choosing between tried and new table entries.
newBias = 100 if a.nTried > 0 && (a.nNew == 0 || a.rand.Intn(2) == 0) {
}
if newBias < 0 {
newBias = 0
}
// Bias between new and tried addresses.
triedCorrelation := math.Sqrt(float64(a.nTried)) *
(100.0 - float64(newBias))
newCorrelation := math.Sqrt(float64(a.nNew)) * float64(newBias)
if ((newCorrelation + triedCorrelation) * a.rand.Float64()) <
triedCorrelation {
// Tried entry. // Tried entry.
large := 1 << 30 large := 1 << 30
factor := 1.0 factor := 1.0

View file

@ -221,7 +221,7 @@ func TestAttempt(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Adding address failed: %v", err) t.Fatalf("Adding address failed: %v", err)
} }
ka := n.GetAddress("any", 100) ka := n.GetAddress("any")
if !ka.LastAttempt().IsZero() { if !ka.LastAttempt().IsZero() {
t.Errorf("Address should not have attempts, but does") t.Errorf("Address should not have attempts, but does")
@ -243,7 +243,7 @@ func TestConnected(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Adding address failed: %v", err) t.Fatalf("Adding address failed: %v", err)
} }
ka := n.GetAddress("any", 100) ka := n.GetAddress("any")
na := ka.NetAddress() na := ka.NetAddress()
na.Timestamp = time.Now().Add(time.Hour * -1) // make it an hour ago na.Timestamp = time.Now().Add(time.Hour * -1) // make it an hour ago
@ -334,7 +334,7 @@ func TestGetAddress(t *testing.T) {
n := addrmgr.New("testgetaddress", lookupFunc) n := addrmgr.New("testgetaddress", lookupFunc)
// Get an address from an empty set (should error) // Get an address from an empty set (should error)
if rv := n.GetAddress("any", 10); rv != nil { if rv := n.GetAddress("any"); rv != nil {
t.Errorf("GetAddress failed: got: %v want: %v\n", rv, nil) t.Errorf("GetAddress failed: got: %v want: %v\n", rv, nil)
} }
@ -343,7 +343,7 @@ func TestGetAddress(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Adding address failed: %v", err) t.Fatalf("Adding address failed: %v", err)
} }
ka := n.GetAddress("any", 120) // 100 bias is max, but shouldn't error ka := n.GetAddress("any")
if ka == nil { if ka == nil {
t.Fatalf("Did not get an address where there is one in the pool") t.Fatalf("Did not get an address where there is one in the pool")
} }
@ -353,7 +353,7 @@ func TestGetAddress(t *testing.T) {
// Mark this as a good address and get it // Mark this as a good address and get it
n.Good(ka.NetAddress()) n.Good(ka.NetAddress())
ka = n.GetAddress("any", -10) // 0 bias is min, but shouldn't error ka = n.GetAddress("any")
if ka == nil { if ka == nil {
t.Fatalf("Did not get an address where there is one in the pool") t.Fatalf("Did not get an address where there is one in the pool")
} }

View file

@ -695,15 +695,11 @@ out:
tries := 0 tries := 0
for state.NeedMoreOutbound() && for state.NeedMoreOutbound() &&
atomic.LoadInt32(&s.shutdown) == 0 { atomic.LoadInt32(&s.shutdown) == 0 {
// We bias like bitcoind does, 10 for no outgoing
// up to 90 (8) for the selection of new vs tried
//addresses.
nPeers := state.OutboundCount() nPeers := state.OutboundCount()
if nPeers > 8 { if nPeers > 8 {
nPeers = 8 nPeers = 8
} }
addr := s.addrManager.GetAddress("any", 10+nPeers*10) addr := s.addrManager.GetAddress("any")
if addr == nil { if addr == nil {
break break
} }