Browse Source

Root admin stuff

Adam Ierymenko 5 years ago
parent
commit
b0d222768a

+ 10 - 11
go/cmd/zerotier/cli/help.go

@@ -24,14 +24,14 @@ Licensed under the ZeroTier BSL (see LICENSE.txt)`, zerotier.CoreVersionMajor, z
 
 
 // Help dumps help to stdout
 // Help dumps help to stdout
 func Help() {
 func Help() {
-	fmt.Println(copyrightText + `
-
+	fmt.Println(copyrightText)
+	fmt.Println(`
 Usage: zerotier [-options] <command> [-options] [command args]
 Usage: zerotier [-options] <command> [-options] [command args]
 
 
 Global Options:
 Global Options:
   -j                                   Output raw JSON where applicable
   -j                                   Output raw JSON where applicable
   -p <path>                            Use alternate base path
   -p <path>                            Use alternate base path
-  -t <authtoken.secret path>           Use secret auth token from this file
+  -t <path>                            Use secret auth token from this file
 
 
 Commands:
 Commands:
   help                                 Show this help
   help                                 Show this help
@@ -40,12 +40,11 @@ Commands:
   status                               Show ZeroTier service status and config
   status                               Show ZeroTier service status and config
   peers                                Show VL1 peers
   peers                                Show VL1 peers
   roots                                Show VL1 root servers
   roots                                Show VL1 root servers
-  addroot <type> [options]             Add a VL1 root
-    static <identity> <ip/port> [...]  Add a root with a set identity and IPs
-    dynamic <name> [default locator]   Add a dynamic root fetched by name
-  removeroot <type> [options]          Remove a VL1 root
-    static <identity>                  Remove a root with a set identity
-    dynamic <name>                     Remove a dynamic root fetched by name
+  addroot <locator> [<name>]           Add a VL1 root
+  removeroot <name>                    Remove a VL1 root
+  makelocator <secret> <address> [...] Make and sign a locator
+  makelocatordnskey                    Create a new secure DNS name and key
+  makelocatordns <key> <locator>       Make DNS TXT records for a locator
   networks                             Show joined VL2 virtual networks
   networks                             Show joined VL2 virtual networks
   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
@@ -71,6 +70,6 @@ Most commands require a secret token to permit control of a running ZeroTier
 service. The CLI will automatically try to read this token from the
 service. The CLI will automatically try to read this token from the
 authtoken.secret file in the service's working directory and then from a
 authtoken.secret file in the service's working directory and then from a
 file called .zerotierauth in the user's home directory. The -t option can be
 file called .zerotierauth in the user's home directory. The -t option can be
-used to explicitly specify a location.
-`)
+used to explicitly specify a location.`)
+	fmt.Println()
 }
 }

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

@@ -0,0 +1,18 @@
+/*
+ * Copyright (c)2019 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: 2023-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
+
+// MakeLocator CLI command
+func MakeLocator(args []string) {
+}

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

@@ -0,0 +1,18 @@
+/*
+ * Copyright (c)2019 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: 2023-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
+
+// MakeLocatorDNS CLI command
+func MakeLocatorDNS(args []string) {
+}

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

@@ -0,0 +1,18 @@
+/*
+ * Copyright (c)2019 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: 2023-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
+
+// MakeLocatorDNSKey CLI command
+func MakeLocatorDNSKey(args []string) {
+}

+ 6 - 0
go/cmd/zerotier/zerotier.go

@@ -121,6 +121,12 @@ func main() {
 	case "removeroot":
 	case "removeroot":
 		authTokenRequired(authToken)
 		authTokenRequired(authToken)
 		cli.RemoveRoot(basePath, authToken, cmdArgs)
 		cli.RemoveRoot(basePath, authToken, cmdArgs)
+	case "makelocator":
+		cli.MakeLocator(cmdArgs)
+	case "makelocatordnskey":
+		cli.MakeLocatorDNSKey(cmdArgs)
+	case "makelocatordns":
+		cli.MakeLocatorDNS(cmdArgs)
 	case "networks", "listnetworks":
 	case "networks", "listnetworks":
 		authTokenRequired(authToken)
 		authTokenRequired(authToken)
 		cli.Networks(basePath, authToken, cmdArgs)
 		cli.Networks(basePath, authToken, cmdArgs)

+ 15 - 4
go/native/GoGlue.cpp

@@ -730,9 +730,9 @@ int ZT_GoLocator_makeSecureDNSName(char *name,unsigned int nameBufSize,uint8_t *
 	uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE];
 	uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE];
 	ECC384GenerateKey(pub,privateKey);
 	ECC384GenerateKey(pub,privateKey);
 	const Str n(Locator::makeSecureDnsName(pub));
 	const Str n(Locator::makeSecureDnsName(pub));
-	if (n.size() >= nameBufSize)
+	if (n.length() >= nameBufSize)
 		return -1;
 		return -1;
-	Utils::scopy(name,sizeof(name),n.c_Str());
+	Utils::scopy(name,sizeof(name),n.c_str());
 	return ZT_ECC384_PRIVATE_KEY_SIZE;
 	return ZT_ECC384_PRIVATE_KEY_SIZE;
 }
 }
 
 
@@ -775,9 +775,20 @@ int ZT_GoLocator_makeLocator(
 	return s;
 	return s;
 }
 }
 
 
-int ZT_GoLocator_decodeLocator(const uint8_t *loc,unsigned int locSize,struct ZT_GoLocator_Info *info)
+int ZT_GoLocator_decodeLocator(const uint8_t *locatorBytes,unsigned int locatorSize,struct ZT_GoLocator_Info *info)
 {
 {
-	memset(info,0,sizeof(struct ZT_GoLocator_Info));
+	Locator loc;
+	if (!loc.deserialize(locatorBytes,locatorSize))
+		return -1;
+	if (!loc.verify())
+		return -2;
+	loc.id().toString(false,info->id);
+	info->phyCount = 0;
+	info->virtCount = 0;
+	for(auto p=loc.phy().begin();p!=loc.phy().end();++p)
+		memcpy(&(info->phy[info->phyCount++]),&(*p),sizeof(struct sockaddr_storage));
+	for(auto v=loc.virt().begin();v!=loc.virt().end();++v)
+		v->toString(false,info->virt[info->virtCount++]);
 	return 1;
 	return 1;
 }
 }
 
 

+ 5 - 5
go/native/GoGlue.h

@@ -92,11 +92,11 @@ int ZT_GoTap_removeRoute(ZT_GoTap *tap,int targetAf,const void *targetIp,int tar
 
 
 struct ZT_GoLocator_Info {
 struct ZT_GoLocator_Info {
 	char id[1024];
 	char id[1024];
-	struct sockaddr_storage phy[256];
-	char virt[256][1024];
 	unsigned int phyCount;
 	unsigned int phyCount;
 	unsigned int virtCount;
 	unsigned int virtCount;
-}
+	struct sockaddr_storage phy[256];
+	char virt[256][1024];
+};
 
 
 /* Returns length of private key stored in private key buffer on success, -1 on fail */
 /* Returns length of private key stored in private key buffer on success, -1 on fail */
 int ZT_GoLocator_makeSecureDNSName(char name[256],unsigned int nameBufSize,uint8_t *privateKey,unsigned int privateKeyBufSize);
 int ZT_GoLocator_makeSecureDNSName(char name[256],unsigned int nameBufSize,uint8_t *privateKey,unsigned int privateKeyBufSize);
@@ -120,8 +120,8 @@ int ZT_GoLocator_makeLocator(
 	const char **virtualAddresses,
 	const char **virtualAddresses,
 	unsigned int virtualAddressCount);
 	unsigned int virtualAddressCount);
 
 
-/* Returns nonzero on success, fills info structure */
-int ZT_GoLocator_decodeLocator(const uint8_t *loc,unsigned int locSize,struct ZT_GoLocator_Info *info);
+/* Returns >0 on success, fills info structure */
+int ZT_GoLocator_decodeLocator(const uint8_t *locatorBytes,unsigned int locatorSize,struct ZT_GoLocator_Info *info);
 
 
 /*
 /*
  * The privateKey and privateKeySize are those created by makeSecureDNSName.
  * The privateKey and privateKeySize are those created by makeSecureDNSName.

+ 3 - 0
go/pkg/zerotier/api.go

@@ -356,6 +356,9 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
 			if queriedID == 0 {
 			if queriedID == 0 {
 				apiSendObj(out, req, http.StatusBadRequest, nil)
 				apiSendObj(out, req, http.StatusBadRequest, nil)
 			} else {
 			} else {
+				var r Root
+				if apiReadObj(out, req, &r) == nil {
+				}
 			}
 			}
 		} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
 		} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
 			roots := node.Roots()
 			roots := node.Roots()

+ 2 - 0
go/pkg/zerotier/errors.go

@@ -20,6 +20,7 @@ func (e Err) Error() string { return (string)(e) }
 
 
 // Simple ZeroTier Errors
 // Simple ZeroTier Errors
 const (
 const (
+	ErrInternal                  Err = "internal error"
 	ErrNodeInitFailed            Err = "unable to initialize core Node instance"
 	ErrNodeInitFailed            Err = "unable to initialize core Node instance"
 	ErrInvalidMACAddress         Err = "invalid MAC address"
 	ErrInvalidMACAddress         Err = "invalid MAC address"
 	ErrInvalidZeroTierAddress    Err = "invalid ZeroTier address"
 	ErrInvalidZeroTierAddress    Err = "invalid ZeroTier address"
@@ -28,5 +29,6 @@ const (
 	ErrTapInitFailed             Err = "unable to create native Tap instance"
 	ErrTapInitFailed             Err = "unable to create native Tap instance"
 	ErrUncrecognizedIdentityType Err = "unrecognized identity type"
 	ErrUncrecognizedIdentityType Err = "unrecognized identity type"
 	ErrInvalidKey                Err = "invalid key data"
 	ErrInvalidKey                Err = "invalid key data"
+	ErrInvalidSignature          Err = "invalid signature"
 	ErrSecretKeyRequired         Err = "secret key required"
 	ErrSecretKeyRequired         Err = "secret key required"
 )
 )

+ 75 - 1
go/pkg/zerotier/locator.go

@@ -17,7 +17,10 @@ package zerotier
 //#include "../../native/GoGlue.h"
 //#include "../../native/GoGlue.h"
 import "C"
 import "C"
 
 
-import "unsafe"
+import (
+	"encoding/json"
+	"unsafe"
+)
 
 
 // LocatorDNSSigningKey is the public (as a secure DNS name) and private keys for entering locators into DNS
 // LocatorDNSSigningKey is the public (as a secure DNS name) and private keys for entering locators into DNS
 type LocatorDNSSigningKey struct {
 type LocatorDNSSigningKey struct {
@@ -25,6 +28,20 @@ type LocatorDNSSigningKey struct {
 	PrivateKey    []byte
 	PrivateKey    []byte
 }
 }
 
 
+// NewLocatorDNSSigningKey creates a new signing key and secure DNS name for storing locators in DNS
+func NewLocatorDNSSigningKey() (*LocatorDNSSigningKey, error) {
+	var nameBuf [256]C.char
+	var keyBuf [64]byte
+	keySize := int(C.ZT_GoLocator_makeSecureDNSName(&nameBuf[0], 256, (*C.uint8_t)(unsafe.Pointer(&keyBuf[0])), 128))
+	if keySize <= 0 {
+		return nil, ErrInternal
+	}
+	var sk LocatorDNSSigningKey
+	sk.SecureDNSName = C.GoString(&nameBuf[0])
+	sk.PrivateKey = keyBuf[0:keySize]
+	return &sk, nil
+}
+
 // Locator is a binary serialized record containing information about where a ZeroTier node is located on the network
 // Locator is a binary serialized record containing information about where a ZeroTier node is located on the network
 type Locator struct {
 type Locator struct {
 	// Identity is the full identity of the node being located
 	// Identity is the full identity of the node being located
@@ -95,5 +112,62 @@ func NewLocator(id *Identity, virtualAddresses []*Identity, physicalAddresses []
 	}, nil
 	}, nil
 }
 }
 
 
+// NewLocatorFromBytes decodes a locator from its serialized byte array form
+func NewLocatorFromBytes(b []byte) (*Locator, error) {
+	if len(b) == 0 {
+		return nil, ErrInvalidParameter
+	}
+	var info C.struct_ZT_GoLocator_Info
+	res := C.ZT_GoLocator_decodeLocator((*C.uint8_t)(unsafe.Pointer(&b[0])), C.uint(len(b)), &info)
+	if res == -2 {
+		return nil, ErrInvalidSignature
+	} else if res <= 0 {
+		return nil, ErrInvalidParameter
+	}
+
+	var loc Locator
+
+	var err error
+	loc.Identity, err = NewIdentityFromString(C.GoString(info.id))
+	if err != nil {
+		return nil, err
+	}
+	for i := 0; i < int(info.phyCount); i++ {
+		ua := sockaddrStorageToUDPAddr(&info.phy[i])
+		if ua != nil {
+			loc.Physical = append(loc.Physical, &InetAddress{IP: ua.IP, Port: ua.Port})
+		}
+	}
+	for i := 0; i < int(info.virtCount); i++ {
+		id, err := NewIdentityFromString(C.GoString(info.virt[i]))
+		if err == nil {
+			loc.Virtual = append(loc.Virtual, id)
+		}
+	}
+
+	return &loc, nil
+}
+
 // Bytes returns this locator in byte serialized format
 // Bytes returns this locator in byte serialized format
 func (l *Locator) Bytes() []byte { return l.bytes }
 func (l *Locator) Bytes() []byte { return l.bytes }
+
+// MarshalJSON marshals this Locator as its byte encoding
+func (l *Locator) MarshalJSON() ([]byte, error) {
+	b := l.bytes
+	return json.Marshal(&b)
+}
+
+// UnmarshalJSON unmarshals this Locator from a byte array in JSON.
+func (l *Locator) UnmarshalJSON(j []byte) error {
+	var ba []byte
+	err := json.Unmarshal(j, &ba)
+	if err != nil {
+		return nil
+	}
+	tmp, err := NewLocatorFromBytes(ba)
+	if err != nil {
+		return err
+	}
+	*l = *tmp
+	return nil
+}

+ 37 - 1
go/pkg/zerotier/node.go

@@ -558,7 +558,7 @@ func (n *Node) Roots() []*Root {
 					}
 					}
 				}
 				}
 				roots = append(roots, &Root{
 				roots = append(roots, &Root{
-					DNSName:   C.GoString(root.dnsName),
+					Name:      C.GoString(root.dnsName),
 					Identity:  id,
 					Identity:  id,
 					Addresses: addrs,
 					Addresses: addrs,
 					Preferred: (root.preferred != 0),
 					Preferred: (root.preferred != 0),
@@ -571,6 +571,42 @@ func (n *Node) Roots() []*Root {
 	return roots
 	return roots
 }
 }
 
 
+// SetRoot sets or updates a root.
+// Name can be a DNS name (preferably secure) for DNS fetched locators or can be
+// the empty string for static roots. If the name is empty then the locator must
+// be non-nil.
+func (n *Node) SetRoot(name string, locator *Locator) error {
+	if len(name) == 0 {
+		if locator == nil {
+			return ErrInvalidParameter
+		}
+		name = locator.Identity.address.String()
+	}
+	var lb []byte
+	if locator != nil {
+		lb = locator.Bytes()
+	}
+	var lbp unsafe.Pointer
+	if len(lb) > 0 {
+		lbp = unsafe.Pointer(&lb[0])
+	}
+	cn := C.CString(name)
+	defer C.free(unsafe.Pointer(cn))
+	if C.ZT_Node_setRoot(n.zn, cn, lbp, C.uint(len(lb))) != 0 {
+		return ErrInternal
+	}
+	return nil
+}
+
+// RemoveRoot removes a root.
+// For static roots the name should be the ZeroTier address.
+func (n *Node) RemoveRoot(name string) {
+	cn := C.CString(name)
+	defer C.free(unsafe.Pointer(cn))
+	C.ZT_Node_removeRoot(n.zn, cn)
+	return
+}
+
 // Peers retrieves a list of current peers
 // Peers retrieves a list of current peers
 func (n *Node) Peers() []*Peer {
 func (n *Node) Peers() []*Peer {
 	var peers []*Peer
 	var peers []*Peer

+ 2 - 8
go/pkg/zerotier/root.go

@@ -15,16 +15,10 @@ package zerotier
 
 
 // Root describes a root server used to find and establish communication with other nodes.
 // Root describes a root server used to find and establish communication with other nodes.
 type Root struct {
 type Root struct {
-	DNSName   string
+	Name      string
 	Identity  *Identity
 	Identity  *Identity
 	Addresses []InetAddress
 	Addresses []InetAddress
-	Locator   Locator
+	Locator   *Locator
 	Preferred bool
 	Preferred bool
 	Online    bool
 	Online    bool
 }
 }
-
-// Static returns true if this is a static root
-func (r *Root) Static() bool { return len(r.DNSName) == 0 }
-
-// Dynamic returns true if this is a dynamic root
-func (r *Root) Dynamic() bool { return len(r.DNSName) > 0 }

+ 1 - 1
go/pkg/zerotier/sizelimitwriter.go

@@ -57,7 +57,7 @@ func (w *sizeLimitWriter) trim(maxSize int, trimFactor float64, trimAtCR bool) e
 
 
 	if flen > int64(maxSize) {
 	if flen > int64(maxSize) {
 		var buf [131072]byte
 		var buf [131072]byte
-		trimAt := int64(float64(flen) * trimFactor)
+		trimAt := int64(float64(maxSize) * trimFactor)
 		if trimAt >= flen { // sanity check
 		if trimAt >= flen { // sanity check
 			return nil
 			return nil
 		}
 		}

+ 5 - 5
include/ZeroTierCore.h

@@ -523,13 +523,13 @@ enum ZT_Event
  */
  */
 typedef struct {
 typedef struct {
 	/**
 	/**
-	 * DNS name for dynamic roots or NULL for static roots
+	 * Name of root
 	 *
 	 *
-	 * If this is a static root this will be NULL and identity
-	 * will never be NULL. For dynamic roots identity can be NULL
-	 * if the name of this root has never been properly resolved.
+	 * This will be a DNS name for dynamic roots. For static roots
+	 * it will be the ZeroTier address. The presence or absence
+	 * of a dot is used internally as a distinguisher.
 	 */
 	 */
-	const char *dnsName;
+	const char *name;
 
 
 	/**
 	/**
 	 * Current public identity or NULL if not known (only possible with dynamic roots)
 	 * Current public identity or NULL if not known (only possible with dynamic roots)

+ 0 - 8
node/Locator.hpp

@@ -316,14 +316,6 @@ public:
 			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
 			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
 		_ts = (int64_t)b.template at<uint64_t>(p); p += 8;
 		_ts = (int64_t)b.template at<uint64_t>(p); p += 8;
 		p += _id.deserialize(b,p);
 		p += _id.deserialize(b,p);
-		const unsigned int signerCount = b[p++];
-		if (signerCount > 1) /* only one third party signer is currently supported */
-			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
-		if (signerCount == 1) {
-			p += _signedBy.deserialize(b,p);
-		} else {
-			_signedBy.zero();
-		}
 		const unsigned int physicalCount = b[p++];
 		const unsigned int physicalCount = b[p++];
 		_physical.resize(physicalCount);
 		_physical.resize(physicalCount);
 		for(unsigned int i=0;i<physicalCount;++i)
 		for(unsigned int i=0;i<physicalCount;++i)

+ 2 - 2
node/Topology.hpp

@@ -81,11 +81,11 @@ public:
 	ZT_ALWAYS_INLINE Topology(const RuntimeEnvironment *renv,const Identity &myId) :
 	ZT_ALWAYS_INLINE Topology(const RuntimeEnvironment *renv,const Identity &myId) :
 		RR(renv),
 		RR(renv),
 		_myIdentity(myId),
 		_myIdentity(myId),
+		_numConfiguredPhysicalPaths(0),
 		_peers(64),
 		_peers(64),
 		_paths(128),
 		_paths(128),
 		_roots(8),
 		_roots(8),
 		_rootIdentities(8),
 		_rootIdentities(8),
-		_numConfiguredPhysicalPaths(0),
 		_lastUpdatedBestRoot(0) {}
 		_lastUpdatedBestRoot(0) {}
 	ZT_ALWAYS_INLINE ~Topology() {}
 	ZT_ALWAYS_INLINE ~Topology() {}
 
 
@@ -385,7 +385,7 @@ public:
 			Locator *v = (Locator *)0;
 			Locator *v = (Locator *)0;
 			Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_roots);
 			Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_roots);
 			while (i.next(k,v)) {
 			while (i.next(k,v)) {
-				rl->roots[c].dnsName = nameBufPtr;
+				rl->roots[c].name = nameBufPtr;
 				const char *p = k->c_str();
 				const char *p = k->c_str();
 				while (*p)
 				while (*p)
 					*(nameBufPtr++) = *(p++);
 					*(nameBufPtr++) = *(p++);