A bunch of CLI work

This commit is contained in:
Adam Ierymenko 2019-09-30 16:12:08 -07:00
parent c4504fd3ff
commit 7fc78129f4
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
19 changed files with 225 additions and 153 deletions

View file

@ -14,6 +14,7 @@
package cli
import (
"encoding/json"
"fmt"
"net/http"
"os"
@ -43,3 +44,8 @@ func enabledDisabled(f bool) string {
}
return "DISABLED"
}
func jsonDump(obj interface{}) string {
j, _ := json.MarshalIndent(obj, "", " ")
return string(j)
}

View file

@ -15,6 +15,7 @@ package cli
import (
"fmt"
"zerotier/pkg/zerotier"
)
@ -26,7 +27,7 @@ Licensed under the ZeroTier BSL (see LICENSE.txt)`, zerotier.CoreVersionMajor, z
func Help() {
fmt.Println(copyrightText)
fmt.Println(`
Usage: zerotier [-options] <command> [-options] [command args]
Usage: zerotier [-options] <command> [command args]
Global Options:
-j Output raw JSON where applicable
@ -40,11 +41,18 @@ Commands:
status Show ZeroTier service status and config
peers Show VL1 peers
roots Show VL1 root servers
addroot <locator> [<name>] Add a VL1 root
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
locator <command> [args] Locator management commands
new <identity> <address> [...] Create and sign a locator
newdnskey Create a secure DNS name and secret
getdns <key> <locator> Create secure DNS TXT records
identity <command> [args] Identity management commands
new Create new identity (including secret)
getpublic <identity> Extract only public part of identity
validate <identity> Locally validate an identity
sign <identity> <file> Sign a file with an identity's key
verify <identity> <file> <sig> Verify a signature
networks Show joined VL2 virtual networks
join <network ID> Join a virtual network
leave <network ID> Leave a virtual network

View file

@ -13,6 +13,6 @@
package cli
// MakeLocator CLI command
func MakeLocator(args []string) {
// Identity command
func Identity(args []string) {
}

View file

@ -0,0 +1,135 @@
/*
* 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
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strings"
"zerotier/pkg/zerotier"
)
func locatorNew(args []string) {
if len(args) < 2 {
Help()
os.Exit(1)
}
identityData, err := ioutil.ReadFile(args[0])
if err != nil {
fmt.Printf("FATAL: unable to read identity: %s\n", err.Error())
os.Exit(1)
}
identity, err := zerotier.NewIdentityFromString(string(identityData))
if err != nil {
fmt.Printf("FATAL: invalid identity: %s\n", err.Error())
os.Exit(1)
}
if !identity.HasPrivate() {
fmt.Println("FATAL: identity does not contain secret key")
os.Exit(1)
}
var virt []*zerotier.Identity
var phys []*zerotier.InetAddress
for i := 1; i < len(args); i++ {
if strings.Contains(args[i], "/") {
a := zerotier.NewInetAddressFromString(args[i])
if a == nil {
fmt.Printf("FATAL: IP/port address '%s' is not valid\n", args[i])
os.Exit(1)
}
phys = append(phys, a)
} else {
a, err := zerotier.NewIdentityFromString(args[i])
if err != nil {
fmt.Printf("FATAL: identity (virtual address) '%s' is not valid: %s\n", args[i], err.Error())
os.Exit(1)
}
virt = append(virt, a)
}
}
loc, err := zerotier.NewLocator(identity, virt, phys)
if err != nil {
fmt.Printf("FATAL: internal error creating locator: %s\n", err.Error())
os.Exit(1)
}
fmt.Println(jsonDump(loc))
}
func locatorNewDNSKey(args []string) {
if len(args) != 0 {
Help()
os.Exit(0)
}
sk, err := zerotier.NewLocatorDNSSigningKey()
if err != nil {
fmt.Printf("FATAL: error creating secure DNS signing key: %s", err.Error())
os.Exit(1)
}
fmt.Println(jsonDump(sk))
os.Exit(0)
}
func locatorGetDNS(args []string) {
if len(args) < 2 {
Help()
os.Exit(1)
}
keyData, err := ioutil.ReadFile(args[0])
if err != nil {
fmt.Printf("FATAL: unable to read secure DNS key file: %s\n", err.Error())
os.Exit(1)
}
var sk zerotier.LocatorDNSSigningKey
err = json.Unmarshal(keyData, &sk)
if err != nil {
fmt.Printf("FATAL: DNS key file invalid: %s", err.Error())
os.Exit(1)
}
locData, err := ioutil.ReadFile(args[1])
if err != nil {
fmt.Printf("FATAL: unable to read locator: %s\n", err.Error())
os.Exit(1)
}
var loc zerotier.Locator
err = json.Unmarshal(locData, &loc)
if err != nil {
fmt.Printf("FATAL: locator invalid: %s", err.Error())
os.Exit(1)
}
}
// Locator CLI command
func Locator(args []string) {
if len(args) > 0 {
switch args[0] {
case "new":
locatorNew(args[1:])
case "newdnskey":
locatorNewDNSKey(args[1:])
case "getdns":
locatorGetDNS(args[1:])
}
}
Help()
os.Exit(1)
}

View file

@ -1,18 +0,0 @@
/*
* 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

@ -1,18 +0,0 @@
/*
* 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

@ -14,9 +14,9 @@
package cli
import (
"encoding/json"
"fmt"
"os"
"zerotier/pkg/zerotier"
)
@ -26,8 +26,7 @@ func Peers(basePath, authToken string, args []string, jsonOutput bool) {
apiGet(basePath, authToken, "/peer", &peers)
if jsonOutput {
j, _ := json.MarshalIndent(&peers, "", " ")
fmt.Println(string(j))
fmt.Println(jsonDump(&peers))
} else {
fmt.Printf("<ztaddr> <ver> <role> <lat> <link> <lastTX> <lastRX> <path(s)>\n")
for _, peer := range peers {

View file

@ -14,9 +14,9 @@
package cli
import (
"encoding/json"
"fmt"
"os"
"zerotier/pkg/zerotier"
)
@ -26,8 +26,7 @@ func Status(basePath, authToken string, args []string, jsonOutput bool) {
apiGet(basePath, authToken, "/status", &status)
if jsonOutput {
j, _ := json.MarshalIndent(&status, "", " ")
fmt.Println(string(j))
fmt.Println(jsonDump(&status))
} else {
online := "ONLINE"
if !status.Online {

View file

@ -21,6 +21,7 @@ import (
"path"
"runtime"
"strings"
"zerotier/cmd/zerotier/cli"
"zerotier/pkg/zerotier"
)
@ -112,7 +113,7 @@ func main() {
case "peers", "listpeers":
authTokenRequired(authToken)
cli.Peers(basePath, authToken, cmdArgs, *jflag)
case "roots":
case "roots", "listroots", "listmoons":
authTokenRequired(authToken)
cli.Roots(basePath, authToken, cmdArgs)
case "addroot":
@ -121,12 +122,10 @@ 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 "locator":
cli.Locator(cmdArgs)
case "identity":
cli.Identity(cmdArgs)
case "networks", "listnetworks":
authTokenRequired(authToken)
cli.Networks(basePath, authToken, cmdArgs)

View file

@ -732,7 +732,7 @@ extern "C" int ZT_GoLocator_makeSecureDNSName(char *name,unsigned int nameBufSiz
const Str n(Locator::makeSecureDnsName(pub));
if (n.length() >= nameBufSize)
return -1;
Utils::scopy(name,sizeof(name),n.c_str());
Utils::scopy(name,nameBufSize,n.c_str());
return ZT_ECC384_PRIVATE_KEY_SIZE;
}

View file

@ -132,7 +132,6 @@ int ZT_GoLocator_decodeLocator(const uint8_t *locatorBytes,unsigned int locatorS
int ZT_GoLocator_makeSignedTxtRecords(
const uint8_t *locator,
unsigned int locatorSize,
int64_t ts,
const char *name,
const uint8_t *privateKey,
unsigned int privateKeySize,

View file

@ -45,7 +45,7 @@ type Identity struct {
// NewIdentityFromString generates a new identity from its string representation.
// The private key is imported as well if it is present.
func NewIdentityFromString(s string) (*Identity, error) {
ss := strings.Split(s, ":")
ss := strings.Split(strings.TrimSpace(s), ":")
if len(ss) < 3 {
return nil, ErrInvalidParameter
}

View file

@ -43,7 +43,7 @@ func (i *InetAddress) Less(i2 *InetAddress) bool {
// NewInetAddressFromString parses an IP[/port] format address
func NewInetAddressFromString(s string) *InetAddress {
i := new(InetAddress)
ss := strings.Split(s, "/")
ss := strings.Split(strings.TrimSpace(s), "/")
if len(ss) > 0 {
i.IP = net.ParseIP(ss[0])
i4 := i.IP.To4()

View file

@ -151,6 +151,25 @@ func NewLocatorFromBytes(b []byte) (*Locator, error) {
return &loc, nil
}
// MakeTXTRecords creates secure DNS TXT records for this locator
func (l *Locator) MakeTXTRecords(key *LocatorDNSSigningKey) ([]string, error) {
if key == nil || len(l.Bytes) == 0 || len(key.PrivateKey) == 0 {
return nil, ErrInvalidParameter
}
var results [256][256]C.char
cName := C.CString(key.SecureDNSName)
defer C.free(unsafe.Pointer(cName))
count := int(C.ZT_GoLocator_makeSignedTxtRecords((*C.uint8_t)(&l.Bytes[0]), C.uint(len(l.Bytes)), cName, (*C.uint8_t)(&key.PrivateKey[0]), C.uint(len(key.PrivateKey)), &results[0]))
if count > 0 {
var t []string
for i := 0; i < int(count); i++ {
t = append(t, C.GoString(&results[i][0]))
}
return t, nil
}
return nil, ErrInternal
}
// MarshalJSON marshals this Locator as its byte encoding
func (l *Locator) MarshalJSON() ([]byte, error) {
return json.Marshal(l)

View file

@ -71,6 +71,9 @@ const (
// AFInet6 is the address family for IPv6
AFInet6 = C.AF_INET6
networkConfigOpUp int = C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP
networkConfigOpUpdate int = C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE
defaultVirtualNetworkMTU = C.ZT_DEFAULT_MTU
)
@ -548,21 +551,11 @@ func (n *Node) Roots() []*Root {
if rl != nil {
for i := 0; i < int(rl.count); i++ {
root := (*C.ZT_Root)(unsafe.Pointer(uintptr(unsafe.Pointer(rl)) + C.sizeof_ZT_RootList))
id, err := NewIdentityFromString(C.GoString(root.identity))
if err == nil {
var addrs []InetAddress
for j := uintptr(0); j < uintptr(root.addressCount); j++ {
a := NewInetAddressFromSockaddr(unsafe.Pointer(uintptr(unsafe.Pointer(root.addresses)) + (j * C.sizeof_struct_sockaddr_storage)))
if a != nil && a.Valid() {
addrs = append(addrs, *a)
}
}
loc, _ := NewLocatorFromBytes(C.GoBytes(root.locator, C.int(root.locatorSize)))
if loc != nil {
roots = append(roots, &Root{
Name: C.GoString(root.name),
Identity: id,
Addresses: addrs,
Preferred: root.preferred != 0,
Online: root.online != 0,
Name: C.GoString(root.name),
Locator: loc,
})
}
}
@ -584,11 +577,11 @@ func (n *Node) SetRoot(name string, locator *Locator) error {
}
var lb []byte
if locator != nil {
lb = locator.Bytes()
lb = locator.Bytes
}
var lbp unsafe.Pointer
if len(lb) > 0 {
lbp = &lb[0]
lbp = unsafe.Pointer(&lb[0])
}
cn := C.CString(name)
defer C.free(unsafe.Pointer(cn))
@ -925,8 +918,8 @@ func goVirtualNetworkConfigFunc(gn, _ unsafe.Pointer, nwid C.uint64_t, op C.int,
node.networksLock.RUnlock()
if network != nil {
switch op {
case C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP:
switch int(op) {
case networkConfigOpUp, networkConfigOpUpdate:
ncc := (*C.ZT_VirtualNetworkConfig)(conf)
if network.networkConfigRevision() > uint64(ncc.netconfRevision) {
return

View file

@ -15,8 +15,6 @@ package zerotier
// Root describes a root server used to find and establish communication with other nodes.
type Root struct {
Name string
Locator *Locator
Preferred bool
Online bool
Name string
Locator *Locator
}