Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: implement BIP-155 addrv2 support #1812

Merged
merged 3 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 119 additions & 63 deletions addrmgr/addrmanager.go

Large diffs are not rendered by default.

32 changes: 19 additions & 13 deletions addrmgr/addrmanager_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"net"
"os"
"testing"
"time"

"github.com/btcsuite/btcd/wire"
)

// randAddr generates a *wire.NetAddress backed by a random IPv4/IPv6 address.
func randAddr(t *testing.T) *wire.NetAddress {
// randAddr generates a *wire.NetAddressV2 backed by a random IPv4/IPv6
// address.
func randAddr(t *testing.T) *wire.NetAddressV2 {
t.Helper()

ipv4 := rand.Intn(2) == 0
Expand All @@ -30,22 +32,26 @@ func randAddr(t *testing.T) *wire.NetAddress {
ip = b[:]
}

return &wire.NetAddress{
Services: wire.ServiceFlag(rand.Uint64()),
IP: ip,
Port: uint16(rand.Uint32()),
}
services := wire.ServiceFlag(rand.Uint64())
port := uint16(rand.Uint32())

return wire.NetAddressV2FromBytes(
time.Now(), services, ip, port,
)
}

// assertAddr ensures that the two addresses match. The timestamp is not
// checked as it does not affect uniquely identifying a specific address.
func assertAddr(t *testing.T, got, expected *wire.NetAddress) {
func assertAddr(t *testing.T, got, expected *wire.NetAddressV2) {
if got.Services != expected.Services {
t.Fatalf("expected address services %v, got %v",
expected.Services, got.Services)
}
if !got.IP.Equal(expected.IP) {
t.Fatalf("expected address IP %v, got %v", expected.IP, got.IP)
gotAddr := got.Addr.String()
expectedAddr := expected.Addr.String()
if gotAddr != expectedAddr {
t.Fatalf("expected address IP %v, got %v", expectedAddr,
gotAddr)
}
if got.Port != expected.Port {
t.Fatalf("expected address port %d, got %d", expected.Port,
Expand All @@ -56,7 +62,7 @@ func assertAddr(t *testing.T, got, expected *wire.NetAddress) {
// assertAddrs ensures that the manager's address cache matches the given
// expected addresses.
func assertAddrs(t *testing.T, addrMgr *AddrManager,
expectedAddrs map[string]*wire.NetAddress) {
expectedAddrs map[string]*wire.NetAddressV2) {

t.Helper()

Expand Down Expand Up @@ -96,7 +102,7 @@ func TestAddrManagerSerialization(t *testing.T) {
// We'll be adding 5 random addresses to the manager.
const numAddrs = 5

expectedAddrs := make(map[string]*wire.NetAddress, numAddrs)
expectedAddrs := make(map[string]*wire.NetAddressV2, numAddrs)
for i := 0; i < numAddrs; i++ {
addr := randAddr(t)
expectedAddrs[NetAddressKey(addr)] = addr
Expand Down Expand Up @@ -141,7 +147,7 @@ func TestAddrManagerV1ToV2(t *testing.T) {
// each addresses' services will not be stored.
const numAddrs = 5

expectedAddrs := make(map[string]*wire.NetAddress, numAddrs)
expectedAddrs := make(map[string]*wire.NetAddressV2, numAddrs)
for i := 0; i < numAddrs; i++ {
addr := randAddr(t)
expectedAddrs[NetAddressKey(addr)] = addr
Expand Down
175 changes: 122 additions & 53 deletions addrmgr/addrmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
// naTest is used to describe a test to be performed against the NetAddressKey
// method.
type naTest struct {
in wire.NetAddress
in wire.NetAddressV2
want string
}

Expand Down Expand Up @@ -93,8 +93,10 @@ func addNaTests() {

func addNaTest(ip string, port uint16, want string) {
nip := net.ParseIP(ip)
na := *wire.NewNetAddressIPPort(nip, port, wire.SFNodeNetwork)
test := naTest{na, want}
na := wire.NetAddressV2FromBytes(
time.Now(), wire.SFNodeNetwork, nip, port,
)
test := naTest{*na, want}
naTests = append(naTests, test)
}

Expand Down Expand Up @@ -157,37 +159,49 @@ func TestAddAddressByIP(t *testing.T) {

func TestAddLocalAddress(t *testing.T) {
var tests = []struct {
address wire.NetAddress
address wire.NetAddressV2
priority addrmgr.AddressPriority
valid bool
}{
{
wire.NetAddress{IP: net.ParseIP("192.168.0.100")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("192.168.0.100"), 0,
),
addrmgr.InterfacePrio,
false,
},
{
wire.NetAddress{IP: net.ParseIP("204.124.1.1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.1.1"), 0,
),
addrmgr.InterfacePrio,
true,
},
{
wire.NetAddress{IP: net.ParseIP("204.124.1.1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.1.1"), 0,
),
addrmgr.BoundPrio,
true,
},
{
wire.NetAddress{IP: net.ParseIP("::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("::1"), 0,
),
addrmgr.InterfacePrio,
false,
},
{
wire.NetAddress{IP: net.ParseIP("fe80::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("fe80::1"), 0,
),
addrmgr.InterfacePrio,
false,
},
{
wire.NetAddress{IP: net.ParseIP("2620:100::1")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2620:100::1"), 0,
),
addrmgr.InterfacePrio,
true,
},
Expand All @@ -197,12 +211,12 @@ func TestAddLocalAddress(t *testing.T) {
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)
"been accepted", x, test.address.Addr.String())
continue
}
if result != nil && test.valid {
t.Errorf("TestAddLocalAddress test #%d failed: %s should not have "+
"been accepted", x, test.address.IP)
"been accepted", x, test.address.Addr.String())
continue
}
}
Expand Down Expand Up @@ -257,7 +271,7 @@ func TestNeedMoreAddresses(t *testing.T) {
if !b {
t.Errorf("Expected that we need more addresses")
}
addrs := make([]*wire.NetAddress, addrsToAdd)
addrs := make([]*wire.NetAddressV2, addrsToAdd)

var err error
for i := 0; i < addrsToAdd; i++ {
Expand All @@ -268,7 +282,9 @@ func TestNeedMoreAddresses(t *testing.T) {
}
}

srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
srcAddr := wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4(173, 144, 173, 111), 8333,
)

n.AddAddresses(addrs, srcAddr)
numAddrs := n.NumAddresses()
Expand All @@ -285,7 +301,7 @@ func TestNeedMoreAddresses(t *testing.T) {
func TestGood(t *testing.T) {
n := addrmgr.New("testgood", lookupFunc)
addrsToAdd := 64 * 64
addrs := make([]*wire.NetAddress, addrsToAdd)
addrs := make([]*wire.NetAddressV2, addrsToAdd)

var err error
for i := 0; i < addrsToAdd; i++ {
Expand All @@ -296,7 +312,9 @@ func TestGood(t *testing.T) {
}
}

srcAddr := wire.NewNetAddressIPPort(net.IPv4(173, 144, 173, 111), 8333, 0)
srcAddr := wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4(173, 144, 173, 111), 8333,
)

n.AddAddresses(addrs, srcAddr)
for _, addr := range addrs {
Expand Down Expand Up @@ -331,8 +349,8 @@ func TestGetAddress(t *testing.T) {
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)
if ka.NetAddress().Addr.String() != someIP {
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().Addr.String(), someIP)
}

// Mark this as a good address and get it
Expand All @@ -341,8 +359,8 @@ func TestGetAddress(t *testing.T) {
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)
if ka.NetAddress().Addr.String() != someIP {
t.Errorf("Wrong IP: got %v, want %v", ka.NetAddress().Addr.String(), someIP)
}

numAddrs := n.NumAddresses()
Expand All @@ -352,43 +370,83 @@ func TestGetAddress(t *testing.T) {
}

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")},
localAddrs := []wire.NetAddressV2{
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("192.168.0.100"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("fe80::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
}

var tests = []struct {
remoteAddr wire.NetAddress
want0 wire.NetAddress
want1 wire.NetAddress
want2 wire.NetAddress
want3 wire.NetAddress
remoteAddr wire.NetAddressV2
want0 wire.NetAddressV2
want1 wire.NetAddressV2
want2 wire.NetAddressV2
want3 wire.NetAddressV2
}{
{
// 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")},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.8.1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.8.100"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0,
net.ParseIP("fd87:d87e:eb43:25::1"), 0,
),
},
{
// 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},
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("172.16.0.254"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv4zero, 0,
),
},
{
// 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")},
*wire.NetAddressV2FromBytes(
time.Now(), 0,
net.ParseIP("2602:100:abcd::102"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.IPv6zero, 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
*wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("2001:470::1"), 0,
),
},
/* XXX
{
Expand All @@ -406,9 +464,12 @@ func TestGetBestLocalAddress(t *testing.T) {
// 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) {
wantAddr := test.want0.Addr.String()
gotAddr := got.Addr.String()
if wantAddr != gotAddr {
remoteAddr := test.remoteAddr.Addr.String()
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
x, test.remoteAddr.IP, test.want1.IP, got.IP)
x, remoteAddr, wantAddr, gotAddr)
continue
}
}
Expand All @@ -420,23 +481,31 @@ func TestGetBestLocalAddress(t *testing.T) {
// Test against want1
for x, test := range tests {
got := amgr.GetBestLocalAddress(&test.remoteAddr)
if !test.want1.IP.Equal(got.IP) {
wantAddr := test.want1.Addr.String()
gotAddr := got.Addr.String()
if wantAddr != gotAddr {
remoteAddr := test.remoteAddr.Addr.String()
t.Errorf("TestGetBestLocalAddress test1 #%d failed for remote address %s: want %s got %s",
x, test.remoteAddr.IP, test.want1.IP, got.IP)
x, remoteAddr, wantAddr, gotAddr)
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)
localAddr := wire.NetAddressV2FromBytes(
time.Now(), 0, net.ParseIP("204.124.8.100"), 0,
)
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) {
wantAddr := test.want2.Addr.String()
gotAddr := got.Addr.String()
if wantAddr != gotAddr {
remoteAddr := test.remoteAddr.Addr.String()
t.Errorf("TestGetBestLocalAddress test2 #%d failed for remote address %s: want %s got %s",
x, test.remoteAddr.IP, test.want2.IP, got.IP)
x, remoteAddr, wantAddr, gotAddr)
continue
}
}
Expand Down
Loading