mirror of
https://github.com/logos-messaging/logos-messaging-go.git
synced 2026-01-03 22:43:09 +00:00
fix: discv5 ip advertising (#223)
This commit is contained in:
parent
36d4be451a
commit
a20a128fb7
2
go.mod
2
go.mod
@ -11,7 +11,7 @@ require (
|
||||
github.com/ethereum/go-ethereum v1.10.16
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/rpc v1.2.0
|
||||
github.com/ipfs/go-ds-sql v0.3.0
|
||||
github.com/ipfs/go-log v1.0.5
|
||||
|
||||
@ -66,7 +66,7 @@ type WakuConfig struct {
|
||||
NodeKey *string `json:"nodeKey,omitempty"`
|
||||
KeepAliveInterval *int `json:"keepAliveInterval,omitempty"`
|
||||
EnableRelay *bool `json:"relay"`
|
||||
MinPeersToPublish *int `json:"minPeersToPublish`
|
||||
MinPeersToPublish *int `json:"minPeersToPublish"`
|
||||
}
|
||||
|
||||
var DefaultHost = "0.0.0.0"
|
||||
|
||||
@ -5,10 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var errToCodeMap = map[error]int{
|
||||
//transactions.ErrInvalidTxSender: codeErrInvalidTxSender,
|
||||
}
|
||||
|
||||
type JSONResponse struct {
|
||||
Error *string `json:"error,omitempty"`
|
||||
Result interface{} `json:"result"`
|
||||
|
||||
@ -3,10 +3,12 @@ package discv5
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -16,6 +18,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/discovery"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
"github.com/status-im/go-discover/discover"
|
||||
"github.com/status-im/go-waku/waku/v2/utils"
|
||||
"go.uber.org/zap"
|
||||
@ -57,7 +60,6 @@ type discV5Parameters struct {
|
||||
autoUpdate bool
|
||||
bootnodes []*enode.Node
|
||||
udpPort int
|
||||
tcpPort int
|
||||
advertiseAddr *net.IP
|
||||
}
|
||||
|
||||
@ -93,7 +95,7 @@ func DefaultOptions() []DiscoveryV5Option {
|
||||
}
|
||||
}
|
||||
|
||||
func NewDiscoveryV5(host host.Host, ipAddr net.IP, tcpPort int, priv *ecdsa.PrivateKey, wakuFlags utils.WakuEnrBitfield, log *zap.SugaredLogger, opts ...DiscoveryV5Option) (*DiscoveryV5, error) {
|
||||
func NewDiscoveryV5(host host.Host, addresses []ma.Multiaddr, priv *ecdsa.PrivateKey, wakuFlags utils.WakuEnrBitfield, log *zap.SugaredLogger, opts ...DiscoveryV5Option) (*DiscoveryV5, error) {
|
||||
params := new(discV5Parameters)
|
||||
optList := DefaultOptions()
|
||||
optList = append(optList, opts...)
|
||||
@ -103,9 +105,12 @@ func NewDiscoveryV5(host host.Host, ipAddr net.IP, tcpPort int, priv *ecdsa.Priv
|
||||
|
||||
logger := log.Named("discv5")
|
||||
|
||||
params.tcpPort = tcpPort
|
||||
ipAddr, err := selectIPAddr(addresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localnode, err := newLocalnode(priv, ipAddr, params.udpPort, tcpPort, wakuFlags, params.advertiseAddr, logger)
|
||||
localnode, err := newLocalnode(priv, ipAddr, params.udpPort, wakuFlags, params.advertiseAddr, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -144,16 +149,16 @@ func NewDiscoveryV5(host host.Host, ipAddr net.IP, tcpPort int, priv *ecdsa.Priv
|
||||
}, nil
|
||||
}
|
||||
|
||||
func newLocalnode(priv *ecdsa.PrivateKey, ipAddr net.IP, udpPort int, tcpPort int, wakuFlags utils.WakuEnrBitfield, advertiseAddr *net.IP, log *zap.SugaredLogger) (*enode.LocalNode, error) {
|
||||
func newLocalnode(priv *ecdsa.PrivateKey, ipAddr *net.TCPAddr, udpPort int, wakuFlags utils.WakuEnrBitfield, advertiseAddr *net.IP, log *zap.SugaredLogger) (*enode.LocalNode, error) {
|
||||
db, err := enode.OpenDB("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localnode := enode.NewLocalNode(db, priv)
|
||||
localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
|
||||
localnode.SetFallbackUDP(udpPort)
|
||||
localnode.Set(enr.WithEntry(utils.WakuENRField, wakuFlags))
|
||||
localnode.Set(enr.IP(ipAddr))
|
||||
localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
|
||||
localnode.SetStaticIP(ipAddr.IP)
|
||||
|
||||
if udpPort > 0 && udpPort <= math.MaxUint16 {
|
||||
localnode.Set(enr.UDP(uint16(udpPort))) // lgtm [go/incorrect-integer-conversion]
|
||||
@ -161,10 +166,10 @@ func newLocalnode(priv *ecdsa.PrivateKey, ipAddr net.IP, udpPort int, tcpPort in
|
||||
log.Error("could not set udpPort ", udpPort)
|
||||
}
|
||||
|
||||
if tcpPort > 0 && tcpPort <= math.MaxUint16 {
|
||||
localnode.Set(enr.TCP(uint16(tcpPort))) // lgtm [go/incorrect-integer-conversion]
|
||||
if ipAddr.Port > 0 && ipAddr.Port <= math.MaxUint16 {
|
||||
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // lgtm [go/incorrect-integer-conversion]
|
||||
} else {
|
||||
log.Error("could not set tcpPort ", tcpPort)
|
||||
log.Error("could not set tcpPort ", ipAddr.Port)
|
||||
}
|
||||
|
||||
if advertiseAddr != nil {
|
||||
@ -200,7 +205,7 @@ func (d *DiscoveryV5) listen() error {
|
||||
|
||||
d.listener = listener
|
||||
|
||||
d.log.Info(fmt.Sprintf("Started Discovery V5 at %s:%d, advertising IP: %s:%d", d.udpAddr.IP, d.udpAddr.Port, d.localnode.Node().IP(), d.params.tcpPort))
|
||||
d.log.Info(fmt.Sprintf("Started Discovery V5 at %s:%d, advertising IP: %s:%d", d.udpAddr.IP, d.udpAddr.Port, d.localnode.Node().IP(), d.localnode.Node().TCP()))
|
||||
d.log.Info("Discovery V5 ", d.localnode.Node())
|
||||
|
||||
return nil
|
||||
@ -236,30 +241,6 @@ func (d *DiscoveryV5) Stop() {
|
||||
d.wg.Wait()
|
||||
}
|
||||
|
||||
// IsPrivate reports whether ip is a private address, according to
|
||||
// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).
|
||||
// Copied/Adapted from https://go-review.googlesource.com/c/go/+/272668/11/src/net/ip.go
|
||||
// Copyright (c) The Go Authors. All rights reserved.
|
||||
// @TODO: once Go 1.17 is released in Q42021, remove this function as it will become part of the language
|
||||
func IsPrivate(ip net.IP) bool {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
// Following RFC 4193, Section 3. Local IPv6 Unicast Addresses which says:
|
||||
// The Internet Assigned Numbers Authority (IANA) has reserved the
|
||||
// following three blocks of the IPv4 address space for private internets:
|
||||
// 10.0.0.0 - 10.255.255.255 (10/8 prefix)
|
||||
// 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
|
||||
// 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
|
||||
return ip4[0] == 10 ||
|
||||
(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
|
||||
(ip4[0] == 192 && ip4[1] == 168)
|
||||
}
|
||||
// Following RFC 4193, Section 3. Private Address Space which says:
|
||||
// The Internet Assigned Numbers Authority (IANA) has reserved the
|
||||
// following block of the IPv6 address space for local internets:
|
||||
// FC00:: - FDFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF (FC00::/7 prefix)
|
||||
return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc
|
||||
}
|
||||
|
||||
func (d *DiscoveryV5) UpdateAddr(addr net.IP) error {
|
||||
if !d.params.autoUpdate {
|
||||
return nil
|
||||
@ -273,12 +254,12 @@ func (d *DiscoveryV5) UpdateAddr(addr net.IP) error {
|
||||
}
|
||||
|
||||
// TODO: improve this logic to determine if an address should be replaced or not
|
||||
if !(d.localnode.Node().IP().IsLoopback() && IsPrivate(addr)) && !(IsPrivate(d.localnode.Node().IP()) && !addr.IsLoopback() && !IsPrivate(addr)) {
|
||||
if !((d.localnode.Node().IP().IsLoopback() && isPrivate(&net.TCPAddr{IP: addr})) ||
|
||||
(isPrivate(&net.TCPAddr{IP: d.localnode.Node().IP()}) && isExternal(&net.TCPAddr{IP: addr}))) {
|
||||
return nil
|
||||
}
|
||||
|
||||
d.localnode.Set(enr.IP(addr))
|
||||
|
||||
d.localnode.SetStaticIP(addr)
|
||||
d.log.Info(fmt.Sprintf("Updated Discovery V5 node IP: %s", d.localnode.Node().IP()))
|
||||
d.log.Info("Discovery V5 ", d.localnode.Node())
|
||||
|
||||
@ -479,3 +460,82 @@ func (d *DiscoveryV5) FindPeers(ctx context.Context, topic string, opts ...disco
|
||||
|
||||
return chPeer, err
|
||||
}
|
||||
|
||||
// IsPrivate reports whether ip is a private address, according to
|
||||
// RFC 1918 (IPv4 addresses) and RFC 4193 (IPv6 addresses).
|
||||
// Copied/Adapted from https://go-review.googlesource.com/c/go/+/272668/11/src/net/ip.go
|
||||
// Copyright (c) The Go Authors. All rights reserved.
|
||||
// @TODO: once Go 1.17 is released in Q42021, remove this function as it will become part of the language
|
||||
func isPrivate(ip *net.TCPAddr) bool {
|
||||
if ip4 := ip.IP.To4(); ip4 != nil {
|
||||
// Following RFC 4193, Section 3. Local IPv6 Unicast Addresses which says:
|
||||
// The Internet Assigned Numbers Authority (IANA) has reserved the
|
||||
// following three blocks of the IPv4 address space for private internets:
|
||||
// 10.0.0.0 - 10.255.255.255 (10/8 prefix)
|
||||
// 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
|
||||
// 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
|
||||
return ip4[0] == 10 ||
|
||||
(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
|
||||
(ip4[0] == 192 && ip4[1] == 168)
|
||||
}
|
||||
// Following RFC 4193, Section 3. Private Address Space which says:
|
||||
// The Internet Assigned Numbers Authority (IANA) has reserved the
|
||||
// following block of the IPv6 address space for local internets:
|
||||
// FC00:: - FDFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF (FC00::/7 prefix)
|
||||
return len(ip.IP) == net.IPv6len && ip.IP[0]&0xfe == 0xfc
|
||||
}
|
||||
|
||||
func isExternal(ip *net.TCPAddr) bool {
|
||||
return !isPrivate(ip) && !ip.IP.IsLoopback() && !ip.IP.IsUnspecified()
|
||||
}
|
||||
|
||||
func isLoopback(ip *net.TCPAddr) bool {
|
||||
return ip.IP.IsLoopback()
|
||||
}
|
||||
func filter(ss []*net.TCPAddr, fn func(*net.TCPAddr) bool) (ret []*net.TCPAddr) {
|
||||
for _, s := range ss {
|
||||
if fn(s) {
|
||||
ret = append(ret, s)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func selectIPAddr(addresses []ma.Multiaddr) (*net.TCPAddr, error) {
|
||||
var ipAddrs []*net.TCPAddr
|
||||
for _, addr := range addresses {
|
||||
ipStr, err := addr.ValueForProtocol(ma.P_IP4)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
portStr, err := addr.ValueForProtocol(ma.P_TCP)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ipAddrs = append(ipAddrs, &net.TCPAddr{
|
||||
IP: net.ParseIP(ipStr),
|
||||
Port: port,
|
||||
})
|
||||
}
|
||||
|
||||
externalIPs := filter(ipAddrs, isExternal)
|
||||
if len(externalIPs) > 0 {
|
||||
return externalIPs[0], nil
|
||||
}
|
||||
|
||||
privateIPs := filter(ipAddrs, isPrivate)
|
||||
if len(privateIPs) > 0 {
|
||||
return privateIPs[0], nil
|
||||
}
|
||||
|
||||
loopback := filter(ipAddrs, isLoopback)
|
||||
if len(loopback) > 0 {
|
||||
return loopback[0], nil
|
||||
}
|
||||
|
||||
return nil, errors.New("could not obtain ip address")
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -45,22 +44,22 @@ func createHost(t *testing.T) (host.Host, int, *ecdsa.PrivateKey) {
|
||||
func TestDiscV5(t *testing.T) {
|
||||
// Host1 <-> Host2 <-> Host3
|
||||
|
||||
host1, tcpPort1, prvKey1 := createHost(t)
|
||||
host1, _, prvKey1 := createHost(t)
|
||||
udpPort1, err := tests.FindFreePort(t, "127.0.0.1", 3)
|
||||
require.NoError(t, err)
|
||||
d1, err := NewDiscoveryV5(host1, net.IPv4(127, 0, 0, 1), tcpPort1, prvKey1, utils.NewWakuEnrBitfield(true, true, true, true), tests.Logger(), WithUDPPort(udpPort1))
|
||||
d1, err := NewDiscoveryV5(host1, host1.Addrs(), prvKey1, utils.NewWakuEnrBitfield(true, true, true, true), tests.Logger(), WithUDPPort(udpPort1))
|
||||
require.NoError(t, err)
|
||||
|
||||
host2, tcpPort2, prvKey2 := createHost(t)
|
||||
host2, _, prvKey2 := createHost(t)
|
||||
udpPort2, err := tests.FindFreePort(t, "127.0.0.1", 3)
|
||||
require.NoError(t, err)
|
||||
d2, err := NewDiscoveryV5(host2, net.IPv4(127, 0, 0, 1), tcpPort2, prvKey2, utils.NewWakuEnrBitfield(true, true, true, true), tests.Logger(), WithUDPPort(udpPort2), WithBootnodes([]*enode.Node{d1.localnode.Node()}))
|
||||
d2, err := NewDiscoveryV5(host2, host2.Addrs(), prvKey2, utils.NewWakuEnrBitfield(true, true, true, true), tests.Logger(), WithUDPPort(udpPort2), WithBootnodes([]*enode.Node{d1.localnode.Node()}))
|
||||
require.NoError(t, err)
|
||||
|
||||
host3, tcpPort3, prvKey3 := createHost(t)
|
||||
host3, _, prvKey3 := createHost(t)
|
||||
udpPort3, err := tests.FindFreePort(t, "127.0.0.1", 3)
|
||||
require.NoError(t, err)
|
||||
d3, err := NewDiscoveryV5(host3, net.IPv4(127, 0, 0, 1), tcpPort3, prvKey3, utils.NewWakuEnrBitfield(true, true, true, true), tests.Logger(), WithUDPPort(udpPort3), WithBootnodes([]*enode.Node{d2.localnode.Node()}))
|
||||
d3, err := NewDiscoveryV5(host3, host3.Addrs(), prvKey3, utils.NewWakuEnrBitfield(true, true, true, true), tests.Logger(), WithUDPPort(udpPort3), WithBootnodes([]*enode.Node{d2.localnode.Node()}))
|
||||
require.NoError(t, err)
|
||||
|
||||
defer d1.Stop()
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -197,6 +196,7 @@ func (w *WakuNode) onAddrChange() {
|
||||
continue
|
||||
}
|
||||
ip := net.ParseIP(ipStr)
|
||||
|
||||
if !ip.IsLoopback() && !ip.IsUnspecified() {
|
||||
if w.opts.enableDiscV5 {
|
||||
err := w.discoveryV5.UpdateAddr(ip)
|
||||
@ -458,24 +458,8 @@ func (w *WakuNode) mountDiscV5() error {
|
||||
discV5Options = append(discV5Options, discv5.WithAdvertiseAddr(*w.opts.advertiseAddr))
|
||||
}
|
||||
|
||||
addr := w.ListenAddresses()[0]
|
||||
|
||||
ipStr, err := addr.ValueForProtocol(ma.P_IP4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
portStr, err := addr.ValueForProtocol(ma.P_TCP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w.discoveryV5, err = discv5.NewDiscoveryV5(w.Host(), net.ParseIP(ipStr), port, w.opts.privKey, w.wakuFlag, w.log, discV5Options...)
|
||||
var err error
|
||||
w.discoveryV5, err = discv5.NewDiscoveryV5(w.Host(), w.ListenAddresses(), w.opts.privKey, w.wakuFlag, w.log, discV5Options...)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user