bcd50ea838
In this commit, we update the serialized version of the AddressManager to also store each address' service bits. This allows an address' service bits to be properly set when read from disk, which allows external callers to reliably filter out addresses which do not support their required services. Since the service bits were not previously stored, the serialization version needed to be bumped. A test has been added to test the behavior of upgrading from version 1 to 2.
472 lines
12 KiB
Go
472 lines
12 KiB
Go
// Copyright (c) 2013-2014 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package addrmgr_test
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/btcsuite/btcd/addrmgr"
|
|
"github.com/btcsuite/btcd/wire"
|
|
)
|
|
|
|
// naTest is used to describe a test to be performed against the NetAddressKey
|
|
// method.
|
|
type naTest struct {
|
|
in wire.NetAddress
|
|
want string
|
|
}
|
|
|
|
// naTests houses all of the tests to be performed against the NetAddressKey
|
|
// method.
|
|
var naTests = make([]naTest, 0)
|
|
|
|
// Put some IP in here for convenience. Points to google.
|
|
var someIP = "173.194.115.66"
|
|
|
|
// addNaTests
|
|
func addNaTests() {
|
|
// IPv4
|
|
// Localhost
|
|
addNaTest("127.0.0.1", 8333, "127.0.0.1:8333")
|
|
addNaTest("127.0.0.1", 8334, "127.0.0.1:8334")
|
|
|
|
// Class A
|
|
addNaTest("1.0.0.1", 8333, "1.0.0.1:8333")
|
|
addNaTest("2.2.2.2", 8334, "2.2.2.2:8334")
|
|
addNaTest("27.253.252.251", 8335, "27.253.252.251:8335")
|
|
addNaTest("123.3.2.1", 8336, "123.3.2.1:8336")
|
|
|
|
// Private Class A
|
|
addNaTest("10.0.0.1", 8333, "10.0.0.1:8333")
|
|
addNaTest("10.1.1.1", 8334, "10.1.1.1:8334")
|
|
addNaTest("10.2.2.2", 8335, "10.2.2.2:8335")
|
|
addNaTest("10.10.10.10", 8336, "10.10.10.10:8336")
|
|
|
|
// Class B
|
|
addNaTest("128.0.0.1", 8333, "128.0.0.1:8333")
|
|
addNaTest("129.1.1.1", 8334, "129.1.1.1:8334")
|
|
addNaTest("180.2.2.2", 8335, "180.2.2.2:8335")
|
|
addNaTest("191.10.10.10", 8336, "191.10.10.10:8336")
|
|
|
|
// Private Class B
|
|
addNaTest("172.16.0.1", 8333, "172.16.0.1:8333")
|
|
addNaTest("172.16.1.1", 8334, "172.16.1.1:8334")
|
|
addNaTest("172.16.2.2", 8335, "172.16.2.2:8335")
|
|
addNaTest("172.16.172.172", 8336, "172.16.172.172:8336")
|
|
|
|
// Class C
|
|
addNaTest("193.0.0.1", 8333, "193.0.0.1:8333")
|
|
addNaTest("200.1.1.1", 8334, "200.1.1.1:8334")
|
|
addNaTest("205.2.2.2", 8335, "205.2.2.2:8335")
|
|
addNaTest("223.10.10.10", 8336, "223.10.10.10:8336")
|
|
|
|
// Private Class C
|
|
addNaTest("192.168.0.1", 8333, "192.168.0.1:8333")
|
|
addNaTest("192.168.1.1", 8334, "192.168.1.1:8334")
|
|
addNaTest("192.168.2.2", 8335, "192.168.2.2:8335")
|
|
addNaTest("192.168.192.192", 8336, "192.168.192.192:8336")
|
|
|
|
// IPv6
|
|
// Localhost
|
|
addNaTest("::1", 8333, "[::1]:8333")
|
|
addNaTest("fe80::1", 8334, "[fe80::1]:8334")
|
|
|
|
// Link-local
|
|
addNaTest("fe80::1:1", 8333, "[fe80::1:1]:8333")
|
|
addNaTest("fe91::2:2", 8334, "[fe91::2:2]:8334")
|
|
addNaTest("fea2::3:3", 8335, "[fea2::3:3]:8335")
|
|
addNaTest("feb3::4:4", 8336, "[feb3::4:4]:8336")
|
|
|
|
// Site-local
|
|
addNaTest("fec0::1:1", 8333, "[fec0::1:1]:8333")
|
|
addNaTest("fed1::2:2", 8334, "[fed1::2:2]:8334")
|
|
addNaTest("fee2::3:3", 8335, "[fee2::3:3]:8335")
|
|
addNaTest("fef3::4:4", 8336, "[fef3::4:4]:8336")
|
|
}
|
|
|
|
func addNaTest(ip string, port uint16, want string) {
|
|
nip := net.ParseIP(ip)
|
|
na := *wire.NewNetAddressIPPort(nip, port, wire.SFNodeNetwork)
|
|
test := naTest{na, want}
|
|
naTests = append(naTests, test)
|
|
}
|
|
|
|
func lookupFunc(host string) ([]net.IP, error) {
|
|
return nil, errors.New("not implemented")
|
|
}
|
|
|
|
func TestStartStop(t *testing.T) {
|
|
n := addrmgr.New("teststartstop", lookupFunc)
|
|
n.Start()
|
|
err := n.Stop()
|
|
if err != nil {
|
|
t.Fatalf("Address Manager failed to stop: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAddAddressByIP(t *testing.T) {
|
|
fmtErr := fmt.Errorf("")
|
|
addrErr := &net.AddrError{}
|
|
var tests = []struct {
|
|
addrIP string
|
|
err error
|
|
}{
|
|
{
|
|
someIP + ":8333",
|
|
nil,
|
|
},
|
|
{
|
|
someIP,
|
|
addrErr,
|
|
},
|
|
{
|
|
someIP[:12] + ":8333",
|
|
fmtErr,
|
|
},
|
|
{
|
|
someIP + ":abcd",
|
|
fmtErr,
|
|
},
|
|
}
|
|
|
|
amgr := addrmgr.New("testaddressbyip", nil)
|
|
for i, test := range tests {
|
|
err := amgr.AddAddressByIP(test.addrIP)
|
|
if test.err != nil && err == nil {
|
|
t.Errorf("TestGood test %d failed expected an error and got none", i)
|
|
continue
|
|
}
|
|
if test.err == nil && err != nil {
|
|
t.Errorf("TestGood test %d failed expected no error and got one", i)
|
|
continue
|
|
}
|
|
if reflect.TypeOf(err) != reflect.TypeOf(test.err) {
|
|
t.Errorf("TestGood test %d failed got %v, want %v", i,
|
|
reflect.TypeOf(err), reflect.TypeOf(test.err))
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAddLocalAddress(t *testing.T) {
|
|
var tests = []struct {
|
|
address wire.NetAddress
|
|
priority addrmgr.AddressPriority
|
|
valid bool
|
|
}{
|
|
{
|
|
wire.NetAddress{IP: net.ParseIP("192.168.0.100")},
|
|
addrmgr.InterfacePrio,
|
|
false,
|
|
},
|
|
{
|
|
wire.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
|
addrmgr.InterfacePrio,
|
|
true,
|
|
},
|
|
{
|
|
wire.NetAddress{IP: net.ParseIP("204.124.1.1")},
|
|
addrmgr.BoundPrio,
|
|
true,
|
|
},
|
|
{
|
|
wire.NetAddress{IP: net.ParseIP("::1")},
|
|
addrmgr.InterfacePrio,
|
|
false,
|
|
},
|
|
{
|
|
wire.NetAddress{IP: net.ParseIP("fe80::1")},
|
|
addrmgr.InterfacePrio,
|
|
false,
|
|
},
|
|
{
|
|
wire.NetAddress{IP: net.ParseIP("2620:100::1")},
|
|
addrmgr.InterfacePrio,
|
|
true,
|
|
},
|
|
}
|
|
amgr := addrmgr.New("testaddlocaladdress", nil)
|
|
for x, test := range tests {
|
|
result := amgr.AddLocalAddress(&test.address, test.priority)
|
|
if result == nil && !test.valid {
|
|
t.Errorf("TestAddLocalAddress test #%d failed: %s should have "+
|
|
"been accepted", x, test.address.IP)
|
|
continue
|
|
}
|
|
if result != nil && test.valid {
|
|
t.Errorf("TestAddLocalAddress test #%d failed: %s should not have "+
|
|
"been accepted", x, test.address.IP)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAttempt(t *testing.T) {
|
|
n := addrmgr.New("testattempt", lookupFunc)
|
|
|
|
// Add a new address and get it
|
|
err := n.AddAddressByIP(someIP + ":8333")
|
|
if err != nil {
|
|
t.Fatalf("Adding address failed: %v", err)
|
|
}
|
|
ka := n.GetAddress()
|
|
|
|
if !ka.LastAttempt().IsZero() {
|
|
t.Errorf("Address should not have attempts, but does")
|
|
}
|
|
|
|
na := ka.NetAddress()
|
|
n.Attempt(na)
|
|
|
|
if ka.LastAttempt().IsZero() {
|
|
t.Errorf("Address should have an attempt, but does not")
|
|
}
|
|
}
|
|
|
|
func TestConnected(t *testing.T) {
|
|
n := addrmgr.New("testconnected", lookupFunc)
|
|
|
|
// Add a new address and get it
|
|
err := n.AddAddressByIP(someIP + ":8333")
|
|
if err != nil {
|
|
t.Fatalf("Adding address failed: %v", err)
|
|
}
|
|
ka := n.GetAddress()
|
|
na := ka.NetAddress()
|
|
// make it an hour ago
|
|
na.Timestamp = time.Unix(time.Now().Add(time.Hour*-1).Unix(), 0)
|
|
|
|
n.Connected(na)
|
|
|
|
if !ka.NetAddress().Timestamp.After(na.Timestamp) {
|
|
t.Errorf("Address should have a new timestamp, but does not")
|
|
}
|
|
}
|
|
|
|
func TestNeedMoreAddresses(t *testing.T) {
|
|
n := addrmgr.New("testneedmoreaddresses", lookupFunc)
|
|
addrsToAdd := 1500
|
|
b := n.NeedMoreAddresses()
|
|
if !b {
|
|
t.Errorf("Expected that we need more addresses")
|
|
}
|
|
addrs := make([]*wire.NetAddress, addrsToAdd)
|
|
|
|
var err error
|
|
for i := 0; i < addrsToAdd; i++ {
|
|
s := fmt.Sprintf("%d.%d.173.147:8333", i/128+60, i%128+60)
|
|
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
|
|
if err != nil {
|
|
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
|
}
|
|
}
|
|
|
|
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
|
|
|
n.AddAddresses(addrs, srcAddr)
|
|
numAddrs := n.NumAddresses()
|
|
if numAddrs > addrsToAdd {
|
|
t.Errorf("Number of addresses is too many %d vs %d", numAddrs, addrsToAdd)
|
|
}
|
|
|
|
b = n.NeedMoreAddresses()
|
|
if b {
|
|
t.Errorf("Expected that we don't need more addresses")
|
|
}
|
|
}
|
|
|
|
func TestGood(t *testing.T) {
|
|
n := addrmgr.New("testgood", lookupFunc)
|
|
addrsToAdd := 64 * 64
|
|
addrs := make([]*wire.NetAddress, addrsToAdd)
|
|
|
|
var err error
|
|
for i := 0; i < addrsToAdd; i++ {
|
|
s := fmt.Sprintf("%d.173.147.%d:8333", i/64+60, i%64+60)
|
|
addrs[i], err = n.DeserializeNetAddress(s, wire.SFNodeNetwork)
|
|
if err != nil {
|
|
t.Errorf("Failed to turn %s into an address: %v", s, err)
|
|
}
|
|
}
|
|
|
|
srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
|
|
|
|
n.AddAddresses(addrs, srcAddr)
|
|
for _, addr := range addrs {
|
|
n.Good(addr)
|
|
}
|
|
|
|
numAddrs := n.NumAddresses()
|
|
if numAddrs >= addrsToAdd {
|
|
t.Errorf("Number of addresses is too many: %d vs %d", numAddrs, addrsToAdd)
|
|
}
|
|
|
|
numCache := len(n.AddressCache())
|
|
if numCache >= numAddrs/4 {
|
|
t.Errorf("Number of addresses in cache: got %d, want %d", numCache, numAddrs/4)
|
|
}
|
|
}
|
|
|
|
func TestGetAddress(t *testing.T) {
|
|
n := addrmgr.New("testgetaddress", lookupFunc)
|
|
|
|
// Get an address from an empty set (should error)
|
|
if rv := n.GetAddress(); rv != nil {
|
|
t.Errorf("GetAddress failed: got: %v want: %v\n", rv, nil)
|
|
}
|
|
|
|
// Add a new address and get it
|
|
err := n.AddAddressByIP(someIP + ":8333")
|
|
if err != nil {
|
|
t.Fatalf("Adding address failed: %v", err)
|
|
}
|
|
ka := n.GetAddress()
|
|
if ka == nil {
|
|
t.Fatalf("Did not get an address where there is one in the pool")
|
|
}
|
|
if ka.NetAddress().IP.String() != someIP {
|
|
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP)
|
|
}
|
|
|
|
// Mark this as a good address and get it
|
|
n.Good(ka.NetAddress())
|
|
ka = n.GetAddress()
|
|
if ka == nil {
|
|
t.Fatalf("Did not get an address where there is one in the pool")
|
|
}
|
|
if ka.NetAddress().IP.String() != someIP {
|
|
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().IP.String(), someIP)
|
|
}
|
|
|
|
numAddrs := n.NumAddresses()
|
|
if numAddrs != 1 {
|
|
t.Errorf("Wrong number of addresses: got %d, want %d", numAddrs, 1)
|
|
}
|
|
}
|
|
|
|
func TestGetBestLocalAddress(t *testing.T) {
|
|
localAddrs := []wire.NetAddress{
|
|
{IP: net.ParseIP("192.168.0.100")},
|
|
{IP: net.ParseIP("::1")},
|
|
{IP: net.ParseIP("fe80::1")},
|
|
{IP: net.ParseIP("2001:470::1")},
|
|
}
|
|
|
|
var tests = []struct {
|
|
remoteAddr wire.NetAddress
|
|
want0 wire.NetAddress
|
|
want1 wire.NetAddress
|
|
want2 wire.NetAddress
|
|
want3 wire.NetAddress
|
|
}{
|
|
{
|
|
// Remote connection from public IPv4
|
|
wire.NetAddress{IP: net.ParseIP("204.124.8.1")},
|
|
wire.NetAddress{IP: net.IPv4zero},
|
|
wire.NetAddress{IP: net.IPv4zero},
|
|
wire.NetAddress{IP: net.ParseIP("204.124.8.100")},
|
|
wire.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")},
|
|
},
|
|
{
|
|
// Remote connection from private IPv4
|
|
wire.NetAddress{IP: net.ParseIP("172.16.0.254")},
|
|
wire.NetAddress{IP: net.IPv4zero},
|
|
wire.NetAddress{IP: net.IPv4zero},
|
|
wire.NetAddress{IP: net.IPv4zero},
|
|
wire.NetAddress{IP: net.IPv4zero},
|
|
},
|
|
{
|
|
// Remote connection from public IPv6
|
|
wire.NetAddress{IP: net.ParseIP("2602:100:abcd::102")},
|
|
wire.NetAddress{IP: net.IPv6zero},
|
|
wire.NetAddress{IP: net.ParseIP("2001:470::1")},
|
|
wire.NetAddress{IP: net.ParseIP("2001:470::1")},
|
|
wire.NetAddress{IP: net.ParseIP("2001:470::1")},
|
|
},
|
|
/* XXX
|
|
{
|
|
// Remote connection from Tor
|
|
wire.NetAddress{IP: net.ParseIP("fd87:d87e:eb43::100")},
|
|
wire.NetAddress{IP: net.IPv4zero},
|
|
wire.NetAddress{IP: net.ParseIP("204.124.8.100")},
|
|
wire.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")},
|
|
},
|
|
*/
|
|
}
|
|
|
|
amgr := addrmgr.New("testgetbestlocaladdress", nil)
|
|
|
|
// Test against default when there's no address
|
|
for x, test := range tests {
|
|
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
|
if !test.want0.IP.Equal(got.IP) {
|
|
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
|
|
x, test.remoteAddr.IP, test.want1.IP, got.IP)
|
|
continue
|
|
}
|
|
}
|
|
|
|
for _, localAddr := range localAddrs {
|
|
amgr.AddLocalAddress(&localAddr, addrmgr.InterfacePrio)
|
|
}
|
|
|
|
// Test against want1
|
|
for x, test := range tests {
|
|
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
|
if !test.want1.IP.Equal(got.IP) {
|
|
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
|
|
x, test.remoteAddr.IP, test.want1.IP, got.IP)
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Add a public IP to the list of local addresses.
|
|
localAddr := wire.NetAddress{IP: net.ParseIP("204.124.8.100")}
|
|
amgr.AddLocalAddress(&localAddr, addrmgr.InterfacePrio)
|
|
|
|
// Test against want2
|
|
for x, test := range tests {
|
|
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
|
if !test.want2.IP.Equal(got.IP) {
|
|
t.Errorf("TestGetBestLocalAddress test2 #%d failed for remote address %s: want %s got %s",
|
|
x, test.remoteAddr.IP, test.want2.IP, got.IP)
|
|
continue
|
|
}
|
|
}
|
|
/*
|
|
// Add a Tor generated IP address
|
|
localAddr = wire.NetAddress{IP: net.ParseIP("fd87:d87e:eb43:25::1")}
|
|
amgr.AddLocalAddress(&localAddr, addrmgr.ManualPrio)
|
|
|
|
// Test against want3
|
|
for x, test := range tests {
|
|
got := amgr.GetBestLocalAddress(&test.remoteAddr)
|
|
if !test.want3.IP.Equal(got.IP) {
|
|
t.Errorf("TestGetBestLocalAddress test3 #%d failed for remote address %s: want %s got %s",
|
|
x, test.remoteAddr.IP, test.want3.IP, got.IP)
|
|
continue
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
func TestNetAddressKey(t *testing.T) {
|
|
addNaTests()
|
|
|
|
t.Logf("Running %d tests", len(naTests))
|
|
for i, test := range naTests {
|
|
key := addrmgr.NetAddressKey(&test.in)
|
|
if key != test.want {
|
|
t.Errorf("NetAddressKey #%d\n got: %s want: %s", i, key, test.want)
|
|
continue
|
|
}
|
|
}
|
|
|
|
}
|