diff --git a/cmd/bootnode/main.go b/cmd/bootnode/main.go index fd96a7b48..dda9f34d4 100644 --- a/cmd/bootnode/main.go +++ b/cmd/bootnode/main.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/nat" ) func main() { @@ -38,8 +39,10 @@ func main() { genKey = flag.String("genkey", "", "generate a node key and quit") nodeKeyFile = flag.String("nodekey", "", "private key filename") nodeKeyHex = flag.String("nodekeyhex", "", "private key as hex (for testing)") - nodeKey *ecdsa.PrivateKey - err error + natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|extip:)") + + nodeKey *ecdsa.PrivateKey + err error ) flag.Parse() logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.DebugLevel)) @@ -49,6 +52,10 @@ func main() { os.Exit(0) } + natm, err := nat.Parse(*natdesc) + if err != nil { + log.Fatalf("-nat: %v", err) + } switch { case *nodeKeyFile == "" && *nodeKeyHex == "": log.Fatal("Use -nodekey or -nodekeyhex to specify a private key") @@ -64,7 +71,7 @@ func main() { } } - if _, err := discover.ListenUDP(nodeKey, *listenAddr); err != nil { + if _, err := discover.ListenUDP(nodeKey, *listenAddr, natm); err != nil { log.Fatal(err) } select {} diff --git a/p2p/discover/udp.go b/p2p/discover/udp.go index 1f91641f3..a9ed7fcb8 100644 --- a/p2p/discover/udp.go +++ b/p2p/discover/udp.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/rlp" ) @@ -82,6 +83,7 @@ type udp struct { addpending chan *pending replies chan reply closing chan struct{} + nat nat.Interface *Table } @@ -121,17 +123,26 @@ type reply struct { } // ListenUDP returns a new table that listens for UDP packets on laddr. -func ListenUDP(priv *ecdsa.PrivateKey, laddr string) (*Table, error) { - net, realaddr, err := listen(priv, laddr) +func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface) (*Table, error) { + t, realaddr, err := listen(priv, laddr, natm) if err != nil { return nil, err } - net.Table = newTable(net, PubkeyID(&priv.PublicKey), realaddr) - log.Debugf("Listening, %v\n", net.self) - return net.Table, nil + if natm != nil { + if !realaddr.IP.IsLoopback() { + go nat.Map(natm, t.closing, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") + } + // TODO: react to external IP changes over time. + if ext, err := natm.ExternalIP(); err == nil { + realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port} + } + } + t.Table = newTable(t, PubkeyID(&priv.PublicKey), realaddr) + log.Infoln("Listening, ", t.self) + return t.Table, nil } -func listen(priv *ecdsa.PrivateKey, laddr string) (*udp, *net.UDPAddr, error) { +func listen(priv *ecdsa.PrivateKey, laddr string, nat nat.Interface) (*udp, *net.UDPAddr, error) { addr, err := net.ResolveUDPAddr("udp", laddr) if err != nil { return nil, nil, err diff --git a/p2p/discover/udp_test.go b/p2p/discover/udp_test.go index 740d0a5d9..0a8ff6358 100644 --- a/p2p/discover/udp_test.go +++ b/p2p/discover/udp_test.go @@ -18,8 +18,8 @@ func init() { func TestUDP_ping(t *testing.T) { t.Parallel() - n1, _ := ListenUDP(newkey(), "127.0.0.1:0") - n2, _ := ListenUDP(newkey(), "127.0.0.1:0") + n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) + n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) defer n1.Close() defer n2.Close() @@ -48,8 +48,8 @@ func find(tab *Table, id NodeID) *Node { func TestUDP_findnode(t *testing.T) { t.Parallel() - n1, _ := ListenUDP(newkey(), "127.0.0.1:0") - n2, _ := ListenUDP(newkey(), "127.0.0.1:0") + n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) + n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) defer n1.Close() defer n2.Close() @@ -98,7 +98,7 @@ func TestUDP_replytimeout(t *testing.T) { } defer fd.Close() - n1, _ := ListenUDP(newkey(), "127.0.0.1:0") + n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) defer n1.Close() n2 := n1.bumpOrAdd(randomID(n1.self.ID, 10), fd.LocalAddr().(*net.UDPAddr)) @@ -116,8 +116,8 @@ func TestUDP_replytimeout(t *testing.T) { func TestUDP_findnodeMultiReply(t *testing.T) { t.Parallel() - n1, _ := ListenUDP(newkey(), "127.0.0.1:0") - n2, _ := ListenUDP(newkey(), "127.0.0.1:0") + n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) + n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil) udp2 := n2.net.(*udp) defer n1.Close() defer n2.Close() diff --git a/p2p/server.go b/p2p/server.go index a0f2dee23..e44f3d7ab 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -182,7 +182,7 @@ func (srv *Server) Start() (err error) { } // dial stuff - dt, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr) + dt, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT) if err != nil { return err } @@ -194,7 +194,6 @@ func (srv *Server) Start() (err error) { srv.loopWG.Add(1) go srv.dialLoop() } - if srv.NoDial && srv.ListenAddr == "" { srvlog.Warnln("I will be kind-of useless, neither dialing nor listening.") }