A bunch of cleanup, make Location serialization format saner, reduce core memory use.

This commit is contained in:
Adam Ierymenko 2020-07-31 13:27:27 -07:00
parent 0c56d7c769
commit 1fc4dce835
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
16 changed files with 251 additions and 195 deletions

View file

@ -17,11 +17,9 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"zerotier/pkg/zerotier" "zerotier/pkg/zerotier"
) )
func Cert(basePath, authToken string, args []string, jsonOutput bool) int { func Cert(basePath, authToken string, args []string, jsonOutput bool) int {
if len(args) < 1 { if len(args) < 1 {
Help() Help()
@ -52,28 +50,18 @@ func Cert(basePath, authToken string, args []string, jsonOutput bool) int {
} }
case "newcsr": case "newcsr":
if len(args) < 3 { if len(args) != 4 {
Help() Help()
return 1 return 1
} }
var cs zerotier.CertificateSubject var cs zerotier.CertificateSubject
csb, err := ioutil.ReadFile(args[1]) err := readJSONFile(args[1], &cs)
if err != nil {
fmt.Printf("ERROR: unable to read subject from %s: %s\n", args[1], err.Error())
return 1
}
err = json.Unmarshal(csb, &cs)
if err != nil { if err != nil {
fmt.Printf("ERROR: unable to read subject from %s: %s\n", args[1], err.Error()) fmt.Printf("ERROR: unable to read subject from %s: %s\n", args[1], err.Error())
return 1 return 1
} }
var subj zerotier.CertificateSubjectUniqueIDSecret var subj zerotier.CertificateSubjectUniqueIDSecret
subjb, err := ioutil.ReadFile(args[2]) err = readJSONFile(args[2], &subj)
if err != nil {
fmt.Printf("ERROR: unable to read unique ID secret from %s: %s\n", args[2], err.Error())
return 1
}
err = json.Unmarshal(subjb, &subj)
if err != nil { if err != nil {
fmt.Printf("ERROR: unable to read unique ID secret from %s: %s\n", args[2], err.Error()) fmt.Printf("ERROR: unable to read unique ID secret from %s: %s\n", args[2], err.Error())
return 1 return 1
@ -83,13 +71,56 @@ func Cert(basePath, authToken string, args []string, jsonOutput bool) int {
fmt.Printf("ERROR: problem creating CSR: %s\n", err.Error()) fmt.Printf("ERROR: problem creating CSR: %s\n", err.Error())
return 1 return 1
} }
if len(args) == 3 { err = ioutil.WriteFile(args[3], csr, 0644)
_, _ = os.Stdout.Write(csr) if err == nil {
fmt.Printf("Wrote CSR to %s\n", args[3])
} else { } else {
_ = ioutil.WriteFile(args[3], csr, 0644) fmt.Printf("ERROR: unable to write CSR to %s: %s\n", args[3], err.Error())
return 1
} }
case "sign": case "sign":
if len(args) != 4 {
Help()
return 1
}
var csr zerotier.Certificate
csrBytes, err := ioutil.ReadFile(args[1])
if err != nil {
fmt.Printf("ERROR: unable to read CSR from %s: %s\n", args[1], err.Error())
return 1
}
c, err := zerotier.NewCertificateFromBytes(csrBytes, false)
if err != nil {
fmt.Printf("ERROR: CSR in %s is invalid: %s\n", args[1], err.Error())
return 1
}
id := readIdentity(args[2])
if id == nil {
fmt.Printf("ERROR: unable to read identity from %s\n", args[2])
return 1
}
if !id.HasPrivate() {
fmt.Printf("ERROR: signing identity in %s lacks private key\n", args[2])
return 1
}
c, err = csr.Sign(id)
if err != nil {
fmt.Printf("ERROR: error signing CSR or generating certificate: %s\n", err.Error())
return 1
}
cb, err := c.Marshal()
if err != nil {
fmt.Printf("ERROR: error marshaling signed certificate: %s\n", err.Error())
return 1
}
err = ioutil.WriteFile(args[3], cb, 0644)
if err == nil {
fmt.Printf("Wrote signed certificate to %s\n", args[3])
} else {
fmt.Printf("ERROR: unable to write signed certificate to %s: %s\n", args[3], err.Error())
return 1
}
case "verify": case "verify":

View file

@ -75,15 +75,16 @@ 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
certs List certificates
cert <command> [args] - Certificate commands cert <command> [args] - Certificate commands
show [serial] List or show details of a certificate show [serial] List or show details of a certificate
newsid [secret] Create a new subject unique ID newsid <secret out> Create a new subject unique ID
newcsr <subject> <secret> [csr] Create a subject CSR newcsr <subject> <secret> <csr out> Create a subject CSR
sign <csr> <identity> [certificate] Sign a CSR to create a certificate sign <csr> <identity> <cert out> Sign a CSR to create a certificate
verify <certificate> Verify a certificate verify <cert> Verify a certificate
import <certificate> [trust,[trust]] Import certificate into this node import <cert> [trust,[trust]] Import certificate into this node
rootca Certificate is a root CA rootca Certificate is a root CA
rootset ZeroTier root node set ztrootset ZeroTier root node set
restore Re-import default certificates restore Re-import default certificates
export <serial> [path] Export a certificate from this node export <serial> [path] Export a certificate from this node
delete <serial|ALL> Delete certificate from this node delete <serial|ALL> Delete certificate from this node

View file

@ -203,3 +203,11 @@ func networkStatusStr(status int) string {
} }
return "???" return "???"
} }
func readJSONFile(p string, obj interface{}) error {
b, err := ioutil.ReadFile(p)
if err != nil {
return err
}
return json.Unmarshal(b, obj)
}

View file

@ -81,8 +81,12 @@ func main() {
// Reduce Go's thread and memory footprint. This would slow things down if the Go code // Reduce Go's thread and memory footprint. This would slow things down if the Go code
// were doing a lot, but it's not. It just manages the core and is not directly involved // were doing a lot, but it's not. It just manages the core and is not directly involved
// in pushing a lot of packets around. If that ever changes this should be adjusted. // in pushing a lot of packets around. If that ever changes this should be adjusted.
if runtime.NumCPU() > 1 {
runtime.GOMAXPROCS(2)
} else {
runtime.GOMAXPROCS(1) runtime.GOMAXPROCS(1)
debug.SetGCPercent(15) }
debug.SetGCPercent(10)
globalOpts := flag.NewFlagSet("global", flag.ContinueOnError) globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities
@ -142,6 +146,8 @@ func main() {
exitCode = cli.Set(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs) exitCode = cli.Set(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs)
case "identity": case "identity":
exitCode = cli.Identity(cmdArgs) exitCode = cli.Identity(cmdArgs)
case "certs", "listcerts", "lscerts": // same as "cert show" with no specific serial to show
exitCode = cli.Cert(basePath, authToken(basePath, *tflag, *tTflag), []string{"show"}, *jflag)
case "cert": case "cert":
exitCode = cli.Cert(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs, *jflag) exitCode = cli.Cert(basePath, authToken(basePath, *tflag, *tTflag), cmdArgs, *jflag)
} }

View file

@ -211,7 +211,7 @@ public:
* @return Number of entries * @return Number of entries
*/ */
ZT_INLINE unsigned int size() const noexcept ZT_INLINE unsigned int size() const noexcept
{ return m_entries.size(); } { return (unsigned int)m_entries.size(); }
/** /**
* @return True if dictionary is not empty * @return True if dictionary is not empty

View file

@ -20,14 +20,14 @@
/** /**
* Number of buckets to use to maintain a list of expected replies. * Number of buckets to use to maintain a list of expected replies.
* *
* Making this a power of two improves efficiency a little by allowing bit shift division. * This must be a power of two. Memory consumed will be about this*4 bytes.
*/ */
#define ZT_EXPECT_BUCKETS 32768 #define ZT_EXPECT_BUCKETS 32768
/** /**
* 1/2 the TTL for expected replies in milliseconds * 1/2 the TTL for expected replies in milliseconds
* *
* Making this a power of two improves efficiency a little by allowing bit shift division. * This must be a power of two.
*/ */
#define ZT_EXPECT_TTL 4096LL #define ZT_EXPECT_TTL 4096LL
@ -39,7 +39,8 @@ namespace ZeroTier {
class Expect class Expect
{ {
public: public:
ZT_INLINE Expect() ZT_INLINE Expect() :
m_packetIdSent()
{} {}
/** /**
@ -49,13 +50,14 @@ public:
* @param now Current time * @param now Current time
*/ */
ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept
{ m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL)); } { m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS] = (uint32_t)(now / ZT_EXPECT_TTL); }
/** /**
* Check if an OK is expected and if so reset the corresponding bucket. * Check if an OK is expected and if so reset the corresponding bucket.
* *
* This means this call mutates the state. If it returns true, it will * This means this call mutates the state. If it returns true, it will
* subsequently return false. This is for replay protection for OKs. * subsequently return false. This is to filter OKs against replays or
* responses to queries we did not send.
* *
* @param inRePacketId In-re packet ID we're expecting * @param inRePacketId In-re packet ID we're expecting
* @param now Current time * @param now Current time

View file

@ -18,7 +18,10 @@
namespace ZeroTier { namespace ZeroTier {
Locator::Locator(const char *const str) noexcept const SharedPtr< const Locator::EndpointAttributes > Locator::EndpointAttributes::DEFAULT(new Locator::EndpointAttributes());
Locator::Locator(const char *const str) noexcept :
__refCount(0)
{ {
if (!fromString(str)) { if (!fromString(str)) {
m_ts = 0; m_ts = 0;
@ -28,16 +31,16 @@ Locator::Locator(const char *const str) noexcept
} }
} }
bool Locator::add(const Endpoint &ep, const EndpointAttributes &a) bool Locator::add(const Endpoint &ep, const SharedPtr< const EndpointAttributes > &a)
{ {
for (Vector< std::pair< Endpoint, EndpointAttributes > >::iterator i(m_endpoints.begin());i!=m_endpoints.end();++i) { for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::iterator i(m_endpoints.begin());i!=m_endpoints.end();++i) {
if (i->first == ep) { if (i->first == ep) {
i->second = a; i->second = (a) ? a : EndpointAttributes::DEFAULT;
return true; return true;
} }
} }
if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) { if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) {
m_endpoints.push_back(std::pair<Endpoint, EndpointAttributes>(ep, a)); m_endpoints.push_back(std::pair<Endpoint, SharedPtr< const EndpointAttributes > >(ep, (a) ? a : EndpointAttributes::DEFAULT));
return true; return true;
} }
return false; return false;
@ -47,7 +50,7 @@ struct p_SortByEndpoint
{ {
// There can't be more than one of the same endpoint, so only need to sort // There can't be more than one of the same endpoint, so only need to sort
// by endpoint. // by endpoint.
ZT_INLINE bool operator()(const std::pair< Endpoint, Locator::EndpointAttributes > &a,const std::pair< Endpoint, Locator::EndpointAttributes > &b) const noexcept ZT_INLINE bool operator()(const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &a,const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &b) const noexcept
{ return a.first < b.first; } { return a.first < b.first; }
}; };
@ -116,14 +119,14 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool exclu
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_endpoints.size()); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_endpoints.size());
p += 2; p += 2;
for (Vector< std::pair< Endpoint, EndpointAttributes> >::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) { for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) {
l = e->first.marshal(data + p); l = e->first.marshal(data + p);
if (l <= 0) if (l <= 0)
return -1; return -1;
p += l; p += l;
l = (int)e->second.data[0] + 1; l = (int)e->second->data[0] + 1;
Utils::copy(data + p, e->second.data, (unsigned int)l); Utils::copy(data + p, e->second->data, (unsigned int)l);
p += l; p += l;
} }
@ -167,7 +170,12 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
p += l; p += l;
l = (int)data[p] + 1; l = (int)data[p] + 1;
Utils::copy(m_endpoints[i].second.data, data + p, (unsigned int)l); if (l <= 1) {
m_endpoints[i].second = EndpointAttributes::DEFAULT;
} else {
m_endpoints[i].second.set(new EndpointAttributes());
Utils::copy(const_cast< uint8_t * >(m_endpoints[i].second->data), data + p, (unsigned int)l);
}
p += l; p += l;
} }
@ -183,7 +191,7 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
return -1; return -1;
m_signature.unsafeSetSize(siglen); m_signature.unsafeSetSize(siglen);
Utils::copy(m_signature.data(), data + p, siglen); Utils::copy(m_signature.data(), data + p, siglen);
p += siglen; p += (int)siglen;
if (unlikely(p > len)) if (unlikely(p > len))
return -1; return -1;
@ -204,10 +212,9 @@ ZT_Locator *ZT_Locator_create(
try { try {
if ((ts <= 0) || (!endpoints) || (endpointCount == 0) || (!signer)) if ((ts <= 0) || (!endpoints) || (endpointCount == 0) || (!signer))
return nullptr; return nullptr;
ZeroTier::Locator::EndpointAttributes emptyAttributes;
ZeroTier::Locator *loc = new ZeroTier::Locator(); 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], emptyAttributes); loc->add(reinterpret_cast< const ZeroTier::Endpoint * >(endpoints)[i], ZeroTier::Locator::EndpointAttributes::DEFAULT);
if (!loc->sign(ts, *reinterpret_cast< const ZeroTier::Identity * >(signer))) { if (!loc->sign(ts, *reinterpret_cast< const ZeroTier::Identity * >(signer))) {
delete loc; delete loc;
return nullptr; return nullptr;

View file

@ -53,7 +53,6 @@ namespace ZeroTier {
class Locator class Locator
{ {
friend class SharedPtr< Locator >; friend class SharedPtr< Locator >;
friend class SharedPtr< const Locator >; friend class SharedPtr< const Locator >;
public: public:
@ -65,6 +64,14 @@ public:
*/ */
struct EndpointAttributes struct EndpointAttributes
{ {
friend class SharedPtr< Locator::EndpointAttributes >;
friend class SharedPtr< const Locator::EndpointAttributes >;
/**
* Default endpoint attributes
*/
static const SharedPtr< const Locator::EndpointAttributes > DEFAULT;
/** /**
* Raw attributes data in the form of a dictionary prefixed by its size. * Raw attributes data in the form of a dictionary prefixed by its size.
* *
@ -93,6 +100,9 @@ public:
ZT_INLINE bool operator>=(const EndpointAttributes &a) const noexcept ZT_INLINE bool operator>=(const EndpointAttributes &a) const noexcept
{ return !(*this < a); } { return !(*this < a); }
private:
std::atomic< int > __refCount;
}; };
ZT_INLINE Locator() noexcept: ZT_INLINE Locator() noexcept:
@ -124,7 +134,7 @@ public:
/** /**
* @return Endpoints specified in locator * @return Endpoints specified in locator
*/ */
ZT_INLINE const Vector< std::pair< Endpoint, EndpointAttributes > > &endpoints() const noexcept ZT_INLINE const Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > > &endpoints() const noexcept
{ return m_endpoints; } { return m_endpoints; }
/** /**
@ -140,10 +150,10 @@ public:
* care not to add duplicates. * care not to add duplicates.
* *
* @param ep Endpoint to add * @param ep Endpoint to add
* @param a Endpoint attributes * @param a Endpoint attributes or NULL to use default
* @return True if endpoint was added (or already present), false if locator is full * @return True if endpoint was added (or already present), false if locator is full
*/ */
bool add(const Endpoint &ep, const EndpointAttributes &a); bool add(const Endpoint &ep, const SharedPtr< const EndpointAttributes > &a);
/** /**
* Sign this locator * Sign this locator
@ -191,27 +201,35 @@ public:
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_LOCATOR_MARSHAL_SIZE_MAX; } { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept; int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept; int unmarshal(const uint8_t *data, int len) noexcept;
ZT_INLINE bool operator==(const Locator &l) const noexcept ZT_INLINE bool operator==(const Locator &l) const noexcept
{ {
return ( const unsigned long es = (unsigned long)m_endpoints.size();
(m_ts == l.m_ts) && if ((m_ts == l.m_ts) && (m_signer == l.m_signer) && (es == (unsigned long)l.m_endpoints.size()) && (m_signature == l.m_signature)) {
(m_signer == l.m_signer) && for(unsigned long i=0;i<es;++i) {
(m_endpoints == l.m_endpoints) && if (m_endpoints[i].first != l.m_endpoints[i].first)
(m_signature == l.m_signature)); return false;
if (!m_endpoints[i].second) {
if (l.m_endpoints[i].second)
return false;
} else {
if ((!l.m_endpoints[i].second) || (*(m_endpoints[i].second) != *(l.m_endpoints[i].second)))
return false;
}
}
return true;
}
return false;
} }
ZT_INLINE bool operator!=(const Locator &l) const noexcept ZT_INLINE bool operator!=(const Locator &l) const noexcept
{ return !(*this == l); } { return !(*this == l); }
private: private:
int64_t m_ts; int64_t m_ts;
Fingerprint m_signer; Fingerprint m_signer;
Vector< std::pair< Endpoint, EndpointAttributes > > m_endpoints; Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > > 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;
}; };

View file

@ -43,7 +43,10 @@ public:
* *
* @param now Start time * @param now Start time
*/ */
ZT_INLINE Meter() noexcept ZT_INLINE Meter() noexcept :
m_counts(),
m_totalExclCounts(0),
m_bucket(0)
{} {}
/** /**

View file

@ -254,7 +254,7 @@ void Peer::pulse(void *const tPtr, const int64_t now, const bool isRoot)
// callback (if one was supplied). // callback (if one was supplied).
if (m_locator) { if (m_locator) {
for (Vector< std::pair<Endpoint, Locator::EndpointAttributes > >::const_iterator ep(m_locator->endpoints().begin()); ep != m_locator->endpoints().end(); ++ep) { for (Vector< std::pair<Endpoint, SharedPtr< const Locator::EndpointAttributes > > >::const_iterator ep(m_locator->endpoints().begin()); ep != m_locator->endpoints().end(); ++ep) {
if (ep->first.type == ZT_ENDPOINT_TYPE_IP_UDP) { if (ep->first.type == ZT_ENDPOINT_TYPE_IP_UDP) {
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr, m_id, -1, ep->first.ip())) { if (RR->node->shouldUsePathForZeroTierTraffic(tPtr, m_id, -1, ep->first.ip())) {
int64_t &lt = m_lastTried[ep->first]; int64_t &lt = m_lastTried[ep->first];

View file

@ -907,8 +907,8 @@ extern "C" const char *ZTT_general()
Endpoint ep0(InetAddress::LO4); Endpoint ep0(InetAddress::LO4);
Endpoint ep1(InetAddress::LO6); Endpoint ep1(InetAddress::LO6);
Locator loc; Locator loc;
loc.add(ep0, Locator::EndpointAttributes()); loc.add(ep0, Locator::EndpointAttributes::DEFAULT);
loc.add(ep1, Locator::EndpointAttributes()); loc.add(ep1, Locator::EndpointAttributes::DEFAULT);
loc.sign(now(), v1id); loc.sign(now(), v1id);
String locStr(loc.toString()); String locStr(loc.toString());
//ZT_T_PRINTF("%s %s %s ",locStr.c_str(),loc.endpoints()[0].toString().c_str(),loc.endpoints()[1].toString().c_str()); //ZT_T_PRINTF("%s %s %s ",locStr.c_str(),loc.endpoints()[0].toString().c_str(),loc.endpoints()[1].toString().c_str());

View file

@ -51,7 +51,7 @@ extern "C" {
/** /**
* IP protocol number for naked IP encapsulation (this is not currently used) * IP protocol number for naked IP encapsulation (this is not currently used)
*/ */
#define ZT_DEFAULT_IP_PROTOCOL 193 #define ZT_DEFAULT_RAW_IP_PROTOCOL 193
/** /**
* Ethernet type for naked Ethernet encapsulation (this is not currently used) * Ethernet type for naked Ethernet encapsulation (this is not currently used)
@ -260,6 +260,8 @@ extern "C" {
/** /**
* Identity type codes (must be the same as Identity.hpp). * Identity type codes (must be the same as Identity.hpp).
*
* Do not change these integer values. They're protocol constants.
*/ */
enum ZT_IdentityType enum ZT_IdentityType
{ {
@ -2726,7 +2728,7 @@ ZT_SDK_API unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc);
*/ */
ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint( ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint(
const ZT_Locator *loc, const ZT_Locator *loc,
const unsigned int ep); unsigned int ep);
/** /**
* Verify this locator's signature * Verify this locator's signature

View file

@ -131,7 +131,7 @@ type APIStatus struct {
PeerCount int `json:"peerCount"` PeerCount int `json:"peerCount"`
PathCount int `json:"pathCount"` PathCount int `json:"pathCount"`
Identity *Identity `json:"identity"` Identity *Identity `json:"identity"`
InterfaceAddresses []net.IP `json:"interfaceAddresses,omitempty"` InterfaceAddresses []net.IP `json:"localInterfaceAddresses,omitempty"`
MappedExternalAddresses []*InetAddress `json:"mappedExternalAddresses,omitempty"` MappedExternalAddresses []*InetAddress `json:"mappedExternalAddresses,omitempty"`
Version string `json:"version"` Version string `json:"version"`
VersionMajor int `json:"versionMajor"` VersionMajor int `json:"versionMajor"`
@ -280,7 +280,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
PeerCount: len(peers), PeerCount: len(peers),
PathCount: pathCount, PathCount: pathCount,
Identity: node.Identity(), Identity: node.Identity(),
InterfaceAddresses: node.InterfaceAddresses(), InterfaceAddresses: node.LocalInterfaceAddresses(),
MappedExternalAddresses: nil, MappedExternalAddresses: nil,
Version: fmt.Sprintf("%d.%d.%d", CoreVersionMajor, CoreVersionMinor, CoreVersionRevision), Version: fmt.Sprintf("%d.%d.%d", CoreVersionMajor, CoreVersionMinor, CoreVersionRevision),
VersionMajor: CoreVersionMajor, VersionMajor: CoreVersionMajor,

View file

@ -27,6 +27,9 @@ const (
CertificateSerialNoSize = 48 CertificateSerialNoSize = 48
CertificateMaxStringLength = int(C.ZT_CERTIFICATE_MAX_STRING_LENGTH) CertificateMaxStringLength = int(C.ZT_CERTIFICATE_MAX_STRING_LENGTH)
CertificateLocalTrustFlagRootCA = int(C.ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA)
CertificateLocalTrustFlagZeroTierRootSet = int(C.ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ZEROTIER_ROOT_SET)
CertificateUniqueIdTypeNistP384 = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384) CertificateUniqueIdTypeNistP384 = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384)
CertificateUniqueIdTypeNistP384Size = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE) CertificateUniqueIdTypeNistP384Size = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_SIZE)
CertificateUniqueIdTypeNistP384PrivateSize = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE) CertificateUniqueIdTypeNistP384PrivateSize = int(C.ZT_CERTIFICATE_UNIQUE_ID_TYPE_NIST_P_384_PRIVATE_SIZE)
@ -425,7 +428,7 @@ func (c *Certificate) cCertificate() unsafe.Pointer {
return unsafe.Pointer(C._ZT_Certificate_clone2(C.uintptr_t(uintptr(unsafe.Pointer(&cc))))) return unsafe.Pointer(C._ZT_Certificate_clone2(C.uintptr_t(uintptr(unsafe.Pointer(&cc)))))
} }
// Marshal encodes this certificate as a byte array. // Marshal encodes this certificate as a byte array (binary format).
func (c *Certificate) Marshal() ([]byte, error) { func (c *Certificate) Marshal() ([]byte, error) {
cc := c.cCertificate() cc := c.cCertificate()
if cc == nil { if cc == nil {

View file

@ -26,7 +26,6 @@ type Locator struct {
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
Fingerprint *Fingerprint `json:"fingerprint"` Fingerprint *Fingerprint `json:"fingerprint"`
Endpoints []Endpoint `json:"endpoints"` Endpoints []Endpoint `json:"endpoints"`
String string `json:"string"`
cl unsafe.Pointer cl unsafe.Pointer
} }
@ -96,6 +95,9 @@ func (loc *Locator) Validate(id *Identity) bool {
} }
func (loc *Locator) Bytes() []byte { func (loc *Locator) Bytes() []byte {
if loc.cl == nil {
return nil
}
var buf [4096]byte var buf [4096]byte
bl := C.ZT_Locator_marshal(loc.cl, unsafe.Pointer(&buf[0]), 4096) bl := C.ZT_Locator_marshal(loc.cl, unsafe.Pointer(&buf[0]), 4096)
if bl <= 0 { if bl <= 0 {
@ -104,26 +106,28 @@ func (loc *Locator) Bytes() []byte {
return buf[0:int(bl)] return buf[0:int(bl)]
} }
func (loc *Locator) String() string {
if loc.cl == nil {
return ""
}
var buf [4096]C.char
return C.GoString(C.ZT_Locator_toString(loc.cl, &buf[0], 4096))
}
func (loc *Locator) MarshalJSON() ([]byte, error) { func (loc *Locator) MarshalJSON() ([]byte, error) {
return json.Marshal(loc) return json.Marshal(loc)
} }
func (loc *Locator) UnmarshalJSON(j []byte) error { func (loc *Locator) UnmarshalJSON(j []byte) error {
if loc.cl != nil {
C.ZT_Locator_delete(loc.cl) C.ZT_Locator_delete(loc.cl)
loc.cl = unsafe.Pointer(nil) loc.cl = unsafe.Pointer(nil)
}
err := json.Unmarshal(j, loc) err := json.Unmarshal(j, loc)
if err != nil { if err != nil {
return err return err
} }
sb := []byte(loc.String)
sb = append(sb, 0)
cl := C.ZT_Locator_fromString((*C.char)(unsafe.Pointer(&sb[0])))
if cl == nil {
return ErrInvalidParameter
}
loc.cl = cl
return loc.init(true) return loc.init(true)
} }
@ -148,8 +152,6 @@ func (loc *Locator) init(needFinalizer bool) error {
for i := 0; i < epc; i++ { for i := 0; i < epc; i++ {
loc.Endpoints[i].cep = *C.ZT_Locator_endpoint(loc.cl, C.uint(i)) loc.Endpoints[i].cep = *C.ZT_Locator_endpoint(loc.cl, C.uint(i))
} }
var buf [4096]byte
loc.String = C.GoString(C.ZT_Locator_toString(loc.cl, (*C.char)(unsafe.Pointer(&buf[0])), 4096))
if needFinalizer { if needFinalizer {
runtime.SetFinalizer(loc, locatorFinalizer) runtime.SetFinalizer(loc, locatorFinalizer)
} }

View file

@ -48,23 +48,23 @@ const (
NetworkIDLength = 8 NetworkIDLength = 8
AddressStringLength = 10 AddressStringLength = 10
AddressLength = 5 AddressLength = 5
DefaultPort = int(C.ZT_DEFAULT_PORT)
DefaultRawIPProto = int(C.ZT_DEFAULT_RAW_IP_PROTOCOL)
DefaultEthernetProto = int(C.ZT_DEFAULT_ETHERNET_PROTOCOL)
NetworkMaxShortNameLength = int(C.ZT_MAX_NETWORK_SHORT_NAME_LENGTH)
NetworkStatusRequestingConfiguration int = C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION NetworkStatusRequestingConfiguration = int(C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION)
NetworkStatusOK int = C.ZT_NETWORK_STATUS_OK NetworkStatusOK = int(C.ZT_NETWORK_STATUS_OK)
NetworkStatusAccessDenied int = C.ZT_NETWORK_STATUS_ACCESS_DENIED NetworkStatusAccessDenied = int(C.ZT_NETWORK_STATUS_ACCESS_DENIED)
NetworkStatusNotFound int = C.ZT_NETWORK_STATUS_NOT_FOUND NetworkStatusNotFound = int(C.ZT_NETWORK_STATUS_NOT_FOUND)
NetworkTypePrivate int = C.ZT_NETWORK_TYPE_PRIVATE NetworkTypePrivate = int(C.ZT_NETWORK_TYPE_PRIVATE)
NetworkTypePublic int = C.ZT_NETWORK_TYPE_PUBLIC NetworkTypePublic = int(C.ZT_NETWORK_TYPE_PUBLIC)
networkConfigOpUp int = C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP networkConfigOpUp = int(C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP)
networkConfigOpUpdate int = C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE networkConfigOpUpdate = int(C.ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE)
defaultVirtualNetworkMTU = int(C.ZT_DEFAULT_MTU)
defaultVirtualNetworkMTU = C.ZT_DEFAULT_MTU maxCNodeRefs = 8 // perfectly fine to increase this
// maxCNodeRefs is the maximum number of Node instances that can be created in this process.
// This is perfectly fine to increase.
maxCNodeRefs = 8
) )
var ( var (
@ -77,8 +77,9 @@ var (
// cNodeRefs maps an index to a *Node // cNodeRefs maps an index to a *Node
cNodeRefs [maxCNodeRefs]*Node cNodeRefs [maxCNodeRefs]*Node
// cNodeRefsUsed maps an index to whether or not the corresponding cNodeRefs[] entry is used. // cNodeRefUsed maps an index to whether or not the corresponding cNodeRefs[] entry is used.
cNodeRefUsed [maxCNodeRefs]uint32 // This is accessed atomically to provide a really fast way to gate cNodeRefs.
cNodeRefUsed [maxCNodeRefs]uintptr
) )
func init() { func init() {
@ -96,46 +97,37 @@ type Node struct {
// Time this node was created // Time this node was created
startupTime int64 startupTime int64
// an arbitrary uintptr given to the core as its pointer back to Go's Node instance. // cPtr is an arbitrary pseudo-pointer given to the core to map back to our Go object.
// This is an index in the cNodeRefs array, which is synchronized by way of a set of // This is an index into the cNodeRefs array.
// used/free booleans accessed atomically.
cPtr uintptr cPtr uintptr
// networks contains networks we have joined, and networksByMAC by their local MAC address
networks map[NetworkID]*Network networks map[NetworkID]*Network
networksByMAC map[MAC]*Network // locked by networksLock networksByMAC map[MAC]*Network // locked by networksLock
networksLock sync.RWMutex networksLock sync.RWMutex
localInterfaceAddresses map[string]net.IP
// interfaceAddresses are physical IPs assigned to the local machine. localInterfaceAddressesLock sync.Mutex
// These are the detected IPs, not those configured explicitly. They include running uintptr // atomic flag
// both private and global IPs. online uintptr // atomic flag
interfaceAddresses map[string]net.IP
interfaceAddressesLock sync.Mutex
running uint32
online uint32
basePath string basePath string
peersPath string peersPath string
certsPath string
networksPath string networksPath string
localConfigPath string localConfigPath string
infoLogPath string infoLogPath string
errorLogPath string errorLogPath string
// localConfig is the current state of local.conf.
localConfig *LocalConfig localConfig *LocalConfig
previousLocalConfig *LocalConfig previousLocalConfig *LocalConfig
localConfigLock sync.RWMutex localConfigLock sync.RWMutex
infoLogW *sizeLimitWriter infoLogW *sizeLimitWriter
errLogW *sizeLimitWriter errLogW *sizeLimitWriter
traceLogW io.Writer traceLogW io.Writer
infoLog *log.Logger infoLog *log.Logger
errLog *log.Logger errLog *log.Logger
traceLog *log.Logger traceLog *log.Logger
namedSocketAPIServer *http.Server
tcpAPIServer *http.Server
// gn is the GoNode instance, see go/native/GoNode.hpp // gn is the GoNode instance, see serviceiocore/GoNode.hpp
gn *C.ZT_GoNode gn *C.ZT_GoNode
// zn is the underlying ZT_Node (ZeroTier::Node) instance // zn is the underlying ZT_Node (ZeroTier::Node) instance
@ -144,9 +136,6 @@ type Node struct {
// id is the identity of this node (includes private key) // id is the identity of this node (includes private key)
id *Identity id *Identity
namedSocketAPIServer *http.Server
tcpAPIServer *http.Server
// runWaitGroup is used to wait for all node goroutines on shutdown. // runWaitGroup is used to wait for all node goroutines on shutdown.
// Any new goroutine is tracked via this wait group so node shutdown can // Any new goroutine is tracked via this wait group so node shutdown can
// itself wait until all goroutines have exited. // itself wait until all goroutines have exited.
@ -163,7 +152,7 @@ func NewNode(basePath string) (n *Node, err error) {
// returning an error. // returning an error.
cPtr := -1 cPtr := -1
for i := 0; i < maxCNodeRefs; i++ { for i := 0; i < maxCNodeRefs; i++ {
if atomic.CompareAndSwapUint32(&cNodeRefUsed[i], 0, 1) { if atomic.CompareAndSwapUintptr(&cNodeRefUsed[i], 0, 1) {
cNodeRefs[i] = n cNodeRefs[i] = n
cPtr = i cPtr = i
n.cPtr = uintptr(i) n.cPtr = uintptr(i)
@ -173,20 +162,16 @@ func NewNode(basePath string) (n *Node, err error) {
if cPtr < 0 { if cPtr < 0 {
return nil, ErrInternal return nil, ErrInternal
} }
// Check and delete node reference pointer if it's non-negative. This helps
// with error handling cleanup. At the end we set cPtr to -1 to disable.
defer func() { defer func() {
if cPtr >= 0 { if cPtr >= 0 {
atomic.StoreUint32(&cNodeRefUsed[cPtr], 0) atomic.StoreUintptr(&cNodeRefUsed[cPtr], 0)
cNodeRefs[cPtr] = nil cNodeRefs[cPtr] = nil
} }
}() }()
n.networks = make(map[NetworkID]*Network) n.networks = make(map[NetworkID]*Network)
n.networksByMAC = make(map[MAC]*Network) n.networksByMAC = make(map[MAC]*Network)
n.interfaceAddresses = make(map[string]net.IP) n.localInterfaceAddresses = make(map[string]net.IP)
n.running = 1 n.running = 1
_ = os.MkdirAll(basePath, 0755) _ = os.MkdirAll(basePath, 0755)
@ -200,16 +185,12 @@ func NewNode(basePath string) (n *Node, err error) {
if _, err = os.Stat(n.peersPath); err != nil { if _, err = os.Stat(n.peersPath); err != nil {
return return
} }
n.certsPath = path.Join(basePath, "certs.d")
_ = os.MkdirAll(n.certsPath, 0755)
n.networksPath = path.Join(basePath, "networks.d") n.networksPath = path.Join(basePath, "networks.d")
_ = os.MkdirAll(n.networksPath, 0755) _ = os.MkdirAll(n.networksPath, 0755)
if _, err = os.Stat(n.networksPath); err != nil {
return
}
n.localConfigPath = path.Join(basePath, "local.conf") n.localConfigPath = path.Join(basePath, "local.conf")
// Read local configuration, initializing with defaults if not found. We
// check for identity.secret's existence to determine if this is a new
// node or one that already existed. This influences some of the defaults.
_, isTotallyNewNode := os.Stat(path.Join(basePath, "identity.secret")) _, isTotallyNewNode := os.Stat(path.Join(basePath, "identity.secret"))
n.localConfig = new(LocalConfig) n.localConfig = new(LocalConfig)
err = n.localConfig.Read(n.localConfigPath, true, isTotallyNewNode != nil) err = n.localConfig.Read(n.localConfigPath, true, isTotallyNewNode != nil)
@ -282,9 +263,8 @@ func NewNode(basePath string) (n *Node, err error) {
return nil, err return nil, err
} }
cPath := C.CString(basePath) cPath := cStr(basePath)
n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(n.cPtr)) n.gn = C.ZT_GoNode_new((*C.char)(unsafe.Pointer(&cPath[0])), C.uintptr_t(n.cPtr))
C.free(unsafe.Pointer(cPath))
if n.gn == nil { if n.gn == nil {
n.infoLog.Println("FATAL: node initialization failed") n.infoLog.Println("FATAL: node initialization failed")
return nil, ErrNodeInitFailed return nil, ErrNodeInitFailed
@ -297,13 +277,11 @@ func NewNode(basePath string) (n *Node, err error) {
return nil, err return nil, err
} }
// Background maintenance goroutine that handles polling for local network changes, cleaning internal data
// structures, syncing local config changes, and numerous other things that must happen from time to time.
n.runWaitGroup.Add(1) n.runWaitGroup.Add(1)
go func() { go func() {
defer n.runWaitGroup.Done() defer n.runWaitGroup.Done()
lastMaintenanceRun := int64(0) lastMaintenanceRun := int64(0)
for atomic.LoadUint32(&n.running) != 0 { for atomic.LoadUintptr(&n.running) != 0 {
time.Sleep(250 * time.Millisecond) time.Sleep(250 * time.Millisecond)
nowS := time.Now().Unix() nowS := time.Now().Unix()
if (nowS - lastMaintenanceRun) >= 30 { if (nowS - lastMaintenanceRun) >= 30 {
@ -322,7 +300,7 @@ func NewNode(basePath string) (n *Node, err error) {
// Close closes this Node and frees its underlying C++ Node structures // Close closes this Node and frees its underlying C++ Node structures
func (n *Node) Close() { func (n *Node) Close() {
if atomic.SwapUint32(&n.running, 0) != 0 { if atomic.SwapUintptr(&n.running, 0) != 0 {
if n.namedSocketAPIServer != nil { if n.namedSocketAPIServer != nil {
_ = n.namedSocketAPIServer.Close() _ = n.namedSocketAPIServer.Close()
} }
@ -335,7 +313,7 @@ func (n *Node) Close() {
n.runWaitGroup.Wait() n.runWaitGroup.Wait()
cNodeRefs[n.cPtr] = nil cNodeRefs[n.cPtr] = nil
atomic.StoreUint32(&cNodeRefUsed[n.cPtr], 0) atomic.StoreUintptr(&cNodeRefUsed[n.cPtr], 0)
} }
} }
@ -346,16 +324,16 @@ func (n *Node) Address() Address { return n.id.address }
func (n *Node) Identity() *Identity { return n.id } func (n *Node) Identity() *Identity { return n.id }
// Online returns true if this node can reach something // Online returns true if this node can reach something
func (n *Node) Online() bool { return atomic.LoadUint32(&n.online) != 0 } func (n *Node) Online() bool { return atomic.LoadUintptr(&n.online) != 0 }
// InterfaceAddresses are external IPs belonging to physical interfaces on this machine // LocalInterfaceAddresses are external IPs belonging to physical interfaces on this machine
func (n *Node) InterfaceAddresses() []net.IP { func (n *Node) LocalInterfaceAddresses() []net.IP {
n.localInterfaceAddressesLock.Lock()
defer n.localInterfaceAddressesLock.Unlock()
var ea []net.IP var ea []net.IP
n.interfaceAddressesLock.Lock() for _, a := range n.localInterfaceAddresses {
for _, a := range n.interfaceAddresses {
ea = append(ea, a) ea = append(ea, a)
} }
n.interfaceAddressesLock.Unlock()
sort.Slice(ea, func(a, b int) bool { return bytes.Compare(ea[a], ea[b]) < 0 }) sort.Slice(ea, func(a, b int) bool { return bytes.Compare(ea[a], ea[b]) < 0 })
return ea return ea
} }
@ -395,14 +373,15 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error)
// If tap is nil, the default system tap for this OS/platform is used (if available). // If tap is nil, the default system tap for this OS/platform is used (if available).
func (n *Node) Join(nwid NetworkID, controllerFingerprint *Fingerprint, settings *NetworkLocalSettings, tap Tap) (*Network, error) { func (n *Node) Join(nwid NetworkID, controllerFingerprint *Fingerprint, settings *NetworkLocalSettings, tap Tap) (*Network, error) {
n.networksLock.RLock() n.networksLock.RLock()
defer n.networksLock.RUnlock()
if nw, have := n.networks[nwid]; have { if nw, have := n.networks[nwid]; have {
n.infoLog.Printf("join network %.16x ignored: already a member", nwid) n.infoLog.Printf("join network %.16x ignored: already a member", nwid)
if settings != nil { if settings != nil {
nw.SetLocalSettings(settings) go nw.SetLocalSettings(settings) // "go" this to avoid possible deadlocks
} }
return nw, nil return nw, nil
} }
n.networksLock.RUnlock()
if tap != nil { if tap != nil {
panic("non-native taps not yet implemented") panic("non-native taps not yet implemented")
@ -423,11 +402,9 @@ func (n *Node) Join(nwid NetworkID, controllerFingerprint *Fingerprint, settings
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid)) C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
return nil, err return nil, err
} }
n.networksLock.Lock()
n.networks[nwid] = nw n.networks[nwid] = nw
n.networksLock.Unlock()
if settings != nil { if settings != nil {
nw.SetLocalSettings(settings) go nw.SetLocalSettings(settings)
} }
return nw, nil return nw, nil
@ -457,12 +434,12 @@ func (n *Node) Network(nwid NetworkID) *Network {
// Networks returns a list of networks that this node has joined // Networks returns a list of networks that this node has joined
func (n *Node) Networks() []*Network { func (n *Node) Networks() []*Network {
var nws []*Network
n.networksLock.RLock() n.networksLock.RLock()
defer n.networksLock.RUnlock()
var nws []*Network
for _, nw := range n.networks { for _, nw := range n.networks {
nws = append(nws, nw) nws = append(nws, nw)
} }
n.networksLock.RUnlock()
return nws return nws
} }
@ -471,13 +448,13 @@ func (n *Node) Peers() []*Peer {
var peers []*Peer var peers []*Peer
pl := C.ZT_Node_peers(n.zn) pl := C.ZT_Node_peers(n.zn)
if pl != nil { if pl != nil {
defer C.ZT_freeQueryResult(unsafe.Pointer(pl))
for i := uintptr(0); i < uintptr(pl.peerCount); i++ { for i := uintptr(0); i < uintptr(pl.peerCount); i++ {
p, _ := newPeerFromCPeer((*C.ZT_Peer)(unsafe.Pointer(uintptr(unsafe.Pointer(pl.peers)) + (i * C.sizeof_ZT_Peer)))) p, _ := newPeerFromCPeer((*C.ZT_Peer)(unsafe.Pointer(uintptr(unsafe.Pointer(pl.peers)) + (i * C.sizeof_ZT_Peer))))
if p != nil { if p != nil {
peers = append(peers, p) peers = append(peers, p)
} }
} }
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
@ -499,14 +476,13 @@ func (n *Node) Peer(fpOrAddress interface{}) *Peer {
} }
pl := C.ZT_Node_peers(n.zn) pl := C.ZT_Node_peers(n.zn)
if pl != nil { if pl != nil {
defer C.ZT_freeQueryResult(unsafe.Pointer(pl))
for i := uintptr(0); i < uintptr(pl.peerCount); i++ { for i := uintptr(0); i < uintptr(pl.peerCount); i++ {
p, _ := newPeerFromCPeer((*C.ZT_Peer)(unsafe.Pointer(uintptr(unsafe.Pointer(pl.peers)) + (i * C.sizeof_ZT_Peer)))) p, _ := newPeerFromCPeer((*C.ZT_Peer)(unsafe.Pointer(uintptr(unsafe.Pointer(pl.peers)) + (i * C.sizeof_ZT_Peer))))
if p != nil && p.Identity.Fingerprint().BestSpecificityEquals(fp) { if p != nil && p.Identity.Fingerprint().BestSpecificityEquals(fp) {
C.ZT_freeQueryResult(unsafe.Pointer(pl))
return p return p
} }
} }
C.ZT_freeQueryResult(unsafe.Pointer(pl))
} }
return nil return nil
} }
@ -545,6 +521,7 @@ func (n *Node) TryPeer(fpOrAddress interface{}, ep *Endpoint, retries int) bool
func (n *Node) ListCertificates() (certs []*Certificate, localTrust []uint, err error) { func (n *Node) ListCertificates() (certs []*Certificate, localTrust []uint, err error) {
cl := C.ZT_Node_listCertificates(n.zn) cl := C.ZT_Node_listCertificates(n.zn)
if cl != nil { if cl != nil {
defer C.ZT_freeQueryResult(unsafe.Pointer(cl))
for i := uintptr(0); i < uintptr(cl.certCount); i++ { for i := uintptr(0); i < uintptr(cl.certCount); i++ {
c := newCertificateFromCCertificate(unsafe.Pointer(uintptr(unsafe.Pointer(cl.certs)) + (i * pointerSize))) c := newCertificateFromCCertificate(unsafe.Pointer(uintptr(unsafe.Pointer(cl.certs)) + (i * pointerSize)))
if c != nil { if c != nil {
@ -553,7 +530,6 @@ func (n *Node) ListCertificates() (certs []*Certificate, localTrust []uint, err
localTrust = append(localTrust, uint(lt)) localTrust = append(localTrust, uint(lt))
} }
} }
C.ZT_freeQueryResult(unsafe.Pointer(cl))
} }
return return
} }
@ -615,9 +591,9 @@ func (n *Node) runMaintenance() {
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 { if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
ports = append(ports, n.localConfig.Settings.SecondaryPort) ports = append(ports, n.localConfig.Settings.SecondaryPort)
} }
n.interfaceAddressesLock.Lock() n.localInterfaceAddressesLock.Lock()
for astr, ipn := range interfaceAddresses { for astr, ipn := range interfaceAddresses {
if _, alreadyKnown := n.interfaceAddresses[astr]; !alreadyKnown { if _, alreadyKnown := n.localInterfaceAddresses[astr]; !alreadyKnown {
interfaceAddressesChanged = true interfaceAddressesChanged = true
ipCstr := C.CString(ipn.String()) ipCstr := C.CString(ipn.String())
for pn, p := range ports { for pn, p := range ports {
@ -631,7 +607,7 @@ func (n *Node) runMaintenance() {
C.free(unsafe.Pointer(ipCstr)) C.free(unsafe.Pointer(ipCstr))
} }
} }
for astr, ipn := range n.interfaceAddresses { for astr, ipn := range n.localInterfaceAddresses {
if _, stillPresent := interfaceAddresses[astr]; !stillPresent { if _, stillPresent := interfaceAddresses[astr]; !stillPresent {
interfaceAddressesChanged = true interfaceAddressesChanged = true
ipCstr := C.CString(ipn.String()) ipCstr := C.CString(ipn.String())
@ -642,8 +618,8 @@ func (n *Node) runMaintenance() {
C.free(unsafe.Pointer(ipCstr)) C.free(unsafe.Pointer(ipCstr))
} }
} }
n.interfaceAddresses = interfaceAddresses n.localInterfaceAddresses = interfaceAddresses
n.interfaceAddressesLock.Unlock() n.localInterfaceAddressesLock.Unlock()
// Update node's interface address list if detected or configured addresses have changed. // Update node's interface address list if detected or configured addresses have changed.
if interfaceAddressesChanged || n.previousLocalConfig == nil || !reflect.DeepEqual(n.localConfig.Settings.ExplicitAddresses, n.previousLocalConfig.Settings.ExplicitAddresses) { if interfaceAddressesChanged || n.previousLocalConfig == nil || !reflect.DeepEqual(n.localConfig.Settings.ExplicitAddresses, n.previousLocalConfig.Settings.ExplicitAddresses) {
@ -729,20 +705,17 @@ func (n *Node) makeStateObjectPath(objType int, id []uint64) (string, bool) {
case C.ZT_STATE_OBJECT_LOCATOR: case C.ZT_STATE_OBJECT_LOCATOR:
fp = path.Join(n.basePath, "locator") fp = path.Join(n.basePath, "locator")
case C.ZT_STATE_OBJECT_PEER: case C.ZT_STATE_OBJECT_PEER:
fp = path.Join(n.basePath, "peers.d") _ = os.Mkdir(n.peersPath, 0700)
_ = os.Mkdir(fp, 0700) fp = path.Join(n.peersPath, fmt.Sprintf("%.10x.peer", id[0]))
fp = path.Join(fp, fmt.Sprintf("%.10x.peer", id[0]))
secret = true secret = true
case C.ZT_STATE_OBJECT_NETWORK_CONFIG: case C.ZT_STATE_OBJECT_NETWORK_CONFIG:
fp = path.Join(n.basePath, "networks.d") _ = os.Mkdir(n.networksPath, 0755)
_ = os.Mkdir(fp, 0755) fp = path.Join(n.networksPath, fmt.Sprintf("%.16x.conf", id[0]))
fp = path.Join(fp, fmt.Sprintf("%.16x.conf", id[0]))
case C.ZT_STATE_OBJECT_TRUST_STORE: case C.ZT_STATE_OBJECT_TRUST_STORE:
fp = path.Join(n.basePath, "truststore") fp = path.Join(n.basePath, "truststore")
case C.ZT_STATE_OBJECT_CERT: case C.ZT_STATE_OBJECT_CERT:
fp = path.Join(n.basePath, "certs.d") _ = os.Mkdir(n.certsPath, 0755)
_ = os.Mkdir(fp, 0755) fp = path.Join(n.certsPath, Base32StdLowerCase.EncodeToString((*[48]byte)(unsafe.Pointer(&id[0]))[:]))
fp = path.Join(fp, Base32StdLowerCase.EncodeToString((*[48]byte)(unsafe.Pointer(&id[0]))[:]))
} }
return fp, secret return fp, secret
} }
@ -956,8 +929,8 @@ func goZtEvent(gn unsafe.Pointer, eventType C.int, data unsafe.Pointer) {
switch eventType { switch eventType {
case C.ZT_EVENT_OFFLINE: case C.ZT_EVENT_OFFLINE:
atomic.StoreUint32(&node.online, 0) atomic.StoreUintptr(&node.online, 0)
case C.ZT_EVENT_ONLINE: case C.ZT_EVENT_ONLINE:
atomic.StoreUint32(&node.online, 1) atomic.StoreUintptr(&node.online, 1)
} }
} }