mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-04-30 07:05:06 +03:00
Update addPeer behavior and peer loop for URIs that may have transforms (like srv:// and txt://)
This commit is contained in:
parent
246c60ae4d
commit
a642c6009f
4 changed files with 123 additions and 67 deletions
|
@ -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:]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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":
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue