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: Add getaddrv2 and addrv2. #2627

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
32 changes: 9 additions & 23 deletions addrmgr/addrmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,13 +546,15 @@ func (a *AddrManager) deserializePeers(filePath string) error {
for _, v := range sam.Addresses {
netAddr, err := a.newAddressFromString(v.Addr)
if err != nil {
return fmt.Errorf("failed to deserialize netaddress "+
"%s: %v", v.Addr, err)
log.Warnf("skipping unrecognized network address %s: %v",
v.Addr, err)
continue
}
srcAddr, err := a.newAddressFromString(v.Src)
if err != nil {
return fmt.Errorf("failed to deserialize netaddress "+
"%s: %v", v.Src, err)
log.Warnf("skipping unrecognized network address %s: %v",
v.Src, err)
continue
}

ka := &KnownAddress{
Expand Down Expand Up @@ -759,17 +761,6 @@ func (a *AddrManager) reset() {
// an unknown address type is returned without error.
func ParseHost(host string) (NetAddressType, []byte, error) {
if strings.HasSuffix(host, ".onion") {
// Check if this is a TorV2 address.
if len(host) == 22 {
data, err := base32.StdEncoding.DecodeString(
strings.ToUpper(host[:16]))
if err != nil {
return UnknownAddressType, nil, err
}
prefix := []byte{0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43}
addrBytes := append(prefix, data...)
return TORv2Address, addrBytes, nil
}
// Check if this is a valid TORv3 address.
if len(host) == 62 {
torAddressBytes, err := base32.StdEncoding.DecodeString(
Expand All @@ -787,9 +778,6 @@ func ParseHost(host string) (NetAddressType, []byte, error) {
if isIPv4(ip) {
return IPv4Address, ip.To4(), nil
}
if isOnionCatTor(ip) {
return TORv2Address, ip, nil
}
return IPv6Address, ip, nil
}

Expand Down Expand Up @@ -1137,10 +1125,8 @@ func getReachabilityFrom(localAddr, remoteAddr *NetAddress) NetAddressReach {
return Unreachable
}

isRemoteAddrTOR := remoteAddr.Type == TORv2Address ||
remoteAddr.Type == TORv3Address
isLocalAddrTOR := localAddr.Type == TORv2Address ||
localAddr.Type == TORv3Address
isRemoteAddrTOR := remoteAddr.Type == TORv3Address
isLocalAddrTOR := localAddr.Type == TORv3Address

if isRemoteAddrTOR {
if isLocalAddrTOR {
Expand Down Expand Up @@ -1236,7 +1222,7 @@ func (a *AddrManager) GetBestLocalAddress(remoteAddr *NetAddress, supportedNetAd

// Send something unroutable if nothing suitable.
var ip net.IP
if remoteAddr.Type != IPv4Address && remoteAddr.Type != TORv2Address {
if remoteAddr.Type != IPv4Address {
ip = net.IPv6zero
} else {
ip = net.IPv4zero
Expand Down
60 changes: 43 additions & 17 deletions addrmgr/addrmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
// Put some IP in here for convenience. Points to google.
var someIP = "173.194.115.66"

var zeroTime = time.Time{}

// defaultNetAddressTypeFilter defines a filter that instructs address manager
// operations that accept it to return network addresses of any type.
func defaultNetAddressTypeFilter(netAddressType NetAddressType) bool {
Expand Down Expand Up @@ -619,7 +621,7 @@ func TestValidatePeerNa(t *testing.T) {
const unroutableIpv6Address = "::1"
const routableIpv4Address = "12.1.2.3"
const routableIpv6Address = "2003::"
onionCatTorV2Address := onionCatNet.IP.String()
onionCatTorV3Address := "xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jyd.onion"
rfc4380IPAddress := rfc4380Net.IP.String()
rfc3964IPAddress := rfc3964Net.IP.String()
rfc6052IPAddress := rfc6052Net.IP.String()
Expand All @@ -632,33 +634,33 @@ func TestValidatePeerNa(t *testing.T) {
valid bool
reach NetAddressReach
}{{
name: "torv2 to torv2",
localAddress: onionCatTorV2Address,
remoteAddress: onionCatTorV2Address,
name: "torv3 to torv3",
localAddress: onionCatTorV3Address,
remoteAddress: onionCatTorV3Address,
valid: false,
reach: Private,
}, {
name: "routable ipv4 to torv2",
name: "routable ipv4 to torv3",
localAddress: routableIpv4Address,
remoteAddress: onionCatTorV2Address,
remoteAddress: onionCatTorV3Address,
valid: true,
reach: Ipv4,
}, {
name: "unroutable ipv4 to torv2",
name: "unroutable ipv4 to torv3",
localAddress: unroutableIpv4Address,
remoteAddress: onionCatTorV2Address,
remoteAddress: onionCatTorV3Address,
valid: false,
reach: Default,
}, {
name: "routable ipv6 to torv2",
name: "routable ipv6 to torv3",
localAddress: routableIpv6Address,
remoteAddress: onionCatTorV2Address,
remoteAddress: onionCatTorV3Address,
valid: false,
reach: Default,
}, {
name: "unroutable ipv6 to torv2",
name: "unroutable ipv6 to torv3",
localAddress: unroutableIpv6Address,
remoteAddress: onionCatTorV2Address,
remoteAddress: onionCatTorV3Address,
valid: false,
reach: Default,
}, {
Expand Down Expand Up @@ -755,20 +757,44 @@ func TestValidatePeerNa(t *testing.T) {

addressManager := New("testValidatePeerNa")
for _, test := range tests {
localIP := net.ParseIP(test.localAddress)
remoteIP := net.ParseIP(test.remoteAddress)
localNa := NewNetAddressIPPort(localIP, 8333, wire.SFNodeNetwork)
remoteNa := NewNetAddressIPPort(remoteIP, 8333, wire.SFNodeNetwork)
localAddrType, localAddrBytes, err := ParseHost(test.localAddress)
if err != nil {
t.Errorf("%q: failed to parse local address '%v': %v", test.name,
test.localAddress, err)
return
}
remoteAddrType, remoteAddrBytes, err := ParseHost(test.remoteAddress)
if err != nil {
t.Errorf("%q: failed to parse remote address '%v': %v", test.name,
test.remoteAddress, err)
return
}

localNa, err := NewNetAddressByType(localAddrType, localAddrBytes,
8333, zeroTime, wire.SFNodeNetwork)
if err != nil {
t.Errorf("%q: failed to create local network address '%v': %v",
test.name, test.localAddress, err)
return
}
remoteNa, err := NewNetAddressByType(remoteAddrType, remoteAddrBytes,
8333, zeroTime, wire.SFNodeNetwork)
if err != nil {
t.Errorf("%q: failed to create remote network address '%v': %v",
test.name, test.remoteAddress, err)
return
}

valid, reach := addressManager.ValidatePeerNa(localNa, remoteNa)
if valid != test.valid {
t.Errorf("%q: unexpected return value for valid - want '%v', "+
"got '%v'", test.name, test.valid, valid)
continue
return
}
if reach != test.reach {
t.Errorf("%q: unexpected return value for reach - want '%v', "+
"got '%v'", test.name, test.reach, reach)
return
}
}
}
Expand Down
17 changes: 4 additions & 13 deletions addrmgr/netaddress.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,11 @@ func (netAddr *NetAddress) IsRoutable() bool {
}

// ipString returns a string representation of the network address' IP field.
// If the ip is in the range used for TORv2 addresses then it will be
// transformed into the respective .onion address. It does not include the
// port.
// If the ip is in the range used for TOR addresses then it will be transformed
// into the respective .onion address. It does not include the port.
func (netAddr *NetAddress) ipString() string {
netIP := netAddr.IP
switch netAddr.Type {
case TORv2Address:
base32 := base32.StdEncoding.EncodeToString(netIP[6:])
return strings.ToLower(base32) + ".onion"
case TORv3Address:
addrBytes := netIP
checksum := calcTORv3Checksum(addrBytes)
Expand Down Expand Up @@ -99,9 +95,6 @@ func canonicalizeIP(addrType NetAddressType, addrBytes []byte) []byte {
switch {
case len == 16 && addrType == IPv4Address:
return net.IP(addrBytes).To4()
case len == 10 && addrType == TORv2Address:
prefix := []byte{0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43}
return append(prefix, addrBytes...)
case addrType == IPv6Address:
return net.IP(addrBytes).To16()
}
Expand All @@ -116,8 +109,6 @@ func deriveNetAddressType(claimedType NetAddressType, addrBytes []byte) (NetAddr
switch {
case isIPv4(addrBytes):
return IPv4Address, nil
case len == 16 && isOnionCatTor(addrBytes):
return TORv2Address, nil
case len == 16:
return IPv6Address, nil
case len == 32 && claimedType == TORv3Address:
Expand Down Expand Up @@ -190,8 +181,8 @@ func (a *AddrManager) newAddressFromString(addr string) (*NetAddress, error) {

// NewNetAddressIPPort creates a new address manager network address given an
// ip, port, and the supported service flags for the address. The provided ip
// MUST be an IPv4, IPv6, or TORv2 address since this method does not perform
// error checking on the derived network address type.
// MUST be a valid address since this method does not perform error checking on
// the derived network address type.
func NewNetAddressIPPort(ip net.IP, port uint16, services wire.ServiceFlag) *NetAddress {
netAddressType, _ := deriveNetAddressType(UnknownAddressType, ip)
timestamp := time.Unix(time.Now().Unix(), 0)
Expand Down
136 changes: 54 additions & 82 deletions addrmgr/netaddress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ import (
"github.com/decred/dcrd/wire"
)

var (
torV3AddressString = "xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jyd.onion"
torV3AddressBytes = []byte{
0xb8, 0x39, 0x1d, 0x20, 0x03, 0xbb, 0x3b, 0xd2,
0x85, 0xb0, 0x35, 0xac, 0x8e, 0xb3, 0x0c, 0x80,
0xc4, 0xe2, 0xa2, 0x9b, 0xb7, 0xa2, 0xf0, 0xce,
0x0d, 0xf8, 0x74, 0x3c, 0x37, 0xec, 0x35, 0x93}
)

// TestNewNetAddressByType verifies that the TestNewNetAddressByType constructor
// converts a network address with expected field values.
func TestNewNetAddressByType(t *testing.T) {
Expand All @@ -26,78 +35,53 @@ func TestNewNetAddressByType(t *testing.T) {
addrType NetAddressType
addrBytes []byte
want *NetAddress
}{
{
name: "4 byte ipv4 address stored as 4 byte ip",
addrType: IPv4Address,
addrBytes: net.ParseIP("127.0.0.1").To4(),
want: &NetAddress{
IP: []byte{0x7f, 0x00, 0x00, 0x01},
Port: port,
Services: services,
Timestamp: timestamp,
Type: IPv4Address,
},
}{{
name: "4 byte ipv4 address stored as 4 byte ip",
addrType: IPv4Address,
addrBytes: net.ParseIP("127.0.0.1").To4(),
want: &NetAddress{
IP: []byte{0x7f, 0x00, 0x00, 0x01},
Port: port,
Services: services,
Timestamp: timestamp,
Type: IPv4Address,
},
{
name: "16 byte ipv4 address stored as 4 byte ip",
addrType: IPv4Address,
addrBytes: net.ParseIP("127.0.0.1").To16(),
want: &NetAddress{
IP: []byte{0x7f, 0x00, 0x00, 0x01},
Port: port,
Services: services,
Timestamp: timestamp,
Type: IPv4Address,
},
},
{
name: "16 byte ipv6 address stored in 16 bytes",
addrType: IPv6Address,
addrBytes: net.ParseIP("::1"),
want: &NetAddress{
IP: []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
Port: port,
Services: services,
Timestamp: timestamp,
Type: IPv6Address,
},
}, {
name: "16 byte ipv4 address stored as 4 byte ip",
addrType: IPv4Address,
addrBytes: net.ParseIP("127.0.0.1").To16(),
want: &NetAddress{
IP: []byte{0x7f, 0x00, 0x00, 0x01},
Port: port,
Services: services,
Timestamp: timestamp,
Type: IPv4Address,
},
{
name: "16 byte torv2 address stored in 16 bytes",
addrType: TORv2Address,
addrBytes: net.ParseIP("fd87:d87e:eb43::"),
want: &NetAddress{
IP: []byte{
0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
Port: port,
Services: services,
Timestamp: timestamp,
Type: TORv2Address,
},
}, {
name: "16 byte ipv6 address stored in 16 bytes",
addrType: IPv6Address,
addrBytes: net.ParseIP("::1"),
want: &NetAddress{
IP: []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
Port: port,
Services: services,
Timestamp: timestamp,
Type: IPv6Address,
},
{
name: "10 byte torv2 public key stored in 16 bytes with prefix",
addrType: TORv2Address,
addrBytes: []byte{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
},
want: &NetAddress{
IP: []byte{
0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43, 0x01, 0x02,
0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
},
Port: port,
Services: services,
Timestamp: timestamp,
Type: TORv2Address,
},
}, {
name: "32 byte torv3 address stored in 32 bytes",
addrType: TORv3Address,
addrBytes: torV3AddressBytes,
want: &NetAddress{
IP: torV3AddressBytes,
Port: port,
Services: services,
Timestamp: timestamp,
Type: TORv3Address,
},
}
}}

for _, test := range tests {
addr, err := NewNetAddressByType(test.addrType, test.addrBytes, port,
Expand Down Expand Up @@ -178,23 +162,11 @@ func TestKey(t *testing.T) {
{host: "fee2::3:3", port: 8335, want: "[fee2::3:3]:8335"},
{host: "fef3::4:4", port: 8336, want: "[fef3::4:4]:8336"},

// TORv2
{
host: "fd87:d87e:eb43::",
port: 8333,
want: "aaaaaaaaaaaaaaaa.onion:8333",
},
{
host: "aaaaaaaaaaaaaaaa.onion",
port: 8334,
want: "aaaaaaaaaaaaaaaa.onion:8334",
},

// TORv3
{
host: "xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jyd.onion",
host: torV3AddressString,
port: 8333,
want: "xa4r2iadxm55fbnqgwwi5mymqdcofiu3w6rpbtqn7b2dyn7mgwj64jyd.onion:8333",
want: torV3AddressString + ":8333",
},
}

Expand Down