From b809adf9812c7df4526d79931b6577a7284319d6 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 21 Oct 2018 17:57:48 +0100 Subject: [PATCH] Add FriendlyName option, show friendly name and real endpoint in admin socket/yggdrasilctl --- src/yggdrasil/admin.go | 5 ++++ src/yggdrasil/config/config.go | 1 + src/yggdrasil/core.go | 49 +++++++++++++++++++++------------- src/yggdrasil/peer.go | 42 ++++++++++++++++------------- src/yggdrasil/router.go | 2 +- src/yggdrasil/tcp.go | 2 +- yggdrasilctl.go | 6 +++++ 7 files changed, 67 insertions(+), 40 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 9d3866f8..630db177 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -470,6 +470,7 @@ func (a *admin) getData_getSelf() *admin_nodeInfo { {"ip", a.core.GetAddress().String()}, {"subnet", a.core.GetSubnet().String()}, {"coords", fmt.Sprint(coords)}, + {"friendly_name", a.core.friendlyName}, } return &self } @@ -492,6 +493,8 @@ func (a *admin) getData_getPeers() []admin_nodeInfo { {"uptime", int(time.Since(p.firstSeen).Seconds())}, {"bytes_sent", atomic.LoadUint64(&p.bytesSent)}, {"bytes_recvd", atomic.LoadUint64(&p.bytesRecvd)}, + {"endpoint", p.endpoint}, + {"friendly_name", p.friendlyName}, } peerInfos = append(peerInfos, info) } @@ -516,6 +519,8 @@ func (a *admin) getData_getSwitchPeers() []admin_nodeInfo { {"port", elem.port}, {"bytes_sent", atomic.LoadUint64(&peer.bytesSent)}, {"bytes_recvd", atomic.LoadUint64(&peer.bytesRecvd)}, + {"endpoint", peer.endpoint}, + {"friendly_name", peer.friendlyName}, } peerInfos = append(peerInfos, info) } diff --git a/src/yggdrasil/config/config.go b/src/yggdrasil/config/config.go index bcf4f322..530c18cb 100644 --- a/src/yggdrasil/config/config.go +++ b/src/yggdrasil/config/config.go @@ -2,6 +2,7 @@ package config // NodeConfig defines all configuration values needed to run a signle yggdrasil node type NodeConfig struct { + FriendlyName string `comment:"Friendly name for this node. It is visible to direct peers."` Listen string `comment:"Listen address for peer connections. Default is to listen for all\nTCP connections over IPv4 and IPv6 with a random port."` AdminListen string `comment:"Listen address for admin connections Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X."` Peers []string `comment:"List of connection strings for static peers in URI format, i.e.\ntcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j."` diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 015147c4..8f61bf69 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -16,29 +16,31 @@ import ( // object for each Yggdrasil node you plan to run. type Core struct { // This is the main data structure that holds everything else for a node - boxPub boxPubKey - boxPriv boxPrivKey - sigPub sigPubKey - sigPriv sigPrivKey - switchTable switchTable - peers peers - sigs sigManager - sessions sessions - router router - dht dht - tun tunDevice - admin admin - searches searches - multicast multicast - tcp tcpInterface - log *log.Logger - ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this + boxPub boxPubKey + boxPriv boxPrivKey + sigPub sigPubKey + sigPriv sigPrivKey + friendlyName string + switchTable switchTable + peers peers + sigs sigManager + sessions sessions + router router + dht dht + tun tunDevice + admin admin + searches searches + multicast multicast + tcp tcpInterface + log *log.Logger + ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this } func (c *Core) init(bpub *boxPubKey, bpriv *boxPrivKey, spub *sigPubKey, - spriv *sigPrivKey) { + spriv *sigPrivKey, + friendlyname string) { // TODO separate init and start functions // Init sets up structs // Start launches goroutines that depend on structs being set up @@ -49,6 +51,7 @@ func (c *Core) init(bpub *boxPubKey, } c.boxPub, c.boxPriv = *bpub, *bpriv c.sigPub, c.sigPriv = *spub, *spriv + c.friendlyName = friendlyname c.admin.core = c c.sigs.init() c.searches.init(c) @@ -61,6 +64,14 @@ func (c *Core) init(bpub *boxPubKey, c.tun.init(c) } +// Gets the friendly name of this node, as specified in the NodeConfig. +func (c *Core) GetFriendlyName() string { + if c.friendlyName == "" { + return "(none)" + } + return c.friendlyName +} + // Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging // through the provided log.Logger. The started stack will include TCP and UDP // sockets, a multicast discovery socket, an admin socket, router, switch and @@ -94,7 +105,7 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { copy(sigPub[:], sigPubHex) copy(sigPriv[:], sigPrivHex) - c.init(&boxPub, &boxPriv, &sigPub, &sigPriv) + c.init(&boxPub, &boxPriv, &sigPub, &sigPriv, nc.FriendlyName) c.admin.init(c, nc.AdminListen) if err := c.tcp.init(c, nc.Listen, nc.ReadTimeout); err != nil { diff --git a/src/yggdrasil/peer.go b/src/yggdrasil/peer.go index de463b43..4f792376 100644 --- a/src/yggdrasil/peer.go +++ b/src/yggdrasil/peer.go @@ -79,30 +79,34 @@ type peer struct { bytesSent uint64 // To track bandwidth usage for getPeers bytesRecvd uint64 // To track bandwidth usage for getPeers // BUG: sync/atomic, 32 bit platforms need the above to be the first element - core *Core - port switchPort - box boxPubKey - sig sigPubKey - shared boxSharedKey - linkShared boxSharedKey - firstSeen time.Time // To track uptime for getPeers - linkOut (chan []byte) // used for protocol traffic (to bypass queues) - doSend (chan struct{}) // tell the linkLoop to send a switchMsg - dinfo *dhtInfo // used to keep the DHT working - out func([]byte) // Set up by whatever created the peers struct, used to send packets to other nodes - close func() // Called when a peer is removed, to close the underlying connection, or via admin api + core *Core + port switchPort + box boxPubKey + sig sigPubKey + shared boxSharedKey + linkShared boxSharedKey + endpoint string + friendlyName string + firstSeen time.Time // To track uptime for getPeers + linkOut (chan []byte) // used for protocol traffic (to bypass queues) + doSend (chan struct{}) // tell the linkLoop to send a switchMsg + dinfo *dhtInfo // used to keep the DHT working + out func([]byte) // Set up by whatever created the peers struct, used to send packets to other nodes + close func() // Called when a peer is removed, to close the underlying connection, or via admin api } // Creates a new peer with the specified box, sig, and linkShared keys, using the lowest unocupied port number. -func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey, linkShared *boxSharedKey) *peer { +func (ps *peers) newPeer(box *boxPubKey, sig *sigPubKey, linkShared *boxSharedKey, endpoint string, friendlyname string) *peer { now := time.Now() p := peer{box: *box, - sig: *sig, - shared: *getSharedKey(&ps.core.boxPriv, box), - linkShared: *linkShared, - firstSeen: now, - doSend: make(chan struct{}, 1), - core: ps.core} + sig: *sig, + shared: *getSharedKey(&ps.core.boxPriv, box), + linkShared: *linkShared, + endpoint: endpoint, + friendlyName: friendlyname, + firstSeen: now, + doSend: make(chan struct{}, 1), + core: ps.core} ps.mutex.Lock() defer ps.mutex.Unlock() oldPorts := ps.getPorts() diff --git a/src/yggdrasil/router.go b/src/yggdrasil/router.go index d2a8c43b..dcc6a5c4 100644 --- a/src/yggdrasil/router.go +++ b/src/yggdrasil/router.go @@ -47,7 +47,7 @@ func (r *router) init(core *Core) { r.core = core r.addr = *address_addrForNodeID(&r.core.dht.nodeID) in := make(chan []byte, 32) // TODO something better than this... - p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}) + p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}, "(self)", r.core.GetFriendlyName()) p.out = func(packet []byte) { // This is to make very sure it never blocks select { diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 0bc5802b..58d9422e 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -287,7 +287,7 @@ func (iface *tcpInterface) handler(sock net.Conn, incoming bool) { }() // Note that multiple connections to the same node are allowed // E.g. over different interfaces - p := iface.core.peers.newPeer(&info.box, &info.sig, getSharedKey(myLinkPriv, &meta.link)) + p := iface.core.peers.newPeer(&info.box, &info.sig, getSharedKey(myLinkPriv, &meta.link), sock.RemoteAddr().String(), "(none)") p.linkOut = make(chan []byte, 1) in := func(bs []byte) { p.handlePacket(bs) diff --git a/yggdrasilctl.go b/yggdrasilctl.go index d98386b7..2b5b79a4 100644 --- a/yggdrasilctl.go +++ b/yggdrasilctl.go @@ -155,6 +155,12 @@ func main() { minutes := uint(preformatted.(float64)/60) % 60 hours := uint(preformatted.(float64) / 60 / 60) formatted = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) + case "friendly_name": + if len(preformatted.(string)) > 32 { + formatted = fmt.Sprintf("%s...", preformatted.(string)[:32]) + } else { + formatted = preformatted.(string) + } default: formatted = fmt.Sprint(preformatted) }