Browse Source

More wiring up of addroot/removeroot etc.

Adam Ierymenko 5 years ago
parent
commit
e9656ecf11

+ 0 - 18
go/cmd/zerotier/cli/addroot.go

@@ -1,18 +0,0 @@
-/*
- * Copyright (c)2013-2020 ZeroTier, Inc.
- *
- * Use of this software is governed by the Business Source License included
- * in the LICENSE.TXT file in the project's root directory.
- *
- * Change Date: 2024-01-01
- *
- * On the date above, in accordance with the Business Source License, use
- * of this software will be governed by version 2.0 of the Apache License.
- */
-/****/
-
-package cli
-
-// AddRoot CLI command
-func AddRoot(basePath, authToken string, args []string) {
-}

+ 3 - 3
go/cmd/zerotier/cli/help.go

@@ -41,13 +41,13 @@ Commands:
   service                              Start as service
   status                               Show ZeroTier status and config
   peers                                Show VL1 peers and link information
+  roots                                Show only root peers
+  addroot <identity> [IP/port]         Add root with optional bootstrap IP
+  removeroot <address|identity>        Remove root
   join <network ID>                    Join a virtual network
   leave <network ID>                   Leave a virtual network
   networks                             List joined VL2 virtual networks
   network <network ID>                 Show verbose network info
-  addroot <identity> [IP/port]         Add root with optional bootstrap IP
-  removeroot <identity|address>        Remove root
-  roots                                Show configured VL1 root servers
   set <network ID> [option] [value]    Get or set a network config option
     manageips <boolean>                Is IP management allowed?
     manageroutes <boolean>             Is route management allowed?

+ 30 - 23
go/cmd/zerotier/cli/peers.go

@@ -16,45 +16,52 @@ package cli
 import (
 	"fmt"
 	"os"
+	"strings"
 
 	"zerotier/pkg/zerotier"
 )
 
-// Peers CLI command
-func Peers(basePath, authToken string, args []string, jsonOutput bool) {
+// Peers CLI command (also used for 'roots' command with rootsOnly set to true)
+func Peers(basePath, authToken string, args []string, jsonOutput bool, rootsOnly bool) {
 	var peers []zerotier.Peer
-	clock := apiGet(basePath, authToken, "/peer", &peers)
+	apiGet(basePath, authToken, "/peer", &peers)
+
+	if rootsOnly {
+		roots := make([]zerotier.Peer, 0, len(peers))
+		for i := range peers {
+			if peers[i].Root {
+				roots = append(roots, peers[i])
+			}
+		}
+		peers = roots
+	}
 
 	if jsonOutput {
 		fmt.Println(jsonDump(&peers))
 	} else {
-		fmt.Printf("<address>  <ver>   <role> <lat> <link> <lastTX> <lastRX> <path(s)>\n")
+		fmt.Printf("<address>  <ver>   <root> <lat(ms)> <path(s)>\n")
 		for _, peer := range peers {
-			role := "LEAF"
-			link := "RELAY"
-			lastTX, lastRX := int64(0), int64(0)
-			address := ""
+			root := ""
+			if peer.Root {
+				root = " *"
+			}
+
+			var paths strings.Builder
 			if len(peer.Paths) > 0 {
-				link = "DIRECT"
-				lastTX, lastRX = clock-peer.Paths[0].LastSend, clock-peer.Paths[0].LastReceive
-				if lastTX < 0 {
-					lastTX = 0
+				if paths.Len() > 0 {
+					paths.WriteRune(' ')
 				}
-				if lastRX < 0 {
-					lastRX = 0
-				}
-				address = fmt.Sprintf("%s/%d", peer.Paths[0].IP.String(), peer.Paths[0].Port)
+				paths.WriteString(fmt.Sprintf("%s/%d", peer.Paths[0].IP.String(), peer.Paths[0].Port))
+			} else {
+				paths.WriteString("(relayed)")
 			}
-			fmt.Printf("%.10x %-7s %-6s %-5d %-6s %-8d %-8d %s\n",
+
+			fmt.Printf("%.10x %-7s %-6s %-9d %s\n",
 				uint64(peer.Address),
 				fmt.Sprintf("%d.%d.%d", peer.Version[0], peer.Version[1], peer.Version[2]),
-				role,
+				root,
 				peer.Latency,
-				link,
-				lastTX,
-				lastRX,
-				address,
-			)
+				paths.String())
 		}
 	}
 

+ 0 - 18
go/cmd/zerotier/cli/removeroot.go

@@ -1,18 +0,0 @@
-/*
- * Copyright (c)2013-2020 ZeroTier, Inc.
- *
- * Use of this software is governed by the Business Source License included
- * in the LICENSE.TXT file in the project's root directory.
- *
- * Change Date: 2024-01-01
- *
- * On the date above, in accordance with the Business Source License, use
- * of this software will be governed by version 2.0 of the Apache License.
- */
-/****/
-
-package cli
-
-// RemoveRoot CLI command
-func RemoveRoot(basePath, authToken string, args []string) {
-}

+ 0 - 18
go/cmd/zerotier/cli/roots.go

@@ -1,18 +0,0 @@
-/*
- * Copyright (c)2013-2020 ZeroTier, Inc.
- *
- * Use of this software is governed by the Business Source License included
- * in the LICENSE.TXT file in the project's root directory.
- *
- * Change Date: 2024-01-01
- *
- * On the date above, in accordance with the Business Source License, use
- * of this software will be governed by version 2.0 of the Apache License.
- */
-/****/
-
-package cli
-
-// Roots CLI command
-func Roots(basePath, authToken string, args []string, jsonOutput bool) {
-}

+ 52 - 0
go/cmd/zerotier/cli/setroot.go

@@ -0,0 +1,52 @@
+/*
+ * Copyright (c)2013-2020 ZeroTier, Inc.
+ *
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
+ *
+ * Change Date: 2024-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+package cli
+
+import (
+	"fmt"
+	"os"
+
+	"zerotier/pkg/zerotier"
+)
+
+// SetRoot CLI command, used for addroot and removeroot.
+func SetRoot(basePath, authToken string, args []string, root bool) {
+	if len(args) < 1 || len(args) > 2 {
+		Help()
+		os.Exit(1)
+	}
+
+	id := readIdentity(args[0])
+	if id == nil {
+		fmt.Printf("ERROR: invalid identity '%s' (tried literal or reading as file)\n",args[0])
+		os.Exit(1)
+	}
+
+	var bootstrap *zerotier.InetAddress
+	if len(args) == 2 {
+		bootstrap = zerotier.NewInetAddressFromString(args[1])
+		if bootstrap == nil || bootstrap.Nil() {
+			fmt.Printf("ERROR: invalid bootstrap address '%s'\n",args[1])
+			os.Exit(1)
+		}
+	}
+
+	var peer zerotier.PeerMutableFields
+	peer.Identity = id
+	peer.Bootstrap = bootstrap
+	peer.Root = &root
+	apiPost(basePath, authToken, "/peer/"+id.Address().String(), &peer, nil)
+	fmt.Printf("OK %s", id.String())
+	os.Exit(0)
+}

+ 4 - 4
go/cmd/zerotier/zerotier.go

@@ -133,16 +133,16 @@ func main() {
 		cli.Status(basePath, authToken, cmdArgs, *jflag)
 	case "peers", "listpeers":
 		authTokenRequired(authToken)
-		cli.Peers(basePath, authToken, cmdArgs, *jflag)
+		cli.Peers(basePath, authToken, cmdArgs, *jflag, false)
 	case "roots", "listroots":
 		authTokenRequired(authToken)
-		cli.Roots(basePath, authToken, cmdArgs, *jflag)
+		cli.Peers(basePath, authToken, cmdArgs, *jflag, true)
 	case "addroot":
 		authTokenRequired(authToken)
-		cli.AddRoot(basePath, authToken, cmdArgs)
+		cli.SetRoot(basePath, authToken, cmdArgs, true)
 	case "removeroot":
 		authTokenRequired(authToken)
-		cli.RemoveRoot(basePath, authToken, cmdArgs)
+		cli.SetRoot(basePath, authToken, cmdArgs, false)
 	case "identity":
 		cli.Identity(cmdArgs)
 	case "networks", "listnetworks":

+ 4 - 10
go/pkg/zerotier/api.go

@@ -226,12 +226,6 @@ func apiCheckAuth(out http.ResponseWriter, req *http.Request, token string) bool
 	return false
 }
 
-type peerMutableFields struct {
-	Identity  *Identity    `json:"identity"`
-	Role      *int         `json:"role"`
-	Bootstrap *InetAddress `json:"bootstrap,omitempty"`
-}
-
 // createAPIServer creates and starts an HTTP server for a given node
 func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, error) {
 	// Read authorization token, automatically generating one if it's missing
@@ -372,14 +366,14 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
 				_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"peer not found"})
 				return
 			}
-			var peerChanges peerMutableFields
+			var peerChanges PeerMutableFields
 			if apiReadObj(out, req, &peerChanges) == nil {
-				if peerChanges.Role != nil || peerChanges.Bootstrap != nil {
+				if peerChanges.Root != nil || peerChanges.Bootstrap != nil {
 					peers := node.Peers()
 					for _, p := range peers {
 						if p.Address == queriedID && (peerChanges.Identity == nil || peerChanges.Identity.Equals(p.Identity)) {
-							if peerChanges.Role != nil && *peerChanges.Role != p.Role {
-								if *peerChanges.Role == PeerRoleRoot {
+							if peerChanges.Root != nil && *peerChanges.Root != p.Root {
+								if *peerChanges.Root {
 									_ = node.AddRoot(p.Identity, peerChanges.Bootstrap)
 								} else {
 									node.RemoveRoot(p.Identity)

+ 5 - 0
go/pkg/zerotier/inetaddress.go

@@ -105,6 +105,11 @@ type InetAddress struct {
 	Port int
 }
 
+// Nil returns true if this InetAddress is empty.
+func (ina *InetAddress) Nil() bool {
+	return len(ina.IP) == 0
+}
+
 // Less returns true if this IP/port is lexicographically less than another
 func (ina *InetAddress) Less(i2 *InetAddress) bool {
 	c := bytes.Compare(ina.IP, i2.IP)

+ 11 - 6
go/pkg/zerotier/node.go

@@ -80,6 +80,7 @@ var (
 
 	// This map is used to get the Go Node object from a pointer passed back in via C callbacks
 	nodesByUserPtr     = make(map[uintptr]*Node)
+	nodesByUserPtrCtr  = uintptr(0)
 	nodesByUserPtrLock sync.RWMutex
 )
 
@@ -130,6 +131,9 @@ type Node struct {
 
 	// runWaitGroup is used to wait for all node goroutines on shutdown
 	runWaitGroup sync.WaitGroup
+
+	// an arbitrary uintptr given to the core as its pointer back to Go's Node instance
+	cPtr uintptr
 }
 
 // NewNode creates and initializes a new instance of the ZeroTier node service
@@ -242,17 +246,18 @@ func NewNode(basePath string) (n *Node, err error) {
 	}
 
 	nodesByUserPtrLock.Lock()
-	nodesByUserPtr[uintptr(unsafe.Pointer(n))] = n
+	nodesByUserPtrCtr++
+	n.cPtr = nodesByUserPtrCtr
+	nodesByUserPtr[n.cPtr] = n
 	nodesByUserPtrLock.Unlock()
 
-	// Instantiate GoNode and friends from the land of C/C++
 	cPath := C.CString(basePath)
-	n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(uintptr(unsafe.Pointer(n))))
+	n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(n.cPtr))
 	C.free(unsafe.Pointer(cPath))
 	if n.gn == nil {
 		n.infoLog.Println("FATAL: node initialization failed")
 		nodesByUserPtrLock.Lock()
-		delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
+		delete(nodesByUserPtr, n.cPtr)
 		nodesByUserPtrLock.Unlock()
 		return nil, ErrNodeInitFailed
 	}
@@ -261,7 +266,7 @@ func NewNode(basePath string) (n *Node, err error) {
 	if err != nil {
 		n.infoLog.Printf("FATAL: error obtaining node's identity")
 		nodesByUserPtrLock.Lock()
-		delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
+		delete(nodesByUserPtr, n.cPtr)
 		nodesByUserPtrLock.Unlock()
 		C.ZT_GoNode_delete(n.gn)
 		return nil, err
@@ -600,7 +605,7 @@ func (n *Node) Peers() []*Peer {
 			p2.IdentityHash = hex.EncodeToString((*[48]byte)(unsafe.Pointer(&p.identityHash[0]))[:])
 			p2.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)}
 			p2.Latency = int(p.latency)
-			p2.Role = int(p.role)
+			p2.Root = p.root != 0
 			p2.Bootstrap = NewInetAddressFromSockaddr(unsafe.Pointer(&p.bootstrap))
 
 			p2.Paths = make([]Path, 0, int(p.pathCount))

+ 8 - 9
go/pkg/zerotier/peer.go

@@ -13,14 +13,6 @@
 
 package zerotier
 
-// Peer roles must be the same as in ZeroTierCore.h.
-
-// PeerRoleLeaf indicates a normal leaf node.
-const PeerRoleLeaf = 0
-
-// PeerRoleRoot indicates a root peer.
-const PeerRoleRoot = 1
-
 // Peer is another ZeroTier node
 type Peer struct {
 	Address      Address      `json:"address"`
@@ -28,7 +20,14 @@ type Peer struct {
 	IdentityHash string       `json:"identityHash"`
 	Version      [3]int       `json:"version"`
 	Latency      int          `json:"latency"`
-	Role         int          `json:"role"`
+	Root         bool         `json:"root"`
 	Bootstrap    *InetAddress `json:"bootstrap,omitempty"`
 	Paths        []Path       `json:"paths,omitempty"`
 }
+
+// PeerMutableFields contains only the mutable fields of Peer as nullable pointers.
+type PeerMutableFields struct {
+	Identity  *Identity    `json:"identity"`
+	Root      *bool        `json:"root"`
+	Bootstrap *InetAddress `json:"bootstrap,omitempty"`
+}

+ 2 - 11
include/ZeroTierCore.h

@@ -1323,15 +1323,6 @@ typedef struct
 	int preferred;
 } ZT_PeerPhysicalPath;
 
-/**
- * What trust hierarchy role does this peer have?
- */
-enum ZT_PeerRole
-{
-	ZT_PEER_ROLE_LEAF = 0,
-	ZT_PEER_ROLE_ROOT = 1
-};
-
 /**
  * Peer status result buffer
  */
@@ -1373,9 +1364,9 @@ typedef struct
 	int latency;
 
 	/**
-	 * What trust hierarchy role does this device have?
+	 * If non-zero this peer is a root
 	 */
-	enum ZT_PeerRole role;
+	int root;
 
 	/**
 	 * Bootstrap address

+ 1 - 1
node/Node.cpp

@@ -446,7 +446,7 @@ ZT_PeerList *Node::peers() const
 		p->latency = (int)(*pi)->latency();
 		if (p->latency >= 0xffff)
 			p->latency = -1;
-		p->role = RR->topology->isRoot((*pi)->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF;
+		p->root = RR->topology->isRoot((*pi)->identity()) ? 1 : 0;
 		memcpy(&p->bootstrap,&((*pi)->bootstrap()),sizeof(sockaddr_storage));
 
 		std::vector< SharedPtr<Path> > paths;