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
 func Help() {
-	fmt.Println(copyrightText + `
-
+	fmt.Println(copyrightText)
+	fmt.Println(`
 Usage: zerotier [-options] <command> [-options] [command args]
 
 Global Options:
   -j                                   Output raw JSON where applicable
   -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:
   help                                 Show this help
@@ -40,12 +40,11 @@ Commands:
   status                               Show ZeroTier service status and config
   peers                                Show VL1 peers
   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
   join <network ID>                    Join 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
 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
-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":
 		authTokenRequired(authToken)
 		cli.RemoveRoot(basePath, authToken, cmdArgs)
+	case "makelocator":
+		cli.MakeLocator(cmdArgs)
+	case "makelocatordnskey":
+		cli.MakeLocatorDNSKey(cmdArgs)
+	case "makelocatordns":
+		cli.MakeLocatorDNS(cmdArgs)
 	case "networks", "listnetworks":
 		authTokenRequired(authToken)
 		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];
 	ECC384GenerateKey(pub,privateKey);
 	const Str n(Locator::makeSecureDnsName(pub));
-	if (n.size() >= nameBufSize)
+	if (n.length() >= nameBufSize)
 		return -1;
-	Utils::scopy(name,sizeof(name),n.c_Str());
+	Utils::scopy(name,sizeof(name),n.c_str());
 	return ZT_ECC384_PRIVATE_KEY_SIZE;
 }
 
@@ -775,9 +775,20 @@ int ZT_GoLocator_makeLocator(
 	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;
 }
 

+ 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 {
 	char id[1024];
-	struct sockaddr_storage phy[256];
-	char virt[256][1024];
 	unsigned int phyCount;
 	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 */
 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,
 	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.

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

@@ -356,6 +356,9 @@ func createAPIServer(basePath string, node *Node) (*http.Server, error) {
 			if queriedID == 0 {
 				apiSendObj(out, req, http.StatusBadRequest, nil)
 			} else {
+				var r Root
+				if apiReadObj(out, req, &r) == nil {
+				}
 			}
 		} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
 			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
 const (
+	ErrInternal                  Err = "internal error"
 	ErrNodeInitFailed            Err = "unable to initialize core Node instance"
 	ErrInvalidMACAddress         Err = "invalid MAC address"
 	ErrInvalidZeroTierAddress    Err = "invalid ZeroTier address"
@@ -28,5 +29,6 @@ const (
 	ErrTapInitFailed             Err = "unable to create native Tap instance"
 	ErrUncrecognizedIdentityType Err = "unrecognized identity type"
 	ErrInvalidKey                Err = "invalid key data"
+	ErrInvalidSignature          Err = "invalid signature"
 	ErrSecretKeyRequired         Err = "secret key required"
 )

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

@@ -17,7 +17,10 @@ package zerotier
 //#include "../../native/GoGlue.h"
 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
 type LocatorDNSSigningKey struct {
@@ -25,6 +28,20 @@ type LocatorDNSSigningKey struct {
 	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
 type Locator struct {
 	// Identity is the full identity of the node being located
@@ -95,5 +112,62 @@ func NewLocator(id *Identity, virtualAddresses []*Identity, physicalAddresses []
 	}, 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
 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{
-					DNSName:   C.GoString(root.dnsName),
+					Name:      C.GoString(root.dnsName),
 					Identity:  id,
 					Addresses: addrs,
 					Preferred: (root.preferred != 0),
@@ -571,6 +571,42 @@ func (n *Node) Roots() []*Root {
 	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
 func (n *Node) 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.
 type Root struct {
-	DNSName   string
+	Name      string
 	Identity  *Identity
 	Addresses []InetAddress
-	Locator   Locator
+	Locator   *Locator
 	Preferred 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) {
 		var buf [131072]byte
-		trimAt := int64(float64(flen) * trimFactor)
+		trimAt := int64(float64(maxSize) * trimFactor)
 		if trimAt >= flen { // sanity check
 			return nil
 		}

+ 5 - 5
include/ZeroTierCore.h

@@ -523,13 +523,13 @@ enum ZT_Event
  */
 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)

+ 0 - 8
node/Locator.hpp

@@ -316,14 +316,6 @@ public:
 			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
 		_ts = (int64_t)b.template at<uint64_t>(p); p += 8;
 		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++];
 		_physical.resize(physicalCount);
 		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) :
 		RR(renv),
 		_myIdentity(myId),
+		_numConfiguredPhysicalPaths(0),
 		_peers(64),
 		_paths(128),
 		_roots(8),
 		_rootIdentities(8),
-		_numConfiguredPhysicalPaths(0),
 		_lastUpdatedBestRoot(0) {}
 	ZT_ALWAYS_INLINE ~Topology() {}
 
@@ -385,7 +385,7 @@ public:
 			Locator *v = (Locator *)0;
 			Hashtable< Str,Locator >::Iterator i(const_cast<Topology *>(this)->_roots);
 			while (i.next(k,v)) {
-				rl->roots[c].dnsName = nameBufPtr;
+				rl->roots[c].name = nameBufPtr;
 				const char *p = k->c_str();
 				while (*p)
 					*(nameBufPtr++) = *(p++);