Plumb new locator code through to Go, fix some cgo issues, fix some compiler warnings.

This commit is contained in:
Adam Ierymenko 2020-05-29 10:16:38 -07:00
parent 864e33cf2d
commit a5390b1bc8
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
17 changed files with 384 additions and 138 deletions

View file

@ -484,10 +484,10 @@ void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender)
} }
#endif #endif
std::string lfJSON; String lfJSON;
OSUtils::readFile((_ztPath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lfJSON); OSUtils::readFile((_ztPath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lfJSON);
if (lfJSON.length() > 0) { if (lfJSON.length() > 0) {
nlohmann::json lfConfig(OSUtils::jsonParse(lfJSON)); nlohmann::json lfConfig(OSUtils::jsonParse(std::string(lfJSON.c_str())));
nlohmann::json &settings = lfConfig["settings"]; nlohmann::json &settings = lfConfig["settings"];
if (settings.is_object()) { if (settings.is_object()) {
nlohmann::json &controllerDb = settings["controllerDb"]; nlohmann::json &controllerDb = settings["controllerDb"];
@ -831,13 +831,13 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
json &v6m = b["v6AssignMode"]; json &v6m = b["v6AssignMode"];
if (!nv6m.is_object()) nv6m = json::object(); if (!nv6m.is_object()) nv6m = json::object();
if (v6m.is_string()) { // backward compatibility if (v6m.is_string()) { // backward compatibility
std::vector<std::string> v6ms(OSUtils::split(OSUtils::jsonString(v6m,"").c_str(),",","","")); Vector<String> v6ms(OSUtils::split(OSUtils::jsonString(v6m,"").c_str(),",","",""));
std::sort(v6ms.begin(),v6ms.end()); std::sort(v6ms.begin(),v6ms.end());
v6ms.erase(std::unique(v6ms.begin(),v6ms.end()),v6ms.end()); v6ms.erase(std::unique(v6ms.begin(),v6ms.end()),v6ms.end());
nv6m["rfc4193"] = false; nv6m["rfc4193"] = false;
nv6m["zt"] = false; nv6m["zt"] = false;
nv6m["6plane"] = false; nv6m["6plane"] = false;
for(std::vector<std::string>::iterator i(v6ms.begin());i!=v6ms.end();++i) { for(Vector<String>::iterator i(v6ms.begin());i!=v6ms.end();++i) {
if (*i == "rfc4193") if (*i == "rfc4193")
nv6m["rfc4193"] = true; nv6m["rfc4193"] = true;
else if (*i == "zt") else if (*i == "zt")
@ -1295,7 +1295,7 @@ void EmbeddedNetworkController::_request(
nc->credentialTimeMaxDelta = credentialtmd; nc->credentialTimeMaxDelta = credentialtmd;
nc->revision = OSUtils::jsonInt(network["revision"],0ULL); nc->revision = OSUtils::jsonInt(network["revision"],0ULL);
nc->issuedTo = identity.address(); nc->issuedTo = identity.address();
memcpy(nc->issuedToFingerprintHash,identity.fingerprint().hash(),sizeof(nc->issuedToFingerprintHash)); memcpy(nc->issuedToFingerprintHash,identity.fingerprint().hash,sizeof(nc->issuedToFingerprintHash));
if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str()); Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str());
nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);

View file

@ -19,31 +19,31 @@ namespace ZeroTier
FileDB::FileDB(const char *path) : FileDB::FileDB(const char *path) :
DB(), DB(),
_path(path), _path(path),
_networksPath(_path + ZT_PATH_SEPARATOR_S + "network"), _networksPath((_path + ZT_PATH_SEPARATOR_S + "network").c_str()),
_running(true) _running(true)
{ {
OSUtils::mkdir(_path.c_str()); OSUtils::mkdir(_path.c_str());
OSUtils::lockDownFile(_path.c_str(),true); OSUtils::lockDownFile(_path.c_str(),true);
OSUtils::mkdir(_networksPath.c_str()); OSUtils::mkdir(_networksPath.c_str());
std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(),false)); Vector<String> networks(OSUtils::listDirectory(_networksPath.c_str(),false));
std::string buf; String buf;
for(auto n=networks.begin();n!=networks.end();++n) { for(auto n=networks.begin();n!=networks.end();++n) {
buf.clear(); buf.clear();
if ((n->length() == 21)&&(OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(),buf))) { if ((n->length() == 21)&&(OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(),buf))) {
try { try {
nlohmann::json network(OSUtils::jsonParse(buf)); nlohmann::json network(OSUtils::jsonParse(std::string(buf.c_str())));
const std::string nwids = network["id"]; const std::string nwids = network["id"];
if (nwids.length() == 16) { if (nwids.length() == 16) {
nlohmann::json nullJson; nlohmann::json nullJson;
_networkChanged(nullJson,network,false); _networkChanged(nullJson,network,false);
std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member"); String membersPath((_networksPath + ZT_PATH_SEPARATOR_S + nwids.c_str() + ZT_PATH_SEPARATOR_S "member").c_str());
std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(),false)); Vector<String> members(OSUtils::listDirectory(membersPath.c_str(),false));
for(auto m=members.begin();m!=members.end();++m) { for(auto m=members.begin();m!=members.end();++m) {
buf.clear(); buf.clear();
if ((m->length() == 15)&&(OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(),buf))) { if ((m->length() == 15)&&(OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(),buf))) {
try { try {
nlohmann::json member(OSUtils::jsonParse(buf)); nlohmann::json member(OSUtils::jsonParse(std::string(buf.c_str())));
const std::string addrs = member["id"]; const std::string addrs = member["id"];
if (addrs.length() == 10) { if (addrs.length() == 10) {
nlohmann::json nullJson2; nlohmann::json nullJson2;

View file

@ -33,8 +33,8 @@ public:
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress); virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
protected: protected:
std::string _path; String _path;
std::string _networksPath; String _networksPath;
std::thread _onlineUpdateThread; std::thread _onlineUpdateThread;
std::map< uint64_t,std::map<uint64_t,std::map<int64_t,InetAddress> > > _online; std::map< uint64_t,std::map<uint64_t,std::map<int64_t,InetAddress> > > _online;
std::mutex _online_l; std::mutex _online_l;

View file

@ -38,9 +38,6 @@ Commands:
service Start as service service Start as service
status Show node status, identity, and config status Show node status, identity, and config
peers List all VL1 peers peers List all VL1 peers
roots List root peers
addroot <path | URL> Add root from root spec file or URL
removeroot <address> Remove a peer from the root list
join <network ID> [fingerprint] Join a virtual network join <network ID> [fingerprint] Join a virtual network
leave <network ID> Leave a virtual network leave <network ID> Leave a virtual network
networks List VL2 virtual networks networks List VL2 virtual networks
@ -63,7 +60,13 @@ Commands:
validate <identity> Locally validate an identity validate <identity> Locally validate an identity
sign <identity> <file> Sign a file with an identity's key sign <identity> <file> Sign a file with an identity's key
verify <identity> <file> <sig> Verify a signature verify <identity> <file> <sig> Verify a signature
makeroot <identity> <address[,...]> Make a root spec (see docs) 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
The 'service' command does not exit until the service receives a signal. 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 This is typically run from launchd (Mac), systemd or init (Linux), a Windows

View file

@ -102,10 +102,6 @@ func Identity(args []string) {
} }
} }
case "makeroot":
if len(args) >= 2 {
}
} }
} }
Help() Help()

View file

@ -352,11 +352,8 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
if err != nil || len(rsdata) == 0 { if err != nil || len(rsdata) == 0 {
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"read error"}) _ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"read error"})
} else { } else {
p, err := node.AddRoot(rsdata) // TODO
if err != nil { _ = apiSendObj(out, req, http.StatusOK, nil)
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"invalid root spec"})
}
_ = apiSendObj(out, req, http.StatusOK, p)
} }
} else { } else {
out.Header().Set("Allow", "POST, PUT") out.Header().Set("Allow", "POST, PUT")

View file

@ -1,13 +1,15 @@
package zerotier package zerotier
// #include "../../native/GoGlue.h" // #include "../../native/GoGlue.h"
// static inline const ZT_Fingerprint *_getFP(const ZT_Endpoint *ep) { return &(ep->value.fp); }
// 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); }
import "C" import "C"
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strconv"
"strings"
"unsafe" "unsafe"
) )
@ -29,26 +31,57 @@ type Endpoint struct {
// Type returns this endpoint's type. // Type returns this endpoint's type.
func (ep *Endpoint) Type() int { func (ep *Endpoint) Type() int {
return ep.cep._type return int(ep.cep._type)
} }
// InetAddress gets this Endpoint as an InetAddress or nil if its type is not addressed by one. // InetAddress gets this Endpoint as an InetAddress or nil if its type is not addressed by one.
func (ep *Endpoint) InetAddress() *InetAddress { func (ep *Endpoint) InetAddress() *InetAddress {
switch ep.cep._type { switch ep.cep._type {
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2: case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2:
ua := sockaddrStorageToUDPAddr(&(ep.cep.a.ss)) ua := sockaddrStorageToUDPAddr(C._getSS(&ep.cep))
return &InetAddress{IP: ua.IP, Port: ua.Port} return &InetAddress{IP: ua.IP, Port: ua.Port}
} }
return nil return nil
} }
// Address returns a ZeroTier address if this is a ZeroTier endpoint or a zero address otherwise.
func (ep *Endpoint) Address() Address {
switch ep.cep._type {
case EndpointTypeZeroTier:
return Address(C._getAddress(&ep.cep))
}
return Address(0)
}
// Fingerprint returns a fingerprint if this is a ZeroTier endpoint or nil otherwise.
func (ep *Endpoint) Fingerprint() *Fingerprint {
switch ep.cep._type {
case EndpointTypeZeroTier:
cfp := C._getFP(&ep.cep)
fp := Fingerprint{Address: Address(cfp.address), Hash: C.GoBytes(unsafe.Pointer(&cfp.hash[0]), 48)}
if allZero(fp.Hash) {
fp.Hash = nil
}
return &fp
}
return nil
}
// MAC returns a MAC address if this is an Ethernet type endpoint or a zero address otherwise.
func (ep *Endpoint) MAC() MAC {
switch ep.cep._type {
case EndpointTypeEthernet, EndpointTypeWifiDirect, EndpointTypeBluetooth:
return MAC(C._getMAC(&ep.cep))
}
return MAC(0)
}
func (ep *Endpoint) String() string { func (ep *Endpoint) String() string {
switch ep.cep._type { switch ep.cep._type {
case EndpointTypeZeroTier: case EndpointTypeZeroTier:
fp := Fingerprint{Address: Address(ep.cep.a.fp.address), Hash: *((*[48]byte)(unsafe.Pointer(&ep.cep.a.fp.hash[0])))} return fmt.Sprintf("%d/%s", ep.Type(), ep.Fingerprint().String())
return fmt.Sprintf("%d/%s", ep.Type(), fp.String())
case EndpointTypeEthernet, EndpointTypeWifiDirect, EndpointTypeBluetooth: case EndpointTypeEthernet, EndpointTypeWifiDirect, EndpointTypeBluetooth:
return fmt.Sprintf("%d/%s", ep.Type(), MAC(ep.cep.a.mac).String()) return fmt.Sprintf("%d/%s", ep.Type(), ep.MAC().String())
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2: case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2:
return fmt.Sprintf("%d/%s", ep.Type(), ep.InetAddress().String()) return fmt.Sprintf("%d/%s", ep.Type(), ep.InetAddress().String())
} }
@ -61,33 +94,6 @@ func (ep *Endpoint) MarshalJSON() ([]byte, error) {
} }
func (ep *Endpoint) UnmarshalJSON(j []byte) error { func (ep *Endpoint) UnmarshalJSON(j []byte) error {
var s string // TODO
err := json.Unmarshal(j, &s)
if err != nil {
return err
}
slashIdx := strings.IndexRune(s, '/')
if slashIdx < 0 {
ep.cep._type = C.uint(strconv.ParseUint(s, 10, 32))
} else if slashIdx == 0 || slashIdx >= (len(s)-1) {
return ErrInvalidParameter
} else {
ep.cep._type = C.uint(strconv.ParseUint(s[0:slashIdx], 10, 32))
s = s[slashIdx+1:]
}
switch ep.cep._type {
case EndpointTypeNil:
return nil
case EndpointTypeZeroTier:
fp, err := NewFingerprintFromString(s)
if err != nil {
return err
}
ep.cep.a.fp.address = C.uint64_t(fp.Address)
copy(((*[48]byte)(unsafe.Pointer(&ep.cep.a.fp.hash[0])))[:], fp.Hash[:])
return nil return nil
} }
return ErrInvalidParameter
}

View file

@ -53,6 +53,18 @@ func NewFingerprintFromString(fps string) (*Fingerprint, error) {
return &Fingerprint{Address: a, Hash: nil}, nil return &Fingerprint{Address: a, Hash: nil}, nil
} }
func newFingerprintFromCFingerprint(cfp *C.ZT_Fingerprint) *Fingerprint {
var fp Fingerprint
if uintptr(unsafe.Pointer(cfp)) != 0 {
fp.Address = Address(cfp.address)
fp.Hash = C.GoBytes(unsafe.Pointer(&cfp.hash[0]), 48)
if allZero(fp.Hash) {
fp.Hash = nil
}
}
return &fp
}
func (fp *Fingerprint) String() string { func (fp *Fingerprint) String() string {
if len(fp.Hash) == 48 { 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))
@ -64,7 +76,7 @@ func (fp *Fingerprint) Equals(fp2 *Fingerprint) bool {
return fp.Address == fp2.Address && bytes.Equal(fp.Hash[:], fp2.Hash[:]) return fp.Address == fp2.Address && bytes.Equal(fp.Hash[:], fp2.Hash[:])
} }
func (fp *Fingerprint) apiFingerprint() *C.ZT_Fingerprint { func (fp *Fingerprint) cFingerprint() *C.ZT_Fingerprint {
var apifp C.ZT_Fingerprint var apifp C.ZT_Fingerprint
apifp.address = C.uint64_t(fp.Address) apifp.address = C.uint64_t(fp.Address)
copy((*[48]byte)(unsafe.Pointer(&apifp.hash[0]))[:], fp.Hash[:]) copy((*[48]byte)(unsafe.Pointer(&apifp.hash[0]))[:], fp.Hash[:])

View file

@ -20,7 +20,6 @@ import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"runtime" "runtime"
"strings" "strings"
@ -92,7 +91,13 @@ func (id *Identity) initCIdentityPtr() bool {
// NewIdentity generates a new identity of the selected type // NewIdentity generates a new identity of the selected type
func NewIdentity(identityType int) (*Identity, error) { func NewIdentity(identityType int) (*Identity, error) {
return newIdentityFromCIdentity(C.ZT_Identity_new(C.enum_ZT_Identity_Type(identityType))) switch identityType {
case C.ZT_IDENTITY_TYPE_C25519:
return newIdentityFromCIdentity(C.ZT_Identity_new(C.ZT_IDENTITY_TYPE_C25519))
case C.ZT_IDENTITY_TYPE_P384:
return newIdentityFromCIdentity(C.ZT_Identity_new(C.ZT_IDENTITY_TYPE_P384))
}
return nil, ErrInvalidParameter
} }
// NewIdentityFromString generates a new identity from its string representation. // NewIdentityFromString generates a new identity from its string representation.
@ -231,29 +236,6 @@ func (id *Identity) Verify(msg, sig []byte) bool {
return C.ZT_Identity_verify(id.cid, dataP, C.uint(len(msg)), unsafe.Pointer(&sig[0]), C.uint(len(sig))) != 0 return C.ZT_Identity_verify(id.cid, dataP, C.uint(len(msg)), unsafe.Pointer(&sig[0]), C.uint(len(sig))) != 0
} }
// MakeRoot generates a root spec consisting of a serialized identity and a root locator.
func (id *Identity) MakeRoot(addresses []InetAddress) ([]byte, error) {
if len(addresses) == 0 {
return nil, errors.New("at least one static address must be specified for a root")
}
if !id.initCIdentityPtr() {
return nil, errors.New("error initializing ZT_Identity")
}
ss := make([]C.struct_sockaddr_storage, len(addresses))
for i := range addresses {
if !makeSockaddrStorage(addresses[i].IP, addresses[i].Port, &ss[i]) {
return nil, errors.New("invalid address in address list")
}
}
var buf [8192]byte
rl := C.ZT_Identity_makeRootSpecification(id.cid, C.int64_t(TimeMs()), &ss[0], C.uint(len(ss)), unsafe.Pointer(&buf[0]), 8192)
if rl <= 0 {
return nil, errors.New("unable to make root specification (does identity contain a secret key?)")
}
return buf[0:int(rl)], nil
}
// Equals performs a deep equality test between this and another identity // Equals performs a deep equality test between this and another identity
func (id *Identity) Equals(id2 *Identity) bool { func (id *Identity) Equals(id2 *Identity) bool {
if id2 == nil { if id2 == nil {

View file

@ -0,0 +1,86 @@
/*
* 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 zerotier
// #include "../../native/GoGlue.h"
import "C"
import (
"runtime"
"unsafe"
)
type Locator struct {
cl unsafe.Pointer
}
func locatorFinalizer(obj interface{}) {
if obj != nil {
C.ZT_Locator_delete(obj.(Locator).cl)
}
}
func NewLocator(ts int64, endpoints []Endpoint, signer *Identity) (*Locator, error) {
if ts <= 0 || len(endpoints) == 0 || signer == nil {
return nil, ErrInvalidParameter
}
eps := make([]C.ZT_Endpoint, 0, len(endpoints))
for _, e := range endpoints {
eps = append(eps, e.cep)
}
signer.initCIdentityPtr()
loc := C.ZT_Locator_create(C.int64_t(ts), &eps[0], C.uint(len(eps)), signer.cid)
if uintptr(loc) == 0 {
return nil, ErrInvalidParameter
}
goloc := new(Locator)
goloc.cl = unsafe.Pointer(loc)
runtime.SetFinalizer(goloc, locatorFinalizer)
return goloc, nil
}
func NewLocatorFromBytes(lb []byte) (*Locator, error) {
if len(lb) == 0 {
return nil, ErrInvalidParameter
}
loc := C.ZT_Locator_unmarshal(unsafe.Pointer(&lb[0]), C.uint(len(lb)))
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) {
cfp := C.ZT_Locator_fingerprint(loc.cl)
if uintptr(unsafe.Pointer(cfp)) == 0 {
err = ErrInternal
return
}
fp = newFingerprintFromCFingerprint(cfp)
epc := int(C.ZT_Locator_endpointCount(loc.cl))
eps = make([]Endpoint, epc)
for i:=0;i<epc;i++ {
eps[i].cep = *C.ZT_Locator_endpoint(loc.cl, C.uint(i))
}
if id != nil {
id.initCIdentityPtr()
valid = C.ZT_Locator_verify(loc.cl, id.cid) != 0
}
return
}

View file

@ -410,7 +410,7 @@ func (n *Node) Join(nwid NetworkID, controllerFingerprint *Fingerprint, settings
} }
var fp *C.ZT_Fingerprint var fp *C.ZT_Fingerprint
if controllerFingerprint != nil { if controllerFingerprint != nil {
fp = controllerFingerprint.apiFingerprint() fp = controllerFingerprint.cFingerprint()
} }
ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid), fp) ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid), fp)
if ntap == nil { if ntap == nil {
@ -448,31 +448,13 @@ func (n *Node) Leave(nwid NetworkID) error {
return nil return nil
} }
func (n *Node) AddRoot(spec []byte) (*Peer, error) { func (n *Node) AddRoot(id *Identity, loc *Locator) (*Peer, error) {
if len(spec) == 0 { // TODO
return nil, ErrInvalidParameter return nil, nil
}
var address C.uint64_t
res := C.ZT_Node_addRoot(n.zn, nil, unsafe.Pointer(&spec[0]), C.uint(len(spec)), &address)
if res != 0 {
return nil, ErrInvalidParameter
}
peers := n.Peers()
for _, p := range peers {
if p.Address == Address(uint64(address)) {
return p, nil
}
}
return nil, ErrInternal
} }
func (n *Node) RemoveRoot(address Address) { func (n *Node) RemoveRoot(address Address) {
var cfp C.ZT_Fingerprint C.ZT_Node_removeRoot(n.zn, nil, C.uint64_t(address))
cfp.address = C.uint64_t(address)
for i := 0; i < 48; i++ {
cfp.hash[i] = 0
}
C.ZT_Node_removeRoot(n.zn, nil, &cfp)
} }
// GetNetwork looks up a network by ID or returns nil if not joined // GetNetwork looks up a network by ID or returns nil if not joined
@ -512,9 +494,10 @@ func (n *Node) Peers() []*Peer {
p2.Paths = make([]Path, 0, int(p.pathCount)) p2.Paths = make([]Path, 0, int(p.pathCount))
for j := 0; j < len(p2.Paths); j++ { for j := 0; j < len(p2.Paths); j++ {
pt := (*C.ZT_PeerPhysicalPath)(unsafe.Pointer(uintptr(unsafe.Pointer(p.paths)) + uintptr(j*C.sizeof_ZT_PeerPhysicalPath))) pt := (*C.ZT_Path)(unsafe.Pointer(uintptr(unsafe.Pointer(p.paths)) + uintptr(j*C.sizeof_ZT_Path)))
if pt.alive != 0 { if pt.alive != 0 {
a := sockaddrStorageToUDPAddr(&pt.address) ep := Endpoint{pt.endpoint}
a := ep.InetAddress()
if a != nil { if a != nil {
p2.Paths = append(p2.Paths, Path{ p2.Paths = append(p2.Paths, Path{
IP: a.IP, IP: a.IP,
@ -528,7 +511,7 @@ func (n *Node) Peers() []*Peer {
peers = append(peers, p2) peers = append(peers, p2)
} }
C.ZT_Node_freeQueryResult(n.zn, unsafe.Pointer(pl)) C.ZT_freeQueryResult(unsafe.Pointer(pl))
} }
sort.Slice(peers, func(a, b int) bool { sort.Slice(peers, func(a, b int) bool {
return peers[a].Address < peers[b].Address return peers[a].Address < peers[b].Address

View file

@ -2132,7 +2132,11 @@ ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id);
* @param signer Identity to sign locator (must include private key) * @param signer Identity to sign locator (must include private key)
* @return Locator or NULL on error (too many endpoints or identity does not have private key) * @return Locator or NULL on error (too many endpoints or identity does not have private key)
*/ */
ZT_SDK_API ZT_Locator *ZT_Locator_create(int64_t ts,const ZT_Endpoint *endpoints,unsigned int endpointCount,const ZT_Identity *signer); ZT_SDK_API ZT_Locator *ZT_Locator_create(
int64_t ts,
const ZT_Endpoint *endpoints,
unsigned int endpointCount,
const ZT_Identity *signer);
/** /**
* Decode a serialized locator * Decode a serialized locator
@ -2141,7 +2145,29 @@ ZT_SDK_API ZT_Locator *ZT_Locator_create(int64_t ts,const ZT_Endpoint *endpoints
* @param len Length of data * @param len Length of data
* @return Locator or NULL if data is not valid * @return Locator or NULL if data is not valid
*/ */
ZT_SDK_API ZT_Locator *ZT_Locator_unmarshal(const void *data,unsigned int len); ZT_SDK_API ZT_Locator *ZT_Locator_unmarshal(
const void *data,
unsigned int len);
/**
* Serialize this locator into a buffer
*
* @param loc Locator to serialize
* @param buf Buffer to store bytes
* @param bufSize Size of buffer in bytes (needs to be at least 2048 bytes in size)
* @return Number of bytes stored to buf or -1 on error such as buffer too small
*/
ZT_SDK_API int ZT_Locator_marshal(const ZT_Locator *loc,void *buf,unsigned int bufSize);
/**
* Get a pointer to the fingerprint of this locator's signer.
*
* The returned pointer remains valid as long as the Locator is not deleted.
*
* @param loc Locator to query
* @return Pointer to fingerprint of signer
*/
ZT_SDK_API const ZT_Fingerprint *ZT_Locator_fingerprint(const ZT_Locator *loc);
/** /**
* Get the number of endpoints in this locator * Get the number of endpoints in this locator
@ -2159,7 +2185,15 @@ ZT_SDK_API unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc);
* @param ep Endpoint number from 0 to 1 - endpointCount() * @param ep Endpoint number from 0 to 1 - endpointCount()
* @return Endpoint or NULL if out of bounds * @return Endpoint or NULL if out of bounds
*/ */
ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint(const unsigned int ep); ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc,const unsigned int ep);
/**
* Verify this locator's signature
*
* @param signer Signing identity
* @return Non-zero if locator is valid
*/
ZT_SDK_API int ZT_Locator_verify(const ZT_Locator *loc,const ZT_Identity *signer);
/** /**
* Delete a locator * Delete a locator
@ -2178,7 +2212,11 @@ ZT_SDK_API void ZT_Locator_delete(ZT_Locator *loc);
* @param revision Result: revision * @param revision Result: revision
* @param build Result: build number * @param build Result: build number
*/ */
ZT_SDK_API void ZT_version(int *major,int *minor,int *revision,int *build); ZT_SDK_API void ZT_version(
int *major,
int *minor,
int *revision,
int *build);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -157,8 +157,11 @@ class String : public std::basic_string< char,std::char_traits<char>,Utils::Mall
{ {
public: public:
ZT_INLINE String() {} ZT_INLINE String() {}
explicit ZT_INLINE String(const char *const s) { assign(s); } ZT_INLINE String(const String &s) : std::basic_string< char,std::char_traits<char>,Utils::Mallocator<char> >(s.c_str()) {}
ZT_INLINE String(const std::string &s) : std::basic_string< char,std::char_traits<char>,Utils::Mallocator<char> >(s.c_str()) {}
ZT_INLINE String(const char *const s) : std::basic_string< char,std::char_traits<char>,Utils::Mallocator<char> >(s) {}
ZT_INLINE String &operator=(const char *const s) { assign(s); return *this; } ZT_INLINE String &operator=(const char *const s) { assign(s); return *this; }
ZT_INLINE String &operator=(const std::string &s) { assign(s.c_str()); return *this; }
}; };
} // ZeroTier } // ZeroTier

View file

@ -147,6 +147,7 @@ int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept
// to the unmarshal method of InetAddress and considered UDP endpoints. // to the unmarshal method of InetAddress and considered UDP endpoints.
// This allows backward compatibility with old endpoint fields in the // This allows backward compatibility with old endpoint fields in the
// protocol that were serialized InetAddress instances. // protocol that were serialized InetAddress instances.
if (data[0] < 16) { if (data[0] < 16) {
switch (data[0]) { switch (data[0]) {
case 0: case 0:

View file

@ -20,6 +20,7 @@
#include "Utils.hpp" #include "Utils.hpp"
#define ZT_FINGERPRINT_STRING_SIZE_MAX 128 #define ZT_FINGERPRINT_STRING_SIZE_MAX 128
#define ZT_FINGERPRINT_MARSHAL_SIZE 53
namespace ZeroTier { namespace ZeroTier {
@ -93,6 +94,25 @@ public:
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return this->address != 0; } { return this->address != 0; }
static constexpr int marshalSizeMax() noexcept
{ return ZT_FINGERPRINT_MARSHAL_SIZE; }
ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept
{
Address(this->address).copyTo(data);
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + ZT_ADDRESS_LENGTH,this->hash);
return ZT_FINGERPRINT_MARSHAL_SIZE;
}
ZT_INLINE int unmarshal(const uint8_t *const data, int len) noexcept
{
if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE))
return -1;
this->address = Address(data);
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(hash,data + ZT_ADDRESS_LENGTH);
return ZT_FINGERPRINT_MARSHAL_SIZE;
}
ZT_INLINE bool operator==(const Fingerprint &h) const noexcept ZT_INLINE bool operator==(const Fingerprint &h) const noexcept
{ return ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); } { return ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); }

View file

@ -12,6 +12,7 @@
/****/ /****/
#include "Locator.hpp" #include "Locator.hpp"
#include "Identity.hpp"
#include <algorithm> #include <algorithm>
@ -30,6 +31,7 @@ bool Locator::add(const Endpoint &ep)
bool Locator::sign(const int64_t ts, const Identity &id) noexcept bool Locator::sign(const int64_t ts, const Identity &id) noexcept
{ {
m_ts = ts; m_ts = ts;
m_signer = id.fingerprint();
std::sort(m_endpoints.begin(), m_endpoints.end()); std::sort(m_endpoints.begin(), m_endpoints.end());
uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX]; uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX];
@ -45,58 +47,81 @@ bool Locator::sign(const int64_t ts, const Identity &id) noexcept
bool Locator::verify(const Identity &id) const noexcept bool Locator::verify(const Identity &id) const noexcept
{ {
if (m_ts <= 0) try {
return false; if ((m_ts > 0) && (m_signer == id.fingerprint())) {
uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX]; uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const unsigned int signlen = marshal(signdata, true); const unsigned int signlen = marshal(signdata, true);
return id.verify(signdata, signlen, m_signature.data(), m_signature.size()); return id.verify(signdata, signlen, m_signature.data(), m_signature.size());
} }
} catch ( ... ) {} // fail verify on any unexpected exception
return false;
}
int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool excludeSignature) const noexcept 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); Utils::storeBigEndian<uint64_t>(data, (uint64_t) m_ts);
Utils::storeBigEndian<uint16_t>(data + 8, (uint16_t) m_endpoints.size()); int p = 8;
int p = 10;
int l = m_signer.marshal(data + p);
if (l <= 0)
return -1;
p += l;
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_endpoints.size());
p += 2;
for (Vector<Endpoint>::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) { for (Vector<Endpoint>::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) {
int l = e->marshal(data + p); l = e->marshal(data + p);
if (l <= 0) if (l <= 0)
return -1; return -1;
p += l; p += l;
} }
Utils::storeAsIsEndian<uint16_t>(data + p, 0); // length of meta-data, currently always 0 Utils::storeAsIsEndian<uint16_t>(data + p, 0); // length of meta-data, currently always 0
p += 2; p += 2;
if (!excludeSignature) { if (!excludeSignature) {
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signature.size()); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signature.size());
p += 2; p += 2;
Utils::copy(data + p, m_signature.data(), m_signature.size()); Utils::copy(data + p, m_signature.data(), m_signature.size());
p += (int) m_signature.size(); p += (int) m_signature.size();
} }
return p; return p;
} }
int Locator::unmarshal(const uint8_t *data, const int len) noexcept int Locator::unmarshal(const uint8_t *data, const int len) noexcept
{ {
if (unlikely(len < 10)) if (unlikely(len < 8))
return -1; return -1;
m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data); m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data);
int p = 8;
int l = m_signer.unmarshal(data + p,len - p);
if (l <= 0)
return -1;
p += l;
if (unlikely(p + 2) > len)
return -1;
unsigned int endpointCount = Utils::loadBigEndian<uint16_t>(data + 8); unsigned int endpointCount = Utils::loadBigEndian<uint16_t>(data + 8);
if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)) if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS))
return -1; return -1;
int p = 10;
m_endpoints.resize(endpointCount); m_endpoints.resize(endpointCount);
m_endpoints.shrink_to_fit(); m_endpoints.shrink_to_fit();
for (unsigned int i = 0;i < endpointCount;++i) { for (unsigned int i = 0;i < endpointCount;++i) {
int l = m_endpoints[i].unmarshal(data + p, len - p); l = m_endpoints[i].unmarshal(data + p, len - p);
if (l <= 0) if (l <= 0)
return -1; return -1;
p += l; p += l;
} }
if (unlikely((p + 2) > len)) if (unlikely((p + 2) > len))
return -1; return -1;
p += 2 + (int) Utils::loadBigEndian<uint16_t>(data + p); p += 2 + (int) Utils::loadBigEndian<uint16_t>(data + p);
if (unlikely((p + 2) > len)) if (unlikely((p + 2) > len))
return -1; return -1;
unsigned int siglen = Utils::loadBigEndian<uint16_t>(data + p); const unsigned int siglen = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; 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; return -1;
@ -105,7 +130,93 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
p += siglen; p += siglen;
if (unlikely(p > len)) if (unlikely(p > len))
return -1; return -1;
return p; return p;
} }
} // namespace ZeroTier } // namespace ZeroTier
extern "C" {
ZT_Locator *ZT_Locator_create(
int64_t ts,
const ZT_Endpoint *endpoints,
unsigned int endpointCount,
const ZT_Identity *signer)
{
try {
if ((ts <= 0) || (!endpoints) || (endpointCount == 0) || (!signer))
return nullptr;
ZeroTier::Locator *loc = new ZeroTier::Locator();
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))) {
delete loc;
return nullptr;
}
return reinterpret_cast<ZT_Locator *>(loc);
} catch ( ... ) {
return nullptr;
}
}
ZT_Locator *ZT_Locator_unmarshal(
const void *data,
unsigned int len)
{
try {
if ((!data) || (len == 0))
return nullptr;
ZeroTier::Locator *loc = new ZeroTier::Locator();
if (loc->unmarshal(reinterpret_cast<const uint8_t *>(data),(int)len) <= 0) {
delete loc;
return nullptr;
}
return reinterpret_cast<ZT_Locator *>(loc);
} catch ( ... ) {
return nullptr;
}
}
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);
}
const ZT_Fingerprint *ZT_Locator_fingerprint(const ZT_Locator *loc)
{
if (!loc)
return nullptr;
return (ZT_Fingerprint *)(&(reinterpret_cast<const ZeroTier::Locator *>(loc)->signer()));
}
unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc)
{
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)
{
if (!loc)
return nullptr;
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)
{
if ((!loc) || (!signer))
return 0;
return reinterpret_cast<const ZeroTier::Locator *>(loc)->verify(*reinterpret_cast<const ZeroTier::Identity *>(signer)) ? 1 : 0;
}
void ZT_Locator_delete(ZT_Locator *loc)
{
if (loc)
delete reinterpret_cast<ZeroTier::Locator *>(loc);
}
} // C API functions

View file

@ -23,7 +23,7 @@
#include "Containers.hpp" #include "Containers.hpp"
#define ZT_LOCATOR_MAX_ENDPOINTS 8 #define ZT_LOCATOR_MAX_ENDPOINTS 8
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_LOCATOR_MAX_ENDPOINTS * ZT_ENDPOINT_MARSHAL_SIZE_MAX) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE) #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)
namespace ZeroTier { namespace ZeroTier {
@ -45,6 +45,7 @@ public:
ZT_INLINE Locator(const Locator &loc) noexcept : ZT_INLINE Locator(const Locator &loc) noexcept :
m_ts(loc.m_ts), m_ts(loc.m_ts),
m_signer(loc.m_signer),
m_endpoints(loc.m_endpoints), m_endpoints(loc.m_endpoints),
m_signature(loc.m_signature), m_signature(loc.m_signature),
__refCount(0) __refCount(0)
@ -56,6 +57,12 @@ public:
ZT_INLINE int64_t timestamp() const noexcept ZT_INLINE int64_t timestamp() const noexcept
{ return m_ts; } { return m_ts; }
/**
* @return Fingerprint of identity that signed this locator
*/
ZT_INLINE const Fingerprint &signer() const noexcept
{ return m_signer; }
/** /**
* @return Endpoints specified in locator * @return Endpoints specified in locator
*/ */
@ -110,6 +117,7 @@ public:
private: private:
int64_t m_ts; int64_t m_ts;
Fingerprint m_signer;
Vector<Endpoint> m_endpoints; Vector<Endpoint> m_endpoints;
FCV<uint8_t, ZT_SIGNATURE_BUFFER_SIZE> m_signature; FCV<uint8_t, ZT_SIGNATURE_BUFFER_SIZE> m_signature;
std::atomic<int> __refCount; std::atomic<int> __refCount;