Skip to content
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
4 changes: 2 additions & 2 deletions cmd/shisui/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestGenConfig(t *testing.T) {
flagSet.String("rpc.port", "8888", "test")
flagSet.String("data.dir", "./test", "test")
flagSet.Uint64("data.capacity", size, "test")
flagSet.String("udp.addr", "172.23.50.11", "test")
// flagSet.String("udp.addr", "172.23.50.11", "test")
flagSet.Int("udp.port", 9999, "test")
flagSet.Int("loglevel", 3, "test")
val := cli.NewStringSlice("history")
Expand All @@ -32,7 +32,7 @@ func TestGenConfig(t *testing.T) {
require.Equal(t, config.DataCapacity, size)
require.Equal(t, config.DataDir, "./test")
require.Equal(t, config.LogLevel, 3)
require.Equal(t, config.RpcAddr, "127.0.0.11:8888")
// require.Equal(t, config.RpcAddr, "127.0.0.11:8888")
require.Equal(t, config.Protocol.ListenAddr, ":9999")
require.Equal(t, config.Networks, []string{"history"})
}
40 changes: 18 additions & 22 deletions cmd/shisui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/discover/portalwire"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/portalnetwork/beacon"
"github.com/ethereum/go-ethereum/portalnetwork/history"
"github.com/ethereum/go-ethereum/portalnetwork/storage"
Expand All @@ -44,7 +45,7 @@ var app = flags.NewApp("the go-portal-network command line interface")

var (
portalProtocolFlags = []cli.Flag{
utils.PortalUDPListenAddrFlag,
utils.PortalNATFlag,
utils.PortalUDPPortFlag,
utils.PortalBootNodesFlag,
utils.PortalPrivateKeyFlag,
Expand Down Expand Up @@ -158,22 +159,18 @@ func initDiscV5(config Config, conn discover.UDPConn) (*discover.UDPv5, *enode.L
localNode.Set(discover.Tag)

var addrs []net.Addr
if config.Protocol.NodeIP != nil {
localNode.SetStaticIP(config.Protocol.NodeIP)
} else {
addrs, err = net.InterfaceAddrs()
addrs, err = net.InterfaceAddrs()

if err != nil {
return nil, nil, err
}
if err != nil {
return nil, nil, err
}

for _, address := range addrs {
// check ip addr is loopback addr
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
localNode.SetStaticIP(ipnet.IP)
break
}
for _, address := range addrs {
// check ip addr is loopback addr
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
localNode.SetStaticIP(ipnet.IP)
break
}
}
}
Expand Down Expand Up @@ -280,14 +277,13 @@ func getPortalConfig(ctx *cli.Context) (*Config, error) {
config.Protocol.ListenAddr = port
}

udpAddr := ctx.String(utils.PortalUDPListenAddrFlag.Name)
if udpAddr != "" {
ip := udpAddr
netIp := net.ParseIP(ip)
if netIp == nil {
return config, fmt.Errorf("invalid ip addr: %s", ip)
natString := ctx.String(utils.PortalNATFlag.Name)
if natString != "" {
natInterface, err := nat.Parse(natString)
if err != nil {
return config, err
}
config.Protocol.NodeIP = netIp
config.Protocol.NAT = natInterface
}

bootNodes := ctx.StringSlice(utils.PortalBootNodesFlag.Name)
Expand Down
7 changes: 7 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,13 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Category: flags.PortalNetworkCategory,
}

PortalNATFlag = &cli.StringFlag{
Name: "nat",
Usage: "NAT port mapping mechanism (any|none|upnp|pmp|pmp:<IP>|extip:<IP>)",
Value: "none",
Category: flags.PortalNetworkCategory,
}

PortalUDPListenAddrFlag = &cli.StringFlag{
Name: "udp.addr",
Usage: "protocol UDP server listening interface",
Expand Down
2 changes: 1 addition & 1 deletion node/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const (
DefaultAuthHost = "localhost" // Default host interface for the authenticated apis
DefaultAuthPort = 8551 // Default port for the authenticated apis
DefaultUDPPort = 9009 // Default UDP port for the p2p network
DefaultLoglevel = 1 // Default loglevel for portal network, which is error level
DefaultLoglevel = 3 // Default loglevel for portal network, which is error level
)

const (
Expand Down
166 changes: 166 additions & 0 deletions p2p/discover/nat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package discover

import (
"net"
"time"

"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/p2p/nat"
)

const (
portMapDuration = 10 * time.Minute
portMapRefreshInterval = 8 * time.Minute
portMapRetryInterval = 5 * time.Minute
extipRetryInterval = 2 * time.Minute
)

type portMapping struct {
protocol string
name string
port int

// for use by the portMappingLoop goroutine:
extPort int // the mapped port returned by the NAT interface
nextTime mclock.AbsTime
}

// setupPortMapping starts the port mapping loop if necessary.
// Note: this needs to be called after the LocalNode instance has been set on the server.
func (p *PortalProtocol) setupPortMapping() {
// portMappingRegister will receive up to two values: one for the TCP port if
// listening is enabled, and one more for enabling UDP port mapping if discovery is
// enabled. We make it buffered to avoid blocking setup while a mapping request is in
// progress.
p.portMappingRegister = make(chan *portMapping, 2)

switch p.NAT.(type) {
case nil:
// No NAT interface configured.
go p.consumePortMappingRequests()

case nat.ExtIP:
// ExtIP doesn't block, set the IP right away.
ip, _ := p.NAT.ExternalIP()
p.localNode.SetStaticIP(ip)
go p.consumePortMappingRequests()

default:
go p.portMappingLoop()
}
}

func (p *PortalProtocol) consumePortMappingRequests() {
for {
select {
case <-p.closeCtx.Done():
return
case <-p.portMappingRegister:
}
}
}

// portMappingLoop manages port mappings for UDP and TCP.
func (p *PortalProtocol) portMappingLoop() {
newLogger := func(proto string, e int, i int) log.Logger {
return log.New("proto", proto, "extport", e, "intport", i, "interface", p.NAT)
}

var (
mappings = make(map[string]*portMapping, 2)
refresh = mclock.NewAlarm(p.clock)
extip = mclock.NewAlarm(p.clock)
lastExtIP net.IP
)
extip.Schedule(p.clock.Now())
defer func() {
refresh.Stop()
extip.Stop()
for _, m := range mappings {
if m.extPort != 0 {
log := newLogger(m.protocol, m.extPort, m.port)
log.Debug("Deleting port mapping")
p.NAT.DeleteMapping(m.protocol, m.extPort, m.port)
}
}
}()

for {
// Schedule refresh of existing mappings.
for _, m := range mappings {
refresh.Schedule(m.nextTime)
}

select {
case <-p.closeCtx.Done():
return

case <-extip.C():
extip.Schedule(p.clock.Now().Add(extipRetryInterval))
ip, err := p.NAT.ExternalIP()
if err != nil {
log.Debug("Couldn't get external IP", "err", err, "interface", p.NAT)
} else if !ip.Equal(lastExtIP) {
log.Debug("External IP changed", "ip", extip, "interface", p.NAT)
} else {
continue
}
// Here, we either failed to get the external IP, or it has changed.
lastExtIP = ip
p.localNode.SetStaticIP(ip)
p.Log.Debug("set static ip in nat", "ip", p.localNode.Node().IP().String())
// Ensure port mappings are refreshed in case we have moved to a new network.
for _, m := range mappings {
m.nextTime = p.clock.Now()
}

case m := <-p.portMappingRegister:
if m.protocol != "TCP" && m.protocol != "UDP" {
panic("unknown NAT protocol name: " + m.protocol)
}
mappings[m.protocol] = m
m.nextTime = p.clock.Now()

case <-refresh.C():
for _, m := range mappings {
if p.clock.Now() < m.nextTime {
continue
}

external := m.port
if m.extPort != 0 {
external = m.extPort
}
log := newLogger(m.protocol, external, m.port)

log.Trace("Attempting port mapping")
port, err := p.NAT.AddMapping(m.protocol, external, m.port, m.name, portMapDuration)
if err != nil {
log.Debug("Couldn't add port mapping", "err", err)
m.extPort = 0
m.nextTime = p.clock.Now().Add(portMapRetryInterval)
continue
}
// It was mapped!
m.extPort = int(port)
m.nextTime = p.clock.Now().Add(portMapRefreshInterval)
if external != m.extPort {
log = newLogger(m.protocol, m.extPort, m.port)
log.Info("NAT mapped alternative port")
} else {
log.Info("NAT mapped port")
}

// Update port in local ENR.
switch m.protocol {
case "TCP":
p.localNode.Set(enr.TCP(m.extPort))
case "UDP":
p.localNode.SetFallbackUDP(m.extPort)
}
}
}
}
}
32 changes: 23 additions & 9 deletions p2p/discover/portal_protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import (
"time"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/p2p/discover/v5wire"

"github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover/portalwire"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/portalnetwork/storage"
"github.com/ethereum/go-ethereum/rlp"
Expand Down Expand Up @@ -138,13 +140,15 @@ type traceContentInfoResp struct {
type PortalProtocolOption func(p *PortalProtocol)

type PortalProtocolConfig struct {
BootstrapNodes []*enode.Node
NodeIP net.IP
BootstrapNodes []*enode.Node
// NodeIP net.IP
ListenAddr string
NetRestrict *netutil.Netlist
NodeRadius *uint256.Int
RadiusCacheSize int
NodeDBPath string
NAT nat.Interface
clock mclock.Clock
}

func DefaultPortalProtocolConfig() *PortalProtocolConfig {
Expand All @@ -156,6 +160,8 @@ func DefaultPortalProtocolConfig() *PortalProtocolConfig {
NodeRadius: nodeRadius,
RadiusCacheSize: 32 * 1024 * 1024,
NodeDBPath: "",
// NAT: nat.Any(),
clock: mclock.System{},
}
}

Expand Down Expand Up @@ -190,6 +196,10 @@ type PortalProtocol struct {

contentQueue chan *ContentElement
offerQueue chan *OfferRequestWithNode

portMappingRegister chan *portMapping
clock mclock.Clock
NAT nat.Interface
}

func defaultContentIdFunc(contentKey []byte) []byte {
Expand Down Expand Up @@ -222,6 +232,8 @@ func NewPortalProtocol(config *PortalProtocolConfig, protocolId string, privateK
offerQueue: make(chan *OfferRequestWithNode, concurrentOffers),
conn: conn,
DiscV5: discV5,
NAT: config.NAT,
clock: config.clock,
}

for _, opt := range opts {
Expand All @@ -232,6 +244,8 @@ func NewPortalProtocol(config *PortalProtocolConfig, protocolId string, privateK
}

func (p *PortalProtocol) Start() error {
p.setupPortMapping()

err := p.setupDiscV5AndTable()
if err != nil {
return err
Expand Down Expand Up @@ -286,13 +300,13 @@ func (p *PortalProtocol) setupUDPListening() error {
p.localNode.SetFallbackUDP(laddr.Port)
p.Log.Debug("UDP listener up", "addr", laddr)
// TODO: NAT
//if !laddr.IP.IsLoopback() && !laddr.IP.IsPrivate() {
// srv.portMappingRegister <- &portMapping{
// protocol: "UDP",
// name: "ethereum peer discovery",
// port: laddr.Port,
// }
//}
if !laddr.IP.IsLoopback() && !laddr.IP.IsPrivate() {
p.portMappingRegister <- &portMapping{
protocol: "UDP",
name: "ethereum portal peer discovery",
port: laddr.Port,
}
}

var err error
p.packetRouter = utp.NewPacketRouter(
Expand Down
Loading