Skip to content

Commit

Permalink
feat: nat
Browse files Browse the repository at this point in the history
  • Loading branch information
fearlessfe authored and GrapeBaBa committed Jun 5, 2024
1 parent 04c5048 commit 1ed713a
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 89 deletions.
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 @@ -20,13 +20,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 @@ -139,13 +141,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 @@ -157,6 +161,8 @@ func DefaultPortalProtocolConfig() *PortalProtocolConfig {
NodeRadius: nodeRadius,
RadiusCacheSize: 32 * 1024 * 1024,
NodeDBPath: "",
// NAT: nat.Any(),
clock: mclock.System{},
}
}

Expand Down Expand Up @@ -191,6 +197,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 @@ -223,6 +233,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 @@ -233,6 +245,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 @@ -287,13 +301,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

0 comments on commit 1ed713a

Please sign in to comment.