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 service Start as service
status Show ZeroTier status and config status Show ZeroTier status and config
peers Show VL1 peers and link information 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 join <network ID> Join a virtual network
leave <network ID> Leave a virtual network leave <network ID> Leave a virtual network
networks List joined VL2 virtual networks networks List joined VL2 virtual networks
network <network ID> Show verbose network info 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 set <network ID> [option] [value] Get or set a network config option
manageips <boolean> Is IP management allowed? manageips <boolean> Is IP management allowed?
manageroutes <boolean> Is route management allowed? manageroutes <boolean> Is route management allowed?

View file

@ -16,45 +16,52 @@ package cli
import ( import (
"fmt" "fmt"
"os" "os"
"strings"
"zerotier/pkg/zerotier" "zerotier/pkg/zerotier"
) )
// Peers CLI command // Peers CLI command (also used for 'roots' command with rootsOnly set to true)
func Peers(basePath, authToken string, args []string, jsonOutput bool) { func Peers(basePath, authToken string, args []string, jsonOutput bool, rootsOnly bool) {
var peers []zerotier.Peer 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 { if jsonOutput {
fmt.Println(jsonDump(&peers)) fmt.Println(jsonDump(&peers))
} else { } 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 { for _, peer := range peers {
role := "LEAF" root := ""
link := "RELAY" if peer.Root {
lastTX, lastRX := int64(0), int64(0) root = " *"
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)
} }
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), uint64(peer.Address),
fmt.Sprintf("%d.%d.%d", peer.Version[0], peer.Version[1], peer.Version[2]), fmt.Sprintf("%d.%d.%d", peer.Version[0], peer.Version[1], peer.Version[2]),
role, root,
peer.Latency, peer.Latency,
link, paths.String())
lastTX,
lastRX,
address,
)
} }
} }

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) cli.Status(basePath, authToken, cmdArgs, *jflag)
case "peers", "listpeers": case "peers", "listpeers":
authTokenRequired(authToken) authTokenRequired(authToken)
cli.Peers(basePath, authToken, cmdArgs, *jflag) cli.Peers(basePath, authToken, cmdArgs, *jflag, false)
case "roots", "listroots": case "roots", "listroots":
authTokenRequired(authToken) authTokenRequired(authToken)
cli.Roots(basePath, authToken, cmdArgs, *jflag) cli.Peers(basePath, authToken, cmdArgs, *jflag, true)
case "addroot": case "addroot":
authTokenRequired(authToken) authTokenRequired(authToken)
cli.AddRoot(basePath, authToken, cmdArgs) cli.SetRoot(basePath, authToken, cmdArgs, true)
case "removeroot": case "removeroot":
authTokenRequired(authToken) authTokenRequired(authToken)
cli.RemoveRoot(basePath, authToken, cmdArgs) cli.SetRoot(basePath, authToken, cmdArgs, false)
case "identity": case "identity":
cli.Identity(cmdArgs) cli.Identity(cmdArgs)
case "networks", "listnetworks": case "networks", "listnetworks":

View file

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

View file

@ -105,6 +105,11 @@ type InetAddress struct {
Port int 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 // Less returns true if this IP/port is lexicographically less than another
func (ina *InetAddress) Less(i2 *InetAddress) bool { func (ina *InetAddress) Less(i2 *InetAddress) bool {
c := bytes.Compare(ina.IP, i2.IP) 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 // This map is used to get the Go Node object from a pointer passed back in via C callbacks
nodesByUserPtr = make(map[uintptr]*Node) nodesByUserPtr = make(map[uintptr]*Node)
nodesByUserPtrCtr = uintptr(0)
nodesByUserPtrLock sync.RWMutex nodesByUserPtrLock sync.RWMutex
) )
@ -130,6 +131,9 @@ type Node struct {
// runWaitGroup is used to wait for all node goroutines on shutdown // runWaitGroup is used to wait for all node goroutines on shutdown
runWaitGroup sync.WaitGroup 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 // 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() nodesByUserPtrLock.Lock()
nodesByUserPtr[uintptr(unsafe.Pointer(n))] = n nodesByUserPtrCtr++
n.cPtr = nodesByUserPtrCtr
nodesByUserPtr[n.cPtr] = n
nodesByUserPtrLock.Unlock() nodesByUserPtrLock.Unlock()
// Instantiate GoNode and friends from the land of C/C++
cPath := C.CString(basePath) 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)) C.free(unsafe.Pointer(cPath))
if n.gn == nil { if n.gn == nil {
n.infoLog.Println("FATAL: node initialization failed") n.infoLog.Println("FATAL: node initialization failed")
nodesByUserPtrLock.Lock() nodesByUserPtrLock.Lock()
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n))) delete(nodesByUserPtr, n.cPtr)
nodesByUserPtrLock.Unlock() nodesByUserPtrLock.Unlock()
return nil, ErrNodeInitFailed return nil, ErrNodeInitFailed
} }
@ -261,7 +266,7 @@ func NewNode(basePath string) (n *Node, err error) {
if err != nil { if err != nil {
n.infoLog.Printf("FATAL: error obtaining node's identity") n.infoLog.Printf("FATAL: error obtaining node's identity")
nodesByUserPtrLock.Lock() nodesByUserPtrLock.Lock()
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n))) delete(nodesByUserPtr, n.cPtr)
nodesByUserPtrLock.Unlock() nodesByUserPtrLock.Unlock()
C.ZT_GoNode_delete(n.gn) C.ZT_GoNode_delete(n.gn)
return nil, err return nil, err
@ -600,7 +605,7 @@ func (n *Node) Peers() []*Peer {
p2.IdentityHash = hex.EncodeToString((*[48]byte)(unsafe.Pointer(&p.identityHash[0]))[:]) 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.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)}
p2.Latency = int(p.latency) p2.Latency = int(p.latency)
p2.Role = int(p.role) p2.Root = p.root != 0
p2.Bootstrap = NewInetAddressFromSockaddr(unsafe.Pointer(&p.bootstrap)) p2.Bootstrap = NewInetAddressFromSockaddr(unsafe.Pointer(&p.bootstrap))
p2.Paths = make([]Path, 0, int(p.pathCount)) p2.Paths = make([]Path, 0, int(p.pathCount))

View file

@ -13,14 +13,6 @@
package zerotier 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 // Peer is another ZeroTier node
type Peer struct { type Peer struct {
Address Address `json:"address"` Address Address `json:"address"`
@ -28,7 +20,14 @@ type Peer struct {
IdentityHash string `json:"identityHash"` IdentityHash string `json:"identityHash"`
Version [3]int `json:"version"` Version [3]int `json:"version"`
Latency int `json:"latency"` Latency int `json:"latency"`
Role int `json:"role"` Root bool `json:"root"`
Bootstrap *InetAddress `json:"bootstrap,omitempty"` Bootstrap *InetAddress `json:"bootstrap,omitempty"`
Paths []Path `json:"paths,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; int preferred;
} ZT_PeerPhysicalPath; } 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 * Peer status result buffer
*/ */
@ -1373,9 +1364,9 @@ typedef struct
int latency; 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 * Bootstrap address

View file

@ -446,7 +446,7 @@ ZT_PeerList *Node::peers() const
p->latency = (int)(*pi)->latency(); p->latency = (int)(*pi)->latency();
if (p->latency >= 0xffff) if (p->latency >= 0xffff)
p->latency = -1; 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)); memcpy(&p->bootstrap,&((*pi)->bootstrap()),sizeof(sockaddr_storage));
std::vector< SharedPtr<Path> > paths; std::vector< SharedPtr<Path> > paths;