Update addPeer behavior and peer loop for URIs that may have transforms (like srv:// and txt://)

This commit is contained in:
Neil Alexander 2019-03-26 19:15:59 +00:00
parent 246c60ae4d
commit a642c6009f
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
4 changed files with 123 additions and 67 deletions

View file

@ -108,10 +108,13 @@ func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeCo
// Check to see if the peers are in a parsable format, if not then default
// them to the TCP scheme
if peers, ok := dat["Peers"].([]interface{}); ok {
peerloop:
for index, peer := range peers {
uri := peer.(string)
if strings.HasPrefix(uri, "tcp://") || strings.HasPrefix(uri, "socks://") {
continue
for _, prefix := range []string{"tcp://", "socks://", "srv://", "txt://"} {
if strings.HasPrefix(uri, prefix) {
continue peerloop
}
}
if strings.HasPrefix(uri, "tcp:") {
uri = uri[4:]
@ -121,11 +124,14 @@ func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeCo
}
// Now do the same with the interface peers
if interfacepeers, ok := dat["InterfacePeers"].(map[string]interface{}); ok {
interfacepeerloop:
for intf, peers := range interfacepeers {
for index, peer := range peers.([]interface{}) {
uri := peer.(string)
if strings.HasPrefix(uri, "tcp://") || strings.HasPrefix(uri, "socks://") {
continue
for _, prefix := range []string{"tcp://", "socks://", "srv://", "txt://"} {
if strings.HasPrefix(uri, prefix) {
continue interfacepeerloop
}
}
if strings.HasPrefix(uri, "tcp:") {
uri = uri[4:]

View file

@ -591,7 +591,11 @@ func (a *admin) printInfos(infos []admin_nodeInfo) string {
// addPeer triggers a connection attempt to a node.
func (a *admin) addPeer(addr string, sintf string) error {
err := a.core.link.call(addr, sintf)
entry, err := a.core.resolvePeerEntry(addr, sintf)
if err != nil {
return err
}
err = a.core.link.call(entry.uri, entry.sintf)
if err != nil {
return err
}

View file

@ -2,8 +2,11 @@ package yggdrasil
import (
"encoding/hex"
"fmt"
"io/ioutil"
"net"
"net/url"
"strings"
"sync"
"time"
@ -23,6 +26,11 @@ type module interface {
start() error
}
type peerEntry struct {
uri string
sintf string
}
// The Core object represents the Yggdrasil node. You should create a Core
// object for each Yggdrasil node you plan to run.
type Core struct {
@ -32,6 +40,8 @@ type Core struct {
config config.NodeConfig // Active config
configOld config.NodeConfig // Previous config
configMutex sync.RWMutex // Protects both config and configOld
configPeers []peerEntry // Transformed peer list
configPeersMutex sync.RWMutex // Protects configPeers
boxPub crypto.BoxPubKey
boxPriv crypto.BoxPrivKey
sigPub crypto.SigPubKey
@ -94,33 +104,42 @@ func (c *Core) init() error {
// If any static peers were provided in the configuration above then we should
// configure them. The loop ensures that disconnected peers will eventually
// be reconnected with.
func (c *Core) addPeerLoop() {
func (c *Core) runPeerLoop() {
for {
// Get the peers from the config - these could change!
c.configMutex.RLock()
peers := c.config.Peers
interfacepeers := c.config.InterfacePeers
c.configMutex.RUnlock()
// Add peers from the Peers section
for _, peer := range peers {
c.AddPeer(peer, "")
c.configPeersMutex.RLock()
for _, peer := range c.configPeers {
c.AddPeer(peer.uri, peer.sintf)
time.Sleep(time.Second)
}
// Add peers from the InterfacePeers section
for intf, intfpeers := range interfacepeers {
for _, peer := range intfpeers {
c.AddPeer(peer, intf)
time.Sleep(time.Second)
}
}
c.configPeersMutex.RUnlock()
// Sit for a while
time.Sleep(time.Minute)
}
}
// When we start up or reconfigure, draw up the peer loop
func (c *Core) updatePeerLoop() {
c.configMutex.RLock()
c.configPeersMutex.Lock()
c.configPeers = []peerEntry{}
for _, peer := range c.config.Peers {
if entry, err := c.resolvePeerEntry(peer, ""); err == nil {
c.configPeers = append(c.configPeers, entry)
}
}
for intf, intfpeers := range c.config.InterfacePeers {
for _, peer := range intfpeers {
if entry, err := c.resolvePeerEntry(peer, intf); err == nil {
c.configPeers = append(c.configPeers, entry)
}
}
}
c.configPeersMutex.Unlock()
c.configMutex.RUnlock()
}
// UpdateConfig updates the configuration in Core and then signals the
// various module goroutines to reconfigure themselves if needed
func (c *Core) UpdateConfig(config *config.NodeConfig) {
@ -161,6 +180,8 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
} else {
c.log.Infoln("Configuration reloaded successfully")
}
c.updatePeerLoop()
}
// GetBuildName gets the current build name. This is usually injected if built
@ -238,7 +259,8 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
return err
}
go c.addPeerLoop()
c.updatePeerLoop()
go c.runPeerLoop()
c.log.Infoln("Startup complete")
return nil
@ -350,3 +372,54 @@ func (c *Core) GetTUNIfName() string {
func (c *Core) GetTUNIfMTU() int {
return c.router.tun.mtu
}
// Resolves the peer URI that may require a DNS lookup (or some other transform
// into a peer URI that can be given directly to link.go
func (c *Core) resolvePeerEntry(uri, sintf string) (peerEntry, error) {
u, err := url.Parse(uri)
if err != nil {
return peerEntry{}, err
}
switch u.Scheme {
case "srv":
for _, proto := range []string{"tcp"} {
if cname, srv, err := net.LookupSRV("yggdrasil", proto, u.Host); err == nil {
for _, record := range srv {
c.log.Traceln("SRV lookup for", u.Host, "found:", cname, record.Target, record.Port)
switch proto {
case "tcp":
return peerEntry{
uri: fmt.Sprintf("tcp://%s:%d", record.Target, record.Port),
sintf: sintf,
}, nil
}
}
} else {
c.log.Debugln("SRV lookup for", u.Host, "failed:", err)
return peerEntry{}, err
}
}
case "txt":
recordname := fmt.Sprintf("_yggdrasil.%s", u.Host)
if records, err := net.LookupTXT(recordname); err == nil {
for _, record := range records {
c.log.Traceln("Found TXT record:", record)
if !strings.HasPrefix(record, "txt://") {
return peerEntry{
uri: fmt.Sprintf("%s", record),
sintf: sintf,
}, nil
}
}
} else {
c.log.Debugln("TXT lookup failed:", err)
return peerEntry{}, err
}
default:
break
}
return peerEntry{
uri: uri,
sintf: sintf,
}, nil
}

View file

@ -102,33 +102,6 @@ func (l *link) call(uri string, sintf string) error {
}
pathtokens := strings.Split(strings.Trim(u.Path, "/"), "/")
switch u.Scheme {
case "srv":
for _, proto := range []string{"tcp"} {
if cname, srv, err := net.LookupSRV("yggdrasil", proto, u.Host); err == nil {
for _, record := range srv {
l.core.log.Debugln("SRV lookup for", u.Host, "found:", cname, record.Target, record.Port)
switch proto {
case "tcp":
saddr := fmt.Sprintf("%s:%d", record.Target, record.Port)
l.tcp.call(saddr, nil, sintf)
}
}
} else {
l.core.log.Debugln("SRV lookup for", u.Host, "failed:", err)
}
}
case "txt":
recordname := fmt.Sprintf("_yggdrasil.%s", u.Host)
if records, err := net.LookupTXT(recordname); err == nil {
for _, record := range records {
l.core.log.Debugln("Found TXT record:", record)
if !strings.HasPrefix(record, "txt://") {
l.call(record, sintf)
}
}
} else {
l.core.log.Debugln("TXT lookup failed:", err)
}
case "tcp":
l.tcp.call(u.Host, nil, sintf)
case "socks":