p2p: external address

* new config option for external address to advertise
* if blank, defaults to best guess from listener
* if laddr ip address is also blank, default to IPv4
This commit is contained in:
Ethan Buchman 2018-07-01 22:21:29 -04:00
parent 60f233a4bc
commit 1c018d3fd2
7 changed files with 49 additions and 16 deletions

View File

@ -22,6 +22,8 @@ FEATURES
[metrics](https://tendermint.readthedocs.io/projects/tools/en/develop/metrics.html) [metrics](https://tendermint.readthedocs.io/projects/tools/en/develop/metrics.html)
guide. guide.
- [p2p] Add IPv6 support to peering. - [p2p] Add IPv6 support to peering.
- [p2p] Add `external_address` to config to allow specifying the address for
peers to dial
IMPROVEMENT IMPROVEMENT
- [rpc/client] Supports https and wss now. - [rpc/client] Supports https and wss now.

View File

@ -276,6 +276,9 @@ type P2PConfig struct {
// Address to listen for incoming connections // Address to listen for incoming connections
ListenAddress string `mapstructure:"laddr"` ListenAddress string `mapstructure:"laddr"`
// Address to advertise to peers for them to dial
ExternalAddress string `mapstructure:"external_address"`
// Comma separated list of seed nodes to connect to // Comma separated list of seed nodes to connect to
// We only use these if we cant connect to peers in the addrbook // We only use these if we cant connect to peers in the addrbook
Seeds string `mapstructure:"seeds"` Seeds string `mapstructure:"seeds"`
@ -340,6 +343,7 @@ type P2PConfig struct {
func DefaultP2PConfig() *P2PConfig { func DefaultP2PConfig() *P2PConfig {
return &P2PConfig{ return &P2PConfig{
ListenAddress: "tcp://0.0.0.0:26656", ListenAddress: "tcp://0.0.0.0:26656",
ExternalAddress: "",
UPNP: false, UPNP: false,
AddrBook: defaultAddrBookPath, AddrBook: defaultAddrBookPath,
AddrBookStrict: true, AddrBookStrict: true,

View File

@ -142,6 +142,12 @@ max_open_connections = {{ .RPC.MaxOpenConnections }}
# Address to listen for incoming connections # Address to listen for incoming connections
laddr = "{{ .P2P.ListenAddress }}" laddr = "{{ .P2P.ListenAddress }}"
# Address to advertise to peers for them to dial
# If empty, will use the same port as the laddr,
# and will introspect on the listener or use UPnP
# to figure out the address.
external_address = "{{ .P2P.ExternalAddress }}"
# Comma separated list of seed nodes to connect to # Comma separated list of seed nodes to connect to
seeds = "{{ .P2P.Seeds }}" seeds = "{{ .P2P.Seeds }}"

View File

@ -426,8 +426,7 @@ func (n *Node) OnStart() error {
} }
// Create & add listener // Create & add listener
protocol, address := cmn.ProtocolAndAddress(n.config.P2P.ListenAddress) l := p2p.NewDefaultListener(n.config.P2P, n.Logger.With("module", "p2p"))
l := p2p.NewDefaultListener(protocol, address, n.config.P2P.UPNP, n.Logger.With("module", "p2p"))
n.sw.AddListener(l) n.sw.AddListener(l)
// Generate node PrivKey // Generate node PrivKey

View File

@ -7,9 +7,10 @@ import (
"strings" "strings"
"time" "time"
"github.com/tendermint/tendermint/p2p/upnp" "github.com/tendermint/tendermint/config"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/p2p/upnp"
) )
// Listener is a network listener for stream-oriented protocols, providing // Listener is a network listener for stream-oriented protocols, providing
@ -59,8 +60,10 @@ func splitHostPort(addr string) (host string, port int) {
// NewDefaultListener creates a new DefaultListener on lAddr, optionally trying // NewDefaultListener creates a new DefaultListener on lAddr, optionally trying
// to determine external address using UPnP. // to determine external address using UPnP.
func NewDefaultListener(protocol string, lAddr string, UPNP bool, logger log.Logger) Listener { func NewDefaultListener(cfg *config.P2PConfig, logger log.Logger) Listener {
// Local listen IP & port
// Split protocol, address, and port.
protocol, lAddr := cmn.ProtocolAndAddress(cfg.ListenAddress)
lAddrIP, lAddrPort := splitHostPort(lAddr) lAddrIP, lAddrPort := splitHostPort(lAddr)
// Create listener // Create listener
@ -88,17 +91,29 @@ func NewDefaultListener(protocol string, lAddr string, UPNP bool, logger log.Log
panic(err) panic(err)
} }
inAddrAny := lAddrIP == "" || lAddrIP == "0.0.0.0"
// Determine external address... // Determine external address...
var extAddr *NetAddress var extAddr *NetAddress
if UPNP { if cfg.UPNP {
// If the lAddrIP is INADDR_ANY, try UPnP // If the lAddrIP is INADDR_ANY, try UPnP
if lAddrIP == "" || lAddrIP == "0.0.0.0" { if inAddrAny {
extAddr = getUPNPExternalAddress(lAddrPort, listenerPort, logger) extAddr = getUPNPExternalAddress(lAddrPort, listenerPort, logger)
} }
} }
if cfg.ExternalAddress != "" {
var err error
extAddr, err = NewNetAddressStringWithOptionalID(cfg.ExternalAddress)
if err != nil {
panic(fmt.Sprintf("Error in ExternalAddress: %v", err))
}
}
// Otherwise just use the local address... // Otherwise just use the local address...
if extAddr == nil { if extAddr == nil {
extAddr = getNaiveExternalAddress(listenerPort, false, logger) defaultToIPv4 := inAddrAny
extAddr = getNaiveExternalAddress(defaultToIPv4, listenerPort, false, logger)
} }
if extAddr == nil { if extAddr == nil {
panic("Could not determine external address!") panic("Could not determine external address!")
@ -237,7 +252,7 @@ func isIpv6(ip net.IP) bool {
} }
// TODO: use syscalls: see issue #712 // TODO: use syscalls: see issue #712
func getNaiveExternalAddress(port int, settleForLocal bool, logger log.Logger) *NetAddress { func getNaiveExternalAddress(defaultToIPv4 bool, port int, settleForLocal bool, logger log.Logger) *NetAddress {
addrs, err := net.InterfaceAddrs() addrs, err := net.InterfaceAddrs()
if err != nil { if err != nil {
panic(cmn.Fmt("Could not fetch interface addresses: %v", err)) panic(cmn.Fmt("Could not fetch interface addresses: %v", err))
@ -248,7 +263,7 @@ func getNaiveExternalAddress(port int, settleForLocal bool, logger log.Logger) *
if !ok { if !ok {
continue continue
} }
if !isIpv6(ipnet.IP) { if defaultToIPv4 || !isIpv6(ipnet.IP) {
v4 := ipnet.IP.To4() v4 := ipnet.IP.To4()
if v4 == nil || (!settleForLocal && v4[0] == 127) { if v4 == nil || (!settleForLocal && v4[0] == 127) {
// loopback // loopback
@ -263,5 +278,5 @@ func getNaiveExternalAddress(port int, settleForLocal bool, logger log.Logger) *
// try again, but settle for local // try again, but settle for local
logger.Info("Node may not be connected to internet. Settling for local address") logger.Info("Node may not be connected to internet. Settling for local address")
return getNaiveExternalAddress(port, true, logger) return getNaiveExternalAddress(defaultToIPv4, port, true, logger)
} }

View File

@ -4,12 +4,16 @@ import (
"bytes" "bytes"
"testing" "testing"
"github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
) )
func TestListener(t *testing.T) { func TestListener(t *testing.T) {
// Create a listener // Create a listener
l := NewDefaultListener("tcp", ":8001", false, log.TestingLogger()) cfg := &config.P2PConfig{
ListenAddress: "tcp://:8001",
}
l := NewDefaultListener(cfg, log.TestingLogger())
// Dial the listener // Dial the listener
lAddr := l.ExternalAddress() lAddr := l.ExternalAddress()

View File

@ -109,7 +109,10 @@ func TestPEXReactorRunning(t *testing.T) {
addOtherNodeAddrToAddrBook(2, 1) addOtherNodeAddrToAddrBook(2, 1)
for i, sw := range switches { for i, sw := range switches {
sw.AddListener(p2p.NewDefaultListener("tcp", sw.NodeInfo().ListenAddr, false, logger.With("pex", i))) cfg := &config.P2PConfig{
ListenAddress: fmt.Sprintf("tcp://%v", sw.NodeInfo().ListenAddr),
}
sw.AddListener(p2p.NewDefaultListener(cfg, logger.With("pex", i)))
err := sw.Start() // start switch and reactors err := sw.Start() // start switch and reactors
require.Nil(t, err) require.Nil(t, err)
@ -230,9 +233,9 @@ func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
) )
seed.AddListener( seed.AddListener(
p2p.NewDefaultListener( p2p.NewDefaultListener(
"tcp", &config.P2PConfig{
seed.NodeInfo().ListenAddr, ListenAddress: fmt.Sprintf("tcp://%v", seed.NodeInfo().ListenAddr),
false, },
log.TestingLogger(), log.TestingLogger(),
), ),
) )