Move some toString/fromString to C++ since any ZT code base would need it, and stub out the controller commands.

This commit is contained in:
Adam Ierymenko 2020-05-30 11:42:59 -07:00
parent a5390b1bc8
commit 1970dab13d
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
17 changed files with 414 additions and 67 deletions

View file

@ -0,0 +1,17 @@
/*
* Copyright (c)2013-2020 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: 2024-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
func Controller(basePath, authToken string, args []string, jsonOutput bool) {
}

View file

@ -18,7 +18,6 @@ import (
"zerotier/pkg/zerotier"
)
// Help dumps help to stdout
func Help() {
fmt.Printf(`ZeroTier Network Hypervisor Service Version %d.%d.%d
(c)2013-2020 ZeroTier, Inc.
@ -38,11 +37,11 @@ Commands:
service Start as service
status Show node status, identity, and config
peers List all VL1 peers
join <network ID> [fingerprint] Join a virtual network
leave <network ID> Leave a virtual network
join <network> [fingerprint] Join a virtual network
leave <network> Leave a virtual network
networks List VL2 virtual networks
network <network ID> Show verbose network info
set <network ID> [option] [value] Get or set a network config option
network <network> Show verbose network info
set <network> [option] [value] Get or set a network config option
manageips <boolean> Is IP management allowed?
manageroutes <boolean> Is route management allowed?
globalips <boolean> Allow assignment of global IPs?
@ -62,11 +61,20 @@ Commands:
verify <identity> <file> <sig> Verify a signature
locator <command> [args] Locator management commands
new <identity> <address> [...] Create and sign a new locator
show <locator> [<identity>] Show locator information
roots List root peers
addroot <identity> <locator> Add a root or update its locator
addroot <url> Add or update roots from a URL
removeroot <address> Remove a peer from the root list
show <locator> [identity] Show locator information
root [command] Root management commands
list List root peers (same as no command)
add <identity> <locator> Add or manually update a root
add <url> Add or update root(s) from a URL
remove <address> Un-designate a peer as a root
controller <command> [option] Local controller management commands
networks List networks run by local controller
new Create a new network
set <network> [setting] [value] Show or modify network settings
members <network> List members of a network
member <network> [setting] [value] Show or modify member level settings
auth <address|fingerprint> Authorize a peer
deauth <address|fingerprint> Deauthorize a peer
The 'service' command does not exit until the service receives a signal.
This is typically run from launchd (Mac), systemd or init (Linux), a Windows
@ -78,6 +86,5 @@ node.
Identities can be specified verbatim on the command line or as a path to
a file. This is detected automatically.
`,zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
}

View file

@ -23,7 +23,6 @@ import (
"zerotier/pkg/zerotier"
)
// Identity command
func Identity(args []string) {
if len(args) > 0 {
switch args[0] {

View file

@ -0,0 +1,83 @@
/*
* Copyright (c)2013-2020 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: 2024-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 (
"fmt"
"os"
"time"
"zerotier/pkg/zerotier"
)
func Locator(args []string) {
if len(args) > 0 {
switch args[0] {
case "new":
if len(args) >= 3 {
id := readIdentity(args[1])
if !id.HasPrivate() {
fmt.Println("ERROR: identity is missing private key and can't be used to sign a locator.")
os.Exit(1)
}
var eps []zerotier.Endpoint
for i:=2;i<len(args);i++ {
ep, _ := zerotier.NewEndpointFromString(args[i])
if ep != nil {
eps = append(eps, *ep)
}
}
loc, err := zerotier.NewLocator(zerotier.TimeMs(),eps,id)
if err != nil {
fmt.Printf("ERROR: unable to create or sign locator: %s\n",err.Error())
os.Exit(1)
}
fmt.Println(loc.String())
os.Exit(0)
}
case "show":
if len(args) > 1 && len(args) < 4 {
loc := readLocator(args[1])
var id *zerotier.Identity
if len(args) == 3 {
id = readIdentity(args[2])
}
ts, fp, eps, valid, _ := loc.GetInfo(id)
fmt.Printf("%s\n Timestamp: %s (%d)\n Validity: ",fp.String(),time.Unix(ts / 1000,ts * 1000).String(),ts)
if id == nil {
fmt.Printf("(no identity provided)\n")
} else {
if valid {
fmt.Printf("SIGNATURE VERIFIED\n")
} else {
fmt.Printf("! INVALID SIGNATURE\n")
}
}
fmt.Print(" Endpoints: ")
for i := range eps {
if i > 0 {
fmt.Print(" ")
}
fmt.Print(eps[i].String())
}
fmt.Printf("\n")
}
}
}
Help()
os.Exit(1)
}

View file

@ -99,23 +99,43 @@ func readIdentity(s string) *zerotier.Identity {
}
idData, err := ioutil.ReadFile(s)
if err != nil {
fmt.Printf("FATAL: identity '%s' cannot be resolved as file or literal identity: %s", s, err.Error())
fmt.Printf("FATAL: identity '%s' cannot be parsed as file or literal: %s", s, err.Error())
os.Exit(1)
}
id, err := zerotier.NewIdentityFromString(string(idData))
if err != nil {
fmt.Printf("FATAL: identity '%s' cannot be resolved as file or literal identity: %s", s, err.Error())
fmt.Printf("FATAL: identity '%s' cannot be parsed as file or literal: %s", s, err.Error())
os.Exit(1)
}
return id
}
func readLocator(s string) *zerotier.Locator {
if strings.ContainsRune(s, '@') {
loc, _ := zerotier.NewLocatorFromString(s)
if loc != nil {
return loc
}
}
locData, err := ioutil.ReadFile(s)
if err != nil {
fmt.Printf("FATAL: locator '%s' cannot be parsed as file or literal: %s", s, err.Error())
os.Exit(1)
}
loc, err := zerotier.NewLocatorFromString(string(locData))
if err != nil {
fmt.Printf("FATAL: locator '%s' cannot be parsed as file or literal: %s", s, err.Error())
os.Exit(1)
}
return loc
}
func networkStatusStr(status int) string {
switch status {
case zerotier.NetworkStatusNotFound:
return "NOTFOUND"
case zerotier.NetworkStatusAccessDenied:
return "DENIED"
return "ACCESSDENIED"
case zerotier.NetworkStatusRequestConfiguration:
return "UPDATING"
case zerotier.NetworkStatusOK:

View file

@ -21,7 +21,6 @@ import (
"zerotier/pkg/zerotier"
)
// Network CLI command
func Network(basePath, authToken string, args []string, jsonOutput bool) {
if len(args) != 1 {
Help()

View file

@ -0,0 +1,17 @@
/*
* Copyright (c)2013-2020 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: 2024-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
func Root(basePath, authToken string, args []string, jsonOutput bool) {
}

View file

@ -127,13 +127,6 @@ func main() {
case "peers", "listpeers", "lspeers":
authTokenRequired(authToken)
cli.Peers(basePath, authToken, cmdArgs, *jflag, false)
case "roots", "listroots", "lsroots":
authTokenRequired(authToken)
cli.Peers(basePath, authToken, cmdArgs, *jflag, true)
case "addroot":
// TODO
case "removeroot":
// TODO
case "join":
authTokenRequired(authToken)
cli.Join(basePath, authToken, cmdArgs)
@ -151,8 +144,19 @@ func main() {
cli.Set(basePath, authToken, cmdArgs)
case "identity":
cli.Identity(cmdArgs)
case "locator":
cli.Locator(cmdArgs)
case "root":
authTokenRequired(authToken)
cli.Root(basePath, authToken, cmdArgs, *jflag)
case "controller":
authTokenRequired(authToken)
cli.Controller(basePath, authToken, cmdArgs, *jflag)
}
// Commands in the 'cli' sub-package do not return, so if we make
// it here the command was not recognized.
cli.Help()
os.Exit(1)
}

View file

@ -5,11 +5,12 @@ package zerotier
// static inline uint64_t _getAddress(const ZT_Endpoint *ep) { return ep->value.fp.address; }
// static inline uint64_t _getMAC(const ZT_Endpoint *ep) { return ep->value.mac; }
// static inline const struct sockaddr_storage *_getSS(const ZT_Endpoint *ep) { return &(ep->value.ss); }
// static inline void _setSS(ZT_Endpoint *ep,const void *ss) { memcpy(&(ep->value.ss),ss,sizeof(struct sockaddr_storage)); }
import "C"
import (
"encoding/json"
"fmt"
"strings"
"unsafe"
)
@ -29,6 +30,42 @@ type Endpoint struct {
cep C.ZT_Endpoint
}
// NewEndpointFromString constructs a new endpoint from an InetAddress or Endpoint string.
// This will auto detect whether this is a plain InetAddress or an Endpoint in string
// format. If the former it's created as a ZT_ENDPOINT_TYPE_IP_UDP endpoint.
func NewEndpointFromString(s string) (*Endpoint, error) {
if len(s) == 0 {
var ep Endpoint
ep.cep._type = C.ZT_ENDPOINT_TYPE_NIL
return &ep, nil
}
if strings.IndexRune(s, '-') > 0 || (strings.IndexRune(s, ':') < 0 && strings.IndexRune(s, '.') < 0) {
var ep Endpoint
cs := C.CString(s)
defer C.free(cs)
if C.ZT_Endpoint_fromString(cs) == nil {
return nil, ErrInvalidParameter
}
return &ep, nil
}
inaddr := NewInetAddressFromString(s)
if inaddr == nil {
return nil, ErrInvalidParameter
}
return NewEndpointFromInetAddress(inaddr)
}
func NewEndpointFromInetAddress(addr *InetAddress) (*Endpoint, error) {
var ep Endpoint
var ss C.struct_sockaddr_storage
if !makeSockaddrStorage(addr.IP, addr.Port, &ss) {
return nil, ErrInvalidParameter
}
ep.cep._type = C.ZT_ENDPOINT_TYPE_IP_UDP
C._setSS(&ep.cep, unsafe.Pointer(&ss))
return &ep, nil
}
// Type returns this endpoint's type.
func (ep *Endpoint) Type() int {
return int(ep.cep._type)
@ -77,15 +114,12 @@ func (ep *Endpoint) MAC() MAC {
}
func (ep *Endpoint) String() string {
switch ep.cep._type {
case EndpointTypeZeroTier:
return fmt.Sprintf("%d/%s", ep.Type(), ep.Fingerprint().String())
case EndpointTypeEthernet, EndpointTypeWifiDirect, EndpointTypeBluetooth:
return fmt.Sprintf("%d/%s", ep.Type(), ep.MAC().String())
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2:
return fmt.Sprintf("%d/%s", ep.Type(), ep.InetAddress().String())
var buf [4096]byte
cs := C.ZT_Endpoint_toString(&ep.cep,unsafe.Pointer(&buf[0]),4096)
if cs == nil {
return "0"
}
return fmt.Sprintf("%d", ep.Type())
return C.GoString(cs)
}
func (ep *Endpoint) MarshalJSON() ([]byte, error) {
@ -94,6 +128,15 @@ func (ep *Endpoint) MarshalJSON() ([]byte, error) {
}
func (ep *Endpoint) UnmarshalJSON(j []byte) error {
// TODO
var s string
err := json.Unmarshal(j, &s)
if err != nil {
return err
}
ep2, err := NewEndpointFromString(s)
if err != nil {
return err
}
*ep = *ep2
return nil
}

View file

@ -32,7 +32,7 @@ func NewFingerprintFromString(fps string) (*Fingerprint, error) {
if len(fps) < AddressStringLength {
return nil, ErrInvalidZeroTierAddress
}
ss := strings.Split(fps, "/")
ss := strings.Split(fps, "-")
if len(ss) < 1 || len(ss) > 2 {
return nil, ErrInvalidParameter
}
@ -67,7 +67,7 @@ func newFingerprintFromCFingerprint(cfp *C.ZT_Fingerprint) *Fingerprint {
func (fp *Fingerprint) String() string {
if len(fp.Hash) == 48 {
return fmt.Sprintf("%.10x/%s", uint64(fp.Address), Base32StdLowerCase.EncodeToString(fp.Hash))
return fmt.Sprintf("%.10x-%s", uint64(fp.Address), Base32StdLowerCase.EncodeToString(fp.Hash))
}
return fp.Address.String()
}

View file

@ -64,9 +64,26 @@ func NewLocatorFromBytes(lb []byte) (*Locator, error) {
return goloc, nil
}
func NewLocatorFromString(s string) (*Locator, error) {
if len(s) == 0 {
return nil, ErrInvalidParameter
}
sb := []byte(s)
sb = append(sb,0)
loc := C.ZT_Locator_fromString(unsafe.Pointer(&sb[0]))
if uintptr(loc) == 0 {
return nil, ErrInvalidParameter
}
goloc := new(Locator)
goloc.cl = unsafe.Pointer(loc)
runtime.SetFinalizer(goloc, locatorFinalizer)
return goloc, nil
}
// GetInfo gets information about this locator, also validating its signature if 'id' is non-nil.
// If 'id' is nil the 'valid' return value is undefined.
func (loc *Locator) GetInfo(id *Identity) (fp *Fingerprint, eps []Endpoint, valid bool, err error) {
func (loc *Locator) GetInfo(id *Identity) (ts int64, fp *Fingerprint, eps []Endpoint, valid bool, err error) {
ts = int64(C.ZT_Locator_timestamp(loc.cl))
cfp := C.ZT_Locator_fingerprint(loc.cl)
if uintptr(unsafe.Pointer(cfp)) == 0 {
err = ErrInternal
@ -84,3 +101,14 @@ func (loc *Locator) GetInfo(id *Identity) (fp *Fingerprint, eps []Endpoint, vali
}
return
}
func (loc *Locator) String() string {
var buf [4096]byte
C.ZT_Locator_toString(loc.cl,unsafe.Pointer(&buf[0]),4096)
for i:=range buf {
if buf[i] == 0 {
return string(buf[0:i])
}
}
return ""
}

View file

@ -2123,6 +2123,17 @@ ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id);
/* ---------------------------------------------------------------------------------------------------------------- */
ZT_SDK_API char *ZT_Endpoint_toString(
const ZT_Endpoint *ep,
char *buf,
int capacity);
ZT_SDK_API int ZT_Endpoint_fromString(
ZT_Endpoint *ep,
const char *str);
/* ---------------------------------------------------------------------------------------------------------------- */
/**
* Create and sign a new locator
*
@ -2149,6 +2160,14 @@ ZT_SDK_API ZT_Locator *ZT_Locator_unmarshal(
const void *data,
unsigned int len);
/**
* Decode a locator from string format
*
* @param str String format locator
* @return Locator or NULL if string is not valid
*/
ZT_SDK_API ZT_Locator *ZT_Locator_fromString(const char *str);
/**
* Serialize this locator into a buffer
*
@ -2159,6 +2178,19 @@ ZT_SDK_API ZT_Locator *ZT_Locator_unmarshal(
*/
ZT_SDK_API int ZT_Locator_marshal(const ZT_Locator *loc,void *buf,unsigned int bufSize);
/**
* Get this locator in string format
*
* @param loc Locator
* @param buf Buffer to store string
* @param capacity Capacity of buffer in bytes (recommended size: 4096)
* @return Pointer to buffer or NULL if an error occurs
*/
ZT_SDK_API char *ZT_Locator_toString(
const ZT_Locator *loc,
char *buf,
int capacity);
/**
* Get a pointer to the fingerprint of this locator's signer.
*
@ -2169,6 +2201,14 @@ ZT_SDK_API int ZT_Locator_marshal(const ZT_Locator *loc,void *buf,unsigned int b
*/
ZT_SDK_API const ZT_Fingerprint *ZT_Locator_fingerprint(const ZT_Locator *loc);
/**
* Get a locator's timestamp
*
* @param loc Locator to query
* @return Locator timestamp in milliseconds since epoch
*/
ZT_SDK_API int64_t ZT_Locator_timestamp(const ZT_Locator *loc);
/**
* Get the number of endpoints in this locator
*

View file

@ -16,7 +16,7 @@
namespace ZeroTier {
void Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
{
static const char *const s_endpointTypeChars = ZT_ENDPOINT_TYPE_CHAR_INDEX;
@ -30,14 +30,14 @@ void Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
break;
case ZT_ENDPOINT_TYPE_ZEROTIER:
s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_ZEROTIER];
s[1] = '/';
s[1] = '-';
zt().toString(s + 2);
break;
case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH:
s[0] = s_endpointTypeChars[this->type];
s[1] = '/';
s[1] = '-';
eth().toString(s + 2);
break;
case ZT_ENDPOINT_TYPE_IP:
@ -45,10 +45,12 @@ void Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_HTTP2:
s[0] = s_endpointTypeChars[this->type];
s[1] = '/';
s[1] = '-';
ip().toString(s + 2);
break;
}
return s;
}
bool Endpoint::fromString(const char *s) noexcept
@ -57,7 +59,7 @@ bool Endpoint::fromString(const char *s) noexcept
if ((!s) || (!*s))
return true;
const char *start = strchr(s, '/');
const char *start = strchr(s, '-');
if (start) {
char tmp[16];
for (unsigned int i = 0;i < 15;++i) {
@ -248,3 +250,26 @@ bool Endpoint::operator<(const Endpoint &ep) const noexcept
}
} // namespace ZeroTier
extern "C" {
char *ZT_Endpoint_toString(
const ZT_Endpoint *ep,
char *buf,
int capacity)
{
if ((!ep) || (!buf) || (capacity < ZT_ENDPOINT_STRING_SIZE_MAX))
return nullptr;
return reinterpret_cast<const ZeroTier::Endpoint *>(ep)->toString(buf);
}
int ZT_Endpoint_fromString(
ZT_Endpoint *ep,
const char *str)
{
if ((!ep) || (!str))
return ZT_RESULT_ERROR_BAD_PARAMETER;
return reinterpret_cast<ZeroTier::Endpoint *>(ep)->fromString(str) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
}
} // C API

View file

@ -147,14 +147,9 @@ public:
ZT_INLINE Fingerprint zt() const noexcept
{ return Fingerprint(this->value.fp); }
void toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept;
char *toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept;
ZT_INLINE String toString() const
{
char tmp[ZT_ENDPOINT_STRING_SIZE_MAX];
toString(tmp);
return String(tmp);
}
ZT_INLINE String toString() const { char tmp[ZT_ENDPOINT_STRING_SIZE_MAX]; return String(toString(tmp)); }
bool fromString(const char *s) noexcept;

View file

@ -54,7 +54,7 @@ public:
{
Address(this->address).toString(s);
if (haveHash()) {
s[ZT_ADDRESS_LENGTH_HEX] = '/';
s[ZT_ADDRESS_LENGTH_HEX] = '-';
Utils::b32e(this->hash, ZT_FINGERPRINT_HASH_SIZE, s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_FINGERPRINT_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1));
}
}

View file

@ -53,10 +53,33 @@ bool Locator::verify(const Identity &id) const noexcept
const unsigned int signlen = marshal(signdata, true);
return id.verify(signdata, signlen, m_signature.data(), m_signature.size());
}
} catch ( ... ) {} // fail verify on any unexpected exception
} catch (...) {} // fail verify on any unexpected exception
return false;
}
char *Locator::toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept
{
static_assert(ZT_LOCATOR_STRING_SIZE_MAX > ((((ZT_LOCATOR_MARSHAL_SIZE_MAX / 5) + 1) * 8) + ZT_ADDRESS_LENGTH_HEX + 1), "overflow");
uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX];
Address(m_signer.address).toString(s);
s[ZT_ADDRESS_LENGTH_HEX] = '@';
Utils::b32e(bin, marshal(bin, false), s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_LOCATOR_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1));
return s;
}
bool Locator::fromString(const char *s) noexcept
{
if (!s)
return false;
if (strlen(s) < (ZT_ADDRESS_LENGTH_HEX + 1))
return false;
uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const int bl = Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), bin, ZT_LOCATOR_MARSHAL_SIZE_MAX);
if ((bl <= 0) || (bl > ZT_LOCATOR_MARSHAL_SIZE_MAX))
return false;
return unmarshal(bin, bl) > 0;
}
int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool excludeSignature) const noexcept
{
Utils::storeBigEndian<uint64_t>(data, (uint64_t) m_ts);
@ -96,7 +119,7 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data);
int p = 8;
int l = m_signer.unmarshal(data + p,len - p);
int l = m_signer.unmarshal(data + p, len - p);
if (l <= 0)
return -1;
p += l;
@ -123,7 +146,7 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
return -1;
const unsigned int siglen = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
if (unlikely((siglen > ZT_SIGNATURE_BUFFER_SIZE) || ((p + (int)siglen) > len)))
if (unlikely((siglen > ZT_SIGNATURE_BUFFER_SIZE) || ((p + (int) siglen) > len)))
return -1;
m_signature.unsafeSetSize(siglen);
Utils::copy(m_signature.data(), data + p, siglen);
@ -148,9 +171,25 @@ ZT_Locator *ZT_Locator_create(
if ((ts <= 0) || (!endpoints) || (endpointCount == 0) || (!signer))
return nullptr;
ZeroTier::Locator *loc = new ZeroTier::Locator();
for(unsigned int i=0;i<endpointCount;++i)
for (unsigned int i = 0;i < endpointCount;++i)
loc->add(reinterpret_cast<const ZeroTier::Endpoint *>(endpoints)[i]);
if (!loc->sign(ts,*reinterpret_cast<const ZeroTier::Identity *>(signer))) {
if (!loc->sign(ts, *reinterpret_cast<const ZeroTier::Identity *>(signer))) {
delete loc;
return nullptr;
}
return reinterpret_cast<ZT_Locator *>(loc);
} catch (...) {
return nullptr;
}
}
ZT_Locator *ZT_Locator_fromString(const char *str)
{
try {
if (!str)
return nullptr;
ZeroTier::Locator *loc = new ZeroTier::Locator();
if (!loc->fromString(str)) {
delete loc;
return nullptr;
}
@ -168,45 +207,62 @@ ZT_Locator *ZT_Locator_unmarshal(
if ((!data) || (len == 0))
return nullptr;
ZeroTier::Locator *loc = new ZeroTier::Locator();
if (loc->unmarshal(reinterpret_cast<const uint8_t *>(data),(int)len) <= 0) {
if (loc->unmarshal(reinterpret_cast<const uint8_t *>(data), (int) len) <= 0) {
delete loc;
return nullptr;
}
return reinterpret_cast<ZT_Locator *>(loc);
} catch ( ... ) {
} catch (...) {
return nullptr;
}
}
int ZT_Locator_marshal(const ZT_Locator *loc,void *buf,unsigned int bufSize)
int ZT_Locator_marshal(const ZT_Locator *loc, void *buf, unsigned int bufSize)
{
if ((!loc) || (bufSize < ZT_LOCATOR_MARSHAL_SIZE_MAX))
return -1;
return reinterpret_cast<const ZeroTier::Locator *>(loc)->marshal(reinterpret_cast<uint8_t *>(buf),(int)bufSize);
return reinterpret_cast<const ZeroTier::Locator *>(loc)->marshal(reinterpret_cast<uint8_t *>(buf), (int) bufSize);
}
char *ZT_Locator_toString(
const ZT_Locator *loc,
char *buf,
int capacity)
{
if ((!loc) || (capacity < ZT_LOCATOR_STRING_SIZE_MAX))
return nullptr;
return reinterpret_cast<const ZeroTier::Locator *>(loc)->toString(buf);
}
const ZT_Fingerprint *ZT_Locator_fingerprint(const ZT_Locator *loc)
{
if (!loc)
return nullptr;
return (ZT_Fingerprint *)(&(reinterpret_cast<const ZeroTier::Locator *>(loc)->signer()));
return (ZT_Fingerprint *) (&(reinterpret_cast<const ZeroTier::Locator *>(loc)->signer()));
}
int64_t ZT_Locator_timestamp(const ZT_Locator *loc)
{
if (!loc)
return 0;
return reinterpret_cast<const ZeroTier::Locator *>(loc)->timestamp();
}
unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc)
{
return (loc) ? (unsigned int)(reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()) : 0;
return (loc) ? (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()) : 0;
}
const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc,const unsigned int ep)
const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc, const unsigned int ep)
{
if (!loc)
return nullptr;
if (ep >= (unsigned int)(reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()))
if (ep >= (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()))
return nullptr;
return reinterpret_cast<const ZT_Endpoint *>(&(reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints()[ep]));
}
int ZT_Locator_verify(const ZT_Locator *loc,const ZT_Identity *signer)
int ZT_Locator_verify(const ZT_Locator *loc, const ZT_Identity *signer)
{
if ((!loc) || (!signer))
return 0;

View file

@ -24,6 +24,7 @@
#define ZT_LOCATOR_MAX_ENDPOINTS 8
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + ZT_FINGERPRINT_MARSHAL_SIZE + 2 + (ZT_LOCATOR_MAX_ENDPOINTS * ZT_ENDPOINT_MARSHAL_SIZE_MAX) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE)
#define ZT_LOCATOR_STRING_SIZE_MAX 4096
namespace ZeroTier {
@ -105,14 +106,27 @@ public:
*/
bool verify(const Identity &id) const noexcept;
/**
* Convert this locator to a string
*
* @param s String buffer
* @return Pointer to buffer
*/
char *toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept;
/**
* Decode a string format locator
*
* @param s Locator from toString()
* @return True if format was valid
*/
bool fromString(const char *s) noexcept;
explicit ZT_INLINE operator bool() const noexcept
{ return m_ts > 0; }
static constexpr int marshalSizeMax() noexcept
{ return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
static constexpr int marshalSizeMax() noexcept { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept;
private: