mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-27 12:05:23 +00:00
Start factoring out the admin socket into a separate module (not all functions implemented yet)
This commit is contained in:
parent
7ca5a2533d
commit
8ef1978cb1
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/kardianos/minwinsvc"
|
"github.com/kardianos/minwinsvc"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/tuntap"
|
"github.com/yggdrasil-network/yggdrasil-go/src/tuntap"
|
||||||
@ -31,6 +32,7 @@ type node struct {
|
|||||||
core Core
|
core Core
|
||||||
tuntap tuntap.TunAdapter
|
tuntap tuntap.TunAdapter
|
||||||
multicast multicast.Multicast
|
multicast multicast.Multicast
|
||||||
|
admin admin.AdminSocket
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig {
|
func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig {
|
||||||
@ -184,6 +186,11 @@ func main() {
|
|||||||
logger.Errorln("An error occurred during startup")
|
logger.Errorln("An error occurred during startup")
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
// Start the admin socket
|
||||||
|
n.admin.Init(&n.core, state, logger, nil)
|
||||||
|
if err := n.admin.Start(); err != nil {
|
||||||
|
logger.Errorln("An error occurred starting admin socket:", err)
|
||||||
|
}
|
||||||
// Start the multicast interface
|
// Start the multicast interface
|
||||||
n.multicast.Init(&n.core, state, logger, nil)
|
n.multicast.Init(&n.core, state, logger, nil)
|
||||||
if err := n.multicast.Start(); err != nil {
|
if err := n.multicast.Start(); err != nil {
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
package yggdrasil
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gologme/log"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Add authentication
|
// TODO: Add authentication
|
||||||
|
|
||||||
type admin struct {
|
type AdminSocket struct {
|
||||||
core *Core
|
core *yggdrasil.Core
|
||||||
|
log *log.Logger
|
||||||
reconfigure chan chan error
|
reconfigure chan chan error
|
||||||
listenaddr string
|
listenaddr string
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
@ -46,27 +46,28 @@ type admin_pair struct {
|
|||||||
type admin_nodeInfo []admin_pair
|
type admin_nodeInfo []admin_pair
|
||||||
|
|
||||||
// addHandler is called for each admin function to add the handler and help documentation to the API.
|
// addHandler is called for each admin function to add the handler and help documentation to the API.
|
||||||
func (a *admin) addHandler(name string, args []string, handler func(admin_info) (admin_info, error)) {
|
func (a *AdminSocket) addHandler(name string, args []string, handler func(admin_info) (admin_info, error)) {
|
||||||
a.handlers = append(a.handlers, admin_handlerInfo{name, args, handler})
|
a.handlers = append(a.handlers, admin_handlerInfo{name, args, handler})
|
||||||
}
|
}
|
||||||
|
|
||||||
// init runs the initial admin setup.
|
// init runs the initial admin setup.
|
||||||
func (a *admin) init(c *Core) {
|
func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) {
|
||||||
a.core = c
|
a.core = c
|
||||||
|
a.log = log
|
||||||
a.reconfigure = make(chan chan error, 1)
|
a.reconfigure = make(chan chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
e := <-a.reconfigure
|
e := <-a.reconfigure
|
||||||
current, previous := a.core.config.Get()
|
current, previous := state.Get()
|
||||||
if current.AdminListen != previous.AdminListen {
|
if current.AdminListen != previous.AdminListen {
|
||||||
a.listenaddr = current.AdminListen
|
a.listenaddr = current.AdminListen
|
||||||
a.close()
|
a.Stop()
|
||||||
a.start()
|
a.Start()
|
||||||
}
|
}
|
||||||
e <- nil
|
e <- nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
current, _ := a.core.config.Get()
|
current, _ := state.Get()
|
||||||
a.listenaddr = current.AdminListen
|
a.listenaddr = current.AdminListen
|
||||||
a.addHandler("list", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("list", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
handlers := make(map[string]interface{})
|
handlers := make(map[string]interface{})
|
||||||
@ -75,64 +76,93 @@ func (a *admin) init(c *Core) {
|
|||||||
}
|
}
|
||||||
return admin_info{"list": handlers}, nil
|
return admin_info{"list": handlers}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("dot", []string{}, func(in admin_info) (admin_info, error) {
|
/*a.addHandler("dot", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
return admin_info{"dot": string(a.getResponse_dot())}, nil
|
return admin_info{"dot": string(a.getResponse_dot())}, nil
|
||||||
})
|
})*/
|
||||||
a.addHandler("getSelf", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getSelf", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
self := a.getData_getSelf().asMap()
|
ip := c.Address().String()
|
||||||
ip := fmt.Sprint(self["ip"])
|
return admin_info{
|
||||||
delete(self, "ip")
|
"self": admin_info{
|
||||||
return admin_info{"self": admin_info{ip: self}}, nil
|
ip: admin_info{
|
||||||
|
"box_pub_key": c.BoxPubKey(),
|
||||||
|
"build_name": yggdrasil.BuildName(),
|
||||||
|
"build_version": yggdrasil.BuildVersion(),
|
||||||
|
"coords": fmt.Sprintf("%v", c.Coords()),
|
||||||
|
"subnet": c.Subnet().String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getPeers", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getPeers", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
sort := "ip"
|
|
||||||
peers := make(admin_info)
|
peers := make(admin_info)
|
||||||
for _, peerdata := range a.getData_getPeers() {
|
for _, p := range a.core.GetPeers() {
|
||||||
p := peerdata.asMap()
|
addr := *address.AddrForNodeID(crypto.GetNodeID(&p.PublicKey))
|
||||||
so := fmt.Sprint(p[sort])
|
so := net.IP(addr[:]).String()
|
||||||
peers[so] = p
|
peers[so] = admin_info{
|
||||||
delete(peers[so].(map[string]interface{}), sort)
|
"ip": so,
|
||||||
|
"port": p.Port,
|
||||||
|
"uptime": p.Uptime.Seconds(),
|
||||||
|
"bytes_sent": p.BytesSent,
|
||||||
|
"bytes_recvd": p.BytesRecvd,
|
||||||
|
"proto": p.Protocol,
|
||||||
|
"endpoint": p.Endpoint,
|
||||||
|
"box_pub_key": p.PublicKey,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return admin_info{"peers": peers}, nil
|
return admin_info{"peers": peers}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getSwitchPeers", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getSwitchPeers", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
sort := "port"
|
|
||||||
switchpeers := make(admin_info)
|
switchpeers := make(admin_info)
|
||||||
for _, s := range a.getData_getSwitchPeers() {
|
for _, s := range a.core.GetSwitchPeers() {
|
||||||
p := s.asMap()
|
addr := *address.AddrForNodeID(crypto.GetNodeID(&s.PublicKey))
|
||||||
so := fmt.Sprint(p[sort])
|
so := fmt.Sprint(s.Port)
|
||||||
switchpeers[so] = p
|
switchpeers[so] = admin_info{
|
||||||
delete(switchpeers[so].(map[string]interface{}), sort)
|
"ip": net.IP(addr[:]).String(),
|
||||||
|
"coords": fmt.Sprintf("%v", s.Coords),
|
||||||
|
"port": s.Port,
|
||||||
|
"bytes_sent": s.BytesSent,
|
||||||
|
"bytes_recvd": s.BytesRecvd,
|
||||||
|
"proto": s.Protocol,
|
||||||
|
"endpoint": s.Endpoint,
|
||||||
|
"box_pub_key": s.PublicKey,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return admin_info{"switchpeers": switchpeers}, nil
|
return admin_info{"switchpeers": switchpeers}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getSwitchQueues", []string{}, func(in admin_info) (admin_info, error) {
|
/*a.addHandler("getSwitchQueues", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
queues := a.getData_getSwitchQueues()
|
queues := a.core.GetSwitchQueues()
|
||||||
return admin_info{"switchqueues": queues.asMap()}, nil
|
return admin_info{"switchqueues": queues.asMap()}, nil
|
||||||
})
|
})*/
|
||||||
a.addHandler("getDHT", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getDHT", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
sort := "ip"
|
|
||||||
dht := make(admin_info)
|
dht := make(admin_info)
|
||||||
for _, d := range a.getData_getDHT() {
|
for _, d := range a.core.GetDHT() {
|
||||||
p := d.asMap()
|
addr := *address.AddrForNodeID(crypto.GetNodeID(&d.PublicKey))
|
||||||
so := fmt.Sprint(p[sort])
|
so := net.IP(addr[:]).String()
|
||||||
dht[so] = p
|
dht[so] = admin_info{
|
||||||
delete(dht[so].(map[string]interface{}), sort)
|
"coords": fmt.Sprintf("%v", d.Coords),
|
||||||
|
"last_seen": d.LastSeen.Seconds(),
|
||||||
|
"box_pub_key": d.PublicKey,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return admin_info{"dht": dht}, nil
|
return admin_info{"dht": dht}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getSessions", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getSessions", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
sort := "ip"
|
|
||||||
sessions := make(admin_info)
|
sessions := make(admin_info)
|
||||||
for _, s := range a.getData_getSessions() {
|
for _, s := range a.core.GetSessions() {
|
||||||
p := s.asMap()
|
addr := *address.AddrForNodeID(crypto.GetNodeID(&s.PublicKey))
|
||||||
so := fmt.Sprint(p[sort])
|
so := net.IP(addr[:]).String()
|
||||||
sessions[so] = p
|
sessions[so] = admin_info{
|
||||||
delete(sessions[so].(map[string]interface{}), sort)
|
"coords": fmt.Sprintf("%v", s.Coords),
|
||||||
|
"bytes_sent": s.BytesSent,
|
||||||
|
"bytes_recvd": s.BytesRecvd,
|
||||||
|
"mtu": s.MTU,
|
||||||
|
"was_mtu_fixed": s.WasMTUFixed,
|
||||||
|
"box_pub_key": s.PublicKey,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return admin_info{"sessions": sessions}, nil
|
return admin_info{"sessions": sessions}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("addPeer", []string{"uri", "[interface]"}, func(in admin_info) (admin_info, error) {
|
/*a.addHandler("addPeer", []string{"uri", "[interface]"}, func(in admin_info) (admin_info, error) {
|
||||||
// Set sane defaults
|
// Set sane defaults
|
||||||
intf := ""
|
intf := ""
|
||||||
// Has interface been specified?
|
// Has interface been specified?
|
||||||
@ -168,7 +198,7 @@ func (a *admin) init(c *Core) {
|
|||||||
}, errors.New("Failed to remove peer")
|
}, errors.New("Failed to remove peer")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
/* a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) {
|
a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
r = admin_info{"none": admin_info{}}
|
r = admin_info{"none": admin_info{}}
|
||||||
@ -215,7 +245,7 @@ func (a *admin) init(c *Core) {
|
|||||||
intfs = append(intfs, v.Name)
|
intfs = append(intfs, v.Name)
|
||||||
}
|
}
|
||||||
return admin_info{"multicast_interfaces": intfs}, nil
|
return admin_info{"multicast_interfaces": intfs}, nil
|
||||||
})*/
|
})
|
||||||
a.addHandler("getAllowedEncryptionPublicKeys", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getAllowedEncryptionPublicKeys", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
return admin_info{"allowed_box_pubs": a.getAllowedEncryptionPublicKeys()}, nil
|
return admin_info{"allowed_box_pubs": a.getAllowedEncryptionPublicKeys()}, nil
|
||||||
})
|
})
|
||||||
@ -249,7 +279,7 @@ func (a *admin) init(c *Core) {
|
|||||||
}, errors.New("Failed to remove allowed key")
|
}, errors.New("Failed to remove allowed key")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
/*a.addHandler("getTunnelRouting", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("getTunnelRouting", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
enabled := false
|
enabled := false
|
||||||
a.core.router.doAdmin(func() {
|
a.core.router.doAdmin(func() {
|
||||||
enabled = a.core.router.cryptokey.isEnabled()
|
enabled = a.core.router.cryptokey.isEnabled()
|
||||||
@ -335,7 +365,7 @@ func (a *admin) init(c *Core) {
|
|||||||
} else {
|
} else {
|
||||||
return admin_info{"not_removed": []string{fmt.Sprintf("%s via %s", in["subnet"].(string), in["box_pub_key"].(string))}}, errors.New("Failed to remove route")
|
return admin_info{"not_removed": []string{fmt.Sprintf("%s via %s", in["subnet"].(string), in["box_pub_key"].(string))}}, errors.New("Failed to remove route")
|
||||||
}
|
}
|
||||||
})*/
|
})
|
||||||
a.addHandler("dhtPing", []string{"box_pub_key", "coords", "[target]"}, func(in admin_info) (admin_info, error) {
|
a.addHandler("dhtPing", []string{"box_pub_key", "coords", "[target]"}, func(in admin_info) (admin_info, error) {
|
||||||
if in["target"] == nil {
|
if in["target"] == nil {
|
||||||
in["target"] = "none"
|
in["target"] = "none"
|
||||||
@ -390,11 +420,11 @@ func (a *admin) init(c *Core) {
|
|||||||
} else {
|
} else {
|
||||||
return admin_info{}, err
|
return admin_info{}, err
|
||||||
}
|
}
|
||||||
})
|
})*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// start runs the admin API socket to listen for / respond to admin API calls.
|
// start runs the admin API socket to listen for / respond to admin API calls.
|
||||||
func (a *admin) start() error {
|
func (a *AdminSocket) Start() error {
|
||||||
if a.listenaddr != "none" && a.listenaddr != "" {
|
if a.listenaddr != "none" && a.listenaddr != "" {
|
||||||
go a.listen()
|
go a.listen()
|
||||||
}
|
}
|
||||||
@ -402,7 +432,7 @@ func (a *admin) start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cleans up when stopping
|
// cleans up when stopping
|
||||||
func (a *admin) close() error {
|
func (a *AdminSocket) Stop() error {
|
||||||
if a.listener != nil {
|
if a.listener != nil {
|
||||||
return a.listener.Close()
|
return a.listener.Close()
|
||||||
} else {
|
} else {
|
||||||
@ -411,21 +441,21 @@ func (a *admin) close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// listen is run by start and manages API connections.
|
// listen is run by start and manages API connections.
|
||||||
func (a *admin) listen() {
|
func (a *AdminSocket) listen() {
|
||||||
u, err := url.Parse(a.listenaddr)
|
u, err := url.Parse(a.listenaddr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
switch strings.ToLower(u.Scheme) {
|
switch strings.ToLower(u.Scheme) {
|
||||||
case "unix":
|
case "unix":
|
||||||
if _, err := os.Stat(a.listenaddr[7:]); err == nil {
|
if _, err := os.Stat(a.listenaddr[7:]); err == nil {
|
||||||
a.core.log.Debugln("Admin socket", a.listenaddr[7:], "already exists, trying to clean up")
|
a.log.Debugln("Admin socket", a.listenaddr[7:], "already exists, trying to clean up")
|
||||||
if _, err := net.DialTimeout("unix", a.listenaddr[7:], time.Second*2); err == nil || err.(net.Error).Timeout() {
|
if _, err := net.DialTimeout("unix", a.listenaddr[7:], time.Second*2); err == nil || err.(net.Error).Timeout() {
|
||||||
a.core.log.Errorln("Admin socket", a.listenaddr[7:], "already exists and is in use by another process")
|
a.log.Errorln("Admin socket", a.listenaddr[7:], "already exists and is in use by another process")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
if err := os.Remove(a.listenaddr[7:]); err == nil {
|
if err := os.Remove(a.listenaddr[7:]); err == nil {
|
||||||
a.core.log.Debugln(a.listenaddr[7:], "was cleaned up")
|
a.log.Debugln(a.listenaddr[7:], "was cleaned up")
|
||||||
} else {
|
} else {
|
||||||
a.core.log.Errorln(a.listenaddr[7:], "already exists and was not cleaned up:", err)
|
a.log.Errorln(a.listenaddr[7:], "already exists and was not cleaned up:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -436,7 +466,7 @@ func (a *admin) listen() {
|
|||||||
case "@": // maybe abstract namespace
|
case "@": // maybe abstract namespace
|
||||||
default:
|
default:
|
||||||
if err := os.Chmod(a.listenaddr[7:], 0660); err != nil {
|
if err := os.Chmod(a.listenaddr[7:], 0660); err != nil {
|
||||||
a.core.log.Warnln("WARNING:", a.listenaddr[:7], "may have unsafe permissions!")
|
a.log.Warnln("WARNING:", a.listenaddr[:7], "may have unsafe permissions!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -450,10 +480,10 @@ func (a *admin) listen() {
|
|||||||
a.listener, err = net.Listen("tcp", a.listenaddr)
|
a.listener, err = net.Listen("tcp", a.listenaddr)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.core.log.Errorf("Admin socket failed to listen: %v", err)
|
a.log.Errorf("Admin socket failed to listen: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
a.core.log.Infof("%s admin socket listening on %s",
|
a.log.Infof("%s admin socket listening on %s",
|
||||||
strings.ToUpper(a.listener.Addr().Network()),
|
strings.ToUpper(a.listener.Addr().Network()),
|
||||||
a.listener.Addr().String())
|
a.listener.Addr().String())
|
||||||
defer a.listener.Close()
|
defer a.listener.Close()
|
||||||
@ -466,7 +496,7 @@ func (a *admin) listen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleRequest calls the request handler for each request sent to the admin API.
|
// handleRequest calls the request handler for each request sent to the admin API.
|
||||||
func (a *admin) handleRequest(conn net.Conn) {
|
func (a *AdminSocket) handleRequest(conn net.Conn) {
|
||||||
decoder := json.NewDecoder(conn)
|
decoder := json.NewDecoder(conn)
|
||||||
encoder := json.NewEncoder(conn)
|
encoder := json.NewEncoder(conn)
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
@ -480,9 +510,9 @@ func (a *admin) handleRequest(conn net.Conn) {
|
|||||||
"status": "error",
|
"status": "error",
|
||||||
"error": "Unrecoverable error, possibly as a result of invalid input types or malformed syntax",
|
"error": "Unrecoverable error, possibly as a result of invalid input types or malformed syntax",
|
||||||
}
|
}
|
||||||
a.core.log.Errorln("Admin socket error:", r)
|
a.log.Errorln("Admin socket error:", r)
|
||||||
if err := encoder.Encode(&send); err != nil {
|
if err := encoder.Encode(&send); err != nil {
|
||||||
a.core.log.Errorln("Admin socket JSON encode error:", err)
|
a.log.Errorln("Admin socket JSON encode error:", err)
|
||||||
}
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
@ -577,7 +607,7 @@ func (n *admin_nodeInfo) toString() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// printInfos returns a newline separated list of strings from admin_nodeInfos, e.g. a printable string of info about all peers.
|
// printInfos returns a newline separated list of strings from admin_nodeInfos, e.g. a printable string of info about all peers.
|
||||||
func (a *admin) printInfos(infos []admin_nodeInfo) string {
|
func (a *AdminSocket) printInfos(infos []admin_nodeInfo) string {
|
||||||
var out []string
|
var out []string
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
out = append(out, info.toString())
|
out = append(out, info.toString())
|
||||||
@ -586,8 +616,9 @@ func (a *admin) printInfos(infos []admin_nodeInfo) string {
|
|||||||
return strings.Join(out, "\n")
|
return strings.Join(out, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// addPeer triggers a connection attempt to a node.
|
// addPeer triggers a connection attempt to a node.
|
||||||
func (a *admin) addPeer(addr string, sintf string) error {
|
func (a *AdminSocket) addPeer(addr string, sintf string) error {
|
||||||
err := a.core.link.call(addr, sintf)
|
err := a.core.link.call(addr, sintf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -596,220 +627,18 @@ func (a *admin) addPeer(addr string, sintf string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// removePeer disconnects an existing node (given by the node's port number).
|
// removePeer disconnects an existing node (given by the node's port number).
|
||||||
func (a *admin) removePeer(p string) error {
|
func (a *AdminSocket) removePeer(p string) error {
|
||||||
iport, err := strconv.Atoi(p)
|
iport, err := strconv.Atoi(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.core.peers.removePeer(switchPort(iport))
|
a.core.RemovePeer(iport)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// startTunWithMTU creates the tun/tap device, sets its address, and sets the MTU to the provided value.
|
|
||||||
/*
|
|
||||||
func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error {
|
|
||||||
// Close the TUN first if open
|
|
||||||
_ = a.core.router.tun.close()
|
|
||||||
// Then reconfigure and start it
|
|
||||||
addr := a.core.router.addr
|
|
||||||
straddr := fmt.Sprintf("%s/%v", net.IP(addr[:]).String(), 8*len(address.GetPrefix())-1)
|
|
||||||
if ifname != "none" {
|
|
||||||
err := a.core.router.tun.setup(ifname, iftapmode, straddr, ifmtu)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// If we have open sessions then we need to notify them
|
|
||||||
// that our MTU has now changed
|
|
||||||
for _, sinfo := range a.core.sessions.sinfos {
|
|
||||||
if ifname == "none" {
|
|
||||||
sinfo.myMTU = 0
|
|
||||||
} else {
|
|
||||||
sinfo.myMTU = uint16(ifmtu)
|
|
||||||
}
|
|
||||||
a.core.sessions.sendPingPong(sinfo, false)
|
|
||||||
}
|
|
||||||
// Aaaaand... go!
|
|
||||||
go a.core.router.tun.read()
|
|
||||||
}
|
|
||||||
go a.core.router.tun.write()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
// getData_getSelf returns the self node's info for admin responses.
|
|
||||||
func (a *admin) getData_getSelf() *admin_nodeInfo {
|
|
||||||
table := a.core.switchTable.table.Load().(lookupTable)
|
|
||||||
coords := table.self.getCoords()
|
|
||||||
nodeid := *crypto.GetNodeID(&a.core.boxPub)
|
|
||||||
self := admin_nodeInfo{
|
|
||||||
{"node_id", hex.EncodeToString(nodeid[:])},
|
|
||||||
{"box_pub_key", hex.EncodeToString(a.core.boxPub[:])},
|
|
||||||
{"ip", a.core.Address().String()},
|
|
||||||
{"subnet", a.core.Subnet().String()},
|
|
||||||
{"coords", fmt.Sprint(coords)},
|
|
||||||
}
|
|
||||||
if name := BuildName(); name != "unknown" {
|
|
||||||
self = append(self, admin_pair{"build_name", name})
|
|
||||||
}
|
|
||||||
if version := BuildVersion(); version != "unknown" {
|
|
||||||
self = append(self, admin_pair{"build_version", version})
|
|
||||||
}
|
|
||||||
|
|
||||||
return &self
|
|
||||||
}
|
|
||||||
|
|
||||||
// getData_getPeers returns info from Core.peers for an admin response.
|
|
||||||
func (a *admin) getData_getPeers() []admin_nodeInfo {
|
|
||||||
ports := a.core.peers.ports.Load().(map[switchPort]*peer)
|
|
||||||
var peerInfos []admin_nodeInfo
|
|
||||||
var ps []switchPort
|
|
||||||
for port := range ports {
|
|
||||||
ps = append(ps, port)
|
|
||||||
}
|
|
||||||
sort.Slice(ps, func(i, j int) bool { return ps[i] < ps[j] })
|
|
||||||
for _, port := range ps {
|
|
||||||
p := ports[port]
|
|
||||||
addr := *address.AddrForNodeID(crypto.GetNodeID(&p.box))
|
|
||||||
info := admin_nodeInfo{
|
|
||||||
{"ip", net.IP(addr[:]).String()},
|
|
||||||
{"port", port},
|
|
||||||
{"uptime", int(time.Since(p.firstSeen).Seconds())},
|
|
||||||
{"bytes_sent", atomic.LoadUint64(&p.bytesSent)},
|
|
||||||
{"bytes_recvd", atomic.LoadUint64(&p.bytesRecvd)},
|
|
||||||
{"proto", p.intf.info.linkType},
|
|
||||||
{"endpoint", p.intf.name},
|
|
||||||
{"box_pub_key", hex.EncodeToString(p.box[:])},
|
|
||||||
}
|
|
||||||
peerInfos = append(peerInfos, info)
|
|
||||||
}
|
|
||||||
return peerInfos
|
|
||||||
}
|
|
||||||
|
|
||||||
// getData_getSwitchPeers returns info from Core.switchTable for an admin response.
|
|
||||||
func (a *admin) getData_getSwitchPeers() []admin_nodeInfo {
|
|
||||||
var peerInfos []admin_nodeInfo
|
|
||||||
table := a.core.switchTable.table.Load().(lookupTable)
|
|
||||||
peers := a.core.peers.ports.Load().(map[switchPort]*peer)
|
|
||||||
for _, elem := range table.elems {
|
|
||||||
peer, isIn := peers[elem.port]
|
|
||||||
if !isIn {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
addr := *address.AddrForNodeID(crypto.GetNodeID(&peer.box))
|
|
||||||
coords := elem.locator.getCoords()
|
|
||||||
info := admin_nodeInfo{
|
|
||||||
{"ip", net.IP(addr[:]).String()},
|
|
||||||
{"coords", fmt.Sprint(coords)},
|
|
||||||
{"port", elem.port},
|
|
||||||
{"bytes_sent", atomic.LoadUint64(&peer.bytesSent)},
|
|
||||||
{"bytes_recvd", atomic.LoadUint64(&peer.bytesRecvd)},
|
|
||||||
{"proto", peer.intf.info.linkType},
|
|
||||||
{"endpoint", peer.intf.info.remote},
|
|
||||||
{"box_pub_key", hex.EncodeToString(peer.box[:])},
|
|
||||||
}
|
|
||||||
peerInfos = append(peerInfos, info)
|
|
||||||
}
|
|
||||||
return peerInfos
|
|
||||||
}
|
|
||||||
|
|
||||||
// getData_getSwitchQueues returns info from Core.switchTable for an queue data.
|
|
||||||
func (a *admin) getData_getSwitchQueues() admin_nodeInfo {
|
|
||||||
var peerInfos admin_nodeInfo
|
|
||||||
switchTable := &a.core.switchTable
|
|
||||||
getSwitchQueues := func() {
|
|
||||||
queues := make([]map[string]interface{}, 0)
|
|
||||||
for k, v := range switchTable.queues.bufs {
|
|
||||||
nexthop := switchTable.bestPortForCoords([]byte(k))
|
|
||||||
queue := map[string]interface{}{
|
|
||||||
"queue_id": k,
|
|
||||||
"queue_size": v.size,
|
|
||||||
"queue_packets": len(v.packets),
|
|
||||||
"queue_port": nexthop,
|
|
||||||
}
|
|
||||||
queues = append(queues, queue)
|
|
||||||
}
|
|
||||||
peerInfos = admin_nodeInfo{
|
|
||||||
{"queues", queues},
|
|
||||||
{"queues_count", len(switchTable.queues.bufs)},
|
|
||||||
{"queues_size", switchTable.queues.size},
|
|
||||||
{"highest_queues_count", switchTable.queues.maxbufs},
|
|
||||||
{"highest_queues_size", switchTable.queues.maxsize},
|
|
||||||
{"maximum_queues_size", switchTable.queueTotalMaxSize},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.core.switchTable.doAdmin(getSwitchQueues)
|
|
||||||
return peerInfos
|
|
||||||
}
|
|
||||||
|
|
||||||
// getData_getDHT returns info from Core.dht for an admin response.
|
|
||||||
func (a *admin) getData_getDHT() []admin_nodeInfo {
|
|
||||||
var infos []admin_nodeInfo
|
|
||||||
getDHT := func() {
|
|
||||||
now := time.Now()
|
|
||||||
var dhtInfos []*dhtInfo
|
|
||||||
for _, v := range a.core.dht.table {
|
|
||||||
dhtInfos = append(dhtInfos, v)
|
|
||||||
}
|
|
||||||
sort.SliceStable(dhtInfos, func(i, j int) bool {
|
|
||||||
return dht_ordered(&a.core.dht.nodeID, dhtInfos[i].getNodeID(), dhtInfos[j].getNodeID())
|
|
||||||
})
|
|
||||||
for _, v := range dhtInfos {
|
|
||||||
addr := *address.AddrForNodeID(v.getNodeID())
|
|
||||||
info := admin_nodeInfo{
|
|
||||||
{"ip", net.IP(addr[:]).String()},
|
|
||||||
{"coords", fmt.Sprint(v.coords)},
|
|
||||||
{"last_seen", int(now.Sub(v.recv).Seconds())},
|
|
||||||
{"box_pub_key", hex.EncodeToString(v.key[:])},
|
|
||||||
}
|
|
||||||
infos = append(infos, info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.core.router.doAdmin(getDHT)
|
|
||||||
return infos
|
|
||||||
}
|
|
||||||
|
|
||||||
// getData_getSessions returns info from Core.sessions for an admin response.
|
|
||||||
func (a *admin) getData_getSessions() []admin_nodeInfo {
|
|
||||||
var infos []admin_nodeInfo
|
|
||||||
getSessions := func() {
|
|
||||||
for _, sinfo := range a.core.sessions.sinfos {
|
|
||||||
// TODO? skipped known but timed out sessions?
|
|
||||||
info := admin_nodeInfo{
|
|
||||||
{"ip", net.IP(sinfo.theirAddr[:]).String()},
|
|
||||||
{"coords", fmt.Sprint(sinfo.coords)},
|
|
||||||
{"mtu", sinfo.getMTU()},
|
|
||||||
{"was_mtu_fixed", sinfo.wasMTUFixed},
|
|
||||||
{"bytes_sent", sinfo.bytesSent},
|
|
||||||
{"bytes_recvd", sinfo.bytesRecvd},
|
|
||||||
{"box_pub_key", hex.EncodeToString(sinfo.theirPermPub[:])},
|
|
||||||
}
|
|
||||||
infos = append(infos, info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.core.router.doAdmin(getSessions)
|
|
||||||
return infos
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAllowedEncryptionPublicKeys returns the public keys permitted for incoming peer connections.
|
|
||||||
func (a *admin) getAllowedEncryptionPublicKeys() []string {
|
|
||||||
return a.core.peers.getAllowedEncryptionPublicKeys()
|
|
||||||
}
|
|
||||||
|
|
||||||
// addAllowedEncryptionPublicKey whitelists a key for incoming peer connections.
|
|
||||||
func (a *admin) addAllowedEncryptionPublicKey(bstr string) (err error) {
|
|
||||||
a.core.peers.addAllowedEncryptionPublicKey(bstr)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeAllowedEncryptionPublicKey removes a key from the whitelist for incoming peer connections.
|
|
||||||
// If none are set, an empty list permits all incoming connections.
|
|
||||||
func (a *admin) removeAllowedEncryptionPublicKey(bstr string) (err error) {
|
|
||||||
a.core.peers.removeAllowedEncryptionPublicKey(bstr)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a DHT ping to the node with the provided key and coords, optionally looking up the specified target NodeID.
|
// Send a DHT ping to the node with the provided key and coords, optionally looking up the specified target NodeID.
|
||||||
func (a *admin) admin_dhtPing(keyString, coordString, targetString string) (dhtRes, error) {
|
func (a *AdminSocket) admin_dhtPing(keyString, coordString, targetString string) (dhtRes, error) {
|
||||||
var key crypto.BoxPubKey
|
var key crypto.BoxPubKey
|
||||||
if keyBytes, err := hex.DecodeString(keyString); err != nil {
|
if keyBytes, err := hex.DecodeString(keyString); err != nil {
|
||||||
return dhtRes{}, err
|
return dhtRes{}, err
|
||||||
@ -866,7 +695,7 @@ func (a *admin) admin_dhtPing(keyString, coordString, targetString string) (dhtR
|
|||||||
return dhtRes{}, errors.New(fmt.Sprintf("DHT ping timeout: %s", keyString))
|
return dhtRes{}, errors.New(fmt.Sprintf("DHT ping timeout: %s", keyString))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *admin) admin_getNodeInfo(keyString, coordString string, nocache bool) (nodeinfoPayload, error) {
|
func (a *AdminSocket) admin_getNodeInfo(keyString, coordString string, nocache bool) (nodeinfoPayload, error) {
|
||||||
var key crypto.BoxPubKey
|
var key crypto.BoxPubKey
|
||||||
if keyBytes, err := hex.DecodeString(keyString); err != nil {
|
if keyBytes, err := hex.DecodeString(keyString); err != nil {
|
||||||
return nodeinfoPayload{}, err
|
return nodeinfoPayload{}, err
|
||||||
@ -915,7 +744,7 @@ func (a *admin) admin_getNodeInfo(keyString, coordString string, nocache bool) (
|
|||||||
// getResponse_dot returns a response for a graphviz dot formatted representation of the known parts of the network.
|
// getResponse_dot returns a response for a graphviz dot formatted representation of the known parts of the network.
|
||||||
// This is color-coded and labeled, and includes the self node, switch peers, nodes known to the DHT, and nodes with open sessions.
|
// This is color-coded and labeled, and includes the self node, switch peers, nodes known to the DHT, and nodes with open sessions.
|
||||||
// The graph is structured as a tree with directed links leading away from the root.
|
// The graph is structured as a tree with directed links leading away from the root.
|
||||||
func (a *admin) getResponse_dot() []byte {
|
func (a *AdminSocket) getResponse_dot() []byte {
|
||||||
self := a.getData_getSelf()
|
self := a.getData_getSelf()
|
||||||
peers := a.getData_getSwitchPeers()
|
peers := a.getData_getSwitchPeers()
|
||||||
dht := a.getData_getDHT()
|
dht := a.getData_getDHT()
|
||||||
@ -1037,3 +866,4 @@ func (a *admin) getResponse_dot() []byte {
|
|||||||
put("}\n")
|
put("}\n")
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
*/
|
@ -36,6 +36,7 @@ type SwitchPeer struct {
|
|||||||
BytesRecvd uint64
|
BytesRecvd uint64
|
||||||
Port uint64
|
Port uint64
|
||||||
Protocol string
|
Protocol string
|
||||||
|
Endpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
// DHTEntry represents a single DHT entry that has been learned or cached from
|
// DHTEntry represents a single DHT entry that has been learned or cached from
|
||||||
@ -127,6 +128,7 @@ func (c *Core) GetSwitchPeers() []SwitchPeer {
|
|||||||
BytesRecvd: atomic.LoadUint64(&peer.bytesRecvd),
|
BytesRecvd: atomic.LoadUint64(&peer.bytesRecvd),
|
||||||
Port: uint64(elem.port),
|
Port: uint64(elem.port),
|
||||||
Protocol: peer.intf.info.linkType,
|
Protocol: peer.intf.info.linkType,
|
||||||
|
Endpoint: peer.intf.info.remote,
|
||||||
}
|
}
|
||||||
copy(info.PublicKey[:], peer.box[:])
|
copy(info.PublicKey[:], peer.box[:])
|
||||||
switchpeers = append(switchpeers, info)
|
switchpeers = append(switchpeers, info)
|
||||||
@ -289,6 +291,12 @@ func (c *Core) BoxPubKey() string {
|
|||||||
return hex.EncodeToString(c.boxPub[:])
|
return hex.EncodeToString(c.boxPub[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Coords returns the current coordinates of the node.
|
||||||
|
func (c *Core) Coords() []byte {
|
||||||
|
table := c.switchTable.table.Load().(lookupTable)
|
||||||
|
return table.self.getCoords()
|
||||||
|
}
|
||||||
|
|
||||||
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
||||||
// address.
|
// address.
|
||||||
func (c *Core) Address() *net.IP {
|
func (c *Core) Address() *net.IP {
|
||||||
@ -359,5 +367,6 @@ func (c *Core) CallPeer(addr string, sintf string) error {
|
|||||||
// AddAllowedEncryptionPublicKey adds an allowed public key. This allow peerings
|
// AddAllowedEncryptionPublicKey adds an allowed public key. This allow peerings
|
||||||
// to be restricted only to keys that you have selected.
|
// to be restricted only to keys that you have selected.
|
||||||
func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error {
|
func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error {
|
||||||
return c.admin.addAllowedEncryptionPublicKey(boxStr)
|
//return c.admin.addAllowedEncryptionPublicKey(boxStr)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ type Core struct {
|
|||||||
sessions sessions
|
sessions sessions
|
||||||
router router
|
router router
|
||||||
dht dht
|
dht dht
|
||||||
admin admin
|
|
||||||
searches searches
|
searches searches
|
||||||
link link
|
link link
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
@ -69,7 +68,6 @@ func (c *Core) init() error {
|
|||||||
copy(c.sigPub[:], sigPubHex)
|
copy(c.sigPub[:], sigPubHex)
|
||||||
copy(c.sigPriv[:], sigPrivHex)
|
copy(c.sigPriv[:], sigPrivHex)
|
||||||
|
|
||||||
c.admin.init(c)
|
|
||||||
c.searches.init(c)
|
c.searches.init(c)
|
||||||
c.dht.init(c)
|
c.dht.init(c)
|
||||||
c.sessions.init(c)
|
c.sessions.init(c)
|
||||||
@ -118,7 +116,6 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
|||||||
errors := 0
|
errors := 0
|
||||||
|
|
||||||
components := []chan chan error{
|
components := []chan chan error{
|
||||||
c.admin.reconfigure,
|
|
||||||
c.searches.reconfigure,
|
c.searches.reconfigure,
|
||||||
c.dht.reconfigure,
|
c.dht.reconfigure,
|
||||||
c.sessions.reconfigure,
|
c.sessions.reconfigure,
|
||||||
@ -189,11 +186,6 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.admin.start(); err != nil {
|
|
||||||
c.log.Errorln("Failed to start admin socket")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
go c.addPeerLoop()
|
go c.addPeerLoop()
|
||||||
|
|
||||||
c.log.Infoln("Startup complete")
|
c.log.Infoln("Startup complete")
|
||||||
@ -203,5 +195,4 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState,
|
|||||||
// Stop shuts down the Yggdrasil node.
|
// Stop shuts down the Yggdrasil node.
|
||||||
func (c *Core) Stop() {
|
func (c *Core) Stop() {
|
||||||
c.log.Infoln("Stopping...")
|
c.log.Infoln("Stopping...")
|
||||||
c.admin.close()
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user