mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-25 23:01:38 +00:00
Merge pull request #84 from neilalexander/admin
JSON support for admin socket
This commit is contained in:
commit
cc6fb8bd98
@ -54,7 +54,7 @@ cat > /tmp/$PKGNAME/debian/docs << EOF
|
|||||||
Please see https://github.com/Arceliar/yggdrasil-go/
|
Please see https://github.com/Arceliar/yggdrasil-go/
|
||||||
EOF
|
EOF
|
||||||
cat > /tmp/$PKGNAME/debian/install << EOF
|
cat > /tmp/$PKGNAME/debian/install << EOF
|
||||||
usr/bin/yggdrasil usr/bin
|
usr/bin/yggdrasil usr/bin/yggdrasilctl usr/bin
|
||||||
etc/systemd/system/*.service etc/systemd/system
|
etc/systemd/system/*.service etc/systemd/system
|
||||||
EOF
|
EOF
|
||||||
cat > /tmp/$PKGNAME/debian/postinst << EOF
|
cat > /tmp/$PKGNAME/debian/postinst << EOF
|
||||||
@ -69,11 +69,12 @@ systemctl stop yggdrasil
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
cp yggdrasil /tmp/$PKGNAME/usr/bin/
|
cp yggdrasil /tmp/$PKGNAME/usr/bin/
|
||||||
|
cp yggdrasilctl /tmp/$PKGNAME/usr/bin/
|
||||||
cp contrib/systemd/yggdrasil.service /tmp/$PKGNAME/etc/systemd/system/
|
cp contrib/systemd/yggdrasil.service /tmp/$PKGNAME/etc/systemd/system/
|
||||||
cp contrib/systemd/yggdrasil-resume.service /tmp/$PKGNAME/etc/systemd/system/
|
cp contrib/systemd/yggdrasil-resume.service /tmp/$PKGNAME/etc/systemd/system/
|
||||||
|
|
||||||
tar -czvf /tmp/$PKGNAME/data.tar.gz -C /tmp/$PKGNAME/ \
|
tar -czvf /tmp/$PKGNAME/data.tar.gz -C /tmp/$PKGNAME/ \
|
||||||
usr/bin/yggdrasil \
|
usr/bin/yggdrasil usr/bin/yggdrasilctl \
|
||||||
etc/systemd/system/yggdrasil.service \
|
etc/systemd/system/yggdrasil.service \
|
||||||
etc/systemd/system/yggdrasil-resume.service
|
etc/systemd/system/yggdrasil-resume.service
|
||||||
tar -czvf /tmp/$PKGNAME/control.tar.gz -C /tmp/$PKGNAME/debian .
|
tar -czvf /tmp/$PKGNAME/control.tar.gz -C /tmp/$PKGNAME/debian .
|
||||||
|
@ -2,8 +2,8 @@ package yggdrasil
|
|||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
import "os"
|
import "os"
|
||||||
import "bytes"
|
|
||||||
import "encoding/hex"
|
import "encoding/hex"
|
||||||
|
import "encoding/json"
|
||||||
import "errors"
|
import "errors"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "net/url"
|
import "net/url"
|
||||||
@ -13,7 +13,6 @@ import "strconv"
|
|||||||
import "sync/atomic"
|
import "sync/atomic"
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// TODO? Make all of this JSON
|
|
||||||
// TODO: Add authentication
|
// TODO: Add authentication
|
||||||
|
|
||||||
type admin struct {
|
type admin struct {
|
||||||
@ -22,124 +21,184 @@ type admin struct {
|
|||||||
handlers []admin_handlerInfo
|
handlers []admin_handlerInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type admin_info map[string]interface{}
|
||||||
|
|
||||||
type admin_handlerInfo struct {
|
type admin_handlerInfo struct {
|
||||||
name string // Checked against the first word of the api call
|
name string // Checked against the first word of the api call
|
||||||
args []string // List of human-readable argument names
|
args []string // List of human-readable argument names
|
||||||
handler func(*[]byte, ...string) // First arg is pointer to the out slice, rest is args
|
handler func(admin_info) (admin_info, error) // First is input map, second is output
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *admin) addHandler(name string, args []string, handler func(*[]byte, ...string)) {
|
// Maps things like "IP", "port", "bucket", or "coords" onto strings
|
||||||
|
type admin_pair struct {
|
||||||
|
key string
|
||||||
|
val interface{}
|
||||||
|
}
|
||||||
|
type admin_nodeInfo []admin_pair
|
||||||
|
|
||||||
|
func (a *admin) 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})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *admin) init(c *Core, listenaddr string) {
|
func (a *admin) init(c *Core, listenaddr string) {
|
||||||
a.core = c
|
a.core = c
|
||||||
a.listenaddr = listenaddr
|
a.listenaddr = listenaddr
|
||||||
a.addHandler("help", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("help", nil, func(in admin_info) (admin_info, error) {
|
||||||
|
handlers := make(map[string][]string)
|
||||||
for _, handler := range a.handlers {
|
for _, handler := range a.handlers {
|
||||||
tmp := append([]string{handler.name}, handler.args...)
|
handlers[handler.name] = handler.args
|
||||||
*out = append(*out, []byte(strings.Join(tmp, " "))...)
|
|
||||||
*out = append(*out, "\n"...)
|
|
||||||
}
|
}
|
||||||
|
return admin_info{"handlers": handlers}, nil
|
||||||
})
|
})
|
||||||
// TODO? have other parts of the program call to add their own handlers
|
a.addHandler("dot", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
a.addHandler("dot", nil, func(out *[]byte, _ ...string) {
|
return admin_info{"dot": string(a.getResponse_dot())}, nil
|
||||||
*out = a.getResponse_dot()
|
|
||||||
})
|
})
|
||||||
a.addHandler("getSelf", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("getSelf", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
*out = []byte(a.printInfos([]admin_nodeInfo{*a.getData_getSelf()}))
|
return admin_info{"self": a.getData_getSelf().asMap()}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getPeers", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("getPeers", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
*out = []byte(a.printInfos(a.getData_getPeers()))
|
sort := "ip"
|
||||||
|
peers := make(admin_info)
|
||||||
|
for _, peerdata := range a.getData_getPeers() {
|
||||||
|
p := peerdata.asMap()
|
||||||
|
so := fmt.Sprint(p[sort])
|
||||||
|
peers[so] = p
|
||||||
|
delete(peers[so].(map[string]interface{}), sort)
|
||||||
|
}
|
||||||
|
return admin_info{"peers": peers}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getSwitchPeers", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("getSwitchPeers", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
*out = []byte(a.printInfos(a.getData_getSwitchPeers()))
|
sort := "port"
|
||||||
|
switchpeers := make(admin_info)
|
||||||
|
for _, s := range a.getData_getSwitchPeers() {
|
||||||
|
p := s.asMap()
|
||||||
|
so := fmt.Sprint(p[sort])
|
||||||
|
switchpeers[so] = p
|
||||||
|
delete(switchpeers[so].(map[string]interface{}), sort)
|
||||||
|
}
|
||||||
|
return admin_info{"switchpeers": switchpeers}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getDHT", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("getDHT", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
*out = []byte(a.printInfos(a.getData_getDHT()))
|
sort := "ip"
|
||||||
|
dht := make(admin_info)
|
||||||
|
for _, d := range a.getData_getDHT() {
|
||||||
|
p := d.asMap()
|
||||||
|
so := fmt.Sprint(p[sort])
|
||||||
|
dht[so] = p
|
||||||
|
delete(dht[so].(map[string]interface{}), sort)
|
||||||
|
}
|
||||||
|
return admin_info{"dht": dht}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("getSessions", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("getSessions", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
*out = []byte(a.printInfos(a.getData_getSessions()))
|
sort := "ip"
|
||||||
|
sessions := make(admin_info)
|
||||||
|
for _, s := range a.getData_getSessions() {
|
||||||
|
p := s.asMap()
|
||||||
|
so := fmt.Sprint(p[sort])
|
||||||
|
sessions[so] = p
|
||||||
|
delete(sessions[so].(map[string]interface{}), sort)
|
||||||
|
}
|
||||||
|
return admin_info{"sessions": sessions}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("addPeer", []string{"<proto://address:port>"}, func(out *[]byte, saddr ...string) {
|
a.addHandler("addPeer", []string{"uri"}, func(in admin_info) (admin_info, error) {
|
||||||
if a.addPeer(saddr[0]) == nil {
|
if a.addPeer(in["uri"].(string)) == nil {
|
||||||
*out = []byte("Adding peer: " + saddr[0] + "\n")
|
return admin_info{
|
||||||
|
"added": []string{
|
||||||
|
in["uri"].(string),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
} else {
|
} else {
|
||||||
*out = []byte("Failed to add peer: " + saddr[0] + "\n")
|
return admin_info{
|
||||||
|
"not_added": []string{
|
||||||
|
in["uri"].(string),
|
||||||
|
},
|
||||||
|
}, errors.New("Failed to add peer")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
a.addHandler("removePeer", []string{"<port>"}, func(out *[]byte, sport ...string) {
|
a.addHandler("removePeer", []string{"port"}, func(in admin_info) (admin_info, error) {
|
||||||
if a.removePeer(sport[0]) == nil {
|
if a.removePeer(fmt.Sprint(in["port"])) == nil {
|
||||||
*out = []byte("Removing peer: " + sport[0] + "\n")
|
return admin_info{
|
||||||
|
"removed": []string{
|
||||||
|
fmt.Sprint(in["port"]),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
} else {
|
} else {
|
||||||
*out = []byte("Failed to remove peer: " + sport[0] + "\n")
|
return admin_info{
|
||||||
|
"not_removed": []string{
|
||||||
|
fmt.Sprint(in["port"]),
|
||||||
|
},
|
||||||
|
}, errors.New("Failed to remove peer")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
a.addHandler("getTunTap", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) {
|
||||||
var info admin_nodeInfo
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
recover()
|
||||||
info = admin_nodeInfo{
|
r = admin_info{"name": "none"}
|
||||||
{"Interface name", "none"},
|
e = nil
|
||||||
}
|
|
||||||
*out = []byte(a.printInfos([]admin_nodeInfo{info}))
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
info = admin_nodeInfo{
|
return admin_info{
|
||||||
{"Interface name", a.core.tun.iface.Name()},
|
"name": a.core.tun.iface.Name(),
|
||||||
{"TAP mode", strconv.FormatBool(a.core.tun.iface.IsTAP())},
|
"tap_mode": a.core.tun.iface.IsTAP(),
|
||||||
{"MTU", strconv.Itoa(a.core.tun.mtu)},
|
"mtu": a.core.tun.mtu,
|
||||||
}
|
}, nil
|
||||||
*out = []byte(a.printInfos([]admin_nodeInfo{info}))
|
|
||||||
})
|
})
|
||||||
a.addHandler("setTunTap", []string{"<ifname|auto|none>", "[<tun|tap>]", "[<mtu>]"}, func(out *[]byte, ifparams ...string) {
|
a.addHandler("setTunTap", []string{"name", "[tap_mode]", "[mtu]"}, func(in admin_info) (admin_info, error) {
|
||||||
// Set sane defaults
|
// Set sane defaults
|
||||||
iftapmode := false
|
iftapmode := getDefaults().defaultIfTAPMode
|
||||||
ifmtu := 1280
|
ifmtu := getDefaults().defaultIfMTU
|
||||||
var err error
|
// Has TAP mode been specified?
|
||||||
// Check we have enough params for TAP mode
|
if tap, ok := in["tap_mode"]; ok {
|
||||||
if len(ifparams) > 1 {
|
iftapmode = tap.(bool)
|
||||||
// Is it a TAP adapter?
|
|
||||||
if ifparams[1] == "tap" {
|
|
||||||
iftapmode = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Check we have enough params for MTU
|
// Check we have enough params for MTU
|
||||||
if len(ifparams) > 2 {
|
if mtu, ok := in["mtu"]; ok {
|
||||||
// Make sure the MTU is sane
|
if mtu.(float64) >= 1280 && ifmtu <= getDefaults().maximumIfMTU {
|
||||||
ifmtu, err = strconv.Atoi(ifparams[2])
|
ifmtu = int(in["mtu"].(float64))
|
||||||
if err != nil || ifmtu < 1280 || ifmtu > 65535 {
|
|
||||||
ifmtu = 1280
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Start the TUN adapter
|
// Start the TUN adapter
|
||||||
if err := a.startTunWithMTU(ifparams[0], iftapmode, ifmtu); err != nil {
|
if err := a.startTunWithMTU(in["name"].(string), iftapmode, ifmtu); err != nil {
|
||||||
*out = []byte(fmt.Sprintf("Failed to set TUN: %v\n", err))
|
return admin_info{}, errors.New("Failed to configure adapter")
|
||||||
} else {
|
} else {
|
||||||
info := admin_nodeInfo{
|
return admin_info{
|
||||||
{"Interface name", ifparams[0]},
|
"name": a.core.tun.iface.Name(),
|
||||||
{"TAP mode", strconv.FormatBool(iftapmode)},
|
"tap_mode": a.core.tun.iface.IsTAP(),
|
||||||
{"MTU", strconv.Itoa(ifmtu)},
|
"mtu": ifmtu,
|
||||||
}
|
}, nil
|
||||||
*out = []byte(a.printInfos([]admin_nodeInfo{info}))
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
a.addHandler("getAllowedBoxPubs", nil, func(out *[]byte, _ ...string) {
|
a.addHandler("getAllowedBoxPubs", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
*out = []byte(a.getAllowedBoxPubs())
|
return admin_info{"allowed_box_pubs": a.getAllowedBoxPubs()}, nil
|
||||||
})
|
})
|
||||||
a.addHandler("addAllowedBoxPub", []string{"<boxPubKey>"}, func(out *[]byte, saddr ...string) {
|
a.addHandler("addAllowedBoxPub", []string{"box_pub_key"}, func(in admin_info) (admin_info, error) {
|
||||||
if a.addAllowedBoxPub(saddr[0]) == nil {
|
if a.addAllowedBoxPub(in["box_pub_key"].(string)) == nil {
|
||||||
*out = []byte("Adding key: " + saddr[0] + "\n")
|
return admin_info{
|
||||||
|
"added": []string{
|
||||||
|
in["box_pub_key"].(string),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
} else {
|
} else {
|
||||||
*out = []byte("Failed to add key: " + saddr[0] + "\n")
|
return admin_info{
|
||||||
|
"not_added": []string{
|
||||||
|
in["box_pub_key"].(string),
|
||||||
|
},
|
||||||
|
}, errors.New("Failed to add allowed box pub key")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
a.addHandler("removeAllowedBoxPub", []string{"<boxPubKey>"}, func(out *[]byte, sport ...string) {
|
a.addHandler("removeAllowedBoxPub", []string{"box_pub_key"}, func(in admin_info) (admin_info, error) {
|
||||||
if a.removeAllowedBoxPub(sport[0]) == nil {
|
if a.removeAllowedBoxPub(in["box_pub_key"].(string)) == nil {
|
||||||
*out = []byte("Removing key: " + sport[0] + "\n")
|
return admin_info{
|
||||||
|
"removed": []string{
|
||||||
|
in["box_pub_key"].(string),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
} else {
|
} else {
|
||||||
*out = []byte("Failed to remove key: " + sport[0] + "\n")
|
return admin_info{
|
||||||
|
"not_removed": []string{
|
||||||
|
in["box_pub_key"].(string),
|
||||||
|
},
|
||||||
|
}, errors.New("Failed to remove allowed box pub key")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
go a.listen()
|
go a.listen()
|
||||||
@ -162,49 +221,99 @@ func (a *admin) listen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *admin) handleRequest(conn net.Conn) {
|
func (a *admin) handleRequest(conn net.Conn) {
|
||||||
buf := make([]byte, 1024)
|
decoder := json.NewDecoder(conn)
|
||||||
_, err := conn.Read(buf)
|
encoder := json.NewEncoder(conn)
|
||||||
if err != nil {
|
encoder.SetIndent("", " ")
|
||||||
a.core.log.Printf("Admin socket failed to read: %v", err)
|
recv := make(admin_info)
|
||||||
|
send := make(admin_info)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
if r != nil {
|
||||||
|
send = admin_info{
|
||||||
|
"status": "error",
|
||||||
|
"error": "Unrecoverable error, possibly as a result of invalid input types or malformed syntax",
|
||||||
|
}
|
||||||
|
fmt.Println("Admin socket error:", r)
|
||||||
|
if err := encoder.Encode(&send); err != nil {
|
||||||
|
fmt.Println("Admin socket JSON encode error:", err)
|
||||||
|
}
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Start with a clean slate on each request
|
||||||
|
recv = admin_info{}
|
||||||
|
send = admin_info{}
|
||||||
|
|
||||||
|
// Decode the input
|
||||||
|
if err := decoder.Decode(&recv); err != nil {
|
||||||
|
// fmt.Println("Admin socket JSON decode error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var out []byte
|
|
||||||
buf = bytes.Trim(buf, "\x00\r\n\t")
|
// Send the request back with the response, and default to "error"
|
||||||
call := strings.Split(string(buf), " ")
|
// unless the status is changed below by one of the handlers
|
||||||
var cmd string
|
send["request"] = recv
|
||||||
var args []string
|
send["status"] = "error"
|
||||||
if len(call) > 0 {
|
|
||||||
cmd = call[0]
|
handlers:
|
||||||
args = call[1:]
|
|
||||||
}
|
|
||||||
done := false
|
|
||||||
for _, handler := range a.handlers {
|
for _, handler := range a.handlers {
|
||||||
if cmd == handler.name {
|
// We've found the handler that matches the request
|
||||||
handler.handler(&out, args...)
|
if recv["request"] == handler.name {
|
||||||
done = true
|
// Check that we have all the required arguments
|
||||||
|
for _, arg := range handler.args {
|
||||||
|
// An argument in [square brackets] is optional and not required,
|
||||||
|
// so we can safely ignore those
|
||||||
|
if strings.HasPrefix(arg, "[") && strings.HasSuffix(arg, "]") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Check if the field is missing
|
||||||
|
if _, ok := recv[arg]; !ok {
|
||||||
|
send = admin_info{
|
||||||
|
"status": "error",
|
||||||
|
"error": "Expected field missing",
|
||||||
|
"expecting": arg,
|
||||||
|
}
|
||||||
|
break handlers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By this point we should have all the fields we need, so call
|
||||||
|
// the handler
|
||||||
|
response, err := handler.handler(recv)
|
||||||
|
if err != nil {
|
||||||
|
send["error"] = err.Error()
|
||||||
|
if response != nil {
|
||||||
|
send["response"] = response
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
send["status"] = "success"
|
||||||
|
if response != nil {
|
||||||
|
send["response"] = response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !done {
|
|
||||||
out = []byte("I didn't understand that!\n")
|
// Send the response back
|
||||||
}
|
if err := encoder.Encode(&send); err != nil {
|
||||||
_, err = conn.Write(out)
|
// fmt.Println("Admin socket JSON encode error:", err)
|
||||||
if err != nil {
|
return
|
||||||
a.core.log.Printf("Admin socket error: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If "keepalive" isn't true then close the connection
|
||||||
|
if keepalive, ok := recv["keepalive"]; !ok || !keepalive.(bool) {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps things like "IP", "port", "bucket", or "coords" onto strings
|
|
||||||
type admin_pair struct {
|
|
||||||
key string
|
|
||||||
val string
|
|
||||||
}
|
}
|
||||||
type admin_nodeInfo []admin_pair
|
}
|
||||||
|
|
||||||
func (n *admin_nodeInfo) asMap() map[string]string {
|
func (n *admin_nodeInfo) asMap() map[string]interface{} {
|
||||||
m := make(map[string]string, len(*n))
|
m := make(map[string]interface{}, len(*n))
|
||||||
for _, p := range *n {
|
for _, p := range *n {
|
||||||
m[p.key] = p.val
|
m[p.key] = p.val
|
||||||
}
|
}
|
||||||
@ -303,7 +412,7 @@ func (a *admin) getData_getSelf() *admin_nodeInfo {
|
|||||||
addr := a.core.router.addr
|
addr := a.core.router.addr
|
||||||
coords := table.self.getCoords()
|
coords := table.self.getCoords()
|
||||||
self := admin_nodeInfo{
|
self := admin_nodeInfo{
|
||||||
{"IP", net.IP(addr[:]).String()},
|
{"ip", net.IP(addr[:]).String()},
|
||||||
{"coords", fmt.Sprint(coords)},
|
{"coords", fmt.Sprint(coords)},
|
||||||
}
|
}
|
||||||
return &self
|
return &self
|
||||||
@ -321,11 +430,11 @@ func (a *admin) getData_getPeers() []admin_nodeInfo {
|
|||||||
p := ports[port]
|
p := ports[port]
|
||||||
addr := *address_addrForNodeID(getNodeID(&p.box))
|
addr := *address_addrForNodeID(getNodeID(&p.box))
|
||||||
info := admin_nodeInfo{
|
info := admin_nodeInfo{
|
||||||
{"IP", net.IP(addr[:]).String()},
|
{"ip", net.IP(addr[:]).String()},
|
||||||
{"port", fmt.Sprint(port)},
|
{"port", port},
|
||||||
{"uptime", fmt.Sprint(time.Since(p.firstSeen))},
|
{"uptime", fmt.Sprint(time.Since(p.firstSeen))},
|
||||||
{"bytesSent", fmt.Sprint(atomic.LoadUint64(&p.bytesSent))},
|
{"bytes_sent", atomic.LoadUint64(&p.bytesSent)},
|
||||||
{"bytesRecvd", fmt.Sprint(atomic.LoadUint64(&p.bytesRecvd))},
|
{"bytes_recvd", atomic.LoadUint64(&p.bytesRecvd)},
|
||||||
}
|
}
|
||||||
peerInfos = append(peerInfos, info)
|
peerInfos = append(peerInfos, info)
|
||||||
}
|
}
|
||||||
@ -344,9 +453,9 @@ func (a *admin) getData_getSwitchPeers() []admin_nodeInfo {
|
|||||||
addr := *address_addrForNodeID(getNodeID(&peer.box))
|
addr := *address_addrForNodeID(getNodeID(&peer.box))
|
||||||
coords := elem.locator.getCoords()
|
coords := elem.locator.getCoords()
|
||||||
info := admin_nodeInfo{
|
info := admin_nodeInfo{
|
||||||
{"IP", net.IP(addr[:]).String()},
|
{"ip", net.IP(addr[:]).String()},
|
||||||
{"coords", fmt.Sprint(coords)},
|
{"coords", fmt.Sprint(coords)},
|
||||||
{"port", fmt.Sprint(elem.port)},
|
{"port", elem.port},
|
||||||
}
|
}
|
||||||
peerInfos = append(peerInfos, info)
|
peerInfos = append(peerInfos, info)
|
||||||
}
|
}
|
||||||
@ -363,11 +472,11 @@ func (a *admin) getData_getDHT() []admin_nodeInfo {
|
|||||||
for _, v := range vs {
|
for _, v := range vs {
|
||||||
addr := *address_addrForNodeID(v.getNodeID())
|
addr := *address_addrForNodeID(v.getNodeID())
|
||||||
info := admin_nodeInfo{
|
info := admin_nodeInfo{
|
||||||
{"IP", net.IP(addr[:]).String()},
|
{"ip", net.IP(addr[:]).String()},
|
||||||
{"coords", fmt.Sprint(v.coords)},
|
{"coords", fmt.Sprint(v.coords)},
|
||||||
{"bucket", fmt.Sprint(i)},
|
{"bucket", i},
|
||||||
{"peerOnly", fmt.Sprint(isPeer)},
|
{"peer_only", isPeer},
|
||||||
{"lastSeen", fmt.Sprint(now.Sub(v.recv))},
|
{"last_seen", fmt.Sprint(now.Sub(v.recv))},
|
||||||
}
|
}
|
||||||
infos = append(infos, info)
|
infos = append(infos, info)
|
||||||
}
|
}
|
||||||
@ -386,12 +495,12 @@ func (a *admin) getData_getSessions() []admin_nodeInfo {
|
|||||||
for _, sinfo := range a.core.sessions.sinfos {
|
for _, sinfo := range a.core.sessions.sinfos {
|
||||||
// TODO? skipped known but timed out sessions?
|
// TODO? skipped known but timed out sessions?
|
||||||
info := admin_nodeInfo{
|
info := admin_nodeInfo{
|
||||||
{"IP", net.IP(sinfo.theirAddr[:]).String()},
|
{"ip", net.IP(sinfo.theirAddr[:]).String()},
|
||||||
{"coords", fmt.Sprint(sinfo.coords)},
|
{"coords", fmt.Sprint(sinfo.coords)},
|
||||||
{"MTU", fmt.Sprint(sinfo.getMTU())},
|
{"mtu", sinfo.getMTU()},
|
||||||
{"wasMTUFixed", fmt.Sprint(sinfo.wasMTUFixed)},
|
{"was_mtu_fixed", sinfo.wasMTUFixed},
|
||||||
{"bytesSent", fmt.Sprint(sinfo.bytesSent)},
|
{"bytes_sent", sinfo.bytesSent},
|
||||||
{"bytesRecvd", fmt.Sprint(sinfo.bytesRecvd)},
|
{"bytes_recvd", sinfo.bytesRecvd},
|
||||||
}
|
}
|
||||||
infos = append(infos, info)
|
infos = append(infos, info)
|
||||||
}
|
}
|
||||||
@ -400,14 +509,13 @@ func (a *admin) getData_getSessions() []admin_nodeInfo {
|
|||||||
return infos
|
return infos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *admin) getAllowedBoxPubs() string {
|
func (a *admin) getAllowedBoxPubs() []string {
|
||||||
pubs := a.core.peers.getAllowedBoxPubs()
|
pubs := a.core.peers.getAllowedBoxPubs()
|
||||||
var out []string
|
var out []string
|
||||||
for _, pub := range pubs {
|
for _, pub := range pubs {
|
||||||
out = append(out, hex.EncodeToString(pub[:]))
|
out = append(out, hex.EncodeToString(pub[:]))
|
||||||
}
|
}
|
||||||
out = append(out, "")
|
return out
|
||||||
return strings.Join(out, "\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *admin) addAllowedBoxPub(bstr string) (err error) {
|
func (a *admin) addAllowedBoxPub(bstr string) (err error) {
|
||||||
@ -438,18 +546,18 @@ func (a *admin) getResponse_dot() []byte {
|
|||||||
sessions := a.getData_getSessions()
|
sessions := a.getData_getSessions()
|
||||||
// Map of coords onto IP
|
// Map of coords onto IP
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
m[self["coords"]] = self["IP"]
|
m[self["coords"].(string)] = self["ip"].(string)
|
||||||
for _, peer := range peers {
|
for _, peer := range peers {
|
||||||
p := peer.asMap()
|
p := peer.asMap()
|
||||||
m[p["coords"]] = p["IP"]
|
m[p["coords"].(string)] = p["ip"].(string)
|
||||||
}
|
}
|
||||||
for _, node := range dht {
|
for _, node := range dht {
|
||||||
n := node.asMap()
|
n := node.asMap()
|
||||||
m[n["coords"]] = n["IP"]
|
m[n["coords"].(string)] = n["ip"].(string)
|
||||||
}
|
}
|
||||||
for _, node := range sessions {
|
for _, node := range sessions {
|
||||||
n := node.asMap()
|
n := node.asMap()
|
||||||
m[n["coords"]] = n["IP"]
|
m[n["coords"].(string)] = n["ip"].(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start building a tree from all known nodes
|
// Start building a tree from all known nodes
|
||||||
|
85
yggdrasilctl.go
Normal file
85
yggdrasilctl.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "flag"
|
||||||
|
import "fmt"
|
||||||
|
import "strings"
|
||||||
|
import "net"
|
||||||
|
import "encoding/json"
|
||||||
|
import "strconv"
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
type admin_info map[string]interface{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
server := flag.String("endpoint", "localhost:9001", "Admin socket endpoint")
|
||||||
|
flag.Parse()
|
||||||
|
args := flag.Args()
|
||||||
|
|
||||||
|
if len(args) == 0 {
|
||||||
|
fmt.Println("usage:", os.Args[0], "[-endpoint=localhost:9001] command [key=value] [...]")
|
||||||
|
fmt.Println("example:", os.Args[0], "getPeers")
|
||||||
|
fmt.Println("example:", os.Args[0], "setTunTap name=auto mtu=1500 tap_mode=false")
|
||||||
|
fmt.Println("example:", os.Args[0], "-endpoint=localhost:9001 getDHT")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.Dial("tcp", *server)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(conn)
|
||||||
|
encoder := json.NewEncoder(conn)
|
||||||
|
send := make(admin_info)
|
||||||
|
recv := make(admin_info)
|
||||||
|
|
||||||
|
for c, a := range args {
|
||||||
|
if c == 0 {
|
||||||
|
send["request"] = a
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tokens := strings.Split(a, "=")
|
||||||
|
if i, err := strconv.Atoi(tokens[1]); err == nil {
|
||||||
|
send[tokens[0]] = i
|
||||||
|
} else {
|
||||||
|
switch tokens[1] {
|
||||||
|
case "true":
|
||||||
|
send[tokens[0]] = true
|
||||||
|
case "false":
|
||||||
|
send[tokens[0]] = false
|
||||||
|
default:
|
||||||
|
send[tokens[0]] = tokens[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := encoder.Encode(&send); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := decoder.Decode(&recv); err == nil {
|
||||||
|
if _, ok := recv["request"]; !ok {
|
||||||
|
fmt.Println("Missing request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok := recv["response"]; !ok {
|
||||||
|
fmt.Println("Missing response")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req := recv["request"].(map[string]interface{})
|
||||||
|
res := recv["response"].(map[string]interface{})
|
||||||
|
switch req["request"] {
|
||||||
|
case "dot":
|
||||||
|
fmt.Println(res["dot"])
|
||||||
|
default:
|
||||||
|
if json, err := json.MarshalIndent(recv["response"], "", " "); err == nil {
|
||||||
|
fmt.Println(string(json))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := recv["status"]; ok && v == "error" {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user