aboutsummaryrefslogtreecommitdiffstats
path: root/p2p/enr
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2019-06-07 21:31:00 +0800
committerGitHub <noreply@github.com>2019-06-07 21:31:00 +0800
commite83c3ccc47b2001b7871b60084d10c5f861c9c93 (patch)
tree54014c38b9cab361d2194304b19d2f51c11d7cda /p2p/enr
parent896322bf88f40329b400d691cbdce9275739310e (diff)
downloadgo-tangerine-e83c3ccc47b2001b7871b60084d10c5f861c9c93.tar
go-tangerine-e83c3ccc47b2001b7871b60084d10c5f861c9c93.tar.gz
go-tangerine-e83c3ccc47b2001b7871b60084d10c5f861c9c93.tar.bz2
go-tangerine-e83c3ccc47b2001b7871b60084d10c5f861c9c93.tar.lz
go-tangerine-e83c3ccc47b2001b7871b60084d10c5f861c9c93.tar.xz
go-tangerine-e83c3ccc47b2001b7871b60084d10c5f861c9c93.tar.zst
go-tangerine-e83c3ccc47b2001b7871b60084d10c5f861c9c93.zip
p2p/enode: improve IPv6 support, add ENR text representation (#19663)
* p2p/enr: add entries for for IPv4/IPv6 separation This adds entry types for "ip6", "udp6", "tcp6" keys. The IP type stays around because removing it would break a lot of code and force everyone to care about the distinction. * p2p/enode: track IPv4 and IPv6 address separately LocalNode predicts the local node's UDP endpoint and updates the record. This change makes it predict IPv4 and IPv6 endpoints separately since they can now be in the record at the same time. * p2p/enode: implement base64 text format * all: switch to enode.Parse(...) This allows passing base64-encoded node records to all the places that previously accepted enode:// URLs. The URL format is still supported. * cmd/bootnode, p2p: log node URL instead of ENR ...and return the base64 record in NodeInfo.
Diffstat (limited to 'p2p/enr')
-rw-r--r--p2p/enr/enr.go12
-rw-r--r--p2p/enr/enr_test.go24
-rw-r--r--p2p/enr/entries.go76
3 files changed, 96 insertions, 16 deletions
diff --git a/p2p/enr/enr.go b/p2p/enr/enr.go
index 444820c15..c36ae9e3e 100644
--- a/p2p/enr/enr.go
+++ b/p2p/enr/enr.go
@@ -163,6 +163,16 @@ func (r *Record) invalidate() {
r.raw = nil
}
+// Signature returns the signature of the record.
+func (r *Record) Signature() []byte {
+ if r.signature == nil {
+ return nil
+ }
+ cpy := make([]byte, len(r.signature))
+ copy(cpy, r.signature)
+ return cpy
+}
+
// EncodeRLP implements rlp.Encoder. Encoding fails if
// the record is unsigned.
func (r Record) EncodeRLP(w io.Writer) error {
@@ -173,7 +183,7 @@ func (r Record) EncodeRLP(w io.Writer) error {
return err
}
-// DecodeRLP implements rlp.Decoder. Decoding verifies the signature.
+// DecodeRLP implements rlp.Decoder. Decoding doesn't verify the signature.
func (r *Record) DecodeRLP(s *rlp.Stream) error {
dec, raw, err := decodeRecord(s)
if err != nil {
diff --git a/p2p/enr/enr_test.go b/p2p/enr/enr_test.go
index 449c898a8..434685e0b 100644
--- a/p2p/enr/enr_test.go
+++ b/p2p/enr/enr_test.go
@@ -49,23 +49,23 @@ func TestGetSetID(t *testing.T) {
}
// TestGetSetIP4 tests encoding/decoding and setting/getting of the IP key.
-func TestGetSetIP4(t *testing.T) {
- ip := IP{192, 168, 0, 3}
+func TestGetSetIPv4(t *testing.T) {
+ ip := IPv4{192, 168, 0, 3}
var r Record
r.Set(ip)
- var ip2 IP
+ var ip2 IPv4
require.NoError(t, r.Load(&ip2))
assert.Equal(t, ip, ip2)
}
-// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP key.
-func TestGetSetIP6(t *testing.T) {
- ip := IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}
+// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP6 key.
+func TestGetSetIPv6(t *testing.T) {
+ ip := IPv6{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}
var r Record
r.Set(ip)
- var ip2 IP
+ var ip2 IPv6
require.NoError(t, r.Load(&ip2))
assert.Equal(t, ip, ip2)
}
@@ -83,7 +83,7 @@ func TestGetSetUDP(t *testing.T) {
func TestLoadErrors(t *testing.T) {
var r Record
- ip4 := IP{127, 0, 0, 1}
+ ip4 := IPv4{127, 0, 0, 1}
r.Set(ip4)
// Check error for missing keys.
@@ -185,13 +185,13 @@ func TestSeq(t *testing.T) {
func TestGetSetOverwrite(t *testing.T) {
var r Record
- ip := IP{192, 168, 0, 3}
+ ip := IPv4{192, 168, 0, 3}
r.Set(ip)
- ip2 := IP{192, 168, 0, 4}
+ ip2 := IPv4{192, 168, 0, 4}
r.Set(ip2)
- var ip3 IP
+ var ip3 IPv4
require.NoError(t, r.Load(&ip3))
assert.Equal(t, ip2, ip3)
}
@@ -200,7 +200,7 @@ func TestGetSetOverwrite(t *testing.T) {
func TestSignEncodeAndDecode(t *testing.T) {
var r Record
r.Set(UDP(30303))
- r.Set(IP{127, 0, 0, 1})
+ r.Set(IPv4{127, 0, 0, 1})
require.NoError(t, signTest([]byte{5}, &r))
blob, err := rlp.EncodeToBytes(r)
diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go
index 347990ab6..f2118401a 100644
--- a/p2p/enr/entries.go
+++ b/p2p/enr/entries.go
@@ -60,11 +60,21 @@ type TCP uint16
func (v TCP) ENRKey() string { return "tcp" }
+// UDP is the "udp" key, which holds the IPv6-specific UDP port of the node.
+type TCP6 uint16
+
+func (v TCP6) ENRKey() string { return "tcp6" }
+
// UDP is the "udp" key, which holds the UDP port of the node.
type UDP uint16
func (v UDP) ENRKey() string { return "udp" }
+// UDP is the "udp" key, which holds the IPv6-specific UDP port of the node.
+type UDP6 uint16
+
+func (v UDP6) ENRKey() string { return "udp6" }
+
// ID is the "id" key, which holds the name of the identity scheme.
type ID string
@@ -72,17 +82,27 @@ const IDv4 = ID("v4") // the default identity scheme
func (v ID) ENRKey() string { return "id" }
-// IP is the "ip" key, which holds the IP address of the node.
+// IP is either the "ip" or "ip6" key, depending on the value.
+// Use this value to encode IP addresses that can be either v4 or v6.
+// To load an address from a record use the IPv4 or IPv6 types.
type IP net.IP
-func (v IP) ENRKey() string { return "ip" }
+func (v IP) ENRKey() string {
+ if net.IP(v).To4() == nil {
+ return "ip6"
+ }
+ return "ip"
+}
// EncodeRLP implements rlp.Encoder.
func (v IP) EncodeRLP(w io.Writer) error {
if ip4 := net.IP(v).To4(); ip4 != nil {
return rlp.Encode(w, ip4)
}
- return rlp.Encode(w, net.IP(v))
+ if ip6 := net.IP(v).To16(); ip6 != nil {
+ return rlp.Encode(w, ip6)
+ }
+ return fmt.Errorf("invalid IP address: %v", net.IP(v))
}
// DecodeRLP implements rlp.Decoder.
@@ -96,6 +116,56 @@ func (v *IP) DecodeRLP(s *rlp.Stream) error {
return nil
}
+// IPv4 is the "ip" key, which holds the IP address of the node.
+type IPv4 net.IP
+
+func (v IPv4) ENRKey() string { return "ip" }
+
+// EncodeRLP implements rlp.Encoder.
+func (v IPv4) EncodeRLP(w io.Writer) error {
+ ip4 := net.IP(v).To4()
+ if ip4 == nil {
+ return fmt.Errorf("invalid IPv4 address: %v", net.IP(v))
+ }
+ return rlp.Encode(w, ip4)
+}
+
+// DecodeRLP implements rlp.Decoder.
+func (v *IPv4) DecodeRLP(s *rlp.Stream) error {
+ if err := s.Decode((*net.IP)(v)); err != nil {
+ return err
+ }
+ if len(*v) != 4 {
+ return fmt.Errorf("invalid IPv4 address, want 4 bytes: %v", *v)
+ }
+ return nil
+}
+
+// IPv6 is the "ip6" key, which holds the IP address of the node.
+type IPv6 net.IP
+
+func (v IPv6) ENRKey() string { return "ip6" }
+
+// EncodeRLP implements rlp.Encoder.
+func (v IPv6) EncodeRLP(w io.Writer) error {
+ ip6 := net.IP(v).To16()
+ if ip6 == nil {
+ return fmt.Errorf("invalid IPv6 address: %v", net.IP(v))
+ }
+ return rlp.Encode(w, ip6)
+}
+
+// DecodeRLP implements rlp.Decoder.
+func (v *IPv6) DecodeRLP(s *rlp.Stream) error {
+ if err := s.Decode((*net.IP)(v)); err != nil {
+ return err
+ }
+ if len(*v) != 16 {
+ return fmt.Errorf("invalid IPv6 address, want 16 bytes: %v", *v)
+ }
+ return nil
+}
+
// KeyError is an error related to a key.
type KeyError struct {
Key string