From a6ef7166eab06de5620ae1420b65932480d685fe Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 17:21:14 +0100 Subject: [PATCH 01/11] Start JSON-ifying the admin socket --- src/yggdrasil/admin.go | 377 ++++++++++++++++++++++++----------------- 1 file changed, 220 insertions(+), 157 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 8e6ee91a..633ff7c3 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -2,8 +2,10 @@ package yggdrasil import "net" import "os" -import "bytes" + +// import "bytes" import "encoding/hex" +import "encoding/json" import "errors" import "fmt" import "net/url" @@ -22,126 +24,167 @@ type admin struct { handlers []admin_handlerInfo } +type admin_info map[string]interface{} + type admin_handlerInfo struct { - name string // Checked against the first word of the api call - args []string // List of human-readable argument names - handler func(*[]byte, ...string) // First arg is pointer to the out slice, rest is args + name string // Checked against the first word of the api call + args []string // List of human-readable argument names + 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}) } func (a *admin) init(c *Core, listenaddr string) { a.core = c 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 { - tmp := append([]string{handler.name}, handler.args...) - *out = append(*out, []byte(strings.Join(tmp, " "))...) - *out = append(*out, "\n"...) + handlers[handler.name] = handler.args } + return admin_info{"handlers": handlers}, nil }) - // TODO? have other parts of the program call to add their own handlers - a.addHandler("dot", nil, func(out *[]byte, _ ...string) { - *out = a.getResponse_dot() + a.addHandler("dot", nil, func(in admin_info) (admin_info, error) { + return admin_info{"dot": string(a.getResponse_dot())}, nil }) - a.addHandler("getSelf", nil, func(out *[]byte, _ ...string) { - *out = []byte(a.printInfos([]admin_nodeInfo{*a.getData_getSelf()})) + a.addHandler("getSelf", nil, func(in admin_info) (admin_info, error) { + return admin_info{"self": a.getData_getSelf().asMap()}, nil }) - a.addHandler("getPeers", nil, func(out *[]byte, _ ...string) { - *out = []byte(a.printInfos(a.getData_getPeers())) - }) - a.addHandler("getSwitchPeers", nil, func(out *[]byte, _ ...string) { - *out = []byte(a.printInfos(a.getData_getSwitchPeers())) - }) - a.addHandler("getDHT", nil, func(out *[]byte, _ ...string) { - *out = []byte(a.printInfos(a.getData_getDHT())) - }) - a.addHandler("getSessions", nil, func(out *[]byte, _ ...string) { - *out = []byte(a.printInfos(a.getData_getSessions())) - }) - a.addHandler("addPeer", []string{""}, func(out *[]byte, saddr ...string) { - if a.addPeer(saddr[0]) == nil { - *out = []byte("Adding peer: " + saddr[0] + "\n") - } else { - *out = []byte("Failed to add peer: " + saddr[0] + "\n") + a.addHandler("getPeers", nil, func(in admin_info) (admin_info, error) { + 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("removePeer", []string{""}, func(out *[]byte, sport ...string) { - if a.removePeer(sport[0]) == nil { - *out = []byte("Removing peer: " + sport[0] + "\n") - } else { - *out = []byte("Failed to remove peer: " + sport[0] + "\n") + a.addHandler("getSwitchPeers", nil, func(in admin_info) (admin_info, error) { + 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("getTunTap", nil, func(out *[]byte, _ ...string) { - var info admin_nodeInfo - defer func() { - if r := recover(); r != nil { - info = admin_nodeInfo{ - {"Interface name", "none"}, + a.addHandler("getDHT", nil, func(in admin_info) (admin_info, error) { + 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(in admin_info) (admin_info, error) { + 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{""}, func(out *[]byte, saddr ...string) { + if a.addPeer(saddr[0]) == nil { + *out = []byte("Adding peer: " + saddr[0] + "\n") + } else { + *out = []byte("Failed to add peer: " + saddr[0] + "\n") + } + }) + a.addHandler("removePeer", []string{""}, func(out *[]byte, sport ...string) { + if a.removePeer(sport[0]) == nil { + *out = []byte("Removing peer: " + sport[0] + "\n") + } else { + *out = []byte("Failed to remove peer: " + sport[0] + "\n") + } + }) + a.addHandler("getTunTap", nil, func(out *[]byte, _ ...string) { + var info admin_nodeInfo + defer func() { + if r := recover(); r != nil { + info = admin_nodeInfo{ + {"Interface name", "none"}, + } + *out = []byte(a.printInfos([]admin_nodeInfo{info})) + } + }() + + info = admin_nodeInfo{ + {"Interface name", a.core.tun.iface.Name()}, + {"TAP mode", strconv.FormatBool(a.core.tun.iface.IsTAP())}, + {"mtu", strconv.Itoa(a.core.tun.mtu)}, + } + *out = []byte(a.printInfos([]admin_nodeInfo{info})) + }) + a.addHandler("setTunTap", []string{"", "[]", "[]"}, func(out *[]byte, ifparams ...string) { + // Set sane defaults + iftapmode := false + ifmtu := 1280 + var err error + // Check we have enough params for TAP mode + if len(ifparams) > 1 { + // Is it a TAP adapter? + if ifparams[1] == "tap" { + iftapmode = true + } + } + // Check we have enough params for MTU + if len(ifparams) > 2 { + // Make sure the MTU is sane + ifmtu, err = strconv.Atoi(ifparams[2]) + if err != nil || ifmtu < 1280 || ifmtu > 65535 { + ifmtu = 1280 + } + } + // Start the TUN adapter + if err := a.startTunWithMTU(ifparams[0], iftapmode, ifmtu); err != nil { + *out = []byte(fmt.Sprintf("Failed to set TUN: %v\n", err)) + } else { + info := admin_nodeInfo{ + {"Interface name", ifparams[0]}, + {"TAP mode", strconv.FormatBool(iftapmode)}, + {"mtu", strconv.Itoa(ifmtu)}, } *out = []byte(a.printInfos([]admin_nodeInfo{info})) } - }() - - info = admin_nodeInfo{ - {"Interface name", a.core.tun.iface.Name()}, - {"TAP mode", strconv.FormatBool(a.core.tun.iface.IsTAP())}, - {"MTU", strconv.Itoa(a.core.tun.mtu)}, - } - *out = []byte(a.printInfos([]admin_nodeInfo{info})) - }) - a.addHandler("setTunTap", []string{"", "[]", "[]"}, func(out *[]byte, ifparams ...string) { - // Set sane defaults - iftapmode := false - ifmtu := 1280 - var err error - // Check we have enough params for TAP mode - if len(ifparams) > 1 { - // Is it a TAP adapter? - if ifparams[1] == "tap" { - iftapmode = true + }) + a.addHandler("getAllowedBoxPubs", nil, func(out *[]byte, _ ...string) { + *out = []byte(a.getAllowedBoxPubs()) + }) + a.addHandler("addAllowedBoxPub", []string{""}, func(out *[]byte, saddr ...string) { + if a.addAllowedBoxPub(saddr[0]) == nil { + *out = []byte("Adding key: " + saddr[0] + "\n") + } else { + *out = []byte("Failed to add key: " + saddr[0] + "\n") } - } - // Check we have enough params for MTU - if len(ifparams) > 2 { - // Make sure the MTU is sane - ifmtu, err = strconv.Atoi(ifparams[2]) - if err != nil || ifmtu < 1280 || ifmtu > 65535 { - ifmtu = 1280 + }) + a.addHandler("removeAllowedBoxPub", []string{""}, func(out *[]byte, sport ...string) { + if a.removeAllowedBoxPub(sport[0]) == nil { + *out = []byte("Removing key: " + sport[0] + "\n") + } else { + *out = []byte("Failed to remove key: " + sport[0] + "\n") } - } - // Start the TUN adapter - if err := a.startTunWithMTU(ifparams[0], iftapmode, ifmtu); err != nil { - *out = []byte(fmt.Sprintf("Failed to set TUN: %v\n", err)) - } else { - info := admin_nodeInfo{ - {"Interface name", ifparams[0]}, - {"TAP mode", strconv.FormatBool(iftapmode)}, - {"MTU", strconv.Itoa(ifmtu)}, - } - *out = []byte(a.printInfos([]admin_nodeInfo{info})) - } - }) - a.addHandler("getAllowedBoxPubs", nil, func(out *[]byte, _ ...string) { - *out = []byte(a.getAllowedBoxPubs()) - }) - a.addHandler("addAllowedBoxPub", []string{""}, func(out *[]byte, saddr ...string) { - if a.addAllowedBoxPub(saddr[0]) == nil { - *out = []byte("Adding key: " + saddr[0] + "\n") - } else { - *out = []byte("Failed to add key: " + saddr[0] + "\n") - } - }) - a.addHandler("removeAllowedBoxPub", []string{""}, func(out *[]byte, sport ...string) { - if a.removeAllowedBoxPub(sport[0]) == nil { - *out = []byte("Removing key: " + sport[0] + "\n") - } else { - *out = []byte("Failed to remove key: " + sport[0] + "\n") - } - }) + })*/ go a.listen() } @@ -162,49 +205,69 @@ func (a *admin) listen() { } func (a *admin) handleRequest(conn net.Conn) { - buf := make([]byte, 1024) - _, err := conn.Read(buf) - if err != nil { - a.core.log.Printf("Admin socket failed to read: %v", err) - conn.Close() + defer conn.Close() + decoder := json.NewDecoder(conn) + encoder := json.NewEncoder(conn) + encoder.SetIndent("", " ") + recv := make(admin_info) + send := make(admin_info) + + for { + if err := decoder.Decode(&recv); err != nil { + fmt.Println("Admin socket JSON decode error:", err) + return + } + + handlers: + for _, handler := range a.handlers { + if recv["request"] == handler.name { + // Check that we have all the required arguments + for _, arg := range handler.args { + // An argument in 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 { + fmt.Println("Missing required argument", arg) + send = admin_info{ + "error": "Missing field '" + arg + "'", + "fields": handler.args, + } + 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 = admin_info{ + "request": recv["request"], + "error": err.Error(), + } + } else { + send = admin_info{ + "request": recv["request"], + "response": response, + } + } + break + } + } + + if err := encoder.Encode(&send); err != nil { + fmt.Println("Admin socket JSON encode error:", err) + return + } + return } - var out []byte - buf = bytes.Trim(buf, "\x00\r\n\t") - call := strings.Split(string(buf), " ") - var cmd string - var args []string - if len(call) > 0 { - cmd = call[0] - args = call[1:] - } - done := false - for _, handler := range a.handlers { - if cmd == handler.name { - handler.handler(&out, args...) - done = true - break - } - } - if !done { - out = []byte("I didn't understand that!\n") - } - _, err = conn.Write(out) - if err != nil { - a.core.log.Printf("Admin socket error: %v", err) - } - 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 { - m := make(map[string]string, len(*n)) +func (n *admin_nodeInfo) asMap() map[string]interface{} { + m := make(map[string]interface{}, len(*n)) for _, p := range *n { m[p.key] = p.val } @@ -303,7 +366,7 @@ func (a *admin) getData_getSelf() *admin_nodeInfo { addr := a.core.router.addr coords := table.self.getCoords() self := admin_nodeInfo{ - {"IP", net.IP(addr[:]).String()}, + {"ip", net.IP(addr[:]).String()}, {"coords", fmt.Sprint(coords)}, } return &self @@ -321,11 +384,11 @@ func (a *admin) getData_getPeers() []admin_nodeInfo { p := ports[port] addr := *address_addrForNodeID(getNodeID(&p.box)) info := admin_nodeInfo{ - {"IP", net.IP(addr[:]).String()}, - {"port", fmt.Sprint(port)}, + {"ip", net.IP(addr[:]).String()}, + {"port", port}, {"uptime", fmt.Sprint(time.Since(p.firstSeen))}, - {"bytesSent", fmt.Sprint(atomic.LoadUint64(&p.bytesSent))}, - {"bytesRecvd", fmt.Sprint(atomic.LoadUint64(&p.bytesRecvd))}, + {"bytes_sent", atomic.LoadUint64(&p.bytesSent)}, + {"bytes_recvd", atomic.LoadUint64(&p.bytesRecvd)}, } peerInfos = append(peerInfos, info) } @@ -344,9 +407,9 @@ func (a *admin) getData_getSwitchPeers() []admin_nodeInfo { addr := *address_addrForNodeID(getNodeID(&peer.box)) coords := elem.locator.getCoords() info := admin_nodeInfo{ - {"IP", net.IP(addr[:]).String()}, + {"ip", net.IP(addr[:]).String()}, {"coords", fmt.Sprint(coords)}, - {"port", fmt.Sprint(elem.port)}, + {"port", elem.port}, } peerInfos = append(peerInfos, info) } @@ -363,11 +426,11 @@ func (a *admin) getData_getDHT() []admin_nodeInfo { for _, v := range vs { addr := *address_addrForNodeID(v.getNodeID()) info := admin_nodeInfo{ - {"IP", net.IP(addr[:]).String()}, + {"ip", net.IP(addr[:]).String()}, {"coords", fmt.Sprint(v.coords)}, - {"bucket", fmt.Sprint(i)}, - {"peerOnly", fmt.Sprint(isPeer)}, - {"lastSeen", fmt.Sprint(now.Sub(v.recv))}, + {"bucket", i}, + {"peer_only", isPeer}, + {"last_seen", fmt.Sprint(now.Sub(v.recv))}, } infos = append(infos, info) } @@ -386,12 +449,12 @@ func (a *admin) getData_getSessions() []admin_nodeInfo { for _, sinfo := range a.core.sessions.sinfos { // TODO? skipped known but timed out sessions? info := admin_nodeInfo{ - {"IP", net.IP(sinfo.theirAddr[:]).String()}, + {"ip", net.IP(sinfo.theirAddr[:]).String()}, {"coords", fmt.Sprint(sinfo.coords)}, - {"MTU", fmt.Sprint(sinfo.getMTU())}, - {"wasMTUFixed", fmt.Sprint(sinfo.wasMTUFixed)}, - {"bytesSent", fmt.Sprint(sinfo.bytesSent)}, - {"bytesRecvd", fmt.Sprint(sinfo.bytesRecvd)}, + {"mtu", sinfo.getMTU()}, + {"was_mtu_fixed", sinfo.wasMTUFixed}, + {"bytes_sent", sinfo.bytesSent}, + {"bytes_recvd", sinfo.bytesRecvd}, } infos = append(infos, info) } @@ -438,18 +501,18 @@ func (a *admin) getResponse_dot() []byte { sessions := a.getData_getSessions() // Map of coords onto IP m := make(map[string]string) - m[self["coords"]] = self["IP"] + m[self["coords"].(string)] = self["IP"].(string) for _, peer := range peers { p := peer.asMap() - m[p["coords"]] = p["IP"] + m[p["coords"].(string)] = p["IP"].(string) } for _, node := range dht { n := node.asMap() - m[n["coords"]] = n["IP"] + m[n["coords"].(string)] = n["IP"].(string) } for _, node := range sessions { n := node.asMap() - m[n["coords"]] = n["IP"] + m[n["coords"].(string)] = n["IP"].(string) } // Start building a tree from all known nodes From 9713e739695ad1e80fe8d9a3f4503aad96f9fa90 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 17:25:13 +0100 Subject: [PATCH 02/11] Fix dot --- src/yggdrasil/admin.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 633ff7c3..90d0829a 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -501,18 +501,18 @@ func (a *admin) getResponse_dot() []byte { sessions := a.getData_getSessions() // Map of coords onto IP m := make(map[string]string) - m[self["coords"].(string)] = self["IP"].(string) + m[self["coords"].(string)] = self["ip"].(string) for _, peer := range peers { p := peer.asMap() - m[p["coords"].(string)] = p["IP"].(string) + m[p["coords"].(string)] = p["ip"].(string) } for _, node := range dht { n := node.asMap() - m[n["coords"].(string)] = n["IP"].(string) + m[n["coords"].(string)] = n["ip"].(string) } for _, node := range sessions { n := node.asMap() - m[n["coords"].(string)] = n["IP"].(string) + m[n["coords"].(string)] = n["ip"].(string) } // Start building a tree from all known nodes From c3ca5c64b1fc1c3fa975544bfa55381f7f7af52a Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 19:23:43 +0100 Subject: [PATCH 03/11] Add some more functions to JSON admin socket --- src/yggdrasil/admin.go | 63 +++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 90d0829a..880fc281 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -103,21 +103,37 @@ func (a *admin) init(c *Core, listenaddr string) { } return admin_info{"sessions": sessions}, nil }) + a.addHandler("addPeer", []string{"uri"}, func(in admin_info) (admin_info, error) { + if a.addPeer(in["uri"].(string)) == nil { + return admin_info{ + "peers_added": []string{ + in["uri"].(string), + }, + }, nil + } else { + return admin_info{ + "peers_not_added": []string{ + in["uri"].(string), + }, + }, errors.New("Failed to add peer") + } + }) + a.addHandler("removePeer", []string{"port"}, func(in admin_info) (admin_info, error) { + if a.removePeer(fmt.Sprint(in["port"])) == nil { + return admin_info{ + "peers_removed": []string{ + fmt.Sprint(in["port"]), + }, + }, nil + } else { + return admin_info{ + "peers_not_removed": []string{ + fmt.Sprint(in["port"]), + }, + }, errors.New("Failed to remove peer") + } + }) /* - a.addHandler("addPeer", []string{""}, func(out *[]byte, saddr ...string) { - if a.addPeer(saddr[0]) == nil { - *out = []byte("Adding peer: " + saddr[0] + "\n") - } else { - *out = []byte("Failed to add peer: " + saddr[0] + "\n") - } - }) - a.addHandler("removePeer", []string{""}, func(out *[]byte, sport ...string) { - if a.removePeer(sport[0]) == nil { - *out = []byte("Removing peer: " + sport[0] + "\n") - } else { - *out = []byte("Failed to remove peer: " + sport[0] + "\n") - } - }) a.addHandler("getTunTap", nil, func(out *[]byte, _ ...string) { var info admin_nodeInfo defer func() { @@ -218,6 +234,9 @@ func (a *admin) handleRequest(conn net.Conn) { return } + send["request"] = recv + send["status"] = "error" + handlers: for _, handler := range a.handlers { if recv["request"] == handler.name { @@ -232,8 +251,8 @@ func (a *admin) handleRequest(conn net.Conn) { if _, ok := recv[arg]; !ok { fmt.Println("Missing required argument", arg) send = admin_info{ - "error": "Missing field '" + arg + "'", - "fields": handler.args, + "error": "One or more expected fields missing", + "expecting": handler.args, } break handlers } @@ -243,14 +262,14 @@ func (a *admin) handleRequest(conn net.Conn) { // the handler response, err := handler.handler(recv) if err != nil { - send = admin_info{ - "request": recv["request"], - "error": err.Error(), + send["error"] = err.Error() + if response != nil { + send["response"] = response } } else { - send = admin_info{ - "request": recv["request"], - "response": response, + send["status"] = "success" + if response != nil { + send["response"] = response } } break From 4ecc7ce86072df7b406a97c2a11900d9b172859e Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 19:42:37 +0100 Subject: [PATCH 04/11] Add getTunTap to JSON admin socket --- src/yggdrasil/admin.go | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 880fc281..80088a1e 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -2,8 +2,6 @@ package yggdrasil import "net" import "os" - -// import "bytes" import "encoding/hex" import "encoding/json" import "errors" @@ -15,7 +13,6 @@ import "strconv" import "sync/atomic" import "time" -// TODO? Make all of this JSON // TODO: Add authentication type admin struct { @@ -133,25 +130,20 @@ func (a *admin) init(c *Core, listenaddr string) { }, errors.New("Failed to remove peer") } }) - /* - a.addHandler("getTunTap", nil, func(out *[]byte, _ ...string) { - var info admin_nodeInfo - defer func() { - if r := recover(); r != nil { - info = admin_nodeInfo{ - {"Interface name", "none"}, - } - *out = []byte(a.printInfos([]admin_nodeInfo{info})) - } - }() + a.addHandler("getTunTap", nil, func(in admin_info) (r admin_info, e error) { + defer func() { + recover() + r = admin_info{"name": "none"} + e = nil + }() - info = admin_nodeInfo{ - {"Interface name", a.core.tun.iface.Name()}, - {"TAP mode", strconv.FormatBool(a.core.tun.iface.IsTAP())}, - {"mtu", strconv.Itoa(a.core.tun.mtu)}, - } - *out = []byte(a.printInfos([]admin_nodeInfo{info})) - }) + return admin_info{ + "name": a.core.tun.iface.Name(), + "tap_mode": a.core.tun.iface.IsTAP(), + "mtu": a.core.tun.mtu, + }, nil + }) + /* a.addHandler("setTunTap", []string{"", "[]", "[]"}, func(out *[]byte, ifparams ...string) { // Set sane defaults iftapmode := false @@ -184,6 +176,8 @@ func (a *admin) init(c *Core, listenaddr string) { *out = []byte(a.printInfos([]admin_nodeInfo{info})) } }) + */ + /* a.addHandler("getAllowedBoxPubs", nil, func(out *[]byte, _ ...string) { *out = []byte(a.getAllowedBoxPubs()) }) From c75566d5acbb27c8c80a59994ced7a4d06452a7d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 21:44:30 +0100 Subject: [PATCH 05/11] Various fixes and error catching, add setTunTap --- src/yggdrasil/admin.go | 105 +++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 80088a1e..5b800f37 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -143,44 +143,35 @@ func (a *admin) init(c *Core, listenaddr string) { "mtu": a.core.tun.mtu, }, nil }) + a.addHandler("setTunTap", []string{"name", "", ""}, func(in admin_info) (admin_info, error) { + // Set sane defaults + iftapmode := false + ifmtu := getDefaults().defaultIfMTU + // Has TAP mode been specified? + if tap, ok := in["tap_mode"]; ok { + iftapmode = tap.(bool) + } + // Check we have enough params for MTU + if mtu, ok := in["mtu"]; ok { + if mtu.(int) >= 1280 && ifmtu <= getDefaults().maximumIfMTU { + ifmtu = in["mtu"].(int) + } + } + // Start the TUN adapter + if err := a.startTunWithMTU(in["name"].(string), iftapmode, ifmtu); err != nil { + return admin_info{}, errors.New("Failed to configure adapter") + } else { + return admin_info{ + "name": a.core.tun.iface.Name(), + "tap_mode": iftapmode, + "mtu": ifmtu, + }, nil + } + }) + a.addHandler("getAllowedBoxPubs", nil, func(in admin_info) (admin_info, error) { + return admin_info{"allowed_box_pubs": a.getAllowedBoxPubs()}, nil + }) /* - a.addHandler("setTunTap", []string{"", "[]", "[]"}, func(out *[]byte, ifparams ...string) { - // Set sane defaults - iftapmode := false - ifmtu := 1280 - var err error - // Check we have enough params for TAP mode - if len(ifparams) > 1 { - // Is it a TAP adapter? - if ifparams[1] == "tap" { - iftapmode = true - } - } - // Check we have enough params for MTU - if len(ifparams) > 2 { - // Make sure the MTU is sane - ifmtu, err = strconv.Atoi(ifparams[2]) - if err != nil || ifmtu < 1280 || ifmtu > 65535 { - ifmtu = 1280 - } - } - // Start the TUN adapter - if err := a.startTunWithMTU(ifparams[0], iftapmode, ifmtu); err != nil { - *out = []byte(fmt.Sprintf("Failed to set TUN: %v\n", err)) - } else { - info := admin_nodeInfo{ - {"Interface name", ifparams[0]}, - {"TAP mode", strconv.FormatBool(iftapmode)}, - {"mtu", strconv.Itoa(ifmtu)}, - } - *out = []byte(a.printInfos([]admin_nodeInfo{info})) - } - }) - */ - /* - a.addHandler("getAllowedBoxPubs", nil, func(out *[]byte, _ ...string) { - *out = []byte(a.getAllowedBoxPubs()) - }) a.addHandler("addAllowedBoxPub", []string{""}, func(out *[]byte, saddr ...string) { if a.addAllowedBoxPub(saddr[0]) == nil { *out = []byte("Adding key: " + saddr[0] + "\n") @@ -215,24 +206,45 @@ func (a *admin) listen() { } func (a *admin) handleRequest(conn net.Conn) { - defer conn.Close() decoder := json.NewDecoder(conn) encoder := json.NewEncoder(conn) encoder.SetIndent("", " ") 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", + } + if err := encoder.Encode(&send); err != nil { + fmt.Println("Admin socket JSON encode error:", err) + } + 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 } + // Send the request back with the response, and default to "error" + // unless the status is changed below by one of the handlers send["request"] = recv send["status"] = "error" handlers: for _, handler := range a.handlers { + // We've found the handler that matches the request if recv["request"] == handler.name { // Check that we have all the required arguments for _, arg := range handler.args { @@ -243,10 +255,9 @@ func (a *admin) handleRequest(conn net.Conn) { } // Check if the field is missing if _, ok := recv[arg]; !ok { - fmt.Println("Missing required argument", arg) send = admin_info{ - "error": "One or more expected fields missing", - "expecting": handler.args, + "error": "Expected field missing", + "expecting": arg, } break handlers } @@ -266,16 +277,21 @@ func (a *admin) handleRequest(conn net.Conn) { send["response"] = response } } + break } } + // Send the response back if err := encoder.Encode(&send); err != nil { fmt.Println("Admin socket JSON encode error:", err) return } - return + // If "keepalive" isn't true then close the connection + if keepalive, ok := recv["keepalive"]; !ok || !keepalive.(bool) { + conn.Close() + } } } @@ -476,14 +492,13 @@ func (a *admin) getData_getSessions() []admin_nodeInfo { return infos } -func (a *admin) getAllowedBoxPubs() string { +func (a *admin) getAllowedBoxPubs() []string { pubs := a.core.peers.getAllowedBoxPubs() var out []string for _, pub := range pubs { out = append(out, hex.EncodeToString(pub[:])) } - out = append(out, "") - return strings.Join(out, "\n") + return out } func (a *admin) addAllowedBoxPub(bstr string) (err error) { From c765e0566f84592be74b6ae2389ad7d28b7189d1 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 21:54:15 +0100 Subject: [PATCH 06/11] Convert rest of functions, fix setTunTap --- src/yggdrasil/admin.go | 62 ++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 5b800f37..afa8e895 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -103,13 +103,13 @@ func (a *admin) init(c *Core, listenaddr string) { a.addHandler("addPeer", []string{"uri"}, func(in admin_info) (admin_info, error) { if a.addPeer(in["uri"].(string)) == nil { return admin_info{ - "peers_added": []string{ + "added": []string{ in["uri"].(string), }, }, nil } else { return admin_info{ - "peers_not_added": []string{ + "not_added": []string{ in["uri"].(string), }, }, errors.New("Failed to add peer") @@ -118,13 +118,13 @@ func (a *admin) init(c *Core, listenaddr string) { a.addHandler("removePeer", []string{"port"}, func(in admin_info) (admin_info, error) { if a.removePeer(fmt.Sprint(in["port"])) == nil { return admin_info{ - "peers_removed": []string{ + "removed": []string{ fmt.Sprint(in["port"]), }, }, nil } else { return admin_info{ - "peers_not_removed": []string{ + "not_removed": []string{ fmt.Sprint(in["port"]), }, }, errors.New("Failed to remove peer") @@ -145,7 +145,7 @@ func (a *admin) init(c *Core, listenaddr string) { }) a.addHandler("setTunTap", []string{"name", "", ""}, func(in admin_info) (admin_info, error) { // Set sane defaults - iftapmode := false + iftapmode := getDefaults().defaultIfTAPMode ifmtu := getDefaults().defaultIfMTU // Has TAP mode been specified? if tap, ok := in["tap_mode"]; ok { @@ -153,8 +153,8 @@ func (a *admin) init(c *Core, listenaddr string) { } // Check we have enough params for MTU if mtu, ok := in["mtu"]; ok { - if mtu.(int) >= 1280 && ifmtu <= getDefaults().maximumIfMTU { - ifmtu = in["mtu"].(int) + if mtu.(float64) >= 1280 && ifmtu <= getDefaults().maximumIfMTU { + ifmtu = int(in["mtu"].(float64)) } } // Start the TUN adapter @@ -163,7 +163,7 @@ func (a *admin) init(c *Core, listenaddr string) { } else { return admin_info{ "name": a.core.tun.iface.Name(), - "tap_mode": iftapmode, + "tap_mode": a.core.tun.iface.IsTAP(), "mtu": ifmtu, }, nil } @@ -171,21 +171,36 @@ func (a *admin) init(c *Core, listenaddr string) { a.addHandler("getAllowedBoxPubs", nil, func(in admin_info) (admin_info, error) { return admin_info{"allowed_box_pubs": a.getAllowedBoxPubs()}, nil }) - /* - a.addHandler("addAllowedBoxPub", []string{""}, func(out *[]byte, saddr ...string) { - if a.addAllowedBoxPub(saddr[0]) == nil { - *out = []byte("Adding key: " + saddr[0] + "\n") - } else { - *out = []byte("Failed to add key: " + saddr[0] + "\n") - } - }) - a.addHandler("removeAllowedBoxPub", []string{""}, func(out *[]byte, sport ...string) { - if a.removeAllowedBoxPub(sport[0]) == nil { - *out = []byte("Removing key: " + sport[0] + "\n") - } else { - *out = []byte("Failed to remove key: " + sport[0] + "\n") - } - })*/ + a.addHandler("addAllowedBoxPub", []string{"box_pub_key"}, func(in admin_info) (admin_info, error) { + if a.addAllowedBoxPub(in["box_pub_key"].(string)) == nil { + return admin_info{ + "added": []string{ + in["box_pub_key"].(string), + }, + }, nil + } else { + return admin_info{ + "not_added": []string{ + in["box_pub_key"].(string), + }, + }, errors.New("Failed to add allowed box pub key") + } + }) + a.addHandler("removeAllowedBoxPub", []string{"box_pub_key"}, func(in admin_info) (admin_info, error) { + if a.removeAllowedBoxPub(in["box_pub_key"].(string)) == nil { + return admin_info{ + "removed": []string{ + in["box_pub_key"].(string), + }, + }, nil + } else { + return admin_info{ + "not_removed": []string{ + in["box_pub_key"].(string), + }, + }, errors.New("Failed to remove allowed box pub key") + } + }) go a.listen() } @@ -219,6 +234,7 @@ func (a *admin) handleRequest(conn net.Conn) { "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) } From aae570de2a3ec4ab019c9f5e97a870d255ba5a6d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 21:57:05 +0100 Subject: [PATCH 07/11] Optional parameters are now square instead of pointed brackets, avoid nils for help --- src/yggdrasil/admin.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index afa8e895..f06d2ab6 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -50,13 +50,13 @@ func (a *admin) init(c *Core, listenaddr string) { } return admin_info{"handlers": handlers}, nil }) - a.addHandler("dot", nil, 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 }) - a.addHandler("getSelf", nil, func(in admin_info) (admin_info, error) { + a.addHandler("getSelf", []string{}, func(in admin_info) (admin_info, error) { return admin_info{"self": a.getData_getSelf().asMap()}, nil }) - a.addHandler("getPeers", nil, func(in admin_info) (admin_info, error) { + a.addHandler("getPeers", []string{}, func(in admin_info) (admin_info, error) { sort := "ip" peers := make(admin_info) for _, peerdata := range a.getData_getPeers() { @@ -67,7 +67,7 @@ func (a *admin) init(c *Core, listenaddr string) { } return admin_info{"peers": peers}, nil }) - a.addHandler("getSwitchPeers", nil, func(in admin_info) (admin_info, error) { + a.addHandler("getSwitchPeers", []string{}, func(in admin_info) (admin_info, error) { sort := "port" switchpeers := make(admin_info) for _, s := range a.getData_getSwitchPeers() { @@ -78,7 +78,7 @@ func (a *admin) init(c *Core, listenaddr string) { } return admin_info{"switchpeers": switchpeers}, nil }) - a.addHandler("getDHT", nil, func(in admin_info) (admin_info, error) { + a.addHandler("getDHT", []string{}, func(in admin_info) (admin_info, error) { sort := "ip" dht := make(admin_info) for _, d := range a.getData_getDHT() { @@ -89,7 +89,7 @@ func (a *admin) init(c *Core, listenaddr string) { } return admin_info{"dht": dht}, nil }) - a.addHandler("getSessions", nil, func(in admin_info) (admin_info, error) { + a.addHandler("getSessions", []string{}, func(in admin_info) (admin_info, error) { sort := "ip" sessions := make(admin_info) for _, s := range a.getData_getSessions() { @@ -130,7 +130,7 @@ func (a *admin) init(c *Core, listenaddr string) { }, errors.New("Failed to remove peer") } }) - a.addHandler("getTunTap", nil, func(in admin_info) (r admin_info, e error) { + a.addHandler("getTunTap", []string{}, func(in admin_info) (r admin_info, e error) { defer func() { recover() r = admin_info{"name": "none"} @@ -143,7 +143,7 @@ func (a *admin) init(c *Core, listenaddr string) { "mtu": a.core.tun.mtu, }, nil }) - a.addHandler("setTunTap", []string{"name", "", ""}, func(in admin_info) (admin_info, error) { + a.addHandler("setTunTap", []string{"name", "[tap_mode]", "[mtu]"}, func(in admin_info) (admin_info, error) { // Set sane defaults iftapmode := getDefaults().defaultIfTAPMode ifmtu := getDefaults().defaultIfMTU @@ -168,7 +168,7 @@ func (a *admin) init(c *Core, listenaddr string) { }, nil } }) - a.addHandler("getAllowedBoxPubs", nil, func(in admin_info) (admin_info, error) { + a.addHandler("getAllowedBoxPubs", []string{}, func(in admin_info) (admin_info, error) { return admin_info{"allowed_box_pubs": a.getAllowedBoxPubs()}, nil }) a.addHandler("addAllowedBoxPub", []string{"box_pub_key"}, func(in admin_info) (admin_info, error) { @@ -264,9 +264,9 @@ func (a *admin) handleRequest(conn net.Conn) { if recv["request"] == handler.name { // Check that we have all the required arguments for _, arg := range handler.args { - // An argument in is optional and not required, + // An argument in [square brackets] is optional and not required, // so we can safely ignore those - if strings.HasPrefix(arg, "<") && strings.HasSuffix(arg, ">") { + if strings.HasPrefix(arg, "[") && strings.HasSuffix(arg, "]") { continue } // Check if the field is missing From 79131bb959a8db32326fe23dd3d7c1d9c6e039d3 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 23:25:07 +0100 Subject: [PATCH 08/11] Minor tweaks --- src/yggdrasil/admin.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index f06d2ab6..a76ffc49 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -249,7 +249,7 @@ func (a *admin) handleRequest(conn net.Conn) { // Decode the input if err := decoder.Decode(&recv); err != nil { - fmt.Println("Admin socket JSON decode error:", err) + // fmt.Println("Admin socket JSON decode error:", err) return } @@ -272,6 +272,7 @@ func (a *admin) handleRequest(conn net.Conn) { // Check if the field is missing if _, ok := recv[arg]; !ok { send = admin_info{ + "status": "error", "error": "Expected field missing", "expecting": arg, } @@ -300,7 +301,7 @@ func (a *admin) handleRequest(conn net.Conn) { // Send the response back if err := encoder.Encode(&send); err != nil { - fmt.Println("Admin socket JSON encode error:", err) + // fmt.Println("Admin socket JSON encode error:", err) return } From ee99ae008dabe4af13b4af0cb7c9aea65b6014cd Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 23:32:17 +0100 Subject: [PATCH 09/11] Add yggdrasilctl --- yggdrasilctl.go | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 yggdrasilctl.go diff --git a/yggdrasilctl.go b/yggdrasilctl.go new file mode 100644 index 00000000..9914cd8b --- /dev/null +++ b/yggdrasilctl.go @@ -0,0 +1,69 @@ +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() + + 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 { + 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) +} From cda7a2abccae4a4c833c0a81fe494e952f70cafe Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 23:46:02 +0100 Subject: [PATCH 10/11] Builds for yggdrasilctl plus usage info and fixes --- .circleci/config.yml | 30 +++++++++++++++--------------- contrib/deb/generate.sh | 1 + yggdrasilctl.go | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5773c6b1..93aa264c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,42 +21,42 @@ jobs: - run: name: Build for Linux (including Debian packages) command: | - PKGARCH=amd64 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-amd64; - PKGARCH=i386 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-i386; - PKGARCH=mipsel sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mipsel; - PKGARCH=mips sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mips; - PKGARCH=armhf sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-armhf; + PKGARCH=amd64 sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-amd64; + PKGARCH=i386 sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-i386; + PKGARCH=mipsel sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-mipsel; + PKGARCH=mips sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-mips; + PKGARCH=armhf sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-armhf; mv *.deb /tmp/upload/ - run: name: Build for macOS command: | - GOOS=darwin GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-amd64; - GOOS=darwin GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-i386; + GOOS=darwin GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-darwin-amd64; + GOOS=darwin GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-darwin-i386; - run: name: Build for OpenBSD command: | - GOOS=openbsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-openbsd-amd64; - GOOS=openbsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-openbsd-i386; + GOOS=openbsd GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-openbsd-amd64; + GOOS=openbsd GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-openbsd-i386; - run: name: Build for FreeBSD command: | - GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64; - GOOS=freebsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-i386; + GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64; + GOOS=freebsd GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-freebsd-i386; - run: name: Build for NetBSD command: | - GOOS=netbsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-amd64; - GOOS=netbsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-i386; + GOOS=netbsd GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-netbsd-amd64; + GOOS=netbsd GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-netbsd-i386; - run: name: Build for Windows command: | - GOOS=windows GOARCH=amd64 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-amd64.exe; - GOOS=windows GOARCH=386 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-i386.exe; + GOOS=windows GOARCH=amd64 ./build && mv yggdrasil.exe yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-windows-amd64.exe; + GOOS=windows GOARCH=386 ./build && mv yggdrasil.exe yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-windows-i386.exe; - run: name: Build for EdgeRouter diff --git a/contrib/deb/generate.sh b/contrib/deb/generate.sh index c46aa247..860d4f1e 100644 --- a/contrib/deb/generate.sh +++ b/contrib/deb/generate.sh @@ -69,6 +69,7 @@ systemctl stop yggdrasil EOF 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-resume.service /tmp/$PKGNAME/etc/systemd/system/ diff --git a/yggdrasilctl.go b/yggdrasilctl.go index 9914cd8b..9d3f3281 100644 --- a/yggdrasilctl.go +++ b/yggdrasilctl.go @@ -15,6 +15,14 @@ func main() { 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) @@ -50,6 +58,14 @@ func main() { 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"] { From ab3eb9877a16eb438234a04c5a48a98ecda94e4f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 20 May 2018 23:59:42 +0100 Subject: [PATCH 11/11] Fix builds --- .circleci/config.yml | 30 +++++++++++++++--------------- contrib/deb/generate.sh | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 93aa264c..5773c6b1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,42 +21,42 @@ jobs: - run: name: Build for Linux (including Debian packages) command: | - PKGARCH=amd64 sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-amd64; - PKGARCH=i386 sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-i386; - PKGARCH=mipsel sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-mipsel; - PKGARCH=mips sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-mips; - PKGARCH=armhf sh contrib/deb/generate.sh && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-linux-armhf; + PKGARCH=amd64 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-amd64; + PKGARCH=i386 sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-i386; + PKGARCH=mipsel sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mipsel; + PKGARCH=mips sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-mips; + PKGARCH=armhf sh contrib/deb/generate.sh && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-linux-armhf; mv *.deb /tmp/upload/ - run: name: Build for macOS command: | - GOOS=darwin GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-darwin-amd64; - GOOS=darwin GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-darwin-i386; + GOOS=darwin GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-amd64; + GOOS=darwin GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-darwin-i386; - run: name: Build for OpenBSD command: | - GOOS=openbsd GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-openbsd-amd64; - GOOS=openbsd GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-openbsd-i386; + GOOS=openbsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-openbsd-amd64; + GOOS=openbsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-openbsd-i386; - run: name: Build for FreeBSD command: | - GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64; - GOOS=freebsd GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-freebsd-i386; + GOOS=freebsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-amd64; + GOOS=freebsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-freebsd-i386; - run: name: Build for NetBSD command: | - GOOS=netbsd GOARCH=amd64 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-netbsd-amd64; - GOOS=netbsd GOARCH=386 ./build && mv yggdrasil yggdrasilctl /tmp/upload/$CINAME-$CIVERSION-netbsd-i386; + GOOS=netbsd GOARCH=amd64 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-amd64; + GOOS=netbsd GOARCH=386 ./build && mv yggdrasil /tmp/upload/$CINAME-$CIVERSION-netbsd-i386; - run: name: Build for Windows command: | - GOOS=windows GOARCH=amd64 ./build && mv yggdrasil.exe yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-windows-amd64.exe; - GOOS=windows GOARCH=386 ./build && mv yggdrasil.exe yggdrasilctl.exe /tmp/upload/$CINAME-$CIVERSION-windows-i386.exe; + GOOS=windows GOARCH=amd64 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-amd64.exe; + GOOS=windows GOARCH=386 ./build && mv yggdrasil.exe /tmp/upload/$CINAME-$CIVERSION-windows-i386.exe; - run: name: Build for EdgeRouter diff --git a/contrib/deb/generate.sh b/contrib/deb/generate.sh index 860d4f1e..100e8cc7 100644 --- a/contrib/deb/generate.sh +++ b/contrib/deb/generate.sh @@ -54,7 +54,7 @@ cat > /tmp/$PKGNAME/debian/docs << EOF Please see https://github.com/Arceliar/yggdrasil-go/ 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 EOF cat > /tmp/$PKGNAME/debian/postinst << EOF @@ -74,7 +74,7 @@ cp contrib/systemd/yggdrasil.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/ \ - usr/bin/yggdrasil \ + usr/bin/yggdrasil usr/bin/yggdrasilctl \ etc/systemd/system/yggdrasil.service \ etc/systemd/system/yggdrasil-resume.service tar -czvf /tmp/$PKGNAME/control.tar.gz -C /tmp/$PKGNAME/debian .