Skip to content

Commit

Permalink
multi: add automatic network address discovery.
Browse files Browse the repository at this point in the history
This discovers the network address of the daemon
through connected outbound peers. The address is
advertised to subsequent connecting peers if
automatic network address discovery is not disabled.
  • Loading branch information
dnldd committed Apr 16, 2019
1 parent e69a789 commit 44e7879
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 0 deletions.
11 changes: 11 additions & 0 deletions addrmgr/addrmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,17 @@ func (a *AddrManager) AddLocalAddress(na *wire.NetAddress, priority AddressPrior
return nil
}

// HasLocalAddress asserts if the address manager has the provided local
// address.
func (a *AddrManager) HasLocalAddress(na *wire.NetAddress) bool {
a.lamtx.Lock()
defer a.lamtx.Unlock()

key := NetAddressKey(na)
_, ok := a.localAddresses[key]
return ok
}

// getReachabilityFrom returns the relative reachability of the provided local
// address to the provided remote address.
func getReachabilityFrom(localAddr, remoteAddr *wire.NetAddress) int {
Expand Down
1 change: 1 addition & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ type config struct {
OnionProxyUser string `long:"onionuser" description:"Username for onion proxy server"`
OnionProxyPass string `long:"onionpass" default-mask:"-" description:"Password for onion proxy server"`
NoOnion bool `long:"noonion" description:"Disable connecting to tor hidden services"`
NoDiscoverIP bool `long:"nodiscoverip" description:"Disable automatic network address discovery"`
TorIsolation bool `long:"torisolation" description:"Enable Tor stream isolation by randomizing user credentials for each connection."`
TestNet bool `long:"testnet" description:"Use the test network"`
SimNet bool `long:"simnet" description:"Use the simulation test network"`
Expand Down
109 changes: 109 additions & 0 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,103 @@ func (ps *peerState) forAllPeers(closure func(sp *serverPeer)) {
ps.forAllOutboundPeers(closure)
}

// ResolveNetworkAddress returns the network address string representation
// (ip:port) of the node based on cummulated suggestions from outbound peers.
func (ps *peerState) ResolveNetworkAddress() string {
peers := ps.outboundPeers

// Return if there are no outbound peers or only a single outbound peer.
if len(peers) <= 1 {
return ""
}

suggestions := make(map[string]uint32, len(peers))
for _, p := range peers {
if p.peerNetworkAddress == "" {
continue
}

suggestions[p.peerNetworkAddress]++
}

// Return if there are no public ip suggestions to pick from.
if len(suggestions) == 0 {
return ""
}

// Pick the public ip with the highest suggestion count.
var maxCount uint32
var ip string
for entry, count := range suggestions {
if count > maxCount {
ip = entry
maxCount = count
}
}

return ip
}

// networkAddressHandler collects network address suggestions fron outbound
// peers.
func (ps *peerState) networkAddressHandler(s *server) {
ticker := time.NewTicker(time.Second * 10)
defer ticker.Stop()

port, err := strconv.ParseUint(activeNetParams.DefaultPort, 10, 16)
if err != nil {
amgrLog.Error(err)
return
}

srvrLog.Infof("Starting network address handler")

for {
select {
case <-ticker.C:
host := ps.ResolveNetworkAddress()
if host == "" {
continue
}

na, err := s.addrManager.HostToNetAddress(host, uint16(port),
s.services)
if err != nil {
amgrLog.Errorf("unable to generate network address: %v", err)
continue
}

s.networkAddress = na

// The conditions to disable automatic network address discovery
// are:
// - If there is a proxy set (--proxy, --onion).
// - If automatic network address discovery is explicitly disabled
// (--nodiscoverip).
// - If there is an external ip explicitly set (--externalip).
// - If listening has been disabled (--nolisten, listen disabled
// because of --connect, etc).
// - If Universal Plug and Play is enabled (--upnp).
if (cfg.Proxy != "" || cfg.OnionProxy != "") ||
cfg.NoDiscoverIP || len(cfg.ExternalIPs) > 0 ||
(cfg.DisableListen || len(cfg.Listeners) == 0) || cfg.Upnp {
continue
}

if !s.addrManager.HasLocalAddress(na) {
err = s.addrManager.AddLocalAddress(na, addrmgr.ManualPrio)
if err != nil {
amgrLog.Error(err)
}
}

case <-s.context.Done():
amgrLog.Infof("Network address handler done")
return
}
}
}

// server provides a Decred server for handling communications to and from
// Decred peers.
type server struct {
Expand Down Expand Up @@ -222,6 +319,10 @@ type server struct {
addrIndex *indexers.AddrIndex
existsAddrIndex *indexers.ExistsAddrIndex
cfIndex *indexers.CFIndex

// networkAddress is the address for the daemon discovered
// through connected outbound peers.
networkAddress *wire.NetAddress
}

// serverPeer extends the peer to maintain state shared by the server and
Expand Down Expand Up @@ -251,6 +352,10 @@ type serverPeer struct {
// The following chans are used to sync blockmanager and server.
txProcessed chan struct{}
blockProcessed chan struct{}

// peerNetworkAddress is the string representation (ip:port) of the peer
// network address connected to.
peerNetworkAddress string
}

// newServerPeer returns a new serverPeer instance. The peer needs to be set by
Expand Down Expand Up @@ -439,6 +544,9 @@ func (sp *serverPeer) OnVersion(p *peer.Peer, msg *wire.MsgVersion) *wire.MsgRej
addrManager.Good(remoteAddr)
}

// Save the network address of the peer.
sp.peerNetworkAddress = msg.AddrYou.IP.String()

// Choose whether or not to relay transactions.
sp.setDisableRelayTx(msg.DisableRelayTx)

Expand Down Expand Up @@ -1771,6 +1879,7 @@ func (s *server) peerHandler() {
})
}
go s.connManager.Start()
go state.networkAddressHandler(s)

out:
for {
Expand Down

0 comments on commit 44e7879

Please sign in to comment.