More wiring up of addroot/removeroot etc.

This commit is contained in:
Adam Ierymenko 2020-01-24 13:27:01 -08:00
parent 5c6bf9d0a4
commit e9656ecf11
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
13 changed files with 122 additions and 123 deletions

View file

@ -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) {
}

View file

@ -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?

View file

@ -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 := ""
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 lastRX < 0 {
lastRX = 0
}
address = fmt.Sprintf("%s/%d", peer.Paths[0].IP.String(), peer.Paths[0].Port)
root := ""
if peer.Root {
root = " *"
}
fmt.Printf("%.10x %-7s %-6s %-5d %-6s %-8d %-8d %s\n",
var paths strings.Builder
if len(peer.Paths) > 0 {
if paths.Len() > 0 {
paths.WriteRune(' ')
}
paths.WriteString(fmt.Sprintf("%s/%d", peer.Paths[0].IP.String(), peer.Paths[0].Port))
} else {
paths.WriteString("(relayed)")
}
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())
}
}

View file

@ -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) {
}

View file

@ -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) {
}

View file

@ -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)
}

View file

@ -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":

View file

@ -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)

View file

@ -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)

View file

@ -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))

View file

@ -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"`
}

View file

@ -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

View file

@ -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;