Bunch more fixes, implement C API for Identity operations.

This commit is contained in:
Adam Ierymenko 2020-01-09 13:50:51 -08:00
parent 57710cbc38
commit 2fbeaaf148
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
12 changed files with 601 additions and 600 deletions

View file

@ -13,29 +13,25 @@
#include "GoGlue.h" #include "GoGlue.h"
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <ctime>
#include "../../node/Constants.hpp" #include "../../node/Constants.hpp"
#include "../../node/InetAddress.hpp" #include "../../node/InetAddress.hpp"
#include "../../node/Node.hpp" #include "../../node/Node.hpp"
#include "../../node/Utils.hpp" #include "../../node/Utils.hpp"
#include "../../node/MAC.hpp" #include "../../node/MAC.hpp"
#include "../../node/Address.hpp" #include "../../node/Address.hpp"
#include "../../node/Locator.hpp"
#include "../../osdep/OSUtils.hpp" #include "../../osdep/OSUtils.hpp"
#include "../../osdep/EthernetTap.hpp" #include "../../osdep/EthernetTap.hpp"
#include "../../osdep/ManagedRoute.hpp"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#ifndef __WINDOWS__ #ifndef __WINDOWS__
#include <errno.h> extern "C" {
#include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -45,6 +41,7 @@
#ifdef __BSD__ #ifdef __BSD__
#include <net/if.h> #include <net/if.h>
#endif #endif
}
#ifdef __LINUX__ #ifdef __LINUX__
#ifndef IPV6_DONTFRAG #ifndef IPV6_DONTFRAG
#define IPV6_DONTFRAG 62 #define IPV6_DONTFRAG 62
@ -56,7 +53,6 @@
#include <mutex> #include <mutex>
#include <map> #include <map>
#include <vector> #include <vector>
#include <array>
#include <set> #include <set>
#include <memory> #include <memory>
#include <atomic> #include <atomic>
@ -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" 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" 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" 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 goVirtualNetworkConfigFunc(void *,ZT_GoTap *,uint64_t,int,const ZT_VirtualNetworkConfig *);
extern "C" void goZtEvent(void *,int,const void *); extern "C" void goZtEvent(void *,int,const void *);
extern "C" void goHandleTapAddedMulticastGroup(void *,ZT_GoTap *,uint64_t,uint64_t,uint32_t); 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 *uptr,
void *tptr, void *tptr,
uint64_t ztAddress, uint64_t ztAddress,
const ZT_Identity *id,
int desiredAddressFamily, int desiredAddressFamily,
struct sockaddr_storage *sa) struct sockaddr_storage *sa)
{ {
@ -310,20 +306,6 @@ static int ZT_GoNode_PathLookupFunction(
return 0; 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<numTypes)&&(i<256);++i) t[i] = (uint8_t)types[i];
goDNSResolverFunc(reinterpret_cast<ZT_GoNode *>(uptr)->goUserPtr,t,(int)numTypes,name,requestId);
}
/****************************************************************************/ /****************************************************************************/
extern "C" ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr) 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.virtualNetworkFrameFunction = &ZT_GoNode_VirtualNetworkFrameFunction;
cb.virtualNetworkConfigFunction = &ZT_GoNode_VirtualNetworkConfigFunction; cb.virtualNetworkConfigFunction = &ZT_GoNode_VirtualNetworkConfigFunction;
cb.eventCallback = &ZT_GoNode_EventCallback; cb.eventCallback = &ZT_GoNode_EventCallback;
cb.dnsResolver = &ZT_GoNode_DNSResolver;
cb.pathCheckFunction = &ZT_GoNode_PathCheckFunction; cb.pathCheckFunction = &ZT_GoNode_PathCheckFunction;
cb.pathLookupFunction = &ZT_GoNode_PathLookupFunction; 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<EthernetTap *>(tap)->removeRoute(target,via,metric); return reinterpret_cast<EthernetTap *>(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<physicalAddressCount;++i) {
loc.add(*reinterpret_cast<const InetAddress *>(physicalAddresses + i));
}
for(unsigned int i=0;i<virtualAddressCount;++i) {
Identity id;
if (!id.fromString(virtualAddresses[i]))
return -1;
loc.add(id);
}
Identity signingId;
if (!signingId.fromString(id))
return -1;
if (!signingId.hasPrivate())
return -1;
if (!loc.finish(signingId,ts))
return -1;
Buffer<65536> *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<Str> r(loc.makeTxtRecords(privateKey));
if (r.size() > 256)
return -1;
for(unsigned long i=0;i<r.size();++i)
Utils::scopy(results[i],256,r[i].c_str());
return (int)r.size();
}

View file

@ -14,9 +14,15 @@
#ifndef ZT_GONODE_H #ifndef ZT_GONODE_H
#define ZT_GONODE_H #define ZT_GONODE_H
#ifdef __cplusplus
#include <cstdint>
#include <cstdlib>
#include <cstring>
#else
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#endif
#include "../../include/ZeroTierCore.h" #include "../../include/ZeroTierCore.h"
#include "../../node/Constants.hpp" #include "../../node/Constants.hpp"

View file

@ -21,6 +21,7 @@
#ifdef __cplusplus #ifdef __cplusplus
#include <cstdint> #include <cstdint>
extern "C" {
#else #else
#include <stdint.h> #include <stdint.h>
#endif #endif
@ -43,10 +44,6 @@
#define ZT_SDK_API #define ZT_SDK_API
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************/ /****************************************************************************/
/* Core constants */ /* Core constants */
/****************************************************************************/ /****************************************************************************/
@ -95,11 +92,6 @@ extern "C" {
*/ */
#define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM) #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 * Maximum length of network short name
*/ */
@ -262,78 +254,6 @@ extern "C" {
*/ */
#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL #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 */ /* Structures and other types */
/****************************************************************************/ /****************************************************************************/
@ -503,48 +423,23 @@ enum ZT_Event
* *
* Meta-data: ZT_UserMessage structure * Meta-data: ZT_UserMessage structure
*/ */
ZT_EVENT_USER_MESSAGE = 6, 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
}; };
/** /**
* Payload of REMOTE_TRACE event * Identity type codes
*/ */
typedef struct enum ZT_Identity_Type
{ {
/** /* These values must be the same as in Identity.hpp in the core. */
* ZeroTier address of sender (in least significant 40 bits only) ZT_IDENTITY_TYPE_C25519 = 0,
*/ ZT_IDENTITY_TYPE_P384 = 1
uint64_t origin; };
/** /**
* Null-terminated Dictionary containing key/value pairs sent by origin * A ZeroTier identity (opaque)
*
* 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; typedef void ZT_Identity;
/**
* Length of dict[] in bytes, INCLUDING terminating null
*/
unsigned int len;
} ZT_RemoteTrace;
/** /**
* User message used with ZT_EVENT_USER_MESSAGE * User message used with ZT_EVENT_USER_MESSAGE
@ -589,6 +484,11 @@ typedef struct
*/ */
uint64_t address; uint64_t address;
/**
* Actual identity object for this node
*/
const ZT_Identity *identity;
/** /**
* Public identity in string-serialized form (safe to send to others) * 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 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 * Virtual network configuration
*/ */
@ -1183,6 +1073,15 @@ typedef struct
int preferred; int preferred;
} ZT_PeerPhysicalPath; } 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 * Peer status result buffer
*/ */
@ -1193,6 +1092,11 @@ typedef struct
*/ */
uint64_t address; uint64_t address;
/**
* Peer identity
*/
const ZT_Identity *identity;
/** /**
* Remote major version or -1 if not known * Remote major version or -1 if not known
*/ */
@ -1497,7 +1401,7 @@ typedef int (*ZT_PathLookupFunction)(
void *, /* User ptr */ void *, /* User ptr */
void *, /* Thread ptr */ void *, /* Thread ptr */
uint64_t, /* ZeroTier address (40 bits) */ 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 */ int, /* Desired ss_family or -1 for any */
struct sockaddr_storage *); /* Result buffer */ struct sockaddr_storage *); /* Result buffer */
@ -1541,12 +1445,12 @@ struct ZT_Node_Callbacks
ZT_EventCallback eventCallback; 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; 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; 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); 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 * Get ZeroTier One version
* *

View file

@ -56,6 +56,7 @@ set(core_src
Identity.cpp Identity.cpp
IncomingPacket.cpp IncomingPacket.cpp
InetAddress.cpp InetAddress.cpp
Locator.cpp
Membership.cpp Membership.cpp
Network.cpp Network.cpp
NetworkConfig.cpp NetworkConfig.cpp
@ -74,16 +75,3 @@ set(core_src
add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers}) add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers})
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}) 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)

View file

@ -11,10 +11,8 @@
*/ */
/****/ /****/
#include <stdio.h> #include <cstring>
#include <stdlib.h> #include <cstdint>
#include <string.h>
#include <stdint.h>
#include "Constants.hpp" #include "Constants.hpp"
#include "Identity.hpp" #include "Identity.hpp"
@ -143,6 +141,108 @@ bool Identity::locallyValidate() const
return false; 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 char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{ {
switch(_type) { switch(_type) {
@ -286,3 +386,99 @@ bool Identity::fromString(const char *str)
} }
} // namespace ZeroTier } // 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<ZT_Identity *>(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<ZT_Identity *>(id);
} catch ( ... ) {
return nullptr;
}
}
int ZT_Identity_validate(const ZT_Identity *id)
{
if (!id)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(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<const ZeroTier::Identity *>(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<const ZeroTier::Identity *>(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<const ZeroTier::Identity *>(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<const ZeroTier::Identity *>(id)->toString(includePrivate != 0,buf);
return buf;
}
int ZT_Identity_hasPrivate(const ZT_Identity *id)
{
if (!id)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->hasPrivate() ? 1 : 0;
}
uint64_t ZT_Identity_address(const ZT_Identity *id)
{
if (!id)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->address().toInt();
}
void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate)
{
reinterpret_cast<const ZeroTier::Identity *>(id)->hash(h,includePrivate != 0);
}
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)
{
if (id)
delete reinterpret_cast<ZeroTier::Identity *>(id);
}
}

View file

@ -67,7 +67,7 @@ public:
* *
* @param str Identity in canonical string format * @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) * Set identity to NIL value (all zero)
@ -86,7 +86,7 @@ public:
* *
* @param t Type of identity to generate * @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 * 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 h Buffer to receive SHA384 of public key(s)
* @param includePrivate If true, hash private key(s) as well * @param includePrivate If true, hash private key(s) as well
*/ */
inline bool hash(uint8_t h[48],const bool includePrivate = false) const bool hash(uint8_t h[48],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;
}
/** /**
* Sign a message with this identity (private key required) * Sign a message with this identity (private key required)
@ -138,31 +120,7 @@ public:
* @param siglen Length of buffer * @param siglen Length of buffer
* @return Number of bytes actually written to sig or 0 on error * @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 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;
}
/** /**
* Verify a message signature against this identity * Verify a message signature against this identity
@ -173,24 +131,7 @@ public:
* @param siglen Length of signature in bytes * @param siglen Length of signature in bytes
* @return True if signature validates and data integrity checks * @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 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;
}
/** /**
* Shortcut method to perform key agreement with another identity * Shortcut method to perform key agreement with another identity
@ -201,42 +142,7 @@ public:
* @param key Result parameter to fill with key bytes * @param key Result parameter to fill with key bytes
* @return Was agreement successful? * @return Was agreement successful?
*/ */
inline bool agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const 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;
}
/** /**
* @return This identity's address * @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]; 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))) 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 -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) { } else if (privlen == 0) {
_hasPrivate = false; _hasPrivate = false;
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2); return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);

View file

@ -41,7 +41,7 @@ namespace {
// Implementation of each protocol verb // // Implementation of each protocol verb //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid,const SharedPtr<Path> &path) void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid,const SharedPtr<Path> &path)
{ {
Packet outp(pkt.source(),RR->identity.address(),Packet::VERB_ERROR); Packet outp(pkt.source(),RR->identity.address(),Packet::VERB_ERROR);
outp.append((uint8_t)pkt.verb()); 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()); 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> &path) ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const bool alreadyAuthenticated,const SharedPtr<Path> &path)
{ {
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
@ -181,15 +181,15 @@ static inline bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *const
return true; return true;
} }
static inline bool _doACK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doACK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
} }
static inline bool _doQOS_MEASUREMENT(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doQOS_MEASUREMENT(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
} }
static inline bool _doERROR(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doERROR(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const Packet::Verb inReVerb = (Packet::Verb)pkt[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; const Packet::Verb inReVerb = (Packet::Verb)pkt[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB];
const uint64_t inRePacketId = pkt.at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); const uint64_t inRePacketId = pkt.at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID);
@ -251,7 +251,7 @@ static inline bool _doERROR(IncomingPacket &pkt,const RuntimeEnvironment *const
return true; return true;
} }
static inline bool _doOK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doOK(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const Packet::Verb inReVerb = (Packet::Verb)pkt[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const Packet::Verb inReVerb = (Packet::Verb)pkt[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB];
const uint64_t inRePacketId = pkt.at<uint64_t>(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); const uint64_t inRePacketId = pkt.at<uint64_t>(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; return true;
} }
static inline bool _doWHOIS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doWHOIS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
if (!peer->rateGateInboundWhoisRequest(RR->node->now())) if (!peer->rateGateInboundWhoisRequest(RR->node->now()))
return true; return true;
@ -353,7 +353,7 @@ static inline bool _doWHOIS(IncomingPacket &pkt,const RuntimeEnvironment *const
return true; return true;
} }
static inline bool _doRENDEZVOUS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doRENDEZVOUS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
if (RR->topology->isRoot(peer->identity())) { if (RR->topology->isRoot(peer->identity())) {
const Address with(pkt.field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); 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; return true;
} }
static inline bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID);
const SharedPtr<Network> network(RR->node->network(nwid)); const SharedPtr<Network> network(RR->node->network(nwid));
@ -398,7 +398,7 @@ static inline bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *const
return true; return true;
} }
static inline bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID);
const SharedPtr<Network> network(RR->node->network(nwid)); const SharedPtr<Network> network(RR->node->network(nwid));
@ -476,7 +476,7 @@ static inline bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment *co
return true; return true;
} }
static inline bool _doECHO(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doECHO(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
if (!peer->rateGateEchoRequest(RR->node->now())) if (!peer->rateGateEchoRequest(RR->node->now()))
return true; return true;
@ -495,7 +495,7 @@ static inline bool _doECHO(IncomingPacket &pkt,const RuntimeEnvironment *const R
return true; return true;
} }
static inline bool _doNETWORK_CREDENTIALS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doNETWORK_CREDENTIALS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
if (!peer->rateGateCredentialsReceived(RR->node->now())) if (!peer->rateGateCredentialsReceived(RR->node->now()))
return true; return true;
@ -577,7 +577,7 @@ static inline bool _doNETWORK_CREDENTIALS(IncomingPacket &pkt,const RuntimeEnvir
return true; return true;
} }
static inline bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
const unsigned int hopCount = pkt.hops(); const unsigned int hopCount = pkt.hops();
@ -603,7 +603,7 @@ static inline bool _doNETWORK_CONFIG_REQUEST(IncomingPacket &pkt,const RuntimeEn
return true; return true;
} }
static inline bool _doNETWORK_CONFIG(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doNETWORK_CONFIG(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const SharedPtr<Network> network(RR->node->network(pkt.at<uint64_t>(ZT_PACKET_IDX_PAYLOAD))); const SharedPtr<Network> network(RR->node->network(pkt.at<uint64_t>(ZT_PACKET_IDX_PAYLOAD)));
if (network) { if (network) {
@ -622,7 +622,7 @@ static inline bool _doNETWORK_CONFIG(IncomingPacket &pkt,const RuntimeEnvironmen
return true; return true;
} }
static inline bool _doMULTICAST_GATHER(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doMULTICAST_GATHER(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); const uint64_t nwid = pkt.at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID);
const unsigned int flags = pkt[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; 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; return true;
} }
static inline bool _doPUSH_DIRECT_PATHS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doPUSH_DIRECT_PATHS(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
@ -720,7 +720,7 @@ static inline bool _doPUSH_DIRECT_PATHS(IncomingPacket &pkt,const RuntimeEnviron
return true; return true;
} }
static inline bool _doUSER_MESSAGE(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path) ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &pkt,const RuntimeEnvironment *const RR,void *const tPtr,const SharedPtr<Peer> &peer,const SharedPtr<Path> &path)
{ {
if (likely(pkt.size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { if (likely(pkt.size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) {
ZT_UserMessage um; ZT_UserMessage um;

View file

@ -376,7 +376,7 @@ bool InetAddress::operator<(const InetAddress &a) const
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
{ {
InetAddress r; InetAddress r;
sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r); sockaddr_in6 *const sin6 = reinterpret_cast<sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6; sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfe; sin6->sin6_addr.s6_addr[0] = 0xfe;
sin6->sin6_addr.s6_addr[1] = 0x80; 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 InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
{ {
InetAddress r; InetAddress r;
sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r); sockaddr_in6 *const sin6 = reinterpret_cast<sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6; sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfd; sin6->sin6_addr.s6_addr[0] = 0xfd;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56U); 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); nwid ^= (nwid >> 32U);
InetAddress r; InetAddress r;
sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r); sockaddr_in6 *const sin6 = reinterpret_cast<sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6; sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfc; sin6->sin6_addr.s6_addr[0] = 0xfc;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U); sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U);

View file

@ -42,6 +42,16 @@ namespace ZeroTier {
*/ */
struct InetAddress : public sockaddr_storage struct InetAddress : public sockaddr_storage
{ {
private:
template<typename SA>
ZT_ALWAYS_INLINE void copySockaddrToThis(const SA *sa)
{
memcpy(reinterpret_cast<void *>(this),sa,sizeof(SA));
if (sizeof(SA) < sizeof(InetAddress))
memset(reinterpret_cast<char *>(this) + sizeof(SA),0,sizeof(InetAddress) - sizeof(SA));
}
public:
/** /**
* Loopback IPv4 address (no port) * Loopback IPv4 address (no port)
*/ */
@ -79,116 +89,83 @@ struct InetAddress : public sockaddr_storage
// Hasher for unordered sets and maps in C++11 // 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(); } }; 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() { memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress)); }
ZT_ALWAYS_INLINE InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); } explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
ZT_ALWAYS_INLINE InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); } explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; } explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; } explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; } explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; } explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; } explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 &sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; } explicit 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(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 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 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 void clear() { memset(reinterpret_cast<void *>(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 InetAddress &operator=(const struct sockaddr_storage &ss) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage &ss)
{ {
if (reinterpret_cast<const InetAddress *>(&ss) != this) memcpy(reinterpret_cast<void *>(this),&ss,sizeof(InetAddress));
memcpy(this,&ss,sizeof(InetAddress));
return *this; return *this;
} }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage *ss) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage *ss)
{ {
if (reinterpret_cast<const InetAddress *>(ss) != this) if (ss)
memcpy(this,ss,sizeof(InetAddress)); memcpy(reinterpret_cast<void *>(this),ss,sizeof(InetAddress));
else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
return *this; return *this;
} }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in &sa) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in &sa)
{ {
if (reinterpret_cast<const InetAddress *>(&sa) != this) { copySockaddrToThis(&sa);
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in));
}
return *this; return *this;
} }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in *sa) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in *sa)
{ {
if (reinterpret_cast<const InetAddress *>(sa) != this) { if (sa)
memset(this,0,sizeof(InetAddress)); copySockaddrToThis(sa);
memcpy(this,sa,sizeof(struct sockaddr_in)); else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
}
return *this; return *this;
} }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 &sa) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 &sa)
{ {
if (reinterpret_cast<const InetAddress *>(&sa) != this) { copySockaddrToThis(&sa);
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in6));
}
return *this; return *this;
} }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 *sa) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 *sa)
{ {
if (reinterpret_cast<const InetAddress *>(sa) != this) { if (sa)
memset(this,0,sizeof(InetAddress)); copySockaddrToThis(sa);
memcpy(this,sa,sizeof(struct sockaddr_in6)); else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
}
return *this; return *this;
} }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr &sa) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr &sa)
{ {
if (reinterpret_cast<const InetAddress *>(&sa) != this) { if (sa.sa_family == AF_INET)
memset(this,0,sizeof(InetAddress)); copySockaddrToThis(reinterpret_cast<const sockaddr_in *>(&sa));
switch(sa.sa_family) { else if (sa.sa_family == AF_INET6)
case AF_INET: copySockaddrToThis(reinterpret_cast<const sockaddr_in6 *>(&sa));
memcpy(this,&sa,sizeof(struct sockaddr_in)); else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
break;
case AF_INET6:
memcpy(this,&sa,sizeof(struct sockaddr_in6));
break;
}
}
return *this; return *this;
} }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr *sa) ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr *sa)
{ {
if (reinterpret_cast<const InetAddress *>(sa) != this) { if (sa) {
memset(this,0,sizeof(InetAddress)); if (sa->sa_family == AF_INET)
switch(sa->sa_family) { copySockaddrToThis(reinterpret_cast<const sockaddr_in *>(sa));
case AF_INET: else if (sa->sa_family == AF_INET6)
memcpy(this,sa,sizeof(struct sockaddr_in)); copySockaddrToThis(reinterpret_cast<const sockaddr_in6 *>(sa));
break; return *this;
case AF_INET6:
memcpy(this,sa,sizeof(struct sockaddr_in6));
break;
}
} }
memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
return *this; return *this;
} }
@ -517,6 +494,9 @@ struct InetAddress : public sockaddr_storage
} }
inline int unmarshal(const uint8_t *restrict data,const int len) inline int unmarshal(const uint8_t *restrict data,const int len)
{ {
#ifdef ZT_NO_TYPE_PUNNING
uint16_t tmp;
#endif
if (len <= 0) if (len <= 0)
return -1; return -1;
switch(data[0]) { switch(data[0]) {
@ -525,22 +505,32 @@ struct InetAddress : public sockaddr_storage
case 4: case 4:
if (len < 7) if (len < 7)
return -1; return -1;
memset(this,0,sizeof(InetAddress)); memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
reinterpret_cast<sockaddr_in *>(this)->sin_family = AF_INET; reinterpret_cast<sockaddr_in *>(this)->sin_family = AF_INET;
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[0] = data[1]; reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[0] = data[1];
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[1] = data[2]; reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[1] = data[2];
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[2] = data[3]; reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[2] = data[3];
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[3] = data[4]; reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[3] = data[4];
reinterpret_cast<sockaddr_in *>(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<sockaddr_in *>(this)->sin_port = tmp;
#else
reinterpret_cast<sockaddr_in *>(this)->sin_port = *((const uint16_t *)(data + 5));
#endif
return 7; return 7;
case 6: case 6:
if (len < 19) if (len < 19)
return -1; return -1;
memset(this,0,sizeof(InetAddress)); memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
reinterpret_cast<sockaddr_in6 *>(this)->sin6_family = AF_INET6; reinterpret_cast<sockaddr_in6 *>(this)->sin6_family = AF_INET6;
for(int i=0;i<16;i++) for(int i=0;i<16;i++)
(reinterpret_cast<sockaddr_in6 *>(this)->sin6_addr.s6_addr)[i] = data[i+1]; (reinterpret_cast<sockaddr_in6 *>(this)->sin6_addr.s6_addr)[i] = data[i+1];
reinterpret_cast<sockaddr_in6 *>(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<sockaddr_in *>(this)->sin_port = tmp;
#else
reinterpret_cast<sockaddr_in *>(this)->sin_port = *((const uint16_t *)(data + 17));
#endif
return 19; return 19;
default: default:
return -1; return -1;
@ -666,6 +656,13 @@ struct InetAddress : public sockaddr_storage
static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress); static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress);
}; };
InetAddress *asInetAddress(sockaddr_in *p) { return reinterpret_cast<InetAddress *>(p); }
InetAddress *asInetAddress(sockaddr_in6 *p) { return reinterpret_cast<InetAddress *>(p); }
InetAddress *asInetAddress(sockaddr *p) { return reinterpret_cast<InetAddress *>(p); }
const InetAddress *asInetAddress(const sockaddr_in *p) { return reinterpret_cast<const InetAddress *>(p); }
const InetAddress *asInetAddress(const sockaddr_in6 *p) { return reinterpret_cast<const InetAddress *>(p); }
const InetAddress *asInetAddress(const sockaddr *p) { return reinterpret_cast<const InetAddress *>(p); }
} // namespace ZeroTier } // namespace ZeroTier
#endif #endif

106
node/Locator.cpp Normal file
View file

@ -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<ec;++i) {
int tmp = _at[i].unmarshal(data + p,len - p);
if (tmp < 0)
return -1;
p += tmp;
}
if ((p + 2) > 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

View file

@ -54,38 +54,32 @@ public:
ZT_ALWAYS_INLINE bool isSigned() const { return (_signatureLength > 0); } 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 * @param ep Endpoint to add
* @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
*/ */
inline bool add(const Endpoint &ep) ZT_ALWAYS_INLINE bool add(const Endpoint &ep)
{ {
if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS) if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS)
return false; return false;
if (!std::binary_search(_at,_at + _endpointCount,ep)) {
_at[_endpointCount++] = ep; _at[_endpointCount++] = ep;
std::sort(_at,_at + _endpointCount);
}
return true; return true;
} }
/** /**
* Sign this locator * 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 * @param id Identity that includes private key
* @return True if signature successful * @return True if signature successful
*/ */
inline bool sign(const int64_t ts,const Identity &id) bool sign(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);
}
/** /**
* Verify this Locator's validity and signature * Verify this Locator's validity and signature
@ -93,84 +87,13 @@ public:
* @param id Identity corresponding to hash * @param id Identity corresponding to hash
* @return True if valid and signature checks out * @return True if valid and signature checks out
*/ */
inline bool verify(const Identity &id) const 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);
}
explicit ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); } explicit ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); }
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_LOCATOR_MARSHAL_SIZE_MAX; } 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 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);
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<ec;++i) {
int tmp = _at[i].unmarshal(data + p,len - p);
if (tmp < 0)
return -1;
p += tmp;
}
if ((p + 2) > 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;
}
////////////////////////////////////////////////////////////////////////////
private: private:
int64_t _ts; int64_t _ts;

View file

@ -371,6 +371,7 @@ uint64_t Node::address() const
void Node::status(ZT_NodeStatus *status) const void Node::status(ZT_NodeStatus *status) const
{ {
status->address = RR->identity.address().toInt(); status->address = RR->identity.address().toInt();
status->identity = reinterpret_cast<const ZT_Identity *>(&RR->identity);
status->publicIdentity = RR->publicIdentityStr; status->publicIdentity = RR->publicIdentityStr;
status->secretIdentity = RR->secretIdentityStr; status->secretIdentity = RR->secretIdentityStr;
status->online = _online ? 1 : 0; status->online = _online ? 1 : 0;
@ -384,34 +385,38 @@ ZT_PeerList *Node::peers() const
RR->topology->getAllPeers(peers); RR->topology->getAllPeers(peers);
std::sort(peers.begin(),peers.end(),_sortPeerPtrsByAddress()); 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) if (!buf)
return (ZT_PeerList *)0; return (ZT_PeerList *)0;
ZT_PeerList *pl = (ZT_PeerList *)buf; ZT_PeerList *pl = (ZT_PeerList *)buf;
pl->peers = (ZT_Peer *)(buf + sizeof(ZT_PeerList)); 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; pl->peerCount = 0;
for(std::vector< SharedPtr<Peer> >::iterator pi(peers.begin());pi!=peers.end();++pi) { for(std::vector< SharedPtr<Peer> >::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(); 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; p->hadAggregateLink = 0;
if ((*pi)->remoteVersionKnown()) { if ((*pi)->remoteVersionKnown()) {
p->versionMajor = (*pi)->remoteVersionMajor(); p->versionMajor = (int)(*pi)->remoteVersionMajor();
p->versionMinor = (*pi)->remoteVersionMinor(); p->versionMinor = (int)(*pi)->remoteVersionMinor();
p->versionRev = (*pi)->remoteVersionRevision(); p->versionRev = (int)(*pi)->remoteVersionRevision();
} else { } else {
p->versionMajor = -1; p->versionMajor = -1;
p->versionMinor = -1; p->versionMinor = -1;
p->versionRev = -1; p->versionRev = -1;
} }
p->latency = (*pi)->latency(_now); p->latency = (int)(*pi)->latency(now);
if (p->latency >= 0xffff) if (p->latency >= 0xffff)
p->latency = -1; 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<Path> > paths((*pi)->paths(now));
std::vector< SharedPtr<Path> > paths((*pi)->paths(_now)); SharedPtr<Path> bestp((*pi)->getAppropriatePath(now,false));
SharedPtr<Path> bestp((*pi)->getAppropriatePath(_now,false));
p->hadAggregateLink |= (*pi)->hasAggregateLink(); p->hadAggregateLink |= (*pi)->hasAggregateLink();
p->pathCount = 0; p->pathCount = 0;
for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) { for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) {
@ -434,6 +439,8 @@ ZT_PeerList *Node::peers() const
++p->pathCount; ++p->pathCount;
} }
++pl->peerCount;
} }
return pl; 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) bool Node::externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr)
{ {
char idStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; if (_cb.pathLookupFunction) {
id.toString(false,idStr); return (_cb.pathLookupFunction(
return (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,id.address().toInt(),idStr,family,reinterpret_cast<sockaddr_storage *>(&addr)) == ZT_RESULT_OK); reinterpret_cast<ZT_Node *>(this),
_uPtr,
tPtr,
id.address().toInt(),
reinterpret_cast<const ZT_Identity *>(&id),
family,
reinterpret_cast<sockaddr_storage *>(&addr)) == ZT_RESULT_OK);
}
return false;
} }
ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig) ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig)