QSP-16 Fix Support for IPv6 (#6363)

* checkpoint changes

* new changes

* comment

* clean up

* set

* fix

* fix more

* more stuff

* clean up

* clean up

* remove

* clean up

* clean up

* comment

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Nishant Das
2020-09-16 08:17:22 +08:00
committed by GitHub
parent bb374362e4
commit 56d6e05196
7 changed files with 122 additions and 22 deletions

View File

@@ -127,6 +127,7 @@ go_test(
"//shared/testutil:go_default_library",
"//shared/testutil/assert:go_default_library",
"//shared/testutil/require:go_default_library",
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",

View File

@@ -3,7 +3,6 @@ package p2p
import (
"bytes"
"crypto/ecdsa"
"fmt"
"net"
"strconv"
"time"
@@ -124,9 +123,10 @@ func (s *Service) createListener(
if err != nil {
return nil, errors.Wrap(err, "could not listen to UDP")
}
localNode, err := s.createLocalNode(
privKey,
ipAddr,
udpAddr.IP,
int(s.cfg.UDPPort),
int(s.cfg.TCPPort),
)
@@ -365,22 +365,13 @@ func convertToAddrInfo(node *enode.Node) (*peer.AddrInfo, ma.Multiaddr, error) {
}
func convertToSingleMultiAddr(node *enode.Node) (ma.Multiaddr, error) {
ip4 := node.IP().To4()
if ip4 == nil {
return nil, errors.Errorf("node doesn't have an ip4 address, it's stated IP is %s", node.IP().String())
}
pubkey := node.Pubkey()
assertedKey := convertToInterfacePubkey(pubkey)
id, err := peer.IDFromPublicKey(assertedKey)
if err != nil {
return nil, errors.Wrap(err, "could not get peer id")
}
multiAddrString := fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ip4.String(), node.TCP(), id)
multiAddr, err := ma.NewMultiaddr(multiAddrString)
if err != nil {
return nil, errors.Wrap(err, "could not get multiaddr")
}
return multiAddr, nil
return multiAddressBuilderWithID(node.IP().String(), uint(node.TCP()), id)
}
func peersFromStringAddrs(addrs []string) ([]ma.Multiaddr, error) {

View File

@@ -6,6 +6,7 @@ import (
"net"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/peer"
noise "github.com/libp2p/go-libp2p-noise"
secio "github.com/libp2p/go-libp2p-secio"
ma "github.com/multiformats/go-multiaddr"
@@ -85,6 +86,20 @@ func multiAddressBuilder(ipAddr string, port uint) (ma.Multiaddr, error) {
return ma.NewMultiaddr(fmt.Sprintf("/ip6/%s/tcp/%d", ipAddr, port))
}
func multiAddressBuilderWithID(ipAddr string, port uint, id peer.ID) (ma.Multiaddr, error) {
parsedIP := net.ParseIP(ipAddr)
if parsedIP.To4() == nil && parsedIP.To16() == nil {
return nil, errors.Errorf("invalid ip address provided: %s", ipAddr)
}
if id.String() == "" {
return nil, errors.New("empty peer id given")
}
if parsedIP.To4() != nil {
return ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ipAddr, port, id.String()))
}
return ma.NewMultiaddr(fmt.Sprintf("/ip6/%s/tcp/%d/p2p/%s", ipAddr, port, id.String()))
}
// Adds a private key to the libp2p option if the option was provided.
// If the private key file is missing or cannot be read, or if the
// private key contents cannot be marshaled, an exception is thrown.

View File

@@ -5,9 +5,13 @@ import (
"crypto/rand"
"encoding/hex"
"io/ioutil"
"net"
"os"
"testing"
gethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
@@ -46,3 +50,30 @@ func TestPrivateKeyLoading(t *testing.T) {
t.Errorf("Private keys do not match got %#x but wanted %#x", rawBytes, newRaw)
}
}
func TestIPV6Support(t *testing.T) {
key, err := gethCrypto.GenerateKey()
db, err := enode.OpenDB("")
if err != nil {
log.Error("could not open node's peer database")
}
lNode := enode.NewLocalNode(db, key)
mockIPV6 := net.IP{0xff, 0x02, 0xAA, 0, 0x1F, 0, 0x2E, 0, 0, 0x36, 0x45, 0, 0, 0, 0, 0x02}
lNode.Set(enr.IP(mockIPV6))
ma, err := convertToSingleMultiAddr(lNode.Node())
if err != nil {
t.Fatal(err)
}
ipv6Exists := false
for _, p := range ma.Protocols() {
if p.Name == "ip4" {
t.Error("Got ip4 address instead of ip6")
}
if p.Name == "ip6" {
ipv6Exists = true
}
}
if !ipv6Exists {
t.Error("Multiaddress did not have ipv6 protocol")
}
}

View File

@@ -150,7 +150,7 @@ func metaDataFromConfig(cfg *Config) (*pbp2p.MetaData, error) {
// Retrieves an external ipv4 address and converts into a libp2p formatted value.
func ipAddr() net.IP {
ip, err := iputils.ExternalIPv4()
ip, err := iputils.ExternalIP()
if err != nil {
log.Fatalf("Could not get IPv4 address: %v", err)
}
@@ -160,7 +160,7 @@ func ipAddr() net.IP {
// Attempt to dial an address to verify its connectivity
func verifyConnectivity(addr string, port uint, protocol string) {
if addr != "" {
a := fmt.Sprintf("%s:%d", addr, port)
a := net.JoinHostPort(addr, fmt.Sprintf("%d", port))
fields := logrus.Fields{
"protocol": protocol,
"address": a,

View File

@@ -7,10 +7,64 @@ import (
// ExternalIPv4 returns the first IPv4 available.
func ExternalIPv4() (string, error) {
ifaces, err := net.Interfaces()
ips, err := retrieveIPAddrs()
if err != nil {
return "", err
}
if len(ips) == 0 {
return "127.0.0.1", nil
}
for _, ip := range ips {
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
return ip.String(), nil
}
return "127.0.0.1", nil
}
// ExternalIPv6 retrieves any allocated IPv6 addresses
// from the accessible network interfaces.
func ExternalIPv6() (string, error) {
ips, err := retrieveIPAddrs()
if err != nil {
return "", err
}
if len(ips) == 0 {
return "127.0.0.1", nil
}
for _, ip := range ips {
if ip.To4() != nil {
continue // not an ipv6 address
}
if ip.To16() == nil {
continue
}
return ip.String(), nil
}
return "127.0.0.1", nil
}
// ExternalIP returns the first IPv4/IPv6 available.
func ExternalIP() (string, error) {
ips, err := retrieveIPAddrs()
if err != nil {
return "", err
}
if len(ips) == 0 {
return "127.0.0.1", nil
}
return ips[0].String(), nil
}
// retrieveIP returns all the valid IPs available.
func retrieveIPAddrs() ([]net.IP, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
ipAddrs := []net.IP{}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
@@ -20,7 +74,7 @@ func ExternalIPv4() (string, error) {
}
addrs, err := iface.Addrs()
if err != nil {
return "", err
return nil, err
}
for _, addr := range addrs {
var ip net.IP
@@ -33,12 +87,8 @@ func ExternalIPv4() (string, error) {
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
return ip.String(), nil
ipAddrs = append(ipAddrs, ip)
}
}
return "127.0.0.1", nil
return ipAddrs, nil
}

View File

@@ -1,6 +1,7 @@
package iputils_test
import (
"net"
"regexp"
"testing"
@@ -18,3 +19,14 @@ func TestExternalIPv4(t *testing.T) {
valid := regexp.MustCompile(IPv4Format)
assert.Equal(t, true, valid.MatchString(test))
}
func TestRetrieveIP(t *testing.T) {
ip, err := iputils.ExternalIP()
if err != nil {
t.Fatal(err)
}
retIP := net.ParseIP(ip)
if retIP.To4() == nil && retIP.To16() == nil {
t.Errorf("An invalid IP was retrieved: %s", ip)
}
}