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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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