Root admin stuff

This commit is contained in:
Adam Ierymenko 2019-09-30 09:32:00 -07:00
parent 4303c43db7
commit b0d222768a
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
16 changed files with 217 additions and 46 deletions

View file

@ -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 addroot <locator> [<name>] Add a VL1 root
static <identity> <ip/port> [...] Add a root with a set identity and IPs removeroot <name> Remove a VL1 root
dynamic <name> [default locator] Add a dynamic root fetched by name makelocator <secret> <address> [...] Make and sign a locator
removeroot <type> [options] Remove a VL1 root makelocatordnskey Create a new secure DNS name and key
static <identity> Remove a root with a set identity makelocatordns <key> <locator> Make DNS TXT records for a locator
dynamic <name> Remove a dynamic root fetched by name
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()
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 */ /* Returns >0 on success, fills info structure */
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);
/* /*
* The privateKey and privateKeySize are those created by makeSecureDNSName. * The privateKey and privateKeySize are those created by makeSecureDNSName.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 * This will be a DNS name for dynamic roots. For static roots
* will never be NULL. For dynamic roots identity can be NULL * it will be the ZeroTier address. The presence or absence
* if the name of this root has never been properly resolved. * 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)

View file

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

View file

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