From 2fbeaaf148247aa4800f9063bd69170868c0cf57 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 9 Jan 2020 13:50:51 -0800 Subject: [PATCH] Bunch more fixes, implement C API for Identity operations. --- go/native/GoGlue.cpp | 165 ++---------------------- go/native/GoGlue.h | 6 + include/ZeroTierCore.h | 273 +++++++++++++++++++++------------------- node/CMakeLists.txt | 14 +-- node/Identity.cpp | 204 +++++++++++++++++++++++++++++- node/Identity.hpp | 108 ++-------------- node/IncomingPacket.cpp | 34 ++--- node/InetAddress.cpp | 6 +- node/InetAddress.hpp | 141 ++++++++++----------- node/Locator.cpp | 106 ++++++++++++++++ node/Locator.hpp | 103 ++------------- node/Node.cpp | 41 ++++-- 12 files changed, 601 insertions(+), 600 deletions(-) create mode 100644 node/Locator.cpp diff --git a/go/native/GoGlue.cpp b/go/native/GoGlue.cpp index c903c8e7a..359a26158 100644 --- a/go/native/GoGlue.cpp +++ b/go/native/GoGlue.cpp @@ -13,29 +13,25 @@ #include "GoGlue.h" +#include +#include +#include +#include + #include "../../node/Constants.hpp" #include "../../node/InetAddress.hpp" #include "../../node/Node.hpp" #include "../../node/Utils.hpp" #include "../../node/MAC.hpp" #include "../../node/Address.hpp" -#include "../../node/Locator.hpp" #include "../../osdep/OSUtils.hpp" #include "../../osdep/EthernetTap.hpp" -#include "../../osdep/ManagedRoute.hpp" - -#include -#include -#include #ifndef __WINDOWS__ -#include -#include +extern "C" { #include #include -#include #include -#include #include #include #include @@ -45,6 +41,7 @@ #ifdef __BSD__ #include #endif +} #ifdef __LINUX__ #ifndef IPV6_DONTFRAG #define IPV6_DONTFRAG 62 @@ -56,7 +53,6 @@ #include #include #include -#include #include #include #include @@ -114,7 +110,6 @@ extern "C" int goPathCheckFunc(void *,uint64_t,int,const void *,int); extern "C" int goPathLookupFunc(void *,uint64_t,int,int *,uint8_t [16],int *); extern "C" void goStateObjectPutFunc(void *,int,const uint64_t [2],const void *,int); extern "C" int goStateObjectGetFunc(void *,int,const uint64_t [2],void *,unsigned int); -extern "C" void goDNSResolverFunc(void *,const uint8_t *,int,const char *,uintptr_t); extern "C" void goVirtualNetworkConfigFunc(void *,ZT_GoTap *,uint64_t,int,const ZT_VirtualNetworkConfig *); extern "C" void goZtEvent(void *,int,const void *); extern "C" void goHandleTapAddedMulticastGroup(void *,ZT_GoTap *,uint64_t,uint64_t,uint32_t); @@ -279,6 +274,7 @@ static int ZT_GoNode_PathLookupFunction( void *uptr, void *tptr, uint64_t ztAddress, + const ZT_Identity *id, int desiredAddressFamily, struct sockaddr_storage *sa) { @@ -310,20 +306,6 @@ static int ZT_GoNode_PathLookupFunction( return 0; } -static void ZT_GoNode_DNSResolver( - ZT_Node *node, - void *uptr, - void *tptr, - const enum ZT_DNSRecordType *types, - unsigned int numTypes, - const char *name, - uintptr_t requestId) -{ - uint8_t t[256]; - for(unsigned int i=0;(i(uptr)->goUserPtr,t,(int)numTypes,name,requestId); -} - /****************************************************************************/ extern "C" ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr) @@ -336,7 +318,6 @@ extern "C" ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr) cb.virtualNetworkFrameFunction = &ZT_GoNode_VirtualNetworkFrameFunction; cb.virtualNetworkConfigFunction = &ZT_GoNode_VirtualNetworkConfigFunction; cb.eventCallback = &ZT_GoNode_EventCallback; - cb.dnsResolver = &ZT_GoNode_DNSResolver; cb.pathCheckFunction = &ZT_GoNode_PathCheckFunction; cb.pathLookupFunction = &ZT_GoNode_PathLookupFunction; @@ -727,133 +708,3 @@ extern "C" int ZT_GoTap_removeRoute(ZT_GoTap *tap,int targetAf,const void *targe } return reinterpret_cast(tap)->removeRoute(target,via,metric); } - -/****************************************************************************/ - -extern "C" const char *ZT_GoIdentity_generate(int type) -{ - Identity id; - id.generate((Identity::Type)type); - char *tmp = (char *)malloc(ZT_IDENTITY_STRING_BUFFER_LENGTH); - if (tmp) - id.toString(true,tmp); - return tmp; -} - -extern "C" int ZT_GoIdentity_validate(const char *idStr) -{ - Identity id; - if (!id.fromString(idStr)) - return 0; - if (!id.locallyValidate()) - return 0; - return 1; -} - -extern "C" int ZT_GoIdentity_sign(const char *idStr,const void *data,unsigned int len,void *sigbuf,unsigned int sigbuflen) -{ - Identity id; - if (!id.fromString(idStr)) - return 0; - return (int)id.sign(data,len,sigbuf,sigbuflen); -} - -extern "C" int ZT_GoIdentity_verify(const char *idStr,const void *data,unsigned int len,const void *sig,unsigned int siglen) -{ - Identity id; - if (!id.fromString(idStr)) - return 0; - return id.verify(data,len,sig,siglen) ? 1 : 0; -} - -/****************************************************************************/ - -extern "C" int ZT_GoLocator_makeSecureDNSName(char *name,unsigned int nameBufSize,uint8_t *privateKey,unsigned int privateKeyBufSize) -{ - if ((privateKeyBufSize < ZT_ECC384_PRIVATE_KEY_SIZE)||(nameBufSize < 256)) - return -1; - uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE]; - ECC384GenerateKey(pub,privateKey); - const Str n(Locator::makeSecureDnsName(pub)); - if (n.length() >= nameBufSize) - return -1; - Utils::scopy(name,nameBufSize,n.c_str()); - return ZT_ECC384_PRIVATE_KEY_SIZE; -} - -extern "C" int ZT_GoLocator_makeLocator( - uint8_t *buf, - unsigned int bufSize, - int64_t ts, - const char *id, - const struct sockaddr_storage *physicalAddresses, - unsigned int physicalAddressCount, - const char **virtualAddresses, - unsigned int virtualAddressCount) -{ - Locator loc; - for(unsigned int i=0;i(physicalAddresses + i)); - } - for(unsigned int i=0;i *tmp = new Buffer<65536>(); - loc.serialize(*tmp); - if (tmp->size() > bufSize) { - delete tmp; - return -1; - } - memcpy(buf,tmp->data(),tmp->size()); - int s = (int)tmp->size(); - delete tmp; - return s; -} - -extern "C" int ZT_GoLocator_decodeLocator(const uint8_t *locatorBytes,unsigned int locatorSize,struct ZT_GoLocator_Info *info) -{ - Locator loc; - if (!loc.deserialize(locatorBytes,locatorSize)) - return -1; - if (!loc.verify()) - return -2; - loc.id().toString(false,info->id); - info->phyCount = 0; - info->virtCount = 0; - for(auto p=loc.phy().begin();p!=loc.phy().end();++p) - memcpy(&(info->phy[info->phyCount++]),&(*p),sizeof(struct sockaddr_storage)); - for(auto v=loc.virt().begin();v!=loc.virt().end();++v) - v->toString(false,info->virt[info->virtCount++]); - return 1; -} - -int ZT_GoLocator_makeSignedTxtRecords( - const uint8_t *locator, - unsigned int locatorSize, - const char *name, - const uint8_t *privateKey, - unsigned int privateKeySize, - char results[256][256]) -{ - if (privateKeySize != ZT_ECC384_PRIVATE_KEY_SIZE) - return -1; - Locator loc; - if (!loc.deserialize(locator,locatorSize)) - return -1; - std::vector r(loc.makeTxtRecords(privateKey)); - if (r.size() > 256) - return -1; - for(unsigned long i=0;i +#include +#include +#else #include #include #include +#endif #include "../../include/ZeroTierCore.h" #include "../../node/Constants.hpp" diff --git a/include/ZeroTierCore.h b/include/ZeroTierCore.h index 1037d97f7..41022a40a 100644 --- a/include/ZeroTierCore.h +++ b/include/ZeroTierCore.h @@ -21,6 +21,7 @@ #ifdef __cplusplus #include +extern "C" { #else #include #endif @@ -43,10 +44,6 @@ #define ZT_SDK_API #endif -#ifdef __cplusplus -extern "C" { -#endif - /****************************************************************************/ /* Core constants */ /****************************************************************************/ @@ -95,11 +92,6 @@ extern "C" { */ #define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM) -/** - * Maximum size of a remote trace message's serialized Dictionary - */ -#define ZT_MAX_REMOTE_TRACE_SIZE 10000 - /** * Maximum length of network short name */ @@ -262,78 +254,6 @@ extern "C" { */ #define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL -/****************************************************************************/ - -// Fields in remote trace dictionaries -#define ZT_REMOTE_TRACE_FIELD__EVENT "event" -#define ZT_REMOTE_TRACE_FIELD__NODE_ID "nodeId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "packetId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "packetVerb" -#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "packetTrustedPathId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "packetTrustedPathApproved" -#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "packetHops" -#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "remoteZtAddr" -#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "remotePhyAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "localZtAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "localPhyAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "localSocket" -#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "phyAddrIpScope" -#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "networkId" -#define ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR "sourceZtAddr" -#define ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR "destZtAddr" -#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "sourceMac" -#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "destMac" -#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "etherType" -#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlanId" -#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "frameLength" -#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "frameData" -#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE "filterNoTee" -#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND "filterInbound" -#define ZT_REMOTE_TRACE_FIELD__FILTER_RESULT "filterResult" -#define ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG "filterBaseRuleLog" -#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG "filterCapRuleLog" -#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID "filterMatchingCapId" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credType" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credId" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credTs" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credInfo" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "credIssuedTo" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "credRevocationTarget" -#define ZT_REMOTE_TRACE_FIELD__REASON "reason" -#define ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID "networkControllerId" - -// Event types in remote traces -#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000 -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1001 -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1002 -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1003 -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1004 -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1005 -#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO 0x1006 -#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED 0x2000 -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED 0x2001 -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED 0x2002 -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED 0x2003 -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED 0x2004 -#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT 0x2005 -#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE 0x2006 - -// Event types in remote traces in hex string form -#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1001" -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1002" -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1003" -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1004" -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1005" -#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" -#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000" -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001" -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002" -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" -#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S "2005" -#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S "2006" - /****************************************************************************/ /* Structures and other types */ /****************************************************************************/ @@ -503,48 +423,23 @@ enum ZT_Event * * Meta-data: ZT_UserMessage structure */ - ZT_EVENT_USER_MESSAGE = 6, - - /** - * Remote trace received - * - * NOTE: any node can fling a VERB_REMOTE_TRACE at you. It's up to you - * to determine if you want to do anything with it or just silently - * drop it on the floor. It's also up to you to handle these securely! - * - * Meta-data: ZT_RemoteTrace structure - */ - ZT_EVENT_REMOTE_TRACE = 7 + ZT_EVENT_USER_MESSAGE = 6 }; /** - * Payload of REMOTE_TRACE event + * Identity type codes */ -typedef struct +enum ZT_Identity_Type { - /** - * ZeroTier address of sender (in least significant 40 bits only) - */ - uint64_t origin; + /* These values must be the same as in Identity.hpp in the core. */ + ZT_IDENTITY_TYPE_C25519 = 0, + ZT_IDENTITY_TYPE_P384 = 1 +}; - /** - * Null-terminated Dictionary containing key/value pairs sent by origin - * - * This *should* be a dictionary, but the implementation only checks - * that it is a valid non-empty C-style null-terminated string. Be very - * careful to use a well-tested parser to parse this as it represents - * data received from a potentially un-trusted peer on the network. - * Invalid payloads should be dropped. - * - * The contents of data[] may be modified. - */ - const char *data; - - /** - * Length of dict[] in bytes, INCLUDING terminating null - */ - unsigned int len; -} ZT_RemoteTrace; +/** + * A ZeroTier identity (opaque) + */ +typedef void ZT_Identity; /** * User message used with ZT_EVENT_USER_MESSAGE @@ -589,6 +484,11 @@ typedef struct */ uint64_t address; + /** + * Actual identity object for this node + */ + const ZT_Identity *identity; + /** * Public identity in string-serialized form (safe to send to others) * @@ -965,16 +865,6 @@ enum ZT_VirtualNetworkConfigOperation ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 }; -/** - * What trust hierarchy role does this peer have? - */ -enum ZT_PeerRole -{ - ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_MOON = 1, // moon root - ZT_PEER_ROLE_PLANET = 2 // planetary root -}; - /** * Virtual network configuration */ @@ -1183,6 +1073,15 @@ typedef struct int preferred; } ZT_PeerPhysicalPath; +/** + * What trust hierarchy role does this peer have? + */ +enum ZT_PeerRole +{ + ZT_PEER_ROLE_LEAF = 0, // ordinary node + ZT_PEER_ROLE_ROOT = 1 // root server +}; + /** * Peer status result buffer */ @@ -1193,6 +1092,11 @@ typedef struct */ uint64_t address; + /** + * Peer identity + */ + const ZT_Identity *identity; + /** * Remote major version or -1 if not known */ @@ -1497,7 +1401,7 @@ typedef int (*ZT_PathLookupFunction)( void *, /* User ptr */ void *, /* Thread ptr */ uint64_t, /* ZeroTier address (40 bits) */ - const char *, /* Identity in string form */ + const ZT_Identity *, /* Full identity of node */ int, /* Desired ss_family or -1 for any */ struct sockaddr_storage *); /* Result buffer */ @@ -1541,12 +1445,12 @@ struct ZT_Node_Callbacks ZT_EventCallback eventCallback; /** - * OPTIONAL: Function to check whether a given physical path should be used + * OPTIONAL: Function to check whether a given physical path should be used for ZeroTier traffic */ ZT_PathCheckFunction pathCheckFunction; /** - * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses + * RECOMMENDED: Function to look up paths to ZeroTier nodes */ ZT_PathLookupFunction pathLookupFunction; }; @@ -1865,6 +1769,115 @@ ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterIns */ ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); +/** + * Generate a new identity + * + * Due to a small amount of proof of work this can be a time consuming and CPU + * intensive operation. It takes less than a second on most desktop-class systems + * but can take longer on e.g. phones. + * + * @param type Type of identity to generate + * @return New identity or NULL on error + */ +ZT_SDK_API ZT_Identity *ZT_Identity_new(enum ZT_Identity_Type type); + +/** + * Create a new identity object from a string-serialized identity + * + * @param idStr Identity in string format + * @return Identity object or NULL if the supplied identity string was not valid + */ +ZT_SDK_API ZT_Identity *ZT_Identity_fromString(const char *idStr); + +/** + * Validate this identity + * + * This can be slightly time consuming due to address derivation (work) checking. + * + * @return Non-zero if identity is valid + */ +ZT_SDK_API int ZT_Identity_validate(const ZT_Identity *id); + +/** + * Sign a data object with this identity + * + * The identity must have a private key or this will fail. + * + * @param id Identity to use to sign + * @param data Data to sign + * @param len Length of data + * @param signature Buffer to store signature + * @param signatureBufferLength Length of buffer (must be at least 96 bytes) + * @return Length of signature in bytes or 0 on failure. + */ +ZT_SDK_API unsigned int ZT_Identity_sign(const ZT_Identity *id,const void *data,unsigned int len,void *signature,unsigned int signatureBufferLength); + +/** + * Verify a signature + * + * @param id Identity to use to verify + * @param data Data to verify + * @param len Length of data + * @param signature Signature to check + * @param sigLen Length of signature in bytes + * @return Non-zero if signature is valid + */ +ZT_SDK_API int ZT_Identity_verify(const ZT_Identity *id,const void *data,unsigned int len,const void *signature,unsigned int sigLen); + +/** + * Get identity type + * + * @param id Identity to query + * @return Identity type code + */ +ZT_SDK_API enum ZT_Identity_Type ZT_Identity_type(const ZT_Identity *id); + +/** + * Convert an identity to its string representation + * + * @param id Identity to convert + * @param buf Buffer to store identity (should be at least about 1024 bytes in length) + * @param capacity Capacity of buffer + * @param includePrivate If true include the private key if present + * @return Pointer to buf or NULL on overflow or other error + */ +ZT_SDK_API char *ZT_Identity_toString(const ZT_Identity *id,char *buf,int capacity,int includePrivate); + +/** + * Check whether this identity object also holds a private key + * + * @param id Identity to query + * @return Non-zero if a private key is held + */ +ZT_SDK_API int ZT_Identity_hasPrivate(const ZT_Identity *id); + +/** + * Get the ZeroTier address associated with this identity + * + * @param id Identity to query + * @return ZeroTier address (only least significant 40 bits are meaningful, rest will be 0) + */ +ZT_SDK_API uint64_t ZT_Identity_address(const ZT_Identity *id); + +/** + * Compute a hash of this identity's public keys (or both public and private if includePrivate is true) + * + * @param id Identity to query + * @param h Buffer for 384-bit hash + * @param includePrivate If true include private keys if any + */ +ZT_SDK_API void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate); + +/** + * Delete an identity and free associated memory + * + * This should only be used with identities created via Identity_new + * and Identity_fromString(). + * + * @param id Identity to delete + */ +ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id); + /** * Get ZeroTier One version * diff --git a/node/CMakeLists.txt b/node/CMakeLists.txt index e98f4d48b..2002cc660 100644 --- a/node/CMakeLists.txt +++ b/node/CMakeLists.txt @@ -56,6 +56,7 @@ set(core_src Identity.cpp IncomingPacket.cpp InetAddress.cpp + Locator.cpp Membership.cpp Network.cpp NetworkConfig.cpp @@ -74,16 +75,3 @@ set(core_src add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers}) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}) - -#if(UNIX) -# set_source_files_properties( -# AES.cpp -# AES-aesni.c -# ECC384.cpp -# Salsa20.cpp -# C25519.cpp -# Poly1305.cpp -# PROPERTIES -# COMPILE_FLAGS "-Wall -O3" -# ) -#endif(UNIX) diff --git a/node/Identity.cpp b/node/Identity.cpp index cf0f4be1e..ddcd5c948 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -11,10 +11,8 @@ */ /****/ -#include -#include -#include -#include +#include +#include #include "Constants.hpp" #include "Identity.hpp" @@ -143,6 +141,108 @@ bool Identity::locallyValidate() const return false; } +bool Identity::hash(uint8_t h[48],const bool includePrivate) const +{ + switch(_type) { + + case C25519: + if ((_hasPrivate)&&(includePrivate)) + SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); + else SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); + return true; + + case P384: + if ((_hasPrivate)&&(includePrivate)) + SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv)); + else SHA384(h,&_pub,sizeof(_pub)); + return true; + + } + return false; +} + +unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const +{ + if (_hasPrivate) { + switch(_type) { + + case C25519: + if (siglen >= ZT_C25519_SIGNATURE_LEN) { + C25519::sign(_priv.c25519,_pub.c25519,data,len,sig); + return ZT_C25519_SIGNATURE_LEN; + } + + case P384: + if (siglen >= ZT_ECC384_SIGNATURE_SIZE) { + // When signing with P384 we also hash the C25519 public key as an + // extra measure to ensure that only this identity can verify. + uint8_t h[48]; + SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); + ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig); + return ZT_ECC384_SIGNATURE_SIZE; + } + + } + } + return 0; +} + +bool Identity::verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const +{ + switch(_type) { + + case C25519: + return C25519::verify(_pub.c25519,data,len,sig,siglen); + + case P384: + if (siglen == ZT_ECC384_SIGNATURE_SIZE) { + uint8_t h[48]; + SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); + return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig); + } + break; + + } + return false; +} + +bool Identity::agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const +{ + uint8_t rawkey[128]; + uint8_t h[64]; + if (_hasPrivate) { + if (_type == C25519) { + + if ((id._type == C25519)||(id._type == P384)) { + // If we are a C25519 key we can agree with another C25519 key or with only the + // C25519 portion of a type 1 P-384 key. + C25519::agree(_priv.c25519,id._pub.c25519,rawkey); + SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN); + memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH); + return true; + } + + } else if (_type == P384) { + + if (id._type == P384) { + C25519::agree(_priv.c25519,id._pub.c25519,rawkey); + ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN); + SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE); + memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH); + return true; + } else if (id._type == C25519) { + // If the other identity is a C25519 identity we can agree using only that type. + C25519::agree(_priv.c25519,id._pub.c25519,rawkey); + SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN); + memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH); + return true; + } + + } + } + return false; +} + char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const { switch(_type) { @@ -286,3 +386,99 @@ bool Identity::fromString(const char *str) } } // namespace ZeroTier + +extern "C" { + +ZT_Identity *ZT_Identity_new(enum ZT_Identity_Type type) +{ + if ((type != ZT_IDENTITY_TYPE_C25519)&&(type != ZT_IDENTITY_TYPE_P384)) + return nullptr; + try { + ZeroTier::Identity *id = new ZeroTier::Identity(); + id->generate((ZeroTier::Identity::Type)type); + return reinterpret_cast(id); + } catch ( ... ) { + return nullptr; + } +} + +ZT_Identity *ZT_Identity_fromString(const char *idStr) +{ + if (!idStr) + return nullptr; + try { + ZeroTier::Identity *id = new ZeroTier::Identity(); + if (!id->fromString(idStr)) { + delete id; + return nullptr; + } + return reinterpret_cast(id); + } catch ( ... ) { + return nullptr; + } +} + +int ZT_Identity_validate(const ZT_Identity *id) +{ + if (!id) + return 0; + return reinterpret_cast(id)->locallyValidate() ? 1 : 0; +} + +unsigned int ZT_Identity_sign(const ZT_Identity *id,const void *data,unsigned int len,void *signature,unsigned int signatureBufferLength) +{ + if (!id) + return 0; + if (signatureBufferLength < ZT_SIGNATURE_BUFFER_SIZE) + return 0; + return reinterpret_cast(id)->sign(data,len,signature,signatureBufferLength); +} + +int ZT_Identity_verify(const ZT_Identity *id,const void *data,unsigned int len,const void *signature,unsigned int sigLen) +{ + if ((!id)||(!signature)||(!sigLen)) + return 0; + return reinterpret_cast(id)->verify(data,len,signature,sigLen) ? 1 : 0; +} + +enum ZT_Identity_Type ZT_Identity_type(const ZT_Identity *id) +{ + if (!id) + return (ZT_Identity_Type)0; + return (enum ZT_Identity_Type)reinterpret_cast(id)->type(); +} + +char *ZT_Identity_toString(const ZT_Identity *id,char *buf,int capacity,int includePrivate) +{ + if ((!id)||(!buf)||(capacity < ZT_IDENTITY_STRING_BUFFER_LENGTH)) + return nullptr; + reinterpret_cast(id)->toString(includePrivate != 0,buf); + return buf; +} + +int ZT_Identity_hasPrivate(const ZT_Identity *id) +{ + if (!id) + return 0; + return reinterpret_cast(id)->hasPrivate() ? 1 : 0; +} + +uint64_t ZT_Identity_address(const ZT_Identity *id) +{ + if (!id) + return 0; + return reinterpret_cast(id)->address().toInt(); +} + +void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate) +{ + reinterpret_cast(id)->hash(h,includePrivate != 0); +} + +ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id) +{ + if (id) + delete reinterpret_cast(id); +} + +} diff --git a/node/Identity.hpp b/node/Identity.hpp index 88df4d252..aabdc6daa 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -67,7 +67,7 @@ public: * * @param str Identity in canonical string format */ - ZT_ALWAYS_INLINE Identity(const char *str) { fromString(str); } + explicit ZT_ALWAYS_INLINE Identity(const char *str) { fromString(str); } /** * Set identity to NIL value (all zero) @@ -86,7 +86,7 @@ public: * * @param t Type of identity to generate */ - void generate(const Type t); + void generate(Type t); /** * Check the validity of this identity's pairing of key to address @@ -106,25 +106,7 @@ public: * @param h Buffer to receive SHA384 of public key(s) * @param includePrivate If true, hash private key(s) as well */ - inline bool hash(uint8_t h[48],const bool includePrivate = false) const - { - switch(_type) { - - case C25519: - if ((_hasPrivate)&&(includePrivate)) - SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); - else SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); - return true; - - case P384: - if ((_hasPrivate)&&(includePrivate)) - SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv)); - else SHA384(h,&_pub,sizeof(_pub)); - return true; - - } - return false; - } + bool hash(uint8_t h[48],bool includePrivate = false) const; /** * Sign a message with this identity (private key required) @@ -138,31 +120,7 @@ public: * @param siglen Length of buffer * @return Number of bytes actually written to sig or 0 on error */ - inline unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const - { - if (_hasPrivate) { - switch(_type) { - - case C25519: - if (siglen >= ZT_C25519_SIGNATURE_LEN) { - C25519::sign(_priv.c25519,_pub.c25519,data,len,sig); - return ZT_C25519_SIGNATURE_LEN; - } - - case P384: - if (siglen >= ZT_ECC384_SIGNATURE_SIZE) { - // When signing with P384 we also hash the C25519 public key as an - // extra measure to ensure that only this identity can verify. - uint8_t h[48]; - SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); - ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig); - return ZT_ECC384_SIGNATURE_SIZE; - } - - } - } - return 0; - } + unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const; /** * Verify a message signature against this identity @@ -173,24 +131,7 @@ public: * @param siglen Length of signature in bytes * @return True if signature validates and data integrity checks */ - inline bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const - { - switch(_type) { - - case C25519: - return C25519::verify(_pub.c25519,data,len,sig,siglen); - - case P384: - if (siglen == ZT_ECC384_SIGNATURE_SIZE) { - uint8_t h[48]; - SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); - return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig); - } - break; - - } - return false; - } + bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const; /** * Shortcut method to perform key agreement with another identity @@ -201,42 +142,7 @@ public: * @param key Result parameter to fill with key bytes * @return Was agreement successful? */ - inline bool agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const - { - uint8_t rawkey[128]; - uint8_t h[64]; - if (_hasPrivate) { - if (_type == C25519) { - - if ((id._type == C25519)||(id._type == P384)) { - // If we are a C25519 key we can agree with another C25519 key or with only the - // C25519 portion of a type 1 P-384 key. - C25519::agree(_priv.c25519,id._pub.c25519,rawkey); - SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN); - memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH); - return true; - } - - } else if (_type == P384) { - - if (id._type == P384) { - C25519::agree(_priv.c25519,id._pub.c25519,rawkey); - ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN); - SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE); - memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH); - return true; - } else if (id._type == C25519) { - // If the other identity is a C25519 identity we can agree using only that type. - C25519::agree(_priv.c25519,id._pub.c25519,rawkey); - SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN); - memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH); - return true; - } - - } - } - return false; - } + bool agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const; /** * @return This identity's address @@ -476,7 +382,7 @@ public: privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE]; if (len < (privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1))) return -1; - return (privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)); + return (int)(privlen + (unsigned int)(ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)); } else if (privlen == 0) { _hasPrivate = false; return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2); diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 27b7adcb6..bf77874c4 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -41,7 +41,7 @@ namespace { // Implementation of each protocol verb // ////////////////////////////////////////////////////////////////////////////// -static void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid,const SharedPtr &path) +void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid,const SharedPtr &path) { Packet outp(pkt.source(),RR->identity.address(),Packet::VERB_ERROR); outp.append((uint8_t)pkt.verb()); @@ -52,7 +52,7 @@ static void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironme path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } -static inline bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const bool alreadyAuthenticated,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const bool alreadyAuthenticated,const SharedPtr &path) { const int64_t now = RR->node->now(); @@ -181,15 +181,15 @@ static inline bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *const return true; } -static inline bool _doACK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doACK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { } -static inline bool _doQOS_MEASUREMENT(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doQOS_MEASUREMENT(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { } -static inline bool _doERROR(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doERROR(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const Packet::Verb inReVerb = (Packet::Verb)pkt[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; const uint64_t inRePacketId = pkt.at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); @@ -251,7 +251,7 @@ static inline bool _doERROR(IncomingPacket &pkt,const RuntimeEnvironment *const return true; } -static inline bool _doOK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doOK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const Packet::Verb inReVerb = (Packet::Verb)pkt[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = pkt.at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); @@ -318,7 +318,7 @@ static inline bool _doOK(IncomingPacket &pkt,const RuntimeEnvironment *const RR, return true; } -static inline bool _doWHOIS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doWHOIS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { if (!peer->rateGateInboundWhoisRequest(RR->node->now())) return true; @@ -353,7 +353,7 @@ static inline bool _doWHOIS(IncomingPacket &pkt,const RuntimeEnvironment *const return true; } -static inline bool _doRENDEZVOUS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doRENDEZVOUS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { if (RR->topology->isRoot(peer->identity())) { const Address with(pkt.field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); @@ -375,7 +375,7 @@ static inline bool _doRENDEZVOUS(IncomingPacket &pkt,const RuntimeEnvironment *c return true; } -static inline bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const uint64_t nwid = pkt.at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); @@ -398,7 +398,7 @@ static inline bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *const return true; } -static inline bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const uint64_t nwid = pkt.at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); @@ -476,7 +476,7 @@ static inline bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment *co return true; } -static inline bool _doECHO(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doECHO(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { if (!peer->rateGateEchoRequest(RR->node->now())) return true; @@ -495,7 +495,7 @@ static inline bool _doECHO(IncomingPacket &pkt,const RuntimeEnvironment *const R return true; } -static inline bool _doNETWORK_CREDENTIALS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doNETWORK_CREDENTIALS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { if (!peer->rateGateCredentialsReceived(RR->node->now())) return true; @@ -577,7 +577,7 @@ static inline bool _doNETWORK_CREDENTIALS(IncomingPacket &pkt,const RuntimeEnvir return true; } -static inline bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const uint64_t nwid = pkt.at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); const unsigned int hopCount = pkt.hops(); @@ -603,7 +603,7 @@ static inline bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &pkt,const RuntimeEn return true; } -static inline bool _doNETWORK_CONFIG(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const SharedPtr network(RR->node->network(pkt.at(ZT_PACKET_IDX_PAYLOAD))); if (network) { @@ -622,7 +622,7 @@ static inline bool _doNETWORK_CONFIG(IncomingPacket &pkt,const RuntimeEnvironmen return true; } -static inline bool _doMULTICAST_GATHER(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doMULTICAST_GATHER(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const uint64_t nwid = pkt.at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); const unsigned int flags = pkt[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; @@ -670,7 +670,7 @@ static inline bool _doMULTICAST_GATHER(IncomingPacket &pkt,const RuntimeEnvironm return true; } -static inline bool _doPUSH_DIRECT_PATHS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doPUSH_DIRECT_PATHS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { const int64_t now = RR->node->now(); @@ -720,7 +720,7 @@ static inline bool _doPUSH_DIRECT_PATHS(IncomingPacket &pkt,const RuntimeEnviron return true; } -static inline bool _doUSER_MESSAGE(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) +ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr &peer,const SharedPtr &path) { if (likely(pkt.size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { ZT_UserMessage um; diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index 834bcae7e..1f4a0202d 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -376,7 +376,7 @@ bool InetAddress::operator<(const InetAddress &a) const InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) { InetAddress r; - sockaddr_in6 *const sin6 = reinterpret_cast(&r); + sockaddr_in6 *const sin6 = reinterpret_cast(&r); sin6->sin6_family = AF_INET6; sin6->sin6_addr.s6_addr[0] = 0xfe; sin6->sin6_addr.s6_addr[1] = 0x80; @@ -401,7 +401,7 @@ InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress) { InetAddress r; - sockaddr_in6 *const sin6 = reinterpret_cast(&r); + sockaddr_in6 *const sin6 = reinterpret_cast(&r); sin6->sin6_family = AF_INET6; sin6->sin6_addr.s6_addr[0] = 0xfd; sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56U); @@ -427,7 +427,7 @@ InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress) { nwid ^= (nwid >> 32U); InetAddress r; - sockaddr_in6 *const sin6 = reinterpret_cast(&r); + sockaddr_in6 *const sin6 = reinterpret_cast(&r); sin6->sin6_family = AF_INET6; sin6->sin6_addr.s6_addr[0] = 0xfc; sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U); diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index a4dc7ebde..5a703ac0e 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -42,6 +42,16 @@ namespace ZeroTier { */ struct InetAddress : public sockaddr_storage { +private: + template + ZT_ALWAYS_INLINE void copySockaddrToThis(const SA *sa) + { + memcpy(reinterpret_cast(this),sa,sizeof(SA)); + if (sizeof(SA) < sizeof(InetAddress)) + memset(reinterpret_cast(this) + sizeof(SA),0,sizeof(InetAddress) - sizeof(SA)); + } + +public: /** * Loopback IPv4 address (no port) */ @@ -79,116 +89,83 @@ struct InetAddress : public sockaddr_storage // Hasher for unordered sets and maps in C++11 struct Hasher { ZT_ALWAYS_INLINE std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); } }; - ZT_ALWAYS_INLINE InetAddress() { memset(this,0,sizeof(InetAddress)); } - ZT_ALWAYS_INLINE InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); } - ZT_ALWAYS_INLINE InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 &sa) { *this = sa; } - ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 *sa) { *this = sa; } + ZT_ALWAYS_INLINE InetAddress() { memset(reinterpret_cast(this),0,sizeof(InetAddress)); } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 &sa) { *this = sa; } + explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 *sa) { *this = sa; } ZT_ALWAYS_INLINE InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); } ZT_ALWAYS_INLINE InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); } - ZT_ALWAYS_INLINE InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); } + explicit ZT_ALWAYS_INLINE InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); } - ZT_ALWAYS_INLINE void clear() { memset(this,0,sizeof(InetAddress)); } - - ZT_ALWAYS_INLINE InetAddress &operator=(const InetAddress &a) - { - if (&a != this) - memcpy(this,&a,sizeof(InetAddress)); - return *this; - } - - ZT_ALWAYS_INLINE InetAddress &operator=(const InetAddress *a) - { - if (a != this) - memcpy(this,a,sizeof(InetAddress)); - return *this; - } + ZT_ALWAYS_INLINE void clear() { memset(reinterpret_cast(this),0,sizeof(InetAddress)); } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage &ss) { - if (reinterpret_cast(&ss) != this) - memcpy(this,&ss,sizeof(InetAddress)); + memcpy(reinterpret_cast(this),&ss,sizeof(InetAddress)); return *this; } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage *ss) { - if (reinterpret_cast(ss) != this) - memcpy(this,ss,sizeof(InetAddress)); + if (ss) + memcpy(reinterpret_cast(this),ss,sizeof(InetAddress)); + else memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in &sa) { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in)); - } + copySockaddrToThis(&sa); return *this; } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in *sa) { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in)); - } + if (sa) + copySockaddrToThis(sa); + else memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 &sa) { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - } + copySockaddrToThis(&sa); return *this; } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 *sa) { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in6)); - } + if (sa) + copySockaddrToThis(sa); + else memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr &sa) { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - switch(sa.sa_family) { - case AF_INET: - memcpy(this,&sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - break; - } - } + if (sa.sa_family == AF_INET) + copySockaddrToThis(reinterpret_cast(&sa)); + else if (sa.sa_family == AF_INET6) + copySockaddrToThis(reinterpret_cast(&sa)); + else memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr *sa) { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - switch(sa->sa_family) { - case AF_INET: - memcpy(this,sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,sa,sizeof(struct sockaddr_in6)); - break; - } + if (sa) { + if (sa->sa_family == AF_INET) + copySockaddrToThis(reinterpret_cast(sa)); + else if (sa->sa_family == AF_INET6) + copySockaddrToThis(reinterpret_cast(sa)); + return *this; } + memset(reinterpret_cast(this),0,sizeof(InetAddress)); return *this; } @@ -517,6 +494,9 @@ struct InetAddress : public sockaddr_storage } inline int unmarshal(const uint8_t *restrict data,const int len) { +#ifdef ZT_NO_TYPE_PUNNING + uint16_t tmp; +#endif if (len <= 0) return -1; switch(data[0]) { @@ -525,22 +505,32 @@ struct InetAddress : public sockaddr_storage case 4: if (len < 7) return -1; - memset(this,0,sizeof(InetAddress)); + memset(reinterpret_cast(this),0,sizeof(InetAddress)); reinterpret_cast(this)->sin_family = AF_INET; reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr))[0] = data[1]; reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr))[1] = data[2]; reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr))[2] = data[3]; reinterpret_cast(&(reinterpret_cast(this)->sin_addr.s_addr))[3] = data[4]; - reinterpret_cast(this)->sin_port = Utils::hton((((uint16_t)data[5]) << 8) | (uint16_t)data[6]); +#ifdef ZT_NO_TYPE_PUNNING + memcpy(&tmp,data + 5,2); + reinterpret_cast(this)->sin_port = tmp; +#else + reinterpret_cast(this)->sin_port = *((const uint16_t *)(data + 5)); +#endif return 7; case 6: if (len < 19) return -1; - memset(this,0,sizeof(InetAddress)); + memset(reinterpret_cast(this),0,sizeof(InetAddress)); reinterpret_cast(this)->sin6_family = AF_INET6; for(int i=0;i<16;i++) (reinterpret_cast(this)->sin6_addr.s6_addr)[i] = data[i+1]; - reinterpret_cast(this)->sin6_port = Utils::hton((((uint16_t)data[17]) << 8) | (uint16_t)data[18]); +#ifdef ZT_NO_TYPE_PUNNING + memcpy(&tmp,data + 17,2); + reinterpret_cast(this)->sin_port = tmp; +#else + reinterpret_cast(this)->sin_port = *((const uint16_t *)(data + 17)); +#endif return 19; default: return -1; @@ -666,6 +656,13 @@ struct InetAddress : public sockaddr_storage static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress); }; +InetAddress *asInetAddress(sockaddr_in *p) { return reinterpret_cast(p); } +InetAddress *asInetAddress(sockaddr_in6 *p) { return reinterpret_cast(p); } +InetAddress *asInetAddress(sockaddr *p) { return reinterpret_cast(p); } +const InetAddress *asInetAddress(const sockaddr_in *p) { return reinterpret_cast(p); } +const InetAddress *asInetAddress(const sockaddr_in6 *p) { return reinterpret_cast(p); } +const InetAddress *asInetAddress(const sockaddr *p) { return reinterpret_cast(p); } + } // namespace ZeroTier #endif diff --git a/node/Locator.cpp b/node/Locator.cpp new file mode 100644 index 000000000..66b145e2e --- /dev/null +++ b/node/Locator.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c)2019 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2023-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +#include "Locator.hpp" + +namespace ZeroTier { + +bool Locator::sign(const int64_t ts,const Identity &id) +{ + uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX]; + if (!id.hasPrivate()) + return false; + _ts = ts; + if (_endpointCount > 0) + std::sort(_at,_at + _endpointCount); + const unsigned int signLen = marshal(signData,true); + _signatureLength = id.sign(signData, signLen, _signature, sizeof(_signature)); + return (_signatureLength > 0); +} + +bool Locator::verify(const Identity &id) const +{ + if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) + return false; + uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX]; + const unsigned int signLen = marshal(signData,true); + return id.verify(signData,signLen,_signature,_signatureLength); +} + +int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature = false) const +{ + if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) + return -1; + + Utils::putUInt64(data,(uint64_t)_ts); + int p = 8; + + data[p++] = (uint8_t)(_endpointCount >> 8U); + data[p++] = (uint8_t)_endpointCount; + for(unsigned int i=0;i<_endpointCount;++i) { + int tmp = _at[i].marshal(data + p); + if (tmp < 0) + return -1; + p += tmp; + } + + if (!excludeSignature) { + data[p++] = (uint8_t)(_signatureLength >> 8U); + data[p++] = (uint8_t)_signatureLength; + memcpy(data + p,_signature,_signatureLength); + p += (int)_signatureLength; + } + + return p; +} + +int Locator::unmarshal(const uint8_t *restrict data,const int len) +{ + if (len <= (8 + 48)) + return -1; + + _ts = (int64_t)Utils::readUInt64(data); + int p = 8; + + if ((p + 2) > len) + return -1; + unsigned int ec = (int)data[p++]; + ec <<= 8U; + ec |= data[p++]; + if (ec > ZT_LOCATOR_MAX_ENDPOINTS) + return -1; + _endpointCount = ec; + for(int i=0;i len) + return -1; + unsigned int sl = data[p++]; + sl <<= 8U; + sl |= data[p++]; + if (sl > ZT_SIGNATURE_BUFFER_SIZE) + return -1; + _signatureLength = sl; + if ((p + sl) > len) + return -1; + memcpy(_signature,data + p,sl); + p += (int)sl; + + return p; +} + +} // namespace ZeroTier diff --git a/node/Locator.hpp b/node/Locator.hpp index e959bc0df..e18399884 100644 --- a/node/Locator.hpp +++ b/node/Locator.hpp @@ -54,38 +54,32 @@ public: ZT_ALWAYS_INLINE bool isSigned() const { return (_signatureLength > 0); } /** - * Add an endpoint to this locator if not already present + * Add an endpoint to this locator + * + * This doesn't check for the presence of the endpoint, so take + * care not to add duplicates. * * @param ep Endpoint to add * @return True if endpoint was added (or already present), false if locator is full */ - inline bool add(const Endpoint &ep) + ZT_ALWAYS_INLINE bool add(const Endpoint &ep) { if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS) return false; - if (!std::binary_search(_at,_at + _endpointCount,ep)) { - _at[_endpointCount++] = ep; - std::sort(_at,_at + _endpointCount); - } + _at[_endpointCount++] = ep; return true; } /** * Sign this locator * + * This sets timestamp, sorts endpoints so that the same set of endpoints + * will always produce the same locator, and signs. + * * @param id Identity that includes private key * @return True if signature successful */ - inline bool sign(const int64_t ts,const Identity &id) - { - uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX]; - if (!id.hasPrivate()) - return false; - _ts = ts; - const unsigned int signLen = marshal(signData,true); - _signatureLength = id.sign(signData, signLen, _signature, sizeof(_signature)); - return (_signatureLength > 0); - } + bool sign(int64_t ts,const Identity &id); /** * Verify this Locator's validity and signature @@ -93,84 +87,13 @@ public: * @param id Identity corresponding to hash * @return True if valid and signature checks out */ - inline bool verify(const Identity &id) const - { - if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) - return false; - uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX]; - const unsigned int signLen = marshal(signData,true); - return id.verify(signData,signLen,_signature,_signatureLength); - } + bool verify(const Identity &id) const; explicit ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); } - // Marshal interface /////////////////////////////////////////////////////// static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_LOCATOR_MARSHAL_SIZE_MAX; } - inline int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature = false) const - { - if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) - return -1; - - Utils::putUInt64(data,(uint64_t)_ts); - int p = 8; - - data[p++] = (uint8_t)(_endpointCount >> 8U); - data[p++] = (uint8_t)_endpointCount; - for(unsigned int i=0;i<_endpointCount;++i) { - int tmp = _at[i].marshal(data + p); - if (tmp < 0) - return -1; - p += tmp; - } - - if (!excludeSignature) { - data[p++] = (uint8_t)(_signatureLength >> 8U); - data[p++] = (uint8_t)_signatureLength; - memcpy(data + p,_signature,_signatureLength); - p += (int)_signatureLength; - } - - return p; - } - inline int unmarshal(const uint8_t *restrict data,const int len) - { - if (len <= (8 + 48)) - return -1; - - _ts = (int64_t)Utils::readUInt64(data); - int p = 8; - - if ((p + 2) > len) - return -1; - unsigned int ec = (int)data[p++]; - ec <<= 8U; - ec |= data[p++]; - if (ec > ZT_LOCATOR_MAX_ENDPOINTS) - return -1; - _endpointCount = ec; - for(int i=0;i len) - return -1; - unsigned int sl = data[p++]; - sl <<= 8U; - sl |= data[p++]; - if (sl > ZT_SIGNATURE_BUFFER_SIZE) - return -1; - _signatureLength = sl; - if ((p + sl) > len) - return -1; - memcpy(_signature,data + p,sl); - p += (int)sl; - - return p; - } - //////////////////////////////////////////////////////////////////////////// + int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature = false) const; + int unmarshal(const uint8_t *restrict data,const int len); private: int64_t _ts; diff --git a/node/Node.cpp b/node/Node.cpp index dccf040f3..2ccbc7a1d 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -371,6 +371,7 @@ uint64_t Node::address() const void Node::status(ZT_NodeStatus *status) const { status->address = RR->identity.address().toInt(); + status->identity = reinterpret_cast(&RR->identity); status->publicIdentity = RR->publicIdentityStr; status->secretIdentity = RR->secretIdentityStr; status->online = _online ? 1 : 0; @@ -384,34 +385,38 @@ ZT_PeerList *Node::peers() const RR->topology->getAllPeers(peers); std::sort(peers.begin(),peers.end(),_sortPeerPtrsByAddress()); - char *buf = (char *)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size())); + char *buf = (char *)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size()) + (sizeof(Identity) * peers.size())); if (!buf) return (ZT_PeerList *)0; ZT_PeerList *pl = (ZT_PeerList *)buf; pl->peers = (ZT_Peer *)(buf + sizeof(ZT_PeerList)); + Identity *identities = (Identity *)(buf + sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size())); + const int64_t now = _now; pl->peerCount = 0; for(std::vector< SharedPtr >::iterator pi(peers.begin());pi!=peers.end();++pi) { - ZT_Peer *p = &(pl->peers[pl->peerCount++]); + ZT_Peer *p = &(pl->peers[pl->peerCount]); + p->address = (*pi)->address().toInt(); + identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted + p->identity = &identities[pl->peerCount]; p->hadAggregateLink = 0; if ((*pi)->remoteVersionKnown()) { - p->versionMajor = (*pi)->remoteVersionMajor(); - p->versionMinor = (*pi)->remoteVersionMinor(); - p->versionRev = (*pi)->remoteVersionRevision(); + p->versionMajor = (int)(*pi)->remoteVersionMajor(); + p->versionMinor = (int)(*pi)->remoteVersionMinor(); + p->versionRev = (int)(*pi)->remoteVersionRevision(); } else { p->versionMajor = -1; p->versionMinor = -1; p->versionRev = -1; } - p->latency = (*pi)->latency(_now); + p->latency = (int)(*pi)->latency(now); if (p->latency >= 0xffff) p->latency = -1; - p->role = RR->topology->isRoot((*pi)->identity()) ? ZT_PEER_ROLE_PLANET : ZT_PEER_ROLE_LEAF; + p->role = RR->topology->isRoot((*pi)->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF; - const int64_t now = _now; - std::vector< SharedPtr > paths((*pi)->paths(_now)); - SharedPtr bestp((*pi)->getAppropriatePath(_now,false)); + std::vector< SharedPtr > paths((*pi)->paths(now)); + SharedPtr bestp((*pi)->getAppropriatePath(now,false)); p->hadAggregateLink |= (*pi)->hasAggregateLink(); p->pathCount = 0; for(std::vector< SharedPtr >::iterator path(paths.begin());path!=paths.end();++path) { @@ -434,6 +439,8 @@ ZT_PeerList *Node::peers() const ++p->pathCount; } + + ++pl->peerCount; } return pl; @@ -553,9 +560,17 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,cons bool Node::externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr) { - char idStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - id.toString(false,idStr); - return (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,id.address().toInt(),idStr,family,reinterpret_cast(&addr)) == ZT_RESULT_OK); + if (_cb.pathLookupFunction) { + return (_cb.pathLookupFunction( + reinterpret_cast(this), + _uPtr, + tPtr, + id.address().toInt(), + reinterpret_cast(&id), + family, + reinterpret_cast(&addr)) == ZT_RESULT_OK); + } + return false; } ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig)