Clang-format!!!

This commit is contained in:
Adam Ierymenko 2024-09-26 08:52:29 -04:00
parent f190df8621
commit 96ba1079b2
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
122 changed files with 41245 additions and 39820 deletions

View file

@ -57,7 +57,7 @@ SpacesInCStyleCastParentheses: 'false'
SpacesInContainerLiterals: 'true' SpacesInContainerLiterals: 'true'
SpacesInParentheses: 'false' SpacesInParentheses: 'false'
SpacesInSquareBrackets: 'false' SpacesInSquareBrackets: 'false'
UseTab: 'Always' UseTab: 'Never'
--- ---
Language: Cpp Language: Cpp

View file

@ -21,8 +21,8 @@
#define ZT_DEBUG_H #define ZT_DEBUG_H
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(__APPLE__)
#include <sys/syscall.h>
#include <pthread.h> #include <pthread.h>
#include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -33,72 +33,69 @@
// Debug output colors // Debug output colors
#if defined(__APPLE__) #if defined(__APPLE__)
#include "TargetConditionals.h" #include "TargetConditionals.h"
#endif #endif
#if defined(ZT_COLOR) && !defined(_WIN32) && !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(__APP_FRAMEWORK__) #if defined(ZT_COLOR) && ! defined(_WIN32) && ! defined(__ANDROID__) && ! defined(TARGET_OS_IPHONE) && ! defined(TARGET_IPHONE_SIMULATOR) && ! defined(__APP_FRAMEWORK__)
#define ZT_RED "\x1B[31m" #define ZT_RED "\x1B[31m"
#define ZT_GRN "\x1B[32m" #define ZT_GRN "\x1B[32m"
#define ZT_YEL "\x1B[33m" #define ZT_YEL "\x1B[33m"
#define ZT_BLU "\x1B[34m" #define ZT_BLU "\x1B[34m"
#define ZT_MAG "\x1B[35m" #define ZT_MAG "\x1B[35m"
#define ZT_CYN "\x1B[36m" #define ZT_CYN "\x1B[36m"
#define ZT_WHT "\x1B[37m" #define ZT_WHT "\x1B[37m"
#define ZT_RESET "\x1B[0m" #define ZT_RESET "\x1B[0m"
#else #else
#define ZT_RED #define ZT_RED
#define ZT_GRN #define ZT_GRN
#define ZT_YEL #define ZT_YEL
#define ZT_BLU #define ZT_BLU
#define ZT_MAG #define ZT_MAG
#define ZT_CYN #define ZT_CYN
#define ZT_WHT #define ZT_WHT
#define ZT_RESET #define ZT_RESET
#endif #endif
#define ZT_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // short #define ZT_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // short
#ifdef __linux__ #ifdef __linux__
#define ZT_THREAD_ID (long)0 // syscall(SYS_gettid) #define ZT_THREAD_ID (long)0 // syscall(SYS_gettid)
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
#define ZT_THREAD_ID (long)0 // (long)gettid() #define ZT_THREAD_ID (long)0 // (long)gettid()
#endif #endif
#ifdef __FreeBSD__ #ifdef __FreeBSD__
#define ZT_THREAD_ID (long)0 // (long)gettid() #define ZT_THREAD_ID (long)0 // (long)gettid()
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
#define ZT_THREAD_ID (long)0 // #define ZT_THREAD_ID (long)0 //
#endif #endif
#if defined(__JNI_LIB__) #if defined(__JNI_LIB__)
#include <jni.h> #include <jni.h>
#endif #endif
#if defined(__ANDROID__) #if defined(__ANDROID__)
#include <android/log.h> #include <android/log.h>
#define ZT_LOG_TAG "ZTSDK" #define ZT_LOG_TAG "ZTSDK"
#endif #endif
#if defined(ZT_DEBUG_TRACE) #if defined(ZT_DEBUG_TRACE)
#if ZT_MSG_INFO == true #if ZT_MSG_INFO == true
#if defined(__ANDROID__) #if defined(__ANDROID__)
#define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \ #define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, "INFO : %17s:%5d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args))
"INFO : %17s:%5d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args)) #endif
#endif #if defined(_WIN32)
#if defined(_WIN32) #define DEBUG_INFO(fmt, ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, __VA_ARGS__)
#define DEBUG_INFO(fmt, ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \ #endif
ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, __VA_ARGS__) #if defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__)
#endif #define DEBUG_INFO(fmt, args...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args)
#if defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__) #endif
#define DEBUG_INFO(fmt, args ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \ #else
ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) #define DEBUG_INFO(fmt, args...)
#endif #endif
#else
#define DEBUG_INFO(fmt, args...)
#endif
#else // blank #else // blank
#if defined(_WIN32) #if defined(_WIN32)
#define DEBUG_INFO(...) #define DEBUG_INFO(...)
#else #else
#define DEBUG_INFO(fmt, args...) #define DEBUG_INFO(fmt, args...)
#endif #endif
#endif #endif
#endif // _H #endif // _H

View file

@ -23,22 +23,22 @@
// For the struct sockaddr_storage structure // For the struct sockaddr_storage structure
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <windows.h>
#else /* not Windows */ #else /* not Windows */
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h>
#endif /* Windows or not */ #endif /* Windows or not */
#if defined (_MSC_VER) #if defined(_MSC_VER)
#ifdef ZT_EXPORT #ifdef ZT_EXPORT
#define ZT_SDK_API __declspec(dllexport) #define ZT_SDK_API __declspec(dllexport)
#else #else
#define ZT_SDK_API __declspec(dllimport) #define ZT_SDK_API __declspec(dllimport)
#if !defined(ZT_SDK) #if ! defined(ZT_SDK)
#ifdef _DEBUG #ifdef _DEBUG
#ifdef _WIN64 #ifdef _WIN64
#pragma comment(lib, "ZeroTierOne_x64d.lib") #pragma comment(lib, "ZeroTierOne_x64d.lib")
@ -372,8 +372,7 @@ extern "C" {
* indicate serious problems like an inaccessible data store or a compile * indicate serious problems like an inaccessible data store or a compile
* problem. * problem.
*/ */
enum ZT_ResultCode enum ZT_ResultCode {
{
/** /**
* Operation completed normally * Operation completed normally
*/ */
@ -423,13 +422,12 @@ enum ZT_ResultCode
* @param x Result code * @param x Result code
* @return True if result code indicates a fatal error * @return True if result code indicates a fatal error
*/ */
#define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100)&&(((int)(x)) < 1000)) #define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100) && (((int)(x)) < 1000))
/** /**
* Status codes sent to status update callback when things happen * Status codes sent to status update callback when things happen
*/ */
enum ZT_Event enum ZT_Event {
{
/** /**
* Node has been initialized * Node has been initialized
* *
@ -534,8 +532,7 @@ enum ZT_Event
/** /**
* Payload of REMOTE_TRACE event * Payload of REMOTE_TRACE event
*/ */
typedef struct typedef struct {
{
/** /**
* ZeroTier address of sender * ZeroTier address of sender
*/ */
@ -552,7 +549,7 @@ typedef struct
* *
* The contents of data[] may be modified. * The contents of data[] may be modified.
*/ */
char *data; char* data;
/** /**
* Length of dict[] in bytes, including terminating null * Length of dict[] in bytes, including terminating null
@ -570,8 +567,7 @@ typedef struct
* in the world can send you a user message! (Unless your network is air * in the world can send you a user message! (Unless your network is air
* gapped.) * gapped.)
*/ */
typedef struct typedef struct {
{
/** /**
* ZeroTier address of sender (least significant 40 bits) * ZeroTier address of sender (least significant 40 bits)
*/ */
@ -585,7 +581,7 @@ typedef struct
/** /**
* User message data (not including type ID) * User message data (not including type ID)
*/ */
const void *data; const void* data;
/** /**
* Length of data in bytes * Length of data in bytes
@ -596,8 +592,7 @@ typedef struct
/** /**
* Current node status * Current node status
*/ */
typedef struct typedef struct {
{
/** /**
* 40-bit ZeroTier address of this node * 40-bit ZeroTier address of this node
*/ */
@ -608,14 +603,14 @@ typedef struct
* *
* This pointer will remain valid as long as the node exists. * This pointer will remain valid as long as the node exists.
*/ */
const char *publicIdentity; const char* publicIdentity;
/** /**
* Full identity including secret key in string-serialized form * Full identity including secret key in string-serialized form
* *
* This pointer will remain valid as long as the node exists. * This pointer will remain valid as long as the node exists.
*/ */
const char *secretIdentity; const char* secretIdentity;
/** /**
* True if some kind of connectivity appears available * True if some kind of connectivity appears available
@ -628,8 +623,7 @@ typedef struct
* *
* This structure is subject to change between versions. * This structure is subject to change between versions.
*/ */
typedef struct typedef struct {
{
/** /**
* Number of each protocol verb (possible verbs 0..31) received * Number of each protocol verb (possible verbs 0..31) received
*/ */
@ -644,8 +638,7 @@ typedef struct
/** /**
* Virtual network status codes * Virtual network status codes
*/ */
enum ZT_VirtualNetworkStatus enum ZT_VirtualNetworkStatus {
{
/** /**
* Waiting for network configuration (also means revision == 0) * Waiting for network configuration (also means revision == 0)
*/ */
@ -685,8 +678,7 @@ enum ZT_VirtualNetworkStatus
/** /**
* Virtual network type codes * Virtual network type codes
*/ */
enum ZT_VirtualNetworkType enum ZT_VirtualNetworkType {
{
/** /**
* Private networks are authorized via certificates of membership * Private networks are authorized via certificates of membership
*/ */
@ -707,8 +699,7 @@ enum ZT_VirtualNetworkType
* Each rule is composed of zero or more MATCHes followed by an ACTION. * Each rule is composed of zero or more MATCHes followed by an ACTION.
* An ACTION with no MATCHes is always taken. * An ACTION with no MATCHes is always taken.
*/ */
enum ZT_VirtualNetworkRuleType enum ZT_VirtualNetworkRuleType {
{
// 0 to 15 reserved for actions // 0 to 15 reserved for actions
/** /**
@ -799,8 +790,7 @@ enum ZT_VirtualNetworkRuleType
* This is designed to be a more memory-efficient way of storing rules than * This is designed to be a more memory-efficient way of storing rules than
* a wide table, yet still fast and simple to access in code. * a wide table, yet still fast and simple to access in code.
*/ */
typedef struct typedef struct {
{
/** /**
* Type and flags * Type and flags
* *
@ -947,8 +937,7 @@ typedef struct
/** /**
* A route to be pushed on a virtual network * A route to be pushed on a virtual network
*/ */
typedef struct typedef struct {
{
/** /**
* Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default
*/ */
@ -973,8 +962,7 @@ typedef struct
/** /**
* DNS configuration to be pushed on a virtual network * DNS configuration to be pushed on a virtual network
*/ */
typedef struct typedef struct {
{
char domain[128]; char domain[128];
struct sockaddr_storage server_addr[ZT_MAX_DNS_SERVERS]; struct sockaddr_storage server_addr[ZT_MAX_DNS_SERVERS];
} ZT_VirtualNetworkDNS; } ZT_VirtualNetworkDNS;
@ -982,8 +970,7 @@ typedef struct
/** /**
* An Ethernet multicast group * An Ethernet multicast group
*/ */
typedef struct typedef struct {
{
/** /**
* MAC address (least significant 48 bits) * MAC address (least significant 48 bits)
*/ */
@ -998,8 +985,7 @@ typedef struct
/** /**
* Virtual network configuration update type * Virtual network configuration update type
*/ */
enum ZT_VirtualNetworkConfigOperation enum ZT_VirtualNetworkConfigOperation {
{
/** /**
* Network is coming up (either for the first time or after service restart) * Network is coming up (either for the first time or after service restart)
*/ */
@ -1024,8 +1010,7 @@ enum ZT_VirtualNetworkConfigOperation
/** /**
* What trust hierarchy role does this peer have? * What trust hierarchy role does this peer have?
*/ */
enum ZT_PeerRole enum ZT_PeerRole {
{
ZT_PEER_ROLE_LEAF = 0, // ordinary node ZT_PEER_ROLE_LEAF = 0, // ordinary node
ZT_PEER_ROLE_MOON = 1, // moon root ZT_PEER_ROLE_MOON = 1, // moon root
ZT_PEER_ROLE_PLANET = 2 // planetary root ZT_PEER_ROLE_PLANET = 2 // planetary root
@ -1034,17 +1019,12 @@ enum ZT_PeerRole
/** /**
* Vendor ID * Vendor ID
*/ */
enum ZT_Vendor enum ZT_Vendor { ZT_VENDOR_UNSPECIFIED = 0, ZT_VENDOR_ZEROTIER = 1 };
{
ZT_VENDOR_UNSPECIFIED = 0,
ZT_VENDOR_ZEROTIER = 1
};
/** /**
* Platform type * Platform type
*/ */
enum ZT_Platform enum ZT_Platform {
{
ZT_PLATFORM_UNSPECIFIED = 0, ZT_PLATFORM_UNSPECIFIED = 0,
ZT_PLATFORM_LINUX = 1, ZT_PLATFORM_LINUX = 1,
ZT_PLATFORM_WINDOWS = 2, ZT_PLATFORM_WINDOWS = 2,
@ -1066,8 +1046,7 @@ enum ZT_Platform
/** /**
* Architecture type * Architecture type
*/ */
enum ZT_Architecture enum ZT_Architecture {
{
ZT_ARCHITECTURE_UNSPECIFIED = 0, ZT_ARCHITECTURE_UNSPECIFIED = 0,
ZT_ARCHITECTURE_X86 = 1, ZT_ARCHITECTURE_X86 = 1,
ZT_ARCHITECTURE_X64 = 2, ZT_ARCHITECTURE_X64 = 2,
@ -1091,8 +1070,7 @@ enum ZT_Architecture
/** /**
* Virtual network configuration * Virtual network configuration
*/ */
typedef struct typedef struct {
{
/** /**
* 64-bit ZeroTier network ID * 64-bit ZeroTier network ID
*/ */
@ -1200,8 +1178,6 @@ typedef struct
*/ */
ZT_VirtualNetworkDNS dns; ZT_VirtualNetworkDNS dns;
/** /**
* sso enabled * sso enabled
*/ */
@ -1256,9 +1232,8 @@ typedef struct
/** /**
* A list of networks * A list of networks
*/ */
typedef struct typedef struct {
{ ZT_VirtualNetworkConfig* networks;
ZT_VirtualNetworkConfig *networks;
unsigned long networkCount; unsigned long networkCount;
} ZT_VirtualNetworkList; } ZT_VirtualNetworkList;
@ -1280,8 +1255,7 @@ typedef struct {
/** /**
* Physical network path to a peer * Physical network path to a peer
*/ */
typedef struct typedef struct {
{
/** /**
* Address of endpoint * Address of endpoint
*/ */
@ -1386,8 +1360,7 @@ typedef struct
/** /**
* Peer status result buffer * Peer status result buffer
*/ */
typedef struct typedef struct {
{
/** /**
* ZeroTier address (40 bits) * ZeroTier address (40 bits)
*/ */
@ -1457,17 +1430,15 @@ typedef struct
/** /**
* List of peers * List of peers
*/ */
typedef struct typedef struct {
{ ZT_Peer* peers;
ZT_Peer *peers;
unsigned long peerCount; unsigned long peerCount;
} ZT_PeerList; } ZT_PeerList;
/** /**
* ZeroTier core state objects * ZeroTier core state objects
*/ */
enum ZT_StateObjectType enum ZT_StateObjectType {
{
/** /**
* Null object -- ignored * Null object -- ignored
*/ */
@ -1559,13 +1530,13 @@ typedef void ZT_Node;
* PORT_ERROR state. * PORT_ERROR state.
*/ */
typedef int (*ZT_VirtualNetworkConfigFunction)( typedef int (*ZT_VirtualNetworkConfigFunction)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
uint64_t, /* Network ID */ uint64_t, /* Network ID */
void **, /* Modifiable network user PTR */ void**, /* Modifiable network user PTR */
enum ZT_VirtualNetworkConfigOperation, /* Config operation */ enum ZT_VirtualNetworkConfigOperation, /* Config operation */
const ZT_VirtualNetworkConfig *); /* Network configuration */ const ZT_VirtualNetworkConfig*); /* Network configuration */
/** /**
* Function to send a frame out to a virtual network port * Function to send a frame out to a virtual network port
@ -1575,16 +1546,16 @@ typedef int (*ZT_VirtualNetworkConfigFunction)(
* (9) frame length. * (9) frame length.
*/ */
typedef void (*ZT_VirtualNetworkFrameFunction)( typedef void (*ZT_VirtualNetworkFrameFunction)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
uint64_t, /* Network ID */ uint64_t, /* Network ID */
void **, /* Modifiable network user PTR */ void**, /* Modifiable network user PTR */
uint64_t, /* Source MAC */ uint64_t, /* Source MAC */
uint64_t, /* Destination MAC */ uint64_t, /* Destination MAC */
unsigned int, /* Ethernet type */ unsigned int, /* Ethernet type */
unsigned int, /* VLAN ID (0 for none) */ unsigned int, /* VLAN ID (0 for none) */
const void *, /* Frame data */ const void*, /* Frame data */
unsigned int); /* Frame length */ unsigned int); /* Frame length */
/** /**
@ -1597,11 +1568,11 @@ typedef void (*ZT_VirtualNetworkFrameFunction)(
* in the definition of ZT_Event. * in the definition of ZT_Event.
*/ */
typedef void (*ZT_EventCallback)( typedef void (*ZT_EventCallback)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
enum ZT_Event, /* Event type */ enum ZT_Event, /* Event type */
const void *); /* Event payload (if applicable) */ const void*); /* Event payload (if applicable) */
/** /**
* Callback for storing and/or publishing state information * Callback for storing and/or publishing state information
@ -1613,12 +1584,12 @@ typedef void (*ZT_EventCallback)(
* deleted. * deleted.
*/ */
typedef void (*ZT_StatePutFunction)( typedef void (*ZT_StatePutFunction)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
enum ZT_StateObjectType, /* State object type */ enum ZT_StateObjectType, /* State object type */
const uint64_t [2], /* State object ID (if applicable) */ const uint64_t[2], /* State object ID (if applicable) */
const void *, /* State object data */ const void*, /* State object data */
int); /* Length of data or -1 to delete */ int); /* Length of data or -1 to delete */
/** /**
@ -1629,12 +1600,12 @@ typedef void (*ZT_StatePutFunction)(
* small to store it. * small to store it.
*/ */
typedef int (*ZT_StateGetFunction)( typedef int (*ZT_StateGetFunction)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
enum ZT_StateObjectType, /* State object type */ enum ZT_StateObjectType, /* State object type */
const uint64_t [2], /* State object ID (if applicable) */ const uint64_t[2], /* State object ID (if applicable) */
void *, /* Buffer to store state object data */ void*, /* Buffer to store state object data */
unsigned int); /* Length of data buffer in bytes */ unsigned int); /* Length of data buffer in bytes */
/** /**
@ -1662,12 +1633,12 @@ typedef int (*ZT_StateGetFunction)(
* delivery. It only means that the packet appears to have been sent. * delivery. It only means that the packet appears to have been sent.
*/ */
typedef int (*ZT_WirePacketSendFunction)( typedef int (*ZT_WirePacketSendFunction)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
int64_t, /* Local socket */ int64_t, /* Local socket */
const struct sockaddr_storage *, /* Remote address */ const struct sockaddr_storage*, /* Remote address */
const void *, /* Packet data */ const void*, /* Packet data */
unsigned int, /* Packet length */ unsigned int, /* Packet length */
unsigned int); /* TTL or 0 to use default */ unsigned int); /* TTL or 0 to use default */
@ -1693,12 +1664,12 @@ typedef int (*ZT_WirePacketSendFunction)(
* interface (recursion). * interface (recursion).
*/ */
typedef int (*ZT_PathCheckFunction)( typedef int (*ZT_PathCheckFunction)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
uint64_t, /* ZeroTier address */ uint64_t, /* ZeroTier address */
int64_t, /* Local socket or -1 if unknown */ int64_t, /* Local socket or -1 if unknown */
const struct sockaddr_storage *); /* Remote address */ const struct sockaddr_storage*); /* Remote address */
/** /**
* Function to get physical addresses for ZeroTier peers * Function to get physical addresses for ZeroTier peers
@ -1716,12 +1687,12 @@ typedef int (*ZT_PathCheckFunction)(
* with an address. * with an address.
*/ */
typedef int (*ZT_PathLookupFunction)( typedef int (*ZT_PathLookupFunction)(
ZT_Node *, /* Node */ ZT_Node*, /* Node */
void *, /* User ptr */ void*, /* User ptr */
void *, /* Thread ptr */ void*, /* Thread ptr */
uint64_t, /* ZeroTier address (40 bits) */ uint64_t, /* ZeroTier address (40 bits) */
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 */
/****************************************************************************/ /****************************************************************************/
/* C Node API */ /* C Node API */
@ -1730,8 +1701,7 @@ typedef int (*ZT_PathLookupFunction)(
/** /**
* Structure for configuring ZeroTier core callback functions * Structure for configuring ZeroTier core callback functions
*/ */
struct ZT_Node_Callbacks struct ZT_Node_Callbacks {
{
/** /**
* Struct version -- must currently be 0 * Struct version -- must currently be 0
*/ */
@ -1793,7 +1763,7 @@ struct ZT_Node_Callbacks
* @param now Current clock in milliseconds * @param now Current clock in milliseconds
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now); ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node** node, void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
/** /**
* Delete a node and free all resources it consumes * Delete a node and free all resources it consumes
@ -1803,7 +1773,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,c
* *
* @param node Node to delete * @param node Node to delete
*/ */
ZT_SDK_API void ZT_Node_delete(ZT_Node *node); ZT_SDK_API void ZT_Node_delete(ZT_Node* node);
/** /**
* Process a packet received from the physical wire * Process a packet received from the physical wire
@ -1818,15 +1788,8 @@ ZT_SDK_API void ZT_Node_delete(ZT_Node *node);
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( ZT_SDK_API enum ZT_ResultCode
ZT_Node *node, ZT_Node_processWirePacket(ZT_Node* node, void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline);
void *tptr,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile int64_t *nextBackgroundTaskDeadline);
/** /**
* Process a frame from a virtual network port (tap) * Process a frame from a virtual network port (tap)
@ -1845,17 +1808,17 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket(
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
ZT_Node *node, ZT_Node* node,
void *tptr, void* tptr,
int64_t now, int64_t now,
uint64_t nwid, uint64_t nwid,
uint64_t sourceMac, uint64_t sourceMac,
uint64_t destMac, uint64_t destMac,
unsigned int etherType, unsigned int etherType,
unsigned int vlanId, unsigned int vlanId,
const void *frameData, const void* frameData,
unsigned int frameLength, unsigned int frameLength,
volatile int64_t *nextBackgroundTaskDeadline); volatile int64_t* nextBackgroundTaskDeadline);
/** /**
* Perform periodic background operations * Perform periodic background operations
@ -1866,7 +1829,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
* @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks()
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node* node, void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline);
/** /**
* Join a network * Join a network
@ -1882,7 +1845,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void
* @param uptr An arbitrary pointer to associate with this network (default: NULL) * @param uptr An arbitrary pointer to associate with this network (default: NULL)
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr); ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node* node, uint64_t nwid, void* uptr, void* tptr);
/** /**
* Leave a network * Leave a network
@ -1899,7 +1862,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *upt
* @param uptr Target pointer is set to uptr (if not NULL) * @param uptr Target pointer is set to uptr (if not NULL)
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr); ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node* node, uint64_t nwid, void** uptr, void* tptr);
/** /**
* Subscribe to an Ethernet multicast group * Subscribe to an Ethernet multicast group
@ -1927,7 +1890,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **u
* @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed)
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node* node, void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
/** /**
* Unsubscribe from an Ethernet multicast group (or all groups) * Unsubscribe from an Ethernet multicast group (or all groups)
@ -1943,7 +1906,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt
* @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed)
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node* node, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
/** /**
* Add or update a moon * Add or update a moon
@ -1959,7 +1922,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_
* @param len Length of moonWorld in bytes * @param len Length of moonWorld in bytes
* @return Error if moon was invalid or failed to be added * @return Error if moon was invalid or failed to be added
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed); ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node* node, void* tptr, uint64_t moonWorldId, uint64_t moonSeed);
/** /**
* Remove a moon (does nothing if not present) * Remove a moon (does nothing if not present)
@ -1969,7 +1932,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t mo
* @param moonWorldId World ID of moon to remove * @param moonWorldId World ID of moon to remove
* @return Error if anything bad happened * @return Error if anything bad happened
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId); ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node* node, void* tptr, uint64_t moonWorldId);
/** /**
* Get this node's 40-bit ZeroTier address * Get this node's 40-bit ZeroTier address
@ -1977,7 +1940,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t
* @param node Node instance * @param node Node instance
* @return ZeroTier address (least significant 40 bits of 64-bit int) * @return ZeroTier address (least significant 40 bits of 64-bit int)
*/ */
ZT_SDK_API uint64_t ZT_Node_address(ZT_Node *node); ZT_SDK_API uint64_t ZT_Node_address(ZT_Node* node);
/** /**
* Get the status of this node * Get the status of this node
@ -1985,7 +1948,7 @@ ZT_SDK_API uint64_t ZT_Node_address(ZT_Node *node);
* @param node Node instance * @param node Node instance
* @param status Buffer to fill with current node status * @param status Buffer to fill with current node status
*/ */
ZT_SDK_API void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status); ZT_SDK_API void ZT_Node_status(ZT_Node* node, ZT_NodeStatus* status);
/** /**
* Get a list of known peer nodes * Get a list of known peer nodes
@ -1996,7 +1959,7 @@ ZT_SDK_API void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status);
* @param node Node instance * @param node Node instance
* @return List of known peers or NULL on failure * @return List of known peers or NULL on failure
*/ */
ZT_SDK_API ZT_PeerList *ZT_Node_peers(ZT_Node *node); ZT_SDK_API ZT_PeerList* ZT_Node_peers(ZT_Node* node);
/** /**
* Get the status of a virtual network * Get the status of a virtual network
@ -2008,7 +1971,7 @@ ZT_SDK_API ZT_PeerList *ZT_Node_peers(ZT_Node *node);
* @param nwid 64-bit network ID * @param nwid 64-bit network ID
* @return Network configuration or NULL if we are not a member of this network * @return Network configuration or NULL if we are not a member of this network
*/ */
ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid); ZT_SDK_API ZT_VirtualNetworkConfig* ZT_Node_networkConfig(ZT_Node* node, uint64_t nwid);
/** /**
* Enumerate and get status of all networks * Enumerate and get status of all networks
@ -2016,7 +1979,7 @@ ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t
* @param node Node instance * @param node Node instance
* @return List of networks or NULL on failure * @return List of networks or NULL on failure
*/ */
ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node); ZT_SDK_API ZT_VirtualNetworkList* ZT_Node_networks(ZT_Node* node);
/** /**
* Free a query result buffer * Free a query result buffer
@ -2026,7 +1989,7 @@ ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node);
* @param node Node instance * @param node Node instance
* @param qr Query result buffer * @param qr Query result buffer
*/ */
ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node* node, void* qr);
/** /**
* Add a local interface address * Add a local interface address
@ -2050,12 +2013,12 @@ ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr);
* @param addr Local interface address * @param addr Local interface address
* @return Boolean: non-zero if address was accepted and added * @return Boolean: non-zero if address was accepted and added
*/ */
ZT_SDK_API int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr); ZT_SDK_API int ZT_Node_addLocalInterfaceAddress(ZT_Node* node, const struct sockaddr_storage* addr);
/** /**
* Clear local interface addresses * Clear local interface addresses
*/ */
ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node* node);
/** /**
* Send a VERB_USER_MESSAGE to another ZeroTier node * Send a VERB_USER_MESSAGE to another ZeroTier node
@ -2071,7 +2034,7 @@ ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node);
* @param len Length of data in bytes * @param len Length of data in bytes
* @return Boolean: non-zero on success, zero on failure * @return Boolean: non-zero on success, zero on failure
*/ */
ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node* node, void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len);
/** /**
* Set a network configuration master instance for this node * Set a network configuration master instance for this node
@ -2088,7 +2051,7 @@ ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,ui
* @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable * @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable
* @return OK (0) or error code if a fatal error condition has occurred * @return OK (0) or error code if a fatal error condition has occurred
*/ */
ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node* node, void* networkConfigMasterInstance);
/** /**
* Set configuration for a given physical path * Set configuration for a given physical path
@ -2098,7 +2061,7 @@ ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMaster
* @param pathConfig Path configuration or NULL to erase this entry and therefore reset it to NULL * @param pathConfig Path configuration or NULL to erase this entry and therefore reset it to NULL
* @return OK or error code * @return OK or error code
*/ */
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);
/** /**
* Get ZeroTier One version * Get ZeroTier One version
@ -2107,7 +2070,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node
* @param minor Result: minor version * @param minor Result: minor version
* @param revision Result: revision * @param revision Result: revision
*/ */
ZT_SDK_API void ZT_version(int *major,int *minor,int *revision); ZT_SDK_API void ZT_version(int* major, int* minor, int* revision);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -11,9 +11,10 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif #endif
@ -49,22 +50,22 @@ namespace {
(rh) = (uint32_t)(zt_##N >> 32U); \ (rh) = (uint32_t)(zt_##N >> 32U); \
(rl) = (uint32_t)zt_##N; (rl) = (uint32_t)zt_##N;
void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) noexcept void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t& y0, uint64_t& y1) noexcept
{ {
uint32_t hhh = (uint32_t)(hh >> 32U); uint32_t hhh = (uint32_t)(hh >> 32U);
uint32_t hhl = (uint32_t)hh; uint32_t hhl = (uint32_t)hh;
uint32_t hlh = (uint32_t)(hl >> 32U); uint32_t hlh = (uint32_t)(hl >> 32U);
uint32_t hll = (uint32_t)hl; uint32_t hll = (uint32_t)hl;
uint32_t hhXlh = hhh ^hlh; uint32_t hhXlh = hhh ^ hlh;
uint32_t hhXll = hhl ^hll; uint32_t hhXll = hhl ^ hll;
uint64_t yl = Utils::ntoh(y0); uint64_t yl = Utils::ntoh(y0);
uint64_t yh = Utils::ntoh(y1); uint64_t yh = Utils::ntoh(y1);
uint32_t cilh = (uint32_t)(yh >> 32U); uint32_t cilh = (uint32_t)(yh >> 32U);
uint32_t cill = (uint32_t)yh; uint32_t cill = (uint32_t)yh;
uint32_t cihh = (uint32_t)(yl >> 32U); uint32_t cihh = (uint32_t)(yl >> 32U);
uint32_t cihl = (uint32_t)yl; uint32_t cihl = (uint32_t)yl;
uint32_t cihXlh = cihh ^cilh; uint32_t cihXlh = cihh ^ cilh;
uint32_t cihXll = cihl ^cill; uint32_t cihXll = cihl ^ cill;
uint32_t aah, aal, abh, abl, ach, acl; uint32_t aah, aal, abh, abl, ach, acl;
s_bmul32(M0, cihh, hhh, aah, aal); s_bmul32(M0, cihh, hhh, aah, aal);
s_bmul32(M1, cihl, hhl, abh, abl); s_bmul32(M1, cihl, hhl, abh, abl);
@ -94,8 +95,8 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
cbh ^= bbh ^ abh; cbh ^= bbh ^ abh;
cbl ^= bbl ^ abl; cbl ^= bbl ^ abl;
uint64_t zhh = ((uint64_t)aah << 32U) | aal; uint64_t zhh = ((uint64_t)aah << 32U) | aal;
uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^(((uint64_t)cah << 32U) | cal); uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^ (((uint64_t)cah << 32U) | cal);
uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^(((uint64_t)cbh << 32U) | cbl); uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^ (((uint64_t)cbh << 32U) | cbl);
uint64_t zll = ((uint64_t)bbh << 32U) | bbl; uint64_t zll = ((uint64_t)bbh << 32U) | bbl;
zhh = zhh << 1U | zhl >> 63U; zhh = zhh << 1U | zhl >> 63U;
zhl = zhl << 1U | zlh >> 63U; zhl = zhl << 1U | zlh >> 63U;
@ -110,9 +111,9 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
} // anonymous namespace } // anonymous namespace
void AES::GMAC::update(const void *const data, unsigned int len) noexcept void AES::GMAC::update(const void* const data, unsigned int len) noexcept
{ {
const uint8_t *in = reinterpret_cast<const uint8_t *>(data); const uint8_t* in = reinterpret_cast<const uint8_t*>(data);
_len += len; _len += len;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
@ -136,14 +137,14 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
if (_rp) { if (_rp) {
for (;;) { for (;;) {
if (!len) { if (! len) {
return; return;
} }
--len; --len;
_r[_rp++] = *(in++); _r[_rp++] = *(in++);
if (_rp == 16) { if (_rp == 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(_r); y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
break; break;
} }
@ -151,8 +152,8 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
} }
while (len >= 16) { while (len >= 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(in); y0 ^= Utils::loadMachineEndian<uint64_t>(in);
y1 ^= Utils::loadMachineEndian< uint64_t >(in + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(in + 8);
in += 16; in += 16;
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
len -= 16; len -= 16;
@ -192,8 +193,8 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
while (_rp < 16) { while (_rp < 16) {
_r[_rp++] = 0; _r[_rp++] = 0;
} }
y0 ^= Utils::loadMachineEndian< uint64_t >(_r); y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
} }
@ -201,24 +202,24 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
uint64_t iv2[2]; uint64_t iv2[2];
Utils::copy< 12 >(iv2, _iv); Utils::copy<12>(iv2, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(iv2)[3] = 0x00000001; reinterpret_cast<uint32_t*>(iv2)[3] = 0x00000001;
#else #else
reinterpret_cast<uint32_t *>(iv2)[3] = 0x01000000; reinterpret_cast<uint32_t*>(iv2)[3] = 0x01000000;
#endif #endif
_aes.encrypt(iv2, iv2); _aes.encrypt(iv2, iv2);
Utils::storeMachineEndian< uint64_t >(tag, iv2[0] ^ y0); Utils::storeMachineEndian<uint64_t>(tag, iv2[0] ^ y0);
Utils::storeMachineEndian< uint64_t >(tag + 8, iv2[1] ^ y1); Utils::storeMachineEndian<uint64_t>(tag + 8, iv2[1] ^ y1);
} }
// AES-CTR ------------------------------------------------------------------------------------------------------------ // AES-CTR ------------------------------------------------------------------------------------------------------------
void AES::CTR::crypt(const void *const input, unsigned int len) noexcept void AES::CTR::crypt(const void* const input, unsigned int len) noexcept
{ {
const uint8_t *in = reinterpret_cast<const uint8_t *>(input); const uint8_t* in = reinterpret_cast<const uint8_t*>(input);
uint8_t *out = _out; uint8_t* out = _out;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
@ -235,23 +236,23 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
#endif // ZT_AES_NEON #endif // ZT_AES_NEON
uint64_t keyStream[2]; uint64_t keyStream[2];
uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t *>(_ctr)[3]); uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t*>(_ctr)[3]);
unsigned int totalLen = _len; unsigned int totalLen = _len;
if ((totalLen & 15U)) { if ((totalLen & 15U)) {
for (;;) { for (;;) {
if (!len) { if (! len) {
_len = (totalLen + len); _len = (totalLen + len);
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if (!(totalLen & 15U)) { if (! (totalLen & 15U)) {
_aes.p_encryptSW(reinterpret_cast<const uint8_t *>(_ctr), reinterpret_cast<uint8_t *>(keyStream)); _aes.p_encryptSW(reinterpret_cast<const uint8_t*>(_ctr), reinterpret_cast<uint8_t*>(keyStream));
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(++ctr); reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(++ctr);
uint8_t *outblk = out + (totalLen - 16); uint8_t* outblk = out + (totalLen - 16);
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
outblk[i] ^= reinterpret_cast<uint8_t *>(keyStream)[i]; outblk[i] ^= reinterpret_cast<uint8_t*>(keyStream)[i];
} }
break; break;
} }
@ -262,10 +263,10 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
_len = (totalLen + len); _len = (totalLen + len);
if (likely(len >= 16)) { if (likely(len >= 16)) {
const uint32_t *const restrict rk = _aes.p_k.sw.ek; const uint32_t* const restrict rk = _aes.p_k.sw.ek;
const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[0]) ^rk[0]; const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[0]) ^ rk[0];
const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[1]) ^rk[1]; const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[1]) ^ rk[1];
const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[2]) ^rk[2]; const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[2]) ^ rk[2];
const uint32_t m8 = 0x000000ff; const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00; const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000; const uint32_t m8_16 = 0x00ff0000;
@ -278,8 +279,8 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = ctr2rk2; s2 = ctr2rk2;
s3 = ctr++ ^ rk[3]; s3 = ctr++ ^ rk[3];
const uint64_t in0 = *reinterpret_cast<const uint64_t *>(in); const uint64_t in0 = *reinterpret_cast<const uint64_t*>(in);
const uint64_t in1 = *reinterpret_cast<const uint64_t *>(in + 8); const uint64_t in1 = *reinterpret_cast<const uint64_t*>(in + 8);
in += 16; in += 16;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -339,11 +340,12 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59];
*reinterpret_cast<uint64_t *>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1); *reinterpret_cast<uint64_t*>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1);
*reinterpret_cast<uint64_t *>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3); *reinterpret_cast<uint64_t*>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3);
out += 16; out += 16;
} while ((len -= 16) >= 16); } while ((len -= 16) >= 16);
} else { }
else {
do { do {
uint32_t s0, s1, s2, s3, t0, t1, t2, t3; uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
s0 = ctr0rk0; s0 = ctr0rk0;
@ -428,7 +430,7 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
in += 16; in += 16;
} while ((len -= 16) >= 16); } while ((len -= 16) >= 16);
} }
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(ctr); reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(ctr);
} }
// Any remaining input is placed in _out. This will be picked up and crypted // Any remaining input is placed in _out. This will be picked up and crypted
@ -454,48 +456,76 @@ void AES::CTR::finish() noexcept
// Software AES and AES key expansion --------------------------------------------------------------------------------- // Software AES and AES key expansion ---------------------------------------------------------------------------------
const uint32_t AES::Te0[256] = {0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, const uint32_t AES::Te0[256] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a}; 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
const uint32_t AES::Te4[256] = {0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616}; 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a };
const uint32_t AES::Td0[256] = {0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, const uint32_t AES::Te4[256] = { 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676,
0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515,
0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484,
0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8,
0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742}; 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2,
const uint8_t AES::Td4[256] = {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373,
0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979,
0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808,
const uint32_t AES::rcon[15] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000}; 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a,
0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e,
0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf,
0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616 };
const uint32_t AES::Td0[256] = { 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 };
const uint8_t AES::Td4[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
const uint32_t AES::rcon[15] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000 };
void AES::p_initSW(const uint8_t *key) noexcept void AES::p_initSW(const uint8_t* key) noexcept
{ {
uint32_t *rk = p_k.sw.ek; uint32_t* rk = p_k.sw.ek;
rk[0] = Utils::loadBigEndian< uint32_t >(key); rk[0] = Utils::loadBigEndian<uint32_t>(key);
rk[1] = Utils::loadBigEndian< uint32_t >(key + 4); rk[1] = Utils::loadBigEndian<uint32_t>(key + 4);
rk[2] = Utils::loadBigEndian< uint32_t >(key + 8); rk[2] = Utils::loadBigEndian<uint32_t>(key + 8);
rk[3] = Utils::loadBigEndian< uint32_t >(key + 12); rk[3] = Utils::loadBigEndian<uint32_t>(key + 12);
rk[4] = Utils::loadBigEndian< uint32_t >(key + 16); rk[4] = Utils::loadBigEndian<uint32_t>(key + 16);
rk[5] = Utils::loadBigEndian< uint32_t >(key + 20); rk[5] = Utils::loadBigEndian<uint32_t>(key + 20);
rk[6] = Utils::loadBigEndian< uint32_t >(key + 24); rk[6] = Utils::loadBigEndian<uint32_t>(key + 24);
rk[7] = Utils::loadBigEndian< uint32_t >(key + 28); rk[7] = Utils::loadBigEndian<uint32_t>(key + 28);
for (int i = 0;;) { for (int i = 0;;) {
uint32_t temp = rk[7]; uint32_t temp = rk[7];
rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i]; rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i];
@ -513,7 +543,7 @@ void AES::p_initSW(const uint8_t *key) noexcept
rk += 8; rk += 8;
} }
p_encryptSW((const uint8_t *)Utils::ZERO256, (uint8_t *)p_k.sw.h); p_encryptSW((const uint8_t*)Utils::ZERO256, (uint8_t*)p_k.sw.h);
p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]); p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]);
p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]); p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]);
@ -545,17 +575,17 @@ void AES::p_initSW(const uint8_t *key) noexcept
} }
} }
void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept void AES::p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept
{ {
const uint32_t *const restrict rk = p_k.sw.ek; const uint32_t* const restrict rk = p_k.sw.ek;
const uint32_t m8 = 0x000000ff; const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00; const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000; const uint32_t m8_16 = 0x00ff0000;
const uint32_t m8_24 = 0xff000000; const uint32_t m8_24 = 0xff000000;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3; uint32_t t0, t1, t2, t3;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -615,20 +645,20 @@ void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0); Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1); Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2); Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3); Utils::storeBigEndian<uint32_t>(out + 12, s3);
} }
void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept void AES::p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept
{ {
const uint32_t *restrict rk = p_k.sw.dk; const uint32_t* restrict rk = p_k.sw.dk;
const uint32_t m8 = 0x000000ff; const uint32_t m8 = 0x000000ff;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3; uint32_t t0, t1, t2, t3;
t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4]; t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4];
@ -683,15 +713,15 @@ void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept
t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53]; t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53];
t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54]; t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54];
t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55]; t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55];
s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1) & m8]) ^ rk[56]; s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1)&m8]) ^ rk[56];
s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2) & m8]) ^ rk[57]; s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2)&m8]) ^ rk[57];
s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3) & m8]) ^ rk[58]; s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3)&m8]) ^ rk[58];
s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0) & m8]) ^ rk[59]; s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0)&m8]) ^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0); Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1); Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2); Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3); Utils::storeBigEndian<uint32_t>(out + 12, s3);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,16 +15,16 @@
#define ZT_AES_HPP #define ZT_AES_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp"
#include "SHA512.hpp" #include "SHA512.hpp"
#include "Utils.hpp"
// Uncomment to disable all hardware acceleration (usually for testing) // Uncomment to disable all hardware acceleration (usually for testing)
//#define ZT_AES_NO_ACCEL // #define ZT_AES_NO_ACCEL
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64) #if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64)
#define ZT_AES_AESNI 1 #define ZT_AES_AESNI 1
#endif #endif
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO) #if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO)
#define ZT_AES_NEON 1 #define ZT_AES_NEON 1
#endif #endif
@ -40,9 +40,8 @@ namespace ZeroTier {
* This includes hardware acceleration for certain processors. The software * This includes hardware acceleration for certain processors. The software
* mode is fallback and is significantly slower. * mode is fallback and is significantly slower.
*/ */
class AES class AES {
{ public:
public:
/** /**
* @return True if this system has hardware AES acceleration * @return True if this system has hardware AES acceleration
*/ */
@ -63,39 +62,44 @@ public:
* Create an un-initialized AES instance (must call init() before use) * Create an un-initialized AES instance (must call init() before use)
*/ */
ZT_INLINE AES() noexcept ZT_INLINE AES() noexcept
{} {
}
/** /**
* Create an AES instance with the given key * Create an AES instance with the given key
* *
* @param key 256-bit key * @param key 256-bit key
*/ */
explicit ZT_INLINE AES(const void *const key) noexcept explicit ZT_INLINE AES(const void* const key) noexcept
{ this->init(key); } {
this->init(key);
}
ZT_INLINE ~AES() ZT_INLINE ~AES()
{ Utils::burn(&p_k, sizeof(p_k)); } {
Utils::burn(&p_k, sizeof(p_k));
}
/** /**
* Set (or re-set) this AES256 cipher's key * Set (or re-set) this AES256 cipher's key
* *
* @param key 256-bit / 32-byte key * @param key 256-bit / 32-byte key
*/ */
ZT_INLINE void init(const void *const key) noexcept ZT_INLINE void init(const void* const key) noexcept
{ {
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
p_init_aesni(reinterpret_cast<const uint8_t *>(key)); p_init_aesni(reinterpret_cast<const uint8_t*>(key));
return; return;
} }
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
if (Utils::ARMCAP.aes) { if (Utils::ARMCAP.aes) {
p_init_armneon_crypto(reinterpret_cast<const uint8_t *>(key)); p_init_armneon_crypto(reinterpret_cast<const uint8_t*>(key));
return; return;
} }
#endif #endif
p_initSW(reinterpret_cast<const uint8_t *>(key)); p_initSW(reinterpret_cast<const uint8_t*>(key));
} }
/** /**
@ -104,7 +108,7 @@ public:
* @param in Input block * @param in Input block
* @param out Output block (can be same as input) * @param out Output block (can be same as input)
*/ */
ZT_INLINE void encrypt(const void *const in, void *const out) const noexcept ZT_INLINE void encrypt(const void* const in, void* const out) const noexcept
{ {
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
@ -118,7 +122,7 @@ public:
return; return;
} }
#endif #endif
p_encryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out)); p_encryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
} }
/** /**
@ -127,7 +131,7 @@ public:
* @param in Input block * @param in Input block
* @param out Output block (can be same as input) * @param out Output block (can be same as input)
*/ */
ZT_INLINE void decrypt(const void *const in, void *const out) const noexcept ZT_INLINE void decrypt(const void* const in, void* const out) const noexcept
{ {
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
@ -141,7 +145,7 @@ public:
return; return;
} }
#endif #endif
p_decryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out)); p_decryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
} }
class GMACSIVEncryptor; class GMACSIVEncryptor;
@ -150,8 +154,7 @@ public:
/** /**
* Streaming GMAC calculator * Streaming GMAC calculator
*/ */
class GMAC class GMAC {
{
friend class GMACSIVEncryptor; friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor; friend class GMACSIVDecryptor;
@ -177,8 +180,9 @@ public:
* *
* @param aes Keyed AES instance to use * @param aes Keyed AES instance to use
*/ */
ZT_INLINE GMAC(const AES &aes) : _aes(aes) ZT_INLINE GMAC(const AES& aes) : _aes(aes)
{} {
}
/** /**
* Reset and initialize for a new GMAC calculation * Reset and initialize for a new GMAC calculation
@ -193,11 +197,11 @@ public:
// this would hold the counter, but we're not doing GCM. The counter is therefore // this would hold the counter, but we're not doing GCM. The counter is therefore
// always 1. // always 1.
#ifdef ZT_AES_AESNI // also implies an x64 processor #ifdef ZT_AES_AESNI // also implies an x64 processor
*reinterpret_cast<uint64_t *>(_iv) = *reinterpret_cast<const uint64_t *>(iv); *reinterpret_cast<uint64_t*>(_iv) = *reinterpret_cast<const uint64_t*>(iv);
*reinterpret_cast<uint32_t *>(_iv + 8) = *reinterpret_cast<const uint64_t *>(iv + 8); *reinterpret_cast<uint32_t*>(_iv + 8) = *reinterpret_cast<const uint64_t*>(iv + 8);
*reinterpret_cast<uint32_t *>(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order *reinterpret_cast<uint32_t*>(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order
#else #else
for(int i=0;i<12;++i) { for (int i = 0; i < 12; ++i) {
_iv[i] = iv[i]; _iv[i] = iv[i];
} }
_iv[12] = 0; _iv[12] = 0;
@ -215,7 +219,7 @@ public:
* @param data Bytes to process * @param data Bytes to process
* @param len Length of input * @param len Length of input
*/ */
void update(const void *data, unsigned int len) noexcept; void update(const void* data, unsigned int len) noexcept;
/** /**
* Process any remaining cached bytes and generate tag * Process any remaining cached bytes and generate tag
@ -228,14 +232,14 @@ public:
private: private:
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
void p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept; void p_aesNIUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_aesNIFinish(uint8_t tag[16]) noexcept; void p_aesNIFinish(uint8_t tag[16]) noexcept;
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
void p_armUpdate(const uint8_t *in, unsigned int len) noexcept; void p_armUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_armFinish(uint8_t tag[16]) noexcept; void p_armFinish(uint8_t tag[16]) noexcept;
#endif #endif
const AES &_aes; const AES& _aes;
unsigned int _rp; unsigned int _rp;
unsigned int _len; unsigned int _len;
uint8_t _r[16]; // remainder uint8_t _r[16]; // remainder
@ -249,14 +253,14 @@ public:
* NOTE: this doesn't support overflow of the counter in the least significant 32 bits. * NOTE: this doesn't support overflow of the counter in the least significant 32 bits.
* AES-GMAC-CTR doesn't need this, so we don't support it as an optimization. * AES-GMAC-CTR doesn't need this, so we don't support it as an optimization.
*/ */
class CTR class CTR {
{
friend class GMACSIVEncryptor; friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor; friend class GMACSIVDecryptor;
public: public:
ZT_INLINE CTR(const AES &aes) noexcept: _aes(aes) ZT_INLINE CTR(const AES& aes) noexcept : _aes(aes)
{} {
}
/** /**
* Initialize this CTR instance to encrypt a new stream * Initialize this CTR instance to encrypt a new stream
@ -264,10 +268,10 @@ public:
* @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian) * @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!) * @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/ */
ZT_INLINE void init(const uint8_t iv[16], void *const output) noexcept ZT_INLINE void init(const uint8_t iv[16], void* const output) noexcept
{ {
Utils::copy< 16 >(_ctr, iv); Utils::copy<16>(_ctr, iv);
_out = reinterpret_cast<uint8_t *>(output); _out = reinterpret_cast<uint8_t*>(output);
_len = 0; _len = 0;
} }
@ -278,11 +282,11 @@ public:
* @param ic Initial counter (must be in big-endian byte order!) * @param ic Initial counter (must be in big-endian byte order!)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!) * @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/ */
ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void *const output) noexcept ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void* const output) noexcept
{ {
Utils::copy< 12 >(_ctr, iv); Utils::copy<12>(_ctr, iv);
reinterpret_cast<uint32_t *>(_ctr)[3] = ic; reinterpret_cast<uint32_t*>(_ctr)[3] = ic;
_out = reinterpret_cast<uint8_t *>(output); _out = reinterpret_cast<uint8_t*>(output);
_len = 0; _len = 0;
} }
@ -292,7 +296,7 @@ public:
* @param input Input data * @param input Input data
* @param len Length of input * @param len Length of input
*/ */
void crypt(const void *input, unsigned int len) noexcept; void crypt(const void* input, unsigned int len) noexcept;
/** /**
* Finish any remaining bytes if total bytes processed wasn't a multiple of 16 * Finish any remaining bytes if total bytes processed wasn't a multiple of 16
@ -303,14 +307,14 @@ public:
private: private:
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
void p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; void p_aesNICrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
void p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; void p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif #endif
const AES &_aes; const AES& _aes;
uint64_t _ctr[2]; uint64_t _ctr[2];
uint8_t *_out; uint8_t* _out;
unsigned int _len; unsigned int _len;
}; };
@ -325,8 +329,7 @@ public:
* This supports encryption of a maximum of 2^31 bytes of data per * This supports encryption of a maximum of 2^31 bytes of data per
* call to init(). * call to init().
*/ */
class GMACSIVEncryptor class GMACSIVEncryptor {
{
public: public:
/** /**
* Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances * Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances
@ -334,10 +337,11 @@ public:
* @param k0 First of two AES instances keyed with K0 * @param k0 First of two AES instances keyed with K0
* @param k1 Second of two AES instances keyed with K1 * @param k1 Second of two AES instances keyed with K1
*/ */
ZT_INLINE GMACSIVEncryptor(const AES &k0, const AES &k1) noexcept : ZT_INLINE GMACSIVEncryptor(const AES& k0, const AES& k1) noexcept
_gmac(k0), : _gmac(k0)
_ctr(k1) , _ctr(k1)
{} {
}
/** /**
* Initialize AES-GMAC-SIV * Initialize AES-GMAC-SIV
@ -345,7 +349,7 @@ public:
* @param iv IV in network byte order (byte order in which it will appear on the wire) * @param iv IV in network byte order (byte order in which it will appear on the wire)
* @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data! * @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data!
*/ */
ZT_INLINE void init(const uint64_t iv, void *const output) noexcept ZT_INLINE void init(const uint64_t iv, void* const output) noexcept
{ {
// Output buffer to receive the result of AES-CTR encryption. // Output buffer to receive the result of AES-CTR encryption.
_output = output; _output = output;
@ -353,7 +357,7 @@ public:
// Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero). // Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero).
_tag[0] = iv; _tag[0] = iv;
_tag[1] = 0; _tag[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(_tag)); _gmac.init(reinterpret_cast<const uint8_t*>(_tag));
} }
/** /**
@ -367,7 +371,7 @@ public:
* @param aad Additional authenticated data * @param aad Additional authenticated data
* @param len Length of AAD in bytes * @param len Length of AAD in bytes
*/ */
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{ {
// Feed ADD into GMAC first // Feed ADD into GMAC first
_gmac.update(aad, len); _gmac.update(aad, len);
@ -385,8 +389,10 @@ public:
* @param input Plaintext chunk * @param input Plaintext chunk
* @param len Length of plaintext chunk * @param len Length of plaintext chunk
*/ */
ZT_INLINE void update1(const void *const input, const unsigned int len) noexcept ZT_INLINE void update1(const void* const input, const unsigned int len) noexcept
{ _gmac.update(input, len); } {
_gmac.update(input, len);
}
/** /**
* Finish first pass, compute CTR IV, initialize second pass. * Finish first pass, compute CTR IV, initialize second pass.
@ -395,7 +401,7 @@ public:
{ {
// Compute 128-bit GMAC tag. // Compute 128-bit GMAC tag.
uint64_t tmp[2]; uint64_t tmp[2];
_gmac.finish(reinterpret_cast<uint8_t *>(tmp)); _gmac.finish(reinterpret_cast<uint8_t*>(tmp));
// Shorten to 64 bits, concatenate with message IV, and encrypt with AES to // Shorten to 64 bits, concatenate with message IV, and encrypt with AES to
// yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV // yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV
@ -415,7 +421,7 @@ public:
// and so 2^31 should be considered the input limit. // and so 2^31 should be considered the input limit.
tmp[0] = _tag[0]; tmp[0] = _tag[0];
tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), _output); _ctr.init(reinterpret_cast<const uint8_t*>(tmp), _output);
} }
/** /**
@ -427,8 +433,10 @@ public:
* @param input Plaintext chunk * @param input Plaintext chunk
* @param len Length of plaintext chunk * @param len Length of plaintext chunk
*/ */
ZT_INLINE void update2(const void *const input, const unsigned int len) noexcept ZT_INLINE void update2(const void* const input, const unsigned int len) noexcept
{ _ctr.crypt(input, len); } {
_ctr.crypt(input, len);
}
/** /**
* Finish second pass and return a pointer to the opaque 128-bit IV+MAC block * Finish second pass and return a pointer to the opaque 128-bit IV+MAC block
@ -438,14 +446,14 @@ public:
* *
* @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers) * @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers)
*/ */
ZT_INLINE const uint64_t *finish2() ZT_INLINE const uint64_t* finish2()
{ {
_ctr.finish(); _ctr.finish();
return _tag; return _tag;
} }
private: private:
void *_output; void* _output;
uint64_t _tag[2]; uint64_t _tag[2];
AES::GMAC _gmac; AES::GMAC _gmac;
AES::CTR _ctr; AES::CTR _ctr;
@ -456,13 +464,13 @@ public:
* *
* GMAC-SIV decryption is single-pass. AAD (if any) must be processed first. * GMAC-SIV decryption is single-pass. AAD (if any) must be processed first.
*/ */
class GMACSIVDecryptor class GMACSIVDecryptor {
{
public: public:
ZT_INLINE GMACSIVDecryptor(const AES &k0, const AES &k1) noexcept: ZT_INLINE GMACSIVDecryptor(const AES& k0, const AES& k1) noexcept
_ctr(k1), : _ctr(k1)
_gmac(k0) , _gmac(k0)
{} {
}
/** /**
* Initialize decryptor for a new message * Initialize decryptor for a new message
@ -470,18 +478,18 @@ public:
* @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption * @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption
* @param output Buffer in which to write output plaintext (must be large enough!) * @param output Buffer in which to write output plaintext (must be large enough!)
*/ */
ZT_INLINE void init(const uint64_t tag[2], void *const output) noexcept ZT_INLINE void init(const uint64_t tag[2], void* const output) noexcept
{ {
uint64_t tmp[2]; uint64_t tmp[2];
tmp[0] = tag[0]; tmp[0] = tag[0];
tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), output); _ctr.init(reinterpret_cast<const uint8_t*>(tmp), output);
_ctr._aes.decrypt(tag, _ivMac); _ctr._aes.decrypt(tag, _ivMac);
tmp[0] = _ivMac[0]; tmp[0] = _ivMac[0];
tmp[1] = 0; tmp[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(tmp)); _gmac.init(reinterpret_cast<const uint8_t*>(tmp));
_output = output; _output = output;
_decryptedLen = 0; _decryptedLen = 0;
@ -493,7 +501,7 @@ public:
* @param aad Additional authenticated data * @param aad Additional authenticated data
* @param len Length of AAD in bytes * @param len Length of AAD in bytes
*/ */
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{ {
_gmac.update(aad, len); _gmac.update(aad, len);
len &= 0xfU; len &= 0xfU;
@ -510,7 +518,7 @@ public:
* @param input Input ciphertext * @param input Input ciphertext
* @param len Length of ciphertext * @param len Length of ciphertext
*/ */
ZT_INLINE void update(const void *const input, const unsigned int len) noexcept ZT_INLINE void update(const void* const input, const unsigned int len) noexcept
{ {
_ctr.crypt(input, len); _ctr.crypt(input, len);
_decryptedLen += len; _decryptedLen += len;
@ -527,7 +535,7 @@ public:
uint64_t gmacTag[2]; uint64_t gmacTag[2];
_gmac.update(_output, _decryptedLen); _gmac.update(_output, _decryptedLen);
_gmac.finish(reinterpret_cast<uint8_t *>(gmacTag)); _gmac.finish(reinterpret_cast<uint8_t*>(gmacTag));
return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1]; return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1];
} }
@ -535,26 +543,24 @@ public:
uint64_t _ivMac[2]; uint64_t _ivMac[2];
AES::CTR _ctr; AES::CTR _ctr;
AES::GMAC _gmac; AES::GMAC _gmac;
void *_output; void* _output;
unsigned int _decryptedLen; unsigned int _decryptedLen;
}; };
private: private:
static const uint32_t Te0[256]; static const uint32_t Te0[256];
static const uint32_t Te4[256]; static const uint32_t Te4[256];
static const uint32_t Td0[256]; static const uint32_t Td0[256];
static const uint8_t Td4[256]; static const uint8_t Td4[256];
static const uint32_t rcon[15]; static const uint32_t rcon[15];
void p_initSW(const uint8_t *key) noexcept; void p_initSW(const uint8_t* key) noexcept;
void p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept; void p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept;
void p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept; void p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept;
union union {
{
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
struct struct {
{
__m128i k[28]; __m128i k[28];
__m128i h[4]; // h, hh, hhh, hhhh __m128i h[4]; // h, hh, hhh, hhhh
__m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc. __m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc.
@ -562,8 +568,7 @@ private:
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
struct struct {
{
uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens
uint8x16_t ek[15]; uint8x16_t ek[15];
uint8x16_t dk[15]; uint8x16_t dk[15];
@ -571,8 +576,7 @@ private:
} neon; } neon;
#endif #endif
struct struct {
{
uint64_t h[2]; uint64_t h[2];
uint32_t ek[60]; uint32_t ek[60];
uint32_t dk[60]; uint32_t dk[60];
@ -580,15 +584,15 @@ private:
} p_k; } p_k;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
void p_init_aesni(const uint8_t *key) noexcept; void p_init_aesni(const uint8_t* key) noexcept;
void p_encrypt_aesni(const void *in, void *out) const noexcept; void p_encrypt_aesni(const void* in, void* out) const noexcept;
void p_decrypt_aesni(const void *in, void *out) const noexcept; void p_decrypt_aesni(const void* in, void* out) const noexcept;
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
void p_init_armneon_crypto(const uint8_t *key) noexcept; void p_init_armneon_crypto(const uint8_t* key) noexcept;
void p_encrypt_armneon_crypto(const void *in, void *out) const noexcept; void p_encrypt_armneon_crypto(const void* in, void* out) const noexcept;
void p_decrypt_armneon_crypto(const void *in, void *out) const noexcept; void p_decrypt_armneon_crypto(const void* in, void* out) const noexcept;
#endif #endif
}; };

View file

@ -11,8 +11,8 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
@ -29,7 +29,8 @@ const __m128i s_sseSwapBytes = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif #endif
__m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept __m128i
p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
{ {
y = _mm_shuffle_epi8(y, s_sseSwapBytes); y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
@ -55,7 +56,7 @@ __m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
* The performance gain can be significant but regular SSE is already so * The performance gain can be significant but regular SSE is already so
* fast it's highly unlikely to be a rate limiting factor except on massive * fast it's highly unlikely to be a rate limiting factor except on massive
* servers and network infrastructure stuff. */ * servers and network infrastructure stuff. */
#if !defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7)) #if ! defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7))
#define ZT_AES_VAES512 1 #define ZT_AES_VAES512 1
@ -80,12 +81,8 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m512i kk13 = _mm512_broadcast_i32x4(k[13]); const __m512i kk13 = _mm512_broadcast_i32x4(k[13]);
const __m512i kk14 = _mm512_broadcast_i32x4(k[14]); const __m512i kk14 = _mm512_broadcast_i32x4(k[14]);
do { do {
__m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i *>(in)); __m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i*>(in));
__m512i d0 = _mm512_set_epi64( __m512i d0 = _mm512_set_epi64((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0, (long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0);
(long long)Utils::hton(c1 + 3ULL), (long long)c0,
(long long)Utils::hton(c1 + 2ULL), (long long)c0,
(long long)Utils::hton(c1 + 1ULL), (long long)c0,
(long long)Utils::hton(c1), (long long)c0);
c1 += 4; c1 += 4;
in += 64; in += 64;
len -= 64; len -= 64;
@ -104,7 +101,7 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d0 = _mm512_aesenc_epi128(d0, kk12); d0 = _mm512_aesenc_epi128(d0, kk12);
d0 = _mm512_aesenc_epi128(d0, kk13); d0 = _mm512_aesenc_epi128(d0, kk13);
d0 = _mm512_aesenclast_epi128(d0, kk14); d0 = _mm512_aesenclast_epi128(d0, kk14);
_mm512_storeu_si512(reinterpret_cast<__m512i *>(out), _mm512_xor_si512(p0, d0)); _mm512_storeu_si512(reinterpret_cast<__m512i*>(out), _mm512_xor_si512(p0, d0));
out += 64; out += 64;
} while (likely(len >= 64)); } while (likely(len >= 64));
} }
@ -132,14 +129,10 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]); const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]);
const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]); const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]);
do { do {
__m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in)); __m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in));
__m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in + 32)); __m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in + 32));
__m256i d0 = _mm256_set_epi64x( __m256i d0 = _mm256_set_epi64x((long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0);
(long long)Utils::hton(c1 + 1ULL), (long long)c0, __m256i d1 = _mm256_set_epi64x((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0);
(long long)Utils::hton(c1), (long long)c0);
__m256i d1 = _mm256_set_epi64x(
(long long)Utils::hton(c1 + 3ULL), (long long)c0,
(long long)Utils::hton(c1 + 2ULL), (long long)c0);
c1 += 4; c1 += 4;
in += 64; in += 64;
len -= 64; len -= 64;
@ -173,8 +166,8 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d1 = _mm256_aesenc_epi128(d1, kk13); d1 = _mm256_aesenc_epi128(d1, kk13);
d0 = _mm256_aesenclast_epi128(d0, kk14); d0 = _mm256_aesenclast_epi128(d0, kk14);
d1 = _mm256_aesenclast_epi128(d1, kk14); d1 = _mm256_aesenclast_epi128(d1, kk14);
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out), _mm256_xor_si256(d0, p0)); _mm256_storeu_si256(reinterpret_cast<__m256i*>(out), _mm256_xor_si256(d0, p0));
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out + 32), _mm256_xor_si256(d1, p1)); _mm256_storeu_si256(reinterpret_cast<__m256i*>(out + 32), _mm256_xor_si256(d1, p1));
out += 64; out += 64;
} while (likely(len >= 64)); } while (likely(len >= 64));
} }
@ -184,7 +177,8 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
__m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept __m128i
p_init256_1_aesni(__m128i a, __m128i b) noexcept
{ {
__m128i x, y; __m128i x, y;
b = _mm_shuffle_epi32(b, 0xff); b = _mm_shuffle_epi32(b, 0xff);
@ -201,7 +195,8 @@ __m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
__m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept __m128i
p_init256_2_aesni(__m128i a, __m128i b) noexcept
{ {
__m128i x, y, z; __m128i x, y, z;
y = _mm_aeskeygenassist_si128(a, 0x00); y = _mm_aeskeygenassist_si128(a, 0x00);
@ -223,18 +218,18 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif #endif
void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
{ {
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y)); __m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// Handle anything left over from a previous run that wasn't a multiple of 16 bytes. // Handle anything left over from a previous run that wasn't a multiple of 16 bytes.
if (_rp) { if (_rp) {
for (;;) { for (;;) {
if (!len) { if (! len) {
return; return;
} }
--len; --len;
_r[_rp++] = *(in++); _r[_rp++] = *(in++);
if (_rp == 16) { if (_rp == 16) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
break; break;
} }
} }
@ -250,17 +245,21 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
const __m128i hh2 = _aes.p_k.ni.h2[1]; const __m128i hh2 = _aes.p_k.ni.h2[1];
const __m128i hhh2 = _aes.p_k.ni.h2[2]; const __m128i hhh2 = _aes.p_k.ni.h2[2];
const __m128i hhhh2 = _aes.p_k.ni.h2[3]; const __m128i hhhh2 = _aes.p_k.ni.h2[3];
const uint8_t *const end64 = in + (len & ~((unsigned int)63)); const uint8_t* const end64 = in + (len & ~((unsigned int)63));
len &= 63U; len &= 63U;
do { do {
__m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))), sb); __m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))), sb);
__m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16)), sb); __m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)), sb);
__m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32)), sb); __m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)), sb);
__m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48)), sb); __m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)), sb);
in += 64; in += 64;
__m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00))); __m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00)));
__m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11))); __m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11)));
__m128i c = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), _mm_xor_si128(a, b)); __m128i c = _mm_xor_si128(
_mm_xor_si128(
_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)),
_mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))),
_mm_xor_si128(a, b));
a = _mm_xor_si128(_mm_slli_si128(c, 8), a); a = _mm_xor_si128(_mm_slli_si128(c, 8), a);
b = _mm_xor_si128(_mm_srli_si128(c, 8), b); b = _mm_xor_si128(_mm_srli_si128(c, 8), b);
c = _mm_srli_epi32(a, 31); c = _mm_srli_epi32(a, 31);
@ -274,12 +273,12 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
} }
while (len >= 16) { while (len >= 16) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)))); y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16; in += 16;
len -= 16; len -= 16;
} }
_mm_storeu_si128(reinterpret_cast<__m128i *>(_y), y); _mm_storeu_si128(reinterpret_cast<__m128i*>(_y), y);
// Any overflow is cached for a later run or finish(). // Any overflow is cached for a later run or finish().
for (unsigned int i = 0; i < len; ++i) { for (unsigned int i = 0; i < len; ++i) {
@ -293,23 +292,23 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul,aes")))
#endif #endif
void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
{ {
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y)); __m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// Handle any remaining bytes, padding the last block with zeroes. // Handle any remaining bytes, padding the last block with zeroes.
if (_rp) { if (_rp) {
while (_rp < 16) { while (_rp < 16) {
_r[_rp++] = 0; _r[_rp++] = 0;
} }
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
} }
// Interleave encryption of IV with the final GHASH of y XOR (length * 8). // Interleave encryption of IV with the final GHASH of y XOR (length * 8).
// Then XOR these together to get the final tag. // Then XOR these together to get the final tag.
const __m128i *const k = _aes.p_k.ni.k; const __m128i* const k = _aes.p_k.ni.k;
const __m128i h = _aes.p_k.ni.h[0]; const __m128i h = _aes.p_k.ni.h[0];
y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U))); y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U)));
y = _mm_shuffle_epi8(y, s_sseSwapBytes); y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i *>(_iv)), k[0]); __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(_iv)), k[0]);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
__m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01);
__m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10);
@ -359,7 +358,7 @@ void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
t4 = _mm_xor_si128(t4, t3); t4 = _mm_xor_si128(t4, t3);
encIV = _mm_aesenclast_si128(encIV, k[14]); encIV = _mm_aesenclast_si128(encIV, k[14]);
t4 = _mm_xor_si128(t4, t5); t4 = _mm_xor_si128(t4, t5);
_mm_storeu_si128(reinterpret_cast<__m128i *>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV)); _mm_storeu_si128(reinterpret_cast<__m128i*>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV));
} }
#ifdef __GNUC__ #ifdef __GNUC__
@ -370,7 +369,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]); const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]);
uint64_t c1 = Utils::ntoh(_ctr[1]); uint64_t c1 = Utils::ntoh(_ctr[1]);
const __m128i *const k = _aes.p_k.ni.k; const __m128i* const k = _aes.p_k.ni.k;
const __m128i k0 = k[0]; const __m128i k0 = k[0];
const __m128i k1 = k[1]; const __m128i k1 = k[1];
const __m128i k2 = k[2]; const __m128i k2 = k[2];
@ -391,14 +390,14 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
unsigned int totalLen = _len; unsigned int totalLen = _len;
if ((totalLen & 15U)) { if ((totalLen & 15U)) {
for (;;) { for (;;) {
if (unlikely(!len)) { if (unlikely(! len)) {
_ctr[1] = Utils::hton(c1); _ctr[1] = Utils::hton(c1);
_len = totalLen; _len = totalLen;
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if (!(totalLen & 15U)) { if (! (totalLen & 15U)) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0); d0 = _mm_xor_si128(d0, k0);
d0 = _mm_aesenc_si128(d0, k1); d0 = _mm_aesenc_si128(d0, k1);
@ -411,7 +410,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k8); d0 = _mm_aesenc_si128(d0, k8);
d0 = _mm_aesenc_si128(d0, k9); d0 = _mm_aesenc_si128(d0, k9);
d0 = _mm_aesenc_si128(d0, k10); d0 = _mm_aesenc_si128(d0, k10);
__m128i *const outblk = reinterpret_cast<__m128i *>(out + (totalLen - 16)); __m128i* const outblk = reinterpret_cast<__m128i*>(out + (totalLen - 16));
d0 = _mm_aesenc_si128(d0, k11); d0 = _mm_aesenc_si128(d0, k11);
const __m128i p0 = _mm_loadu_si128(outblk); const __m128i p0 = _mm_loadu_si128(outblk);
d0 = _mm_aesenc_si128(d0, k12); d0 = _mm_aesenc_si128(d0, k12);
@ -427,26 +426,26 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
_len = totalLen + len; _len = totalLen + len;
if (likely(len >= 64)) { if (likely(len >= 64)) {
#if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) #if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) { if (Utils::CPUID.vaes && (len >= 256)) {
if (Utils::CPUID.avx512f) { if (Utils::CPUID.avx512f) {
p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k);
} else { }
else {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
} }
goto skip_conventional_aesni_64; goto skip_conventional_aesni_64;
} }
#endif #endif
#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) #if ! defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) { if (Utils::CPUID.vaes && (len >= 256)) {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
goto skip_conventional_aesni_64; goto skip_conventional_aesni_64;
} }
#endif #endif
const uint8_t *const eof64 = in + (len & ~((unsigned int)63)); const uint8_t* const eof64 = in + (len & ~((unsigned int)63));
len &= 63; len &= 63;
__m128i d0, d1, d2, d3; __m128i d0, d1, d2, d3;
do { do {
@ -515,21 +514,20 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d1 = _mm_aesenc_si128(d1, k13); d1 = _mm_aesenc_si128(d1, k13);
d2 = _mm_aesenc_si128(d2, k13); d2 = _mm_aesenc_si128(d2, k13);
d3 = _mm_aesenc_si128(d3, k13); d3 = _mm_aesenc_si128(d3, k13);
d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))); d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16))); d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)));
d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32))); d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)));
d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48))); d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)));
in += 64; in += 64;
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0); _mm_storeu_si128(reinterpret_cast<__m128i*>(out), d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1); _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), d2); _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3); _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 48), d3);
out += 64; out += 64;
} while (likely(in != eof64)); } while (likely(in != eof64));
} }
skip_conventional_aesni_64: skip_conventional_aesni_64:
while (len >= 16) { while (len >= 16) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0); d0 = _mm_xor_si128(d0, k0);
@ -546,7 +544,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k11); d0 = _mm_aesenc_si128(d0, k11);
d0 = _mm_aesenc_si128(d0, k12); d0 = _mm_aesenc_si128(d0, k12);
d0 = _mm_aesenc_si128(d0, k13); d0 = _mm_aesenc_si128(d0, k13);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)))); _mm_storeu_si128(reinterpret_cast<__m128i*>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16; in += 16;
len -= 16; len -= 16;
out += 16; out += 16;
@ -568,8 +566,8 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
void AES::p_init_aesni(const uint8_t *key) noexcept void AES::p_init_aesni(const uint8_t *key) noexcept
{ {
__m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13; __m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13;
p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i *)key); p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i*)key);
p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i *)(key + 16)); p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i*)(key + 16));
p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01)); p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01));
p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2); p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2);
p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02)); p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02));
@ -631,7 +629,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
{ {
__m128i tmp = _mm_loadu_si128((const __m128i *)in); __m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[0]); tmp = _mm_xor_si128(tmp, p_k.ni.k[0]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]);
@ -646,7 +644,7 @@ void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]);
_mm_storeu_si128((__m128i *)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14])); _mm_storeu_si128((__m128i*)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14]));
} }
#ifdef __GNUC__ #ifdef __GNUC__
@ -654,7 +652,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
void AES::p_decrypt_aesni(const void *in, void *out) const noexcept void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
{ {
__m128i tmp = _mm_loadu_si128((const __m128i *)in); __m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[14]); tmp = _mm_xor_si128(tmp, p_k.ni.k[14]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]);
@ -669,7 +667,7 @@ void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]);
_mm_storeu_si128((__m128i *)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0])); _mm_storeu_si128((__m128i*)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0]));
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -11,8 +11,8 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
@ -29,34 +29,34 @@ ZT_INLINE uint8x16_t s_clmul_armneon_crypto(uint8x16_t h, uint8x16_t y, const ui
y = vrbitq_u8(y); y = vrbitq_u8(y);
const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087)); const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087));
t0 = vextq_u8(y, y, 8); t0 = vextq_u8(y, y, 8);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (r0) : "w" (h), "w" (y)); __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(r0) : "w"(h), "w"(y));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (r1) : "w" (h), "w" (y)); __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(r1) : "w"(h), "w"(y));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t1) : "w" (h), "w" (t0)); __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t1) : "w"(h), "w"(t0));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (h), "w" (t0)); __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(h), "w"(t0));
t0 = veorq_u8(t0, t1); t0 = veorq_u8(t0, t1);
t1 = vextq_u8(z, t0, 8); t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1); r0 = veorq_u8(r0, t1);
t1 = vextq_u8(t0, z, 8); t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1); r1 = veorq_u8(r1, t1);
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (r1), "w" (p)); __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
t1 = vextq_u8(t0, z, 8); t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1); r1 = veorq_u8(r1, t1);
t1 = vextq_u8(z, t0, 8); t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1); r0 = veorq_u8(r0, t1);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t0) : "w" (r1), "w" (p)); __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
return vrbitq_u8(veorq_u8(r0, t0)); return vrbitq_u8(veorq_u8(r0, t0));
} }
} // anonymous namespace } // anonymous namespace
void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept void AES::GMAC::p_armUpdate(const uint8_t* in, unsigned int len) noexcept
{ {
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y)); uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h; const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) { if (_rp) {
for(;;) { for (;;) {
if (!len) { if (! len) {
return; return;
} }
--len; --len;
@ -74,7 +74,7 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
len -= 16; len -= 16;
} }
vst1q_u8(reinterpret_cast<uint8_t *>(_y), y); vst1q_u8(reinterpret_cast<uint8_t*>(_y), y);
for (unsigned int i = 0; i < len; ++i) { for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i]; _r[i] = in[i];
@ -85,7 +85,7 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
{ {
uint64_t tmp[2]; uint64_t tmp[2];
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y)); uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h; const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) { if (_rp) {
@ -97,25 +97,25 @@ void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
tmp[0] = Utils::hton((uint64_t)_len << 3U); tmp[0] = Utils::hton((uint64_t)_len << 3U);
tmp[1] = 0; tmp[1] = 0;
y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t *>(tmp)); y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t*>(tmp));
Utils::copy< 12 >(tmp, _iv); Utils::copy<12>(tmp, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(tmp)[3] = 0x00000001; reinterpret_cast<uint32_t*>(tmp)[3] = 0x00000001;
#else #else
reinterpret_cast<uint32_t *>(tmp)[3] = 0x01000000; reinterpret_cast<uint32_t*>(tmp)[3] = 0x01000000;
#endif #endif
_aes.encrypt(tmp, tmp); _aes.encrypt(tmp, tmp);
uint8x16_t yy = y; uint8x16_t yy = y;
Utils::storeMachineEndian< uint64_t >(tag, tmp[0] ^ reinterpret_cast<const uint64_t *>(&yy)[0]); Utils::storeMachineEndian<uint64_t>(tag, tmp[0] ^ reinterpret_cast<const uint64_t*>(&yy)[0]);
Utils::storeMachineEndian< uint64_t >(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t *>(&yy)[1]); Utils::storeMachineEndian<uint64_t>(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t*>(&yy)[1]);
} }
void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept void AES::CTR::p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept
{ {
uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t *>(_ctr))); uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t*>(_ctr)));
const uint32x4_t one = {0,0,0,1}; const uint32x4_t one = { 0, 0, 0, 1 };
uint8x16_t k0 = _aes.p_k.neon.ek[0]; uint8x16_t k0 = _aes.p_k.neon.ek[0];
uint8x16_t k1 = _aes.p_k.neon.ek[1]; uint8x16_t k1 = _aes.p_k.neon.ek[1];
@ -136,15 +136,15 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
unsigned int totalLen = _len; unsigned int totalLen = _len;
if ((totalLen & 15U) != 0) { if ((totalLen & 15U) != 0) {
for (;;) { for (;;) {
if (unlikely(!len)) { if (unlikely(! len)) {
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd)); vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
_len = totalLen; _len = totalLen;
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if ((totalLen & 15U) == 0) { if ((totalLen & 15U) == 0) {
uint8_t *const otmp = out + (totalLen - 16); uint8_t* const otmp = out + (totalLen - 16);
uint8x16_t d0 = vrev32q_u8(dd); uint8x16_t d0 = vrev32q_u8(dd);
uint8x16_t pt = vld1q_u8(otmp); uint8x16_t pt = vld1q_u8(otmp);
d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); d0 = vaesmcq_u8(vaeseq_u8(d0, k0));
@ -298,7 +298,7 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
out[i] = in[i]; out[i] = in[i];
} }
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd)); vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
} }
#define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U)) #define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U))
@ -307,37 +307,43 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
#define ZT_INIT_ARMNEON_CRYPTO_NB 4 #define ZT_INIT_ARMNEON_CRYPTO_NB 4
#define ZT_INIT_ARMNEON_CRYPTO_NR 14 #define ZT_INIT_ARMNEON_CRYPTO_NR 14
void AES::p_init_armneon_crypto(const uint8_t *key) noexcept void AES::p_init_armneon_crypto(const uint8_t* key) noexcept
{ {
static const uint8_t s_sbox[256] = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, static const uint8_t s_sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
uint64_t h[2]; uint64_t h[2];
uint32_t *const w = reinterpret_cast<uint32_t *>(p_k.neon.ek); uint32_t* const w = reinterpret_cast<uint32_t*>(p_k.neon.ek);
for (unsigned int i=0;i<ZT_INIT_ARMNEON_CRYPTO_NK;++i) { for (unsigned int i = 0; i < ZT_INIT_ARMNEON_CRYPTO_NK; ++i) {
const unsigned int j = i * 4; const unsigned int j = i * 4;
w[i] = ((uint32_t)key[j] << 24U) | ((uint32_t)key[j + 1] << 16U) | ((uint32_t)key[j + 2] << 8U) | (uint32_t)key[j + 3]; w[i] = ((uint32_t)key[j] << 24U) | ((uint32_t)key[j + 1] << 16U) | ((uint32_t)key[j + 2] << 8U) | (uint32_t)key[j + 3];
} }
for (unsigned int i=ZT_INIT_ARMNEON_CRYPTO_NK;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) { for (unsigned int i = ZT_INIT_ARMNEON_CRYPTO_NK; i < (ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1)); ++i) {
uint32_t t = w[i - 1]; uint32_t t = w[i - 1];
const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1); const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1);
if (imod == 0) { if (imod == 0) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(ZT_INIT_ARMNEON_CRYPTO_ROTWORD(t)) ^ rcon[(i - 1) / ZT_INIT_ARMNEON_CRYPTO_NK]; t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(ZT_INIT_ARMNEON_CRYPTO_ROTWORD(t)) ^ rcon[(i - 1) / ZT_INIT_ARMNEON_CRYPTO_NK];
} else if (imod == 4) { }
else if (imod == 4) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(t); t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(t);
} }
w[i] = w[i - ZT_INIT_ARMNEON_CRYPTO_NK] ^ t; w[i] = w[i - ZT_INIT_ARMNEON_CRYPTO_NK] ^ t;
} }
for (unsigned int i=0;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) { for (unsigned int i = 0; i < (ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1)); ++i) {
w[i] = Utils::hton(w[i]); w[i] = Utils::hton(w[i]);
} }
p_k.neon.dk[0] = p_k.neon.ek[14]; p_k.neon.dk[0] = p_k.neon.ek[14];
for (int i=1;i<14;++i) { for (int i = 1; i < 14; ++i) {
p_k.neon.dk[i] = vaesimcq_u8(p_k.neon.ek[14 - i]); p_k.neon.dk[i] = vaesimcq_u8(p_k.neon.ek[14 - i]);
} }
p_k.neon.dk[14] = p_k.neon.ek[0]; p_k.neon.dk[14] = p_k.neon.ek[0];
@ -349,9 +355,9 @@ void AES::p_init_armneon_crypto(const uint8_t *key) noexcept
p_k.sw.h[1] = Utils::ntoh(h[1]); p_k.sw.h[1] = Utils::ntoh(h[1]);
} }
void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const noexcept void AES::p_encrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{ {
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in)); uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2]));
@ -366,12 +372,12 @@ void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12]));
tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]); tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp); vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
} }
void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const noexcept void AES::p_decrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{ {
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in)); uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2]));
@ -386,7 +392,7 @@ void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12]));
tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]); tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp); vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,49 +14,64 @@
#ifndef ZT_ADDRESS_HPP #ifndef ZT_ADDRESS_HPP
#define ZT_ADDRESS_HPP #define ZT_ADDRESS_HPP
#include <stdio.h> #include "Buffer.hpp"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Buffer.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
namespace ZeroTier { namespace ZeroTier {
/** /**
* A ZeroTier address * A ZeroTier address
*/ */
class Address class Address {
{ public:
public: Address() : _a(0)
Address() : _a(0) {} {
Address(const Address &a) : _a(a._a) {} }
Address(uint64_t a) : _a(a & 0xffffffffffULL) {} Address(const Address& a) : _a(a._a)
{
}
Address(uint64_t a) : _a(a & 0xffffffffffULL)
{
}
/** /**
* @param bits Raw address -- 5 bytes, big-endian byte order * @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array * @param len Length of array
*/ */
Address(const void *bits,unsigned int len) { setTo(bits,len); } Address(const void* bits, unsigned int len)
{
setTo(bits, len);
}
inline Address &operator=(const Address &a) { _a = a._a; return *this; } inline Address& operator=(const Address& a)
inline Address &operator=(const uint64_t a) { _a = (a & 0xffffffffffULL); return *this; } {
_a = a._a;
return *this;
}
inline Address& operator=(const uint64_t a)
{
_a = (a & 0xffffffffffULL);
return *this;
}
/** /**
* @param bits Raw address -- 5 bytes, big-endian byte order * @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array * @param len Length of array
*/ */
inline void setTo(const void *bits,const unsigned int len) inline void setTo(const void* bits, const unsigned int len)
{ {
if (len < ZT_ADDRESS_LENGTH) { if (len < ZT_ADDRESS_LENGTH) {
_a = 0; _a = 0;
return; return;
} }
const unsigned char *b = (const unsigned char *)bits; const unsigned char* b = (const unsigned char*)bits;
uint64_t a = ((uint64_t)*b++) << 32; uint64_t a = ((uint64_t)*b++) << 32;
a |= ((uint64_t)*b++) << 24; a |= ((uint64_t)*b++) << 24;
a |= ((uint64_t)*b++) << 16; a |= ((uint64_t)*b++) << 16;
@ -69,12 +84,12 @@ public:
* @param bits Buffer to hold 5-byte address in big-endian byte order * @param bits Buffer to hold 5-byte address in big-endian byte order
* @param len Length of array * @param len Length of array
*/ */
inline void copyTo(void *const bits,const unsigned int len) const inline void copyTo(void* const bits, const unsigned int len) const
{ {
if (len < ZT_ADDRESS_LENGTH) { if (len < ZT_ADDRESS_LENGTH) {
return; return;
} }
unsigned char *b = (unsigned char *)bits; unsigned char* b = (unsigned char*)bits;
*(b++) = (unsigned char)((_a >> 32) & 0xff); *(b++) = (unsigned char)((_a >> 32) & 0xff);
*(b++) = (unsigned char)((_a >> 24) & 0xff); *(b++) = (unsigned char)((_a >> 24) & 0xff);
*(b++) = (unsigned char)((_a >> 16) & 0xff); *(b++) = (unsigned char)((_a >> 16) & 0xff);
@ -87,10 +102,9 @@ public:
* *
* @param b Buffer to append to * @param b Buffer to append to
*/ */
template<unsigned int C> template <unsigned int C> inline void appendTo(Buffer<C>& b) const
inline void appendTo(Buffer<C> &b) const
{ {
unsigned char *p = (unsigned char *)b.appendField(ZT_ADDRESS_LENGTH); unsigned char* p = (unsigned char*)b.appendField(ZT_ADDRESS_LENGTH);
*(p++) = (unsigned char)((_a >> 32) & 0xff); *(p++) = (unsigned char)((_a >> 32) & 0xff);
*(p++) = (unsigned char)((_a >> 24) & 0xff); *(p++) = (unsigned char)((_a >> 24) & 0xff);
*(p++) = (unsigned char)((_a >> 16) & 0xff); *(p++) = (unsigned char)((_a >> 16) & 0xff);
@ -101,22 +115,34 @@ public:
/** /**
* @return Integer containing address (0 to 2^40) * @return Integer containing address (0 to 2^40)
*/ */
inline uint64_t toInt() const { return _a; } inline uint64_t toInt() const
{
return _a;
}
/** /**
* @return Hash code for use with Hashtable * @return Hash code for use with Hashtable
*/ */
inline unsigned long hashCode() const { return (unsigned long)_a; } inline unsigned long hashCode() const
{
return (unsigned long)_a;
}
/** /**
* @return Hexadecimal string * @return Hexadecimal string
*/ */
inline char *toString(char buf[11]) const { return Utils::hex10(_a,buf); } inline char* toString(char buf[11]) const
{
return Utils::hex10(_a, buf);
}
/** /**
* @return True if this address is not zero * @return True if this address is not zero
*/ */
inline operator bool() const { return (_a != 0); } inline operator bool() const
{
return (_a != 0);
}
/** /**
* Check if this address is reserved * Check if this address is reserved
@ -127,31 +153,76 @@ public:
* *
* @return True if address is reserved and may not be used * @return True if address is reserved and may not be used
*/ */
inline bool isReserved() const { return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); } inline bool isReserved() const
{
return ((! _a) || ((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX));
}
/** /**
* @param i Value from 0 to 4 (inclusive) * @param i Value from 0 to 4 (inclusive)
* @return Byte at said position (address interpreted in big-endian order) * @return Byte at said position (address interpreted in big-endian order)
*/ */
inline uint8_t operator[](unsigned int i) const { return (uint8_t)(_a >> (32 - (i * 8))); } inline uint8_t operator[](unsigned int i) const
{
return (uint8_t)(_a >> (32 - (i * 8)));
}
inline void zero() { _a = 0; } inline void zero()
{
_a = 0;
}
inline bool operator==(const uint64_t &a) const { return (_a == (a & 0xffffffffffULL)); } inline bool operator==(const uint64_t& a) const
inline bool operator!=(const uint64_t &a) const { return (_a != (a & 0xffffffffffULL)); } {
inline bool operator>(const uint64_t &a) const { return (_a > (a & 0xffffffffffULL)); } return (_a == (a & 0xffffffffffULL));
inline bool operator<(const uint64_t &a) const { return (_a < (a & 0xffffffffffULL)); } }
inline bool operator>=(const uint64_t &a) const { return (_a >= (a & 0xffffffffffULL)); } inline bool operator!=(const uint64_t& a) const
inline bool operator<=(const uint64_t &a) const { return (_a <= (a & 0xffffffffffULL)); } {
return (_a != (a & 0xffffffffffULL));
}
inline bool operator>(const uint64_t& a) const
{
return (_a > (a & 0xffffffffffULL));
}
inline bool operator<(const uint64_t& a) const
{
return (_a < (a & 0xffffffffffULL));
}
inline bool operator>=(const uint64_t& a) const
{
return (_a >= (a & 0xffffffffffULL));
}
inline bool operator<=(const uint64_t& a) const
{
return (_a <= (a & 0xffffffffffULL));
}
inline bool operator==(const Address &a) const { return (_a == a._a); } inline bool operator==(const Address& a) const
inline bool operator!=(const Address &a) const { return (_a != a._a); } {
inline bool operator>(const Address &a) const { return (_a > a._a); } return (_a == a._a);
inline bool operator<(const Address &a) const { return (_a < a._a); } }
inline bool operator>=(const Address &a) const { return (_a >= a._a); } inline bool operator!=(const Address& a) const
inline bool operator<=(const Address &a) const { return (_a <= a._a); } {
return (_a != a._a);
}
inline bool operator>(const Address& a) const
{
return (_a > a._a);
}
inline bool operator<(const Address& a) const
{
return (_a < a._a);
}
inline bool operator>=(const Address& a) const
{
return (_a >= a._a);
}
inline bool operator<=(const Address& a) const
{
return (_a <= a._a);
}
private: private:
uint64_t _a; uint64_t _a;
}; };

View file

@ -25,15 +25,17 @@ namespace ZeroTier {
/** /**
* Simple atomic counter supporting increment and decrement * Simple atomic counter supporting increment and decrement
*/ */
class AtomicCounter class AtomicCounter {
{ public:
public: AtomicCounter()
AtomicCounter() { _v = 0; } {
_v = 0;
}
inline int load() const inline int load() const
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_or_and_fetch(const_cast<int *>(&_v),0); return __sync_or_and_fetch(const_cast<int*>(&_v), 0);
#else #else
return _v.load(); return _v.load();
#endif #endif
@ -42,7 +44,7 @@ public:
inline int operator++() inline int operator++()
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_add_and_fetch(&_v,1); return __sync_add_and_fetch(&_v, 1);
#else #else
return ++_v; return ++_v;
#endif #endif
@ -51,15 +53,20 @@ public:
inline int operator--() inline int operator--()
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __sync_sub_and_fetch(&_v,1); return __sync_sub_and_fetch(&_v, 1);
#else #else
return --_v; return --_v;
#endif #endif
} }
private: private:
AtomicCounter(const AtomicCounter &) {} AtomicCounter(const AtomicCounter&)
const AtomicCounter &operator=(const AtomicCounter &) { return *this; } {
}
const AtomicCounter& operator=(const AtomicCounter&)
{
return *this;
}
#ifdef __GNUC__ #ifdef __GNUC__
int _v; int _v;

View file

@ -373,7 +373,7 @@ SharedPtr<Path> Bond::getAppropriatePath(int64_t now, int32_t flowId)
*/ */
if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) {
if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && _paths[_abPathIdx].p) { if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && _paths[_abPathIdx].p) {
//fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str()); // fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str());
return _paths[_abPathIdx].p; return _paths[_abPathIdx].p;
} }
} }
@ -1584,7 +1584,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
} }
} }
} }
if (!foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) { if (! foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) {
log("found non-preferred primary link (_abPathIdx=%d)", _abPathIdx); log("found non-preferred primary link (_abPathIdx=%d)", _abPathIdx);
_abPathIdx = nonPreferredPathIdx; _abPathIdx = nonPreferredPathIdx;
} }

View file

@ -1144,7 +1144,7 @@ class Bond {
__attribute__((format(printf, 2, 3))) __attribute__((format(printf, 2, 3)))
#endif #endif
{ {
//if (_peerId != 0x0 && _peerId != 0x0) { return; } // if (_peerId != 0x0 && _peerId != 0x0) { return; }
#ifdef ZT_TRACE #ifdef ZT_TRACE
time_t rawtime; time_t rawtime;
struct tm* timeinfo; struct tm* timeinfo;
@ -1176,7 +1176,7 @@ class Bond {
__attribute__((format(printf, 2, 3))) __attribute__((format(printf, 2, 3)))
#endif #endif
{ {
//if (_peerId != 0x0 && _peerId != 0x0) { return; } // if (_peerId != 0x0 && _peerId != 0x0) { return; }
#ifdef ZT_DEBUG #ifdef ZT_DEBUG
time_t rawtime; time_t rawtime;
struct tm* timeinfo; struct tm* timeinfo;

View file

@ -14,18 +14,17 @@
#ifndef ZT_BUFFER_HPP #ifndef ZT_BUFFER_HPP
#define ZT_BUFFER_HPP #define ZT_BUFFER_HPP
#include <string.h>
#include <stdint.h>
#include <stdexcept>
#include <string>
#include <algorithm>
#include <utility>
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING)) #include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <string.h>
#include <string>
#include <utility>
#if defined(__GNUC__) && (! defined(ZT_NO_TYPE_PUNNING))
#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__)) #define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
#else #else
#define ZT_VAR_MAY_ALIAS #define ZT_VAR_MAY_ALIAS
@ -46,36 +45,57 @@ namespace ZeroTier {
* *
* @tparam C Total capacity * @tparam C Total capacity
*/ */
template<unsigned int C> template <unsigned int C> class Buffer {
class Buffer
{
// I love me! // I love me!
template <unsigned int C2> friend class Buffer; template <unsigned int C2> friend class Buffer;
public: public:
// STL container idioms // STL container idioms
typedef unsigned char value_type; typedef unsigned char value_type;
typedef unsigned char * pointer; typedef unsigned char* pointer;
typedef const char * const_pointer; typedef const char* const_pointer;
typedef char & reference; typedef char& reference;
typedef const char & const_reference; typedef const char& const_reference;
typedef char * iterator; typedef char* iterator;
typedef const char * const_iterator; typedef const char* const_iterator;
typedef unsigned int size_type; typedef unsigned int size_type;
typedef int difference_type; typedef int difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
inline iterator begin() { return _b; } inline iterator begin()
inline iterator end() { return (_b + _l); } {
inline const_iterator begin() const { return _b; } return _b;
inline const_iterator end() const { return (_b + _l); } }
inline reverse_iterator rbegin() { return reverse_iterator(begin()); } inline iterator end()
inline reverse_iterator rend() { return reverse_iterator(end()); } {
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } return (_b + _l);
inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); } }
inline const_iterator begin() const
{
return _b;
}
inline const_iterator end() const
{
return (_b + _l);
}
inline reverse_iterator rbegin()
{
return reverse_iterator(begin());
}
inline reverse_iterator rend()
{
return reverse_iterator(end());
}
inline const_reverse_iterator rbegin() const
{
return const_reverse_iterator(begin());
}
inline const_reverse_iterator rend() const
{
return const_reverse_iterator(end());
}
Buffer() : Buffer() : _l(0)
_l(0)
{ {
} }
@ -87,37 +107,36 @@ public:
_l = l; _l = l;
} }
template<unsigned int C2> template <unsigned int C2> Buffer(const Buffer<C2>& b)
Buffer(const Buffer<C2> &b)
{ {
*this = b; *this = b;
} }
Buffer(const void *b,unsigned int l) Buffer(const void* b, unsigned int l)
{ {
copyFrom(b,l); copyFrom(b, l);
} }
template<unsigned int C2> template <unsigned int C2> inline Buffer& operator=(const Buffer<C2>& b)
inline Buffer &operator=(const Buffer<C2> &b)
{ {
if (unlikely(b._l > C)) { if (unlikely(b._l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
if (C2 == C) { if (C2 == C) {
memcpy(this,&b,sizeof(Buffer<C>)); memcpy(this, &b, sizeof(Buffer<C>));
} else { }
memcpy(_b,b._b,_l = b._l); else {
memcpy(_b, b._b, _l = b._l);
} }
return *this; return *this;
} }
inline void copyFrom(const void *b,unsigned int l) inline void copyFrom(const void* b, unsigned int l)
{ {
if (unlikely(l > C)) { if (unlikely(l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
memcpy(_b,b,l); memcpy(_b, b, l);
_l = l; _l = l;
} }
@ -129,12 +148,12 @@ public:
return (unsigned char)_b[i]; return (unsigned char)_b[i];
} }
unsigned char &operator[](const unsigned int i) unsigned char& operator[](const unsigned int i)
{ {
if (unlikely(i >= _l)) { if (unlikely(i >= _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
return ((unsigned char *)_b)[i]; return ((unsigned char*)_b)[i];
} }
/** /**
@ -150,19 +169,19 @@ public:
* @return Pointer to field data * @return Pointer to field data
* @throws std::out_of_range Field extends beyond data size * @throws std::out_of_range Field extends beyond data size
*/ */
unsigned char *field(unsigned int i,unsigned int l) unsigned char* field(unsigned int i, unsigned int l)
{ {
if (unlikely((i + l) > _l)) { if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
return (unsigned char *)(_b + i); return (unsigned char*)(_b + i);
} }
const unsigned char *field(unsigned int i,unsigned int l) const const unsigned char* field(unsigned int i, unsigned int l) const
{ {
if (unlikely((i + l) > _l)) { if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
return (const unsigned char *)(_b + i); return (const unsigned char*)(_b + i);
} }
/** /**
@ -172,19 +191,18 @@ public:
* @param v Value * @param v Value
* @tparam T Integer type (e.g. uint16_t, int64_t) * @tparam T Integer type (e.g. uint16_t, int64_t)
*/ */
template<typename T> template <typename T> inline void setAt(unsigned int i, const T v)
inline void setAt(unsigned int i,const T v)
{ {
if (unlikely((i + sizeof(T)) > _l)) { if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i); uint8_t* p = reinterpret_cast<uint8_t*>(_b + i);
for(unsigned int x=1;x<=sizeof(T);++x) { for (unsigned int x = 1; x <= sizeof(T); ++x) {
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
} }
#else #else
T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + i); T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + i);
*p = Utils::hton(v); *p = Utils::hton(v);
#endif #endif
} }
@ -196,22 +214,21 @@ public:
* @tparam T Integer type (e.g. uint16_t, int64_t) * @tparam T Integer type (e.g. uint16_t, int64_t)
* @return Integer value * @return Integer value
*/ */
template<typename T> template <typename T> inline T at(unsigned int i) const
inline T at(unsigned int i) const
{ {
if (unlikely((i + sizeof(T)) > _l)) { if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
T v = 0; T v = 0;
const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i); const uint8_t* p = reinterpret_cast<const uint8_t*>(_b + i);
for(unsigned int x=0;x<sizeof(T);++x) { for (unsigned int x = 0; x < sizeof(T); ++x) {
v <<= 8; v <<= 8;
v |= (T)*(p++); v |= (T) * (p++);
} }
return v; return v;
#else #else
const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i); const T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T*>(_b + i);
return Utils::ntoh(*p); return Utils::ntoh(*p);
#endif #endif
} }
@ -223,19 +240,18 @@ public:
* @tparam T Integer type (e.g. uint16_t, int64_t) * @tparam T Integer type (e.g. uint16_t, int64_t)
* @throws std::out_of_range Attempt to append beyond capacity * @throws std::out_of_range Attempt to append beyond capacity
*/ */
template<typename T> template <typename T> inline void append(const T v)
inline void append(const T v)
{ {
if (unlikely((_l + sizeof(T)) > C)) { if (unlikely((_l + sizeof(T)) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l); uint8_t* p = reinterpret_cast<uint8_t*>(_b + _l);
for(unsigned int x=1;x<=sizeof(T);++x) { for (unsigned int x = 1; x <= sizeof(T); ++x) {
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
} }
#else #else
T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + _l); T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + _l);
*p = Utils::hton(v); *p = Utils::hton(v);
#endif #endif
_l += sizeof(T); _l += sizeof(T);
@ -248,12 +264,12 @@ public:
* @param n Number of times to append * @param n Number of times to append
* @throws std::out_of_range Attempt to append beyond capacity * @throws std::out_of_range Attempt to append beyond capacity
*/ */
inline void append(unsigned char c,unsigned int n) inline void append(unsigned char c, unsigned int n)
{ {
if (unlikely((_l + n) > C)) { if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
for(unsigned int i=0;i<n;++i) { for (unsigned int i = 0; i < n; ++i) {
_b[_l++] = (char)c; _b[_l++] = (char)c;
} }
} }
@ -268,7 +284,7 @@ public:
if (unlikely((_l + n) > C)) { if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
Utils::getSecureRandom(_b + _l,n); Utils::getSecureRandom(_b + _l, n);
_l += n; _l += n;
} }
@ -279,12 +295,12 @@ public:
* @param l Length * @param l Length
* @throws std::out_of_range Attempt to append beyond capacity * @throws std::out_of_range Attempt to append beyond capacity
*/ */
inline void append(const void *b,unsigned int l) inline void append(const void* b, unsigned int l)
{ {
if (unlikely((_l + l) > C)) { if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
memcpy(_b + _l,b,l); memcpy(_b + _l, b, l);
_l += l; _l += l;
} }
@ -294,13 +310,13 @@ public:
* @param s C string * @param s C string
* @throws std::out_of_range Attempt to append beyond capacity * @throws std::out_of_range Attempt to append beyond capacity
*/ */
inline void appendCString(const char *s) inline void appendCString(const char* s)
{ {
for(;;) { for (;;) {
if (unlikely(_l >= C)) { if (unlikely(_l >= C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
if (!(_b[_l++] = *(s++))) { if (! (_b[_l++] = *(s++))) {
break; break;
} }
} }
@ -313,10 +329,9 @@ public:
* @tparam C2 Capacity of second buffer (typically inferred) * @tparam C2 Capacity of second buffer (typically inferred)
* @throws std::out_of_range Attempt to append beyond capacity * @throws std::out_of_range Attempt to append beyond capacity
*/ */
template<unsigned int C2> template <unsigned int C2> inline void append(const Buffer<C2>& b)
inline void append(const Buffer<C2> &b)
{ {
append(b._b,b._l); append(b._b, b._l);
} }
/** /**
@ -329,12 +344,12 @@ public:
* @param l Length of field to append * @param l Length of field to append
* @return Pointer to beginning of appended field of length 'l' * @return Pointer to beginning of appended field of length 'l'
*/ */
inline char *appendField(unsigned int l) inline char* appendField(unsigned int l)
{ {
if (unlikely((_l + l) > C)) { if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
char *r = _b + _l; char* r = _b + _l;
_l += l; _l += l;
return r; return r;
} }
@ -379,13 +394,13 @@ public:
*/ */
inline void behead(const unsigned int at) inline void behead(const unsigned int at)
{ {
if (!at) { if (! at) {
return; return;
} }
if (unlikely(at > _l)) { if (unlikely(at > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
::memmove(_b,_b + at,_l -= at); ::memmove(_b, _b + at, _l -= at);
} }
/** /**
@ -395,88 +410,106 @@ public:
* @param length Length of block to erase * @param length Length of block to erase
* @throws std::out_of_range Position plus length is beyond size of buffer * @throws std::out_of_range Position plus length is beyond size of buffer
*/ */
inline void erase(const unsigned int at,const unsigned int length) inline void erase(const unsigned int at, const unsigned int length)
{ {
const unsigned int endr = at + length; const unsigned int endr = at + length;
if (unlikely(endr > _l)) { if (unlikely(endr > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
} }
::memmove(_b + at,_b + endr,_l - endr); ::memmove(_b + at, _b + endr, _l - endr);
_l -= length; _l -= length;
} }
/** /**
* Set buffer data length to zero * Set buffer data length to zero
*/ */
inline void clear() { _l = 0; } inline void clear()
{
_l = 0;
}
/** /**
* Zero buffer up to size() * Zero buffer up to size()
*/ */
inline void zero() { memset(_b,0,_l); } inline void zero()
{
memset(_b, 0, _l);
}
/** /**
* Zero unused capacity area * Zero unused capacity area
*/ */
inline void zeroUnused() { memset(_b + _l,0,C - _l); } inline void zeroUnused()
{
memset(_b + _l, 0, C - _l);
}
/** /**
* Unconditionally and securely zero buffer's underlying memory * Unconditionally and securely zero buffer's underlying memory
*/ */
inline void burn() { Utils::burn(_b,sizeof(_b)); } inline void burn()
{
Utils::burn(_b, sizeof(_b));
}
/** /**
* @return Constant pointer to data in buffer * @return Constant pointer to data in buffer
*/ */
inline const void *data() const { return _b; } inline const void* data() const
{
return _b;
}
/** /**
* @return Non-constant pointer to data in buffer * @return Non-constant pointer to data in buffer
*/ */
inline void *unsafeData() { return _b; } inline void* unsafeData()
{
return _b;
}
/** /**
* @return Size of data in buffer * @return Size of data in buffer
*/ */
inline unsigned int size() const { return _l; } inline unsigned int size() const
{
return _l;
}
/** /**
* @return Capacity of buffer * @return Capacity of buffer
*/ */
inline unsigned int capacity() const { return C; } inline unsigned int capacity() const
{
return C;
}
template<unsigned int C2> template <unsigned int C2> inline bool operator==(const Buffer<C2>& b) const
inline bool operator==(const Buffer<C2> &b) const
{ {
return ((_l == b._l)&&(!memcmp(_b,b._b,_l))); return ((_l == b._l) && (! memcmp(_b, b._b, _l)));
} }
template<unsigned int C2> template <unsigned int C2> inline bool operator!=(const Buffer<C2>& b) const
inline bool operator!=(const Buffer<C2> &b) const
{ {
return ((_l != b._l)||(memcmp(_b,b._b,_l))); return ((_l != b._l) || (memcmp(_b, b._b, _l)));
} }
template<unsigned int C2> template <unsigned int C2> inline bool operator<(const Buffer<C2>& b) const
inline bool operator<(const Buffer<C2> &b) const
{ {
return (memcmp(_b,b._b,std::min(_l,b._l)) < 0); return (memcmp(_b, b._b, std::min(_l, b._l)) < 0);
} }
template<unsigned int C2> template <unsigned int C2> inline bool operator>(const Buffer<C2>& b) const
inline bool operator>(const Buffer<C2> &b) const
{ {
return (b < *this); return (b < *this);
} }
template<unsigned int C2> template <unsigned int C2> inline bool operator<=(const Buffer<C2>& b) const
inline bool operator<=(const Buffer<C2> &b) const
{ {
return !(b < *this); return ! (b < *this);
} }
template<unsigned int C2> template <unsigned int C2> inline bool operator>=(const Buffer<C2>& b) const
inline bool operator>=(const Buffer<C2> &b) const
{ {
return !(*this < b); return ! (*this < b);
} }
private: private:
char ZT_VAR_MAY_ALIAS _b[C]; char ZT_VAR_MAY_ALIAS _b[C];
unsigned int _l; unsigned int _l;
}; };

View file

@ -12,53 +12,59 @@
/****/ /****/
#include "Capability.hpp" #include "Capability.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier { namespace ZeroTier {
int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const int Capability::verify(const RuntimeEnvironment* RR, void* tPtr) const
{ {
try { try {
// There must be at least one entry, and sanity check for bad chain max length // There must be at least one entry, and sanity check for bad chain max length
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { if ((_maxCustodyChainLength < 1) || (_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
return -1; return -1;
} }
// Validate all entries in chain of custody // Validate all entries in chain of custody
Buffer<(sizeof(Capability) * 2)> tmp; Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true); this->serialize(tmp, true);
for(unsigned int c=0;c<_maxCustodyChainLength;++c) { for (unsigned int c = 0; c < _maxCustodyChainLength; ++c) {
if (c == 0) { if (c == 0) {
if ((!_custody[c].to)||(!_custody[c].from)||(_custody[c].from != Network::controllerFor(_nwid))) { if ((! _custody[c].to) || (! _custody[c].from) || (_custody[c].from != Network::controllerFor(_nwid))) {
return -1; // the first entry must be present and from the network's controller return -1; // the first entry must be present and from the network's controller
} }
} else { }
if (!_custody[c].to) { else {
if (! _custody[c].to) {
return 0; // all previous entries were valid, so we are valid return 0; // all previous entries were valid, so we are valid
} else if ((!_custody[c].from)||(_custody[c].from != _custody[c-1].to)) { }
else if ((! _custody[c].from) || (_custody[c].from != _custody[c - 1].to)) {
return -1; // otherwise if we have another entry it must be from the previous holder in the chain return -1; // otherwise if we have another entry it must be from the previous holder in the chain
} }
} }
const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from)); const Identity id(RR->topology->getIdentity(tPtr, _custody[c].from));
if (id) { if (id) {
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) { if (! id.verify(tmp.data(), tmp.size(), _custody[c].signature)) {
return -1; return -1;
} }
} else { }
RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from); else {
RR->sw->requestWhois(tPtr, RR->node->now(), _custody[c].from);
return 1; return 1;
} }
} }
// We reached max custody chain length and everything was valid // We reached max custody chain length and everything was valid
return 0; return 0;
} catch ( ... ) {} }
catch (...) {
}
return -1; return -1;
} }

View file

@ -14,19 +14,19 @@
#ifndef ZT_CAPABILITY_HPP #ifndef ZT_CAPABILITY_HPP
#define ZT_CAPABILITY_HPP #define ZT_CAPABILITY_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "ECC.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "Address.hpp"
#include "ECC.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp"
#include "../include/ZeroTierOne.h"
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
@ -54,20 +54,17 @@ class RuntimeEnvironment;
* handed off between nodes. Limited transferability of capabilities is * handed off between nodes. Limited transferability of capabilities is
* a feature of true capability based security. * a feature of true capability based security.
*/ */
class Capability : public Credential class Capability : public Credential {
{ public:
public: static inline Credential::Type credentialType()
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; }
Capability() :
_nwid(0),
_ts(0),
_id(0),
_maxCustodyChainLength(0),
_ruleCount(0)
{ {
memset(_rules,0,sizeof(_rules)); return Credential::CREDENTIAL_TYPE_CAPABILITY;
memset(_custody,0,sizeof(_custody)); }
Capability() : _nwid(0), _ts(0), _id(0), _maxCustodyChainLength(0), _ruleCount(0)
{
memset(_rules, 0, sizeof(_rules));
memset(_custody, 0, sizeof(_custody));
} }
/** /**
@ -78,42 +75,57 @@ public:
* @param rules Network flow rules for this capability * @param rules Network flow rules for this capability
* @param ruleCount Number of flow rules * @param ruleCount Number of flow rules
*/ */
Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) : Capability(uint32_t id, uint64_t nwid, int64_t ts, unsigned int mccl, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount)
_nwid(nwid), : _nwid(nwid)
_ts(ts), , _ts(ts)
_id(id), , _id(id)
_maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1), , _maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1)
_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES) , _ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
{ {
if (_ruleCount > 0) { if (_ruleCount > 0) {
memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount); memcpy(_rules, rules, sizeof(ZT_VirtualNetworkRule) * _ruleCount);
} }
} }
/** /**
* @return Rules -- see ruleCount() for size of array * @return Rules -- see ruleCount() for size of array
*/ */
inline const ZT_VirtualNetworkRule *rules() const { return _rules; } inline const ZT_VirtualNetworkRule* rules() const
{
return _rules;
}
/** /**
* @return Number of rules in rules() * @return Number of rules in rules()
*/ */
inline unsigned int ruleCount() const { return _ruleCount; } inline unsigned int ruleCount() const
{
return _ruleCount;
}
/** /**
* @return ID and evaluation order of this capability in network * @return ID and evaluation order of this capability in network
*/ */
inline uint32_t id() const { return _id; } inline uint32_t id() const
{
return _id;
}
/** /**
* @return Network ID for which this capability was issued * @return Network ID for which this capability was issued
*/ */
inline uint64_t networkId() const { return _nwid; } inline uint64_t networkId() const
{
return _nwid;
}
/** /**
* @return Timestamp * @return Timestamp
*/ */
inline int64_t timestamp() const { return _ts; } inline int64_t timestamp() const
{
return _ts;
}
/** /**
* @return Last 'to' address in chain of custody * @return Last 'to' address in chain of custody
@ -121,10 +133,11 @@ public:
inline Address issuedTo() const inline Address issuedTo() const
{ {
Address i2; Address i2;
for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) { for (unsigned int i = 0; i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH; ++i) {
if (!_custody[i].to) { if (! _custody[i].to) {
return i2; return i2;
} else { }
else {
i2 = _custody[i].to; i2 = _custody[i].to;
} }
} }
@ -144,20 +157,22 @@ public:
* @param to Recipient of this signature * @param to Recipient of this signature
* @return True if signature successful and chain of custody appended * @return True if signature successful and chain of custody appended
*/ */
inline bool sign(const Identity &from,const Address &to) inline bool sign(const Identity& from, const Address& to)
{ {
try { try {
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) { for (unsigned int i = 0; ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)); ++i) {
if (!(_custody[i].to)) { if (! (_custody[i].to)) {
Buffer<(sizeof(Capability) * 2)> tmp; Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true); this->serialize(tmp, true);
_custody[i].to = to; _custody[i].to = to;
_custody[i].from = from.address(); _custody[i].from = from.address();
_custody[i].signature = from.sign(tmp.data(),tmp.size()); _custody[i].signature = from.sign(tmp.data(), tmp.size());
return true; return true;
} }
} }
} catch ( ... ) {} }
catch (...) {
}
return false; return false;
} }
@ -167,17 +182,16 @@ public:
* @param RR Runtime environment to provide for peer lookup, etc. * @param RR Runtime environment to provide for peer lookup, etc.
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
*/ */
int verify(const RuntimeEnvironment *RR,void *tPtr) const; int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C> template <unsigned int C> static inline void serializeRules(Buffer<C>& b, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount)
static inline void serializeRules(Buffer<C> &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
{ {
for(unsigned int i=0;i<ruleCount;++i) { for (unsigned int i = 0; i < ruleCount; ++i) {
// Each rule consists of its 8-bit type followed by the size of that type's // Each rule consists of its 8-bit type followed by the size of that type's
// field followed by field data. The inclusion of the size will allow non-supported // field followed by field data. The inclusion of the size will allow non-supported
// rules to be ignored but still parsed. // rules to be ignored but still parsed.
b.append((uint8_t)rules[i].t); b.append((uint8_t)rules[i].t);
switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) { switch ((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) {
default: default:
b.append((uint8_t)0); b.append((uint8_t)0);
break; break;
@ -209,18 +223,18 @@ public:
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
case ZT_NETWORK_RULE_MATCH_MAC_DEST: case ZT_NETWORK_RULE_MATCH_MAC_DEST:
b.append((uint8_t)6); b.append((uint8_t)6);
b.append(rules[i].v.mac,6); b.append(rules[i].v.mac, 6);
break; break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST: case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
b.append((uint8_t)5); b.append((uint8_t)5);
b.append(&(rules[i].v.ipv4.ip),4); b.append(&(rules[i].v.ipv4.ip), 4);
b.append((uint8_t)rules[i].v.ipv4.mask); b.append((uint8_t)rules[i].v.ipv4.mask);
break; break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV6_DEST: case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
b.append((uint8_t)17); b.append((uint8_t)17);
b.append(rules[i].v.ipv6.ip,16); b.append(rules[i].v.ipv6.ip, 16);
b.append((uint8_t)rules[i].v.ipv6.mask); b.append((uint8_t)rules[i].v.ipv6.mask);
break; break;
case ZT_NETWORK_RULE_MATCH_IP_TOS: case ZT_NETWORK_RULE_MATCH_IP_TOS:
@ -284,13 +298,12 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> static inline void deserializeRules(const Buffer<C>& b, unsigned int& p, ZT_VirtualNetworkRule* rules, unsigned int& ruleCount, const unsigned int maxRuleCount)
static inline void deserializeRules(const Buffer<C> &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount)
{ {
while ((ruleCount < maxRuleCount)&&(p < b.size())) { while ((ruleCount < maxRuleCount) && (p < b.size())) {
rules[ruleCount].t = (uint8_t)b[p++]; rules[ruleCount].t = (uint8_t)b[p++];
const unsigned int fieldLen = (unsigned int)b[p++]; const unsigned int fieldLen = (unsigned int)b[p++];
switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) { switch ((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) {
default: default:
break; break;
case ZT_NETWORK_RULE_ACTION_TEE: case ZT_NETWORK_RULE_ACTION_TEE:
@ -302,7 +315,7 @@ public:
break; break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
rules[ruleCount].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); rules[ruleCount].v.zt = Address(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH).toInt();
break; break;
case ZT_NETWORK_RULE_MATCH_VLAN_ID: case ZT_NETWORK_RULE_MATCH_VLAN_ID:
rules[ruleCount].v.vlanId = b.template at<uint16_t>(p); rules[ruleCount].v.vlanId = b.template at<uint16_t>(p);
@ -315,22 +328,22 @@ public:
break; break;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
case ZT_NETWORK_RULE_MATCH_MAC_DEST: case ZT_NETWORK_RULE_MATCH_MAC_DEST:
memcpy(rules[ruleCount].v.mac,b.field(p,6),6); memcpy(rules[ruleCount].v.mac, b.field(p, 6), 6);
break; break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST: case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4); memcpy(&(rules[ruleCount].v.ipv4.ip), b.field(p, 4), 4);
rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4]; rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4];
break; break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV6_DEST: case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
memcpy(rules[ruleCount].v.ipv6.ip,b.field(p,16),16); memcpy(rules[ruleCount].v.ipv6.ip, b.field(p, 16), 16);
rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16]; rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16];
break; break;
case ZT_NETWORK_RULE_MATCH_IP_TOS: case ZT_NETWORK_RULE_MATCH_IP_TOS:
rules[ruleCount].v.ipTos.mask = (uint8_t)b[p]; rules[ruleCount].v.ipTos.mask = (uint8_t)b[p];
rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p+1]; rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p + 1];
rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p+2]; rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p + 2];
break; break;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
rules[ruleCount].v.ipProtocol = (uint8_t)b[p]; rules[ruleCount].v.ipProtocol = (uint8_t)b[p];
@ -340,8 +353,8 @@ public:
break; break;
case ZT_NETWORK_RULE_MATCH_ICMP: case ZT_NETWORK_RULE_MATCH_ICMP:
rules[ruleCount].v.icmp.type = (uint8_t)b[p]; rules[ruleCount].v.icmp.type = (uint8_t)b[p];
rules[ruleCount].v.icmp.code = (uint8_t)b[p+1]; rules[ruleCount].v.icmp.code = (uint8_t)b[p + 1];
rules[ruleCount].v.icmp.flags = (uint8_t)b[p+2]; rules[ruleCount].v.icmp.flags = (uint8_t)b[p + 2];
break; break;
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
@ -380,8 +393,7 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{ {
if (forSign) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -393,19 +405,20 @@ public:
b.append(_id); b.append(_id);
b.append((uint16_t)_ruleCount); b.append((uint16_t)_ruleCount);
serializeRules(b,_rules,_ruleCount); serializeRules(b, _rules, _ruleCount);
b.append((uint8_t)_maxCustodyChainLength); b.append((uint8_t)_maxCustodyChainLength);
if (!forSign) { if (! forSign) {
for(unsigned int i=0;;++i) { for (unsigned int i = 0;; ++i) {
if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { if ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) && (_custody[i].to)) {
_custody[i].to.appendTo(b); _custody[i].to.appendTo(b);
_custody[i].from.appendTo(b); _custody[i].from.appendTo(b);
b.append((uint8_t)1); // 1 == Ed25519 signature b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature
b.append(_custody[i].signature.data,ZT_ECC_SIGNATURE_LEN); b.append(_custody[i].signature.data, ZT_ECC_SIGNATURE_LEN);
} else { }
b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain else {
b.append((unsigned char)0, ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
break; break;
} }
} }
@ -419,8 +432,7 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
*this = Capability(); *this = Capability();
@ -438,33 +450,34 @@ public:
if (rc > ZT_MAX_CAPABILITY_RULES) { if (rc > ZT_MAX_CAPABILITY_RULES) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
} }
deserializeRules(b,p,_rules,_ruleCount,rc); deserializeRules(b, p, _rules, _ruleCount, rc);
_maxCustodyChainLength = (unsigned int)b[p++]; _maxCustodyChainLength = (unsigned int)b[p++];
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { if ((_maxCustodyChainLength < 1) || (_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
} }
for(unsigned int i=0;;++i) { for (unsigned int i = 0;; ++i) {
const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); const Address to(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (!to) { if (! to) {
break; break;
} }
if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { if ((i >= _maxCustodyChainLength) || (i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
} }
_custody[i].to = to; _custody[i].to = to;
_custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _custody[i].from.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) { if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_ECC_SIGNATURE_LEN) { if (b.template at<uint16_t>(p) != ZT_ECC_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} }
p += 2; p += 2;
memcpy(_custody[i].signature.data,b.field(p,ZT_ECC_SIGNATURE_LEN),ZT_ECC_SIGNATURE_LEN); memcpy(_custody[i].signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN);
p += ZT_ECC_SIGNATURE_LEN; p += ZT_ECC_SIGNATURE_LEN;
} else { }
else {
p += 2 + b.template at<uint16_t>(p); p += 2 + b.template at<uint16_t>(p);
} }
} }
@ -478,12 +491,21 @@ public:
} }
// Provides natural sort order by ID // Provides natural sort order by ID
inline bool operator<(const Capability &c) const { return (_id < c._id); } inline bool operator<(const Capability& c) const
{
return (_id < c._id);
}
inline bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); } inline bool operator==(const Capability& c) const
inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); } {
return (memcmp(this, &c, sizeof(Capability)) == 0);
}
inline bool operator!=(const Capability& c) const
{
return (memcmp(this, &c, sizeof(Capability)) != 0);
}
private: private:
uint64_t _nwid; uint64_t _nwid;
int64_t _ts; int64_t _ts;
uint32_t _id; uint32_t _id;

View file

@ -12,16 +12,17 @@
/****/ /****/
#include "CertificateOfMembership.hpp" #include "CertificateOfMembership.hpp"
#include "ECC.hpp" #include "ECC.hpp"
#include "RuntimeEnvironment.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier { namespace ZeroTier {
CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo) CertificateOfMembership::CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo)
{ {
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP; _qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = timestamp; _qualifiers[0].value = timestamp;
@ -37,34 +38,34 @@ CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t tim
// using the original COM format. Format may be revised in the future to make this cleaner. // using the original COM format. Format may be revised in the future to make this cleaner.
uint64_t idHash[6]; uint64_t idHash[6];
issuedTo.publicKeyHash(idHash); issuedTo.publicKeyHash(idHash);
for(unsigned long i=0;i<4;++i) { for (unsigned long i = 0; i < 4; ++i) {
_qualifiers[i + 3].id = (uint64_t)(i + 3); _qualifiers[i + 3].id = (uint64_t)(i + 3);
_qualifiers[i + 3].value = Utils::ntoh(idHash[i]); _qualifiers[i + 3].value = Utils::ntoh(idHash[i]);
_qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL; _qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL;
} }
_qualifierCount = 7; _qualifierCount = 7;
memset(_signature.data,0,ZT_ECC_SIGNATURE_LEN); memset(_signature.data, 0, ZT_ECC_SIGNATURE_LEN);
} }
bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const bool CertificateOfMembership::agreesWith(const CertificateOfMembership& other, const Identity& otherIdentity) const
{ {
if ((_qualifierCount == 0)||(other._qualifierCount == 0)) { if ((_qualifierCount == 0) || (other._qualifierCount == 0)) {
return false; return false;
} }
std::map< uint64_t, uint64_t > otherFields; std::map<uint64_t, uint64_t> otherFields;
for(unsigned int i=0;i<other._qualifierCount;++i) { for (unsigned int i = 0; i < other._qualifierCount; ++i) {
otherFields[other._qualifiers[i].id] = other._qualifiers[i].value; otherFields[other._qualifiers[i].id] = other._qualifiers[i].value;
} }
bool fullIdentityVerification = false; bool fullIdentityVerification = false;
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
const uint64_t qid = _qualifiers[i].id; const uint64_t qid = _qualifiers[i].id;
if ((qid >= 3)&&(qid <= 6)) { if ((qid >= 3) && (qid <= 6)) {
fullIdentityVerification = true; fullIdentityVerification = true;
} }
std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find(qid)); std::map<uint64_t, uint64_t>::iterator otherQ(otherFields.find(qid));
if (otherQ == otherFields.end()) { if (otherQ == otherFields.end()) {
return false; return false;
} }
@ -80,8 +81,8 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
if (fullIdentityVerification) { if (fullIdentityVerification) {
uint64_t idHash[6]; uint64_t idHash[6];
otherIdentity.publicKeyHash(idHash); otherIdentity.publicKeyHash(idHash);
for(unsigned long i=0;i<4;++i) { for (unsigned long i = 0; i < 4; ++i) {
std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find((uint64_t)(i + 3))); std::map<uint64_t, uint64_t>::iterator otherQ(otherFields.find((uint64_t)(i + 3)));
if (otherQ == otherFields.end()) { if (otherQ == otherFields.end()) {
return false; return false;
} }
@ -94,46 +95,47 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
return true; return true;
} }
bool CertificateOfMembership::sign(const Identity &with) bool CertificateOfMembership::sign(const Identity& with)
{ {
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0; unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
buf[ptr++] = Utils::hton(_qualifiers[i].id); buf[ptr++] = Utils::hton(_qualifiers[i].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value); buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
} }
try { try {
_signature = with.sign(buf,ptr * sizeof(uint64_t)); _signature = with.sign(buf, ptr * sizeof(uint64_t));
_signedBy = with.address(); _signedBy = with.address();
return true; return true;
} catch ( ... ) { }
catch (...) {
_signedBy.zero(); _signedBy.zero();
return false; return false;
} }
} }
int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const int CertificateOfMembership::verify(const RuntimeEnvironment* RR, void* tPtr) const
{ {
if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) { if ((! _signedBy) || (_signedBy != Network::controllerFor(networkId())) || (_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) {
return -1; return -1;
} }
const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (!id) { if (! id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1; return 1;
} }
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0; unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
buf[ptr++] = Utils::hton(_qualifiers[i].id); buf[ptr++] = Utils::hton(_qualifiers[i].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value); buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
} }
return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1); return (id.verify(buf, ptr * sizeof(uint64_t), _signature) ? 0 : -1);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,21 +14,20 @@
#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
#define ZT_CERTIFICATEOFMEMBERSHIP_HPP #define ZT_CERTIFICATEOFMEMBERSHIP_HPP
#include <stdint.h> #include "Address.hpp"
#include <string.h> #include "Buffer.hpp"
#include <string>
#include <stdexcept>
#include <algorithm>
#include "Constants.hpp" #include "Constants.hpp"
#include "Credential.hpp" #include "Credential.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include "ECC.hpp" #include "ECC.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <string.h>
#include <string>
/** /**
* Maximum number of qualifiers allowed in a COM (absolute max: 65535) * Maximum number of qualifiers allowed in a COM (absolute max: 65535)
*/ */
@ -64,10 +63,12 @@ class RuntimeEnvironment;
* This is a memcpy()'able structure and is safe (in a crash sense) to modify * This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks. * without locks.
*/ */
class CertificateOfMembership : public Credential class CertificateOfMembership : public Credential {
{ public:
public: static inline Credential::Type credentialType()
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; } {
return Credential::CREDENTIAL_TYPE_COM;
}
/** /**
* Reserved qualifier IDs * Reserved qualifier IDs
@ -78,8 +79,7 @@ public:
* Addition of new required fields requires that code in hasRequiredFields * Addition of new required fields requires that code in hasRequiredFields
* be updated as well. * be updated as well.
*/ */
enum ReservedId enum ReservedId {
{
/** /**
* Timestamp of certificate * Timestamp of certificate
*/ */
@ -101,8 +101,9 @@ public:
/** /**
* Create an empty certificate of membership * Create an empty certificate of membership
*/ */
CertificateOfMembership() : CertificateOfMembership() : _qualifierCount(0)
_qualifierCount(0) {} {
}
/** /**
* Create from required fields common to all networks * Create from required fields common to all networks
@ -112,7 +113,7 @@ public:
* @param nwid Network ID * @param nwid Network ID
* @param issuedTo Certificate recipient * @param issuedTo Certificate recipient
*/ */
CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo); CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo);
/** /**
* Create from binary-serialized COM in buffer * Create from binary-serialized COM in buffer
@ -120,28 +121,33 @@ public:
* @param b Buffer to deserialize from * @param b Buffer to deserialize from
* @param startAt Position to start in buffer * @param startAt Position to start in buffer
*/ */
template<unsigned int C> template <unsigned int C> CertificateOfMembership(const Buffer<C>& b, unsigned int startAt = 0)
CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0)
{ {
deserialize(b,startAt); deserialize(b, startAt);
} }
/** /**
* @return True if there's something here * @return True if there's something here
*/ */
inline operator bool() const { return (_qualifierCount != 0); } inline operator bool() const
{
return (_qualifierCount != 0);
}
/** /**
* @return Credential ID, always 0 for COMs * @return Credential ID, always 0 for COMs
*/ */
inline uint32_t id() const { return 0; } inline uint32_t id() const
{
return 0;
}
/** /**
* @return Timestamp for this cert and maximum delta for timestamp * @return Timestamp for this cert and maximum delta for timestamp
*/ */
inline int64_t timestamp() const inline int64_t timestamp() const
{ {
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) { if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) {
return _qualifiers[i].value; return _qualifiers[i].value;
} }
@ -154,7 +160,7 @@ public:
*/ */
inline Address issuedTo() const inline Address issuedTo() const
{ {
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) { if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) {
return Address(_qualifiers[i].value); return Address(_qualifiers[i].value);
} }
@ -167,7 +173,7 @@ public:
*/ */
inline uint64_t networkId() const inline uint64_t networkId() const
{ {
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) { if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) {
return _qualifiers[i].value; return _qualifiers[i].value;
} }
@ -189,7 +195,7 @@ public:
* @param otherIdentity Identity of other node * @param otherIdentity Identity of other node
* @return True if certs agree and 'other' may be communicated with * @return True if certs agree and 'other' may be communicated with
*/ */
bool agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const; bool agreesWith(const CertificateOfMembership& other, const Identity& otherIdentity) const;
/** /**
* Sign this certificate * Sign this certificate
@ -197,7 +203,7 @@ public:
* @param with Identity to sign with, must include private key * @param with Identity to sign with, must include private key
* @return True if signature was successful * @return True if signature was successful
*/ */
bool sign(const Identity &with); bool sign(const Identity& with);
/** /**
* Verify this COM and its signature * Verify this COM and its signature
@ -206,36 +212,40 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
*/ */
int verify(const RuntimeEnvironment *RR,void *tPtr) const; int verify(const RuntimeEnvironment* RR, void* tPtr) const;
/** /**
* @return True if signed * @return True if signed
*/ */
inline bool isSigned() const { return (_signedBy); } inline bool isSigned() const
{
return (_signedBy);
}
/** /**
* @return Address that signed this certificate or null address if none * @return Address that signed this certificate or null address if none
*/ */
inline const Address &signedBy() const { return _signedBy; } inline const Address& signedBy() const
{
return _signedBy;
}
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b) const
inline void serialize(Buffer<C> &b) const
{ {
b.append((uint8_t)1); b.append((uint8_t)1);
b.append((uint16_t)_qualifierCount); b.append((uint16_t)_qualifierCount);
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
b.append(_qualifiers[i].id); b.append(_qualifiers[i].id);
b.append(_qualifiers[i].value); b.append(_qualifiers[i].value);
b.append(_qualifiers[i].maxDelta); b.append(_qualifiers[i].maxDelta);
} }
_signedBy.appendTo(b); _signedBy.appendTo(b);
if (_signedBy) { if (_signedBy) {
b.append(_signature.data,ZT_ECC_SIGNATURE_LEN); b.append(_signature.data, ZT_ECC_SIGNATURE_LEN);
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
unsigned int p = startAt; unsigned int p = startAt;
@ -249,11 +259,12 @@ public:
unsigned int numq = b.template at<uint16_t>(p); unsigned int numq = b.template at<uint16_t>(p);
p += sizeof(uint16_t); p += sizeof(uint16_t);
uint64_t lastId = 0; uint64_t lastId = 0;
for(unsigned int i=0;i<numq;++i) { for (unsigned int i = 0; i < numq; ++i) {
const uint64_t qid = b.template at<uint64_t>(p); const uint64_t qid = b.template at<uint64_t>(p);
if (qid < lastId) { if (qid < lastId) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
} else { }
else {
lastId = qid; lastId = qid;
} }
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
@ -262,23 +273,24 @@ public:
_qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16); _qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16);
p += 24; p += 24;
++_qualifierCount; ++_qualifierCount;
} else { }
else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
} }
} }
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (_signedBy) { if (_signedBy) {
memcpy(_signature.data,b.field(p,ZT_ECC_SIGNATURE_LEN),ZT_ECC_SIGNATURE_LEN); memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN);
p += ZT_ECC_SIGNATURE_LEN; p += ZT_ECC_SIGNATURE_LEN;
} }
return (p - startAt); return (p - startAt);
} }
inline bool operator==(const CertificateOfMembership &c) const inline bool operator==(const CertificateOfMembership& c) const
{ {
if (_signedBy != c._signedBy) { if (_signedBy != c._signedBy) {
return false; return false;
@ -286,25 +298,32 @@ public:
if (_qualifierCount != c._qualifierCount) { if (_qualifierCount != c._qualifierCount) {
return false; return false;
} }
for(unsigned int i=0;i<_qualifierCount;++i) { for (unsigned int i = 0; i < _qualifierCount; ++i) {
const _Qualifier &a = _qualifiers[i]; const _Qualifier& a = _qualifiers[i];
const _Qualifier &b = c._qualifiers[i]; const _Qualifier& b = c._qualifiers[i];
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta)) { if ((a.id != b.id) || (a.value != b.value) || (a.maxDelta != b.maxDelta)) {
return false; return false;
} }
} }
return (memcmp(_signature.data,c._signature.data,ZT_ECC_SIGNATURE_LEN) == 0); return (memcmp(_signature.data, c._signature.data, ZT_ECC_SIGNATURE_LEN) == 0);
} }
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); } inline bool operator!=(const CertificateOfMembership& c) const
private:
struct _Qualifier
{ {
_Qualifier() : id(0),value(0),maxDelta(0) {} return (! (*this == c));
}
private:
struct _Qualifier {
_Qualifier() : id(0), value(0), maxDelta(0)
{
}
uint64_t id; uint64_t id;
uint64_t value; uint64_t value;
uint64_t maxDelta; uint64_t maxDelta;
inline bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order inline bool operator<(const _Qualifier& q) const
{
return (id < q.id);
} // sort order
}; };
Address _signedBy; Address _signedBy;

View file

@ -12,41 +12,43 @@
/****/ /****/
#include "CertificateOfOwnership.hpp" #include "CertificateOfOwnership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier { namespace ZeroTier {
int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const int CertificateOfOwnership::verify(const RuntimeEnvironment* RR, void* tPtr) const
{ {
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) { if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) {
return -1; return -1;
} }
const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (!id) { if (! id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1; return 1;
} }
try { try {
Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp; Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp;
this->serialize(tmp,true); this->serialize(tmp, true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
} catch ( ... ) { }
catch (...) {
return -1; return -1;
} }
} }
bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing& t, const void* v, unsigned int l) const
{ {
for(unsigned int i=0,j=_thingCount;i<j;++i) { for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
if (_thingTypes[i] == (uint8_t)t) { if (_thingTypes[i] == (uint8_t)t) {
unsigned int k = 0; unsigned int k = 0;
while (k < l) { while (k < l) {
if (reinterpret_cast<const uint8_t *>(v)[k] != _thingValues[i][k]) { if (reinterpret_cast<const uint8_t*>(v)[k] != _thingValues[i][k]) {
break; break;
} }
++k; ++k;

View file

@ -14,20 +14,20 @@
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
#define ZT_CERTIFICATEOFOWNERSHIP_HPP #define ZT_CERTIFICATEOFOWNERSHIP_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "ECC.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "ECC.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
// Max things per CertificateOfOwnership // Max things per CertificateOfOwnership
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16 #define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16
@ -41,84 +41,102 @@ class RuntimeEnvironment;
/** /**
* Certificate indicating ownership of a network identifier * Certificate indicating ownership of a network identifier
*/ */
class CertificateOfOwnership : public Credential class CertificateOfOwnership : public Credential {
{ public:
public: static inline Credential::Type credentialType()
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
enum Thing
{ {
THING_NULL = 0, return Credential::CREDENTIAL_TYPE_COO;
THING_MAC_ADDRESS = 1, }
THING_IPV4_ADDRESS = 2,
THING_IPV6_ADDRESS = 3 enum Thing { THING_NULL = 0, THING_MAC_ADDRESS = 1, THING_IPV4_ADDRESS = 2, THING_IPV6_ADDRESS = 3 };
};
CertificateOfOwnership() CertificateOfOwnership()
{ {
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership)); memset(reinterpret_cast<void*>(this), 0, sizeof(CertificateOfOwnership));
} }
CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id) CertificateOfOwnership(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id)
{ {
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership)); memset(reinterpret_cast<void*>(this), 0, sizeof(CertificateOfOwnership));
_networkId = nwid; _networkId = nwid;
_ts = ts; _ts = ts;
_id = id; _id = id;
_issuedTo = issuedTo; _issuedTo = issuedTo;
} }
inline uint64_t networkId() const { return _networkId; } inline uint64_t networkId() const
inline int64_t timestamp() const { return _ts; } {
inline uint32_t id() const { return _id; } return _networkId;
inline unsigned int thingCount() const { return (unsigned int)_thingCount; } }
inline int64_t timestamp() const
{
return _ts;
}
inline uint32_t id() const
{
return _id;
}
inline unsigned int thingCount() const
{
return (unsigned int)_thingCount;
}
inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } inline Thing thingType(const unsigned int i) const
inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } {
return (Thing)_thingTypes[i];
}
inline const uint8_t* thingValue(const unsigned int i) const
{
return _thingValues[i];
}
inline const Address &issuedTo() const { return _issuedTo; } inline const Address& issuedTo() const
{
return _issuedTo;
}
inline bool owns(const InetAddress &ip) const inline bool owns(const InetAddress& ip) const
{ {
if (ip.ss_family == AF_INET) { if (ip.ss_family == AF_INET) {
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4); return this->_owns(THING_IPV4_ADDRESS, &(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr), 4);
} }
if (ip.ss_family == AF_INET6) { if (ip.ss_family == AF_INET6) {
return this->_owns(THING_IPV6_ADDRESS,reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16); return this->_owns(THING_IPV6_ADDRESS, reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr, 16);
} }
return false; return false;
} }
inline bool owns(const MAC &mac) const inline bool owns(const MAC& mac) const
{ {
uint8_t tmp[6]; uint8_t tmp[6];
mac.copyTo(tmp,6); mac.copyTo(tmp, 6);
return this->_owns(THING_MAC_ADDRESS,tmp,6); return this->_owns(THING_MAC_ADDRESS, tmp, 6);
} }
inline void addThing(const InetAddress &ip) inline void addThing(const InetAddress& ip)
{ {
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return; return;
} }
if (ip.ss_family == AF_INET) { if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS; _thingTypes[_thingCount] = THING_IPV4_ADDRESS;
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4); memcpy(_thingValues[_thingCount], &(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr), 4);
++_thingCount; ++_thingCount;
} else if (ip.ss_family == AF_INET6) { }
else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS; _thingTypes[_thingCount] = THING_IPV6_ADDRESS;
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16); memcpy(_thingValues[_thingCount], reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr, 16);
++_thingCount; ++_thingCount;
} }
} }
inline void addThing(const MAC &mac) inline void addThing(const MAC& mac)
{ {
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return; return;
} }
_thingTypes[_thingCount] = THING_MAC_ADDRESS; _thingTypes[_thingCount] = THING_MAC_ADDRESS;
mac.copyTo(_thingValues[_thingCount],6); mac.copyTo(_thingValues[_thingCount], 6);
++_thingCount; ++_thingCount;
} }
@ -126,13 +144,13 @@ public:
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
inline bool sign(const Identity &signer) inline bool sign(const Identity& signer)
{ {
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp; Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
_signedBy = signer.address(); _signedBy = signer.address();
this->serialize(tmp,true); this->serialize(tmp, true);
_signature = signer.sign(tmp.data(),tmp.size()); _signature = signer.sign(tmp.data(), tmp.size());
return true; return true;
} }
return false; return false;
@ -143,10 +161,9 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature
*/ */
int verify(const RuntimeEnvironment *RR,void *tPtr) const; int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{ {
if (forSign) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -157,17 +174,17 @@ public:
b.append(_flags); b.append(_flags);
b.append(_id); b.append(_id);
b.append((uint16_t)_thingCount); b.append((uint16_t)_thingCount);
for(unsigned int i=0,j=_thingCount;i<j;++i) { for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
b.append((uint8_t)_thingTypes[i]); b.append((uint8_t)_thingTypes[i]);
b.append(_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE); b.append(_thingValues[i], ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
} }
_issuedTo.appendTo(b); _issuedTo.appendTo(b);
_signedBy.appendTo(b); _signedBy.appendTo(b);
if (!forSign) { if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519 b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_ECC_SIGNATURE_LEN); b.append(_signature.data, ZT_ECC_SIGNATURE_LEN);
} }
b.append((uint16_t)0); // length of additional fields, currently 0 b.append((uint16_t)0); // length of additional fields, currently 0
@ -177,8 +194,7 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
unsigned int p = startAt; unsigned int p = startAt;
@ -194,26 +210,27 @@ public:
p += 4; p += 4;
_thingCount = b.template at<uint16_t>(p); _thingCount = b.template at<uint16_t>(p);
p += 2; p += 2;
for(unsigned int i=0,j=_thingCount;i<j;++i) { for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
_thingTypes[i] = (uint8_t)b[p++]; _thingTypes[i] = (uint8_t)b[p++];
memcpy(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE); memcpy(_thingValues[i], b.field(p, ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE), ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE; p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
} }
} }
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _issuedTo.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) { if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_ECC_SIGNATURE_LEN) { if (b.template at<uint16_t>(p) != ZT_ECC_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} }
p += 2; p += 2;
memcpy(_signature.data,b.field(p,ZT_ECC_SIGNATURE_LEN),ZT_ECC_SIGNATURE_LEN); memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN);
p += ZT_ECC_SIGNATURE_LEN; p += ZT_ECC_SIGNATURE_LEN;
} else { }
else {
p += 2 + b.template at<uint16_t>(p); p += 2 + b.template at<uint16_t>(p);
} }
@ -226,13 +243,22 @@ public:
} }
// Provides natural sort order by ID // Provides natural sort order by ID
inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); } inline bool operator<(const CertificateOfOwnership& coo) const
{
return (_id < coo._id);
}
inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); } inline bool operator==(const CertificateOfOwnership& coo) const
inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } {
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) == 0);
}
inline bool operator!=(const CertificateOfOwnership& coo) const
{
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) != 0);
}
private: private:
bool _owns(const Thing &t,const void *v,unsigned int l) const; bool _owns(const Thing& t, const void* v, unsigned int l) const;
uint64_t _networkId; uint64_t _networkId;
int64_t _ts; int64_t _ts;

View file

@ -61,8 +61,8 @@
#ifdef ZT_SSO_SUPPORTED #ifdef ZT_SSO_SUPPORTED
#define ZT_SSO_ENABLED 1 #define ZT_SSO_ENABLED 1
#endif #endif
#define likely(x) __builtin_expect((x),1) #define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x),0) #define unlikely(x) __builtin_expect((x), 0)
#include <TargetConditionals.h> #include <TargetConditionals.h>
#ifndef __UNIX_LIKE__ #ifndef __UNIX_LIKE__
#define __UNIX_LIKE__ #define __UNIX_LIKE__
@ -106,8 +106,8 @@
#pragma warning(disable : 4101) #pragma warning(disable : 4101)
#undef __UNIX_LIKE__ #undef __UNIX_LIKE__
#undef __BSD__ #undef __BSD__
#include <winsock2.h>
#include <windows.h> #include <windows.h>
#include <winsock2.h>
#endif #endif
#ifdef __NetBSD__ #ifdef __NetBSD__
@ -118,13 +118,13 @@
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)) #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#define ZT_ARCH_X64 1 #define ZT_ARCH_X64 1
#include <xmmintrin.h>
#include <emmintrin.h> #include <emmintrin.h>
#include <immintrin.h> #include <immintrin.h>
#include <xmmintrin.h>
#endif #endif
#if (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON)) #if (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON))
#if (defined(__APPLE__) && !defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__)) #if (defined(__APPLE__) && ! defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__))
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
#undef ZT_ARCH_ARM_HAS_NEON #undef ZT_ARCH_ARM_HAS_NEON
#endif #endif
@ -145,7 +145,8 @@
#endif #endif
// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64. // Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64.
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386))) #if (! (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) \
|| defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#ifndef ZT_NO_TYPE_PUNNING #ifndef ZT_NO_TYPE_PUNNING
#define ZT_NO_TYPE_PUNNING 1 #define ZT_NO_TYPE_PUNNING 1
#endif #endif
@ -157,7 +158,7 @@
#endif #endif
// Assume little endian if not defined // Assume little endian if not defined
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER)) #if (defined(__APPLE__) || defined(__WINDOWS__)) && (! defined(__BYTE_ORDER))
#undef __BYTE_ORDER #undef __BYTE_ORDER
#undef __LITTLE_ENDIAN #undef __LITTLE_ENDIAN
#undef __BIG_ENDIAN #undef __BIG_ENDIAN
@ -182,10 +183,10 @@
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
#ifndef likely #ifndef likely
#define likely(x) __builtin_expect((x),1) #define likely(x) __builtin_expect((x), 1)
#endif #endif
#ifndef unlikely #ifndef unlikely
#define unlikely(x) __builtin_expect((x),0) #define unlikely(x) __builtin_expect((x), 0)
#endif #endif
#else #else
#ifndef likely #ifndef likely
@ -197,7 +198,7 @@
#endif #endif
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop)) #define ZT_PACKED_STRUCT(D) __pragma(pack(push, 1)) D __pragma(pack(pop))
#else #else
#define ZT_PACKED_STRUCT(D) D __attribute__((packed)) #define ZT_PACKED_STRUCT(D) D __attribute__((packed))
#endif #endif
@ -212,7 +213,7 @@
#define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first) #define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#elif defined(__linux__) #elif defined(__linux__)
#define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other #define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__) #elif defined(__unix__) || ! defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h> #include <sys/param.h>
#if defined(BSD) #if defined(BSD)
#define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD #define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
@ -255,7 +256,7 @@
#define ZT_ARCH_NAME "mips" #define ZT_ARCH_NAME "mips"
#elif defined(__riscv) || defined(__riscv_xlen) #elif defined(__riscv) || defined(__riscv_xlen)
#define ZT_ARCH_NAME "riscv" #define ZT_ARCH_NAME "riscv"
#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined (_M_PPC) #elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC)
#define ZT_ARCH_NAME "powerpc" #define ZT_ARCH_NAME "powerpc"
#elif defined(__s390__) || defined(__s390x__) || defined(__zarch__) #elif defined(__s390__) || defined(__s390x__) || defined(__zarch__)
#define ZT_ARCH_NAME "s390" #define ZT_ARCH_NAME "s390"
@ -632,7 +633,6 @@
*/ */
#define ZT_PEER_GENERAL_RATE_LIMIT 1000 #define ZT_PEER_GENERAL_RATE_LIMIT 1000
/** /**
* Minimum allowed amount of time between flow/path optimizations (anti-flapping) * Minimum allowed amount of time between flow/path optimizations (anti-flapping)
*/ */

View file

@ -19,14 +19,12 @@ namespace ZeroTier {
/** /**
* Base class for credentials * Base class for credentials
*/ */
class Credential class Credential {
{ public:
public:
/** /**
* Do not change type code IDs -- these are used in Revocation objects and elsewhere * Do not change type code IDs -- these are used in Revocation objects and elsewhere
*/ */
enum Type enum Type {
{
CREDENTIAL_TYPE_NULL = 0, CREDENTIAL_TYPE_NULL = 0,
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
CREDENTIAL_TYPE_CAPABILITY = 2, CREDENTIAL_TYPE_CAPABILITY = 2,

View file

@ -13,45 +13,43 @@
#ifndef ZT_DNS_HPP #ifndef ZT_DNS_HPP
#define ZT_DNS_HPP #define ZT_DNS_HPP
#include "../include/ZeroTierOne.h"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "../include/ZeroTierOne.h"
namespace ZeroTier { namespace ZeroTier {
/** /**
* DNS data serialization methods * DNS data serialization methods
*/ */
class DNS { class DNS {
public: public:
template<unsigned int C> template <unsigned int C> static inline void serializeDNS(Buffer<C>& b, const ZT_VirtualNetworkDNS* dns)
static inline void serializeDNS(Buffer<C> &b, const ZT_VirtualNetworkDNS *dns)
{ {
b.append(dns->domain, 128); b.append(dns->domain, 128);
for(unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
InetAddress tmp(dns->server_addr[j]); InetAddress tmp(dns->server_addr[j]);
tmp.serialize(b); tmp.serialize(b);
} }
} }
template<unsigned int C> template <unsigned int C> static inline void deserializeDNS(const Buffer<C>& b, unsigned int& p, ZT_VirtualNetworkDNS* dns)
static inline void deserializeDNS(const Buffer<C> &b, unsigned int &p, ZT_VirtualNetworkDNS *dns)
{ {
char *d = (char*)b.data()+p; char* d = (char*)b.data() + p;
memset(dns, 0, sizeof(ZT_VirtualNetworkDNS)); memset(dns, 0, sizeof(ZT_VirtualNetworkDNS));
memcpy(dns->domain, d, 128); memcpy(dns->domain, d, 128);
dns->domain[127] = 0; dns->domain[127] = 0;
p += 128; p += 128;
for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
p += reinterpret_cast<InetAddress *>(&(dns->server_addr[j]))->deserialize(b, p); p += reinterpret_cast<InetAddress*>(&(dns->server_addr[j]))->deserialize(b, p);
} }
} }
}; };
} } // namespace ZeroTier
#endif // ZT_DNS_HPP #endif // ZT_DNS_HPP

View file

@ -14,10 +14,10 @@
#ifndef ZT_DICTIONARY_HPP #ifndef ZT_DICTIONARY_HPP
#define ZT_DICTIONARY_HPP #define ZT_DICTIONARY_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include <stdint.h> #include <stdint.h>
@ -45,36 +45,48 @@ namespace ZeroTier {
* *
* @tparam C Dictionary max capacity in bytes * @tparam C Dictionary max capacity in bytes
*/ */
template<unsigned int C> template <unsigned int C> class Dictionary {
class Dictionary public:
{ Dictionary()
public:
Dictionary() { memset(_d,0,sizeof(_d)); }
Dictionary(const char *s) { this->load(s); }
Dictionary(const char *s,unsigned int len)
{ {
for(unsigned int i=0;i<C;++i) { memset(_d, 0, sizeof(_d));
if ((s)&&(i < len)) { }
if (!(_d[i] = *s)) { Dictionary(const char* s)
s = (const char *)0; {
} else { this->load(s);
}
Dictionary(const char* s, unsigned int len)
{
for (unsigned int i = 0; i < C; ++i) {
if ((s) && (i < len)) {
if (! (_d[i] = *s)) {
s = (const char*)0;
}
else {
++s; ++s;
} }
} else { }
else {
_d[i] = (char)0; _d[i] = (char)0;
} }
} }
_d[C - 1] = (char)0; _d[C - 1] = (char)0;
} }
Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); } Dictionary(const Dictionary& d)
inline Dictionary &operator=(const Dictionary &d)
{ {
memcpy(_d,d._d,C); memcpy(_d, d._d, C);
}
inline Dictionary& operator=(const Dictionary& d)
{
memcpy(_d, d._d, C);
return *this; return *this;
} }
inline operator bool() const { return (_d[0] != 0); } inline operator bool() const
{
return (_d[0] != 0);
}
/** /**
* Load a dictionary from a C-string * Load a dictionary from a C-string
@ -82,21 +94,23 @@ public:
* @param s Dictionary in string form * @param s Dictionary in string form
* @return False if 's' was longer than our capacity * @return False if 's' was longer than our capacity
*/ */
inline bool load(const char *s) inline bool load(const char* s)
{ {
for(unsigned int i=0;i<C;++i) { for (unsigned int i = 0; i < C; ++i) {
if (s) { if (s) {
if (!(_d[i] = *s)) { if (! (_d[i] = *s)) {
s = (const char *)0; s = (const char*)0;
} else { }
else {
++s; ++s;
} }
} else { }
else {
_d[i] = (char)0; _d[i] = (char)0;
} }
} }
_d[C - 1] = (char)0; _d[C - 1] = (char)0;
return (!s); return (! s);
} }
/** /**
@ -104,7 +118,7 @@ public:
*/ */
inline void clear() inline void clear()
{ {
memset(_d,0,sizeof(_d)); memset(_d, 0, sizeof(_d));
} }
/** /**
@ -112,12 +126,12 @@ public:
*/ */
inline unsigned int sizeBytes() const inline unsigned int sizeBytes() const
{ {
for(unsigned int i=0;i<C;++i) { for (unsigned int i = 0; i < C; ++i) {
if (!_d[i]) { if (! _d[i]) {
return i; return i;
} }
} }
return C-1; return C - 1;
} }
/** /**
@ -142,21 +156,21 @@ public:
* @param destlen Size of destination buffer * @param destlen Size of destination buffer
* @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0 * @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
*/ */
inline int get(const char *key,char *dest,unsigned int destlen) const inline int get(const char* key, char* dest, unsigned int destlen) const
{ {
const char *p = _d; const char* p = _d;
const char *const eof = p + C; const char* const eof = p + C;
const char *k; const char* k;
bool esc; bool esc;
int j; int j;
if (!destlen) { // sanity check if (! destlen) { // sanity check
return -1; return -1;
} }
while (*p) { while (*p) {
k = key; k = key;
while ((*k)&&(*p)) { while ((*k) && (*p)) {
if (*p != *k) { if (*p != *k) {
break; break;
} }
@ -167,14 +181,14 @@ public:
} }
} }
if ((!*k)&&(*p == '=')) { if ((! *k) && (*p == '=')) {
j = 0; j = 0;
esc = false; esc = false;
++p; ++p;
while ((*p != 0)&&(*p != 13)&&(*p != 10)) { while ((*p != 0) && (*p != 13) && (*p != 10)) {
if (esc) { if (esc) {
esc = false; esc = false;
switch(*p) { switch (*p) {
case 'r': case 'r':
dest[j++] = 13; dest[j++] = 13;
break; break;
@ -192,16 +206,18 @@ public:
break; break;
} }
if (j == (int)destlen) { if (j == (int)destlen) {
dest[j-1] = (char)0; dest[j - 1] = (char)0;
return j-1; return j - 1;
} }
} else if (*p == '\\') { }
else if (*p == '\\') {
esc = true; esc = true;
} else { }
else {
dest[j++] = *p; dest[j++] = *p;
if (j == (int)destlen) { if (j == (int)destlen) {
dest[j-1] = (char)0; dest[j - 1] = (char)0;
return j-1; return j - 1;
} }
} }
if (++p == eof) { if (++p == eof) {
@ -211,8 +227,9 @@ public:
} }
dest[j] = (char)0; dest[j] = (char)0;
return j; return j;
} else { }
while ((*p)&&(*p != 13)&&(*p != 10)) { else {
while ((*p) && (*p != 13) && (*p != 10)) {
if (++p == eof) { if (++p == eof) {
dest[0] = (char)0; dest[0] = (char)0;
return -1; return -1;
@ -223,7 +240,8 @@ public:
dest[0] = (char)0; dest[0] = (char)0;
return -1; return -1;
} }
} else { }
else {
break; break;
} }
} }
@ -241,14 +259,14 @@ public:
* @return True if key was found (if false, dest will be empty) * @return True if key was found (if false, dest will be empty)
* @tparam BC Buffer capacity (usually inferred) * @tparam BC Buffer capacity (usually inferred)
*/ */
template<unsigned int BC> template <unsigned int BC> inline bool get(const char* key, Buffer<BC>& dest) const
inline bool get(const char *key,Buffer<BC> &dest) const
{ {
const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),BC); const int r = this->get(key, const_cast<char*>(reinterpret_cast<const char*>(dest.data())), BC);
if (r >= 0) { if (r >= 0) {
dest.setSize((unsigned int)r); dest.setSize((unsigned int)r);
return true; return true;
} else { }
else {
dest.clear(); dest.clear();
return false; return false;
} }
@ -261,11 +279,11 @@ public:
* @param dfl Default value if not found in dictionary * @param dfl Default value if not found in dictionary
* @return Boolean value of key or 'dfl' if not found * @return Boolean value of key or 'dfl' if not found
*/ */
bool getB(const char *key,bool dfl = false) const bool getB(const char* key, bool dfl = false) const
{ {
char tmp[4]; char tmp[4];
if (this->get(key,tmp,sizeof(tmp)) >= 0) { if (this->get(key, tmp, sizeof(tmp)) >= 0) {
return ((*tmp == '1')||(*tmp == 't')||(*tmp == 'T')); return ((*tmp == '1') || (*tmp == 't') || (*tmp == 'T'));
} }
return dfl; return dfl;
} }
@ -277,10 +295,10 @@ public:
* @param dfl Default value or 0 if unspecified * @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found * @return Decoded hex UInt value or 'dfl' if not found
*/ */
inline uint64_t getUI(const char *key,uint64_t dfl = 0) const inline uint64_t getUI(const char* key, uint64_t dfl = 0) const
{ {
char tmp[128]; char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1) { if (this->get(key, tmp, sizeof(tmp)) >= 1) {
return Utils::hexStrToU64(tmp); return Utils::hexStrToU64(tmp);
} }
return dfl; return dfl;
@ -293,10 +311,10 @@ public:
* @param dfl Default value or 0 if unspecified * @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found * @return Decoded hex UInt value or 'dfl' if not found
*/ */
inline int64_t getI(const char *key,int64_t dfl = 0) const inline int64_t getI(const char* key, int64_t dfl = 0) const
{ {
char tmp[128]; char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1) { if (this->get(key, tmp, sizeof(tmp)) >= 1) {
return Utils::hexStrTo64(tmp); return Utils::hexStrTo64(tmp);
} }
return dfl; return dfl;
@ -316,10 +334,10 @@ public:
* @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0 * @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
* @return True if there was enough room to add this key=value pair * @return True if there was enough room to add this key=value pair
*/ */
inline bool add(const char *key,const char *value,int vlen = -1) inline bool add(const char* key, const char* value, int vlen = -1)
{ {
for(unsigned int i=0;i<C;++i) { for (unsigned int i = 0; i < C; ++i) {
if (!_d[i]) { if (! _d[i]) {
unsigned int j = i; unsigned int j = i;
if (j > 0) { if (j > 0) {
@ -330,7 +348,7 @@ public:
} }
} }
const char *p = key; const char* p = key;
while (*p) { while (*p) {
_d[j++] = *(p++); _d[j++] = *(p++);
if (j == C) { if (j == C) {
@ -347,8 +365,8 @@ public:
p = value; p = value;
int k = 0; int k = 0;
while ( ((vlen < 0)&&(*p)) || (k < vlen) ) { while (((vlen < 0) && (*p)) || (k < vlen)) {
switch(*p) { switch (*p) {
case 0: case 0:
case 13: case 13:
case 10: case 10:
@ -359,7 +377,7 @@ public:
_d[i] = (char)0; _d[i] = (char)0;
return false; return false;
} }
switch(*p) { switch (*p) {
case 0: case 0:
_d[j++] = '0'; _d[j++] = '0';
break; break;
@ -404,41 +422,42 @@ public:
/** /**
* Add a boolean as a '1' or a '0' * Add a boolean as a '1' or a '0'
*/ */
inline bool add(const char *key,bool value) inline bool add(const char* key, bool value)
{ {
return this->add(key,(value) ? "1" : "0",1); return this->add(key, (value) ? "1" : "0", 1);
} }
/** /**
* Add a 64-bit integer (unsigned) as a hex value * Add a 64-bit integer (unsigned) as a hex value
*/ */
inline bool add(const char *key,uint64_t value) inline bool add(const char* key, uint64_t value)
{ {
char tmp[32]; char tmp[32];
return this->add(key,Utils::hex(value,tmp),-1); return this->add(key, Utils::hex(value, tmp), -1);
} }
/** /**
* Add a 64-bit integer (unsigned) as a hex value * Add a 64-bit integer (unsigned) as a hex value
*/ */
inline bool add(const char *key,int64_t value) inline bool add(const char* key, int64_t value)
{ {
char tmp[32]; char tmp[32];
if (value >= 0) { if (value >= 0) {
return this->add(key,Utils::hex((uint64_t)value,tmp),-1); return this->add(key, Utils::hex((uint64_t)value, tmp), -1);
} else { }
else {
tmp[0] = '-'; tmp[0] = '-';
return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1); return this->add(key, Utils::hex((uint64_t)(value * -1), tmp + 1), -1);
} }
} }
/** /**
* Add a 64-bit integer (unsigned) as a hex value * Add a 64-bit integer (unsigned) as a hex value
*/ */
inline bool add(const char *key,const Address &a) inline bool add(const char* key, const Address& a)
{ {
char tmp[32]; char tmp[32];
return this->add(key,Utils::hex(a.toInt(),tmp),-1); return this->add(key, Utils::hex(a.toInt(), tmp), -1);
} }
/** /**
@ -446,31 +465,39 @@ public:
* *
* @tparam BC Buffer capacity (usually inferred) * @tparam BC Buffer capacity (usually inferred)
*/ */
template<unsigned int BC> template <unsigned int BC> inline bool add(const char* key, const Buffer<BC>& value)
inline bool add(const char *key,const Buffer<BC> &value)
{ {
return this->add(key,(const char *)value.data(),(int)value.size()); return this->add(key, (const char*)value.data(), (int)value.size());
} }
/** /**
* @param key Key to check * @param key Key to check
* @return True if key is present * @return True if key is present
*/ */
inline bool contains(const char *key) const inline bool contains(const char* key) const
{ {
char tmp[2]; char tmp[2];
return (this->get(key,tmp,2) >= 0); return (this->get(key, tmp, 2) >= 0);
} }
/** /**
* @return Value of C template parameter * @return Value of C template parameter
*/ */
inline unsigned int capacity() const { return C; } inline unsigned int capacity() const
{
return C;
}
inline const char *data() const { return _d; } inline const char* data() const
inline char *unsafeData() { return _d; } {
return _d;
}
inline char* unsafeData()
{
return _d;
}
private: private:
char _d[C]; char _d[C];
}; };

File diff suppressed because it is too large Load diff

View file

@ -29,24 +29,32 @@
/* FIPS140/NIST ECC cryptography */ /* FIPS140/NIST ECC cryptography */
/* Note that to be FIPS we also need to link against a FIPS-certified library. */ /* Note that to be FIPS we also need to link against a FIPS-certified library. */
#include <openssl/evp.h> #include <openssl/bn.h>
#include <openssl/ec.h> #include <openssl/ec.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/bn.h>
#define ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN 97 /* Single ECC P-384 key */ #define ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN 97 /* Single ECC P-384 key */
#define ZT_ECC_PUBLIC_KEY_SET_LEN (97 * 2) /* Two ECC P-384 keys */ #define ZT_ECC_PUBLIC_KEY_SET_LEN (97 * 2) /* Two ECC P-384 keys */
#define ZT_ECC_PRIVATE_KEY_SET_LEN (48 * 2) /* Two ECC P-384 secret keys */ #define ZT_ECC_PRIVATE_KEY_SET_LEN (48 * 2) /* Two ECC P-384 secret keys */
#define ZT_ECC_SIGNATURE_LEN 96 /* NIST P-384 ECDSA signature */ #define ZT_ECC_SIGNATURE_LEN 96 /* NIST P-384 ECDSA signature */
class ECC class ECC {
{ public:
public: struct Public {
struct Public { uint8_t data[ZT_ECC_PUBLIC_KEY_SET_LEN]; }; uint8_t data[ZT_ECC_PUBLIC_KEY_SET_LEN];
struct Private { uint8_t data[ZT_ECC_PRIVATE_KEY_SET_LEN]; }; };
struct Signature { uint8_t data[ZT_ECC_SIGNATURE_LEN]; }; struct Private {
struct Pair { Public pub; Private priv; }; uint8_t data[ZT_ECC_PRIVATE_KEY_SET_LEN];
};
struct Signature {
uint8_t data[ZT_ECC_SIGNATURE_LEN];
};
struct Pair {
Public pub;
Private priv;
};
}; };
#else // Curve25519 / Ed25519 #else // Curve25519 / Ed25519
@ -58,13 +66,21 @@ namespace ZeroTier {
#define ZT_ECC_PRIVATE_KEY_SET_LEN 64 /* C25519 and Ed25519 secret keys */ #define ZT_ECC_PRIVATE_KEY_SET_LEN 64 /* C25519 and Ed25519 secret keys */
#define ZT_ECC_SIGNATURE_LEN 96 /* Ed25519 signature plus (not necessary) hash */ #define ZT_ECC_SIGNATURE_LEN 96 /* Ed25519 signature plus (not necessary) hash */
class ECC class ECC {
{ public:
public: struct Public {
struct Public { uint8_t data[ZT_ECC_PUBLIC_KEY_SET_LEN]; }; uint8_t data[ZT_ECC_PUBLIC_KEY_SET_LEN];
struct Private { uint8_t data[ZT_ECC_PRIVATE_KEY_SET_LEN]; }; };
struct Signature { uint8_t data[ZT_ECC_SIGNATURE_LEN]; }; struct Private {
struct Pair { Public pub; Private priv; }; uint8_t data[ZT_ECC_PRIVATE_KEY_SET_LEN];
};
struct Signature {
uint8_t data[ZT_ECC_SIGNATURE_LEN];
};
struct Pair {
Public pub;
Private priv;
};
/** /**
* Generate an elliptic curve key pair * Generate an elliptic curve key pair
@ -72,7 +88,7 @@ public:
static inline Pair generate() static inline Pair generate()
{ {
Pair kp; Pair kp;
Utils::getSecureRandom(kp.priv.data,ZT_ECC_PRIVATE_KEY_SET_LEN); Utils::getSecureRandom(kp.priv.data, ZT_ECC_PRIVATE_KEY_SET_LEN);
_calcPubDH(kp); _calcPubDH(kp);
_calcPubED(kp); _calcPubED(kp);
return kp; return kp;
@ -91,18 +107,17 @@ public:
* @return Key pair where cond(kp) returns true * @return Key pair where cond(kp) returns true
* @tparam F Type of 'cond' * @tparam F Type of 'cond'
*/ */
template<typename F> template <typename F> static inline Pair generateSatisfying(F cond)
static inline Pair generateSatisfying(F cond)
{ {
Pair kp; Pair kp;
void *const priv = (void *)kp.priv.data; void* const priv = (void*)kp.priv.data;
Utils::getSecureRandom(priv,ZT_ECC_PRIVATE_KEY_SET_LEN); Utils::getSecureRandom(priv, ZT_ECC_PRIVATE_KEY_SET_LEN);
_calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv _calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv
do { do {
++(((uint64_t *)priv)[1]); ++(((uint64_t*)priv)[1]);
--(((uint64_t *)priv)[2]); --(((uint64_t*)priv)[2]);
_calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied _calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied
} while (!cond(kp)); } while (! cond(kp));
return kp; return kp;
} }
@ -117,8 +132,11 @@ public:
* @param keybuf Buffer to fill * @param keybuf Buffer to fill
* @param keylen Number of key bytes to generate * @param keylen Number of key bytes to generate
*/ */
static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen); static void agree(const Private& mine, const Public& their, void* keybuf, unsigned int keylen);
static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) { agree(mine.priv,their,keybuf,keylen); } static inline void agree(const Pair& mine, const Public& their, void* keybuf, unsigned int keylen)
{
agree(mine.priv, their, keybuf, keylen);
}
/** /**
* Sign a message with a sender's key pair * Sign a message with a sender's key pair
@ -139,8 +157,11 @@ public:
* @param len Length of message in bytes * @param len Length of message in bytes
* @param signature Buffer to fill with signature -- MUST be 96 bytes in length * @param signature Buffer to fill with signature -- MUST be 96 bytes in length
*/ */
static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature); static void sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len, void* signature);
static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) { sign(mine.priv,mine.pub,msg,len,signature); } static inline void sign(const Pair& mine, const void* msg, unsigned int len, void* signature)
{
sign(mine.priv, mine.pub, msg, len, signature);
}
/** /**
* Sign a message with a sender's key pair * Sign a message with a sender's key pair
@ -151,16 +172,16 @@ public:
* @param len Length of message in bytes * @param len Length of message in bytes
* @return Signature * @return Signature
*/ */
static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len) static inline Signature sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len)
{ {
Signature sig; Signature sig;
sign(myPrivate,myPublic,msg,len,sig.data); sign(myPrivate, myPublic, msg, len, sig.data);
return sig; return sig;
} }
static inline Signature sign(const Pair &mine,const void *msg,unsigned int len) static inline Signature sign(const Pair& mine, const void* msg, unsigned int len)
{ {
Signature sig; Signature sig;
sign(mine.priv,mine.pub,msg,len,sig.data); sign(mine.priv, mine.pub, msg, len, sig.data);
return sig; return sig;
} }
@ -173,7 +194,7 @@ public:
* @param signature 96-byte signature * @param signature 96-byte signature
* @return True if signature is valid and the message is authentic and unmodified * @return True if signature is valid and the message is authentic and unmodified
*/ */
static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature); static bool verify(const Public& their, const void* msg, unsigned int len, const void* signature);
/** /**
* Verify a message's signature * Verify a message's signature
@ -184,19 +205,19 @@ public:
* @param signature 96-byte signature * @param signature 96-byte signature
* @return True if signature is valid and the message is authentic and unmodified * @return True if signature is valid and the message is authentic and unmodified
*/ */
static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature) static inline bool verify(const Public& their, const void* msg, unsigned int len, const Signature& signature)
{ {
return verify(their,msg,len,signature.data); return verify(their, msg, len, signature.data);
} }
private: private:
// derive first 32 bytes of kp.pub from first 32 bytes of kp.priv // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv
// this is the ECDH key // this is the ECDH key
static void _calcPubDH(Pair &kp); static void _calcPubDH(Pair& kp);
// derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv
// this is the Ed25519 sign/verify key // this is the Ed25519 sign/verify key
static void _calcPubED(Pair &kp); static void _calcPubED(Pair& kp);
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -16,36 +16,43 @@
#include "Constants.hpp" #include "Constants.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdexcept>
#include <vector>
#include <utility> #include <utility>
#include <algorithm> #include <vector>
namespace ZeroTier { namespace ZeroTier {
/** /**
* A minimal hash table implementation for the ZeroTier core * A minimal hash table implementation for the ZeroTier core
*/ */
template<typename K,typename V> template <typename K, typename V> class Hashtable {
class Hashtable private:
{ struct _Bucket {
private: _Bucket(const K& k, const V& v) : k(k), v(v)
struct _Bucket
{ {
_Bucket(const K &k,const V &v) : k(k),v(v) {} }
_Bucket(const K &k) : k(k),v() {} _Bucket(const K& k) : k(k), v()
_Bucket(const _Bucket &b) : k(b.k),v(b.v) {} {
inline _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; } }
_Bucket(const _Bucket& b) : k(b.k), v(b.v)
{
}
inline _Bucket& operator=(const _Bucket& b)
{
k = b.k;
v = b.v;
return *this;
}
K k; K k;
V v; V v;
_Bucket *next; // must be set manually for each _Bucket _Bucket* next; // must be set manually for each _Bucket
}; };
public: public:
/** /**
* A simple forward iterator (different from STL) * A simple forward iterator (different from STL)
* *
@ -53,16 +60,12 @@ public:
* may rehash and invalidate the iterator. Note the erasing the key will destroy * may rehash and invalidate the iterator. Note the erasing the key will destroy
* the targets of the pointers returned by next(). * the targets of the pointers returned by next().
*/ */
class Iterator class Iterator {
{
public: public:
/** /**
* @param ht Hash table to iterate over * @param ht Hash table to iterate over
*/ */
Iterator(Hashtable &ht) : Iterator(Hashtable& ht) : _idx(0), _ht(&ht), _b(ht._t[0])
_idx(0),
_ht(&ht),
_b(ht._t[0])
{ {
} }
@ -71,9 +74,9 @@ public:
* @param vptr Pointer to set to point to next value * @param vptr Pointer to set to point to next value
* @return True if kptr and vptr are set, false if no more entries * @return True if kptr and vptr are set, false if no more entries
*/ */
inline bool next(K *&kptr,V *&vptr) inline bool next(K*& kptr, V*& vptr)
{ {
for(;;) { for (;;) {
if (_b) { if (_b) {
kptr = &(_b->k); kptr = &(_b->k);
vptr = &(_b->v); vptr = &(_b->v);
@ -90,42 +93,36 @@ public:
private: private:
unsigned long _idx; unsigned long _idx;
Hashtable *_ht; Hashtable* _ht;
_Bucket *_b; _Bucket* _b;
}; };
//friend class Hashtable<K,V>::Iterator; // friend class Hashtable<K,V>::Iterator;
/** /**
* @param bc Initial capacity in buckets (default: 64, must be nonzero) * @param bc Initial capacity in buckets (default: 64, must be nonzero)
*/ */
Hashtable(unsigned long bc = 64) : Hashtable(unsigned long bc = 64) : _t(reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * bc))), _bc(bc), _s(0)
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
_bc(bc),
_s(0)
{ {
if (!_t) { if (! _t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY; throw ZT_EXCEPTION_OUT_OF_MEMORY;
} }
for(unsigned long i=0;i<bc;++i) { for (unsigned long i = 0; i < bc; ++i) {
_t[i] = (_Bucket *)0; _t[i] = (_Bucket*)0;
} }
} }
Hashtable(const Hashtable<K,V> &ht) : Hashtable(const Hashtable<K, V>& ht) : _t(reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * ht._bc))), _bc(ht._bc), _s(ht._s)
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * ht._bc))),
_bc(ht._bc),
_s(ht._s)
{ {
if (!_t) { if (! _t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY; throw ZT_EXCEPTION_OUT_OF_MEMORY;
} }
for(unsigned long i=0;i<_bc;++i) { for (unsigned long i = 0; i < _bc; ++i) {
_t[i] = (_Bucket *)0; _t[i] = (_Bucket*)0;
} }
for(unsigned long i=0;i<_bc;++i) { for (unsigned long i = 0; i < _bc; ++i) {
const _Bucket *b = ht._t[i]; const _Bucket* b = ht._t[i];
while (b) { while (b) {
_Bucket *nb = new _Bucket(*b); _Bucket* nb = new _Bucket(*b);
nb->next = _t[i]; nb->next = _t[i];
_t[i] = nb; _t[i] = nb;
b = b->next; b = b->next;
@ -139,14 +136,14 @@ public:
::free(_t); ::free(_t);
} }
inline Hashtable &operator=(const Hashtable<K,V> &ht) inline Hashtable& operator=(const Hashtable<K, V>& ht)
{ {
this->clear(); this->clear();
if (ht._s) { if (ht._s) {
for(unsigned long i=0;i<ht._bc;++i) { for (unsigned long i = 0; i < ht._bc; ++i) {
const _Bucket *b = ht._t[i]; const _Bucket* b = ht._t[i];
while (b) { while (b) {
this->set(b->k,b->v); this->set(b->k, b->v);
b = b->next; b = b->next;
} }
} }
@ -160,14 +157,14 @@ public:
inline void clear() inline void clear()
{ {
if (_s) { if (_s) {
for(unsigned long i=0;i<_bc;++i) { for (unsigned long i = 0; i < _bc; ++i) {
_Bucket *b = _t[i]; _Bucket* b = _t[i];
while (b) { while (b) {
_Bucket *const nb = b->next; _Bucket* const nb = b->next;
delete b; delete b;
b = nb; b = nb;
} }
_t[i] = (_Bucket *)0; _t[i] = (_Bucket*)0;
} }
_s = 0; _s = 0;
} }
@ -181,8 +178,8 @@ public:
typename std::vector<K> k; typename std::vector<K> k;
if (_s) { if (_s) {
k.reserve(_s); k.reserve(_s);
for(unsigned long i=0;i<_bc;++i) { for (unsigned long i = 0; i < _bc; ++i) {
_Bucket *b = _t[i]; _Bucket* b = _t[i];
while (b) { while (b) {
k.push_back(b->k); k.push_back(b->k);
b = b->next; b = b->next;
@ -198,12 +195,11 @@ public:
* @param v Vector, list, or other compliant container * @param v Vector, list, or other compliant container
* @tparam Type of V (generally inferred) * @tparam Type of V (generally inferred)
*/ */
template<typename C> template <typename C> inline void appendKeys(C& v) const
inline void appendKeys(C &v) const
{ {
if (_s) { if (_s) {
for(unsigned long i=0;i<_bc;++i) { for (unsigned long i = 0; i < _bc; ++i) {
_Bucket *b = _t[i]; _Bucket* b = _t[i];
while (b) { while (b) {
v.push_back(b->k); v.push_back(b->k);
b = b->next; b = b->next;
@ -215,15 +211,15 @@ public:
/** /**
* @return Vector of all entries (pairs of K,V) * @return Vector of all entries (pairs of K,V)
*/ */
inline typename std::vector< std::pair<K,V> > entries() const inline typename std::vector<std::pair<K, V> > entries() const
{ {
typename std::vector< std::pair<K,V> > k; typename std::vector<std::pair<K, V> > k;
if (_s) { if (_s) {
k.reserve(_s); k.reserve(_s);
for(unsigned long i=0;i<_bc;++i) { for (unsigned long i = 0; i < _bc; ++i) {
_Bucket *b = _t[i]; _Bucket* b = _t[i];
while (b) { while (b) {
k.push_back(std::pair<K,V>(b->k,b->v)); k.push_back(std::pair<K, V>(b->k, b->v));
b = b->next; b = b->next;
} }
} }
@ -235,27 +231,30 @@ public:
* @param k Key * @param k Key
* @return Pointer to value or NULL if not found * @return Pointer to value or NULL if not found
*/ */
inline V *get(const K &k) inline V* get(const K& k)
{ {
_Bucket *b = _t[_hc(k) % _bc]; _Bucket* b = _t[_hc(k) % _bc];
while (b) { while (b) {
if (b->k == k) { if (b->k == k) {
return &(b->v); return &(b->v);
} }
b = b->next; b = b->next;
} }
return (V *)0; return (V*)0;
}
inline const V* get(const K& k) const
{
return const_cast<Hashtable*>(this)->get(k);
} }
inline const V *get(const K &k) const { return const_cast<Hashtable *>(this)->get(k); }
/** /**
* @param k Key * @param k Key
* @param v Value to fill with result * @param v Value to fill with result
* @return True if value was found and set (if false, v is not modified) * @return True if value was found and set (if false, v is not modified)
*/ */
inline bool get(const K &k,V &v) const inline bool get(const K& k, V& v) const
{ {
_Bucket *b = _t[_hc(k) % _bc]; _Bucket* b = _t[_hc(k) % _bc];
while (b) { while (b) {
if (b->k == k) { if (b->k == k) {
v = b->v; v = b->v;
@ -270,9 +269,9 @@ public:
* @param k Key to check * @param k Key to check
* @return True if key is present * @return True if key is present
*/ */
inline bool contains(const K &k) const inline bool contains(const K& k) const
{ {
_Bucket *b = _t[_hc(k) % _bc]; _Bucket* b = _t[_hc(k) % _bc];
while (b) { while (b) {
if (b->k == k) { if (b->k == k) {
return true; return true;
@ -286,16 +285,17 @@ public:
* @param k Key * @param k Key
* @return True if value was present * @return True if value was present
*/ */
inline bool erase(const K &k) inline bool erase(const K& k)
{ {
const unsigned long bidx = _hc(k) % _bc; const unsigned long bidx = _hc(k) % _bc;
_Bucket *lastb = (_Bucket *)0; _Bucket* lastb = (_Bucket*)0;
_Bucket *b = _t[bidx]; _Bucket* b = _t[bidx];
while (b) { while (b) {
if (b->k == k) { if (b->k == k) {
if (lastb) { if (lastb) {
lastb->next = b->next; lastb->next = b->next;
} else { }
else {
_t[bidx] = b->next; _t[bidx] = b->next;
} }
delete b; delete b;
@ -313,12 +313,12 @@ public:
* @param v Value * @param v Value
* @return Reference to value in table * @return Reference to value in table
*/ */
inline V &set(const K &k,const V &v) inline V& set(const K& k, const V& v)
{ {
const unsigned long h = _hc(k); const unsigned long h = _hc(k);
unsigned long bidx = h % _bc; unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx]; _Bucket* b = _t[bidx];
while (b) { while (b) {
if (b->k == k) { if (b->k == k) {
b->v = v; b->v = v;
@ -332,7 +332,7 @@ public:
bidx = h % _bc; bidx = h % _bc;
} }
b = new _Bucket(k,v); b = new _Bucket(k, v);
b->next = _t[bidx]; b->next = _t[bidx];
_t[bidx] = b; _t[bidx] = b;
++_s; ++_s;
@ -343,12 +343,12 @@ public:
* @param k Key * @param k Key
* @return Value, possibly newly created * @return Value, possibly newly created
*/ */
inline V &operator[](const K &k) inline V& operator[](const K& k)
{ {
const unsigned long h = _hc(k); const unsigned long h = _hc(k);
unsigned long bidx = h % _bc; unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx]; _Bucket* b = _t[bidx];
while (b) { while (b) {
if (b->k == k) { if (b->k == k) {
return b->v; return b->v;
@ -371,16 +371,21 @@ public:
/** /**
* @return Number of entries * @return Number of entries
*/ */
inline unsigned long size() const { return _s; } inline unsigned long size() const
{
return _s;
}
/** /**
* @return True if table is empty * @return True if table is empty
*/ */
inline bool empty() const { return (_s == 0); } inline bool empty() const
{
return (_s == 0);
}
private: private:
template<typename O> template <typename O> static inline unsigned long _hc(const O& obj)
static inline unsigned long _hc(const O &obj)
{ {
return (unsigned long)obj.hashCode(); return (unsigned long)obj.hashCode();
} }
@ -404,15 +409,15 @@ private:
inline void _grow() inline void _grow()
{ {
const unsigned long nc = _bc * 2; const unsigned long nc = _bc * 2;
_Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc)); _Bucket** nt = reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * nc));
if (nt) { if (nt) {
for(unsigned long i=0;i<nc;++i) { for (unsigned long i = 0; i < nc; ++i) {
nt[i] = (_Bucket *)0; nt[i] = (_Bucket*)0;
} }
for(unsigned long i=0;i<_bc;++i) { for (unsigned long i = 0; i < _bc; ++i) {
_Bucket *b = _t[i]; _Bucket* b = _t[i];
while (b) { while (b) {
_Bucket *const nb = b->next; _Bucket* const nb = b->next;
const unsigned long nidx = _hc(b->k) % nc; const unsigned long nidx = _hc(b->k) % nc;
b->next = nt[nidx]; b->next = nt[nidx];
nt[nidx] = b; nt[nidx] = b;
@ -425,7 +430,7 @@ private:
} }
} }
_Bucket **_t; _Bucket** _t;
unsigned long _bc; unsigned long _bc;
unsigned long _s; unsigned long _s;
}; };

View file

@ -11,18 +11,19 @@
*/ */
/****/ /****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "ECC.hpp"
#include "Constants.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Constants.hpp"
#include "ECC.hpp"
#include "SHA512.hpp" #include "SHA512.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// These can't be changed without a new identity type. They define the // These can't be changed without a new identity type. They define the
// parameters of the hashcash hashing/searching algorithm. // parameters of the hashcash hashing/searching algorithm.
@ -32,74 +33,77 @@
namespace ZeroTier { namespace ZeroTier {
// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing // A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing
static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem) static inline void _computeMemoryHardHash(const void* publicKey, unsigned int publicKeyBytes, void* digest, void* genmem)
{ {
// Digest publicKey[] to obtain initial digest // Digest publicKey[] to obtain initial digest
SHA512(digest,publicKey,publicKeyBytes); SHA512(digest, publicKey, publicKeyBytes);
// Initialize genmem[] using Salsa20 in a CBC-like configuration since // Initialize genmem[] using Salsa20 in a CBC-like configuration since
// ordinary Salsa20 is randomly seek-able. This is good for a cipher // ordinary Salsa20 is randomly seek-able. This is good for a cipher
// but is not what we want for sequential memory-hardness. // but is not what we want for sequential memory-hardness.
memset(genmem,0,ZT_IDENTITY_GEN_MEMORY); memset(genmem, 0, ZT_IDENTITY_GEN_MEMORY);
Salsa20 s20(digest,(char *)digest + 32); Salsa20 s20(digest, (char*)digest + 32);
s20.crypt20((char *)genmem,(char *)genmem,64); s20.crypt20((char*)genmem, (char*)genmem, 64);
for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) { for (unsigned long i = 64; i < ZT_IDENTITY_GEN_MEMORY; i += 64) {
unsigned long k = i - 64; unsigned long k = i - 64;
*((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k)); *((uint64_t*)((char*)genmem + i)) = *((uint64_t*)((char*)genmem + k));
*((uint64_t *)((char *)genmem + i + 8)) = *((uint64_t *)((char *)genmem + k + 8)); *((uint64_t*)((char*)genmem + i + 8)) = *((uint64_t*)((char*)genmem + k + 8));
*((uint64_t *)((char *)genmem + i + 16)) = *((uint64_t *)((char *)genmem + k + 16)); *((uint64_t*)((char*)genmem + i + 16)) = *((uint64_t*)((char*)genmem + k + 16));
*((uint64_t *)((char *)genmem + i + 24)) = *((uint64_t *)((char *)genmem + k + 24)); *((uint64_t*)((char*)genmem + i + 24)) = *((uint64_t*)((char*)genmem + k + 24));
*((uint64_t *)((char *)genmem + i + 32)) = *((uint64_t *)((char *)genmem + k + 32)); *((uint64_t*)((char*)genmem + i + 32)) = *((uint64_t*)((char*)genmem + k + 32));
*((uint64_t *)((char *)genmem + i + 40)) = *((uint64_t *)((char *)genmem + k + 40)); *((uint64_t*)((char*)genmem + i + 40)) = *((uint64_t*)((char*)genmem + k + 40));
*((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48)); *((uint64_t*)((char*)genmem + i + 48)) = *((uint64_t*)((char*)genmem + k + 48));
*((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56)); *((uint64_t*)((char*)genmem + i + 56)) = *((uint64_t*)((char*)genmem + k + 56));
s20.crypt20((char *)genmem + i,(char *)genmem + i,64); s20.crypt20((char*)genmem + i, (char*)genmem + i, 64);
} }
// Render final digest using genmem as a lookup table // Render final digest using genmem as a lookup table
for(unsigned long i=0;i<(ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) { for (unsigned long i = 0; i < (ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) {
unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (64 / sizeof(uint64_t))); unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (64 / sizeof(uint64_t)));
unsigned long idx2 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t))); unsigned long idx2 = (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t)));
uint64_t tmp = ((uint64_t *)genmem)[idx2]; uint64_t tmp = ((uint64_t*)genmem)[idx2];
((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1]; ((uint64_t*)genmem)[idx2] = ((uint64_t*)digest)[idx1];
((uint64_t *)digest)[idx1] = tmp; ((uint64_t*)digest)[idx1] = tmp;
s20.crypt20(digest,digest,64); s20.crypt20(digest, digest, 64);
} }
} }
// Hashcash generation halting condition -- halt when first byte is less than // Hashcash generation halting condition -- halt when first byte is less than
// threshold value. // threshold value.
struct _Identity_generate_cond struct _Identity_generate_cond {
{ _Identity_generate_cond()
_Identity_generate_cond() {}
_Identity_generate_cond(unsigned char *sb,char *gm) : digest(sb),genmem(gm) {}
inline bool operator()(const ECC::Pair &kp) const
{ {
_computeMemoryHardHash(kp.pub.data,ZT_ECC_PUBLIC_KEY_SET_LEN,digest,genmem); }
_Identity_generate_cond(unsigned char* sb, char* gm) : digest(sb), genmem(gm)
{
}
inline bool operator()(const ECC::Pair& kp) const
{
_computeMemoryHardHash(kp.pub.data, ZT_ECC_PUBLIC_KEY_SET_LEN, digest, genmem);
return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN); return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN);
} }
unsigned char *digest; unsigned char* digest;
char *genmem; char* genmem;
}; };
void Identity::generate() void Identity::generate()
{ {
unsigned char digest[64]; unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY]; char* genmem = new char[ZT_IDENTITY_GEN_MEMORY];
ECC::Pair kp; ECC::Pair kp;
do { do {
kp = ECC::generateSatisfying(_Identity_generate_cond(digest,genmem)); kp = ECC::generateSatisfying(_Identity_generate_cond(digest, genmem));
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address _address.setTo(digest + 59, ZT_ADDRESS_LENGTH); // last 5 bytes are address
} while (_address.isReserved()); } while (_address.isReserved());
_publicKey = kp.pub; _publicKey = kp.pub;
if (!_privateKey) { if (! _privateKey) {
_privateKey = new ECC::Private(); _privateKey = new ECC::Private();
} }
*_privateKey = kp.priv; *_privateKey = kp.priv;
delete [] genmem; delete[] genmem;
} }
bool Identity::locallyValidate() const bool Identity::locallyValidate() const
@ -109,60 +113,54 @@ bool Identity::locallyValidate() const
} }
unsigned char digest[64]; unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY]; char* genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_publicKey.data,ZT_ECC_PUBLIC_KEY_SET_LEN,digest,genmem); _computeMemoryHardHash(_publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN, digest, genmem);
delete [] genmem; delete[] genmem;
unsigned char addrb[5]; unsigned char addrb[5];
_address.copyTo(addrb,5); _address.copyTo(addrb, 5);
return ( return ((digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN) && (digest[59] == addrb[0]) && (digest[60] == addrb[1]) && (digest[61] == addrb[2]) && (digest[62] == addrb[3]) && (digest[63] == addrb[4]));
(digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
(digest[59] == addrb[0])&&
(digest[60] == addrb[1])&&
(digest[61] == addrb[2])&&
(digest[62] == addrb[3])&&
(digest[63] == addrb[4]));
} }
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
{ {
char *p = buf; char* p = buf;
Utils::hex10(_address.toInt(),p); Utils::hex10(_address.toInt(), p);
p += 10; p += 10;
*(p++) = ':'; *(p++) = ':';
*(p++) = '0'; *(p++) = '0';
*(p++) = ':'; *(p++) = ':';
Utils::hex(_publicKey.data,ZT_ECC_PUBLIC_KEY_SET_LEN,p); Utils::hex(_publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN, p);
p += ZT_ECC_PUBLIC_KEY_SET_LEN * 2; p += ZT_ECC_PUBLIC_KEY_SET_LEN * 2;
if ((_privateKey)&&(includePrivate)) { if ((_privateKey) && (includePrivate)) {
*(p++) = ':'; *(p++) = ':';
Utils::hex(_privateKey->data,ZT_ECC_PRIVATE_KEY_SET_LEN,p); Utils::hex(_privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN, p);
p += ZT_ECC_PRIVATE_KEY_SET_LEN * 2; p += ZT_ECC_PRIVATE_KEY_SET_LEN * 2;
} }
*p = (char)0; *p = (char)0;
return buf; return buf;
} }
bool Identity::fromString(const char *str) bool Identity::fromString(const char* str)
{ {
if (!str) { if (! str) {
_address.zero(); _address.zero();
return false; return false;
} }
char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH]; char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH];
if (!Utils::scopy(tmp,sizeof(tmp),str)) { if (! Utils::scopy(tmp, sizeof(tmp), str)) {
_address.zero(); _address.zero();
return false; return false;
} }
delete _privateKey; delete _privateKey;
_privateKey = (ECC::Private *)0; _privateKey = (ECC::Private*)0;
int fno = 0; int fno = 0;
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) { for (char* f = Utils::stok(tmp, ":", &saveptr); (f); f = Utils::stok((char*)0, ":", &saveptr)) {
switch(fno++) { switch (fno++) {
case 0: case 0:
_address = Address(Utils::hexStrToU64(f)); _address = Address(Utils::hexStrToU64(f));
if (_address.isReserved()) { if (_address.isReserved()) {
@ -171,20 +169,20 @@ bool Identity::fromString(const char *str)
} }
break; break;
case 1: case 1:
if ((f[0] != '0')||(f[1])) { if ((f[0] != '0') || (f[1])) {
_address.zero(); _address.zero();
return false; return false;
} }
break; break;
case 2: case 2:
if (Utils::unhex(f,_publicKey.data,ZT_ECC_PUBLIC_KEY_SET_LEN) != ZT_ECC_PUBLIC_KEY_SET_LEN) { if (Utils::unhex(f, _publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN) != ZT_ECC_PUBLIC_KEY_SET_LEN) {
_address.zero(); _address.zero();
return false; return false;
} }
break; break;
case 3: case 3:
_privateKey = new ECC::Private(); _privateKey = new ECC::Private();
if (Utils::unhex(f,_privateKey->data,ZT_ECC_PRIVATE_KEY_SET_LEN) != ZT_ECC_PRIVATE_KEY_SET_LEN) { if (Utils::unhex(f, _privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN) != ZT_ECC_PRIVATE_KEY_SET_LEN) {
_address.zero(); _address.zero();
return false; return false;
} }

View file

@ -14,16 +14,16 @@
#ifndef ZT_IDENTITY_HPP #ifndef ZT_IDENTITY_HPP
#define ZT_IDENTITY_HPP #define ZT_IDENTITY_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "ECC.hpp"
#include "SHA512.hpp"
#include "Utils.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp"
#include "ECC.hpp"
#include "Buffer.hpp"
#include "SHA512.hpp"
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 384 #define ZT_IDENTITY_STRING_BUFFER_LENGTH 384
namespace ZeroTier { namespace ZeroTier {
@ -38,56 +38,49 @@ namespace ZeroTier {
* search for a different public key that duplicates an existing address. (See * search for a different public key that duplicates an existing address. (See
* code for deriveAddress() for this algorithm.) * code for deriveAddress() for this algorithm.)
*/ */
class Identity class Identity {
{ public:
public: Identity() : _privateKey((ECC::Private*)0)
Identity() :
_privateKey((ECC::Private *)0)
{ {
} }
Identity(const Identity &id) : Identity(const Identity& id) : _address(id._address), _publicKey(id._publicKey), _privateKey((id._privateKey) ? new ECC::Private(*(id._privateKey)) : (ECC::Private*)0)
_address(id._address),
_publicKey(id._publicKey),
_privateKey((id._privateKey) ? new ECC::Private(*(id._privateKey)) : (ECC::Private *)0)
{ {
} }
Identity(const char *str) : Identity(const char* str) : _privateKey((ECC::Private*)0)
_privateKey((ECC::Private *)0)
{ {
if (!fromString(str)) { if (! fromString(str)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
} }
} }
template<unsigned int C> template <unsigned int C> Identity(const Buffer<C>& b, unsigned int startAt = 0) : _privateKey((ECC::Private*)0)
Identity(const Buffer<C> &b,unsigned int startAt = 0) :
_privateKey((ECC::Private *)0)
{ {
deserialize(b,startAt); deserialize(b, startAt);
} }
~Identity() ~Identity()
{ {
if (_privateKey) { if (_privateKey) {
Utils::burn(_privateKey,sizeof(ECC::Private)); Utils::burn(_privateKey, sizeof(ECC::Private));
delete _privateKey; delete _privateKey;
} }
} }
inline Identity &operator=(const Identity &id) inline Identity& operator=(const Identity& id)
{ {
_address = id._address; _address = id._address;
_publicKey = id._publicKey; _publicKey = id._publicKey;
if (id._privateKey) { if (id._privateKey) {
if (!_privateKey) { if (! _privateKey) {
_privateKey = new ECC::Private(); _privateKey = new ECC::Private();
} }
*_privateKey = *(id._privateKey); *_privateKey = *(id._privateKey);
} else { }
else {
delete _privateKey; delete _privateKey;
_privateKey = (ECC::Private *)0; _privateKey = (ECC::Private*)0;
} }
return *this; return *this;
} }
@ -109,14 +102,17 @@ public:
/** /**
* @return True if this identity contains a private key * @return True if this identity contains a private key
*/ */
inline bool hasPrivate() const { return (_privateKey != (ECC::Private *)0); } inline bool hasPrivate() const
{
return (_privateKey != (ECC::Private*)0);
}
/** /**
* Compute a SHA384 hash of this identity's address and public key(s). * Compute a SHA384 hash of this identity's address and public key(s).
* *
* @param sha384buf Buffer with 48 bytes of space to receive hash * @param sha384buf Buffer with 48 bytes of space to receive hash
*/ */
inline void publicKeyHash(void *sha384buf) const inline void publicKeyHash(void* sha384buf) const
{ {
uint8_t address[ZT_ADDRESS_LENGTH]; uint8_t address[ZT_ADDRESS_LENGTH];
_address.copyTo(address, ZT_ADDRESS_LENGTH); _address.copyTo(address, ZT_ADDRESS_LENGTH);
@ -129,10 +125,10 @@ public:
* @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length) * @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length)
* @return True on success, false if no private key * @return True on success, false if no private key
*/ */
inline bool sha512PrivateKey(void *sha) const inline bool sha512PrivateKey(void* sha) const
{ {
if (_privateKey) { if (_privateKey) {
SHA512(sha,_privateKey->data,ZT_ECC_PRIVATE_KEY_SET_LEN); SHA512(sha, _privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN);
return true; return true;
} }
return false; return false;
@ -144,10 +140,10 @@ public:
* @param data Data to sign * @param data Data to sign
* @param len Length of data * @param len Length of data
*/ */
inline ECC::Signature sign(const void *data,unsigned int len) const inline ECC::Signature sign(const void* data, unsigned int len) const
{ {
if (_privateKey) { if (_privateKey) {
return ECC::sign(*_privateKey,_publicKey,data,len); return ECC::sign(*_privateKey, _publicKey, data, len);
} }
throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED; throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED;
} }
@ -161,12 +157,12 @@ 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 *signature,unsigned int siglen) const inline bool verify(const void* data, unsigned int len, const void* signature, unsigned int siglen) const
{ {
if (siglen != ZT_ECC_SIGNATURE_LEN) { if (siglen != ZT_ECC_SIGNATURE_LEN) {
return false; return false;
} }
return ECC::verify(_publicKey,data,len,signature); return ECC::verify(_publicKey, data, len, signature);
} }
/** /**
@ -177,9 +173,9 @@ public:
* @param signature Signature * @param signature Signature
* @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 ECC::Signature &signature) const inline bool verify(const void* data, unsigned int len, const ECC::Signature& signature) const
{ {
return ECC::verify(_publicKey,data,len,signature); return ECC::verify(_publicKey, data, len, signature);
} }
/** /**
@ -191,10 +187,10 @@ 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,void *const key) const inline bool agree(const Identity& id, void* const key) const
{ {
if (_privateKey) { if (_privateKey) {
ECC::agree(*_privateKey,id._publicKey,key,ZT_SYMMETRIC_KEY_SIZE); ECC::agree(*_privateKey, id._publicKey, key, ZT_SYMMETRIC_KEY_SIZE);
return true; return true;
} }
return false; return false;
@ -203,7 +199,10 @@ public:
/** /**
* @return This identity's address * @return This identity's address
*/ */
inline const Address &address() const { return _address; } inline const Address& address() const
{
return _address;
}
/** /**
* Serialize this identity (binary) * Serialize this identity (binary)
@ -212,16 +211,16 @@ public:
* @param includePrivate If true, include private key component (if present) (default: false) * @param includePrivate If true, include private key component (if present) (default: false)
* @throws std::out_of_range Buffer too small * @throws std::out_of_range Buffer too small
*/ */
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b, bool includePrivate = false) const
inline void serialize(Buffer<C> &b,bool includePrivate = false) const
{ {
_address.appendTo(b); _address.appendTo(b);
b.append((uint8_t)0); // C25519/Ed25519 identity type b.append((uint8_t)0); // C25519/Ed25519 identity type
b.append(_publicKey.data,ZT_ECC_PUBLIC_KEY_SET_LEN); b.append(_publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN);
if ((_privateKey)&&(includePrivate)) { if ((_privateKey) && (includePrivate)) {
b.append((unsigned char)ZT_ECC_PRIVATE_KEY_SET_LEN); b.append((unsigned char)ZT_ECC_PRIVATE_KEY_SET_LEN);
b.append(_privateKey->data,ZT_ECC_PRIVATE_KEY_SET_LEN); b.append(_privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN);
} else { }
else {
b.append((unsigned char)0); b.append((unsigned char)0);
} }
} }
@ -238,22 +237,21 @@ public:
* @throws std::out_of_range Serialized data invalid * @throws std::out_of_range Serialized data invalid
* @throws std::invalid_argument Serialized data invalid * @throws std::invalid_argument Serialized data invalid
*/ */
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
delete _privateKey; delete _privateKey;
_privateKey = (ECC::Private *)0; _privateKey = (ECC::Private*)0;
unsigned int p = startAt; unsigned int p = startAt;
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _address.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (b[p++] != 0) { if (b[p++] != 0) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
} }
memcpy(_publicKey.data,b.field(p,ZT_ECC_PUBLIC_KEY_SET_LEN),ZT_ECC_PUBLIC_KEY_SET_LEN); memcpy(_publicKey.data, b.field(p, ZT_ECC_PUBLIC_KEY_SET_LEN), ZT_ECC_PUBLIC_KEY_SET_LEN);
p += ZT_ECC_PUBLIC_KEY_SET_LEN; p += ZT_ECC_PUBLIC_KEY_SET_LEN;
unsigned int privateKeyLength = (unsigned int)b[p++]; unsigned int privateKeyLength = (unsigned int)b[p++];
@ -262,7 +260,7 @@ public:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} }
_privateKey = new ECC::Private(); _privateKey = new ECC::Private();
memcpy(_privateKey->data,b.field(p,ZT_ECC_PRIVATE_KEY_SET_LEN),ZT_ECC_PRIVATE_KEY_SET_LEN); memcpy(_privateKey->data, b.field(p, ZT_ECC_PRIVATE_KEY_SET_LEN), ZT_ECC_PRIVATE_KEY_SET_LEN);
p += ZT_ECC_PRIVATE_KEY_SET_LEN; p += ZT_ECC_PRIVATE_KEY_SET_LEN;
} }
@ -276,7 +274,7 @@ public:
* @param buf Buffer to store string * @param buf Buffer to store string
* @return ASCII string representation of identity * @return ASCII string representation of identity
*/ */
char *toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const; char* toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
/** /**
* Deserialize a human-friendly string * Deserialize a human-friendly string
@ -287,12 +285,15 @@ public:
* @param str String to deserialize * @param str String to deserialize
* @return True if deserialization appears successful * @return True if deserialization appears successful
*/ */
bool fromString(const char *str); bool fromString(const char* str);
/** /**
* @return C25519 public key * @return C25519 public key
*/ */
inline const ECC::Public &publicKey() const { return _publicKey; } inline const ECC::Public& publicKey() const
{
return _publicKey;
}
/** /**
* @return C25519 key pair (only returns valid pair if private key is present in this Identity object) * @return C25519 key pair (only returns valid pair if private key is present in this Identity object)
@ -303,8 +304,9 @@ public:
pair.pub = _publicKey; pair.pub = _publicKey;
if (_privateKey) { if (_privateKey) {
pair.priv = *_privateKey; pair.priv = *_privateKey;
} else { }
memset(pair.priv.data,0,ZT_ECC_PRIVATE_KEY_SET_LEN); else {
memset(pair.priv.data, 0, ZT_ECC_PRIVATE_KEY_SET_LEN);
} }
return pair; return pair;
} }
@ -312,19 +314,40 @@ public:
/** /**
* @return True if this identity contains something * @return True if this identity contains something
*/ */
inline operator bool() const { return (_address); } inline operator bool() const
{
return (_address);
}
inline bool operator==(const Identity &id) const { return ((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_ECC_PUBLIC_KEY_SET_LEN) == 0)); } inline bool operator==(const Identity& id) const
inline bool operator<(const Identity &id) const { return ((_address < id._address)||((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_ECC_PUBLIC_KEY_SET_LEN) < 0))); } {
inline bool operator!=(const Identity &id) const { return !(*this == id); } return ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN) == 0));
inline bool operator>(const Identity &id) const { return (id < *this); } }
inline bool operator<=(const Identity &id) const { return !(id < *this); } inline bool operator<(const Identity& id) const
inline bool operator>=(const Identity &id) const { return !(*this < id); } {
return ((_address < id._address) || ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN) < 0)));
}
inline bool operator!=(const Identity& id) const
{
return ! (*this == id);
}
inline bool operator>(const Identity& id) const
{
return (id < *this);
}
inline bool operator<=(const Identity& id) const
{
return ! (id < *this);
}
inline bool operator>=(const Identity& id) const
{
return ! (*this < id);
}
private: private:
Address _address; Address _address;
ECC::Public _publicKey; ECC::Public _publicKey;
ECC::Private *_privateKey; ECC::Private* _privateKey;
}; };
} // namespace ZeroTier } // namespace ZeroTier

File diff suppressed because it is too large Load diff

View file

@ -14,13 +14,13 @@
#ifndef ZT_INCOMINGPACKET_HPP #ifndef ZT_INCOMINGPACKET_HPP
#define ZT_INCOMINGPACKET_HPP #define ZT_INCOMINGPACKET_HPP
#include <stdexcept> #include "MulticastGroup.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include "Path.hpp" #include "Path.hpp"
#include "Utils.hpp"
#include "MulticastGroup.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "Utils.hpp"
#include <stdexcept>
/* /*
* The big picture: * The big picture:
@ -46,14 +46,9 @@ class Network;
/** /**
* Subclass of packet that handles the decoding of it * Subclass of packet that handles the decoding of it
*/ */
class IncomingPacket : public Packet class IncomingPacket : public Packet {
{ public:
public: IncomingPacket() : Packet(), _receiveTime(0), _path(), _authenticated(false)
IncomingPacket() :
Packet(),
_receiveTime(0),
_path(),
_authenticated(false)
{ {
} }
@ -66,11 +61,7 @@ public:
* @param now Current time * @param now Current time
* @throws std::out_of_range Range error processing packet * @throws std::out_of_range Range error processing packet
*/ */
IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) : IncomingPacket(const void* data, unsigned int len, const SharedPtr<Path>& path, int64_t now) : Packet(data, len), _receiveTime(now), _path(path), _authenticated(false)
Packet(data,len),
_receiveTime(now),
_path(path),
_authenticated(false)
{ {
} }
@ -83,9 +74,9 @@ public:
* @param now Current time * @param now Current time
* @throws std::out_of_range Range error processing packet * @throws std::out_of_range Range error processing packet
*/ */
inline void init(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) inline void init(const void* data, unsigned int len, const SharedPtr<Path>& path, int64_t now)
{ {
copyFrom(data,len); copyFrom(data, len);
_receiveTime = now; _receiveTime = now;
_path = path; _path = path;
_authenticated = false; _authenticated = false;
@ -104,38 +95,41 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return True if decoding and processing is complete, false if caller should try again * @return True if decoding and processing is complete, false if caller should try again
*/ */
bool tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t flowId); bool tryDecode(const RuntimeEnvironment* RR, void* tPtr, int32_t flowId);
/** /**
* @return Time of packet receipt / start of decode * @return Time of packet receipt / start of decode
*/ */
inline uint64_t receiveTime() const { return _receiveTime; } inline uint64_t receiveTime() const
{
return _receiveTime;
}
private: private:
// These are called internally to handle packet contents once it has // These are called internally to handle packet contents once it has
// been authenticated, decrypted, decompressed, and classified. // been authenticated, decrypted, decompressed, and classified.
bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doERROR(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated); bool _doHELLO(const RuntimeEnvironment* RR, void* tPtr, const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doOK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doWHOIS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doRENDEZVOUS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId); bool _doFRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, int32_t flowId);
bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId); bool _doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, int32_t flowId);
bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doECHO(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doMULTICAST_LIKE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doNETWORK_CONFIG(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doMULTICAST_GATHER(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doUSER_MESSAGE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doREMOTE_TRACE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid); void _sendErrorNeedCredentials(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, const uint64_t nwid);
uint64_t _receiveTime; uint64_t _receiveTime;
SharedPtr<Path> _path; SharedPtr<Path> _path;

View file

@ -11,28 +11,27 @@
*/ */
/****/ /****/
#include <stdio.h> #include "InetAddress.hpp"
#include <string.h>
#include <stdint.h>
#include <string>
#include "Constants.hpp" #include "Constants.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
namespace ZeroTier { namespace ZeroTier {
const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,0); const InetAddress InetAddress::LO4((const void*)("\x7f\x00\x00\x01"), 4, 0);
const InetAddress InetAddress::LO6((const void *)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"),16,0); const InetAddress InetAddress::LO6((const void*)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0);
InetAddress::IpScope InetAddress::ipScope() const InetAddress::IpScope InetAddress::ipScope() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr); const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr);
switch(ip >> 24) { switch (ip >> 24) {
case 0x00: case 0x00:
return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
case 0x06: case 0x06:
@ -102,7 +101,7 @@ InetAddress::IpScope InetAddress::ipScope() const
case 0xff: case 0xff:
return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
} }
switch(ip >> 28) { switch (ip >> 28) {
case 0xe: case 0xe:
return IP_SCOPE_MULTICAST; // 224.0.0.0/4 return IP_SCOPE_MULTICAST; // 224.0.0.0/4
case 0xf: case 0xf:
@ -112,19 +111,20 @@ InetAddress::IpScope InetAddress::ipScope() const
} break; } break;
case AF_INET6: { case AF_INET6: {
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); const unsigned char* ip = reinterpret_cast<const unsigned char*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
if ((ip[0] & 0xf0) == 0xf0) { if ((ip[0] & 0xf0) == 0xf0) {
if (ip[0] == 0xff) { if (ip[0] == 0xff) {
return IP_SCOPE_MULTICAST; // ff00::/8 return IP_SCOPE_MULTICAST; // ff00::/8
} }
if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) { if ((ip[0] == 0xfe) && ((ip[1] & 0xc0) == 0x80)) {
unsigned int k = 2; unsigned int k = 2;
while ((!ip[k])&&(k < 15)) { while ((! ip[k]) && (k < 15)) {
++k; ++k;
} }
if ((k == 15)&&(ip[15] == 0x01)) { if ((k == 15) && (ip[15] == 0x01)) {
return IP_SCOPE_LOOPBACK; // fe80::1/128 return IP_SCOPE_LOOPBACK; // fe80::1/128
} else { }
else {
return IP_SCOPE_LINK_LOCAL; // fe80::/10 return IP_SCOPE_LINK_LOCAL; // fe80::/10
} }
} }
@ -136,7 +136,7 @@ InetAddress::IpScope InetAddress::ipScope() const
// :::ffff:127.0.0.1 // :::ffff:127.0.0.1
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1 // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1
unsigned int k = 0; unsigned int k = 0;
while ((!ip[k])&&(k < 9)) { while ((! ip[k]) && (k < 9)) {
++k; ++k;
} }
if (k == 9) { if (k == 9) {
@ -146,7 +146,7 @@ InetAddress::IpScope InetAddress::ipScope() const
} }
k = 0; k = 0;
while ((!ip[k])&&(k < 15)) { while ((! ip[k]) && (k < 15)) {
++k; ++k;
} }
if (k == 15) { // all 0's except last byte if (k == 15) { // all 0's except last byte
@ -159,79 +159,79 @@ InetAddress::IpScope InetAddress::ipScope() const
} }
return IP_SCOPE_GLOBAL; return IP_SCOPE_GLOBAL;
} break; } break;
} }
return IP_SCOPE_NONE; return IP_SCOPE_NONE;
} }
void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port) void InetAddress::set(const void* ipBytes, unsigned int ipLen, unsigned int port)
{ {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
if (ipLen == 4) { if (ipLen == 4) {
uint32_t ipb[1]; uint32_t ipb[1];
memcpy(ipb,ipBytes,4); memcpy(ipb, ipBytes, 4);
ss_family = AF_INET; ss_family = AF_INET;
reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr = ipb[0]; reinterpret_cast<struct sockaddr_in*>(this)->sin_addr.s_addr = ipb[0];
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port); reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton((uint16_t)port);
} else if (ipLen == 16) { }
else if (ipLen == 16) {
ss_family = AF_INET6; ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes,16); memcpy(reinterpret_cast<struct sockaddr_in6*>(this)->sin6_addr.s6_addr, ipBytes, 16);
reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port); reinterpret_cast<struct sockaddr_in6*>(this)->sin6_port = Utils::hton((uint16_t)port);
} }
} }
char *InetAddress::toString(char buf[64]) const char* InetAddress::toString(char buf[64]) const
{ {
char *p = toIpString(buf); char* p = toIpString(buf);
if (*p) { if (*p) {
while (*p) { while (*p) {
++p; ++p;
} }
*(p++) = '/'; *(p++) = '/';
Utils::decimal(port(),p); Utils::decimal(port(), p);
} }
return buf; return buf;
} }
char *InetAddress::toIpString(char buf[64]) const char* InetAddress::toIpString(char buf[64]) const
{ {
buf[0] = (char)0; buf[0] = (char)0;
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
#ifdef _WIN32 #ifdef _WIN32
inet_ntop(AF_INET, (void*)&reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN); inet_ntop(AF_INET, (void*)&reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#else #else
inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN); inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#endif #endif
} break; } break;
case AF_INET6: { case AF_INET6: {
#ifdef _WIN32 #ifdef _WIN32
inet_ntop(AF_INET6, (void*)reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, (void*)reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#else #else
inet_ntop(AF_INET6, reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#endif #endif
} break; } break;
} }
return buf; return buf;
} }
bool InetAddress::fromString(const char *ipSlashPort) bool InetAddress::fromString(const char* ipSlashPort)
{ {
char buf[64]; char buf[64];
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
if (!*ipSlashPort) { if (! *ipSlashPort) {
return true; return true;
} }
if (!Utils::scopy(buf,sizeof(buf),ipSlashPort)) { if (! Utils::scopy(buf, sizeof(buf), ipSlashPort)) {
return false; return false;
} }
char *portAt = buf; char* portAt = buf;
while ((*portAt)&&(*portAt != '/')) { while ((*portAt) && (*portAt != '/')) {
++portAt; ++portAt;
} }
unsigned int port = 0; unsigned int port = 0;
@ -240,19 +240,21 @@ bool InetAddress::fromString(const char *ipSlashPort)
port = Utils::strToUInt(portAt) & 0xffff; port = Utils::strToUInt(portAt) & 0xffff;
} }
if (strchr(buf,':')) { if (strchr(buf, ':')) {
struct sockaddr_in6 *const in6 = reinterpret_cast<struct sockaddr_in6 *>(this); struct sockaddr_in6* const in6 = reinterpret_cast<struct sockaddr_in6*>(this);
inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr); inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr);
in6->sin6_family = AF_INET6; in6->sin6_family = AF_INET6;
in6->sin6_port = Utils::hton((uint16_t)port); in6->sin6_port = Utils::hton((uint16_t)port);
return true; return true;
} else if (strchr(buf,'.')) { }
struct sockaddr_in *const in = reinterpret_cast<struct sockaddr_in *>(this); else if (strchr(buf, '.')) {
struct sockaddr_in* const in = reinterpret_cast<struct sockaddr_in*>(this);
inet_pton(AF_INET, buf, &in->sin_addr.s_addr); inet_pton(AF_INET, buf, &in->sin_addr.s_addr);
in->sin_family = AF_INET; in->sin_family = AF_INET;
in->sin_port = Utils::hton((uint16_t)port); in->sin_port = Utils::hton((uint16_t)port);
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@ -260,21 +262,22 @@ bool InetAddress::fromString(const char *ipSlashPort)
InetAddress InetAddress::netmask() const InetAddress InetAddress::netmask() const
{ {
InetAddress r(*this); InetAddress r(*this);
switch(r.ss_family) { switch (r.ss_family) {
case AF_INET: case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
break; break;
case AF_INET6: { case AF_INET6: {
uint64_t nm[2]; uint64_t nm[2];
const unsigned int bits = netmaskBits(); const unsigned int bits = netmaskBits();
if(bits) { if (bits) {
nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
} else { }
else {
nm[0] = 0; nm[0] = 0;
nm[1] = 0; nm[1] = 0;
} }
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16); memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break; } break;
} }
return r; return r;
@ -284,7 +287,7 @@ InetAddress InetAddress::broadcast() const
{ {
if (ss_family == AF_INET) { if (ss_family == AF_INET) {
InetAddress r(*this); InetAddress r(*this);
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits())); reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
return r; return r;
} }
return InetAddress(); return InetAddress();
@ -293,34 +296,34 @@ InetAddress InetAddress::broadcast() const
InetAddress InetAddress::network() const InetAddress InetAddress::network() const
{ {
InetAddress r(*this); InetAddress r(*this);
switch(r.ss_family) { switch (r.ss_family) {
case AF_INET: case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
break; break;
case AF_INET6: { case AF_INET6: {
uint64_t nm[2]; uint64_t nm[2];
const unsigned int bits = netmaskBits(); const unsigned int bits = netmaskBits();
memcpy(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16); memcpy(nm, reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, 16);
nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16); memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break; } break;
} }
return r; return r;
} }
bool InetAddress::isEqualPrefix(const InetAddress &addr) const bool InetAddress::isEqualPrefix(const InetAddress& addr) const
{ {
if (addr.ss_family == ss_family) { if (addr.ss_family == ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET6: { case AF_INET6: {
const InetAddress mask(netmask()); const InetAddress mask(netmask());
InetAddress addr_mask(addr.netmask()); InetAddress addr_mask(addr.netmask());
const uint8_t *n = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr_mask)->sin6_addr.s6_addr); const uint8_t* n = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&addr_mask)->sin6_addr.s6_addr);
const uint8_t *m = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&mask)->sin6_addr.s6_addr); const uint8_t* m = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&mask)->sin6_addr.s6_addr);
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr); const uint8_t* a = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&addr)->sin6_addr.s6_addr);
const uint8_t *b = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); const uint8_t* b = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
for(unsigned int i=0;i<16;++i) { for (unsigned int i = 0; i < 16; ++i) {
if ((a[i] & m[i]) != (b[i] & n[i])) { if ((a[i] & m[i]) != (b[i] & n[i])) {
return false; return false;
} }
@ -332,23 +335,24 @@ bool InetAddress::isEqualPrefix(const InetAddress &addr) const
return false; return false;
} }
bool InetAddress::containsAddress(const InetAddress &addr) const bool InetAddress::containsAddress(const InetAddress& addr) const
{ {
if (addr.ss_family == ss_family) { if (addr.ss_family == ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
const unsigned int bits = netmaskBits(); const unsigned int bits = netmaskBits();
if (bits == 0) { if (bits == 0) {
return true; return true;
} }
return ( (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) >> (32 - bits)) ); return (
(Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr) >> (32 - bits)));
} }
case AF_INET6: { case AF_INET6: {
const InetAddress mask(netmask()); const InetAddress mask(netmask());
const uint8_t *m = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&mask)->sin6_addr.s6_addr); const uint8_t* m = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&mask)->sin6_addr.s6_addr);
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr); const uint8_t* a = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&addr)->sin6_addr.s6_addr);
const uint8_t *b = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); const uint8_t* b = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
for(unsigned int i=0;i<16;++i) { for (unsigned int i = 0; i < 16; ++i) {
if ((a[i] & m[i]) != b[i]) { if ((a[i] & m[i]) != b[i]) {
return false; return false;
} }
@ -362,7 +366,7 @@ bool InetAddress::containsAddress(const InetAddress &addr) const
bool InetAddress::isNetwork() const bool InetAddress::isNetwork() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
unsigned int bits = netmaskBits(); unsigned int bits = netmaskBits();
if (bits <= 0) { if (bits <= 0) {
@ -371,7 +375,7 @@ bool InetAddress::isNetwork() const
if (bits >= 32) { if (bits >= 32) {
return false; return false;
} }
uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr); uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr);
return ((ip & (0xffffffff >> bits)) == 0); return ((ip & (0xffffffff >> bits)) == 0);
} }
case AF_INET6: { case AF_INET6: {
@ -382,7 +386,7 @@ bool InetAddress::isNetwork() const
if (bits >= 128) { if (bits >= 128) {
return false; return false;
} }
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); const unsigned char* ip = reinterpret_cast<const unsigned char*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
unsigned int p = bits / 8; unsigned int p = bits / 8;
if ((ip[p++] & (0xff >> (bits % 8))) != 0) { if ((ip[p++] & (0xff >> (bits % 8))) != 0) {
return false; return false;
@ -398,55 +402,60 @@ bool InetAddress::isNetwork() const
return false; return false;
} }
bool InetAddress::operator==(const InetAddress &a) const bool InetAddress::operator==(const InetAddress& a) const
{ {
if (ss_family == a.ss_family) { if (ss_family == a.ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
return ( return (
(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port)&& (reinterpret_cast<const struct sockaddr_in*>(this)->sin_port == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_port)
(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr)); && (reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_addr.s_addr));
break; break;
case AF_INET6: case AF_INET6:
return ( return (
(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port)&& (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_port)
(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo)&& && (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_flowinfo)
(memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0)&& && (memcmp(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_addr.s6_addr, 16) == 0)
(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_scope_id == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_scope_id)); && (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_scope_id == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_scope_id));
break; break;
default: default:
return (memcmp(this,&a,sizeof(InetAddress)) == 0); return (memcmp(this, &a, sizeof(InetAddress)) == 0);
} }
} }
return false; return false;
} }
bool InetAddress::operator<(const InetAddress &a) const bool InetAddress::operator<(const InetAddress& a) const
{ {
if (ss_family < a.ss_family) { if (ss_family < a.ss_family) {
return true; return true;
} else if (ss_family == a.ss_family) { }
switch(ss_family) { else if (ss_family == a.ss_family) {
switch (ss_family) {
case AF_INET: case AF_INET:
if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port) { if (reinterpret_cast<const struct sockaddr_in*>(this)->sin_port < reinterpret_cast<const struct sockaddr_in*>(&a)->sin_port) {
return true; return true;
} else if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port) { }
if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr) { else if (reinterpret_cast<const struct sockaddr_in*>(this)->sin_port == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_port) {
if (reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr < reinterpret_cast<const struct sockaddr_in*>(&a)->sin_addr.s_addr) {
return true; return true;
} }
} }
break; break;
case AF_INET6: case AF_INET6:
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port) { if (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port < reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_port) {
return true; return true;
} else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port) { }
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo) { else if (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_port) {
if (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_flowinfo < reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_flowinfo) {
return true; return true;
} else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo) { }
if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) < 0) { else if (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_flowinfo) {
if (memcmp(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_addr.s6_addr, 16) < 0) {
return true; return true;
} else if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0) { }
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_scope_id < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_scope_id) { else if (memcmp(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_addr.s6_addr, 16) == 0) {
if (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_scope_id < reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_scope_id) {
return true; return true;
} }
} }
@ -454,13 +463,13 @@ bool InetAddress::operator<(const InetAddress &a) const
} }
break; break;
default: default:
return (memcmp(this,&a,sizeof(InetAddress)) < 0); return (memcmp(this, &a, sizeof(InetAddress)) < 0);
} }
} }
return false; return false;
} }
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) InetAddress InetAddress::makeIpv6LinkLocal(const MAC& mac)
{ {
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
sin6.sin6_family = AF_INET6; sin6.sin6_family = AF_INET6;
@ -484,10 +493,10 @@ InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
return InetAddress(sin6); return InetAddress(sin6);
} }
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress) InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress)
{ {
InetAddress r; InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r); struct sockaddr_in6* const sin6 = reinterpret_cast<struct 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 >> 56); sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56);
@ -509,11 +518,11 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
return r; return r;
} }
InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress) InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress)
{ {
nwid ^= (nwid >> 32); nwid ^= (nwid >> 32);
InetAddress r; InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r); struct sockaddr_in6* const sin6 = reinterpret_cast<struct 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 >> 24); sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24);

View file

@ -14,15 +14,15 @@
#ifndef ZT_INETADDRESS_HPP #ifndef ZT_INETADDRESS_HPP
#define ZT_INETADDRESS_HPP #define ZT_INETADDRESS_HPP
#include "../include/ZeroTierOne.h"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "MAC.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Utils.hpp"
#include "MAC.hpp"
#include "Buffer.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -39,8 +39,7 @@ namespace ZeroTier {
* sockaddr_storage and used interchangeably. DO NOT change this by e.g. * sockaddr_storage and used interchangeably. DO NOT change this by e.g.
* adding non-static fields, since much code depends on this identity. * adding non-static fields, since much code depends on this identity.
*/ */
struct InetAddress : public sockaddr_storage struct InetAddress : public sockaddr_storage {
{
/** /**
* Loopback IPv4 address (no port) * Loopback IPv4 address (no port)
*/ */
@ -58,8 +57,7 @@ struct InetAddress : public sockaddr_storage
* MUST remain that way or Path must be changed to reflect. Also be sure * MUST remain that way or Path must be changed to reflect. Also be sure
* to change ZT_INETADDRESS_MAX_SCOPE if the max changes. * to change ZT_INETADDRESS_MAX_SCOPE if the max changes.
*/ */
enum IpScope enum IpScope {
{
IP_SCOPE_NONE = 0, // NULL or not an IP address IP_SCOPE_NONE = 0, // NULL or not an IP address
IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs
IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc.
@ -72,120 +70,164 @@ struct InetAddress : public sockaddr_storage
// Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core // Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core
// but this is safe to put here. // but this is safe to put here.
struct Hasher struct Hasher {
inline std::size_t operator()(const InetAddress& a) const
{ {
inline std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); } return (std::size_t)a.hashCode();
}
}; };
InetAddress() { memset(this,0,sizeof(InetAddress)); } InetAddress()
InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); } {
InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); } memset(this, 0, sizeof(InetAddress));
InetAddress(const struct sockaddr_storage &ss) { *this = ss; } }
InetAddress(const struct sockaddr_storage *ss) { *this = ss; } InetAddress(const InetAddress& a)
InetAddress(const struct sockaddr &sa) { *this = sa; } {
InetAddress(const struct sockaddr *sa) { *this = sa; } memcpy(this, &a, sizeof(InetAddress));
InetAddress(const struct sockaddr_in &sa) { *this = sa; } }
InetAddress(const struct sockaddr_in *sa) { *this = sa; } InetAddress(const InetAddress* a)
InetAddress(const struct sockaddr_in6 &sa) { *this = sa; } {
InetAddress(const struct sockaddr_in6 *sa) { *this = sa; } memcpy(this, a, sizeof(InetAddress));
InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); } }
InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); } InetAddress(const struct sockaddr_storage& ss)
InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); } {
*this = ss;
}
InetAddress(const struct sockaddr_storage* ss)
{
*this = ss;
}
InetAddress(const struct sockaddr& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr* sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in* sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in6& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in6* sa)
{
*this = sa;
}
InetAddress(const void* ipBytes, unsigned int ipLen, unsigned int port)
{
this->set(ipBytes, ipLen, port);
}
InetAddress(const uint32_t ipv4, unsigned int port)
{
this->set(&ipv4, 4, port);
}
InetAddress(const char* ipSlashPort)
{
this->fromString(ipSlashPort);
}
inline InetAddress &operator=(const InetAddress &a) inline InetAddress& operator=(const InetAddress& a)
{ {
if (&a != this) { if (&a != this) {
memcpy(this,&a,sizeof(InetAddress)); memcpy(this, &a, sizeof(InetAddress));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const InetAddress *a) inline InetAddress& operator=(const InetAddress* a)
{ {
if (a != this) { if (a != this) {
memcpy(this,a,sizeof(InetAddress)); memcpy(this, a, sizeof(InetAddress));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr_storage &ss) inline InetAddress& operator=(const struct sockaddr_storage& ss)
{ {
if (reinterpret_cast<const InetAddress *>(&ss) != this) { if (reinterpret_cast<const InetAddress*>(&ss) != this) {
memcpy(this,&ss,sizeof(InetAddress)); memcpy(this, &ss, sizeof(InetAddress));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr_storage *ss) inline InetAddress& operator=(const struct sockaddr_storage* ss)
{ {
if (reinterpret_cast<const InetAddress *>(ss) != this) { if (reinterpret_cast<const InetAddress*>(ss) != this) {
memcpy(this,ss,sizeof(InetAddress)); memcpy(this, ss, sizeof(InetAddress));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr_in &sa) inline InetAddress& operator=(const struct sockaddr_in& sa)
{ {
if (reinterpret_cast<const InetAddress *>(&sa) != this) { if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in)); memcpy(this, &sa, sizeof(struct sockaddr_in));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr_in *sa) inline InetAddress& operator=(const struct sockaddr_in* sa)
{ {
if (reinterpret_cast<const InetAddress *>(sa) != this) { if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in)); memcpy(this, sa, sizeof(struct sockaddr_in));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr_in6 &sa) inline InetAddress& operator=(const struct sockaddr_in6& sa)
{ {
if (reinterpret_cast<const InetAddress *>(&sa) != this) { if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in6)); memcpy(this, &sa, sizeof(struct sockaddr_in6));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr_in6 *sa) inline InetAddress& operator=(const struct sockaddr_in6* sa)
{ {
if (reinterpret_cast<const InetAddress *>(sa) != this) { if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in6)); memcpy(this, sa, sizeof(struct sockaddr_in6));
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr &sa) inline InetAddress& operator=(const struct sockaddr& sa)
{ {
if (reinterpret_cast<const InetAddress *>(&sa) != this) { if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
switch(sa.sa_family) { switch (sa.sa_family) {
case AF_INET: case AF_INET:
memcpy(this,&sa,sizeof(struct sockaddr_in)); memcpy(this, &sa, sizeof(struct sockaddr_in));
break; break;
case AF_INET6: case AF_INET6:
memcpy(this,&sa,sizeof(struct sockaddr_in6)); memcpy(this, &sa, sizeof(struct sockaddr_in6));
break; break;
} }
} }
return *this; return *this;
} }
inline InetAddress &operator=(const struct sockaddr *sa) inline InetAddress& operator=(const struct sockaddr* sa)
{ {
if (reinterpret_cast<const InetAddress *>(sa) != this) { if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
switch(sa->sa_family) { switch (sa->sa_family) {
case AF_INET: case AF_INET:
memcpy(this,sa,sizeof(struct sockaddr_in)); memcpy(this, sa, sizeof(struct sockaddr_in));
break; break;
case AF_INET6: case AF_INET6:
memcpy(this,sa,sizeof(struct sockaddr_in6)); memcpy(this, sa, sizeof(struct sockaddr_in6));
break; break;
} }
} }
@ -204,7 +246,7 @@ struct InetAddress : public sockaddr_storage
* @param ipLen Length of IP address: 4 or 16 * @param ipLen Length of IP address: 4 or 16
* @param port Port number or 0 for none * @param port Port number or 0 for none
*/ */
void set(const void *ipBytes,unsigned int ipLen,unsigned int port); void set(const void* ipBytes, unsigned int ipLen, unsigned int port);
/** /**
* Set the port component * Set the port component
@ -213,12 +255,12 @@ struct InetAddress : public sockaddr_storage
*/ */
inline void setPort(unsigned int port) inline void setPort(unsigned int port)
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port); reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton((uint16_t)port);
break; break;
case AF_INET6: case AF_INET6:
reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port); reinterpret_cast<struct sockaddr_in6*>(this)->sin6_port = Utils::hton((uint16_t)port);
break; break;
} }
} }
@ -228,17 +270,17 @@ struct InetAddress : public sockaddr_storage
*/ */
inline bool isDefaultRoute() const inline bool isDefaultRoute() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
return ( (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == 0) ); return ((reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<const struct sockaddr_in*>(this)->sin_port == 0));
case AF_INET6: case AF_INET6:
const uint8_t *ipb = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); const uint8_t* ipb = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
for(int i=0;i<16;++i) { for (int i = 0; i < 16; ++i) {
if (ipb[i]) { if (ipb[i]) {
return false; return false;
} }
} }
return (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == 0); return (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port == 0);
} }
return false; return false;
} }
@ -246,29 +288,29 @@ struct InetAddress : public sockaddr_storage
/** /**
* @return ASCII IP/port format representation * @return ASCII IP/port format representation
*/ */
char *toString(char buf[64]) const; char* toString(char buf[64]) const;
/** /**
* @return IP portion only, in ASCII string format * @return IP portion only, in ASCII string format
*/ */
char *toIpString(char buf[64]) const; char* toIpString(char buf[64]) const;
/** /**
* @param ipSlashPort IP/port (port is optional, will be 0 if not included) * @param ipSlashPort IP/port (port is optional, will be 0 if not included)
* @return True if address appeared to be valid * @return True if address appeared to be valid
*/ */
bool fromString(const char *ipSlashPort); bool fromString(const char* ipSlashPort);
/** /**
* @return Port or 0 if no port component defined * @return Port or 0 if no port component defined
*/ */
inline unsigned int port() const inline unsigned int port() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port)); return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in*>(this)->sin_port));
case AF_INET6: case AF_INET6:
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port)); return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port));
default: default:
return 0; return 0;
} }
@ -283,7 +325,10 @@ struct InetAddress : public sockaddr_storage
* *
* @return Netmask bits * @return Netmask bits
*/ */
inline unsigned int netmaskBits() const { return port(); } inline unsigned int netmaskBits() const
{
return port();
}
/** /**
* @return True if netmask bits is valid for the address type * @return True if netmask bits is valid for the address type
@ -291,7 +336,7 @@ struct InetAddress : public sockaddr_storage
inline bool netmaskBitsValid() const inline bool netmaskBitsValid() const
{ {
const unsigned int n = port(); const unsigned int n = port();
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
return (n <= 32); return (n <= 32);
case AF_INET6: case AF_INET6:
@ -308,7 +353,10 @@ struct InetAddress : public sockaddr_storage
* *
* @return Gateway metric * @return Gateway metric
*/ */
inline unsigned int metric() const { return port(); } inline unsigned int metric() const
{
return port();
}
/** /**
* Construct a full netmask as an InetAddress * Construct a full netmask as an InetAddress
@ -340,7 +388,7 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check * @param addr Address to check
* @return True if this IPv6 prefix matches the prefix of a given IPv6 address * @return True if this IPv6 prefix matches the prefix of a given IPv6 address
*/ */
bool isEqualPrefix(const InetAddress &addr) const; bool isEqualPrefix(const InetAddress& addr) const;
/** /**
* Test whether this IP/netmask contains this address * Test whether this IP/netmask contains this address
@ -348,28 +396,34 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check * @param addr Address to check
* @return True if this IP/netmask (route) contains this address * @return True if this IP/netmask (route) contains this address
*/ */
bool containsAddress(const InetAddress &addr) const; bool containsAddress(const InetAddress& addr) const;
/** /**
* @return True if this is an IPv4 address * @return True if this is an IPv4 address
*/ */
inline bool isV4() const { return (ss_family == AF_INET); } inline bool isV4() const
{
return (ss_family == AF_INET);
}
/** /**
* @return True if this is an IPv6 address * @return True if this is an IPv6 address
*/ */
inline bool isV6() const { return (ss_family == AF_INET6); } inline bool isV6() const
{
return (ss_family == AF_INET6);
}
/** /**
* @return pointer to raw address bytes or NULL if not available * @return pointer to raw address bytes or NULL if not available
*/ */
inline const void *rawIpData() const inline const void* rawIpData() const
{ {
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr); return (const void*)&(reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr);
case AF_INET6: case AF_INET6:
return (const void *)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); return (const void*)(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
default: default:
return 0; return 0;
} }
@ -381,14 +435,14 @@ struct InetAddress : public sockaddr_storage
inline InetAddress ipOnly() const inline InetAddress ipOnly() const
{ {
InetAddress r; InetAddress r;
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
r.ss_family = AF_INET; r.ss_family = AF_INET;
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr; reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr = reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr;
break; break;
case AF_INET6: case AF_INET6:
r.ss_family = AF_INET6; r.ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16); memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, 16);
break; break;
} }
return r; return r;
@ -400,16 +454,16 @@ struct InetAddress : public sockaddr_storage
* @param a InetAddress to compare again * @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses) * @return True if only IP portions are equal (false for non-IP or null addresses)
*/ */
inline bool ipsEqual(const InetAddress &a) const inline bool ipsEqual(const InetAddress& a) const
{ {
if (ss_family == a.ss_family) { if (ss_family == a.ss_family) {
if (ss_family == AF_INET) { if (ss_family == AF_INET) {
return (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr); return (reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_addr.s_addr);
} }
if (ss_family == AF_INET6) { if (ss_family == AF_INET6) {
return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0); return (memcmp(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_addr.s6_addr, 16) == 0);
} }
return (memcmp(this,&a,sizeof(InetAddress)) == 0); return (memcmp(this, &a, sizeof(InetAddress)) == 0);
} }
return false; return false;
} }
@ -422,16 +476,16 @@ struct InetAddress : public sockaddr_storage
* @param a InetAddress to compare again * @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses) * @return True if only IP portions are equal (false for non-IP or null addresses)
*/ */
inline bool ipsEqual2(const InetAddress &a) const inline bool ipsEqual2(const InetAddress& a) const
{ {
if (ss_family == a.ss_family) { if (ss_family == a.ss_family) {
if (ss_family == AF_INET) { if (ss_family == AF_INET) {
return (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr); return (reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_addr.s_addr);
} }
if (ss_family == AF_INET6) { if (ss_family == AF_INET6) {
return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr, 8) == 0); return (memcmp(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_addr.s6_addr, 8) == 0);
} }
return (memcmp(this,&a,sizeof(InetAddress)) == 0); return (memcmp(this, &a, sizeof(InetAddress)) == 0);
} }
return false; return false;
} }
@ -439,19 +493,21 @@ struct InetAddress : public sockaddr_storage
inline unsigned long hashCode() const inline unsigned long hashCode() const
{ {
if (ss_family == AF_INET) { if (ss_family == AF_INET) {
return ((unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_port); return ((unsigned long)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast<const struct sockaddr_in*>(this)->sin_port);
} else if (ss_family == AF_INET6) { }
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port; else if (ss_family == AF_INET6) {
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); unsigned long tmp = reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port;
for(long i=0;i<16;++i) { const uint8_t* a = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i]; for (long i = 0; i < 16; ++i) {
reinterpret_cast<uint8_t*>(&tmp)[i % sizeof(tmp)] ^= a[i];
} }
return tmp; return tmp;
} else { }
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port; else {
const uint8_t *a = reinterpret_cast<const uint8_t *>(this); unsigned long tmp = reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port;
for(long i=0;i<(long)sizeof(InetAddress);++i) { const uint8_t* a = reinterpret_cast<const uint8_t*>(this);
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i]; for (long i = 0; i < (long)sizeof(InetAddress); ++i) {
reinterpret_cast<uint8_t*>(&tmp)[i % sizeof(tmp)] ^= a[i];
} }
return tmp; return tmp;
} }
@ -460,7 +516,10 @@ struct InetAddress : public sockaddr_storage
/** /**
* Set to null/zero * Set to null/zero
*/ */
inline void zero() { memset(this,0,sizeof(InetAddress)); } inline void zero()
{
memset(this, 0, sizeof(InetAddress));
}
/** /**
* Check whether this is a network/route rather than an IP assignment * Check whether this is a network/route rather than an IP assignment
@ -478,14 +537,14 @@ struct InetAddress : public sockaddr_storage
* @param b Second IP to compare with * @param b Second IP to compare with
* @return Number of matching prefix bits or 0 if none match or IPs are of different families (e.g. v4 and v6) * @return Number of matching prefix bits or 0 if none match or IPs are of different families (e.g. v4 and v6)
*/ */
inline unsigned int matchingPrefixBits(const InetAddress &b) const inline unsigned int matchingPrefixBits(const InetAddress& b) const
{ {
unsigned int c = 0; unsigned int c = 0;
if (ss_family == b.ss_family) { if (ss_family == b.ss_family) {
switch(ss_family) { switch (ss_family) {
case AF_INET: { case AF_INET: {
uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr); uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr);
uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(&b)->sin_addr.s_addr); uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(&b)->sin_addr.s_addr);
while ((ip0 >> 31) == (ip1 >> 31)) { while ((ip0 >> 31) == (ip1 >> 31)) {
ip0 <<= 1; ip0 <<= 1;
ip1 <<= 1; ip1 <<= 1;
@ -495,12 +554,13 @@ struct InetAddress : public sockaddr_storage
} }
} break; } break;
case AF_INET6: { case AF_INET6: {
const uint8_t *ip0 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); const uint8_t* ip0 = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
const uint8_t *ip1 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&b)->sin6_addr.s6_addr); const uint8_t* ip1 = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&b)->sin6_addr.s6_addr);
for(unsigned int i=0;i<16;++i) { for (unsigned int i = 0; i < 16; ++i) {
if (ip0[i] == ip1[i]) { if (ip0[i] == ip1[i]) {
c += 8; c += 8;
} else { }
else {
uint8_t ip0b = ip0[i]; uint8_t ip0b = ip0[i];
uint8_t ip1b = ip1[i]; uint8_t ip1b = ip1[i];
uint8_t bit = 0x80; uint8_t bit = 0x80;
@ -526,13 +586,13 @@ struct InetAddress : public sockaddr_storage
inline unsigned long rateGateHash() const inline unsigned long rateGateHash() const
{ {
unsigned long h = 0; unsigned long h = 0;
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00) >> 8; h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
h ^= (h >> 14); h ^= (h >> 14);
break; break;
case AF_INET6: { case AF_INET6: {
const uint8_t *ip = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr); const uint8_t* ip = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
h = ((unsigned long)ip[0]); h = ((unsigned long)ip[0]);
h <<= 1; h <<= 1;
h += ((unsigned long)ip[1]); h += ((unsigned long)ip[1]);
@ -552,22 +612,24 @@ struct InetAddress : public sockaddr_storage
/** /**
* @return True if address family is non-zero * @return True if address family is non-zero
*/ */
inline operator bool() const { return (ss_family != 0); } inline operator bool() const
{
return (ss_family != 0);
}
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b) const
inline void serialize(Buffer<C> &b) const
{ {
// This is used in the protocol and must be the same as describe in places // This is used in the protocol and must be the same as describe in places
// like VERB_HELLO in Packet.hpp. // like VERB_HELLO in Packet.hpp.
switch(ss_family) { switch (ss_family) {
case AF_INET: case AF_INET:
b.append((uint8_t)0x04); b.append((uint8_t)0x04);
b.append(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr),4); b.append(&(reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr), 4);
b.append((uint16_t)port()); // just in case sin_port != uint16_t b.append((uint16_t)port()); // just in case sin_port != uint16_t
return; return;
case AF_INET6: case AF_INET6:
b.append((uint8_t)0x06); b.append((uint8_t)0x06);
b.append(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16); b.append(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, 16);
b.append((uint16_t)port()); // just in case sin_port != uint16_t b.append((uint16_t)port()); // just in case sin_port != uint16_t
return; return;
default: default:
@ -576,12 +638,11 @@ struct InetAddress : public sockaddr_storage
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
memset(this,0,sizeof(InetAddress)); memset(this, 0, sizeof(InetAddress));
unsigned int p = startAt; unsigned int p = startAt;
switch(b[p++]) { switch (b[p++]) {
case 0: case 0:
return 1; return 1;
case 0x01: case 0x01:
@ -596,16 +657,16 @@ struct InetAddress : public sockaddr_storage
return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
case 0x04: case 0x04:
ss_family = AF_INET; ss_family = AF_INET;
memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); memcpy(&(reinterpret_cast<struct sockaddr_in*>(this)->sin_addr.s_addr), b.field(p, 4), 4);
p += 4; p += 4;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p));
p += 2; p += 2;
break; break;
case 0x06: case 0x06:
ss_family = AF_INET6; ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16); memcpy(reinterpret_cast<struct sockaddr_in6*>(this)->sin6_addr.s6_addr, b.field(p, 16), 16);
p += 16; p += 16;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p));
p += 2; p += 2;
break; break;
default: default:
@ -614,18 +675,30 @@ struct InetAddress : public sockaddr_storage
return (p - startAt); return (p - startAt);
} }
bool operator==(const InetAddress &a) const; bool operator==(const InetAddress& a) const;
bool operator<(const InetAddress &a) const; bool operator<(const InetAddress& a) const;
inline bool operator!=(const InetAddress &a) const { return !(*this == a); } inline bool operator!=(const InetAddress& a) const
inline bool operator>(const InetAddress &a) const { return (a < *this); } {
inline bool operator<=(const InetAddress &a) const { return !(a < *this); } return ! (*this == a);
inline bool operator>=(const InetAddress &a) const { return !(*this < a); } }
inline bool operator>(const InetAddress& a) const
{
return (a < *this);
}
inline bool operator<=(const InetAddress& a) const
{
return ! (a < *this);
}
inline bool operator>=(const InetAddress& a) const
{
return ! (*this < a);
}
/** /**
* @param mac MAC address seed * @param mac MAC address seed
* @return IPv6 link-local address * @return IPv6 link-local address
*/ */
static InetAddress makeIpv6LinkLocal(const MAC &mac); static InetAddress makeIpv6LinkLocal(const MAC& mac);
/** /**
* Compute private IPv6 unicast address from network ID and ZeroTier address * Compute private IPv6 unicast address from network ID and ZeroTier address
@ -668,12 +741,12 @@ struct InetAddress : public sockaddr_storage
* @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored) * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored)
* @return IPv6 private unicast address with /88 netmask * @return IPv6 private unicast address with /88 netmask
*/ */
static InetAddress makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress); static InetAddress makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress);
/** /**
* Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address * Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address
*/ */
static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress); static InetAddress makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress);
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,63 +14,80 @@
#ifndef ZT_MAC_HPP #ifndef ZT_MAC_HPP
#define ZT_MAC_HPP #define ZT_MAC_HPP
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buffer.hpp" #include "Buffer.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
namespace ZeroTier { namespace ZeroTier {
/** /**
* 48-byte Ethernet MAC address * 48-byte Ethernet MAC address
*/ */
class MAC class MAC {
{ public:
public: MAC() : _m(0ULL)
MAC() : _m(0ULL) {} {
MAC(const MAC &m) : _m(m._m) {} }
MAC(const MAC& m) : _m(m._m)
{
}
MAC(const unsigned char a,const unsigned char b,const unsigned char c,const unsigned char d,const unsigned char e,const unsigned char f) : MAC(const unsigned char a, const unsigned char b, const unsigned char c, const unsigned char d, const unsigned char e, const unsigned char f)
_m( ((((uint64_t)a) & 0xffULL) << 40) | : _m(((((uint64_t)a) & 0xffULL) << 40) | ((((uint64_t)b) & 0xffULL) << 32) | ((((uint64_t)c) & 0xffULL) << 24) | ((((uint64_t)d) & 0xffULL) << 16) | ((((uint64_t)e) & 0xffULL) << 8) | (((uint64_t)f) & 0xffULL))
((((uint64_t)b) & 0xffULL) << 32) | {
((((uint64_t)c) & 0xffULL) << 24) | }
((((uint64_t)d) & 0xffULL) << 16) | MAC(const void* bits, unsigned int len)
((((uint64_t)e) & 0xffULL) << 8) | {
(((uint64_t)f) & 0xffULL) ) {} setTo(bits, len);
MAC(const void *bits,unsigned int len) { setTo(bits,len); } }
MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); } MAC(const Address& ztaddr, uint64_t nwid)
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {} {
fromAddress(ztaddr, nwid);
}
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL)
{
}
/** /**
* @return MAC in 64-bit integer * @return MAC in 64-bit integer
*/ */
inline uint64_t toInt() const { return _m; } inline uint64_t toInt() const
{
return _m;
}
/** /**
* Set MAC to zero * Set MAC to zero
*/ */
inline void zero() { _m = 0ULL; } inline void zero()
{
_m = 0ULL;
}
/** /**
* @return True if MAC is non-zero * @return True if MAC is non-zero
*/ */
inline operator bool() const { return (_m != 0ULL); } inline operator bool() const
{
return (_m != 0ULL);
}
/** /**
* @param bits Raw MAC in big-endian byte order * @param bits Raw MAC in big-endian byte order
* @param len Length, must be >= 6 or result is zero * @param len Length, must be >= 6 or result is zero
*/ */
inline void setTo(const void *bits,unsigned int len) inline void setTo(const void* bits, unsigned int len)
{ {
if (len < 6) { if (len < 6) {
_m = 0ULL; _m = 0ULL;
return; return;
} }
const unsigned char *b = (const unsigned char *)bits; const unsigned char* b = (const unsigned char*)bits;
_m = ((((uint64_t)*b) & 0xff) << 40); _m = ((((uint64_t)*b) & 0xff) << 40);
++b; ++b;
_m |= ((((uint64_t)*b) & 0xff) << 32); _m |= ((((uint64_t)*b) & 0xff) << 32);
@ -88,12 +105,12 @@ public:
* @param buf Destination buffer for MAC in big-endian byte order * @param buf Destination buffer for MAC in big-endian byte order
* @param len Length of buffer, must be >= 6 or nothing is copied * @param len Length of buffer, must be >= 6 or nothing is copied
*/ */
inline void copyTo(void *buf,unsigned int len) const inline void copyTo(void* buf, unsigned int len) const
{ {
if (len < 6) { if (len < 6) {
return; return;
} }
unsigned char *b = (unsigned char *)buf; unsigned char* b = (unsigned char*)buf;
*(b++) = (unsigned char)((_m >> 40) & 0xff); *(b++) = (unsigned char)((_m >> 40) & 0xff);
*(b++) = (unsigned char)((_m >> 32) & 0xff); *(b++) = (unsigned char)((_m >> 32) & 0xff);
*(b++) = (unsigned char)((_m >> 24) & 0xff); *(b++) = (unsigned char)((_m >> 24) & 0xff);
@ -107,10 +124,9 @@ public:
* *
* @param b Buffer to append to * @param b Buffer to append to
*/ */
template<unsigned int C> template <unsigned int C> inline void appendTo(Buffer<C>& b) const
inline void appendTo(Buffer<C> &b) const
{ {
unsigned char *p = (unsigned char *)b.appendField(6); unsigned char* p = (unsigned char*)b.appendField(6);
*(p++) = (unsigned char)((_m >> 40) & 0xff); *(p++) = (unsigned char)((_m >> 40) & 0xff);
*(p++) = (unsigned char)((_m >> 32) & 0xff); *(p++) = (unsigned char)((_m >> 32) & 0xff);
*(p++) = (unsigned char)((_m >> 24) & 0xff); *(p++) = (unsigned char)((_m >> 24) & 0xff);
@ -122,17 +138,26 @@ public:
/** /**
* @return True if this is broadcast (all 0xff) * @return True if this is broadcast (all 0xff)
*/ */
inline bool isBroadcast() const { return (_m == 0xffffffffffffULL); } inline bool isBroadcast() const
{
return (_m == 0xffffffffffffULL);
}
/** /**
* @return True if this is a multicast MAC * @return True if this is a multicast MAC
*/ */
inline bool isMulticast() const { return ((_m & 0x010000000000ULL) != 0ULL); } inline bool isMulticast() const
{
return ((_m & 0x010000000000ULL) != 0ULL);
}
/** /**
* @param True if this is a locally-administered MAC * @param True if this is a locally-administered MAC
*/ */
inline bool isLocallyAdministered() const { return ((_m & 0x020000000000ULL) != 0ULL); } inline bool isLocallyAdministered() const
{
return ((_m & 0x020000000000ULL) != 0ULL);
}
/** /**
* Set this MAC to a MAC derived from an address and a network ID * Set this MAC to a MAC derived from an address and a network ID
@ -140,7 +165,7 @@ public:
* @param ztaddr ZeroTier address * @param ztaddr ZeroTier address
* @param nwid 64-bit network ID * @param nwid 64-bit network ID
*/ */
inline void fromAddress(const Address &ztaddr,uint64_t nwid) inline void fromAddress(const Address& ztaddr, uint64_t nwid)
{ {
uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40; uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40;
m |= ztaddr.toInt(); // a is 40 bits m |= ztaddr.toInt(); // a is 40 bits
@ -184,16 +209,25 @@ public:
* @param i Value from 0 to 5 (inclusive) * @param i Value from 0 to 5 (inclusive)
* @return Byte at said position (address interpreted in big-endian order) * @return Byte at said position (address interpreted in big-endian order)
*/ */
inline unsigned char operator[](unsigned int i) const { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); } inline unsigned char operator[](unsigned int i) const
{
return (unsigned char)((_m >> (40 - (i * 8))) & 0xff);
}
/** /**
* @return 6, which is the number of bytes in a MAC, for container compliance * @return 6, which is the number of bytes in a MAC, for container compliance
*/ */
inline unsigned int size() const { return 6; } inline unsigned int size() const
{
return 6;
}
inline unsigned long hashCode() const { return (unsigned long)_m; } inline unsigned long hashCode() const
{
return (unsigned long)_m;
}
inline char *toString(char buf[18]) const inline char* toString(char buf[18]) const
{ {
buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf]; buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf];
buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf]; buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf];
@ -216,25 +250,43 @@ public:
return buf; return buf;
} }
inline MAC &operator=(const MAC &m) inline MAC& operator=(const MAC& m)
{ {
_m = m._m; _m = m._m;
return *this; return *this;
} }
inline MAC &operator=(const uint64_t m) inline MAC& operator=(const uint64_t m)
{ {
_m = m; _m = m;
return *this; return *this;
} }
inline bool operator==(const MAC &m) const { return (_m == m._m); } inline bool operator==(const MAC& m) const
inline bool operator!=(const MAC &m) const { return (_m != m._m); } {
inline bool operator<(const MAC &m) const { return (_m < m._m); } return (_m == m._m);
inline bool operator<=(const MAC &m) const { return (_m <= m._m); } }
inline bool operator>(const MAC &m) const { return (_m > m._m); } inline bool operator!=(const MAC& m) const
inline bool operator>=(const MAC &m) const { return (_m >= m._m); } {
return (_m != m._m);
}
inline bool operator<(const MAC& m) const
{
return (_m < m._m);
}
inline bool operator<=(const MAC& m) const
{
return (_m <= m._m);
}
inline bool operator>(const MAC& m) const
{
return (_m > m._m);
}
inline bool operator>=(const MAC& m) const
{
return (_m >= m._m);
}
private: private:
uint64_t _m; uint64_t _m;
}; };

View file

@ -11,47 +11,41 @@
*/ */
/****/ /****/
#include <algorithm>
#include "Membership.hpp" #include "Membership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Peer.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Packet.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Trace.hpp" #include "Trace.hpp"
#include <algorithm>
namespace ZeroTier { namespace ZeroTier {
Membership::Membership() : Membership::Membership() : _lastUpdatedMulticast(0), _comRevocationThreshold(0), _lastPushedCredentials(0), _revocations(4), _remoteTags(4), _remoteCaps(4), _remoteCoos(4)
_lastUpdatedMulticast(0),
_comRevocationThreshold(0),
_lastPushedCredentials(0),
_revocations(4),
_remoteTags(4),
_remoteCaps(4),
_remoteCoos(4)
{ {
} }
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf) void Membership::pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf)
{ {
const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES]; const Capability* sendCaps[ZT_MAX_NETWORK_CAPABILITIES];
unsigned int sendCapCount = 0; unsigned int sendCapCount = 0;
for(unsigned int c=0;c<nconf.capabilityCount;++c) { for (unsigned int c = 0; c < nconf.capabilityCount; ++c) {
sendCaps[sendCapCount++] = &(nconf.capabilities[c]); sendCaps[sendCapCount++] = &(nconf.capabilities[c]);
} }
const Tag *sendTags[ZT_MAX_NETWORK_TAGS]; const Tag* sendTags[ZT_MAX_NETWORK_TAGS];
unsigned int sendTagCount = 0; unsigned int sendTagCount = 0;
for(unsigned int t=0;t<nconf.tagCount;++t) { for (unsigned int t = 0; t < nconf.tagCount; ++t) {
sendTags[sendTagCount++] = &(nconf.tags[t]); sendTags[sendTagCount++] = &(nconf.tags[t]);
} }
const CertificateOfOwnership *sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]; const CertificateOfOwnership* sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
unsigned int sendCooCount = 0; unsigned int sendCooCount = 0;
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c) { for (unsigned int c = 0; c < nconf.certificateOfOwnershipCount; ++c) {
sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]); sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]);
} }
@ -59,8 +53,8 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
unsigned int tagPtr = 0; unsigned int tagPtr = 0;
unsigned int cooPtr = 0; unsigned int cooPtr = 0;
bool sendCom = (bool)(nconf.com); bool sendCom = (bool)(nconf.com);
while ((capPtr < sendCapCount)||(tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)) { while ((capPtr < sendCapCount) || (tagPtr < sendTagCount) || (cooPtr < sendCooCount) || (sendCom)) {
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); Packet outp(peerAddress, RR->identity.address(), Packet::VERB_NETWORK_CREDENTIALS);
if (sendCom) { if (sendCom) {
sendCom = false; sendCom = false;
@ -71,20 +65,20 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
const unsigned int capCountAt = outp.size(); const unsigned int capCountAt = outp.size();
outp.addSize(2); outp.addSize(2);
unsigned int thisPacketCapCount = 0; unsigned int thisPacketCapCount = 0;
while ((capPtr < sendCapCount)&&((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { while ((capPtr < sendCapCount) && ((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendCaps[capPtr++]->serialize(outp); sendCaps[capPtr++]->serialize(outp);
++thisPacketCapCount; ++thisPacketCapCount;
} }
outp.setAt(capCountAt,(uint16_t)thisPacketCapCount); outp.setAt(capCountAt, (uint16_t)thisPacketCapCount);
const unsigned int tagCountAt = outp.size(); const unsigned int tagCountAt = outp.size();
outp.addSize(2); outp.addSize(2);
unsigned int thisPacketTagCount = 0; unsigned int thisPacketTagCount = 0;
while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { while ((tagPtr < sendTagCount) && ((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendTags[tagPtr++]->serialize(outp); sendTags[tagPtr++]->serialize(outp);
++thisPacketTagCount; ++thisPacketTagCount;
} }
outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount); outp.setAt(tagCountAt, (uint16_t)thisPacketTagCount);
// No revocations, these propagate differently // No revocations, these propagate differently
outp.append((uint16_t)0); outp.append((uint16_t)0);
@ -92,43 +86,43 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
const unsigned int cooCountAt = outp.size(); const unsigned int cooCountAt = outp.size();
outp.addSize(2); outp.addSize(2);
unsigned int thisPacketCooCount = 0; unsigned int thisPacketCooCount = 0;
while ((cooPtr < sendCooCount)&&((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { while ((cooPtr < sendCooCount) && ((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendCoos[cooPtr++]->serialize(outp); sendCoos[cooPtr++]->serialize(outp);
++thisPacketCooCount; ++thisPacketCooCount;
} }
outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount); outp.setAt(cooCountAt, (uint16_t)thisPacketCooCount);
outp.compress(); outp.compress();
RR->sw->send(tPtr,outp,true); RR->sw->send(tPtr, outp, true);
Metrics::pkt_network_credentials_out++; Metrics::pkt_network_credentials_out++;
} }
_lastPushedCredentials = now; _lastPushedCredentials = now;
} }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com)
{ {
const int64_t newts = com.timestamp(); const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) { if (newts <= _comRevocationThreshold) {
RR->t->credentialRejected(tPtr,com,"revoked"); RR->t->credentialRejected(tPtr, com, "revoked");
return ADD_REJECTED; return ADD_REJECTED;
} }
const int64_t oldts = _com.timestamp(); const int64_t oldts = _com.timestamp();
if (newts < oldts) { if (newts < oldts) {
RR->t->credentialRejected(tPtr,com,"old"); RR->t->credentialRejected(tPtr, com, "old");
return ADD_REJECTED; return ADD_REJECTED;
} }
if (_com == com) { if (_com == com) {
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
} }
switch(com.verify(RR,tPtr)) { switch (com.verify(RR, tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,com,"invalid"); RR->t->credentialRejected(tPtr, com, "invalid");
return ADD_REJECTED; return ADD_REJECTED;
case 0: case 0:
//printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout); // printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout);
_com = com; _com = com;
return ADD_ACCEPTED_NEW; return ADD_ACCEPTED_NEW;
case 1: case 1:
@ -137,13 +131,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
// Template out addCredential() for many cred types to avoid copypasta // Template out addCredential() for many cred types to avoid copypasta
template<typename C> template <typename C>
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remoteCreds,const Hashtable<uint64_t,int64_t> &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred) static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t, C>& remoteCreds, const Hashtable<uint64_t, int64_t>& revocations, const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const C& cred)
{ {
C *rc = remoteCreds.get(cred.id()); C* rc = remoteCreds.get(cred.id());
if (rc) { if (rc) {
if (rc->timestamp() > cred.timestamp()) { if (rc->timestamp() > cred.timestamp()) {
RR->t->credentialRejected(tPtr,cred,"old"); RR->t->credentialRejected(tPtr, cred, "old");
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
if (*rc == cred) { if (*rc == cred) {
@ -151,18 +145,18 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
} }
} }
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); const int64_t* const rt = revocations.get(Membership::credentialKey(C::credentialType(), cred.id()));
if ((rt)&&(*rt >= cred.timestamp())) { if ((rt) && (*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr,cred,"revoked"); RR->t->credentialRejected(tPtr, cred, "revoked");
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
switch(cred.verify(RR,tPtr)) { switch (cred.verify(RR, tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,cred,"invalid"); RR->t->credentialRejected(tPtr, cred, "invalid");
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
case 0: case 0:
if (!rc) { if (! rc) {
rc = &(remoteCreds[cred.id()]); rc = &(remoteCreds[cred.id()]);
} }
*rc = cred; *rc = cred;
@ -172,20 +166,29 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
} }
} }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,nconf,tag); } Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag)
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,nconf,cap); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,nconf,coo); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev)
{ {
int64_t *rt; return _addCredImpl<Tag>(_remoteTags, _revocations, RR, tPtr, nconf, tag);
switch(rev.verify(RR,tPtr)) { }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap)
{
return _addCredImpl<Capability>(_remoteCaps, _revocations, RR, tPtr, nconf, cap);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo)
{
return _addCredImpl<CertificateOfOwnership>(_remoteCoos, _revocations, RR, tPtr, nconf, coo);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev)
{
int64_t* rt;
switch (rev.verify(RR, tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,rev,"invalid"); RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED; return ADD_REJECTED;
case 0: { case 0: {
const Credential::Type ct = rev.type(); const Credential::Type ct = rev.type();
switch(ct) { switch (ct) {
case Credential::CREDENTIAL_TYPE_COM: case Credential::CREDENTIAL_TYPE_COM:
if (rev.threshold() > _comRevocationThreshold) { if (rev.threshold() > _comRevocationThreshold) {
_comRevocationThreshold = rev.threshold(); _comRevocationThreshold = rev.threshold();
@ -195,7 +198,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
case Credential::CREDENTIAL_TYPE_CAPABILITY: case Credential::CREDENTIAL_TYPE_CAPABILITY:
case Credential::CREDENTIAL_TYPE_TAG: case Credential::CREDENTIAL_TYPE_TAG:
case Credential::CREDENTIAL_TYPE_COO: case Credential::CREDENTIAL_TYPE_COO:
rt = &(_revocations[credentialKey(ct,rev.credentialId())]); rt = &(_revocations[credentialKey(ct, rev.credentialId())]);
if (*rt < rev.threshold()) { if (*rt < rev.threshold()) {
*rt = rev.threshold(); *rt = rev.threshold();
_comRevocationThreshold = rev.threshold(); _comRevocationThreshold = rev.threshold();
@ -203,7 +206,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
default: default:
RR->t->credentialRejected(tPtr,rev,"invalid"); RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED; return ADD_REJECTED;
} }
} }
@ -212,11 +215,11 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
} }
void Membership::clean(const int64_t now,const NetworkConfig &nconf) void Membership::clean(const int64_t now, const NetworkConfig& nconf)
{ {
_cleanCredImpl<Tag>(nconf,_remoteTags); _cleanCredImpl<Tag>(nconf, _remoteTags);
_cleanCredImpl<Capability>(nconf,_remoteCaps); _cleanCredImpl<Capability>(nconf, _remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos); _cleanCredImpl<CertificateOfOwnership>(nconf, _remoteCoos);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,17 +14,17 @@
#ifndef ZT_MEMBERSHIP_HPP #ifndef ZT_MEMBERSHIP_HPP
#define ZT_MEMBERSHIP_HPP #define ZT_MEMBERSHIP_HPP
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h" #include "../include/ZeroTierOne.h"
#include "Capability.hpp"
#include "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Credential.hpp" #include "Credential.hpp"
#include "Hashtable.hpp" #include "Hashtable.hpp"
#include "CertificateOfMembership.hpp"
#include "Capability.hpp"
#include "Tag.hpp"
#include "Revocation.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#include "Revocation.hpp"
#include "Tag.hpp"
#include <stdint.h>
#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL #define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL
@ -40,16 +40,9 @@ class Network;
* *
* This class is not thread safe. It must be locked externally. * This class is not thread safe. It must be locked externally.
*/ */
class Membership class Membership {
{ public:
public: enum AddCredentialResult { ADD_REJECTED, ADD_ACCEPTED_NEW, ADD_ACCEPTED_REDUNDANT, ADD_DEFERRED_FOR_WHOIS };
enum AddCredentialResult
{
ADD_REJECTED,
ADD_ACCEPTED_NEW,
ADD_ACCEPTED_REDUNDANT,
ADD_DEFERRED_FOR_WHOIS
};
Membership(); Membership();
@ -62,11 +55,20 @@ public:
* @param peerAddress Address of member peer (the one that this Membership describes) * @param peerAddress Address of member peer (the one that this Membership describes)
* @param nconf My network config * @param nconf My network config
*/ */
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf); void pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf);
inline int64_t lastPushedCredentials() { return _lastPushedCredentials; } inline int64_t lastPushedCredentials()
inline int64_t comTimestamp() { return _com.timestamp(); } {
inline int64_t comRevocationThreshold() { return _comRevocationThreshold; } return _lastPushedCredentials;
}
inline int64_t comTimestamp()
{
return _com.timestamp();
}
inline int64_t comRevocationThreshold()
{
return _comRevocationThreshold;
}
/** /**
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true * Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@ -90,14 +92,14 @@ public:
* @param otherNodeIdentity Identity of remote node * @param otherNodeIdentity Identity of remote node
* @return True if this peer is allowed on this network at all * @return True if this peer is allowed on this network at all
*/ */
inline bool isAllowedOnNetwork(const NetworkConfig &thisNodeNetworkConfig, const Identity &otherNodeIdentity) const inline bool isAllowedOnNetwork(const NetworkConfig& thisNodeNetworkConfig, const Identity& otherNodeIdentity) const
{ {
return thisNodeNetworkConfig.isPublic() || (((_com.timestamp() > _comRevocationThreshold) && (thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity)))); return thisNodeNetworkConfig.isPublic() || (((_com.timestamp() > _comRevocationThreshold) && (thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity))));
} }
inline bool recentlyAssociated(const int64_t now) const inline bool recentlyAssociated(const int64_t now) const
{ {
return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT)); return ((_com) && ((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT));
} }
/** /**
@ -108,18 +110,17 @@ public:
* @param r Resource to check * @param r Resource to check
* @return True if this peer has a certificate of ownership for the given resource * @return True if this peer has a certificate of ownership for the given resource
*/ */
template<typename T> template <typename T> inline bool hasCertificateOfOwnershipFor(const NetworkConfig& nconf, const T& r) const
inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const
{ {
uint32_t *k = (uint32_t *)0; uint32_t* k = (uint32_t*)0;
CertificateOfOwnership *v = (CertificateOfOwnership *)0; CertificateOfOwnership* v = (CertificateOfOwnership*)0;
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos))); Hashtable<uint32_t, CertificateOfOwnership>::Iterator i(*(const_cast<Hashtable<uint32_t, CertificateOfOwnership>*>(&_remoteCoos)));
while (i.next(k,v)) { while (i.next(k, v)) {
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r))) { if (_isCredentialTimestampValid(nconf, *v) && (v->owns(r))) {
return true; return true;
} }
} }
return _isV6NDPEmulated(nconf,r); return _isV6NDPEmulated(nconf, r);
} }
/** /**
@ -129,36 +130,36 @@ public:
* @param id Tag ID * @param id Tag ID
* @return Pointer to tag or NULL if not found * @return Pointer to tag or NULL if not found
*/ */
inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const inline const Tag* getTag(const NetworkConfig& nconf, const uint32_t id) const
{ {
const Tag *const t = _remoteTags.get(id); const Tag* const t = _remoteTags.get(id);
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0); return (((t) && (_isCredentialTimestampValid(nconf, *t))) ? t : (Tag*)0);
} }
/** /**
* Validate and add a credential if signature is okay and it's otherwise good * Validate and add a credential if signature is okay and it's otherwise good
*/ */
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com); AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com);
/** /**
* Validate and add a credential if signature is okay and it's otherwise good * Validate and add a credential if signature is okay and it's otherwise good
*/ */
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag); AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag);
/** /**
* Validate and add a credential if signature is okay and it's otherwise good * Validate and add a credential if signature is okay and it's otherwise good
*/ */
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap); AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap);
/** /**
* Validate and add a credential if signature is okay and it's otherwise good * Validate and add a credential if signature is okay and it's otherwise good
*/ */
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo); AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo);
/** /**
* Validate and add a credential if signature is okay and it's otherwise good * Validate and add a credential if signature is okay and it's otherwise good
*/ */
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev); AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev);
/** /**
* Clean internal databases of stale entries * Clean internal databases of stale entries
@ -166,24 +167,30 @@ public:
* @param now Current time * @param now Current time
* @param nconf Current network configuration * @param nconf Current network configuration
*/ */
void clean(const int64_t now,const NetworkConfig &nconf); void clean(const int64_t now, const NetworkConfig& nconf);
/** /**
* Generates a key for the internal use in indexing credentials by type and credential ID * Generates a key for the internal use in indexing credentials by type and credential ID
*/ */
static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); } static uint64_t credentialKey(const Credential::Type& t, const uint32_t i)
private:
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const MAC &m) const { return false; }
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const InetAddress &ip) const
{ {
if ((ip.isV6())&&(nconf.ndpEmulation())) { return (((uint64_t)t << 32) | (uint64_t)i);
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); }
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
private:
inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const MAC& m) const
{
return false;
}
inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const InetAddress& ip) const
{
if ((ip.isV6()) && (nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId, nconf.issuedTo.toInt()));
for (unsigned int i = 0; i < nconf.staticIpCount; ++i) {
if (nconf.staticIps[i].ipsEqual(sixpl)) { if (nconf.staticIps[i].ipsEqual(sixpl)) {
bool prefixMatches = true; bool prefixMatches = true;
for(unsigned int j=0;j<5;++j) { // check for match on /40 for (unsigned int j = 0; j < 5; ++j) { // check for match on /40
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) { if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&sixpl)->sin6_addr.s6_addr)[j]) {
prefixMatches = false; prefixMatches = false;
break; break;
} }
@ -195,12 +202,12 @@ private:
} }
} }
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt())); const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId, nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) { for (unsigned int i = 0; i < nconf.staticIpCount; ++i) {
if (nconf.staticIps[i].ipsEqual(rfc4193)) { if (nconf.staticIps[i].ipsEqual(rfc4193)) {
bool prefixMatches = true; bool prefixMatches = true;
for(unsigned int j=0;j<11;++j) { // check for match on /88 for (unsigned int j = 0; j < 11; ++j) { // check for match on /88
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) { if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&rfc4193)->sin6_addr.s6_addr)[j]) {
prefixMatches = false; prefixMatches = false;
break; break;
} }
@ -215,25 +222,23 @@ private:
return false; return false;
} }
template<typename C> template <typename C> inline bool _isCredentialTimestampValid(const NetworkConfig& nconf, const C& remoteCredential) const
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
{ {
const int64_t ts = remoteCredential.timestamp(); const int64_t ts = remoteCredential.timestamp();
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) { if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
const int64_t *threshold = _revocations.get(credentialKey(C::credentialType(),remoteCredential.id())); const int64_t* threshold = _revocations.get(credentialKey(C::credentialType(), remoteCredential.id()));
return ((!threshold)||(ts > *threshold)); return ((! threshold) || (ts > *threshold));
} }
return false; return false;
} }
template<typename C> template <typename C> inline void _cleanCredImpl(const NetworkConfig& nconf, Hashtable<uint32_t, C>& remoteCreds)
inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
{ {
uint32_t *k = (uint32_t *)0; uint32_t* k = (uint32_t*)0;
C *v = (C *)0; C* v = (C*)0;
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds); typename Hashtable<uint32_t, C>::Iterator i(remoteCreds);
while (i.next(k,v)) { while (i.next(k, v)) {
if (!_isCredentialTimestampValid(nconf,*v)) { if (! _isCredentialTimestampValid(nconf, *v)) {
remoteCreds.erase(*k); remoteCreds.erase(*k);
} }
} }
@ -252,42 +257,36 @@ private:
CertificateOfMembership _com; CertificateOfMembership _com;
// Revocations by credentialKey() // Revocations by credentialKey()
Hashtable< uint64_t,int64_t > _revocations; Hashtable<uint64_t, int64_t> _revocations;
// Remote credentials that we have received from this member (and that are valid) // Remote credentials that we have received from this member (and that are valid)
Hashtable< uint32_t,Tag > _remoteTags; Hashtable<uint32_t, Tag> _remoteTags;
Hashtable< uint32_t,Capability > _remoteCaps; Hashtable<uint32_t, Capability> _remoteCaps;
Hashtable< uint32_t,CertificateOfOwnership > _remoteCoos; Hashtable<uint32_t, CertificateOfOwnership> _remoteCoos;
public:
class CapabilityIterator
{
public: public:
CapabilityIterator(Membership &m,const NetworkConfig &nconf) : class CapabilityIterator {
_hti(m._remoteCaps), public:
_k((uint32_t *)0), CapabilityIterator(Membership& m, const NetworkConfig& nconf) : _hti(m._remoteCaps), _k((uint32_t*)0), _c((Capability*)0), _m(m), _nconf(nconf)
_c((Capability *)0),
_m(m),
_nconf(nconf)
{ {
} }
inline Capability *next() inline Capability* next()
{ {
while (_hti.next(_k,_c)) { while (_hti.next(_k, _c)) {
if (_m._isCredentialTimestampValid(_nconf,*_c)) { if (_m._isCredentialTimestampValid(_nconf, *_c)) {
return _c; return _c;
} }
} }
return (Capability *)0; return (Capability*)0;
} }
private: private:
Hashtable< uint32_t,Capability >::Iterator _hti; Hashtable<uint32_t, Capability>::Iterator _hti;
uint32_t *_k; uint32_t* _k;
Capability *_c; Capability* _c;
Membership &_m; Membership& _m;
const NetworkConfig &_nconf; const NetworkConfig& _nconf;
}; };
}; };

View file

@ -10,263 +10,155 @@
* of this software will be governed by version 2.0 of the Apache License. * of this software will be governed by version 2.0 of the Apache License.
*/ */
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h> #include <prometheus/histogram.h>
#include <prometheus/simpleapi.h>
namespace prometheus { namespace prometheus {
namespace simpleapi { namespace simpleapi {
std::shared_ptr<Registry> registry_ptr = std::make_shared<Registry>(); std::shared_ptr<Registry> registry_ptr = std::make_shared<Registry>();
Registry& registry = *registry_ptr; Registry& registry = *registry_ptr;
SaveToFile saver; SaveToFile saver;
} } // namespace simpleapi
} } // namespace prometheus
namespace ZeroTier { namespace ZeroTier {
namespace Metrics { namespace Metrics {
// Packet Type Counts // Packet Type Counts
prometheus::simpleapi::counter_family_t packets prometheus::simpleapi::counter_family_t packets { "zt_packet", "ZeroTier packet type counts" };
{ "zt_packet", "ZeroTier packet type counts"};
// Incoming packets // Incoming packets
prometheus::simpleapi::counter_metric_t pkt_nop_in prometheus::simpleapi::counter_metric_t pkt_nop_in { packets.Add({ { "packet_type", "nop" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "nop"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_error_in { packets.Add({ { "packet_type", "error" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_in prometheus::simpleapi::counter_metric_t pkt_ack_in { packets.Add({ { "packet_type", "ack" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "error"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_qos_in { packets.Add({ { "packet_type", "qos" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ack_in prometheus::simpleapi::counter_metric_t pkt_hello_in { packets.Add({ { "packet_type", "hello" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "ack"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_ok_in { packets.Add({ { "packet_type", "ok" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_qos_in prometheus::simpleapi::counter_metric_t pkt_whois_in { packets.Add({ { "packet_type", "whois" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "qos"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_rendezvous_in { packets.Add({ { "packet_type", "rendezvous" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_hello_in prometheus::simpleapi::counter_metric_t pkt_frame_in { packets.Add({ { "packet_type", "frame" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "hello"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_ext_frame_in { packets.Add({ { "packet_type", "ext_frame" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ok_in prometheus::simpleapi::counter_metric_t pkt_echo_in { packets.Add({ { "packet_type", "echo" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "ok"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_multicast_like_in { packets.Add({ { "packet_type", "multicast_like" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_whois_in prometheus::simpleapi::counter_metric_t pkt_network_credentials_in { packets.Add({ { "packet_type", "network_credentials" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "whois"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_network_config_request_in { packets.Add({ { "packet_type", "network_config_request" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_in prometheus::simpleapi::counter_metric_t pkt_network_config_in { packets.Add({ { "packet_type", "network_config" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "rendezvous"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in { packets.Add({ { "packet_type", "multicast_gather" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_frame_in prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in { packets.Add({ { "packet_type", "multicast_frame" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "frame"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in { packets.Add({ { "packet_type", "push_direct_paths" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_in prometheus::simpleapi::counter_metric_t pkt_user_message_in { packets.Add({ { "packet_type", "user_message" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "ext_frame"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_remote_trace_in { packets.Add({ { "packet_type", "remote_trace" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_echo_in prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in { packets.Add({ { "packet_type", "path_negotiation_request" }, { "direction", "rx" } }) };
{ packets.Add({{"packet_type", "echo"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_in
{ packets.Add({{"packet_type", "multicast_like"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_in
{ packets.Add({{"packet_type", "network_credentials"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_in
{ packets.Add({{"packet_type", "network_config_request"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_in
{ packets.Add({{"packet_type", "network_config"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in
{ packets.Add({{"packet_type", "multicast_gather"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in
{ packets.Add({{"packet_type", "multicast_frame"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in
{ packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_user_message_in
{ packets.Add({{"packet_type", "user_message"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_in
{ packets.Add({{"packet_type", "remote_trace"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in
{ packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "rx"}}) };
// Outgoing packets // Outgoing packets
prometheus::simpleapi::counter_metric_t pkt_nop_out prometheus::simpleapi::counter_metric_t pkt_nop_out { packets.Add({ { "packet_type", "nop" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "nop"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_error_out { packets.Add({ { "packet_type", "error" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_out prometheus::simpleapi::counter_metric_t pkt_ack_out { packets.Add({ { "packet_type", "ack" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "error"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_qos_out { packets.Add({ { "packet_type", "qos" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ack_out prometheus::simpleapi::counter_metric_t pkt_hello_out { packets.Add({ { "packet_type", "hello" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "ack"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_ok_out { packets.Add({ { "packet_type", "ok" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_qos_out prometheus::simpleapi::counter_metric_t pkt_whois_out { packets.Add({ { "packet_type", "whois" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "qos"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_rendezvous_out { packets.Add({ { "packet_type", "rendezvous" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_hello_out prometheus::simpleapi::counter_metric_t pkt_frame_out { packets.Add({ { "packet_type", "frame" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "hello"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_ext_frame_out { packets.Add({ { "packet_type", "ext_frame" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ok_out prometheus::simpleapi::counter_metric_t pkt_echo_out { packets.Add({ { "packet_type", "echo" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "ok"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_multicast_like_out { packets.Add({ { "packet_type", "multicast_like" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_whois_out prometheus::simpleapi::counter_metric_t pkt_network_credentials_out { packets.Add({ { "packet_type", "network_credentials" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "whois"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_network_config_request_out { packets.Add({ { "packet_type", "network_config_request" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_out prometheus::simpleapi::counter_metric_t pkt_network_config_out { packets.Add({ { "packet_type", "network_config" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "rendezvous"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out { packets.Add({ { "packet_type", "multicast_gather" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_frame_out prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out { packets.Add({ { "packet_type", "multicast_frame" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "frame"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out { packets.Add({ { "packet_type", "push_direct_paths" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_out prometheus::simpleapi::counter_metric_t pkt_user_message_out { packets.Add({ { "packet_type", "user_message" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "ext_frame"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t pkt_remote_trace_out { packets.Add({ { "packet_type", "remote_trace" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_echo_out prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out { packets.Add({ { "packet_type", "path_negotiation_request" }, { "direction", "tx" } }) };
{ packets.Add({{"packet_type", "echo"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_out
{ packets.Add({{"packet_type", "multicast_like"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_out
{ packets.Add({{"packet_type", "network_credentials"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_out
{ packets.Add({{"packet_type", "network_config_request"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_out
{ packets.Add({{"packet_type", "network_config"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out
{ packets.Add({{"packet_type", "multicast_gather"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out
{ packets.Add({{"packet_type", "multicast_frame"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out
{ packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_user_message_out
{ packets.Add({{"packet_type", "user_message"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_out
{ packets.Add({{"packet_type", "remote_trace"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out
{ packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "tx"}}) };
// Packet Error Counts
prometheus::simpleapi::counter_family_t packet_errors { "zt_packet_error", "ZeroTier packet errors" };
// Packet Error Counts // Incoming Error Counts
prometheus::simpleapi::counter_family_t packet_errors prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in { packet_errors.Add({ { "error_type", "obj_not_found" }, { "direction", "rx" } }) };
{ "zt_packet_error", "ZeroTier packet errors"}; prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in { packet_errors.Add({ { "error_type", "unsupported_operation" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in { packet_errors.Add({ { "error_type", "identity_collision" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in { packet_errors.Add({ { "error_type", "need_membership_certificate" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in { packet_errors.Add({ { "error_type", "network_access_denied" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in { packet_errors.Add({ { "error_type", "unwanted_multicast" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in { packet_errors.Add({ { "error_type", "authentication_required" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in { packet_errors.Add({ { "error_type", "internal_server_error" }, { "direction", "rx" } }) };
// Incoming Error Counts // Outgoing Error Counts
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out { packet_errors.Add({ { "error_type", "obj_not_found" }, { "direction", "tx" } }) };
{ packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out { packet_errors.Add({ { "error_type", "unsupported_operation" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out { packet_errors.Add({ { "error_type", "identity_collision" }, { "direction", "tx" } }) };
{ packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out { packet_errors.Add({ { "error_type", "need_membership_certificate" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out { packet_errors.Add({ { "error_type", "network_access_denied" }, { "direction", "tx" } }) };
{ packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out { packet_errors.Add({ { "error_type", "unwanted_multicast" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out { packet_errors.Add({ { "error_type", "authentication_required" }, { "direction", "tx" } }) };
{ packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "rx"}}) }; prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out { packet_errors.Add({ { "error_type", "internal_server_error" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in
{ packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in
{ packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in
{ packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in
{ packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "rx"}}) };
// Outgoing Error Counts // Data Sent/Received Metrics
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out prometheus::simpleapi::counter_family_t data { "zt_data", "number of bytes ZeroTier has transmitted or received" };
{ packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t udp_recv { data.Add({ { "protocol", "udp" }, { "direction", "rx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out prometheus::simpleapi::counter_metric_t udp_send { data.Add({ { "protocol", "udp" }, { "direction", "tx" } }) };
{ packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "tx"}}) }; prometheus::simpleapi::counter_metric_t tcp_send { data.Add({ { "protocol", "tcp" }, { "direction", "tx" } }) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out prometheus::simpleapi::counter_metric_t tcp_recv { data.Add({ { "protocol", "tcp" }, { "direction", "rx" } }) };
{ packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out
{ packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out
{ packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out
{ packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out
{ packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out
{ packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "tx"}}) };
// Data Sent/Received Metrics // Network Metrics
prometheus::simpleapi::counter_family_t data prometheus::simpleapi::gauge_metric_t network_num_joined { "zt_num_networks", "number of networks this instance is joined to" };
{ "zt_data", "number of bytes ZeroTier has transmitted or received" }; prometheus::simpleapi::gauge_family_t network_num_multicast_groups { "zt_network_multicast_groups_subscribed", "number of multicast groups networks are subscribed to" };
prometheus::simpleapi::counter_metric_t udp_recv prometheus::simpleapi::counter_family_t network_packets { "zt_network_packets", "number of incoming/outgoing packets per network" };
{ data.Add({{"protocol","udp"},{"direction","rx"}}) };
prometheus::simpleapi::counter_metric_t udp_send
{ data.Add({{"protocol","udp"},{"direction","tx"}}) };
prometheus::simpleapi::counter_metric_t tcp_send
{ data.Add({{"protocol","tcp"},{"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t tcp_recv
{ data.Add({{"protocol","tcp"},{"direction", "rx"}}) };
// Network Metrics
prometheus::simpleapi::gauge_metric_t network_num_joined
{ "zt_num_networks", "number of networks this instance is joined to" };
prometheus::simpleapi::gauge_family_t network_num_multicast_groups
{ "zt_network_multicast_groups_subscribed", "number of multicast groups networks are subscribed to" };
prometheus::simpleapi::counter_family_t network_packets
{ "zt_network_packets", "number of incoming/outgoing packets per network" };
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
// PeerMetrics // PeerMetrics
prometheus::CustomFamily<prometheus::Histogram<uint64_t>> &peer_latency = prometheus::CustomFamily<prometheus::Histogram<uint64_t> >& peer_latency = prometheus::Builder<prometheus::Histogram<uint64_t> >().Name("zt_peer_latency").Help("peer latency (ms)").Register(prometheus::simpleapi::registry);
prometheus::Builder<prometheus::Histogram<uint64_t>>()
.Name("zt_peer_latency")
.Help("peer latency (ms)")
.Register(prometheus::simpleapi::registry);
prometheus::simpleapi::gauge_family_t peer_path_count prometheus::simpleapi::gauge_family_t peer_path_count { "zt_peer_path_count", "number of paths to peer" };
{ "zt_peer_path_count", "number of paths to peer" }; prometheus::simpleapi::counter_family_t peer_packets { "zt_peer_packets", "number of packets to/from a peer" };
prometheus::simpleapi::counter_family_t peer_packets prometheus::simpleapi::counter_family_t peer_packet_errors { "zt_peer_packet_errors", "number of incoming packet errors from a peer" };
{ "zt_peer_packets", "number of packets to/from a peer" };
prometheus::simpleapi::counter_family_t peer_packet_errors
{ "zt_peer_packet_errors" , "number of incoming packet errors from a peer" };
#endif #endif
// General Controller Metrics // General Controller Metrics
prometheus::simpleapi::gauge_metric_t network_count prometheus::simpleapi::gauge_metric_t network_count { "controller_network_count", "number of networks the controller is serving" };
{"controller_network_count", "number of networks the controller is serving"}; prometheus::simpleapi::gauge_metric_t member_count { "controller_member_count", "number of network members the controller is serving" };
prometheus::simpleapi::gauge_metric_t member_count prometheus::simpleapi::counter_metric_t network_changes { "controller_network_change_count", "number of times a network configuration is changed" };
{"controller_member_count", "number of network members the controller is serving"}; prometheus::simpleapi::counter_metric_t member_changes { "controller_member_change_count", "number of times a network member configuration is changed" };
prometheus::simpleapi::counter_metric_t network_changes prometheus::simpleapi::counter_metric_t member_auths { "controller_member_auth_count", "number of network member auths" };
{"controller_network_change_count", "number of times a network configuration is changed"}; prometheus::simpleapi::counter_metric_t member_deauths { "controller_member_deauth_count", "number of network member deauths" };
prometheus::simpleapi::counter_metric_t member_changes
{"controller_member_change_count", "number of times a network member configuration is changed"};
prometheus::simpleapi::counter_metric_t member_auths
{"controller_member_auth_count", "number of network member auths"};
prometheus::simpleapi::counter_metric_t member_deauths
{"controller_member_deauth_count", "number of network member deauths"};
prometheus::simpleapi::gauge_metric_t network_config_request_queue_size prometheus::simpleapi::gauge_metric_t network_config_request_queue_size { "controller_network_config_request_queue", "number of entries in the request queue for network configurations" };
{ "controller_network_config_request_queue", "number of entries in the request queue for network configurations" };
prometheus::simpleapi::counter_metric_t sso_expiration_checks prometheus::simpleapi::counter_metric_t sso_expiration_checks { "controller_sso_expiration_checks", "number of sso expiration checks done" };
{ "controller_sso_expiration_checks", "number of sso expiration checks done" };
prometheus::simpleapi::counter_metric_t sso_member_deauth prometheus::simpleapi::counter_metric_t sso_member_deauth { "controller_sso_timeouts", "number of sso timeouts" };
{ "controller_sso_timeouts", "number of sso timeouts" };
prometheus::simpleapi::counter_metric_t network_config_request prometheus::simpleapi::counter_metric_t network_config_request { "controller_network_config_request", "count of config requests handled" };
{ "controller_network_config_request", "count of config requests handled" }; prometheus::simpleapi::gauge_metric_t network_config_request_threads { "controller_network_config_request_threads", "number of active network config handling threads" };
prometheus::simpleapi::gauge_metric_t network_config_request_threads prometheus::simpleapi::counter_metric_t db_get_network { "controller_db_get_network", "counter" };
{ "controller_network_config_request_threads", "number of active network config handling threads" }; prometheus::simpleapi::counter_metric_t db_get_network_and_member { "controller_db_get_network_and_member", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary { "controller_db_get_networK_and_member_summary", "counter" };
{ "controller_db_get_network", "counter" }; prometheus::simpleapi::counter_metric_t db_get_member_list { "controller_db_get_member_list", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member prometheus::simpleapi::counter_metric_t db_get_network_list { "controller_db_get_network_list", "counter" };
{ "controller_db_get_network_and_member", "counter" }; prometheus::simpleapi::counter_metric_t db_member_change { "controller_db_member_change", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary prometheus::simpleapi::counter_metric_t db_network_change { "controller_db_network_change", "counter" };
{ "controller_db_get_networK_and_member_summary", "counter" };
prometheus::simpleapi::counter_metric_t db_get_member_list
{ "controller_db_get_member_list", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_list
{ "controller_db_get_network_list", "counter" };
prometheus::simpleapi::counter_metric_t db_member_change
{ "controller_db_member_change", "counter" };
prometheus::simpleapi::counter_metric_t db_network_change
{ "controller_db_network_change", "counter" };
#ifdef ZT_CONTROLLER_USE_LIBPQ #ifdef ZT_CONTROLLER_USE_LIBPQ
// Central Controller Metrics // Central Controller Metrics
prometheus::simpleapi::counter_metric_t pgsql_mem_notification prometheus::simpleapi::counter_metric_t pgsql_mem_notification { "controller_pgsql_member_notifications_received", "number of member change notifications received via pgsql NOTIFY" };
{ "controller_pgsql_member_notifications_received", "number of member change notifications received via pgsql NOTIFY" }; prometheus::simpleapi::counter_metric_t pgsql_net_notification { "controller_pgsql_network_notifications_received", "number of network change notifications received via pgsql NOTIFY" };
prometheus::simpleapi::counter_metric_t pgsql_net_notification prometheus::simpleapi::counter_metric_t pgsql_node_checkin { "controller_pgsql_node_checkin_count", "number of node check-ins (pgsql)" };
{ "controller_pgsql_network_notifications_received", "number of network change notifications received via pgsql NOTIFY" }; prometheus::simpleapi::counter_metric_t pgsql_commit_ticks { "controller_pgsql_commit_ticks", "number of commit ticks run (pgsql)" };
prometheus::simpleapi::counter_metric_t pgsql_node_checkin prometheus::simpleapi::counter_metric_t db_get_sso_info { "controller_db_get_sso_info", "counter" };
{ "controller_pgsql_node_checkin_count", "number of node check-ins (pgsql)" };
prometheus::simpleapi::counter_metric_t pgsql_commit_ticks
{ "controller_pgsql_commit_ticks", "number of commit ticks run (pgsql)" };
prometheus::simpleapi::counter_metric_t db_get_sso_info
{ "controller_db_get_sso_info", "counter" };
prometheus::simpleapi::counter_metric_t redis_mem_notification prometheus::simpleapi::counter_metric_t redis_mem_notification { "controller_redis_member_notifications_received", "number of member change notifications received via redis" };
{ "controller_redis_member_notifications_received", "number of member change notifications received via redis" }; prometheus::simpleapi::counter_metric_t redis_net_notification { "controller_redis_network_notifications_received", "number of network change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_net_notification prometheus::simpleapi::counter_metric_t redis_node_checkin { "controller_redis_node_checkin_count", "number of node check-ins (redis)" };
{ "controller_redis_network_notifications_received", "number of network change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_node_checkin
{ "controller_redis_node_checkin_count", "number of node check-ins (redis)" };
// Central DB Pool Metrics // Central DB Pool Metrics
prometheus::simpleapi::counter_metric_t conn_counter prometheus::simpleapi::counter_metric_t conn_counter { "controller_pgsql_connections_created", "number of pgsql connections created" };
{ "controller_pgsql_connections_created", "number of pgsql connections created"}; prometheus::simpleapi::counter_metric_t max_pool_size { "controller_pgsql_max_conn_pool_size", "max connection pool size for postgres" };
prometheus::simpleapi::counter_metric_t max_pool_size prometheus::simpleapi::counter_metric_t min_pool_size { "controller_pgsql_min_conn_pool_size", "minimum connection pool size for postgres" };
{ "controller_pgsql_max_conn_pool_size", "max connection pool size for postgres"}; prometheus::simpleapi::gauge_metric_t pool_avail { "controller_pgsql_available_conns", "number of available postgres connections" };
prometheus::simpleapi::counter_metric_t min_pool_size prometheus::simpleapi::gauge_metric_t pool_in_use { "controller_pgsql_in_use_conns", "number of postgres database connections in use" };
{ "controller_pgsql_min_conn_pool_size", "minimum connection pool size for postgres" }; prometheus::simpleapi::counter_metric_t pool_errors { "controller_pgsql_connection_errors", "number of connection errors the connection pool has seen" };
prometheus::simpleapi::gauge_metric_t pool_avail
{ "controller_pgsql_available_conns", "number of available postgres connections" };
prometheus::simpleapi::gauge_metric_t pool_in_use
{ "controller_pgsql_in_use_conns", "number of postgres database connections in use" };
prometheus::simpleapi::counter_metric_t pool_errors
{ "controller_pgsql_connection_errors", "number of connection errors the connection pool has seen" };
#endif #endif
} } // namespace Metrics
} } // namespace ZeroTier

View file

@ -12,155 +12,152 @@
#ifndef METRICS_H_ #ifndef METRICS_H_
#define METRICS_H_ #define METRICS_H_
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h> #include <prometheus/histogram.h>
#include <prometheus/simpleapi.h>
namespace prometheus { namespace prometheus {
namespace simpleapi { namespace simpleapi {
extern std::shared_ptr<Registry> registry_ptr; extern std::shared_ptr<Registry> registry_ptr;
}
} }
} // namespace prometheus
namespace ZeroTier { namespace ZeroTier {
namespace Metrics { namespace Metrics {
// Packet Type Counts // Packet Type Counts
extern prometheus::simpleapi::counter_family_t packets; extern prometheus::simpleapi::counter_family_t packets;
// incoming packets // incoming packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_in; extern prometheus::simpleapi::counter_metric_t pkt_nop_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_in; extern prometheus::simpleapi::counter_metric_t pkt_error_in;
extern prometheus::simpleapi::counter_metric_t pkt_ack_in; extern prometheus::simpleapi::counter_metric_t pkt_ack_in;
extern prometheus::simpleapi::counter_metric_t pkt_qos_in; extern prometheus::simpleapi::counter_metric_t pkt_qos_in;
extern prometheus::simpleapi::counter_metric_t pkt_hello_in; extern prometheus::simpleapi::counter_metric_t pkt_hello_in;
extern prometheus::simpleapi::counter_metric_t pkt_ok_in; extern prometheus::simpleapi::counter_metric_t pkt_ok_in;
extern prometheus::simpleapi::counter_metric_t pkt_whois_in; extern prometheus::simpleapi::counter_metric_t pkt_whois_in;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_in; extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_in;
extern prometheus::simpleapi::counter_metric_t pkt_frame_in; extern prometheus::simpleapi::counter_metric_t pkt_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_in; extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_echo_in; extern prometheus::simpleapi::counter_metric_t pkt_echo_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_in; extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_in; extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_in; extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_in; extern prometheus::simpleapi::counter_metric_t pkt_network_config_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in; extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in; extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in; extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_in; extern prometheus::simpleapi::counter_metric_t pkt_user_message_in;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_in; extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_in;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in; extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in;
// outgoing packets // outgoing packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_out; extern prometheus::simpleapi::counter_metric_t pkt_nop_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_out; extern prometheus::simpleapi::counter_metric_t pkt_error_out;
extern prometheus::simpleapi::counter_metric_t pkt_ack_out; extern prometheus::simpleapi::counter_metric_t pkt_ack_out;
extern prometheus::simpleapi::counter_metric_t pkt_qos_out; extern prometheus::simpleapi::counter_metric_t pkt_qos_out;
extern prometheus::simpleapi::counter_metric_t pkt_hello_out; extern prometheus::simpleapi::counter_metric_t pkt_hello_out;
extern prometheus::simpleapi::counter_metric_t pkt_ok_out; extern prometheus::simpleapi::counter_metric_t pkt_ok_out;
extern prometheus::simpleapi::counter_metric_t pkt_whois_out; extern prometheus::simpleapi::counter_metric_t pkt_whois_out;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_out; extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_out;
extern prometheus::simpleapi::counter_metric_t pkt_frame_out; extern prometheus::simpleapi::counter_metric_t pkt_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_out; extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_echo_out; extern prometheus::simpleapi::counter_metric_t pkt_echo_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_out; extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_out; extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_out; extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_out; extern prometheus::simpleapi::counter_metric_t pkt_network_config_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out; extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out; extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out; extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_out; extern prometheus::simpleapi::counter_metric_t pkt_user_message_out;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_out; extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_out;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out; extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out;
// Packet Error Counts // Packet Error Counts
extern prometheus::simpleapi::counter_family_t packet_errors; extern prometheus::simpleapi::counter_family_t packet_errors;
// incoming errors // incoming errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in; extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in; extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in; extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in; extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in; extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in; extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in; extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in; extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in;
// outgoing errors // outgoing errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out; extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out; extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out; extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out; extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out; extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out; extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out; extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out; extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out;
// Data Sent/Received Metrics // Data Sent/Received Metrics
extern prometheus::simpleapi::counter_family_t data; extern prometheus::simpleapi::counter_family_t data;
extern prometheus::simpleapi::counter_metric_t udp_send; extern prometheus::simpleapi::counter_metric_t udp_send;
extern prometheus::simpleapi::counter_metric_t udp_recv; extern prometheus::simpleapi::counter_metric_t udp_recv;
extern prometheus::simpleapi::counter_metric_t tcp_send; extern prometheus::simpleapi::counter_metric_t tcp_send;
extern prometheus::simpleapi::counter_metric_t tcp_recv; extern prometheus::simpleapi::counter_metric_t tcp_recv;
// Network Metrics // Network Metrics
extern prometheus::simpleapi::gauge_metric_t network_num_joined; extern prometheus::simpleapi::gauge_metric_t network_num_joined;
extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups; extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups;
extern prometheus::simpleapi::counter_family_t network_packets; extern prometheus::simpleapi::counter_family_t network_packets;
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
// Peer Metrics // Peer Metrics
extern prometheus::CustomFamily<prometheus::Histogram<uint64_t>> &peer_latency; extern prometheus::CustomFamily<prometheus::Histogram<uint64_t> >& peer_latency;
extern prometheus::simpleapi::gauge_family_t peer_path_count; extern prometheus::simpleapi::gauge_family_t peer_path_count;
extern prometheus::simpleapi::counter_family_t peer_packets; extern prometheus::simpleapi::counter_family_t peer_packets;
extern prometheus::simpleapi::counter_family_t peer_packet_errors; extern prometheus::simpleapi::counter_family_t peer_packet_errors;
#endif #endif
// General Controller Metrics // General Controller Metrics
extern prometheus::simpleapi::gauge_metric_t network_count; extern prometheus::simpleapi::gauge_metric_t network_count;
extern prometheus::simpleapi::gauge_metric_t member_count; extern prometheus::simpleapi::gauge_metric_t member_count;
extern prometheus::simpleapi::counter_metric_t network_changes; extern prometheus::simpleapi::counter_metric_t network_changes;
extern prometheus::simpleapi::counter_metric_t member_changes; extern prometheus::simpleapi::counter_metric_t member_changes;
extern prometheus::simpleapi::counter_metric_t member_auths; extern prometheus::simpleapi::counter_metric_t member_auths;
extern prometheus::simpleapi::counter_metric_t member_deauths; extern prometheus::simpleapi::counter_metric_t member_deauths;
extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size; extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size;
extern prometheus::simpleapi::counter_metric_t sso_expiration_checks; extern prometheus::simpleapi::counter_metric_t sso_expiration_checks;
extern prometheus::simpleapi::counter_metric_t sso_member_deauth; extern prometheus::simpleapi::counter_metric_t sso_member_deauth;
extern prometheus::simpleapi::counter_metric_t network_config_request; extern prometheus::simpleapi::counter_metric_t network_config_request;
extern prometheus::simpleapi::gauge_metric_t network_config_request_threads; extern prometheus::simpleapi::gauge_metric_t network_config_request_threads;
extern prometheus::simpleapi::counter_metric_t db_get_network;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary;
extern prometheus::simpleapi::counter_metric_t db_get_member_list;
extern prometheus::simpleapi::counter_metric_t db_get_network_list;
extern prometheus::simpleapi::counter_metric_t db_member_change;
extern prometheus::simpleapi::counter_metric_t db_network_change;
extern prometheus::simpleapi::counter_metric_t db_get_network;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary;
extern prometheus::simpleapi::counter_metric_t db_get_member_list;
extern prometheus::simpleapi::counter_metric_t db_get_network_list;
extern prometheus::simpleapi::counter_metric_t db_member_change;
extern prometheus::simpleapi::counter_metric_t db_network_change;
#ifdef ZT_CONTROLLER_USE_LIBPQ #ifdef ZT_CONTROLLER_USE_LIBPQ
// Central Controller Metrics // Central Controller Metrics
extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification; extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_net_notification; extern prometheus::simpleapi::counter_metric_t pgsql_net_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin; extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin;
extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks; extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks;
extern prometheus::simpleapi::counter_metric_t db_get_sso_info; extern prometheus::simpleapi::counter_metric_t db_get_sso_info;
extern prometheus::simpleapi::counter_metric_t redis_mem_notification; extern prometheus::simpleapi::counter_metric_t redis_mem_notification;
extern prometheus::simpleapi::counter_metric_t redis_net_notification; extern prometheus::simpleapi::counter_metric_t redis_net_notification;
extern prometheus::simpleapi::counter_metric_t redis_node_checkin; extern prometheus::simpleapi::counter_metric_t redis_node_checkin;
// Central DB Pool Metrics
extern prometheus::simpleapi::counter_metric_t conn_counter;
// Central DB Pool Metrics extern prometheus::simpleapi::counter_metric_t max_pool_size;
extern prometheus::simpleapi::counter_metric_t conn_counter; extern prometheus::simpleapi::counter_metric_t min_pool_size;
extern prometheus::simpleapi::counter_metric_t max_pool_size; extern prometheus::simpleapi::gauge_metric_t pool_avail;
extern prometheus::simpleapi::counter_metric_t min_pool_size; extern prometheus::simpleapi::gauge_metric_t pool_in_use;
extern prometheus::simpleapi::gauge_metric_t pool_avail; extern prometheus::simpleapi::counter_metric_t pool_errors;
extern prometheus::simpleapi::gauge_metric_t pool_in_use;
extern prometheus::simpleapi::counter_metric_t pool_errors;
#endif #endif
} // namespace Metrics } // namespace Metrics
}// namespace ZeroTier } // namespace ZeroTier
#endif // METRICS_H_ #endif // METRICS_H_

View file

@ -14,10 +14,10 @@
#ifndef ZT_MULTICASTGROUP_HPP #ifndef ZT_MULTICASTGROUP_HPP
#define ZT_MULTICASTGROUP_HPP #define ZT_MULTICASTGROUP_HPP
#include <stdint.h>
#include "MAC.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "MAC.hpp"
#include <stdint.h>
namespace ZeroTier { namespace ZeroTier {
@ -36,18 +36,13 @@ namespace ZeroTier {
* *
* MulticastGroup behaves as an immutable value object. * MulticastGroup behaves as an immutable value object.
*/ */
class MulticastGroup class MulticastGroup {
{ public:
public: MulticastGroup() : _mac(), _adi(0)
MulticastGroup() :
_mac(),
_adi(0)
{ {
} }
MulticastGroup(const MAC &m,uint32_t a) : MulticastGroup(const MAC& m, uint32_t a) : _mac(m), _adi(a)
_mac(m),
_adi(a)
{ {
} }
@ -57,21 +52,22 @@ public:
* @param ip IP address (port field is ignored) * @param ip IP address (port field is ignored)
* @return Multicast group for ARP/NDP * @return Multicast group for ARP/NDP
*/ */
static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip) static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip)
{ {
if (ip.isV4()) { if (ip.isV4()) {
// IPv4 wants broadcast MACs, so we shove the V4 address itself into // IPv4 wants broadcast MACs, so we shove the V4 address itself into
// the Multicast Group ADI field. Making V4 ARP work is basically why // the Multicast Group ADI field. Making V4 ARP work is basically why
// ADI was added, as well as handling other things that want mindless // ADI was added, as well as handling other things that want mindless
// Ethernet broadcast to all. // Ethernet broadcast to all.
return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData()))); return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t*)ip.rawIpData())));
} else if (ip.isV6()) { }
else if (ip.isV6()) {
// IPv6 is better designed in this respect. We can compute the IPv6 // IPv6 is better designed in this respect. We can compute the IPv6
// multicast address directly from the IP address, and it gives us // multicast address directly from the IP address, and it gives us
// 24 bits of uniqueness. Collisions aren't likely to be common enough // 24 bits of uniqueness. Collisions aren't likely to be common enough
// to care about. // to care about.
const unsigned char *a = (const unsigned char *)ip.rawIpData(); const unsigned char* a = (const unsigned char*)ip.rawIpData();
return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0); return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0);
} }
return MulticastGroup(); return MulticastGroup();
} }
@ -79,31 +75,56 @@ public:
/** /**
* @return Multicast address * @return Multicast address
*/ */
inline const MAC &mac() const { return _mac; } inline const MAC& mac() const
{
return _mac;
}
/** /**
* @return Additional distinguishing information * @return Additional distinguishing information
*/ */
inline uint32_t adi() const { return _adi; } inline uint32_t adi() const
{
return _adi;
}
inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); } inline unsigned long hashCode() const
{
return (_mac.hashCode() ^ (unsigned long)_adi);
}
inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); } inline bool operator==(const MulticastGroup& g) const
inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); } {
inline bool operator<(const MulticastGroup &g) const return ((_mac == g._mac) && (_adi == g._adi));
}
inline bool operator!=(const MulticastGroup& g) const
{
return ((_mac != g._mac) || (_adi != g._adi));
}
inline bool operator<(const MulticastGroup& g) const
{ {
if (_mac < g._mac) { if (_mac < g._mac) {
return true; return true;
} else if (_mac == g._mac) { }
else if (_mac == g._mac) {
return (_adi < g._adi); return (_adi < g._adi);
} }
return false; return false;
} }
inline bool operator>(const MulticastGroup &g) const { return (g < *this); } inline bool operator>(const MulticastGroup& g) const
inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); } {
inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); } return (g < *this);
}
inline bool operator<=(const MulticastGroup& g) const
{
return ! (g < *this);
}
inline bool operator>=(const MulticastGroup& g) const
{
return ! (*this < g);
}
private: private:
MAC _mac; MAC _mac;
uint32_t _adi; uint32_t _adi;
}; };

View file

@ -11,24 +11,23 @@
*/ */
/****/ /****/
#include <algorithm>
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "Multicaster.hpp" #include "Multicaster.hpp"
#include "Topology.hpp"
#include "Switch.hpp" #include "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "CertificateOfMembership.hpp" #include "RuntimeEnvironment.hpp"
#include "Node.hpp" #include "Switch.hpp"
#include "Network.hpp" #include "Topology.hpp"
#include <algorithm>
namespace ZeroTier { namespace ZeroTier {
Multicaster::Multicaster(const RuntimeEnvironment *renv) : Multicaster::Multicaster(const RuntimeEnvironment* renv) : RR(renv), _groups(32)
RR(renv),
_groups(32)
{ {
} }
@ -36,24 +35,24 @@ Multicaster::~Multicaster()
{ {
} }
void Multicaster::addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) void Multicaster::addMultiple(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const void* addresses, unsigned int count, unsigned int totalKnown)
{ {
const unsigned char *p = (const unsigned char *)addresses; const unsigned char* p = (const unsigned char*)addresses;
const unsigned char *e = p + (5 * count); const unsigned char* e = p + (5 * count);
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; MulticastGroupStatus& gs = _groups[Multicaster::Key(nwid, mg)];
while (p != e) { while (p != e) {
_add(tPtr,now,nwid,mg,gs,Address(p,5)); _add(tPtr, now, nwid, mg, gs, Address(p, 5));
p += 5; p += 5;
} }
} }
void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &member) void Multicaster::remove(uint64_t nwid, const MulticastGroup& mg, const Address& member)
{ {
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg));
if (s) { if (s) {
for(std::vector<MulticastGroupMember>::iterator m(s->members.begin());m!=s->members.end();++m) { for (std::vector<MulticastGroupMember>::iterator m(s->members.begin()); m != s->members.end(); ++m) {
if (m->address == member) { if (m->address == member) {
s->members.erase(m); s->members.erase(m);
break; break;
@ -62,15 +61,16 @@ void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &m
} }
} }
unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const unsigned int Multicaster::gather(const Address& queryingPeer, uint64_t nwid, const MulticastGroup& mg, Buffer<ZT_PROTO_MAX_PACKET_LENGTH>& appendTo, unsigned int limit) const
{ {
unsigned char *p; unsigned char* p;
unsigned int added = 0,i,k,rptr,totalKnown = 0; unsigned int added = 0, i, k, rptr, totalKnown = 0;
uint64_t a,picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2]; uint64_t a, picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2];
if (!limit) { if (! limit) {
return 0; return 0;
} else if (limit > 0xffff) { }
else if (limit > 0xffff) {
limit = 0xffff; limit = 0xffff;
} }
@ -81,7 +81,7 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const
{ // Return myself if I am a member of this group { // Return myself if I am a member of this group
SharedPtr<Network> network(RR->node->network(nwid)); SharedPtr<Network> network(RR->node->network(nwid));
if ((network)&&(network->subscribedToMulticastGroup(mg,true))) { if ((network) && (network->subscribedToMulticastGroup(mg, true))) {
RR->identity.address().appendTo(appendTo); RR->identity.address().appendTo(appendTo);
++totalKnown; ++totalKnown;
++added; ++added;
@ -90,19 +90,19 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); const MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg));
if ((s)&&(!s->members.empty())) { if ((s) && (! s->members.empty())) {
totalKnown += (unsigned int)s->members.size(); totalKnown += (unsigned int)s->members.size();
// Members are returned in random order so that repeated gather queries // Members are returned in random order so that repeated gather queries
// will return different subsets of a large multicast group. // will return different subsets of a large multicast group.
k = 0; k = 0;
while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) { while ((added < limit) && (k < s->members.size()) && ((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) {
rptr = (unsigned int)RR->node->prng(); rptr = (unsigned int)RR->node->prng();
restart_member_scan: restart_member_scan:
a = s->members[rptr % (unsigned int)s->members.size()].address.toInt(); a = s->members[rptr % (unsigned int)s->members.size()].address.toInt();
for(i=0;i<k;++i) { for (i = 0; i < k; ++i) {
if (picked[i] == a) { if (picked[i] == a) {
++rptr; ++rptr;
goto restart_member_scan; goto restart_member_scan;
@ -111,7 +111,7 @@ restart_member_scan:
picked[k++] = a; picked[k++] = a;
if (queryingPeer.toInt() != a) { // do not return the peer that is making the request as a result if (queryingPeer.toInt() != a) { // do not return the peer that is making the request as a result
p = (unsigned char *)appendTo.appendField(ZT_ADDRESS_LENGTH); p = (unsigned char*)appendTo.appendField(ZT_ADDRESS_LENGTH);
*(p++) = (unsigned char)((a >> 32) & 0xff); *(p++) = (unsigned char)((a >> 32) & 0xff);
*(p++) = (unsigned char)((a >> 24) & 0xff); *(p++) = (unsigned char)((a >> 24) & 0xff);
*(p++) = (unsigned char)((a >> 16) & 0xff); *(p++) = (unsigned char)((a >> 16) & 0xff);
@ -122,21 +122,21 @@ restart_member_scan:
} }
} }
appendTo.setAt(totalAt,(uint32_t)totalKnown); appendTo.setAt(totalAt, (uint32_t)totalKnown);
appendTo.setAt(addedAt,(uint16_t)added); appendTo.setAt(addedAt, (uint16_t)added);
return added; return added;
} }
std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const std::vector<Address> Multicaster::getMembers(uint64_t nwid, const MulticastGroup& mg, unsigned int limit) const
{ {
std::vector<Address> ls; std::vector<Address> ls;
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); const MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg));
if (!s) { if (! s) {
return ls; return ls;
} }
for(std::vector<MulticastGroupMember>::const_reverse_iterator m(s->members.rbegin());m!=s->members.rend();++m) { for (std::vector<MulticastGroupMember>::const_reverse_iterator m(s->members.rbegin()); m != s->members.rend(); ++m) {
ls.push_back(m->address); ls.push_back(m->address);
if (ls.size() >= limit) { if (ls.size() >= limit) {
break; break;
@ -145,19 +145,10 @@ std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup
return ls; return ls;
} }
void Multicaster::send( void Multicaster::send(void* tPtr, int64_t now, const SharedPtr<Network>& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len)
void *tPtr,
int64_t now,
const SharedPtr<Network> &network,
const Address &origin,
const MulticastGroup &mg,
const MAC &src,
unsigned int etherType,
const void *data,
unsigned int len)
{ {
unsigned long idxbuf[4096]; unsigned long idxbuf[4096];
unsigned long *indexes = idxbuf; unsigned long* indexes = idxbuf;
// If we're in hub-and-spoke designated multicast replication mode, see if we // If we're in hub-and-spoke designated multicast replication mode, see if we
// have a multicast replicator active. If so, pick the best and send it // have a multicast replicator active. If so, pick the best and send it
@ -167,19 +158,19 @@ void Multicaster::send(
// the current protocol and could be fixed, but fixing it would add more // the current protocol and could be fixed, but fixing it would add more
// complexity than the fix is probably worth. Bridges are generally high // complexity than the fix is probably worth. Bridges are generally high
// bandwidth nodes. // bandwidth nodes.
if (!network->config().isActiveBridge(RR->identity.address())) { if (! network->config().isActiveBridge(RR->identity.address())) {
Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS]; Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS];
const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators); const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators);
if (multicastReplicatorCount) { if (multicastReplicatorCount) {
if (std::find(multicastReplicators,multicastReplicators + multicastReplicatorCount,RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) { if (std::find(multicastReplicators, multicastReplicators + multicastReplicatorCount, RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) {
SharedPtr<Peer> bestMulticastReplicator; SharedPtr<Peer> bestMulticastReplicator;
SharedPtr<Path> bestMulticastReplicatorPath; SharedPtr<Path> bestMulticastReplicatorPath;
unsigned int bestMulticastReplicatorLatency = 0xffff; unsigned int bestMulticastReplicatorLatency = 0xffff;
for(unsigned int i=0;i<multicastReplicatorCount;++i) { for (unsigned int i = 0; i < multicastReplicatorCount; ++i) {
const SharedPtr<Peer> p(RR->topology->getPeerNoCache(multicastReplicators[i])); const SharedPtr<Peer> p(RR->topology->getPeerNoCache(multicastReplicators[i]));
if ((p)&&(p->isAlive(now))) { if ((p) && (p->isAlive(now))) {
const SharedPtr<Path> pp(p->getAppropriatePath(now,false)); const SharedPtr<Path> pp(p->getAppropriatePath(now, false));
if ((pp)&&(pp->latency() < bestMulticastReplicatorLatency)) { if ((pp) && (pp->latency() < bestMulticastReplicatorLatency)) {
bestMulticastReplicatorLatency = pp->latency(); bestMulticastReplicatorLatency = pp->latency();
bestMulticastReplicatorPath = pp; bestMulticastReplicatorPath = pp;
bestMulticastReplicator = p; bestMulticastReplicator = p;
@ -187,20 +178,20 @@ void Multicaster::send(
} }
} }
if (bestMulticastReplicator) { if (bestMulticastReplicator) {
Packet outp(bestMulticastReplicator->address(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME); Packet outp(bestMulticastReplicator->address(), RR->identity.address(), Packet::VERB_MULTICAST_FRAME);
outp.append((uint64_t)network->id()); outp.append((uint64_t)network->id());
outp.append((uint8_t)0x0c); // includes source MAC | please replicate outp.append((uint8_t)0x0c); // includes source MAC | please replicate
((src) ? src : MAC(RR->identity.address(),network->id())).appendTo(outp); ((src) ? src : MAC(RR->identity.address(), network->id())).appendTo(outp);
mg.mac().appendTo(outp); mg.mac().appendTo(outp);
outp.append((uint32_t)mg.adi()); outp.append((uint32_t)mg.adi());
outp.append((uint16_t)etherType); outp.append((uint16_t)etherType);
outp.append(data,len); outp.append(data, len);
if (!network->config().disableCompression()) { if (! network->config().disableCompression()) {
outp.compress(); outp.compress();
} }
outp.armor(bestMulticastReplicator->key(),true,false,bestMulticastReplicator->aesKeysIfSupported(),bestMulticastReplicator->identity()); outp.armor(bestMulticastReplicator->key(), true, false, bestMulticastReplicator->aesKeysIfSupported(), bestMulticastReplicator->identity());
Metrics::pkt_multicast_frame_out++; Metrics::pkt_multicast_frame_out++;
bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now); bestMulticastReplicatorPath->send(RR, tPtr, outp.data(), outp.size(), now);
return; return;
} }
} }
@ -209,19 +200,19 @@ void Multicaster::send(
try { try {
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
MulticastGroupStatus &gs = _groups[Multicaster::Key(network->id(),mg)]; MulticastGroupStatus& gs = _groups[Multicaster::Key(network->id(), mg)];
if (!gs.members.empty()) { if (! gs.members.empty()) {
// Allocate a memory buffer if group is monstrous // Allocate a memory buffer if group is monstrous
if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) { if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) {
indexes = new unsigned long[gs.members.size()]; indexes = new unsigned long[gs.members.size()];
} }
// Generate a random permutation of member indexes // Generate a random permutation of member indexes
for(unsigned long i=0;i<gs.members.size();++i) { for (unsigned long i = 0; i < gs.members.size(); ++i) {
indexes[i] = i; indexes[i] = i;
} }
for(unsigned long i=(unsigned long)gs.members.size()-1;i>0;--i) { for (unsigned long i = (unsigned long)gs.members.size() - 1; i > 0; --i) {
unsigned long j = (unsigned long)RR->node->prng() % (i + 1); unsigned long j = (unsigned long)RR->node->prng() % (i + 1);
unsigned long tmp = indexes[j]; unsigned long tmp = indexes[j];
indexes[j] = indexes[i]; indexes[j] = indexes[i];
@ -252,9 +243,9 @@ void Multicaster::send(
unsigned int count = 0; unsigned int count = 0;
for(unsigned int i=0;i<activeBridgeCount;++i) { for (unsigned int i = 0; i < activeBridgeCount; ++i) {
if ((activeBridges[i] != RR->identity.address())&&(activeBridges[i] != origin)) { if ((activeBridges[i] != RR->identity.address()) && (activeBridges[i] != origin)) {
out.sendOnly(RR,tPtr,activeBridges[i]); // optimization: don't use dedup log if it's a one-pass send out.sendOnly(RR, tPtr, activeBridges[i]); // optimization: don't use dedup log if it's a one-pass send
if (++count >= limit) { if (++count >= limit) {
break; break;
} }
@ -262,14 +253,15 @@ void Multicaster::send(
} }
unsigned long idx = 0; unsigned long idx = 0;
while ((count < limit)&&(idx < gs.members.size())) { while ((count < limit) && (idx < gs.members.size())) {
const Address ma(gs.members[indexes[idx++]].address); const Address ma(gs.members[indexes[idx++]].address);
if ((std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount))&&(ma != origin)) { if ((std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) && (ma != origin)) {
out.sendOnly(RR,tPtr,ma); // optimization: don't use dedup log if it's a one-pass send out.sendOnly(RR, tPtr, ma); // optimization: don't use dedup log if it's a one-pass send
++count; ++count;
} }
} }
} else { }
else {
while (gs.txQueue.size() >= ZT_TX_QUEUE_SIZE) { while (gs.txQueue.size() >= ZT_TX_QUEUE_SIZE) {
gs.txQueue.pop_front(); gs.txQueue.pop_front();
} }
@ -277,7 +269,7 @@ void Multicaster::send(
const unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1; const unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
int timerScale = RR->node->lowBandwidthModeEnabled() ? 3 : 1; int timerScale = RR->node->lowBandwidthModeEnabled() ? 3 : 1;
if ((gs.members.empty())||((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) { if ((gs.members.empty()) || ((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) {
gs.lastExplicitGather = now; gs.lastExplicitGather = now;
Address explicitGatherPeers[16]; Address explicitGatherPeers[16];
@ -293,10 +285,10 @@ void Multicaster::send(
Address ac[ZT_MAX_NETWORK_SPECIALISTS]; Address ac[ZT_MAX_NETWORK_SPECIALISTS];
const unsigned int accnt = network->config().alwaysContactAddresses(ac); const unsigned int accnt = network->config().alwaysContactAddresses(ac);
unsigned int shuffled[ZT_MAX_NETWORK_SPECIALISTS]; unsigned int shuffled[ZT_MAX_NETWORK_SPECIALISTS];
for(unsigned int i=0;i<accnt;++i) { for (unsigned int i = 0; i < accnt; ++i) {
shuffled[i] = i; shuffled[i] = i;
} }
for(unsigned int i=0,k=accnt>>1;i<k;++i) { for (unsigned int i = 0, k = accnt >> 1; i < k; ++i) {
const uint64_t x = RR->node->prng(); const uint64_t x = RR->node->prng();
const unsigned int x1 = shuffled[(unsigned int)x % accnt]; const unsigned int x1 = shuffled[(unsigned int)x % accnt];
const unsigned int x2 = shuffled[(unsigned int)(x >> 32) % accnt]; const unsigned int x2 = shuffled[(unsigned int)(x >> 32) % accnt];
@ -304,7 +296,7 @@ void Multicaster::send(
shuffled[x1] = shuffled[x2]; shuffled[x1] = shuffled[x2];
shuffled[x2] = tmp; shuffled[x2] = tmp;
} }
for(unsigned int i=0;i<accnt;++i) { for (unsigned int i = 0; i < accnt; ++i) {
explicitGatherPeers[numExplicitGatherPeers++] = ac[shuffled[i]]; explicitGatherPeers[numExplicitGatherPeers++] = ac[shuffled[i]];
if (numExplicitGatherPeers == 16) { if (numExplicitGatherPeers == 16) {
break; break;
@ -312,7 +304,7 @@ void Multicaster::send(
} }
std::vector<Address> anchors(network->config().anchors()); std::vector<Address> anchors(network->config().anchors());
for(std::vector<Address>::const_iterator a(anchors.begin());a!=anchors.end();++a) { for (std::vector<Address>::const_iterator a(anchors.begin()); a != anchors.end(); ++a) {
if (*a != RR->identity.address()) { if (*a != RR->identity.address()) {
explicitGatherPeers[numExplicitGatherPeers++] = *a; explicitGatherPeers[numExplicitGatherPeers++] = *a;
if (numExplicitGatherPeers == 16) { if (numExplicitGatherPeers == 16) {
@ -321,9 +313,9 @@ void Multicaster::send(
} }
} }
for(unsigned int k=0;k<numExplicitGatherPeers;++k) { for (unsigned int k = 0; k < numExplicitGatherPeers; ++k) {
const CertificateOfMembership *com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; const CertificateOfMembership* com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership*)0) : (const CertificateOfMembership*)0;
Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER); Packet outp(explicitGatherPeers[k], RR->identity.address(), Packet::VERB_MULTICAST_GATHER);
outp.append(network->id()); outp.append(network->id());
outp.append((uint8_t)((com) ? 0x01 : 0x00)); outp.append((uint8_t)((com) ? 0x01 : 0x00));
mg.mac().appendTo(outp); mg.mac().appendTo(outp);
@ -333,26 +325,15 @@ void Multicaster::send(
com->serialize(outp); com->serialize(outp);
} }
RR->node->expectReplyTo(outp.packetId()); RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,true); RR->sw->send(tPtr, outp, true);
Metrics::pkt_multicast_gather_out++; Metrics::pkt_multicast_gather_out++;
} }
} }
gs.txQueue.push_back(OutboundMulticast()); gs.txQueue.push_back(OutboundMulticast());
OutboundMulticast &out = gs.txQueue.back(); OutboundMulticast& out = gs.txQueue.back();
out.init( out.init(RR, now, network->id(), network->config().disableCompression(), limit, gatherLimit, src, mg, etherType, data, len);
RR,
now,
network->id(),
network->config().disableCompression(),
limit,
gatherLimit,
src,
mg,
etherType,
data,
len);
if (origin) { if (origin) {
out.logAsSent(origin); out.logAsSent(origin);
@ -360,9 +341,9 @@ void Multicaster::send(
unsigned int count = 0; unsigned int count = 0;
for(unsigned int i=0;i<activeBridgeCount;++i) { for (unsigned int i = 0; i < activeBridgeCount; ++i) {
if (activeBridges[i] != RR->identity.address()) { if (activeBridges[i] != RR->identity.address()) {
out.sendAndLog(RR,tPtr,activeBridges[i]); out.sendAndLog(RR, tPtr, activeBridges[i]);
if (++count >= limit) { if (++count >= limit) {
break; break;
} }
@ -370,33 +351,36 @@ void Multicaster::send(
} }
unsigned long idx = 0; unsigned long idx = 0;
while ((count < limit)&&(idx < gs.members.size())) { while ((count < limit) && (idx < gs.members.size())) {
Address ma(gs.members[indexes[idx++]].address); Address ma(gs.members[indexes[idx++]].address);
if (std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount)) { if (std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) {
out.sendAndLog(RR,tPtr,ma); out.sendAndLog(RR, tPtr, ma);
++count; ++count;
} }
} }
} }
} catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted }
catch (...) {
} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted
// Free allocated memory buffer if any // Free allocated memory buffer if any
if (indexes != idxbuf) { if (indexes != idxbuf) {
delete [] indexes; delete[] indexes;
} }
} }
void Multicaster::clean(int64_t now) void Multicaster::clean(int64_t now)
{ {
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
Multicaster::Key *k = (Multicaster::Key *)0; Multicaster::Key* k = (Multicaster::Key*)0;
MulticastGroupStatus *s = (MulticastGroupStatus *)0; MulticastGroupStatus* s = (MulticastGroupStatus*)0;
Hashtable<Multicaster::Key,MulticastGroupStatus>::Iterator mm(_groups); Hashtable<Multicaster::Key, MulticastGroupStatus>::Iterator mm(_groups);
while (mm.next(k,s)) { while (mm.next(k, s)) {
for(std::list<OutboundMulticast>::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) { for (std::list<OutboundMulticast>::iterator tx(s->txQueue.begin()); tx != s->txQueue.end();) {
if ((tx->expired(now))||(tx->atLimit())) { if ((tx->expired(now)) || (tx->atLimit())) {
s->txQueue.erase(tx++); s->txQueue.erase(tx++);
} else { }
else {
++tx; ++tx;
} }
} }
@ -417,15 +401,17 @@ void Multicaster::clean(int64_t now)
if (count) { if (count) {
s->members.resize(count); s->members.resize(count);
} else if (s->txQueue.empty()) { }
else if (s->txQueue.empty()) {
_groups.erase(*k); _groups.erase(*k);
} else { }
else {
s->members.clear(); s->members.clear();
} }
} }
} }
void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) void Multicaster::_add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member)
{ {
// assumes _groups_m is locked // assumes _groups_m is locked
@ -434,25 +420,28 @@ void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup
return; return;
} }
std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(),gs.members.end(),member)); std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(), gs.members.end(), member));
if (m != gs.members.end()) { if (m != gs.members.end()) {
if (m->address == member) { if (m->address == member) {
m->timestamp = now; m->timestamp = now;
return; return;
} }
gs.members.insert(m,MulticastGroupMember(member,now)); gs.members.insert(m, MulticastGroupMember(member, now));
} else { }
gs.members.push_back(MulticastGroupMember(member,now)); else {
gs.members.push_back(MulticastGroupMember(member, now));
} }
for(std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) { for (std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin()); tx != gs.txQueue.end();) {
if (tx->atLimit()) { if (tx->atLimit()) {
gs.txQueue.erase(tx++); gs.txQueue.erase(tx++);
} else { }
tx->sendIfNew(RR,tPtr,member); else {
tx->sendIfNew(RR, tPtr, member);
if (tx->atLimit()) { if (tx->atLimit()) {
gs.txQueue.erase(tx++); gs.txQueue.erase(tx++);
} else { }
else {
++tx; ++tx;
} }
} }

View file

@ -14,22 +14,21 @@
#ifndef ZT_MULTICASTER_HPP #ifndef ZT_MULTICASTER_HPP
#define ZT_MULTICASTER_HPP #define ZT_MULTICASTER_HPP
#include <stdint.h> #include "Address.hpp"
#include <string.h>
#include <map>
#include <vector>
#include <list>
#include "Constants.hpp" #include "Constants.hpp"
#include "Hashtable.hpp" #include "Hashtable.hpp"
#include "Address.hpp"
#include "MAC.hpp" #include "MAC.hpp"
#include "MulticastGroup.hpp" #include "MulticastGroup.hpp"
#include "OutboundMulticast.hpp"
#include "Utils.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "OutboundMulticast.hpp"
#include "SharedPtr.hpp" #include "SharedPtr.hpp"
#include "Utils.hpp"
#include <list>
#include <map>
#include <stdint.h>
#include <string.h>
#include <vector>
namespace ZeroTier { namespace ZeroTier {
@ -41,10 +40,9 @@ class Network;
/** /**
* Database of known multicast peers within a network * Database of known multicast peers within a network
*/ */
class Multicaster class Multicaster {
{ public:
public: Multicaster(const RuntimeEnvironment* renv);
Multicaster(const RuntimeEnvironment *renv);
~Multicaster(); ~Multicaster();
/** /**
@ -55,10 +53,10 @@ public:
* @param mg Multicast group * @param mg Multicast group
* @param member New member address * @param member New member address
*/ */
inline void add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) inline void add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const Address& member)
{ {
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
_add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); _add(tPtr, now, nwid, mg, _groups[Multicaster::Key(nwid, mg)], member);
} }
/** /**
@ -74,7 +72,7 @@ public:
* @param count Number of addresses * @param count Number of addresses
* @param totalKnown Total number of known addresses as reported by peer * @param totalKnown Total number of known addresses as reported by peer
*/ */
void addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); void addMultiple(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const void* addresses, unsigned int count, unsigned int totalKnown);
/** /**
* Remove a multicast group member (if present) * Remove a multicast group member (if present)
@ -83,7 +81,7 @@ public:
* @param mg Multicast group * @param mg Multicast group
* @param member Member to unsubscribe * @param member Member to unsubscribe
*/ */
void remove(uint64_t nwid,const MulticastGroup &mg,const Address &member); void remove(uint64_t nwid, const MulticastGroup& mg, const Address& member);
/** /**
* Append gather results to a packet by choosing registered multicast recipients at random * Append gather results to a packet by choosing registered multicast recipients at random
@ -103,7 +101,7 @@ public:
* @return Number of addresses appended * @return Number of addresses appended
* @throws std::out_of_range Buffer overflow writing to packet * @throws std::out_of_range Buffer overflow writing to packet
*/ */
unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const; unsigned int gather(const Address& queryingPeer, uint64_t nwid, const MulticastGroup& mg, Buffer<ZT_PROTO_MAX_PACKET_LENGTH>& appendTo, unsigned int limit) const;
/** /**
* Get subscribers to a multicast group * Get subscribers to a multicast group
@ -111,7 +109,7 @@ public:
* @param nwid Network ID * @param nwid Network ID
* @param mg Multicast group * @param mg Multicast group
*/ */
std::vector<Address> getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const; std::vector<Address> getMembers(uint64_t nwid, const MulticastGroup& mg, unsigned int limit) const;
/** /**
* Send a multicast * Send a multicast
@ -126,16 +124,7 @@ public:
* @param data Packet data * @param data Packet data
* @param len Length of packet data * @param len Length of packet data
*/ */
void send( void send(void* tPtr, int64_t now, const SharedPtr<Network>& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len);
void *tPtr,
int64_t now,
const SharedPtr<Network> &network,
const Address &origin,
const MulticastGroup &mg,
const MAC &src,
unsigned int etherType,
const void *data,
unsigned int len);
/** /**
* Clean database * Clean database
@ -145,50 +134,84 @@ public:
*/ */
void clean(int64_t now); void clean(int64_t now);
private: private:
struct Key struct Key {
Key() : nwid(0), mg()
{ {
Key() : nwid(0),mg() {} }
Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {} Key(uint64_t n, const MulticastGroup& g) : nwid(n), mg(g)
{
}
uint64_t nwid; uint64_t nwid;
MulticastGroup mg; MulticastGroup mg;
inline bool operator==(const Key &k) const { return ((nwid == k.nwid)&&(mg == k.mg)); } inline bool operator==(const Key& k) const
inline bool operator!=(const Key &k) const { return ((nwid != k.nwid)||(mg != k.mg)); } {
inline unsigned long hashCode() const { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); } return ((nwid == k.nwid) && (mg == k.mg));
}
inline bool operator!=(const Key& k) const
{
return ((nwid != k.nwid) || (mg != k.mg));
}
inline unsigned long hashCode() const
{
return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32)));
}
}; };
struct MulticastGroupMember struct MulticastGroupMember {
MulticastGroupMember()
{ {
MulticastGroupMember() {} }
MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {} MulticastGroupMember(const Address& a, uint64_t ts) : address(a), timestamp(ts)
{
}
inline bool operator<(const MulticastGroupMember &a) const { return (address < a.address); } inline bool operator<(const MulticastGroupMember& a) const
inline bool operator==(const MulticastGroupMember &a) const { return (address == a.address); } {
inline bool operator!=(const MulticastGroupMember &a) const { return (address != a.address); } return (address < a.address);
inline bool operator<(const Address &a) const { return (address < a); } }
inline bool operator==(const Address &a) const { return (address == a); } inline bool operator==(const MulticastGroupMember& a) const
inline bool operator!=(const Address &a) const { return (address != a); } {
return (address == a.address);
}
inline bool operator!=(const MulticastGroupMember& a) const
{
return (address != a.address);
}
inline bool operator<(const Address& a) const
{
return (address < a);
}
inline bool operator==(const Address& a) const
{
return (address == a);
}
inline bool operator!=(const Address& a) const
{
return (address != a);
}
Address address; Address address;
int64_t timestamp; // time of last notification int64_t timestamp; // time of last notification
}; };
struct MulticastGroupStatus struct MulticastGroupStatus {
MulticastGroupStatus() : lastExplicitGather(0)
{ {
MulticastGroupStatus() : lastExplicitGather(0) {} }
int64_t lastExplicitGather; int64_t lastExplicitGather;
std::list<OutboundMulticast> txQueue; // pending outbound multicasts std::list<OutboundMulticast> txQueue; // pending outbound multicasts
std::vector<MulticastGroupMember> members; // members of this group std::vector<MulticastGroupMember> members; // members of this group
}; };
void _add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); void _add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member);
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
Hashtable<Multicaster::Key,MulticastGroupStatus> _groups; Hashtable<Multicaster::Key, MulticastGroupStatus> _groups;
Mutex _groups_m; Mutex _groups_m;
}; };

View file

@ -18,19 +18,18 @@
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#include <pthread.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <pthread.h>
namespace ZeroTier { namespace ZeroTier {
// libpthread based mutex lock // libpthread based mutex lock
class Mutex class Mutex {
{ public:
public:
Mutex() Mutex()
{ {
pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); pthread_mutex_init(&_mh, (const pthread_mutexattr_t*)0);
} }
~Mutex() ~Mutex()
@ -40,25 +39,22 @@ public:
inline void lock() const inline void lock() const
{ {
pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh)); pthread_mutex_lock(&((const_cast<Mutex*>(this))->_mh));
} }
inline void unlock() const inline void unlock() const
{ {
pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh)); pthread_mutex_unlock(&((const_cast<Mutex*>(this))->_mh));
} }
class Lock class Lock {
{
public: public:
Lock(Mutex &m) : Lock(Mutex& m) : _m(&m)
_m(&m)
{ {
m.lock(); m.lock();
} }
Lock(const Mutex &m) : Lock(const Mutex& m) : _m(const_cast<Mutex*>(&m))
_m(const_cast<Mutex *>(&m))
{ {
_m->lock(); _m->lock();
} }
@ -69,12 +65,17 @@ public:
} }
private: private:
Mutex *const _m; Mutex* const _m;
}; };
private: private:
Mutex(const Mutex &) {} Mutex(const Mutex&)
const Mutex &operator=(const Mutex &) { return *this; } {
}
const Mutex& operator=(const Mutex&)
{
return *this;
}
pthread_mutex_t _mh; pthread_mutex_t _mh;
}; };
@ -91,9 +92,8 @@ private:
namespace ZeroTier { namespace ZeroTier {
// Windows critical section based lock // Windows critical section based lock
class Mutex class Mutex {
{ public:
public:
Mutex() Mutex()
{ {
InitializeCriticalSection(&_cs); InitializeCriticalSection(&_cs);
@ -116,25 +116,22 @@ public:
inline void lock() const inline void lock() const
{ {
(const_cast <Mutex *> (this))->lock(); (const_cast<Mutex*>(this))->lock();
} }
inline void unlock() const inline void unlock() const
{ {
(const_cast <Mutex *> (this))->unlock(); (const_cast<Mutex*>(this))->unlock();
} }
class Lock class Lock {
{
public: public:
Lock(Mutex &m) : Lock(Mutex& m) : _m(&m)
_m(&m)
{ {
m.lock(); m.lock();
} }
Lock(const Mutex &m) : Lock(const Mutex& m) : _m(const_cast<Mutex*>(&m))
_m(const_cast<Mutex *>(&m))
{ {
_m->lock(); _m->lock();
} }
@ -145,12 +142,17 @@ public:
} }
private: private:
Mutex *const _m; Mutex* const _m;
}; };
private: private:
Mutex(const Mutex &) {} Mutex(const Mutex&)
const Mutex &operator=(const Mutex &) { return *this; } {
}
const Mutex& operator=(const Mutex&)
{
return *this;
}
CRITICAL_SECTION _cs; CRITICAL_SECTION _cs;
}; };

File diff suppressed because it is too large Load diff

View file

@ -14,30 +14,28 @@
#ifndef ZT_NETWORK_HPP #ifndef ZT_NETWORK_HPP
#define ZT_NETWORK_HPP #define ZT_NETWORK_HPP
#include <stdint.h>
#include "../include/ZeroTierOne.h" #include "../include/ZeroTierOne.h"
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp" #include "AtomicCounter.hpp"
#include "MulticastGroup.hpp"
#include "MAC.hpp"
#include "Dictionary.hpp"
#include "Multicaster.hpp"
#include "Membership.hpp"
#include "NetworkConfig.hpp"
#include "CertificateOfMembership.hpp" #include "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Dictionary.hpp"
#include "Hashtable.hpp"
#include "MAC.hpp"
#include "Membership.hpp"
#include "Metrics.hpp" #include "Metrics.hpp"
#include "MulticastGroup.hpp"
#include "Multicaster.hpp"
#include "Mutex.hpp"
#include "NetworkConfig.hpp"
#include "SharedPtr.hpp"
#include <algorithm>
#include <map>
#include <stdexcept>
#include <stdint.h>
#include <string>
#include <vector>
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3 #define ZT_NETWORK_MAX_INCOMING_UPDATES 3
#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1) #define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
@ -50,11 +48,10 @@ class Peer;
/** /**
* A virtual LAN * A virtual LAN
*/ */
class Network class Network {
{
friend class SharedPtr<Network>; friend class SharedPtr<Network>;
public: public:
/** /**
* Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0
*/ */
@ -63,7 +60,10 @@ public:
/** /**
* Compute primary controller device ID from network ID * Compute primary controller device ID from network ID
*/ */
static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); } static inline Address controllerFor(uint64_t nwid)
{
return Address(nwid >> 24);
}
/** /**
* Construct a new network * Construct a new network
@ -77,18 +77,43 @@ public:
* @param uptr Arbitrary pointer used by externally-facing API (for user use) * @param uptr Arbitrary pointer used by externally-facing API (for user use)
* @param nconf Network config, if known * @param nconf Network config, if known
*/ */
Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr,const NetworkConfig *nconf); Network(const RuntimeEnvironment* renv, void* tPtr, uint64_t nwid, void* uptr, const NetworkConfig* nconf);
~Network(); ~Network();
inline uint64_t id() const { return _id; } inline uint64_t id() const
inline Address controller() const { return Address(_id >> 24); } {
inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } return _id;
inline bool hasConfig() const { return (_config); } }
inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } inline Address controller() const
inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); } {
inline const NetworkConfig &config() const { return _config; } return Address(_id >> 24);
inline const MAC &mac() const { return _mac; } }
inline bool multicastEnabled() const
{
return (_config.multicastLimit > 0);
}
inline bool hasConfig() const
{
return (_config);
}
inline uint64_t lastConfigUpdate() const
{
return _lastConfigUpdate;
}
inline ZT_VirtualNetworkStatus status() const
{
Mutex::Lock _l(_lock);
return _status();
}
inline const NetworkConfig& config() const
{
return _config;
}
inline const MAC& mac() const
{
return _mac;
}
/** /**
* Apply filters to an outgoing packet * Apply filters to an outgoing packet
@ -111,17 +136,17 @@ public:
* @return True if packet should be sent, false if dropped or redirected * @return True if packet should be sent, false if dropped or redirected
*/ */
bool filterOutgoingPacket( bool filterOutgoingPacket(
void *tPtr, void* tPtr,
const bool noTee, const bool noTee,
const Address &ztSource, const Address& ztSource,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *frameData, const uint8_t* frameData,
const unsigned int frameLen, const unsigned int frameLen,
const unsigned int etherType, const unsigned int etherType,
const unsigned int vlanId, const unsigned int vlanId,
uint8_t &qosBucket); uint8_t& qosBucket);
/** /**
* Apply filters to an incoming packet * Apply filters to an incoming packet
@ -143,12 +168,12 @@ public:
* @return 0 == drop, 1 == accept, 2 == accept even if bridged * @return 0 == drop, 1 == accept, 2 == accept even if bridged
*/ */
int filterIncomingPacket( int filterIncomingPacket(
void *tPtr, void* tPtr,
const SharedPtr<Peer> &sourcePeer, const SharedPtr<Peer>& sourcePeer,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *frameData, const uint8_t* frameData,
const unsigned int frameLen, const unsigned int frameLen,
const unsigned int etherType, const unsigned int etherType,
const unsigned int vlanId); const unsigned int vlanId);
@ -160,7 +185,7 @@ public:
* @param includeBridgedGroups If true, also check groups we've learned via bridging * @param includeBridgedGroups If true, also check groups we've learned via bridging
* @return True if this network endpoint / peer is a member * @return True if this network endpoint / peer is a member
*/ */
bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const; bool subscribedToMulticastGroup(const MulticastGroup& mg, bool includeBridgedGroups) const;
/** /**
* Subscribe to a multicast group * Subscribe to a multicast group
@ -168,14 +193,14 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param mg New multicast group * @param mg New multicast group
*/ */
void multicastSubscribe(void *tPtr,const MulticastGroup &mg); void multicastSubscribe(void* tPtr, const MulticastGroup& mg);
/** /**
* Unsubscribe from a multicast group * Unsubscribe from a multicast group
* *
* @param mg Multicast group * @param mg Multicast group
*/ */
void multicastUnsubscribe(const MulticastGroup &mg); void multicastUnsubscribe(const MulticastGroup& mg);
/** /**
* Handle an inbound network config chunk * Handle an inbound network config chunk
@ -191,7 +216,7 @@ public:
* @param ptr Index of chunk and related fields in packet * @param ptr Index of chunk and related fields in packet
* @return Update ID if update was fully assembled and accepted or 0 otherwise * @return Update ID if update was fully assembled and accepted or 0 otherwise
*/ */
uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr); uint64_t handleConfigChunk(void* tPtr, const uint64_t packetId, const Address& source, const Buffer<ZT_PROTO_MAX_PACKET_LENGTH>& chunk, unsigned int ptr);
/** /**
* Set network configuration * Set network configuration
@ -201,12 +226,12 @@ public:
* @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise.
* @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new
*/ */
int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk); int setConfiguration(void* tPtr, const NetworkConfig& nconf, bool saveToDisk);
/** /**
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
*/ */
inline void setAccessDenied(void *tPtr) inline void setAccessDenied(void* tPtr)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED;
@ -217,7 +242,7 @@ public:
/** /**
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
*/ */
inline void setNotFound(void *tPtr) inline void setNotFound(void* tPtr)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_NOT_FOUND; _netconfFailure = NETCONF_FAILURE_NOT_FOUND;
@ -228,7 +253,7 @@ public:
/** /**
* Set netconf failure to 'authentication required' possibly with an authorization URL * Set netconf failure to 'authentication required' possibly with an authorization URL
*/ */
inline void setAuthenticationRequired(void *tPtr, const char *url) inline void setAuthenticationRequired(void* tPtr, const char* url)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED; _netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED;
@ -242,14 +267,14 @@ public:
* set netconf failure to 'authentication required' along with info needed * set netconf failure to 'authentication required' along with info needed
* for sso full flow authentication. * for sso full flow authentication.
*/ */
void setAuthenticationRequired(void *tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char *ssoProvider, const char* nonce, const char* state); void setAuthenticationRequired(void* tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char* ssoProvider, const char* nonce, const char* state);
/** /**
* Causes this network to request an updated configuration from its master node now * Causes this network to request an updated configuration from its master node now
* *
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/ */
void requestConfiguration(void *tPtr); void requestConfiguration(void* tPtr);
/** /**
* Determine whether this peer is permitted to communicate on this network * Determine whether this peer is permitted to communicate on this network
@ -257,7 +282,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer Peer to check * @param peer Peer to check
*/ */
bool gate(void *tPtr,const SharedPtr<Peer> &peer); bool gate(void* tPtr, const SharedPtr<Peer>& peer);
/** /**
* Check whether a given peer has recently had an association with this network * Check whether a given peer has recently had an association with this network
@ -270,7 +295,7 @@ public:
* @param addr Peer address * @param addr Peer address
* @return True if peer has recently associated * @return True if peer has recently associated
*/ */
bool recentlyAssociatedWith(const Address &addr); bool recentlyAssociatedWith(const Address& addr);
/** /**
* Do periodic cleanup and housekeeping tasks * Do periodic cleanup and housekeeping tasks
@ -282,10 +307,10 @@ public:
* *
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/ */
inline void sendUpdatesToMembers(void *tPtr) inline void sendUpdatesToMembers(void* tPtr)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
_sendUpdatesToMembers(tPtr,(const MulticastGroup *)0); _sendUpdatesToMembers(tPtr, (const MulticastGroup*)0);
} }
/** /**
@ -294,17 +319,20 @@ public:
* @param mac MAC address * @param mac MAC address
* @return ZeroTier address of bridge to this MAC * @return ZeroTier address of bridge to this MAC
*/ */
inline Address findBridgeTo(const MAC &mac) const inline Address findBridgeTo(const MAC& mac) const
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
const Address *const br = _remoteBridgeRoutes.get(mac); const Address* const br = _remoteBridgeRoutes.get(mac);
return ((br) ? *br : Address()); return ((br) ? *br : Address());
} }
/** /**
* @return True if QoS is in effect for this network * @return True if QoS is in effect for this network
*/ */
inline bool qosEnabled() { return false; } inline bool qosEnabled()
{
return false;
}
/** /**
* Set a bridge route * Set a bridge route
@ -312,7 +340,7 @@ public:
* @param mac MAC address of destination * @param mac MAC address of destination
* @param addr Bridge this MAC is reachable behind * @param addr Bridge this MAC is reachable behind
*/ */
void learnBridgeRoute(const MAC &mac,const Address &addr); void learnBridgeRoute(const MAC& mac, const Address& addr);
/** /**
* Learn a multicast group that is bridged to our tap device * Learn a multicast group that is bridged to our tap device
@ -321,52 +349,52 @@ public:
* @param mg Multicast group * @param mg Multicast group
* @param now Current time * @param now Current time
*/ */
void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now); void learnBridgedMulticastGroup(void* tPtr, const MulticastGroup& mg, int64_t now);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com); Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfMembership& com);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap) inline Membership::AddCredentialResult addCredential(void* tPtr, const Capability& cap)
{ {
if (cap.networkId() != _id) { if (cap.networkId() != _id) {
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap); return _membership(cap.issuedTo()).addCredential(RR, tPtr, _config, cap);
} }
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag) inline Membership::AddCredentialResult addCredential(void* tPtr, const Tag& tag)
{ {
if (tag.networkId() != _id) { if (tag.networkId() != _id) {
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag); return _membership(tag.issuedTo()).addCredential(RR, tPtr, _config, tag);
} }
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev); Membership::AddCredentialResult addCredential(void* tPtr, const Address& sentFrom, const Revocation& rev);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo) inline Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfOwnership& coo)
{ {
if (coo.networkId() != _id) { if (coo.networkId() != _id) {
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo); return _membership(coo.issuedTo()).addCredential(RR, tPtr, _config, coo);
} }
/** /**
@ -376,13 +404,13 @@ public:
* @param to Destination peer address * @param to Destination peer address
* @param now Current time * @param now Current time
*/ */
inline void peerRequestedCredentials(void *tPtr,const Address &to,const int64_t now) inline void peerRequestedCredentials(void* tPtr, const Address& to, const int64_t now)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
Membership &m = _membership(to); Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials(); const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) { if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) {
m.pushCredentials(RR,tPtr,now,to,_config); m.pushCredentials(RR, tPtr, now, to, _config);
} }
} }
@ -393,13 +421,13 @@ public:
* @param to Destination peer address * @param to Destination peer address
* @param now Current time * @param now Current time
*/ */
inline void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now) inline void pushCredentialsIfNeeded(void* tPtr, const Address& to, const int64_t now)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
Membership &m = _membership(to); Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials(); const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) { if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) {
m.pushCredentials(RR,tPtr,now,to,_config); m.pushCredentials(RR, tPtr, now, to, _config);
} }
} }
@ -416,7 +444,7 @@ public:
* *
* @param ec Buffer to fill with externally-visible network configuration * @param ec Buffer to fill with externally-visible network configuration
*/ */
inline void externalConfig(ZT_VirtualNetworkConfig *ec) const inline void externalConfig(ZT_VirtualNetworkConfig* ec) const
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
_externalConfig(ec); _externalConfig(ec);
@ -425,36 +453,41 @@ public:
/** /**
* @return Externally usable pointer-to-pointer exported via the core API * @return Externally usable pointer-to-pointer exported via the core API
*/ */
inline void **userPtr() { return &_uPtr; } inline void** userPtr()
{
return &_uPtr;
}
private: private:
ZT_VirtualNetworkStatus _status() const; ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked void _externalConfig(ZT_VirtualNetworkConfig* ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer> &peer); bool _gate(const SharedPtr<Peer>& peer);
void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup); void _sendUpdatesToMembers(void* tPtr, const MulticastGroup* const newMulticastGroup);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups); void _announceMulticastGroupsTo(void* tPtr, const Address& peer, const std::vector<MulticastGroup>& allMulticastGroups);
std::vector<MulticastGroup> _allMulticastGroups() const; std::vector<MulticastGroup> _allMulticastGroups() const;
Membership &_membership(const Address &a); Membership& _membership(const Address& a);
void _sendUpdateEvent(void *tPtr); void _sendUpdateEvent(void* tPtr);
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
void *_uPtr; void* _uPtr;
const uint64_t _id; const uint64_t _id;
std::string _nwidStr; std::string _nwidStr;
uint64_t _lastAnnouncedMulticastGroupsUpstream; uint64_t _lastAnnouncedMulticastGroupsUpstream;
MAC _mac; // local MAC address MAC _mac; // local MAC address
bool _portInitialized; bool _portInitialized;
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap) std::vector<MulticastGroup> _myMulticastGroups; // multicast groups that we belong to (according to tap)
Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) Hashtable<MulticastGroup, uint64_t> _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) Hashtable<MAC, Address> _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
NetworkConfig _config; NetworkConfig _config;
int64_t _lastConfigUpdate; int64_t _lastConfigUpdate;
struct _IncomingConfigChunk struct _IncomingConfigChunk {
_IncomingConfigChunk()
{ {
_IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); } memset(this, 0, sizeof(_IncomingConfigChunk));
}
uint64_t ts; uint64_t ts;
uint64_t updateId; uint64_t updateId;
uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];
@ -466,17 +499,11 @@ private:
bool _destroyed; bool _destroyed;
enum { enum { NETCONF_FAILURE_NONE, NETCONF_FAILURE_ACCESS_DENIED, NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED, NETCONF_FAILURE_AUTHENTICATION_REQUIRED } _netconfFailure;
NETCONF_FAILURE_NONE,
NETCONF_FAILURE_ACCESS_DENIED,
NETCONF_FAILURE_NOT_FOUND,
NETCONF_FAILURE_INIT_FAILED,
NETCONF_FAILURE_AUTHENTICATION_REQUIRED
} _netconfFailure;
int _portError; // return value from port config callback int _portError; // return value from port config callback
std::string _authenticationURL; std::string _authenticationURL;
Hashtable<Address,Membership> _memberships; Hashtable<Address, Membership> _memberships;
Mutex _lock; Mutex _lock;

View file

@ -11,88 +11,87 @@
*/ */
/****/ /****/
#include <stdint.h> #include "NetworkConfig.hpp"
#include <algorithm> #include <algorithm>
#include <stdint.h>
#include "NetworkConfig.hpp"
namespace ZeroTier { namespace ZeroTier {
bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d, bool includeLegacy) const
{ {
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>(); Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>* tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
char tmp2[128] = {0}; char tmp2[128] = { 0 };
try { try {
d.clear(); d.clear();
// Try to put the more human-readable fields first // Try to put the more human-readable fields first
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION, (uint64_t)ZT_NETWORKCONFIG_VERSION)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, this->networkId)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, this->timestamp)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, this->credentialTimeMaxDelta)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION, this->revision)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, this->issuedTo.toString(tmp2))) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET, this->remoteTraceTarget.toString(tmp2))) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL, (uint64_t)this->remoteTraceLevel)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, this->flags)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, (uint64_t)this->multicastLimit)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)this->type)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name)) {
delete tmp; delete tmp;
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU, (uint64_t)this->mtu)) {
delete tmp; delete tmp;
return false; return false;
} }
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
if (includeLegacy) { if (includeLegacy) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD, this->enableBroadcast())) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD, this->isPrivate())) {
return false; return false;
} }
std::string v4s; std::string v4s;
for(unsigned int i=0;i<staticIpCount;++i) { for (unsigned int i = 0; i < staticIpCount; ++i) {
if (this->staticIps[i].ss_family == AF_INET) { if (this->staticIps[i].ss_family == AF_INET) {
if (v4s.length() > 0) { if (v4s.length() > 0) {
v4s.push_back(','); v4s.push_back(',');
@ -102,12 +101,12 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
} }
} }
if (v4s.length() > 0) { if (v4s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD, v4s.c_str())) {
return false; return false;
} }
} }
std::string v6s; std::string v6s;
for(unsigned int i=0;i<staticIpCount;++i) { for (unsigned int i = 0; i < staticIpCount; ++i) {
if (this->staticIps[i].ss_family == AF_INET6) { if (this->staticIps[i].ss_family == AF_INET6) {
if (v6s.length() > 0) { if (v6s.length() > 0) {
v6s.push_back(','); v6s.push_back(',');
@ -117,7 +116,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
} }
} }
if (v6s.length() > 0) { if (v6s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD, v6s.c_str())) {
return false; return false;
} }
} }
@ -125,46 +124,47 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
std::string ets; std::string ets;
unsigned int et = 0; unsigned int et = 0;
ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT; ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT;
for(unsigned int i=0;i<ruleCount;++i) { for (unsigned int i = 0; i < ruleCount; ++i) {
ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f); ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f);
if (rt == ZT_NETWORK_RULE_MATCH_ETHERTYPE) { if (rt == ZT_NETWORK_RULE_MATCH_ETHERTYPE) {
et = rules[i].v.etherType; et = rules[i].v.etherType;
} else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) { }
if (((int)lastrt < 32)||(lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) { else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) {
if (((int)lastrt < 32) || (lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) {
if (ets.length() > 0) { if (ets.length() > 0) {
ets.push_back(','); ets.push_back(',');
} }
char tmp2[16] = {0}; char tmp2[16] = { 0 };
ets.append(Utils::hex((uint16_t)et,tmp2)); ets.append(Utils::hex((uint16_t)et, tmp2));
} }
et = 0; et = 0;
} }
lastrt = rt; lastrt = rt;
} }
if (ets.length() > 0) { if (ets.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD, ets.c_str())) {
return false; return false;
} }
} }
if (this->com) { if (this->com) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD, this->com.toString().c_str())) {
return false; return false;
} }
} }
std::string ab; std::string ab;
for(unsigned int i=0;i<this->specialistCount;++i) { for (unsigned int i = 0; i < this->specialistCount; ++i) {
if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
if (ab.length() > 0) { if (ab.length() > 0) {
ab.push_back(','); ab.push_back(',');
} }
char tmp2[16] = {0}; char tmp2[16] = { 0 };
ab.append(Address(this->specialists[i]).toString(tmp2)); ab.append(Address(this->specialists[i]).toString(tmp2));
} }
} }
if (ab.length() > 0) { if (ab.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, ab.c_str())) {
return false; return false;
} }
} }
@ -176,79 +176,79 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
if (this->com) { if (this->com) {
tmp->clear(); tmp->clear();
this->com.serialize(*tmp); this->com.serialize(*tmp);
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_COM, *tmp)) {
return false; return false;
} }
} }
tmp->clear(); tmp->clear();
for(unsigned int i=0;i<this->capabilityCount;++i) { for (unsigned int i = 0; i < this->capabilityCount; ++i) {
this->capabilities[i].serialize(*tmp); this->capabilities[i].serialize(*tmp);
} }
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES, *tmp)) {
return false; return false;
} }
} }
tmp->clear(); tmp->clear();
for(unsigned int i=0;i<this->tagCount;++i) { for (unsigned int i = 0; i < this->tagCount; ++i) {
this->tags[i].serialize(*tmp); this->tags[i].serialize(*tmp);
} }
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS, *tmp)) {
return false; return false;
} }
} }
tmp->clear(); tmp->clear();
for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i) { for (unsigned int i = 0; i < this->certificateOfOwnershipCount; ++i) {
this->certificatesOfOwnership[i].serialize(*tmp); this->certificatesOfOwnership[i].serialize(*tmp);
} }
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP, *tmp)) {
return false; return false;
} }
} }
tmp->clear(); tmp->clear();
for(unsigned int i=0;i<this->specialistCount;++i) { for (unsigned int i = 0; i < this->specialistCount; ++i) {
tmp->append((uint64_t)this->specialists[i]); tmp->append((uint64_t)this->specialists[i]);
} }
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) {
return false; return false;
} }
} }
tmp->clear(); tmp->clear();
for(unsigned int i=0;i<this->routeCount;++i) { for (unsigned int i = 0; i < this->routeCount; ++i) {
reinterpret_cast<const InetAddress *>(&(this->routes[i].target))->serialize(*tmp); reinterpret_cast<const InetAddress*>(&(this->routes[i].target))->serialize(*tmp);
reinterpret_cast<const InetAddress *>(&(this->routes[i].via))->serialize(*tmp); reinterpret_cast<const InetAddress*>(&(this->routes[i].via))->serialize(*tmp);
tmp->append((uint16_t)this->routes[i].flags); tmp->append((uint16_t)this->routes[i].flags);
tmp->append((uint16_t)this->routes[i].metric); tmp->append((uint16_t)this->routes[i].metric);
} }
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES, *tmp)) {
return false; return false;
} }
} }
tmp->clear(); tmp->clear();
for(unsigned int i=0;i<this->staticIpCount;++i) { for (unsigned int i = 0; i < this->staticIpCount; ++i) {
this->staticIps[i].serialize(*tmp); this->staticIps[i].serialize(*tmp);
} }
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) {
return false; return false;
} }
} }
if (this->ruleCount) { if (this->ruleCount) {
tmp->clear(); tmp->clear();
Capability::serializeRules(*tmp,rules,ruleCount); Capability::serializeRules(*tmp, rules, ruleCount);
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) {
return false; return false;
} }
} }
@ -257,59 +257,61 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
tmp->clear(); tmp->clear();
DNS::serializeDNS(*tmp, &dns); DNS::serializeDNS(*tmp, &dns);
if (tmp->size()) { if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) {
return false; return false;
} }
} }
if (this->ssoVersion == 0) { if (this->ssoVersion == 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
return false; return false;
} }
if (this->ssoEnabled) { if (this->ssoEnabled) {
if (this->authenticationURL[0]) { if (this->authenticationURL[0]) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) {
return false; return false;
} }
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) {
return false; return false;
} }
} }
} else if(this->ssoVersion == 1) { }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) { else if (this->ssoVersion == 1) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
return false; return false;
} }
//if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false; // if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) {
return false; return false;
} }
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) { if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) {
return false; return false;
} }
} }
delete tmp; delete tmp;
} catch ( ... ) { }
catch (...) {
delete tmp; delete tmp;
throw; throw;
} }
@ -317,83 +319,84 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
return true; return true;
} }
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d) bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d)
{ {
static const NetworkConfig NIL_NC; static const NetworkConfig NIL_NC;
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>(); Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>* tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
try { try {
*this = NIL_NC; *this = NIL_NC;
// Fields that are always present, new or old // Fields that are always present, new or old
this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0); this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, 0);
if (!this->networkId) { if (! this->networkId) {
delete tmp; delete tmp;
return false; return false;
} }
this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0); this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, 0);
this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0); this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, 0);
this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0); this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION, 0);
this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0); this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, 0);
if (!this->issuedTo) { if (! this->issuedTo) {
delete tmp; delete tmp;
return false; return false;
} }
this->remoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET); this->remoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET);
this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL); this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL);
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, 0);
d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name, sizeof(this->name));
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU); this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU, ZT_DEFAULT_MTU);
if (this->mtu < 1280) { if (this->mtu < 1280) {
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
} else if (this->mtu > ZT_MAX_MTU) { }
else if (this->mtu > ZT_MAX_MTU) {
this->mtu = ZT_MAX_MTU; this->mtu = ZT_MAX_MTU;
} }
if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION, 0) < 6) {
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
char tmp2[1024] = {0}; char tmp2[1024] = { 0 };
// Decode legacy fields if version is old // Decode legacy fields if version is old
if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) { if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) {
this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
} }
this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf
this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD, true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD, tmp2, sizeof(tmp2)) > 0) {
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) { if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
break; break;
} }
InetAddress ip(f); InetAddress ip(f);
if (!ip.isNetwork()) { if (! ip.isNetwork()) {
this->staticIps[this->staticIpCount++] = ip; this->staticIps[this->staticIpCount++] = ip;
} }
} }
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD, tmp2, sizeof(tmp2)) > 0) {
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) { if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
break; break;
} }
InetAddress ip(f); InetAddress ip(f);
if (!ip.isNetwork()) { if (! ip.isNetwork()) {
this->staticIps[this->staticIpCount++] = ip; this->staticIps[this->staticIpCount++] = ip;
} }
} }
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,tmp2,sizeof(tmp2)) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD, tmp2, sizeof(tmp2)) > 0) {
this->com.fromString(tmp2); this->com.fromString(tmp2);
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,tmp2,sizeof(tmp2)) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD, tmp2, sizeof(tmp2)) > 0) {
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
unsigned int et = Utils::hexStrToUInt(f) & 0xffff; unsigned int et = Utils::hexStrToUInt(f) & 0xffff;
if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) { if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) {
break; break;
@ -405,67 +408,74 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
} }
this->rules[this->ruleCount++].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; this->rules[this->ruleCount++].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
} }
} else { }
else {
this->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT; this->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
this->ruleCount = 1; this->ruleCount = 1;
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,tmp2,sizeof(tmp2)) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, tmp2, sizeof(tmp2)) > 0) {
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
this->addSpecialist(Address(Utils::hexStrToU64(f)),ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); this->addSpecialist(Address(Utils::hexStrToU64(f)), ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
} }
} }
#else #else
delete tmp; delete tmp;
return false; return false;
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF #endif // ZT_SUPPORT_OLD_STYLE_NETCONF
} else { }
else {
// Otherwise we can use the new fields // Otherwise we can use the new fields
this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0); this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, 0);
this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE); this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)ZT_NETWORK_TYPE_PRIVATE);
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM, *tmp)) {
this->com.deserialize(*tmp,0); this->com.deserialize(*tmp, 0);
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES, *tmp)) {
try { try {
unsigned int p = 0; unsigned int p = 0;
while (p < tmp->size()) { while (p < tmp->size()) {
Capability cap; Capability cap;
p += cap.deserialize(*tmp,p); p += cap.deserialize(*tmp, p);
this->capabilities[this->capabilityCount++] = cap; this->capabilities[this->capabilityCount++] = cap;
} }
} catch ( ... ) {} }
std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount])); catch (...) {
}
std::sort(&(this->capabilities[0]), &(this->capabilities[this->capabilityCount]));
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS, *tmp)) {
try { try {
unsigned int p = 0; unsigned int p = 0;
while (p < tmp->size()) { while (p < tmp->size()) {
Tag tag; Tag tag;
p += tag.deserialize(*tmp,p); p += tag.deserialize(*tmp, p);
this->tags[this->tagCount++] = tag; this->tags[this->tagCount++] = tag;
} }
} catch ( ... ) {} }
std::sort(&(this->tags[0]),&(this->tags[this->tagCount])); catch (...) {
}
std::sort(&(this->tags[0]), &(this->tags[this->tagCount]));
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP, *tmp)) {
unsigned int p = 0; unsigned int p = 0;
while (p < tmp->size()) { while (p < tmp->size()) {
if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) { if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) {
p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp,p); p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp, p);
} else { }
else {
CertificateOfOwnership foo; CertificateOfOwnership foo;
p += foo.deserialize(*tmp,p); p += foo.deserialize(*tmp, p);
} }
} }
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) {
unsigned int p = 0; unsigned int p = 0;
while ((p + 8) <= tmp->size()) { while ((p + 8) <= tmp->size()) {
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) { if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
@ -475,11 +485,11 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
} }
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES, *tmp)) {
unsigned int p = 0; unsigned int p = 0;
while ((p < tmp->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) { while ((p < tmp->size()) && (routeCount < ZT_MAX_NETWORK_ROUTES)) {
p += reinterpret_cast<InetAddress *>(&(this->routes[this->routeCount].target))->deserialize(*tmp,p); p += reinterpret_cast<InetAddress*>(&(this->routes[this->routeCount].target))->deserialize(*tmp, p);
p += reinterpret_cast<InetAddress *>(&(this->routes[this->routeCount].via))->deserialize(*tmp,p); p += reinterpret_cast<InetAddress*>(&(this->routes[this->routeCount].via))->deserialize(*tmp, p);
this->routes[this->routeCount].flags = tmp->at<uint16_t>(p); this->routes[this->routeCount].flags = tmp->at<uint16_t>(p);
p += 2; p += 2;
this->routes[this->routeCount].metric = tmp->at<uint16_t>(p); this->routes[this->routeCount].metric = tmp->at<uint16_t>(p);
@ -488,17 +498,17 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
} }
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) {
unsigned int p = 0; unsigned int p = 0;
while ((p < tmp->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { while ((p < tmp->size()) && (staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
p += this->staticIps[this->staticIpCount++].deserialize(*tmp,p); p += this->staticIps[this->staticIpCount++].deserialize(*tmp, p);
} }
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) {
this->ruleCount = 0; this->ruleCount = 0;
unsigned int p = 0; unsigned int p = 0;
Capability::deserializeRules(*tmp,p,this->rules,this->ruleCount,ZT_MAX_NETWORK_RULES); Capability::deserializeRules(*tmp, p, this->rules, this->ruleCount, ZT_MAX_NETWORK_RULES);
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) {
@ -514,15 +524,18 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
if (this->ssoEnabled) { if (this->ssoEnabled) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated
} else { }
else {
this->authenticationURL[0] = 0; this->authenticationURL[0] = 0;
} }
this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0); this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0);
} else { }
else {
this->authenticationURL[0] = 0; this->authenticationURL[0] = 0;
this->authenticationExpiryTime = 0; this->authenticationExpiryTime = 0;
} }
} else if (this->ssoVersion == 1) { }
else if (this->ssoVersion == 1) {
// full flow // full flow
if (this->ssoEnabled) { if (this->ssoEnabled) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
@ -545,11 +558,13 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
} }
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider, (unsigned int)(sizeof(this->ssoProvider))) > 0) { if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider, (unsigned int)(sizeof(this->ssoProvider))) > 0) {
this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0; this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0;
} else { }
else {
strncpy(this->ssoProvider, "default", sizeof(this->ssoProvider)); strncpy(this->ssoProvider, "default", sizeof(this->ssoProvider));
this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0; this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0;
} }
} else { }
else {
this->authenticationURL[0] = 0; this->authenticationURL[0] = 0;
this->authenticationExpiryTime = 0; this->authenticationExpiryTime = 0;
this->centralAuthURL[0] = 0; this->centralAuthURL[0] = 0;
@ -562,13 +577,14 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
} }
} }
//printf("~~~\n%s\n~~~\n",d.data()); // printf("~~~\n%s\n~~~\n",d.data());
//dump(); // dump();
//printf("~~~\n"); // printf("~~~\n");
delete tmp; delete tmp;
return true; return true;
} catch ( ... ) { }
catch (...) {
delete tmp; delete tmp;
return false; return false;
} }

View file

@ -14,31 +14,29 @@
#ifndef ZT_NETWORKCONFIG_HPP #ifndef ZT_NETWORKCONFIG_HPP
#define ZT_NETWORKCONFIG_HPP #define ZT_NETWORKCONFIG_HPP
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include "../include/ZeroTierOne.h" #include "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "Buffer.hpp"
#include "DNS.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buffer.hpp"
#include "Capability.hpp"
#include "CertificateOfMembership.hpp" #include "CertificateOfMembership.hpp"
#include "CertificateOfOwnership.hpp" #include "CertificateOfOwnership.hpp"
#include "Capability.hpp" #include "Constants.hpp"
#include "Tag.hpp" #include "DNS.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "Hashtable.hpp" #include "Hashtable.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp" #include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Tag.hpp"
#include "Trace.hpp" #include "Trace.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
/** /**
* Default time delta for COMs, tags, and capabilities * Default time delta for COMs, tags, and capabilities
@ -93,7 +91,9 @@
namespace ZeroTier { namespace ZeroTier {
// Dictionary capacity needed for max size network config // Dictionary capacity needed for max size network config
#define ZT_NETWORKCONFIG_DICT_CAPACITY (4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP)) #define ZT_NETWORKCONFIG_DICT_CAPACITY \
(4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) \
+ (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
// Dictionary capacity needed for max size network meta-data // Dictionary capacity needed for max size network meta-data
#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024 #define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024
@ -248,46 +248,45 @@ namespace ZeroTier {
* This is a memcpy()'able structure and is safe (in a crash sense) to modify * This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks. * without locks.
*/ */
class NetworkConfig class NetworkConfig {
{ public:
public: NetworkConfig()
NetworkConfig() : : networkId(0)
networkId(0), , timestamp(0)
timestamp(0), , credentialTimeMaxDelta(0)
credentialTimeMaxDelta(0), , revision(0)
revision(0), , issuedTo()
issuedTo(), , remoteTraceTarget()
remoteTraceTarget(), , flags(0)
flags(0), , remoteTraceLevel(Trace::LEVEL_NORMAL)
remoteTraceLevel(Trace::LEVEL_NORMAL), , mtu(0)
mtu(0), , multicastLimit(0)
multicastLimit(0), , specialistCount(0)
specialistCount(0), , routeCount(0)
routeCount(0), , staticIpCount(0)
staticIpCount(0), , ruleCount(0)
ruleCount(0), , capabilityCount(0)
capabilityCount(0), , tagCount(0)
tagCount(0), , certificateOfOwnershipCount(0)
certificateOfOwnershipCount(0), , capabilities()
capabilities(), , tags()
tags(), , certificatesOfOwnership()
certificatesOfOwnership(), , type(ZT_NETWORK_TYPE_PRIVATE)
type(ZT_NETWORK_TYPE_PRIVATE), , dnsCount(0)
dnsCount(0), , ssoEnabled(false)
ssoEnabled(false), , authenticationURL()
authenticationURL(), , authenticationExpiryTime(0)
authenticationExpiryTime(0), , issuerURL()
issuerURL(), , centralAuthURL()
centralAuthURL(), , ssoNonce()
ssoNonce(), , ssoState()
ssoState(), , ssoClientID()
ssoClientID()
{ {
name[0] = 0; name[0] = 0;
memset(specialists, 0, sizeof(uint64_t)*ZT_MAX_NETWORK_SPECIALISTS); memset(specialists, 0, sizeof(uint64_t) * ZT_MAX_NETWORK_SPECIALISTS);
memset(routes, 0, sizeof(ZT_VirtualNetworkRoute)*ZT_MAX_NETWORK_ROUTES); memset(routes, 0, sizeof(ZT_VirtualNetworkRoute) * ZT_MAX_NETWORK_ROUTES);
memset(staticIps, 0, sizeof(InetAddress)*ZT_MAX_ZT_ASSIGNED_ADDRESSES); memset(staticIps, 0, sizeof(InetAddress) * ZT_MAX_ZT_ASSIGNED_ADDRESSES);
memset(rules, 0, sizeof(ZT_VirtualNetworkRule)*ZT_MAX_NETWORK_RULES); memset(rules, 0, sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES);
memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS)); memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS));
memset(authenticationURL, 0, sizeof(authenticationURL)); memset(authenticationURL, 0, sizeof(authenticationURL));
memset(issuerURL, 0, sizeof(issuerURL)); memset(issuerURL, 0, sizeof(issuerURL));
@ -305,7 +304,7 @@ public:
* @param includeLegacy If true, include legacy fields for old node versions * @param includeLegacy If true, include legacy fields for old node versions
* @return True if dictionary was successfully created, false if e.g. overflow * @return True if dictionary was successfully created, false if e.g. overflow
*/ */
bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const; bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d, bool includeLegacy) const;
/** /**
* Read this network config from a dictionary * Read this network config from a dictionary
@ -313,17 +312,23 @@ public:
* @param d Dictionary (non-const since it might be modified during parse, should not be used after call) * @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
* @return True if dictionary was valid and network config successfully initialized * @return True if dictionary was valid and network config successfully initialized
*/ */
bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d); bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d);
/** /**
* @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
*/ */
inline bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); } inline bool enableBroadcast() const
{
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0);
}
/** /**
* @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
*/ */
inline bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } inline bool ndpEmulation() const
{
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0);
}
/** /**
* @return True if frames should not be compressed * @return True if frames should not be compressed
@ -344,12 +349,18 @@ public:
/** /**
* @return Network type is public (no access control) * @return Network type is public (no access control)
*/ */
inline bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); } inline bool isPublic() const
{
return (this->type == ZT_NETWORK_TYPE_PUBLIC);
}
/** /**
* @return Network type is private (certificate access control) * @return Network type is private (certificate access control)
*/ */
inline bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); } inline bool isPrivate() const
{
return (this->type == ZT_NETWORK_TYPE_PRIVATE);
}
/** /**
* @return ZeroTier addresses of devices on this network designated as active bridges * @return ZeroTier addresses of devices on this network designated as active bridges
@ -357,7 +368,7 @@ public:
inline std::vector<Address> activeBridges() const inline std::vector<Address> activeBridges() const
{ {
std::vector<Address> r; std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -368,7 +379,7 @@ public:
inline unsigned int activeBridges(Address ab[ZT_MAX_NETWORK_SPECIALISTS]) const inline unsigned int activeBridges(Address ab[ZT_MAX_NETWORK_SPECIALISTS]) const
{ {
unsigned int c = 0; unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
ab[c++] = specialists[i]; ab[c++] = specialists[i];
} }
@ -376,10 +387,10 @@ public:
return c; return c;
} }
inline bool isActiveBridge(const Address &a) const inline bool isActiveBridge(const Address& a) const
{ {
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)&&(a == specialists[i])) { if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) && (a == specialists[i])) {
return true; return true;
} }
} }
@ -389,7 +400,7 @@ public:
inline std::vector<Address> anchors() const inline std::vector<Address> anchors() const
{ {
std::vector<Address> r; std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -400,7 +411,7 @@ public:
inline std::vector<Address> multicastReplicators() const inline std::vector<Address> multicastReplicators() const
{ {
std::vector<Address> r; std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -411,7 +422,7 @@ public:
inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const
{ {
unsigned int c = 0; unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) { if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
mr[c++] = specialists[i]; mr[c++] = specialists[i];
} }
@ -419,10 +430,10 @@ public:
return c; return c;
} }
inline bool isMulticastReplicator(const Address &a) const inline bool isMulticastReplicator(const Address& a) const
{ {
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)&&(a == specialists[i])) { if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) && (a == specialists[i])) {
return true; return true;
} }
} }
@ -432,7 +443,7 @@ public:
inline std::vector<Address> alwaysContactAddresses() const inline std::vector<Address> alwaysContactAddresses() const
{ {
std::vector<Address> r; std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) { if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
r.push_back(Address(specialists[i])); r.push_back(Address(specialists[i]));
} }
@ -443,7 +454,7 @@ public:
inline unsigned int alwaysContactAddresses(Address ac[ZT_MAX_NETWORK_SPECIALISTS]) const inline unsigned int alwaysContactAddresses(Address ac[ZT_MAX_NETWORK_SPECIALISTS]) const
{ {
unsigned int c = 0; unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) { if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
ac[c++] = specialists[i]; ac[c++] = specialists[i];
} }
@ -451,9 +462,9 @@ public:
return c; return c;
} }
inline void alwaysContactAddresses(Hashtable< Address,std::vector<InetAddress> > &a) const inline void alwaysContactAddresses(Hashtable<Address, std::vector<InetAddress> >& a) const
{ {
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) { if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
a[Address(specialists[i])]; a[Address(specialists[i])];
} }
@ -464,19 +475,28 @@ public:
* @param fromPeer Peer attempting to bridge other Ethernet peers onto network * @param fromPeer Peer attempting to bridge other Ethernet peers onto network
* @return True if this network allows bridging * @return True if this network allows bridging
*/ */
inline bool permitsBridging(const Address &fromPeer) const inline bool permitsBridging(const Address& fromPeer) const
{ {
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) { if ((fromPeer == specialists[i]) && ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) {
return true; return true;
} }
} }
return false; return false;
} }
inline operator bool() const { return (networkId != 0); } inline operator bool() const
inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); } {
inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); } return (networkId != 0);
}
inline bool operator==(const NetworkConfig& nc) const
{
return (memcmp(this, &nc, sizeof(NetworkConfig)) == 0);
}
inline bool operator!=(const NetworkConfig& nc) const
{
return (! (*this == nc));
}
/** /**
* Add a specialist or mask flags if already present * Add a specialist or mask flags if already present
@ -488,10 +508,10 @@ public:
* @param f Flags (OR of specialist role/type flags) * @param f Flags (OR of specialist role/type flags)
* @return True if successfully masked or added * @return True if successfully masked or added
*/ */
inline bool addSpecialist(const Address &a,const uint64_t f) inline bool addSpecialist(const Address& a, const uint64_t f)
{ {
const uint64_t aint = a.toInt(); const uint64_t aint = a.toInt();
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & 0xffffffffffULL) == aint) { if ((specialists[i] & 0xffffffffffULL) == aint) {
specialists[i] |= f; specialists[i] |= f;
return true; return true;
@ -504,24 +524,24 @@ public:
return false; return false;
} }
const Capability *capability(const uint32_t id) const const Capability* capability(const uint32_t id) const
{ {
for(unsigned int i=0;i<capabilityCount;++i) { for (unsigned int i = 0; i < capabilityCount; ++i) {
if (capabilities[i].id() == id) { if (capabilities[i].id() == id) {
return &(capabilities[i]); return &(capabilities[i]);
} }
} }
return (Capability *)0; return (Capability*)0;
} }
const Tag *tag(const uint32_t id) const const Tag* tag(const uint32_t id) const
{ {
for(unsigned int i=0;i<tagCount;++i) { for (unsigned int i = 0; i < tagCount; ++i) {
if (tags[i].id() == id) { if (tags[i].id() == id) {
return &(tags[i]); return &(tags[i]);
} }
} }
return (Tag *)0; return (Tag*)0;
} }
/** /**

View file

@ -14,13 +14,13 @@
#ifndef ZT_NETWORKCONFIGMASTER_HPP #ifndef ZT_NETWORKCONFIGMASTER_HPP
#define ZT_NETWORKCONFIGMASTER_HPP #define ZT_NETWORKCONFIGMASTER_HPP
#include <stdint.h> #include "Address.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#include "Revocation.hpp" #include "Revocation.hpp"
#include "Address.hpp"
#include <stdint.h>
namespace ZeroTier { namespace ZeroTier {
@ -30,23 +30,14 @@ struct InetAddress;
/** /**
* Interface for network controller implementations * Interface for network controller implementations
*/ */
class NetworkController class NetworkController {
{ public:
public: enum ErrorCode { NC_ERROR_NONE = 0, NC_ERROR_OBJECT_NOT_FOUND = 1, NC_ERROR_ACCESS_DENIED = 2, NC_ERROR_INTERNAL_SERVER_ERROR = 3, NC_ERROR_AUTHENTICATION_REQUIRED = 4 };
enum ErrorCode
{
NC_ERROR_NONE = 0,
NC_ERROR_OBJECT_NOT_FOUND = 1,
NC_ERROR_ACCESS_DENIED = 2,
NC_ERROR_INTERNAL_SERVER_ERROR = 3,
NC_ERROR_AUTHENTICATION_REQUIRED = 4
};
/** /**
* Interface for sender used to send pushes and replies * Interface for sender used to send pushes and replies
*/ */
class Sender class Sender {
{
public: public:
/** /**
* Send a configuration to a remote peer * Send a configuration to a remote peer
@ -57,7 +48,7 @@ public:
* @param nc Network configuration to send * @param nc Network configuration to send
* @param sendLegacyFormatConfig If true, send an old-format network config * @param sendLegacyFormatConfig If true, send an old-format network config
*/ */
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) = 0; virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig) = 0;
/** /**
* Send revocation to a node * Send revocation to a node
@ -65,7 +56,7 @@ public:
* @param destination Destination node address * @param destination Destination node address
* @param rev Revocation to send * @param rev Revocation to send
*/ */
virtual void ncSendRevocation(const Address &destination,const Revocation &rev) = 0; virtual void ncSendRevocation(const Address& destination, const Revocation& rev) = 0;
/** /**
* Send a network configuration request error * Send a network configuration request error
@ -80,11 +71,15 @@ public:
* @param errorData Data associated with error or NULL if none * @param errorData Data associated with error or NULL if none
* @param errorDataSize Size of errorData in bytes * @param errorDataSize Size of errorData in bytes
*/ */
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize) = 0; virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize) = 0;
}; };
NetworkController() {} NetworkController()
virtual ~NetworkController() {} {
}
virtual ~NetworkController()
{
}
/** /**
* Called when this is added to a Node to initialize and supply info * Called when this is added to a Node to initialize and supply info
@ -92,7 +87,7 @@ public:
* @param signingId Identity for signing of network configurations, certs, etc. * @param signingId Identity for signing of network configurations, certs, etc.
* @param sender Sender implementation for sending replies or config pushes * @param sender Sender implementation for sending replies or config pushes
*/ */
virtual void init(const Identity &signingId,Sender *sender) = 0; virtual void init(const Identity& signingId, Sender* sender) = 0;
/** /**
* Handle a network configuration request * Handle a network configuration request
@ -104,12 +99,7 @@ public:
* @param metaData Meta-data bundled with request (if any) * @param metaData Meta-data bundled with request (if any)
* @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error * @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error
*/ */
virtual void request( virtual void request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData) = 0;
uint64_t nwid,
const InetAddress &fromAddr,
uint64_t requestPacketId,
const Identity &identity,
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData) = 0;
}; };
} // namespace ZeroTier } // namespace ZeroTier

File diff suppressed because it is too large Load diff

View file

@ -14,29 +14,26 @@
#ifndef ZT_NODE_HPP #ifndef ZT_NODE_HPP
#define ZT_NODE_HPP #define ZT_NODE_HPP
#include "../include/ZeroTierOne.h"
#include "Bond.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include "Mutex.hpp"
#include "Network.hpp"
#include "NetworkController.hpp"
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "Salsa20.hpp"
#include "SelfAwareness.hpp"
#include <map>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <map>
#include <vector> #include <vector>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "RuntimeEnvironment.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "MAC.hpp"
#include "Network.hpp"
#include "Path.hpp"
#include "Salsa20.hpp"
#include "NetworkController.hpp"
#include "Hashtable.hpp"
#include "Bond.hpp"
#include "SelfAwareness.hpp"
// Bit mask for "expecting reply" hash // Bit mask for "expecting reply" hash
#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 #define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255
#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 #define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31
@ -50,94 +47,76 @@ class World;
* *
* The pointer returned by ZT_Node_new() is an instance of this class. * The pointer returned by ZT_Node_new() is an instance of this class.
*/ */
class Node : public NetworkController::Sender class Node : public NetworkController::Sender {
{ public:
public: Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
virtual ~Node(); virtual ~Node();
// Get rid of alignment warnings on 32-bit Windows and possibly improve performance // Get rid of alignment warnings on 32-bit Windows and possibly improve performance
#ifdef __WINDOWS__ #ifdef __WINDOWS__
void * operator new(size_t i) { return _mm_malloc(i,16); } void* operator new(size_t i)
void operator delete(void* p) { _mm_free(p); } {
return _mm_malloc(i, 16);
}
void operator delete(void* p)
{
_mm_free(p);
}
#endif #endif
// Public API Functions ---------------------------------------------------- // Public API Functions ----------------------------------------------------
ZT_ResultCode processWirePacket( ZT_ResultCode processWirePacket(void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline);
void *tptr,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processVirtualNetworkFrame( ZT_ResultCode processVirtualNetworkFrame(
void *tptr, void* tptr,
int64_t now, int64_t now,
uint64_t nwid, uint64_t nwid,
uint64_t sourceMac, uint64_t sourceMac,
uint64_t destMac, uint64_t destMac,
unsigned int etherType, unsigned int etherType,
unsigned int vlanId, unsigned int vlanId,
const void *frameData, const void* frameData,
unsigned int frameLength, unsigned int frameLength,
volatile int64_t *nextBackgroundTaskDeadline); volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); ZT_ResultCode processBackgroundTasks(void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr); ZT_ResultCode join(uint64_t nwid, void* uptr, void* tptr);
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr); ZT_ResultCode leave(uint64_t nwid, void** uptr, void* tptr);
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_ResultCode multicastSubscribe(void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); ZT_ResultCode multicastUnsubscribe(uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed); ZT_ResultCode orbit(void* tptr, uint64_t moonWorldId, uint64_t moonSeed);
ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId); ZT_ResultCode deorbit(void* tptr, uint64_t moonWorldId);
uint64_t address() const; uint64_t address() const;
void status(ZT_NodeStatus *status) const; void status(ZT_NodeStatus* status) const;
ZT_PeerList *peers() const; ZT_PeerList* peers() const;
ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; ZT_VirtualNetworkConfig* networkConfig(uint64_t nwid) const;
ZT_VirtualNetworkList *networks() const; ZT_VirtualNetworkList* networks() const;
void freeQueryResult(void *qr); void freeQueryResult(void* qr);
int addLocalInterfaceAddress(const struct sockaddr_storage *addr); int addLocalInterfaceAddress(const struct sockaddr_storage* addr);
void clearLocalInterfaceAddresses(); void clearLocalInterfaceAddresses();
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); int sendUserMessage(void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len);
void setNetconfMaster(void *networkControllerInstance); void setNetconfMaster(void* networkControllerInstance);
// Internal functions ------------------------------------------------------ // Internal functions ------------------------------------------------------
inline int64_t now() const { return _now; } inline int64_t now() const
inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
{ {
return (_cb.wirePacketSendFunction( return _now;
reinterpret_cast<ZT_Node *>(this),
_uPtr,
tPtr,
localSocket,
reinterpret_cast<const struct sockaddr_storage *>(&addr),
data,
len,
ttl) == 0);
} }
inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) inline bool putPacket(void* tPtr, const int64_t localSocket, const InetAddress& addr, const void* data, unsigned int len, unsigned int ttl = 0)
{ {
_cb.virtualNetworkFrameFunction( return (_cb.wirePacketSendFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, localSocket, reinterpret_cast<const struct sockaddr_storage*>(&addr), data, len, ttl) == 0);
reinterpret_cast<ZT_Node *>(this), }
_uPtr,
tPtr, inline void putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len)
nwid, {
nuptr, _cb.virtualNetworkFrameFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, nwid, nuptr, source.toInt(), dest.toInt(), etherType, vlanId, data, len);
source.toInt(),
dest.toInt(),
etherType,
vlanId,
data,
len);
} }
inline SharedPtr<Network> network(uint64_t nwid) const inline SharedPtr<Network> network(uint64_t nwid) const
{ {
Mutex::Lock _l(_networks_m); Mutex::Lock _l(_networks_m);
const SharedPtr<Network> *n = _networks.get(nwid); const SharedPtr<Network>* n = _networks.get(nwid);
if (n) { if (n) {
return *n; return *n;
} }
@ -150,14 +129,14 @@ public:
return _networks.contains(nwid); return _networks.contains(nwid);
} }
inline std::vector< SharedPtr<Network> > allNetworks() const inline std::vector<SharedPtr<Network> > allNetworks() const
{ {
std::vector< SharedPtr<Network> > nw; std::vector<SharedPtr<Network> > nw;
Mutex::Lock _l(_networks_m); Mutex::Lock _l(_networks_m);
Hashtable< uint64_t,SharedPtr<Network> >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr<Network> > * >(&_networks)); Hashtable<uint64_t, SharedPtr<Network> >::Iterator i(*const_cast<Hashtable<uint64_t, SharedPtr<Network> >*>(&_networks));
uint64_t *k = (uint64_t *)0; uint64_t* k = (uint64_t*)0;
SharedPtr<Network> *v = (SharedPtr<Network> *)0; SharedPtr<Network>* v = (SharedPtr<Network>*)0;
while (i.next(k,v)) { while (i.next(k, v)) {
nw.push_back(*v); nw.push_back(*v);
} }
return nw; return nw;
@ -169,30 +148,60 @@ public:
return _directPaths; return _directPaths;
} }
inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); } inline void postEvent(void* tPtr, ZT_Event ev, const void* md = (const void*)0)
{
_cb.eventCallback(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, ev, md);
}
inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,nwid,nuptr,op,nc); } inline int configureVirtualNetworkPort(void* tPtr, uint64_t nwid, void** nuptr, ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig* nc)
{
return _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, nwid, nuptr, op, nc);
}
inline bool online() const { return _online; } inline bool online() const
{
return _online;
}
inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,maxlen); } inline int stateObjectGet(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], void* const data, const unsigned int maxlen)
inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,(int)len); } {
inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,(const void *)0,-1); } return _cb.stateGetFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, data, maxlen);
}
inline void stateObjectPut(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], const void* const data, const unsigned int len)
{
_cb.statePutFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, data, (int)len);
}
inline void stateObjectDelete(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2])
{
_cb.statePutFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, (const void*)0, -1);
}
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress); bool shouldUsePathForZeroTierTraffic(void* tPtr, const Address& ztaddr, const int64_t localSocket, const InetAddress& remoteAddress);
inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); } inline bool externalPathLookup(void* tPtr, const Address& ztaddr, int family, InetAddress& addr)
{
return ((_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, ztaddr.toInt(), family, reinterpret_cast<struct sockaddr_storage*>(&addr)) != 0) : false);
}
uint64_t prng(); uint64_t prng();
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig);
World planet() const; World planet() const;
std::vector<World> moons() const; std::vector<World> moons() const;
inline const Identity &identity() const { return _RR.identity; } inline const Identity& identity() const
{
return _RR.identity;
}
inline const std::vector<InetAddress> SurfaceAddresses() const { return _RR.sa->whoami(); } inline const std::vector<InetAddress> SurfaceAddresses() const
{
return _RR.sa->whoami();
}
inline Bond *bondController() const { return _RR.bc; } inline Bond* bondController() const
{
return _RR.bc;
}
/** /**
* Register that we are expecting a reply to a packet ID * Register that we are expecting a reply to a packet ID
@ -224,7 +233,7 @@ public:
{ {
const uint32_t pid2 = (uint32_t)(packetId >> 32); const uint32_t pid2 = (uint32_t)(packetId >> 32);
const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { for (unsigned long i = 0; i <= ZT_EXPECTING_REPLIES_BUCKET_MASK2; ++i) {
if (_expectingRepliesTo[bucket][i] == pid2) { if (_expectingRepliesTo[bucket][i] == pid2) {
return true; return true;
} }
@ -239,7 +248,7 @@ public:
* @param from Source address of packet * @param from Source address of packet
* @return True if within rate limits * @return True if within rate limits
*/ */
inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from) inline bool rateGateIdentityVerification(const int64_t now, const InetAddress& from)
{ {
unsigned long iph = from.rateGateHash(); unsigned long iph = from.rateGateHash();
if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) {
@ -249,17 +258,23 @@ public:
return false; return false;
} }
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig); virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address &destination,const Revocation &rev); virtual void ncSendRevocation(const Address& destination, const Revocation& rev);
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize); virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize);
inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; } inline const Address& remoteTraceTarget() const
inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; } {
return _remoteTraceTarget;
}
inline Trace::Level remoteTraceLevel() const
{
return _remoteTraceLevel;
}
inline bool localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const inline bool localControllerHasAuthorized(const int64_t now, const uint64_t nwid, const Address& addr) const
{ {
_localControllerAuthorizations_m.lock(); _localControllerAuthorizations_m.lock();
const int64_t *const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid,addr)); const int64_t* const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid, addr));
_localControllerAuthorizations_m.unlock(); _localControllerAuthorizations_m.unlock();
if (at) { if (at) {
return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3)); return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
@ -267,7 +282,7 @@ public:
return false; return false;
} }
inline void statsLogVerb(const unsigned int v,const unsigned int bytes) inline void statsLogVerb(const unsigned int v, const unsigned int bytes)
{ {
++_stats.inVerbCounts[v]; ++_stats.inVerbCounts[v];
_stats.inVerbBytes[v] += (uint64_t)bytes; _stats.inVerbBytes[v] += (uint64_t)bytes;
@ -285,11 +300,10 @@ public:
void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled); void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled);
public:
public:
RuntimeEnvironment _RR; RuntimeEnvironment _RR;
RuntimeEnvironment *RR; RuntimeEnvironment* RR;
void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P void* _uPtr; // _uptr (lower case) is reserved in Visual Studio :P
ZT_Node_Callbacks _cb; ZT_Node_Callbacks _cb;
// For tracking packet IDs to filter out OK/ERROR replies to packets we did not send // For tracking packet IDs to filter out OK/ERROR replies to packets we did not send
@ -304,18 +318,28 @@ public:
// Map that remembers if we have recently sent a network config to someone // Map that remembers if we have recently sent a network config to someone
// querying us as a controller. // querying us as a controller.
struct _LocalControllerAuth struct _LocalControllerAuth {
uint64_t nwid, address;
_LocalControllerAuth(const uint64_t nwid_, const Address& address_) : nwid(nwid_), address(address_.toInt())
{ {
uint64_t nwid,address; }
_LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {} inline unsigned long hashCode() const
inline unsigned long hashCode() const { return (unsigned long)(nwid ^ address); } {
inline bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); } return (unsigned long)(nwid ^ address);
inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); } }
inline bool operator==(const _LocalControllerAuth& a) const
{
return ((a.nwid == nwid) && (a.address == address));
}
inline bool operator!=(const _LocalControllerAuth& a) const
{
return ((a.nwid != nwid) || (a.address != address));
}
}; };
Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations; Hashtable<_LocalControllerAuth, int64_t> _localControllerAuthorizations;
Mutex _localControllerAuthorizations_m; Mutex _localControllerAuthorizations_m;
Hashtable< uint64_t,SharedPtr<Network> > _networks; Hashtable<uint64_t, SharedPtr<Network> > _networks;
Mutex _networks_m; Mutex _networks_m;
std::vector<InetAddress> _directPaths; std::vector<InetAddress> _directPaths;

View file

@ -11,28 +11,29 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "OutboundMulticast.hpp" #include "OutboundMulticast.hpp"
#include "Switch.hpp"
#include "Constants.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp" #include "Topology.hpp"
namespace ZeroTier { namespace ZeroTier {
void OutboundMulticast::init( void OutboundMulticast::init(
const RuntimeEnvironment *RR, const RuntimeEnvironment* RR,
uint64_t timestamp, uint64_t timestamp,
uint64_t nwid, uint64_t nwid,
bool disableCompression, bool disableCompression,
unsigned int limit, unsigned int limit,
unsigned int gatherLimit, unsigned int gatherLimit,
const MAC &src, const MAC& src,
const MulticastGroup &dest, const MulticastGroup& dest,
unsigned int etherType, unsigned int etherType,
const void *payload, const void* payload,
unsigned int len) unsigned int len)
{ {
uint8_t flags = 0; uint8_t flags = 0;
@ -42,8 +43,9 @@ void OutboundMulticast::init(
if (src) { if (src) {
_macSrc = src; _macSrc = src;
flags |= 0x04; flags |= 0x04;
} else { }
_macSrc.fromAddress(RR->identity.address(),nwid); else {
_macSrc.fromAddress(RR->identity.address(), nwid);
} }
_macDest = dest.mac(); _macDest = dest.mac();
_limit = limit; _limit = limit;
@ -67,25 +69,25 @@ void OutboundMulticast::init(
dest.mac().appendTo(_packet); dest.mac().appendTo(_packet);
_packet.append((uint32_t)dest.adi()); _packet.append((uint32_t)dest.adi());
_packet.append((uint16_t)etherType); _packet.append((uint16_t)etherType);
_packet.append(payload,_frameLen); _packet.append(payload, _frameLen);
if (!disableCompression) { if (! disableCompression) {
_packet.compress(); _packet.compress();
} }
memcpy(_frameData,payload,_frameLen); memcpy(_frameData, payload, _frameLen);
} }
void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) void OutboundMulticast::sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{ {
const SharedPtr<Network> nw(RR->node->network(_nwid)); const SharedPtr<Network> nw(RR->node->network(_nwid));
uint8_t QoSBucket = 255; // Dummy value uint8_t QoSBucket = 255; // Dummy value
if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr,_macSrc,_macDest,_frameData,_frameLen,_etherType,0,QoSBucket))) { if ((nw) && (nw->filterOutgoingPacket(tPtr, true, RR->identity.address(), toAddr, _macSrc, _macDest, _frameData, _frameLen, _etherType, 0, QoSBucket))) {
nw->pushCredentialsIfNeeded(tPtr,toAddr,RR->node->now()); nw->pushCredentialsIfNeeded(tPtr, toAddr, RR->node->now());
_packet.newInitializationVector(); _packet.newInitializationVector();
_packet.setDestination(toAddr); _packet.setDestination(toAddr);
RR->node->expectReplyTo(_packet.packetId()); RR->node->expectReplyTo(_packet.packetId());
_tmp = _packet; _tmp = _packet;
RR->sw->send(tPtr,_tmp,true); RR->sw->send(tPtr, _tmp, true);
} }
} }

View file

@ -14,17 +14,16 @@
#ifndef ZT_OUTBOUNDMULTICAST_HPP #ifndef ZT_OUTBOUNDMULTICAST_HPP
#define ZT_OUTBOUNDMULTICAST_HPP #define ZT_OUTBOUNDMULTICAST_HPP
#include <stdint.h> #include "Address.hpp"
#include <vector>
#include <algorithm>
#include "Constants.hpp" #include "Constants.hpp"
#include "MAC.hpp" #include "MAC.hpp"
#include "MulticastGroup.hpp" #include "MulticastGroup.hpp"
#include "Address.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include <algorithm>
#include <stdint.h>
#include <vector>
namespace ZeroTier { namespace ZeroTier {
class CertificateOfMembership; class CertificateOfMembership;
@ -35,15 +34,16 @@ class RuntimeEnvironment;
* *
* This object isn't guarded by a mutex; caller must synchronize access. * This object isn't guarded by a mutex; caller must synchronize access.
*/ */
class OutboundMulticast class OutboundMulticast {
{ public:
public:
/** /**
* Create an uninitialized outbound multicast * Create an uninitialized outbound multicast
* *
* It must be initialized with init(). * It must be initialized with init().
*/ */
OutboundMulticast() {} OutboundMulticast()
{
}
/** /**
* Initialize outbound multicast * Initialize outbound multicast
@ -62,33 +62,42 @@ public:
* @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME * @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME
*/ */
void init( void init(
const RuntimeEnvironment *RR, const RuntimeEnvironment* RR,
uint64_t timestamp, uint64_t timestamp,
uint64_t nwid, uint64_t nwid,
bool disableCompression, bool disableCompression,
unsigned int limit, unsigned int limit,
unsigned int gatherLimit, unsigned int gatherLimit,
const MAC &src, const MAC& src,
const MulticastGroup &dest, const MulticastGroup& dest,
unsigned int etherType, unsigned int etherType,
const void *payload, const void* payload,
unsigned int len); unsigned int len);
/** /**
* @return Multicast creation time * @return Multicast creation time
*/ */
inline uint64_t timestamp() const { return _timestamp; } inline uint64_t timestamp() const
{
return _timestamp;
}
/** /**
* @param now Current time * @param now Current time
* @return True if this multicast is expired (has exceeded transmit timeout) * @return True if this multicast is expired (has exceeded transmit timeout)
*/ */
inline bool expired(int64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } inline bool expired(int64_t now) const
{
return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT);
}
/** /**
* @return True if this outbound multicast has been sent to enough peers * @return True if this outbound multicast has been sent to enough peers
*/ */
inline bool atLimit() const { return (_alreadySentTo.size() >= _limit); } inline bool atLimit() const
{
return (_alreadySentTo.size() >= _limit);
}
/** /**
* Just send without checking log * Just send without checking log
@ -97,7 +106,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address * @param toAddr Destination address
*/ */
void sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr); void sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr);
/** /**
* Just send and log but do not check sent log * Just send and log but do not check sent log
@ -106,10 +115,10 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address * @param toAddr Destination address
*/ */
inline void sendAndLog(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) inline void sendAndLog(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{ {
_alreadySentTo.push_back(toAddr); _alreadySentTo.push_back(toAddr);
sendOnly(RR,tPtr,toAddr); sendOnly(RR, tPtr, toAddr);
} }
/** /**
@ -117,7 +126,7 @@ public:
* *
* @param toAddr Address to log as sent * @param toAddr Address to log as sent
*/ */
inline void logAsSent(const Address &toAddr) inline void logAsSent(const Address& toAddr)
{ {
_alreadySentTo.push_back(toAddr); _alreadySentTo.push_back(toAddr);
} }
@ -130,17 +139,18 @@ public:
* @param toAddr Destination address * @param toAddr Destination address
* @return True if address is new and packet was sent to switch, false if duplicate * @return True if address is new and packet was sent to switch, false if duplicate
*/ */
inline bool sendIfNew(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) inline bool sendIfNew(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{ {
if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) { if (std::find(_alreadySentTo.begin(), _alreadySentTo.end(), toAddr) == _alreadySentTo.end()) {
sendAndLog(RR,tPtr,toAddr); sendAndLog(RR, tPtr, toAddr);
return true; return true;
} else { }
else {
return false; return false;
} }
} }
private: private:
uint64_t _timestamp; uint64_t _timestamp;
uint64_t _nwid; uint64_t _nwid;
MAC _macSrc; MAC _macSrc;
@ -148,7 +158,7 @@ private:
unsigned int _limit; unsigned int _limit;
unsigned int _frameLen; unsigned int _frameLen;
unsigned int _etherType; unsigned int _etherType;
Packet _packet,_tmp; Packet _packet, _tmp;
std::vector<Address> _alreadySentTo; std::vector<Address> _alreadySentTo;
uint8_t _frameData[ZT_MAX_MTU]; uint8_t _frameData[ZT_MAX_MTU];
}; };

File diff suppressed because it is too large Load diff

View file

@ -14,22 +14,20 @@
#ifndef ZT_N_PACKET_HPP #ifndef ZT_N_PACKET_HPP
#define ZT_N_PACKET_HPP #define ZT_N_PACKET_HPP
#include <stdint.h> #include "AES.hpp"
#include <string.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include "Constants.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Identity.hpp"
#include "Poly1305.hpp" #include "Poly1305.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "AES.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp" #include <iostream>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
/** /**
* Protocol version -- incremented only for major changes * Protocol version -- incremented only for major changes
@ -345,9 +343,8 @@ namespace ZeroTier {
* For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever * For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever
* sent in the clear, as it's the "here is my public key" message. * sent in the clear, as it's the "here is my public key" message.
*/ */
class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> {
{ public:
public:
/** /**
* A packet fragment * A packet fragment
* *
@ -374,22 +371,17 @@ public:
* receipt to authenticate and decrypt; there is no per-fragment MAC. (But if * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if
* fragments are corrupt, the MAC will fail for the whole assembled packet.) * fragments are corrupt, the MAC will fail for the whole assembled packet.)
*/ */
class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> {
{
public: public:
Fragment() : Fragment() : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
{ {
} }
template<unsigned int C2> template <unsigned int C2> Fragment(const Buffer<C2>& b) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
Fragment(const Buffer<C2> &b) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
{ {
} }
Fragment(const void *data,unsigned int len) : Fragment(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, len)
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
{ {
} }
@ -402,9 +394,9 @@ public:
* @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0) * @param fragTotal Total number of fragments (including 0)
*/ */
Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) Fragment(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal)
{ {
init(p,fragStart,fragLen,fragNo,fragTotal); init(p, fragStart, fragLen, fragNo, fragTotal);
} }
/** /**
@ -416,7 +408,7 @@ public:
* @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0) * @param fragTotal Total number of fragments (including 0)
*/ */
inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) inline void init(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal)
{ {
if ((fragStart + fragLen) > p.size()) { if ((fragStart + fragLen) > p.size()) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
@ -424,13 +416,13 @@ public:
setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
// NOTE: this copies both the IV/packet ID and the destination address. // NOTE: this copies both the IV/packet ID and the destination address.
memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.field(ZT_PACKET_IDX_IV,13),13); memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID, 13), p.field(ZT_PACKET_IDX_IV, 13), 13);
(*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR; (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
(*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf)); (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
(*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0; (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0;
memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.field(fragStart,fragLen),fragLen); memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, fragLen), p.field(fragStart, fragLen), fragLen);
} }
/** /**
@ -438,32 +430,50 @@ public:
* *
* @return Destination ZT address * @return Destination ZT address
*/ */
inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline Address destination() const
{
return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/** /**
* @return True if fragment is of a valid length * @return True if fragment is of a valid length
*/ */
inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); } inline bool lengthValid() const
{
return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
}
/** /**
* @return ID of packet this is a fragment of * @return ID of packet this is a fragment of
*/ */
inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); } inline uint64_t packetId() const
{
return at<uint64_t>(ZT_PACKET_FRAGMENT_IDX_PACKET_ID);
}
/** /**
* @return Total number of fragments in packet * @return Total number of fragments in packet
*/ */
inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); } inline unsigned int totalFragments() const
{
return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf);
}
/** /**
* @return Fragment number of this fragment * @return Fragment number of this fragment
*/ */
inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); } inline unsigned int fragmentNumber() const
{
return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf);
}
/** /**
* @return Fragment ZT hop count * @return Fragment ZT hop count
*/ */
inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); } inline unsigned int hops() const
{
return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]);
}
/** /**
* Increment this packet's hop count * Increment this packet's hop count
@ -476,14 +486,17 @@ public:
/** /**
* @return Length of payload in bytes * @return Length of payload in bytes
*/ */
inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); } inline unsigned int payloadLength() const
{
return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0);
}
/** /**
* @return Raw packet payload * @return Raw packet payload
*/ */
inline const unsigned char *payload() const inline const unsigned char* payload() const
{ {
return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD); return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
} }
}; };
@ -1013,8 +1026,7 @@ public:
/** /**
* Error codes for VERB_ERROR * Error codes for VERB_ERROR
*/ */
enum ErrorCode enum ErrorCode {
{
/* No error, not actually used in transit */ /* No error, not actually used in transit */
ERROR_NONE = 0x00, ERROR_NONE = 0x00,
@ -1046,14 +1058,11 @@ public:
ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09 ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09
}; };
template<unsigned int C2> template <unsigned int C2> Packet(const Buffer<C2>& b) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
Packet(const Buffer<C2> &b) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
{ {
} }
Packet(const void *data,unsigned int len) : Packet(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, len)
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
{ {
} }
@ -1064,10 +1073,9 @@ public:
* Use the header access methods (setDestination() and friends) to fill out * Use the header access methods (setDestination() and friends) to fill out
* the header. Payload should be appended; initial size is header size. * the header. Payload should be appended; initial size is header size.
*/ */
Packet() : Packet() : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
{ {
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
} }
@ -1080,10 +1088,9 @@ public:
* @param prototype Prototype packet * @param prototype Prototype packet
* @param dest Destination ZeroTier address for new packet * @param dest Destination ZeroTier address for new packet
*/ */
Packet(const Packet &prototype,const Address &dest) : Packet(const Packet& prototype, const Address& dest) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
{ {
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest); setDestination(dest);
} }
@ -1094,10 +1101,9 @@ public:
* @param source Source ZT address * @param source Source ZT address
* @param v Verb * @param v Verb
*/ */
Packet(const Address &dest,const Address &source,const Verb v) : Packet(const Address& dest, const Address& source, const Verb v) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
{ {
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest); setDestination(dest);
setSource(source); setSource(source);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
@ -1111,10 +1117,10 @@ public:
* @param source Source ZT address * @param source Source ZT address
* @param v Verb * @param v Verb
*/ */
inline void reset(const Address &dest,const Address &source,const Verb v) inline void reset(const Address& dest, const Address& source, const Verb v)
{ {
setSize(ZT_PROTO_MIN_PACKET_LENGTH); setSize(ZT_PROTO_MIN_PACKET_LENGTH);
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest); setDestination(dest);
setSource(source); setSource(source);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
@ -1128,45 +1134,66 @@ public:
* technically different but otherwise identical copies of the same * technically different but otherwise identical copies of the same
* packet. * packet.
*/ */
inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); } inline void newInitializationVector()
{
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
}
/** /**
* Set this packet's destination * Set this packet's destination
* *
* @param dest ZeroTier address of destination * @param dest ZeroTier address of destination
*/ */
inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline void setDestination(const Address& dest)
{
dest.copyTo(field(ZT_PACKET_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/** /**
* Set this packet's source * Set this packet's source
* *
* @param source ZeroTier address of source * @param source ZeroTier address of source
*/ */
inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline void setSource(const Address& source)
{
source.copyTo(field(ZT_PACKET_IDX_SOURCE, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/** /**
* Get this packet's destination * Get this packet's destination
* *
* @return Destination ZT address * @return Destination ZT address
*/ */
inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline Address destination() const
{
return Address(field(ZT_PACKET_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/** /**
* Get this packet's source * Get this packet's source
* *
* @return Source ZT address * @return Source ZT address
*/ */
inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline Address source() const
{
return Address(field(ZT_PACKET_IDX_SOURCE, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/** /**
* @return True if packet is of valid length * @return True if packet is of valid length
*/ */
inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); } inline bool lengthValid() const
{
return (size() >= ZT_PROTO_MIN_PACKET_LENGTH);
}
/** /**
* @return True if packet is fragmented (expect fragments) * @return True if packet is fragmented (expect fragments)
*/ */
inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); } inline bool fragmented() const
{
return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0);
}
/** /**
* Set this packet's fragmented flag * Set this packet's fragmented flag
@ -1177,7 +1204,8 @@ public:
{ {
if (f) { if (f) {
(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED; (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
} else { }
else {
(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED); (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
} }
} }
@ -1185,7 +1213,10 @@ public:
/** /**
* @return True if packet is encrypted with an extra ephemeral key * @return True if packet is encrypted with an extra ephemeral key
*/ */
inline bool extendedArmor() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_EXTENDED_ARMOR) != 0); } inline bool extendedArmor() const
{
return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_EXTENDED_ARMOR) != 0);
}
/** /**
* Set this packet's extended armor flag * Set this packet's extended armor flag
@ -1196,7 +1227,8 @@ public:
{ {
if (f) { if (f) {
(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_EXTENDED_ARMOR; (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_EXTENDED_ARMOR;
} else { }
else {
(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_EXTENDED_ARMOR); (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_EXTENDED_ARMOR);
} }
} }
@ -1204,19 +1236,25 @@ public:
/** /**
* @return True if compressed (result only valid if unencrypted) * @return True if compressed (result only valid if unencrypted)
*/ */
inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); } inline bool compressed() const
{
return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0);
}
/** /**
* @return ZeroTier forwarding hops (0 to 7) * @return ZeroTier forwarding hops (0 to 7)
*/ */
inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); } inline unsigned int hops() const
{
return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07);
}
/** /**
* Increment this packet's hop count * Increment this packet's hop count
*/ */
inline void incrementHops() inline void incrementHops()
{ {
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xf8) | ((b + 1) & 0x07); b = (b & 0xf8) | ((b + 1) & 0x07);
} }
@ -1241,7 +1279,7 @@ public:
*/ */
inline void setCipher(unsigned int c) inline void setCipher(unsigned int c)
{ {
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
} }
@ -1250,7 +1288,10 @@ public:
* *
* @return Trusted path ID (from MAC field) * @return Trusted path ID (from MAC field)
*/ */
inline uint64_t trustedPathId() const { return at<uint64_t>(ZT_PACKET_IDX_MAC); } inline uint64_t trustedPathId() const
{
return at<uint64_t>(ZT_PACKET_IDX_MAC);
}
/** /**
* Set this packet's trusted path ID and set the cipher spec to trusted path * Set this packet's trusted path ID and set the cipher spec to trusted path
@ -1260,7 +1301,7 @@ public:
inline void setTrusted(const uint64_t tpid) inline void setTrusted(const uint64_t tpid)
{ {
setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH); setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH);
setAt(ZT_PACKET_IDX_MAC,tpid); setAt(ZT_PACKET_IDX_MAC, tpid);
} }
/** /**
@ -1274,7 +1315,10 @@ public:
* *
* @return Packet ID * @return Packet ID
*/ */
inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_IDX_IV); } inline uint64_t packetId() const
{
return at<uint64_t>(ZT_PACKET_IDX_IV);
}
/** /**
* Set packet verb * Set packet verb
@ -1284,22 +1328,34 @@ public:
* *
* @param v New packet verb * @param v New packet verb
*/ */
inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; } inline void setVerb(Verb v)
{
(*this)[ZT_PACKET_IDX_VERB] = (char)v;
}
/** /**
* @return Packet verb (not including flag bits) * @return Packet verb (not including flag bits)
*/ */
inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); } inline Verb verb() const
{
return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f);
}
/** /**
* @return Length of packet payload * @return Length of packet payload
*/ */
inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); } inline unsigned int payloadLength() const
{
return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH));
}
/** /**
* @return Raw packet payload * @return Raw packet payload
*/ */
inline const unsigned char *payload() const { return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); } inline const unsigned char* payload() const
{
return field(ZT_PACKET_IDX_PAYLOAD, size() - ZT_PACKET_IDX_PAYLOAD);
}
/** /**
* Armor packet for transport * Armor packet for transport
@ -1310,7 +1366,7 @@ public:
* @param identity Identity of packet recipient/destination * @param identity Identity of packet recipient/destination
* @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV
*/ */
void armor(const void *key,bool encryptPayload,bool extendedArmor,const AES aesKeys[2],const Identity &identity); void armor(const void* key, bool encryptPayload, bool extendedArmor, const AES aesKeys[2], const Identity& identity);
/** /**
* Verify and (if encrypted) decrypt packet * Verify and (if encrypted) decrypt packet
@ -1324,7 +1380,7 @@ public:
* @param identity Receiver's identity (must include secret) * @param identity Receiver's identity (must include secret)
* @return False if packet is invalid or failed MAC authenticity check * @return False if packet is invalid or failed MAC authenticity check
*/ */
bool dearmor(const void *key,const AES aesKeys[2],const Identity &identity); bool dearmor(const void* key, const AES aesKeys[2], const Identity& identity);
/** /**
* Encrypt/decrypt a separately armored portion of a packet * Encrypt/decrypt a separately armored portion of a packet
@ -1339,7 +1395,7 @@ public:
* @param start Start of encrypted portion * @param start Start of encrypted portion
* @param len Length of encrypted portion * @param len Length of encrypted portion
*/ */
void cryptField(const void *key,unsigned int start,unsigned int len); void cryptField(const void* key, unsigned int start, unsigned int len);
/** /**
* Attempt to compress payload if not already (must be unencrypted) * Attempt to compress payload if not already (must be unencrypted)
@ -1363,7 +1419,7 @@ public:
*/ */
bool uncompress(); bool uncompress();
private: private:
static const unsigned char ZERO_KEY[32]; static const unsigned char ZERO_KEY[32];
/** /**
@ -1377,13 +1433,13 @@ private:
* @param in Input key (32 bytes) * @param in Input key (32 bytes)
* @param out Output buffer (32 bytes) * @param out Output buffer (32 bytes)
*/ */
inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const inline void _salsa20MangleKey(const unsigned char* in, unsigned char* out) const
{ {
const unsigned char *d = (const unsigned char *)data(); const unsigned char* d = (const unsigned char*)data();
// IV and source/destination addresses. Using the addresses divides the // IV and source/destination addresses. Using the addresses divides the
// key space into two halves-- A->B and B->A (since order will change). // key space into two halves-- A->B and B->A (since order will change).
for(unsigned int i=0;i<18;++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18 for (unsigned int i = 0; i < 18; ++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
out[i] = in[i] ^ d[i]; out[i] = in[i] ^ d[i];
} }
@ -1398,7 +1454,7 @@ private:
out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian
// Rest of raw key is used unchanged // Rest of raw key is used unchanged
for(unsigned int i=21;i<32;++i) { for (unsigned int i = 21; i < 32; ++i) {
out[i] = in[i]; out[i] = in[i];
} }
} }

View file

@ -13,9 +13,9 @@
#include "PacketMultiplexer.hpp" #include "PacketMultiplexer.hpp"
#include "Constants.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp" #include "RuntimeEnvironment.hpp"
#include "Constants.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -30,12 +30,12 @@ PacketMultiplexer::PacketMultiplexer(const RuntimeEnvironment* renv)
void PacketMultiplexer::putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len, unsigned int flowId) void PacketMultiplexer::putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len, unsigned int flowId)
{ {
#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__WINDOWS__) #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__WINDOWS__)
RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len); RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len);
return; return;
#endif #endif
if (!_enabled) { if (! _enabled) {
RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len); RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len);
return; return;
} }

View file

@ -12,14 +12,15 @@
/****/ /****/
#include "Path.hpp" #include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
namespace ZeroTier { namespace ZeroTier {
bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now) bool Path::send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now)
{ {
if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) { if (RR->node->putPacket(tPtr, _localSocket, _addr, data, len)) {
_lastOut = now; _lastOut = now;
return true; return true;
} }

View file

@ -14,20 +14,19 @@
#ifndef ZT_PATH_HPP #ifndef ZT_PATH_HPP
#define ZT_PATH_HPP #define ZT_PATH_HPP
#include <stdint.h> #include "AtomicCounter.hpp"
#include <string.h>
#include <stdlib.h>
#include <stdexcept>
#include <algorithm>
#include "Constants.hpp" #include "Constants.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "Utils.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include "RingBuffer.hpp" #include "RingBuffer.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/** /**
* Maximum return value of preferenceRank() * Maximum return value of preferenceRank()
@ -41,89 +40,102 @@ class RuntimeEnvironment;
/** /**
* A path across the physical network * A path across the physical network
*/ */
class Path class Path {
{
friend class SharedPtr<Path>; friend class SharedPtr<Path>;
friend class Bond; friend class Bond;
public: public:
/** /**
* Efficient unique key for paths in a Hashtable * Efficient unique key for paths in a Hashtable
*/ */
class HashKey class HashKey {
{
public: public:
HashKey() {} HashKey()
{
}
HashKey(const int64_t l,const InetAddress &r) HashKey(const int64_t l, const InetAddress& r)
{ {
if (r.ss_family == AF_INET) { if (r.ss_family == AF_INET) {
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr; _k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in*>(&r)->sin_addr.s_addr;
_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port; _k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in*>(&r)->sin_port;
_k[2] = (uint64_t)l; _k[2] = (uint64_t)l;
} else if (r.ss_family == AF_INET6) { }
memcpy(_k,reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16); else if (r.ss_family == AF_INET6) {
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port << 32) ^ (uint64_t)l; memcpy(_k, reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, 16);
} else { _k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_port << 32) ^ (uint64_t)l;
memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress))); }
else {
memcpy(_k, &r, std::min(sizeof(_k), sizeof(InetAddress)));
_k[2] += (uint64_t)l; _k[2] += (uint64_t)l;
} }
} }
inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); } inline unsigned long hashCode() const
{
return (unsigned long)(_k[0] + _k[1] + _k[2]);
}
inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); } inline bool operator==(const HashKey& k) const
inline bool operator!=(const HashKey &k) const { return (!(*this == k)); } {
return ((_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]));
}
inline bool operator!=(const HashKey& k) const
{
return (! (*this == k));
}
private: private:
uint64_t _k[3]; uint64_t _k[3];
}; };
Path() : Path()
_lastOut(0), : _lastOut(0)
_lastIn(0), , _lastIn(0)
_lastTrustEstablishedPacketReceived(0), , _lastTrustEstablishedPacketReceived(0)
_lastEchoRequestReceived(0), , _lastEchoRequestReceived(0)
_localPort(0), , _localPort(0)
_localSocket(-1), , _localSocket(-1)
_latencyMean(0.0), , _latencyMean(0.0)
_latencyVariance(0.0), , _latencyVariance(0.0)
_packetLossRatio(0.0), , _packetLossRatio(0.0)
_packetErrorRatio(0.0), , _packetErrorRatio(0.0)
_assignedFlowCount(0), , _assignedFlowCount(0)
_valid(true), , _valid(true)
_eligible(false), , _eligible(false)
_bonded(false), , _bonded(false)
_mtu(0), , _mtu(0)
_givenLinkSpeed(0), , _givenLinkSpeed(0)
_relativeQuality(0), , _relativeQuality(0)
_latency(0xffff), , _latency(0xffff)
_addr(), , _addr()
_ipScope(InetAddress::IP_SCOPE_NONE) , _ipScope(InetAddress::IP_SCOPE_NONE)
{} {
}
Path(const int64_t localSocket,const InetAddress &addr) : Path(const int64_t localSocket, const InetAddress& addr)
_lastOut(0), : _lastOut(0)
_lastIn(0), , _lastIn(0)
_lastTrustEstablishedPacketReceived(0), , _lastTrustEstablishedPacketReceived(0)
_lastEchoRequestReceived(0), , _lastEchoRequestReceived(0)
_localPort(0), , _localPort(0)
_localSocket(localSocket), , _localSocket(localSocket)
_latencyMean(0.0), , _latencyMean(0.0)
_latencyVariance(0.0), , _latencyVariance(0.0)
_packetLossRatio(0.0), , _packetLossRatio(0.0)
_packetErrorRatio(0.0), , _packetErrorRatio(0.0)
_assignedFlowCount(0), , _assignedFlowCount(0)
_valid(true), , _valid(true)
_eligible(false), , _eligible(false)
_bonded(false), , _bonded(false)
_mtu(0), , _mtu(0)
_givenLinkSpeed(0), , _givenLinkSpeed(0)
_relativeQuality(0), , _relativeQuality(0)
_latency(0xffff), , _latency(0xffff)
_addr(addr), , _addr(addr)
_ipScope(addr.ipScope()) , _ipScope(addr.ipScope())
{} {
}
/** /**
* Called when a packet is received from this remote path, regardless of content * Called when a packet is received from this remote path, regardless of content
@ -138,7 +150,10 @@ public:
/** /**
* Set time last trusted packet was received (done in Peer::received()) * Set time last trusted packet was received (done in Peer::received())
*/ */
inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; } inline void trustedPacketReceived(const uint64_t t)
{
_lastTrustEstablishedPacketReceived = t;
}
/** /**
* Send a packet via this path (last out time is also updated) * Send a packet via this path (last out time is also updated)
@ -150,14 +165,17 @@ public:
* @param now Current time * @param now Current time
* @return True if transport reported success * @return True if transport reported success
*/ */
bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now); bool send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now);
/** /**
* Manually update last sent time * Manually update last sent time
* *
* @param t Time of send * @param t Time of send
*/ */
inline void sent(const int64_t t) { _lastOut = t; } inline void sent(const int64_t t)
{
_lastOut = t;
}
/** /**
* Update path latency with a new measurement * Update path latency with a new measurement
@ -169,7 +187,8 @@ public:
unsigned int pl = _latency; unsigned int pl = _latency;
if (pl < 0xffff) { if (pl < 0xffff) {
_latency = (pl + l) / 2; _latency = (pl + l) / 2;
} else { }
else {
_latency = l; _latency = l;
} }
} }
@ -177,27 +196,42 @@ public:
/** /**
* @return Local socket as specified by external code * @return Local socket as specified by external code
*/ */
inline int64_t localSocket() const { return _localSocket; } inline int64_t localSocket() const
{
return _localSocket;
}
/** /**
* @return Local port corresponding to the localSocket * @return Local port corresponding to the localSocket
*/ */
inline int64_t localPort() const { return _localPort; } inline int64_t localPort() const
{
return _localPort;
}
/** /**
* @return Physical address * @return Physical address
*/ */
inline const InetAddress &address() const { return _addr; } inline const InetAddress& address() const
{
return _addr;
}
/** /**
* @return IP scope -- faster shortcut for address().ipScope() * @return IP scope -- faster shortcut for address().ipScope()
*/ */
inline InetAddress::IpScope ipScope() const { return _ipScope; } inline InetAddress::IpScope ipScope() const
{
return _ipScope;
}
/** /**
* @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/ */
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } inline bool trustEstablished(const int64_t now) const
{
return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION);
}
/** /**
* @return Preference rank, higher == better * @return Preference rank, higher == better
@ -206,7 +240,7 @@ public:
{ {
// This causes us to rank paths in order of IP scope rank (see InetAddress.hpp) but // This causes us to rank paths in order of IP scope rank (see InetAddress.hpp) but
// within each IP scope class to prefer IPv6 over IPv4. // within each IP scope class to prefer IPv6 over IPv4.
return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); return (((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6));
} }
/** /**
@ -218,10 +252,10 @@ public:
* @param a Address to check * @param a Address to check
* @return True if address is good for ZeroTier path use * @return True if address is good for ZeroTier path use
*/ */
static inline bool isAddressValidForPath(const InetAddress &a) static inline bool isAddressValidForPath(const InetAddress& a)
{ {
if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) { if ((a.ss_family == AF_INET) || (a.ss_family == AF_INET6)) {
switch(a.ipScope()) { switch (a.ipScope()) {
/* Note: we don't do link-local at the moment. Unfortunately these /* Note: we don't do link-local at the moment. Unfortunately these
* cause several issues. The first is that they usually require a * cause several issues. The first is that they usually require a
* device qualifier, which we don't handle yet and can't portably * device qualifier, which we don't handle yet and can't portably
@ -237,8 +271,8 @@ public:
// TEMPORARY HACK: for now, we are going to blacklist he.net IPv6 // TEMPORARY HACK: for now, we are going to blacklist he.net IPv6
// tunnels due to very spotty performance and low MTU issues over // tunnels due to very spotty performance and low MTU issues over
// these IPv6 tunnel links. // these IPv6 tunnel links.
const uint8_t *ipd = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr); const uint8_t* ipd = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_addr.s6_addr);
if ((ipd[0] == 0x20)&&(ipd[1] == 0x01)&&(ipd[2] == 0x04)&&(ipd[3] == 0x70)) { if ((ipd[0] == 0x20) && (ipd[1] == 0x01) && (ipd[2] == 0x04) && (ipd[3] == 0x70)) {
return false; return false;
} }
} }
@ -253,7 +287,10 @@ public:
/** /**
* @return Latency or 0xffff if unknown * @return Latency or 0xffff if unknown
*/ */
inline unsigned int latency() const { return _latency; } inline unsigned int latency() const
{
return _latency;
}
/** /**
* @return Path quality -- lower is better * @return Path quality -- lower is better
@ -261,41 +298,57 @@ public:
inline long quality(const int64_t now) const inline long quality(const int64_t now) const
{ {
const int l = (long)_latency; const int l = (long)_latency;
const int age = (long)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow const int age = (long)std::min((now - _lastIn), (int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow
return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1));
} }
/** /**
* @return True if this path is alive (receiving heartbeats) * @return True if this path is alive (receiving heartbeats)
*/ */
inline bool alive(const int64_t now) const { inline bool alive(const int64_t now) const
{
return (now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000); return (now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000);
} }
/** /**
* @return True if this path needs a heartbeat * @return True if this path needs a heartbeat
*/ */
inline bool needsHeartbeat(const int64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } inline bool needsHeartbeat(const int64_t now) const
{
return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD);
}
/** /**
* @return Last time we sent something * @return Last time we sent something
*/ */
inline int64_t lastOut() const { return _lastOut; } inline int64_t lastOut() const
{
return _lastOut;
}
/** /**
* @return Last time we received anything * @return Last time we received anything
*/ */
inline int64_t lastIn() const { return _lastIn; } inline int64_t lastIn() const
{
return _lastIn;
}
/** /**
* @return the age of the path in terms of receiving packets * @return the age of the path in terms of receiving packets
*/ */
inline int64_t age(int64_t now) { return (now - _lastIn); } inline int64_t age(int64_t now)
{
return (now - _lastIn);
}
/** /**
* @return Time last trust-established packet was received * @return Time last trust-established packet was received
*/ */
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } inline int64_t lastTrustEstablishedPacketReceived() const
{
return _lastTrustEstablishedPacketReceived;
}
/** /**
* Rate limit gate for inbound ECHO requests * Rate limit gate for inbound ECHO requests
@ -312,69 +365,102 @@ public:
/** /**
* @return Mean latency as reported by the bonding layer * @return Mean latency as reported by the bonding layer
*/ */
inline float latencyMean() const { return _latencyMean; } inline float latencyMean() const
{
return _latencyMean;
}
/** /**
* @return Latency variance as reported by the bonding layer * @return Latency variance as reported by the bonding layer
*/ */
inline float latencyVariance() const { return _latencyVariance; } inline float latencyVariance() const
{
return _latencyVariance;
}
/** /**
* @return Packet Loss Ratio as reported by the bonding layer * @return Packet Loss Ratio as reported by the bonding layer
*/ */
inline float packetLossRatio() const { return _packetLossRatio; } inline float packetLossRatio() const
{
return _packetLossRatio;
}
/** /**
* @return Packet Error Ratio as reported by the bonding layer * @return Packet Error Ratio as reported by the bonding layer
*/ */
inline float packetErrorRatio() const { return _packetErrorRatio; } inline float packetErrorRatio() const
{
return _packetErrorRatio;
}
/** /**
* @return Number of flows assigned to this path * @return Number of flows assigned to this path
*/ */
inline unsigned int assignedFlowCount() const { return _assignedFlowCount; } inline unsigned int assignedFlowCount() const
{
return _assignedFlowCount;
}
/** /**
* @return Whether this path is valid as reported by the bonding layer. The bonding layer * @return Whether this path is valid as reported by the bonding layer. The bonding layer
* actually checks with Phy to see if the interface is still up * actually checks with Phy to see if the interface is still up
*/ */
inline bool valid() const { return _valid; } inline bool valid() const
{
return _valid;
}
/** /**
* @return Whether this path is eligible for use in a bond as reported by the bonding layer * @return Whether this path is eligible for use in a bond as reported by the bonding layer
*/ */
inline bool eligible() const { return _eligible; } inline bool eligible() const
{
return _eligible;
}
/** /**
* @return Whether this path is bonded as reported by the bonding layer * @return Whether this path is bonded as reported by the bonding layer
*/ */
inline bool bonded() const { return _bonded; } inline bool bonded() const
{
return _bonded;
}
/** /**
* @return Whether the user-specified MTU for this path (determined by MTU for parent link) * @return Whether the user-specified MTU for this path (determined by MTU for parent link)
*/ */
inline uint16_t mtu() const { return _mtu; } inline uint16_t mtu() const
{
return _mtu;
}
/** /**
* @return Given link capacity as reported by the bonding layer * @return Given link capacity as reported by the bonding layer
*/ */
inline uint32_t givenLinkSpeed() const { return _givenLinkSpeed; } inline uint32_t givenLinkSpeed() const
{
return _givenLinkSpeed;
}
/** /**
* @return Path's quality as reported by the bonding layer * @return Path's quality as reported by the bonding layer
*/ */
inline float relativeQuality() const { return _relativeQuality; } inline float relativeQuality() const
{
return _relativeQuality;
}
/** /**
* @return Physical interface name that this path lives on * @return Physical interface name that this path lives on
*/ */
char *ifname() { char* ifname()
{
return _ifname; return _ifname;
} }
private: private:
char _ifname[ZT_MAX_PHYSIFNAME] = {};
char _ifname[ZT_MAX_PHYSIFNAME] = { };
volatile int64_t _lastOut; volatile int64_t _lastOut;
volatile int64_t _lastIn; volatile int64_t _lastIn;

View file

@ -11,25 +11,26 @@
*/ */
/****/ /****/
#include "Peer.hpp"
#include "../version.h" #include "../version.h"
#include "Constants.hpp" #include "Constants.hpp"
#include "Peer.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "SelfAwareness.hpp"
#include "Packet.hpp"
#include "Trace.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "RingBuffer.hpp"
#include "Utils.hpp"
#include "Metrics.hpp" #include "Metrics.hpp"
#include "Network.hpp"
#include "Packet.hpp"
#include "RingBuffer.hpp"
#include "SelfAwareness.hpp"
#include "Switch.hpp"
#include "Trace.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
static unsigned char s_freeRandomByteCounter = 0; static unsigned char s_freeRandomByteCounter = 0;
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) Peer::Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity)
: RR(renv) : RR(renv)
, _lastReceive(0) , _lastReceive(0)
, _lastNontrivialReceive(0) , _lastNontrivialReceive(0)
@ -53,29 +54,29 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
, _localMultipathSupported(false) , _localMultipathSupported(false)
, _lastComputedAggregateMeanLatency(0) , _lastComputedAggregateMeanLatency(0)
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
, _peer_latency{Metrics::peer_latency.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}}, std::vector<uint64_t>{1,3,6,10,30,60,100,300,600,1000})} , _peer_latency { Metrics::peer_latency.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }, std::vector<uint64_t> { 1, 3, 6, 10, 30, 60, 100, 300, 600, 1000 }) }
, _alive_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","alive"}})} , _alive_path_count { Metrics::peer_path_count.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) }, { "status", "alive" } }) }
, _dead_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","dead"}})} , _dead_path_count { Metrics::peer_path_count.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) }, { "status", "dead" } }) }
, _incoming_packet{Metrics::peer_packets.Add({{"direction", "rx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})} , _incoming_packet { Metrics::peer_packets.Add({ { "direction", "rx" }, { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) }
, _outgoing_packet{Metrics::peer_packets.Add({{"direction", "tx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})} , _outgoing_packet { Metrics::peer_packets.Add({ { "direction", "tx" }, { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) }
, _packet_errors{Metrics::peer_packet_errors.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})} , _packet_errors { Metrics::peer_packet_errors.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) }
#endif #endif
{ {
if (!myIdentity.agree(peerIdentity,_key)) { if (! myIdentity.agree(peerIdentity, _key)) {
throw ZT_EXCEPTION_INVALID_ARGUMENT; throw ZT_EXCEPTION_INVALID_ARGUMENT;
} }
uint8_t ktmp[ZT_SYMMETRIC_KEY_SIZE]; uint8_t ktmp[ZT_SYMMETRIC_KEY_SIZE];
KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K0,0,0,ktmp); KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K0, 0, 0, ktmp);
_aesKeys[0].init(ktmp); _aesKeys[0].init(ktmp);
KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K1,0,0,ktmp); KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K1, 0, 0, ktmp);
_aesKeys[1].init(ktmp); _aesKeys[1].init(ktmp);
Utils::burn(ktmp,ZT_SYMMETRIC_KEY_SIZE); Utils::burn(ktmp, ZT_SYMMETRIC_KEY_SIZE);
} }
void Peer::received( void Peer::received(
void *tPtr, void* tPtr,
const SharedPtr<Path> &path, const SharedPtr<Path>& path,
const unsigned int hops, const unsigned int hops,
const uint64_t packetId, const uint64_t packetId,
const unsigned int payloadLength, const unsigned int payloadLength,
@ -115,7 +116,7 @@ void Peer::received(
bool havePath = false; bool havePath = false;
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if (_paths[i].p == path) { if (_paths[i].p == path) {
_paths[i].lr = now; _paths[i].lr = now;
@ -124,25 +125,26 @@ void Peer::received(
} }
// If same address on same interface then don't learn unless existing path isn't alive (prevents learning loop) // If same address on same interface then don't learn unless existing path isn't alive (prevents learning loop)
if (_paths[i].p->address().ipsEqual(path->address()) && _paths[i].p->localSocket() == path->localSocket()) { if (_paths[i].p->address().ipsEqual(path->address()) && _paths[i].p->localSocket() == path->localSocket()) {
if (_paths[i].p->alive(now) && !_bond) { if (_paths[i].p->alive(now) && ! _bond) {
havePath = true; havePath = true;
break; break;
} }
} }
} else { }
else {
break; break;
} }
} }
} }
if ( (!havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()) ) { if ((! havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr, _id.address(), path->localSocket(), path->address())) {
if (verb == Packet::VERB_OK) { if (verb == Packet::VERB_OK) {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS; unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int oldestPathAge = 0; unsigned int oldestPathAge = 0;
unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS; unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
// Keep track of oldest path as a last resort option // Keep track of oldest path as a last resort option
unsigned int currAge = _paths[i].p->age(now); unsigned int currAge = _paths[i].p->age(now);
@ -152,13 +154,14 @@ void Peer::received(
} }
if (_paths[i].p->address().ipsEqual(path->address())) { if (_paths[i].p->address().ipsEqual(path->address())) {
if (_paths[i].p->localSocket() == path->localSocket()) { if (_paths[i].p->localSocket() == path->localSocket()) {
if (!_paths[i].p->alive(now)) { if (! _paths[i].p->alive(now)) {
replacePath = i; replacePath = i;
break; break;
} }
} }
} }
} else { }
else {
replacePath = i; replacePath = i;
break; break;
} }
@ -172,30 +175,33 @@ void Peer::received(
_paths[replacePath].p = path; _paths[replacePath].p = path;
_paths[replacePath].priority = 1; _paths[replacePath].priority = 1;
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if(_bond) { if (_bond) {
_bond->nominatePathToBond(_paths[replacePath].p, now); _bond->nominatePathToBond(_paths[replacePath].p, now);
} }
} }
} else { }
else {
Mutex::Lock ltl(_lastTriedPath_m); Mutex::Lock ltl(_lastTriedPath_m);
bool triedTooRecently = false; bool triedTooRecently = false;
for(std::list< std::pair< Path *, int64_t > >::iterator i(_lastTriedPath.begin());i!=_lastTriedPath.end();) { for (std::list<std::pair<Path*, int64_t> >::iterator i(_lastTriedPath.begin()); i != _lastTriedPath.end();) {
if ((now - i->second) > 1000) { if ((now - i->second) > 1000) {
_lastTriedPath.erase(i++); _lastTriedPath.erase(i++);
} else if (i->first == path.ptr()) { }
else if (i->first == path.ptr()) {
++i; ++i;
triedTooRecently = true; triedTooRecently = true;
} else { }
else {
++i; ++i;
} }
} }
if (!triedTooRecently) { if (! triedTooRecently) {
_lastTriedPath.push_back(std::pair< Path *, int64_t >(path.ptr(), now)); _lastTriedPath.push_back(std::pair<Path*, int64_t>(path.ptr(), now));
attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true); attemptToContactAt(tPtr, path->localSocket(), path->address(), now, true);
path->sent(now); path->sent(now);
RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); RR->t->peerConfirmingUnknownPath(tPtr, networkId, *this, path, packetId, verb);
} }
} }
} }
@ -213,15 +219,15 @@ void Peer::received(
std::vector<InetAddress> pathsToPush(RR->node->directPaths()); std::vector<InetAddress> pathsToPush(RR->node->directPaths());
std::vector<InetAddress> ma = RR->sa->whoami(); std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end()); pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
if (!pathsToPush.empty()) { if (! pathsToPush.empty()) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin()); std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) { while (p != pathsToPush.end()) {
Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); Packet* const outp = new Packet(_id.address(), RR->identity.address(), Packet::VERB_PUSH_DIRECT_PATHS);
outp->addSize(2); // leave room for count outp->addSize(2); // leave room for count
unsigned int count = 0; unsigned int count = 0;
while ((p != pathsToPush.end())&&((outp->size() + 24) < 1200)) { while ((p != pathsToPush.end()) && ((outp->size() + 24) < 1200)) {
uint8_t addressType = 4; uint8_t addressType = 4;
switch(p->ss_family) { switch (p->ss_family) {
case AF_INET: case AF_INET:
break; break;
case AF_INET6: case AF_INET6:
@ -236,7 +242,7 @@ void Peer::received(
outp->append((uint16_t)0); // no extensions outp->append((uint16_t)0); // no extensions
outp->append(addressType); outp->append(addressType);
outp->append((uint8_t)((addressType == 4) ? 6 : 18)); outp->append((uint8_t)((addressType == 4) ? 6 : 18));
outp->append(p->rawIpData(),((addressType == 4) ? 4 : 16)); outp->append(p->rawIpData(), ((addressType == 4) ? 4 : 16));
outp->append((uint16_t)p->port()); outp->append((uint16_t)p->port());
++count; ++count;
@ -244,11 +250,11 @@ void Peer::received(
} }
if (count) { if (count) {
Metrics::pkt_push_direct_paths_out++; Metrics::pkt_push_direct_paths_out++;
outp->setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); outp->setAt(ZT_PACKET_IDX_PAYLOAD, (uint16_t)count);
outp->compress(); outp->compress();
outp->armor(_key,true,false,aesKeysIfSupported(),_id); outp->armor(_key, true, false, aesKeysIfSupported(), _id);
Metrics::pkt_push_direct_paths_out++; Metrics::pkt_push_direct_paths_out++;
path->send(RR,tPtr,outp->data(),outp->size(),now); path->send(RR, tPtr, outp->data(), outp->size(), now);
} }
delete outp; delete outp;
} }
@ -261,7 +267,7 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
Mutex::Lock _lb(_bond_m); Mutex::Lock _lb(_bond_m);
if(_bond && _bond->isReady()) { if (_bond && _bond->isReady()) {
return _bond->getAppropriatePath(now, flowId); return _bond->getAppropriatePath(now, flowId);
} }
unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS; unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS;
@ -270,16 +276,17 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
* use the old path quality metric from protocol version 9. * use the old path quality metric from protocol version 9.
*/ */
long bestPathQuality = 2147483647; long bestPathQuality = 2147483647;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if ((includeExpired)||((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)) { if ((includeExpired) || ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)) {
const long q = _paths[i].p->quality(now) / _paths[i].priority; const long q = _paths[i].p->quality(now) / _paths[i].priority;
if (q <= bestPathQuality) { if (q <= bestPathQuality) {
bestPathQuality = q; bestPathQuality = q;
bestPath = i; bestPath = i;
} }
} }
} else { }
else {
break; break;
} }
} }
@ -289,17 +296,17 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
return SharedPtr<Path>(); return SharedPtr<Path>();
} }
void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const void Peer::introduce(void* const tPtr, const int64_t now, const SharedPtr<Peer>& other) const
{ {
unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { for (int i = 0; i <= ZT_INETADDRESS_MAX_SCOPE; ++i) {
myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV4QualityByScope[i] = 2147483647; myBestV4QualityByScope[i] = 2147483647;
@ -312,11 +319,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
Mutex::Lock _l1(_paths_m); Mutex::Lock _l1(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
const long q = _paths[i].p->quality(now) / _paths[i].priority; const long q = _paths[i].p->quality(now) / _paths[i].priority;
const unsigned int s = (unsigned int)_paths[i].p->ipScope(); const unsigned int s = (unsigned int)_paths[i].p->ipScope();
switch(_paths[i].p->address().ss_family) { switch (_paths[i].p->address().ss_family) {
case AF_INET: case AF_INET:
if (q <= myBestV4QualityByScope[s]) { if (q <= myBestV4QualityByScope[s]) {
myBestV4QualityByScope[s] = q; myBestV4QualityByScope[s] = q;
@ -330,18 +337,19 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
} }
break; break;
} }
} else { }
else {
break; break;
} }
} }
Mutex::Lock _l2(other->_paths_m); Mutex::Lock _l2(other->_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (other->_paths[i].p) { if (other->_paths[i].p) {
const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority; const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority;
const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); const unsigned int s = (unsigned int)other->_paths[i].p->ipScope();
switch(other->_paths[i].p->address().ss_family) { switch (other->_paths[i].p->address().ss_family) {
case AF_INET: case AF_INET:
if (q <= theirBestV4QualityByScope[s]) { if (q <= theirBestV4QualityByScope[s]) {
theirBestV4QualityByScope[s] = q; theirBestV4QualityByScope[s] = q;
@ -355,7 +363,8 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
} }
break; break;
} }
} else { }
else {
break; break;
} }
} }
@ -363,13 +372,13 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS; unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS; unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS;
for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) { for (int s = ZT_INETADDRESS_MAX_SCOPE; s >= 0; --s) {
if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
mine = myBestV6ByScope[s]; mine = myBestV6ByScope[s];
theirs = theirBestV6ByScope[s]; theirs = theirBestV6ByScope[s];
break; break;
} }
if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
mine = myBestV4ByScope[s]; mine = myBestV4ByScope[s];
theirs = theirBestV4ByScope[s]; theirs = theirBestV4ByScope[s];
break; break;
@ -381,51 +390,54 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
const unsigned int completed = alt + 2; const unsigned int completed = alt + 2;
while (alt != completed) { while (alt != completed) {
if ((alt & 1) == 0) { if ((alt & 1) == 0) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); Packet outp(_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0); outp.append((uint8_t)0);
other->_id.address().appendTo(outp); other->_id.address().appendTo(outp);
outp.append((uint16_t)other->_paths[theirs].p->address().port()); outp.append((uint16_t)other->_paths[theirs].p->address().port());
if (other->_paths[theirs].p->address().ss_family == AF_INET6) { if (other->_paths[theirs].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16); outp.append((uint8_t)16);
outp.append(other->_paths[theirs].p->address().rawIpData(),16); outp.append(other->_paths[theirs].p->address().rawIpData(), 16);
} else {
outp.append((uint8_t)4);
outp.append(other->_paths[theirs].p->address().rawIpData(),4);
} }
outp.armor(_key,true,false,aesKeysIfSupported(),_id); else {
outp.append((uint8_t)4);
outp.append(other->_paths[theirs].p->address().rawIpData(), 4);
}
outp.armor(_key, true, false, aesKeysIfSupported(), _id);
Metrics::pkt_rendezvous_out++; Metrics::pkt_rendezvous_out++;
_paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); _paths[mine].p->send(RR, tPtr, outp.data(), outp.size(), now);
} else { }
Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); else {
Packet outp(other->_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0); outp.append((uint8_t)0);
_id.address().appendTo(outp); _id.address().appendTo(outp);
outp.append((uint16_t)_paths[mine].p->address().port()); outp.append((uint16_t)_paths[mine].p->address().port());
if (_paths[mine].p->address().ss_family == AF_INET6) { if (_paths[mine].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16); outp.append((uint8_t)16);
outp.append(_paths[mine].p->address().rawIpData(),16); outp.append(_paths[mine].p->address().rawIpData(), 16);
} else {
outp.append((uint8_t)4);
outp.append(_paths[mine].p->address().rawIpData(),4);
} }
outp.armor(other->_key,true,false,other->aesKeysIfSupported(),other->identity()); else {
outp.append((uint8_t)4);
outp.append(_paths[mine].p->address().rawIpData(), 4);
}
outp.armor(other->_key, true, false, other->aesKeysIfSupported(), other->identity());
Metrics::pkt_rendezvous_out++; Metrics::pkt_rendezvous_out++;
other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); other->_paths[theirs].p->send(RR, tPtr, outp.data(), outp.size(), now);
} }
++alt; ++alt;
} }
} }
} }
void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now) void Peer::sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now)
{ {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); Packet outp(_id.address(), RR->identity.address(), Packet::VERB_HELLO);
outp.append((unsigned char)ZT_PROTO_VERSION); outp.append((unsigned char)ZT_PROTO_VERSION);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
outp.append(now); outp.append(now);
RR->identity.serialize(outp,false); RR->identity.serialize(outp, false);
atAddress.serialize(outp); atAddress.serialize(outp);
outp.append((uint64_t)RR->topology->planetWorldId()); outp.append((uint64_t)RR->topology->planetWorldId());
@ -436,57 +448,59 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
std::vector<World> moons(RR->topology->moons()); std::vector<World> moons(RR->topology->moons());
std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted()); std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted());
outp.append((uint16_t)(moons.size() + moonsWanted.size())); outp.append((uint16_t)(moons.size() + moonsWanted.size()));
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) { for (std::vector<World>::const_iterator m(moons.begin()); m != moons.end(); ++m) {
outp.append((uint8_t)m->type()); outp.append((uint8_t)m->type());
outp.append((uint64_t)m->id()); outp.append((uint64_t)m->id());
outp.append((uint64_t)m->timestamp()); outp.append((uint64_t)m->timestamp());
} }
for(std::vector<uint64_t>::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) { for (std::vector<uint64_t>::const_iterator m(moonsWanted.begin()); m != moonsWanted.end(); ++m) {
outp.append((uint8_t)World::TYPE_MOON); outp.append((uint8_t)World::TYPE_MOON);
outp.append(*m); outp.append(*m);
outp.append((uint64_t)0); outp.append((uint64_t)0);
} }
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); outp.cryptField(_key, startCryptedPortionAt, outp.size() - startCryptedPortionAt);
Metrics::pkt_hello_out++; Metrics::pkt_hello_out++;
if (atAddress) { if (atAddress) {
// TODO: this is where extended armor should be invoked // TODO: this is where extended armor should be invoked
outp.armor(_key,false,false,nullptr,_id); outp.armor(_key, false, false, nullptr, _id);
RR->node->expectReplyTo(outp.packetId()); RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -1,atAddress,outp.data(),outp.size()); RR->node->putPacket(tPtr, RR->node->lowBandwidthModeEnabled() ? localSocket : -1, atAddress, outp.data(), outp.size());
} else { }
else {
RR->node->expectReplyTo(outp.packetId()); RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,true); RR->sw->send(tPtr, outp, true);
} }
} }
void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello) void Peer::attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello)
{ {
if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { if ((! sendFullHello) && (_vProto >= 5) && (! ((_vMajor == 1) && (_vMinor == 1) && (_vRevision == 0)))) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); Packet outp(_id.address(), RR->identity.address(), Packet::VERB_ECHO);
outp.armor(_key,true,false,aesKeysIfSupported(),_id); outp.armor(_key, true, false, aesKeysIfSupported(), _id);
Metrics::pkt_echo_out++; Metrics::pkt_echo_out++;
RR->node->expectReplyTo(outp.packetId()); RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size());
} else { }
sendHELLO(tPtr,localSocket,atAddress,now); else {
sendHELLO(tPtr, localSocket, atAddress, now);
} }
} }
void Peer::tryMemorizedPath(void *tPtr,int64_t now) void Peer::tryMemorizedPath(void* tPtr, int64_t now)
{ {
if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) {
_lastTriedMemorizedPath = now; _lastTriedMemorizedPath = now;
InetAddress mp; InetAddress mp;
if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) { if (RR->node->externalPathLookup(tPtr, _id.address(), -1, mp)) {
attemptToContactAt(tPtr,-1,mp,now,true); attemptToContactAt(tPtr, -1, mp, now, true);
} }
} }
} }
void Peer::performMultipathStateCheck(void *tPtr, int64_t now) void Peer::performMultipathStateCheck(void* tPtr, int64_t now)
{ {
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
/** /**
@ -495,9 +509,9 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
*/ */
int numAlivePaths = 0; int numAlivePaths = 0;
bool atLeastOneNonExpired = false; bool atLeastOneNonExpired = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if(_paths[i].p->alive(now)) { if (_paths[i].p->alive(now)) {
numAlivePaths++; numAlivePaths++;
} }
if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) { if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) {
@ -506,21 +520,21 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
} }
} }
if (_bond) { if (_bond) {
if (numAlivePaths == 0 && !atLeastOneNonExpired) { if (numAlivePaths == 0 && ! atLeastOneNonExpired) {
_bond = SharedPtr<Bond>(); _bond = SharedPtr<Bond>();
RR->bc->destroyBond(_id.address().toInt()); RR->bc->destroyBond(_id.address().toInt());
} }
return; return;
} }
_localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9)); _localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9));
if (_localMultipathSupported && !_bond) { if (_localMultipathSupported && ! _bond) {
if (RR->bc) { if (RR->bc) {
_bond = RR->bc->createBond(RR, this); _bond = RR->bc->createBond(RR, this);
/** /**
* Allow new bond to retroactively learn all paths known to this peer * Allow new bond to retroactively learn all paths known to this peer
*/ */
if (_bond) { if (_bond) {
for (unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
_bond->nominatePathToBond(_paths[i].p, now); _bond->nominatePathToBond(_paths[i].p, now);
} }
@ -530,7 +544,7 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
} }
} }
unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) unsigned int Peer::doPingAndKeepalive(void* tPtr, int64_t now)
{ {
unsigned int sent = 0; unsigned int sent = 0;
{ {
@ -548,31 +562,33 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
// redirects us its redirect target links override all other links and we // redirects us its redirect target links override all other links and we
// let those old links expire. // let those old links expire.
long maxPriority = 0; long maxPriority = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
maxPriority = std::max(_paths[i].priority,maxPriority); maxPriority = std::max(_paths[i].priority, maxPriority);
} else { }
else {
break; break;
} }
} }
bool deletionOccurred = false; bool deletionOccurred = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
// Clean expired and reduced priority paths // Clean expired and reduced priority paths
if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) { if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority)) {
if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) { if ((sendFullHello) || (_paths[i].p->needsHeartbeat(now))) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello); attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, sendFullHello);
_paths[i].p->sent(now); _paths[i].p->sent(now);
sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2;
} }
} else { }
else {
_paths[i] = _PeerPath(); _paths[i] = _PeerPath();
deletionOccurred = true; deletionOccurred = true;
} }
} }
if (!_paths[i].p || deletionOccurred) { if (! _paths[i].p || deletionOccurred) {
for(unsigned int j=i;j<ZT_MAX_PEER_NETWORK_PATHS;++j) { for (unsigned int j = i; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) {
if (_paths[j].p && i != j) { if (_paths[j].p && i != j) {
_paths[i] = _paths[j]; _paths[i] = _paths[j];
_paths[j] = _PeerPath(); _paths[j] = _PeerPath();
@ -584,7 +600,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
} }
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
uint16_t alive_path_count_tmp = 0, dead_path_count_tmp = 0; uint16_t alive_path_count_tmp = 0, dead_path_count_tmp = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if (_paths[i].p->alive(now)) { if (_paths[i].p->alive(now)) {
alive_path_count_tmp++; alive_path_count_tmp++;
@ -604,25 +620,26 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
return sent; return sent;
} }
void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,const InetAddress &remoteAddress,const int64_t now) void Peer::clusterRedirect(void* tPtr, const SharedPtr<Path>& originatingPath, const InetAddress& remoteAddress, const int64_t now)
{ {
SharedPtr<Path> np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress)); SharedPtr<Path> np(RR->topology->getPath(originatingPath->localSocket(), remoteAddress));
RR->t->peerRedirected(tPtr,0,*this,np); RR->t->peerRedirected(tPtr, 0, *this, np);
attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true); attemptToContactAt(tPtr, originatingPath->localSocket(), remoteAddress, now, true);
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
// New priority is higher than the priority of the originating path (if known) // New priority is higher than the priority of the originating path (if known)
long newPriority = 1; long newPriority = 1;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if (_paths[i].p == originatingPath) { if (_paths[i].p == originatingPath) {
newPriority = _paths[i].priority; newPriority = _paths[i].priority;
break; break;
} }
} else { }
else {
break; break;
} }
} }
@ -631,9 +648,9 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
// Erase any paths with lower priority than this one or that are duplicate // Erase any paths with lower priority than this one or that are duplicate
// IPs and add this path. // IPs and add this path.
unsigned int j = 0; unsigned int j = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if ((_paths[i].priority >= newPriority)&&(!_paths[i].p->address().ipsEqual2(remoteAddress))) { if ((_paths[i].priority >= newPriority) && (! _paths[i].p->address().ipsEqual2(remoteAddress))) {
if (i != j) { if (i != j) {
_paths[j] = _paths[i]; _paths[j] = _paths[i];
} }
@ -656,24 +673,24 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
} }
} }
void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) void Peer::resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now)
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if ((_paths[i].p->address().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { if ((_paths[i].p->address().ss_family == inetAddressFamily) && (_paths[i].p->ipScope() == scope)) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false); attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, false);
_paths[i].p->sent(now); _paths[i].p->sent(now);
_paths[i].lr = 0; // path will not be used unless it speaks again _paths[i].lr = 0; // path will not be used unless it speaks again
} }
} else { }
else {
break; break;
} }
} }
} }
void Peer::recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId, void Peer::recordOutgoingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{ {
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
_outgoing_packet++; _outgoing_packet++;
@ -693,8 +710,7 @@ void Peer::recordIncomingInvalidPacket(const SharedPtr<Path>& path)
} }
} }
void Peer::recordIncomingPacket(const SharedPtr<Path> &path, const uint64_t packetId, void Peer::recordIncomingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{ {
if (_localMultipathSupported && _bond) { if (_localMultipathSupported && _bond) {
_bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now); _bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now);

View file

@ -14,27 +14,26 @@
#ifndef ZT_PEER_HPP #ifndef ZT_PEER_HPP
#define ZT_PEER_HPP #define ZT_PEER_HPP
#include <vector>
#include <list>
#include "../include/ZeroTierOne.h" #include "../include/ZeroTierOne.h"
#include "AES.hpp"
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "Path.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Utils.hpp" #include "AtomicCounter.hpp"
#include "Bond.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#include "Bond.hpp"
#include "AES.hpp"
#include "Metrics.hpp" #include "Metrics.hpp"
#include "Mutex.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <list>
#include <vector>
#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) #define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2))
@ -43,19 +42,19 @@ namespace ZeroTier {
/** /**
* Peer on P2P Network (virtual layer 1) * Peer on P2P Network (virtual layer 1)
*/ */
class Peer class Peer {
{
friend class SharedPtr<Peer>; friend class SharedPtr<Peer>;
friend class SharedPtr<Bond>; friend class SharedPtr<Bond>;
friend class Switch; friend class Switch;
friend class Bond; friend class Bond;
private: private:
Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized
public: public:
~Peer() { ~Peer()
Utils::burn(_key,sizeof(_key)); {
Utils::burn(_key, sizeof(_key));
} }
/** /**
@ -66,17 +65,23 @@ public:
* @param peerIdentity Identity of peer * @param peerIdentity Identity of peer
* @throws std::runtime_error Key agreement with peer's identity failed * @throws std::runtime_error Key agreement with peer's identity failed
*/ */
Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity); Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity);
/** /**
* @return This peer's ZT address (short for identity().address()) * @return This peer's ZT address (short for identity().address())
*/ */
inline const Address &address() const { return _id.address(); } inline const Address& address() const
{
return _id.address();
}
/** /**
* @return This peer's identity * @return This peer's identity
*/ */
inline const Identity &identity() const { return _id; } inline const Identity& identity() const
{
return _id;
}
/** /**
* Log receipt of an authenticated packet * Log receipt of an authenticated packet
@ -95,8 +100,8 @@ public:
* @param networkId Network ID if this pertains to a network, or 0 otherwise * @param networkId Network ID if this pertains to a network, or 0 otherwise
*/ */
void received( void received(
void *tPtr, void* tPtr,
const SharedPtr<Path> &path, const SharedPtr<Path>& path,
const unsigned int hops, const unsigned int hops,
const uint64_t packetId, const uint64_t packetId,
const unsigned int payloadLength, const unsigned int payloadLength,
@ -114,15 +119,16 @@ public:
* @param addr Remote address * @param addr Remote address
* @return True if we have an active path to this destination * @return True if we have an active path to this destination
*/ */
inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const inline bool hasActivePathTo(int64_t now, const InetAddress& addr) const
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)&&(_paths[i].p->address() == addr)) { if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].p->address() == addr)) {
return true; return true;
} }
} else { }
else {
break; break;
} }
} }
@ -139,11 +145,11 @@ public:
* @param force If true, send even if path is not alive * @param force If true, send even if path is not alive
* @return True if we actually sent something * @return True if we actually sent something
*/ */
inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force) inline bool sendDirect(void* tPtr, const void* data, unsigned int len, int64_t now, bool force)
{ {
SharedPtr<Path> bp(getAppropriatePath(now,force)); SharedPtr<Path> bp(getAppropriatePath(now, force));
if (bp) { if (bp) {
return bp->send(RR,tPtr,data,len,now); return bp->send(RR, tPtr, data, len, now);
} }
return false; return false;
} }
@ -159,8 +165,7 @@ public:
* @param flowId Flow ID * @param flowId Flow ID
* @param now Current time * @param now Current time
*/ */
void recordIncomingPacket(const SharedPtr<Path> &path, const uint64_t packetId, void recordIncomingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
/** /**
* *
@ -171,8 +176,7 @@ public:
* @param flowId Flow ID * @param flowId Flow ID
* @param now Current time * @param now Current time
*/ */
void recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId, void recordOutgoingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
/** /**
* Record an invalid incoming packet. This packet failed * Record an invalid incoming packet. This packet failed
@ -195,7 +199,7 @@ public:
/** /**
* Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path * Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path
*/ */
void introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const; void introduce(void* const tPtr, const int64_t now, const SharedPtr<Peer>& other) const;
/** /**
* Send a HELLO to this peer at a specified physical address * Send a HELLO to this peer at a specified physical address
@ -207,7 +211,7 @@ public:
* @param atAddress Destination address * @param atAddress Destination address
* @param now Current time * @param now Current time
*/ */
void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now); void sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now);
/** /**
* Send ECHO (or HELLO for older peers) to this peer at the given address * Send ECHO (or HELLO for older peers) to this peer at the given address
@ -220,7 +224,7 @@ public:
* @param now Current time * @param now Current time
* @param sendFullHello If true, always send a full HELLO instead of just an ECHO * @param sendFullHello If true, always send a full HELLO instead of just an ECHO
*/ */
void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello); void attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello);
/** /**
* Try a memorized or statically defined path if any are known * Try a memorized or statically defined path if any are known
@ -230,14 +234,14 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param now Current time * @param now Current time
*/ */
void tryMemorizedPath(void *tPtr,int64_t now); void tryMemorizedPath(void* tPtr, int64_t now);
/** /**
* A check to be performed periodically which determines whether multipath communication is * A check to be performed periodically which determines whether multipath communication is
* possible with this peer. This check should be performed early in the life-cycle of the peer * possible with this peer. This check should be performed early in the life-cycle of the peer
* as well as during the process of learning new paths. * as well as during the process of learning new paths.
*/ */
void performMultipathStateCheck(void *tPtr, int64_t now); void performMultipathStateCheck(void* tPtr, int64_t now);
/** /**
* Send pings or keepalives depending on configured timeouts * Send pings or keepalives depending on configured timeouts
@ -249,7 +253,7 @@ public:
* @param inetAddressFamily Keep this address family alive, or -1 for any * @param inetAddressFamily Keep this address family alive, or -1 for any
* @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent) * @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent)
*/ */
unsigned int doPingAndKeepalive(void *tPtr,int64_t now); unsigned int doPingAndKeepalive(void* tPtr, int64_t now);
/** /**
* Process a cluster redirect sent by this peer * Process a cluster redirect sent by this peer
@ -259,7 +263,7 @@ public:
* @param remoteAddress Remote address * @param remoteAddress Remote address
* @param now Current time * @param now Current time
*/ */
void clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,const InetAddress &remoteAddress,const int64_t now); void clusterRedirect(void* tPtr, const SharedPtr<Path>& originatingPath, const InetAddress& remoteAddress, const int64_t now);
/** /**
* Reset paths within a given IP scope and address family * Reset paths within a given IP scope and address family
@ -274,18 +278,18 @@ public:
* @param inetAddressFamily Family e.g. AF_INET * @param inetAddressFamily Family e.g. AF_INET
* @param now Current time * @param now Current time
*/ */
void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now); void resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now);
/** /**
* @param now Current time * @param now Current time
* @return All known paths to this peer * @return All known paths to this peer
*/ */
inline std::vector< SharedPtr<Path> > paths(const int64_t now) const inline std::vector<SharedPtr<Path> > paths(const int64_t now) const
{ {
std::vector< SharedPtr<Path> > pp; std::vector<SharedPtr<Path> > pp;
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (!_paths[i].p) { if (! _paths[i].p) {
break; break;
} }
pp.push_back(_paths[i].p); pp.push_back(_paths[i].p);
@ -296,19 +300,31 @@ public:
/** /**
* @return Time of last receive of anything, whether direct or relayed * @return Time of last receive of anything, whether direct or relayed
*/ */
inline int64_t lastReceive() const { return _lastReceive; } inline int64_t lastReceive() const
{
return _lastReceive;
}
/** /**
* @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT
*/ */
inline bool isAlive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } inline bool isAlive(const int64_t now) const
{
return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT);
}
/** /**
* @return True if this peer has sent us real network traffic recently * @return True if this peer has sent us real network traffic recently
*/ */
inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); } inline int64_t isActive(int64_t now) const
{
return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT);
}
inline int64_t lastSentFullHello() { return _lastSentFullHello; } inline int64_t lastSentFullHello()
{
return _lastSentFullHello;
}
/** /**
* @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths * @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths
@ -317,8 +333,9 @@ public:
{ {
if (_localMultipathSupported) { if (_localMultipathSupported) {
return (int)_lastComputedAggregateMeanLatency; return (int)_lastComputedAggregateMeanLatency;
} else { }
SharedPtr<Path> bp(getAppropriatePath(now,false)); else {
SharedPtr<Path> bp(getAppropriatePath(now, false));
if (bp) { if (bp) {
return (unsigned int)bp->latency(); return (unsigned int)bp->latency();
} }
@ -344,7 +361,7 @@ public:
return (~(unsigned int)0); return (~(unsigned int)0);
} }
unsigned int l = latency(now); unsigned int l = latency(now);
if (!l) { if (! l) {
l = 0xffff; l = 0xffff;
} }
return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1)); return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1));
@ -353,7 +370,10 @@ public:
/** /**
* @return 256-bit secret symmetric encryption key * @return 256-bit secret symmetric encryption key
*/ */
inline const unsigned char *key() const { return _key; } inline const unsigned char* key() const
{
return _key;
}
/** /**
* Set the currently known remote version of this peer's client * Set the currently known remote version of this peer's client
@ -363,7 +383,7 @@ public:
* @param vmin Minor version * @param vmin Minor version
* @param vrev Revision * @param vrev Revision
*/ */
inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev) inline void setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev)
{ {
_vProto = (uint16_t)vproto; _vProto = (uint16_t)vproto;
_vMajor = (uint16_t)vmaj; _vMajor = (uint16_t)vmaj;
@ -371,17 +391,35 @@ public:
_vRevision = (uint16_t)vrev; _vRevision = (uint16_t)vrev;
} }
inline unsigned int remoteVersionProtocol() const { return _vProto; } inline unsigned int remoteVersionProtocol() const
inline unsigned int remoteVersionMajor() const { return _vMajor; } {
inline unsigned int remoteVersionMinor() const { return _vMinor; } return _vProto;
inline unsigned int remoteVersionRevision() const { return _vRevision; } }
inline unsigned int remoteVersionMajor() const
{
return _vMajor;
}
inline unsigned int remoteVersionMinor() const
{
return _vMinor;
}
inline unsigned int remoteVersionRevision() const
{
return _vRevision;
}
inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } inline bool remoteVersionKnown() const
{
return ((_vMajor > 0) || (_vMinor > 0) || (_vRevision > 0));
}
/** /**
* @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/ */
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } inline bool trustEstablished(const int64_t now) const
{
return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION);
}
/** /**
* Rate limit gate for VERB_PUSH_DIRECT_PATHS * Rate limit gate for VERB_PUSH_DIRECT_PATHS
@ -390,7 +428,8 @@ public:
{ {
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) { if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) {
++_directPathPushCutoffCount; ++_directPathPushCutoffCount;
} else { }
else {
_directPathPushCutoffCount = 0; _directPathPushCutoffCount = 0;
} }
_lastDirectPathPushReceive = now; _lastDirectPathPushReceive = now;
@ -439,7 +478,7 @@ public:
inline bool rateGateQoS(int64_t now, SharedPtr<Path>& path) inline bool rateGateQoS(int64_t now, SharedPtr<Path>& path)
{ {
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if(_bond) { if (_bond) {
return _bond->rateGateQoS(now, path); return _bond->rateGateQoS(now, path);
} }
return false; // Default behavior. If there is no bond, we drop these return false; // Default behavior. If there is no bond, we drop these
@ -451,7 +490,7 @@ public:
void receivedQoS(const SharedPtr<Path>& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts) void receivedQoS(const SharedPtr<Path>& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts)
{ {
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if(_bond) { if (_bond) {
_bond->receivedQoS(path, now, count, rx_id, rx_ts); _bond->receivedQoS(path, now, count, rx_id, rx_ts);
} }
} }
@ -462,7 +501,7 @@ public:
void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>& path, int16_t remoteUtility) void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>& path, int16_t remoteUtility)
{ {
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if(_bond) { if (_bond) {
_bond->processIncomingPathNegotiationRequest(now, path, remoteUtility); _bond->processIncomingPathNegotiationRequest(now, path, remoteUtility);
} }
} }
@ -473,7 +512,7 @@ public:
inline bool rateGatePathNegotiation(int64_t now, SharedPtr<Path>& path) inline bool rateGatePathNegotiation(int64_t now, SharedPtr<Path>& path)
{ {
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if(_bond) { if (_bond) {
return _bond->rateGatePathNegotiation(now, path); return _bond->rateGatePathNegotiation(now, path);
} }
return false; // Default behavior. If there is no bond, we drop these return false; // Default behavior. If there is no bond, we drop these
@ -485,7 +524,7 @@ public:
bool flowHashingSupported() bool flowHashingSupported()
{ {
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if(_bond) { if (_bond) {
return _bond->flowHashingSupported(); return _bond->flowHashingSupported();
} }
return false; return false;
@ -496,8 +535,7 @@ public:
* *
* This does not serialize everything, just non-ephemeral information. * This does not serialize everything, just non-ephemeral information.
*/ */
template<unsigned int C> template <unsigned int C> inline void serializeForCache(Buffer<C>& b) const
inline void serializeForCache(Buffer<C> &b) const
{ {
b.append((uint8_t)2); b.append((uint8_t)2);
@ -511,22 +549,22 @@ public:
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
unsigned int pc = 0; unsigned int pc = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
++pc; ++pc;
} else { }
else {
break; break;
} }
} }
b.append((uint16_t)pc); b.append((uint16_t)pc);
for(unsigned int i=0;i<pc;++i) { for (unsigned int i = 0; i < pc; ++i) {
_paths[i].p->address().serialize(b); _paths[i].p->address().serialize(b);
} }
} }
} }
template<unsigned int C> template <unsigned int C> inline static SharedPtr<Peer> deserializeFromCache(int64_t now, void* tPtr, Buffer<C>& b, const RuntimeEnvironment* renv)
inline static SharedPtr<Peer> deserializeFromCache(int64_t now,void *tPtr,Buffer<C> &b,const RuntimeEnvironment *renv)
{ {
try { try {
unsigned int ptr = 0; unsigned int ptr = 0;
@ -535,12 +573,12 @@ public:
} }
Identity id; Identity id;
ptr += id.deserialize(b,ptr); ptr += id.deserialize(b, ptr);
if (!id) { if (! id) {
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
SharedPtr<Peer> p(new Peer(renv,renv->identity,id)); SharedPtr<Peer> p(new Peer(renv, renv->identity, id));
p->_vProto = b.template at<uint16_t>(ptr); p->_vProto = b.template at<uint16_t>(ptr);
ptr += 2; ptr += 2;
@ -556,20 +594,22 @@ public:
// Paths are fairly ephemeral in the real world in most cases. // Paths are fairly ephemeral in the real world in most cases.
const unsigned int tryPathCount = b.template at<uint16_t>(ptr); const unsigned int tryPathCount = b.template at<uint16_t>(ptr);
ptr += 2; ptr += 2;
for(unsigned int i=0;i<tryPathCount;++i) { for (unsigned int i = 0; i < tryPathCount; ++i) {
InetAddress inaddr; InetAddress inaddr;
try { try {
ptr += inaddr.deserialize(b,ptr); ptr += inaddr.deserialize(b, ptr);
if (inaddr) { if (inaddr) {
p->attemptToContactAt(tPtr,-1,inaddr,now,true); p->attemptToContactAt(tPtr, -1, inaddr, now, true);
} }
} catch ( ... ) { }
catch (...) {
break; break;
} }
} }
return p; return p;
} catch ( ... ) { }
catch (...) {
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
} }
@ -577,12 +617,16 @@ public:
/** /**
* @return The bonding policy used to reach this peer * @return The bonding policy used to reach this peer
*/ */
SharedPtr<Bond> bond() { return _bond; } SharedPtr<Bond> bond()
{
return _bond;
}
/** /**
* @return The bonding policy used to reach this peer * @return The bonding policy used to reach this peer
*/ */
inline int8_t bondingPolicy() { inline int8_t bondingPolicy()
{
Mutex::Lock _l(_bond_m); Mutex::Lock _l(_bond_m);
if (_bond) { if (_bond) {
return _bond->policy(); return _bond->policy();
@ -593,7 +637,8 @@ public:
/** /**
* @return the number of links in this bond which are considered alive * @return the number of links in this bond which are considered alive
*/ */
inline uint8_t getNumAliveLinks() { inline uint8_t getNumAliveLinks()
{
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
if (_bond) { if (_bond) {
return _bond->getNumAliveLinks(); return _bond->getNumAliveLinks();
@ -604,7 +649,8 @@ public:
/** /**
* @return the number of links in this bond * @return the number of links in this bond
*/ */
inline uint8_t getNumTotalLinks() { inline uint8_t getNumTotalLinks()
{
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
if (_bond) { if (_bond) {
return _bond->getNumTotalLinks(); return _bond->getNumTotalLinks();
@ -612,19 +658,24 @@ public:
return 0; return 0;
} }
//inline const AES *aesKeysIfSupported() const // inline const AES *aesKeysIfSupported() const
//{ return (const AES *)0; } //{ return (const AES *)0; }
inline const AES *aesKeysIfSupported() const inline const AES* aesKeysIfSupported() const
{ return (_vProto >= 12) ? _aesKeys : (const AES *)0; }
inline const AES *aesKeys() const
{ return _aesKeys; }
private:
struct _PeerPath
{ {
_PeerPath() : lr(0),p(),priority(1) {} return (_vProto >= 12) ? _aesKeys : (const AES*)0;
}
inline const AES* aesKeys() const
{
return _aesKeys;
}
private:
struct _PeerPath {
_PeerPath() : lr(0), p(), priority(1)
{
}
int64_t lr; // time of last valid ZeroTier packet int64_t lr; // time of last valid ZeroTier packet
SharedPtr<Path> p; SharedPtr<Path> p;
long priority; // >= 1, higher is better long priority; // >= 1, higher is better
@ -633,7 +684,7 @@ private:
uint8_t _key[ZT_SYMMETRIC_KEY_SIZE]; uint8_t _key[ZT_SYMMETRIC_KEY_SIZE];
AES _aesKeys[2]; AES _aesKeys[2];
const RuntimeEnvironment *RR; const RuntimeEnvironment* RR;
int64_t _lastReceive; // direct or indirect int64_t _lastReceive; // direct or indirect
int64_t _lastNontrivialReceive; // frames, things like netconf, etc. int64_t _lastNontrivialReceive; // frames, things like netconf, etc.
@ -654,7 +705,7 @@ private:
uint16_t _vMinor; uint16_t _vMinor;
uint16_t _vRevision; uint16_t _vRevision;
std::list< std::pair< Path *, int64_t > > _lastTriedPath; std::list<std::pair<Path*, int64_t> > _lastTriedPath;
Mutex _lastTriedPath_m; Mutex _lastTriedPath_m;
_PeerPath _paths[ZT_MAX_PEER_NETWORK_PATHS]; _PeerPath _paths[ZT_MAX_PEER_NETWORK_PATHS];
@ -679,7 +730,7 @@ private:
SharedPtr<Bond> _bond; SharedPtr<Bond> _bond;
#ifndef ZT_NO_PEER_METRICS #ifndef ZT_NO_PEER_METRICS
prometheus::Histogram<uint64_t> &_peer_latency; prometheus::Histogram<uint64_t>& _peer_latency;
prometheus::simpleapi::gauge_metric_t _alive_path_count; prometheus::simpleapi::gauge_metric_t _alive_path_count;
prometheus::simpleapi::gauge_metric_t _dead_path_count; prometheus::simpleapi::gauge_metric_t _dead_path_count;
prometheus::simpleapi::counter_metric_t _incoming_packet; prometheus::simpleapi::counter_metric_t _incoming_packet;
@ -692,11 +743,10 @@ private:
// Add a swap() for shared ptr's to peers to speed up peer sorts // Add a swap() for shared ptr's to peers to speed up peer sorts
namespace std { namespace std {
template<> template <> inline void swap(ZeroTier::SharedPtr<ZeroTier::Peer>& a, ZeroTier::SharedPtr<ZeroTier::Peer>& b)
inline void swap(ZeroTier::SharedPtr<ZeroTier::Peer> &a,ZeroTier::SharedPtr<ZeroTier::Peer> &b) {
{
a.swap(b); a.swap(b);
}
} }
} // namespace std
#endif #endif

View file

@ -4,16 +4,17 @@ D. J. Bernstein
Public domain. Public domain.
*/ */
#include "Constants.hpp"
#include "Poly1305.hpp" #include "Poly1305.hpp"
#include <stdio.h> #include "Constants.hpp"
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#pragma warning(disable: 4146) #pragma warning(disable : 4146)
#endif #endif
namespace ZeroTier { namespace ZeroTier {
@ -31,32 +32,42 @@ typedef struct poly1305_context {
// 128-bit implementation for MSC and GCC from Poly1305-donna // 128-bit implementation for MSC and GCC from Poly1305-donna
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
typedef struct uint128_t { typedef struct uint128_t {
unsigned long long lo; unsigned long long lo;
unsigned long long hi; unsigned long long hi;
} uint128_t; } uint128_t;
#define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi) #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi)
#define ADD(out, in) { unsigned long long t = out.lo; out.lo += in.lo; out.hi += (out.lo < t) + in.hi; } #define ADD(out, in) \
#define ADDLO(out, in) { unsigned long long t = out.lo; out.lo += in; out.hi += (out.lo < t); } { \
#define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift))) unsigned long long t = out.lo; \
#define LO(in) (in.lo) out.lo += in.lo; \
out.hi += (out.lo < t) + in.hi; \
}
#define ADDLO(out, in) \
{ \
unsigned long long t = out.lo; \
out.lo += in; \
out.hi += (out.lo < t); \
}
#define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift)))
#define LO(in) (in.lo)
// #define POLY1305_NOINLINE __declspec(noinline) // #define POLY1305_NOINLINE __declspec(noinline)
#elif defined(__GNUC__) #elif defined(__GNUC__)
#if defined(__SIZEOF_INT128__) #if defined(__SIZEOF_INT128__)
typedef unsigned __int128 uint128_t; typedef unsigned __int128 uint128_t;
#else #else
typedef unsigned uint128_t __attribute__((mode(TI))); typedef unsigned uint128_t __attribute__((mode(TI)));
#endif #endif
#define MUL(out, x, y) out = ((uint128_t)x * y) #define MUL(out, x, y) out = ((uint128_t)x * y)
#define ADD(out, in) out += in #define ADD(out, in) out += in
#define ADDLO(out, in) out += in #define ADDLO(out, in) out += in
#define SHR(in, shift) (unsigned long long)(in >> (shift)) #define SHR(in, shift) (unsigned long long)(in >> (shift))
#define LO(in) (unsigned long long)(in) #define LO(in) (unsigned long long)(in)
// #define POLY1305_NOINLINE __attribute__((noinline)) // #define POLY1305_NOINLINE __attribute__((noinline))
#endif #endif
@ -74,26 +85,20 @@ typedef struct poly1305_state_internal_t {
} poly1305_state_internal_t; } poly1305_state_internal_t;
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) #if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline unsigned long long U8TO64(const unsigned char *p) static inline unsigned long long U8TO64(const unsigned char* p)
{ {
return return (
(((unsigned long long)(p[0] & 0xff) ) | ((unsigned long long)(p[0] & 0xff)) | ((unsigned long long)(p[1] & 0xff) << 8) | ((unsigned long long)(p[2] & 0xff) << 16) | ((unsigned long long)(p[3] & 0xff) << 24) | ((unsigned long long)(p[4] & 0xff) << 32)
((unsigned long long)(p[1] & 0xff) << 8) | | ((unsigned long long)(p[5] & 0xff) << 40) | ((unsigned long long)(p[6] & 0xff) << 48) | ((unsigned long long)(p[7] & 0xff) << 56));
((unsigned long long)(p[2] & 0xff) << 16) |
((unsigned long long)(p[3] & 0xff) << 24) |
((unsigned long long)(p[4] & 0xff) << 32) |
((unsigned long long)(p[5] & 0xff) << 40) |
((unsigned long long)(p[6] & 0xff) << 48) |
((unsigned long long)(p[7] & 0xff) << 56));
} }
#else #else
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p)) #define U8TO64(p) (*reinterpret_cast<const unsigned long long*>(p))
#endif #endif
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) #if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline void U64TO8(unsigned char *p, unsigned long long v) static inline void U64TO8(unsigned char* p, unsigned long long v)
{ {
p[0] = (v ) & 0xff; p[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff; p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff; p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff; p[3] = (v >> 24) & 0xff;
@ -103,20 +108,21 @@ static inline void U64TO8(unsigned char *p, unsigned long long v)
p[7] = (v >> 56) & 0xff; p[7] = (v >> 56) & 0xff;
} }
#else #else
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v)) #define U64TO8(p, v) ((*reinterpret_cast<unsigned long long*>(p)) = (v))
#endif #endif
static inline void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { static inline void poly1305_init(poly1305_context* ctx, const unsigned char key[32])
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; {
unsigned long long t0,t1; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long t0, t1;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO64(&key[0]); t0 = U8TO64(&key[0]);
t1 = U8TO64(&key[8]); t1 = U8TO64(&key[8]);
st->r[0] = ( t0 ) & 0xffc0fffffff; st->r[0] = (t0) & 0xffc0fffffff;
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
/* h = 0 */ /* h = 0 */
st->h[0] = 0; st->h[0] = 0;
@ -131,13 +137,14 @@ static inline void poly1305_init(poly1305_context *ctx, const unsigned char key[
st->final = 0; st->final = 0;
} }
static inline void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { static inline void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes)
{
const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */ const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
unsigned long long r0,r1,r2; unsigned long long r0, r1, r2;
unsigned long long s1,s2; unsigned long long s1, s2;
unsigned long long h0,h1,h2; unsigned long long h0, h1, h2;
unsigned long long c; unsigned long long c;
uint128_t d0,d1,d2,d; uint128_t d0, d1, d2, d;
r0 = st->r[0]; r0 = st->r[0];
r1 = st->r[1]; r1 = st->r[1];
@ -151,26 +158,45 @@ static inline void poly1305_blocks(poly1305_state_internal_t *st, const unsigned
s2 = r2 * (5 << 2); s2 = r2 * (5 << 2);
while (bytes >= poly1305_block_size) { while (bytes >= poly1305_block_size) {
unsigned long long t0,t1; unsigned long long t0, t1;
/* h += m[i] */ /* h += m[i] */
t0 = U8TO64(&m[0]); t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]); t1 = U8TO64(&m[8]);
h0 += (( t0 ) & 0xfffffffffff); h0 += ((t0) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
/* h *= r */ /* h *= r */
MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); MUL(d0, h0, r0);
MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); MUL(d, h1, s2);
MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); ADD(d0, d);
MUL(d, h2, s1);
ADD(d0, d);
MUL(d1, h0, r1);
MUL(d, h1, r0);
ADD(d1, d);
MUL(d, h2, s2);
ADD(d1, d);
MUL(d2, h0, r2);
MUL(d, h1, r1);
ADD(d2, d);
MUL(d, h2, r0);
ADD(d2, d);
/* (partial) h %= p */ /* (partial) h %= p */
c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; c = SHR(d0, 44);
ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; h0 = LO(d0) & 0xfffffffffff;
ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; ADDLO(d1, c);
h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; c = SHR(d1, 44);
h1 = LO(d1) & 0xfffffffffff;
ADDLO(d2, c);
c = SHR(d2, 42);
h2 = LO(d2) & 0x3ffffffffff;
h0 += c * 5;
c = (h0 >> 44);
h0 = h0 & 0xfffffffffff;
h1 += c; h1 += c;
m += poly1305_block_size; m += poly1305_block_size;
@ -182,11 +208,12 @@ static inline void poly1305_blocks(poly1305_state_internal_t *st, const unsigned
st->h[2] = h2; st->h[2] = h2;
} }
static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { static inline void poly1305_finish(poly1305_context* ctx, unsigned char mac[16])
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; {
unsigned long long h0,h1,h2,c; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long g0,g1,g2; unsigned long long h0, h1, h2, c;
unsigned long long t0,t1; unsigned long long g0, g1, g2;
unsigned long long t0, t1;
/* process the remaining block */ /* process the remaining block */
if (st->leftover) { if (st->leftover) {
@ -204,17 +231,32 @@ static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16])
h1 = st->h[1]; h1 = st->h[1];
h2 = st->h[2]; h2 = st->h[2];
c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h1 >> 44);
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; h1 &= 0xfffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; h2 += c;
h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h2 >> 42);
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; h2 &= 0x3ffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; h0 += c * 5;
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += c;
c = (h1 >> 44);
h1 &= 0xfffffffffff;
h2 += c;
c = (h2 >> 42);
h2 &= 0x3ffffffffff;
h0 += c * 5;
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += c; h1 += c;
/* compute h + -p */ /* compute h + -p */
g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; g0 = h0 + 5;
g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; c = (g0 >> 44);
g0 &= 0xfffffffffff;
g1 = h1 + c;
c = (g1 >> 44);
g1 &= 0xfffffffffff;
g2 = h2 + c - ((unsigned long long)1 << 42); g2 = h2 + c - ((unsigned long long)1 << 42);
/* select h if h < p, or h + -p if h >= p */ /* select h if h < p, or h + -p if h >= p */
@ -231,12 +273,17 @@ static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16])
t0 = st->pad[0]; t0 = st->pad[0];
t1 = st->pad[1]; t1 = st->pad[1];
h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff; h0 += ((t0) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h0 >> 44);
h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff; h0 &= 0xfffffffffff;
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
c = (h1 >> 44);
h1 &= 0xfffffffffff;
h2 += (((t1 >> 24)) & 0x3ffffffffff) + c;
h2 &= 0x3ffffffffff;
/* mac = h % (2^128) */ /* mac = h % (2^128) */
h0 = ((h0 ) | (h1 << 44)); h0 = ((h0) | (h1 << 44));
h1 = ((h1 >> 20) | (h2 << 24)); h1 = ((h1 >> 20) | (h2 << 24));
U64TO8(&mac[0], h0); U64TO8(&mac[0], h0);
@ -273,33 +320,29 @@ typedef struct poly1305_state_internal_t {
} poly1305_state_internal_t; } poly1305_state_internal_t;
/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ /* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
static unsigned long static unsigned long U8TO32(const unsigned char* p)
U8TO32(const unsigned char *p) { {
return return (((unsigned long)(p[0] & 0xff)) | ((unsigned long)(p[1] & 0xff) << 8) | ((unsigned long)(p[2] & 0xff) << 16) | ((unsigned long)(p[3] & 0xff) << 24));
(((unsigned long)(p[0] & 0xff) ) |
((unsigned long)(p[1] & 0xff) << 8) |
((unsigned long)(p[2] & 0xff) << 16) |
((unsigned long)(p[3] & 0xff) << 24));
} }
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
static void static void U32TO8(unsigned char* p, unsigned long v)
U32TO8(unsigned char *p, unsigned long v) { {
p[0] = (v ) & 0xff; p[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff; p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff; p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff; p[3] = (v >> 24) & 0xff;
} }
static inline void static inline void poly1305_init(poly1305_context* ctx, const unsigned char key[32])
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; st->r[0] = (U8TO32(&key[0])) & 0x3ffffff;
st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03;
st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff;
st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff;
st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
/* h = 0 */ /* h = 0 */
@ -319,13 +362,13 @@ poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
st->final = 0; st->final = 0;
} }
static inline void static inline void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes)
poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { {
const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */
unsigned long r0,r1,r2,r3,r4; unsigned long r0, r1, r2, r3, r4;
unsigned long s1,s2,s3,s4; unsigned long s1, s2, s3, s4;
unsigned long h0,h1,h2,h3,h4; unsigned long h0, h1, h2, h3, h4;
unsigned long long d0,d1,d2,d3,d4; unsigned long long d0, d1, d2, d3, d4;
unsigned long c; unsigned long c;
r0 = st->r[0]; r0 = st->r[0];
@ -347,11 +390,11 @@ poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t by
while (bytes >= poly1305_block_size) { while (bytes >= poly1305_block_size) {
/* h += m[i] */ /* h += m[i] */
h0 += (U8TO32(m+ 0) ) & 0x3ffffff; h0 += (U8TO32(m + 0)) & 0x3ffffff;
h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff;
h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff;
h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff;
h4 += (U8TO32(m+12) >> 8) | hibit; h4 += (U8TO32(m + 12) >> 8) | hibit;
/* h *= r */ /* h *= r */
d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1);
@ -361,12 +404,23 @@ poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t by
d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0);
/* (partial) h %= p */ /* (partial) h %= p */
c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; c = (unsigned long)(d0 >> 26);
d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; h0 = (unsigned long)d0 & 0x3ffffff;
d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; d1 += c;
d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; c = (unsigned long)(d1 >> 26);
d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; h1 = (unsigned long)d1 & 0x3ffffff;
h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; d2 += c;
c = (unsigned long)(d2 >> 26);
h2 = (unsigned long)d2 & 0x3ffffff;
d3 += c;
c = (unsigned long)(d3 >> 26);
h3 = (unsigned long)d3 & 0x3ffffff;
d4 += c;
c = (unsigned long)(d4 >> 26);
h4 = (unsigned long)d4 & 0x3ffffff;
h0 += c * 5;
c = (h0 >> 26);
h0 = h0 & 0x3ffffff;
h1 += c; h1 += c;
m += poly1305_block_size; m += poly1305_block_size;
@ -380,11 +434,11 @@ poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t by
st->h[4] = h4; st->h[4] = h4;
} }
static inline void static inline void poly1305_finish(poly1305_context* ctx, unsigned char mac[16])
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long h0,h1,h2,h3,h4,c; unsigned long h0, h1, h2, h3, h4, c;
unsigned long g0,g1,g2,g3,g4; unsigned long g0, g1, g2, g3, g4;
unsigned long long f; unsigned long long f;
unsigned long mask; unsigned long mask;
@ -406,18 +460,35 @@ poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
h3 = st->h[3]; h3 = st->h[3];
h4 = st->h[4]; h4 = st->h[4];
c = h1 >> 26; h1 = h1 & 0x3ffffff; c = h1 >> 26;
h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; h1 = h1 & 0x3ffffff;
h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; h2 += c;
h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; c = h2 >> 26;
h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; h2 = h2 & 0x3ffffff;
h3 += c;
c = h3 >> 26;
h3 = h3 & 0x3ffffff;
h4 += c;
c = h4 >> 26;
h4 = h4 & 0x3ffffff;
h0 += c * 5;
c = h0 >> 26;
h0 = h0 & 0x3ffffff;
h1 += c; h1 += c;
/* compute h + -p */ /* compute h + -p */
g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; g0 = h0 + 5;
g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; c = g0 >> 26;
g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; g0 &= 0x3ffffff;
g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; g1 = h1 + c;
c = g1 >> 26;
g1 &= 0x3ffffff;
g2 = h2 + c;
c = g2 >> 26;
g2 &= 0x3ffffff;
g3 = h3 + c;
c = g3 >> 26;
g3 &= 0x3ffffff;
g4 = h4 + c - (1 << 26); g4 = h4 + c - (1 << 26);
/* select h if h < p, or h + -p if h >= p */ /* select h if h < p, or h + -p if h >= p */
@ -435,16 +506,20 @@ poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
h4 = (h4 & mask) | g4; h4 = (h4 & mask) | g4;
/* h = h % (2^128) */ /* h = h % (2^128) */
h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; h0 = ((h0) | (h1 << 26)) & 0xffffffff;
h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */ /* mac = (h + pad) % (2^128) */
f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; f = (unsigned long long)h0 + st->pad[0];
f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; h0 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; f = (unsigned long long)h1 + st->pad[1] + (f >> 32);
f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; h1 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32);
h2 = (unsigned long)f;
f = (unsigned long long)h3 + st->pad[3] + (f >> 32);
h3 = (unsigned long)f;
U32TO8(mac + 0, h0); U32TO8(mac + 0, h0);
U32TO8(mac + 4, h1); U32TO8(mac + 4, h1);
@ -472,8 +547,9 @@ poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
#endif // MSC/GCC or not #endif // MSC/GCC or not
static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { static inline void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes)
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; {
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
size_t i; size_t i;
/* handle leftover */ /* handle leftover */
@ -514,12 +590,12 @@ static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m
} // anonymous namespace } // anonymous namespace
void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key) void Poly1305::compute(void* auth, const void* data, unsigned int len, const void* key)
{ {
poly1305_context ctx; poly1305_context ctx;
poly1305_init(&ctx,reinterpret_cast<const unsigned char *>(key)); poly1305_init(&ctx, reinterpret_cast<const unsigned char*>(key));
poly1305_update(&ctx,reinterpret_cast<const unsigned char *>(data),(size_t)len); poly1305_update(&ctx, reinterpret_cast<const unsigned char*>(data), (size_t)len);
poly1305_finish(&ctx,reinterpret_cast<unsigned char *>(auth)); poly1305_finish(&ctx, reinterpret_cast<unsigned char*>(auth));
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -30,9 +30,8 @@ namespace ZeroTier {
* keystream as a one-time-use key. These 32 bytes are then discarded and * keystream as a one-time-use key. These 32 bytes are then discarded and
* the packet is encrypted with the next N bytes. * the packet is encrypted with the next N bytes.
*/ */
class Poly1305 class Poly1305 {
{ public:
public:
/** /**
* Compute a one-time authentication code * Compute a one-time authentication code
* *
@ -41,7 +40,7 @@ public:
* @param len Length of data to authenticate in bytes * @param len Length of data to authenticate in bytes
* @param key 32-byte one-time use key to authenticate data (must not be reused) * @param key 32-byte one-time use key to authenticate data (must not be reused)
*/ */
static void compute(void *auth,const void *data,unsigned int len,const void *key); static void compute(void* auth, const void* data, unsigned int len, const void* key);
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -12,30 +12,32 @@
/****/ /****/
#include "Revocation.hpp" #include "Revocation.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier { namespace ZeroTier {
int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const int Revocation::verify(const RuntimeEnvironment* RR, void* tPtr) const
{ {
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) { if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) {
return -1; return -1;
} }
const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (!id) { if (! id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1; return 1;
} }
try { try {
Buffer<sizeof(Revocation) + 64> tmp; Buffer<sizeof(Revocation) + 64> tmp;
this->serialize(tmp,true); this->serialize(tmp, true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
} catch ( ... ) { }
catch (...) {
return -1; return -1;
} }
} }

View file

@ -14,19 +14,19 @@
#ifndef ZT_REVOCATION_HPP #ifndef ZT_REVOCATION_HPP
#define ZT_REVOCATION_HPP #define ZT_REVOCATION_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "ECC.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Credential.hpp"
#include "Address.hpp"
#include "ECC.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp"
/** /**
* Flag: fast propagation via rumor mill algorithm * Flag: fast propagation via rumor mill algorithm
@ -40,22 +40,16 @@ class RuntimeEnvironment;
/** /**
* Revocation certificate to instantaneously revoke a COM, capability, or tag * Revocation certificate to instantaneously revoke a COM, capability, or tag
*/ */
class Revocation : public Credential class Revocation : public Credential {
{ public:
public: static inline Credential::Type credentialType()
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
Revocation() :
_id(0),
_credentialId(0),
_networkId(0),
_threshold(0),
_flags(0),
_target(),
_signedBy(),
_type(Credential::CREDENTIAL_TYPE_NULL)
{ {
memset(_signature.data,0,sizeof(_signature.data)); return Credential::CREDENTIAL_TYPE_REVOCATION;
}
Revocation() : _id(0), _credentialId(0), _networkId(0), _threshold(0), _flags(0), _target(), _signedBy(), _type(Credential::CREDENTIAL_TYPE_NULL)
{
memset(_signature.data, 0, sizeof(_signature.data));
} }
/** /**
@ -67,40 +61,64 @@ public:
* @param tgt Target node whose credential(s) are being revoked * @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked * @param ct Credential type being revoked
*/ */
Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const int64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) : Revocation(const uint32_t i, const uint64_t nwid, const uint32_t cid, const int64_t thr, const uint64_t fl, const Address& tgt, const Credential::Type ct)
_id(i), : _id(i)
_credentialId(cid), , _credentialId(cid)
_networkId(nwid), , _networkId(nwid)
_threshold(thr), , _threshold(thr)
_flags(fl), , _flags(fl)
_target(tgt), , _target(tgt)
_signedBy(), , _signedBy()
_type(ct) , _type(ct)
{ {
memset(_signature.data,0,sizeof(_signature.data)); memset(_signature.data, 0, sizeof(_signature.data));
} }
inline uint32_t id() const { return _id; } inline uint32_t id() const
inline uint32_t credentialId() const { return _credentialId; } {
inline uint64_t networkId() const { return _networkId; } return _id;
inline int64_t threshold() const { return _threshold; } }
inline const Address &target() const { return _target; } inline uint32_t credentialId() const
inline const Address &signer() const { return _signedBy; } {
inline Credential::Type type() const { return _type; } return _credentialId;
}
inline uint64_t networkId() const
{
return _networkId;
}
inline int64_t threshold() const
{
return _threshold;
}
inline const Address& target() const
{
return _target;
}
inline const Address& signer() const
{
return _signedBy;
}
inline Credential::Type type() const
{
return _type;
}
inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } inline bool fastPropagate() const
{
return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0);
}
/** /**
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
inline bool sign(const Identity &signer) inline bool sign(const Identity& signer)
{ {
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
Buffer<sizeof(Revocation) + 64> tmp; Buffer<sizeof(Revocation) + 64> tmp;
_signedBy = signer.address(); _signedBy = signer.address();
this->serialize(tmp,true); this->serialize(tmp, true);
_signature = signer.sign(tmp.data(),tmp.size()); _signature = signer.sign(tmp.data(), tmp.size());
return true; return true;
} }
return false; return false;
@ -113,10 +131,9 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
*/ */
int verify(const RuntimeEnvironment *RR,void *tPtr) const; int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{ {
if (forSign) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -133,10 +150,10 @@ public:
_signedBy.appendTo(b); _signedBy.appendTo(b);
b.append((uint8_t)_type); b.append((uint8_t)_type);
if (!forSign) { if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519 signature b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); b.append((uint16_t)ZT_ECC_SIGNATURE_LEN);
b.append(_signature.data,ZT_ECC_SIGNATURE_LEN); b.append(_signature.data, ZT_ECC_SIGNATURE_LEN);
} }
// This is the size of any additional fields, currently 0. // This is the size of any additional fields, currently 0.
@ -147,8 +164,7 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
*this = Revocation(); *this = Revocation();
@ -166,21 +182,23 @@ public:
p += 8; p += 8;
_flags = b.template at<uint64_t>(p); _flags = b.template at<uint64_t>(p);
p += 8; p += 8;
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _target.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
_type = (Credential::Type)b[p++]; _type = (Credential::Type)b[p++];
if (b[p++] == 1) { if (b[p++] == 1) {
if (b.template at<uint16_t>(p) == ZT_ECC_SIGNATURE_LEN) { if (b.template at<uint16_t>(p) == ZT_ECC_SIGNATURE_LEN) {
p += 2; p += 2;
memcpy(_signature.data,b.field(p,ZT_ECC_SIGNATURE_LEN),ZT_ECC_SIGNATURE_LEN); memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN);
p += ZT_ECC_SIGNATURE_LEN; p += ZT_ECC_SIGNATURE_LEN;
} else { }
else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} }
} else { }
else {
p += 2 + b.template at<uint16_t>(p); p += 2 + b.template at<uint16_t>(p);
} }
@ -192,7 +210,7 @@ public:
return (p - startAt); return (p - startAt);
} }
private: private:
uint32_t _id; uint32_t _id;
uint32_t _credentialId; uint32_t _credentialId;
uint64_t _networkId; uint64_t _networkId;

View file

@ -14,12 +14,12 @@
#ifndef ZT_RINGBUFFER_H #ifndef ZT_RINGBUFFER_H
#define ZT_RINGBUFFER_H #define ZT_RINGBUFFER_H
#include <typeinfo>
#include <cstdint>
#include <stdlib.h>
#include <memory.h>
#include <algorithm> #include <algorithm>
#include <cstdint>
#include <math.h> #include <math.h>
#include <memory.h>
#include <stdlib.h>
#include <typeinfo>
namespace ZeroTier { namespace ZeroTier {
@ -34,28 +34,23 @@ namespace ZeroTier {
* to reduce the complexity of code needed to interact with this type of buffer. * to reduce the complexity of code needed to interact with this type of buffer.
*/ */
template <class T,size_t S> template <class T, size_t S> class RingBuffer {
class RingBuffer private:
{
private:
T buf[S]; T buf[S];
size_t begin; size_t begin;
size_t end; size_t end;
bool wrap; bool wrap;
public: public:
RingBuffer() : RingBuffer() : begin(0), end(0), wrap(false)
begin(0),
end(0),
wrap(false)
{ {
memset(buf,0,sizeof(T)*S); memset(buf, 0, sizeof(T) * S);
} }
/** /**
* @return A pointer to the underlying buffer * @return A pointer to the underlying buffer
*/ */
inline T *get_buf() inline T* get_buf()
{ {
return buf + begin; return buf + begin;
} }
@ -87,7 +82,10 @@ public:
* Fast erase, O(1). * Fast erase, O(1).
* Merely reset the buffer pointer, doesn't erase contents * Merely reset the buffer pointer, doesn't erase contents
*/ */
inline void reset() { consume(count()); } inline void reset()
{
consume(count());
}
/** /**
* adjust buffer index pointer as if we copied data out * adjust buffer index pointer as if we copied data out
@ -116,7 +114,7 @@ public:
* @param data Buffer that is to be written to the ring * @param data Buffer that is to be written to the ring
* @param n Number of elements to write to the buffer * @param n Number of elements to write to the buffer
*/ */
inline size_t write(const T * data, size_t n) inline size_t write(const T* data, size_t n)
{ {
n = std::min(n, getFree()); n = std::min(n, getFree());
if (n == 0) { if (n == 0) {
@ -157,14 +155,17 @@ public:
/** /**
* @return The most recently pushed element on the buffer * @return The most recently pushed element on the buffer
*/ */
inline T get_most_recent() { return *(buf + end); } inline T get_most_recent()
{
return *(buf + end);
}
/** /**
* @param dest Destination buffer * @param dest Destination buffer
* @param n Size (in terms of number of elements) of the destination buffer * @param n Size (in terms of number of elements) of the destination buffer
* @return Number of elements read from the buffer * @return Number of elements read from the buffer
*/ */
inline size_t read(T *dest,size_t n) inline size_t read(T* dest, size_t n)
{ {
n = std::min(n, count()); n = std::min(n, count());
if (n == 0) { if (n == 0) {
@ -193,9 +194,11 @@ public:
{ {
if (end == begin) { if (end == begin) {
return wrap ? S : 0; return wrap ? S : 0;
} else if (end > begin) { }
else if (end > begin) {
return end - begin; return end - begin;
} else { }
else {
return S + end - begin; return S + end - begin;
} }
} }
@ -203,7 +206,10 @@ public:
/** /**
* @return The number of slots that are unused in the buffer * @return The number of slots that are unused in the buffer
*/ */
inline size_t getFree() { return S - count(); } inline size_t getFree()
{
return S - count();
}
/** /**
* @return The arithmetic mean of the contents of the buffer * @return The arithmetic mean of the contents of the buffer
@ -213,7 +219,7 @@ public:
size_t iterator = begin; size_t iterator = begin;
float subtotal = 0; float subtotal = 0;
size_t curr_cnt = count(); size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) { for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt; iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator); subtotal += (float)*(buf + iterator);
} }
@ -229,7 +235,7 @@ public:
size_t iterator = begin; size_t iterator = begin;
float subtotal = 0; float subtotal = 0;
size_t curr_cnt = count(); size_t curr_cnt = count();
for (size_t i=0; i<n; i++) { for (size_t i = 0; i < n; i++) {
iterator = (iterator + S - 1) % curr_cnt; iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator); subtotal += (float)*(buf + iterator);
} }
@ -244,7 +250,7 @@ public:
size_t iterator = begin; size_t iterator = begin;
float total = 0; float total = 0;
size_t curr_cnt = count(); size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) { for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt; iterator = (iterator + S - 1) % curr_cnt;
total += (float)*(buf + iterator); total += (float)*(buf + iterator);
} }
@ -254,7 +260,10 @@ public:
/** /**
* @return The sample standard deviation of element values * @return The sample standard deviation of element values
*/ */
inline float stddev() { return sqrt(variance()); } inline float stddev()
{
return sqrt(variance());
}
/** /**
* @return The variance of element values * @return The variance of element values
@ -265,10 +274,10 @@ public:
float cached_mean = mean(); float cached_mean = mean();
size_t curr_cnt = count(); size_t curr_cnt = count();
T sum_of_squared_deviations = 0; T sum_of_squared_deviations = 0;
for (size_t i=0; i<curr_cnt; i++) { for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt; iterator = (iterator + S - 1) % curr_cnt;
float deviation = (buf[i] - cached_mean); float deviation = (buf[i] - cached_mean);
sum_of_squared_deviations += (T)(deviation*deviation); sum_of_squared_deviations += (T)(deviation * deviation);
} }
float variance = (float)sum_of_squared_deviations / (float)(S - 1); float variance = (float)sum_of_squared_deviations / (float)(S - 1);
return variance; return variance;
@ -282,7 +291,7 @@ public:
size_t iterator = begin; size_t iterator = begin;
size_t zeros = 0; size_t zeros = 0;
size_t curr_cnt = count(); size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) { for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt; iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == 0) { if (*(buf + iterator) == 0) {
zeros++; zeros++;
@ -300,7 +309,7 @@ public:
size_t iterator = begin; size_t iterator = begin;
size_t cnt = 0; size_t cnt = 0;
size_t curr_cnt = count(); size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) { for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt; iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == value) { if (*(buf + iterator) == value) {
cnt++; cnt++;

View file

@ -14,11 +14,11 @@
#ifndef ZT_RUNTIMEENVIRONMENT_HPP #ifndef ZT_RUNTIMEENVIRONMENT_HPP
#define ZT_RUNTIMEENVIRONMENT_HPP #define ZT_RUNTIMEENVIRONMENT_HPP
#include <string.h>
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp"
#include <string.h>
namespace ZeroTier { namespace ZeroTier {
@ -36,17 +36,9 @@ class PacketMultiplexer;
/** /**
* Holds global state for an instance of ZeroTier::Node * Holds global state for an instance of ZeroTier::Node
*/ */
class RuntimeEnvironment class RuntimeEnvironment {
{ public:
public: RuntimeEnvironment(Node* n) : node(n), localNetworkController((NetworkController*)0), rtmem((void*)0), sw((Switch*)0), mc((Multicaster*)0), topology((Topology*)0), sa((SelfAwareness*)0)
RuntimeEnvironment(Node *n) :
node(n)
,localNetworkController((NetworkController *)0)
,rtmem((void *)0)
,sw((Switch *)0)
,mc((Multicaster *)0)
,topology((Topology *)0)
,sa((SelfAwareness *)0)
{ {
publicIdentityStr[0] = (char)0; publicIdentityStr[0] = (char)0;
secretIdentityStr[0] = (char)0; secretIdentityStr[0] = (char)0;
@ -54,17 +46,17 @@ public:
~RuntimeEnvironment() ~RuntimeEnvironment()
{ {
Utils::burn(secretIdentityStr,sizeof(secretIdentityStr)); Utils::burn(secretIdentityStr, sizeof(secretIdentityStr));
} }
// Node instance that owns this RuntimeEnvironment // Node instance that owns this RuntimeEnvironment
Node *const node; Node* const node;
// This is set externally to an instance of this base class // This is set externally to an instance of this base class
NetworkController *localNetworkController; NetworkController* localNetworkController;
// Memory actually occupied by Trace, Switch, etc. // Memory actually occupied by Trace, Switch, etc.
void *rtmem; void* rtmem;
/* Order matters a bit here. These are constructed in this order /* Order matters a bit here. These are constructed in this order
* and then deleted in the opposite order on Node exit. The order ensures * and then deleted in the opposite order on Node exit. The order ensures
@ -72,13 +64,13 @@ public:
* *
* These are constant and never null after startup unless indicated. */ * These are constant and never null after startup unless indicated. */
Trace *t; Trace* t;
Switch *sw; Switch* sw;
Multicaster *mc; Multicaster* mc;
Topology *topology; Topology* topology;
SelfAwareness *sa; SelfAwareness* sa;
Bond *bc; Bond* bc;
PacketMultiplexer *pm; PacketMultiplexer* pm;
// This node's identity and string representations thereof // This node's identity and string representations thereof
Identity identity; Identity identity;

View file

@ -1,10 +1,11 @@
// This code is public domain, taken from a PD crypto source file on GitHub. // This code is public domain, taken from a PD crypto source file on GitHub.
#include <algorithm>
#include "SHA512.hpp" #include "SHA512.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <algorithm>
namespace ZeroTier { namespace ZeroTier {
#ifndef ZT_HAVE_NATIVE_SHA512 #ifndef ZT_HAVE_NATIVE_SHA512
@ -12,48 +13,35 @@ namespace ZeroTier {
namespace { namespace {
struct sha512_state { struct sha512_state {
uint64_t length,state[8]; uint64_t length, state[8];
unsigned long curlen; unsigned long curlen;
uint8_t buf[128]; uint8_t buf[128];
}; };
static const uint64_t K[80] = { static const uint64_t K[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
0x428a2f98d728ae22ULL,0x7137449123ef65cdULL,0xb5c0fbcfec4d3b2fULL,0xe9b5dba58189dbbcULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x3956c25bf348b538ULL,0x59f111f1b605d019ULL,0x923f82a4af194f9bULL,0xab1c5ed5da6d8118ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
0xd807aa98a3030242ULL,0x12835b0145706fbeULL,0x243185be4ee4b28cULL,0x550c7dc3d5ffb4e2ULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x72be5d74f27b896fULL,0x80deb1fe3b1696b1ULL,0x9bdc06a725c71235ULL,0xc19bf174cf692694ULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0xe49b69c19ef14ad2ULL,0xefbe4786384f25e3ULL,0x0fc19dc68b8cd5b5ULL,0x240ca1cc77ac9c65ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x2de92c6f592b0275ULL,0x4a7484aa6ea6e483ULL,0x5cb0a9dcbd41fbd4ULL,0x76f988da831153b5ULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
0x983e5152ee66dfabULL,0xa831c66d2db43210ULL,0xb00327c898fb213fULL,0xbf597fc7beef0ee4ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0xc6e00bf33da88fc2ULL,0xd5a79147930aa725ULL,0x06ca6351e003826fULL,0x142929670a0e6e70ULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
0x27b70a8546d22ffcULL,0x2e1b21385c26c926ULL,0x4d2c6dfc5ac42aedULL,0x53380d139d95b3dfULL,
0x650a73548baf63deULL,0x766a0abb3c77b2a8ULL,0x81c2c92e47edaee6ULL,0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL,0xa81a664bbc423001ULL,0xc24b8b70d0f89791ULL,0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL,0xd69906245565a910ULL,0xf40e35855771202aULL,0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL,0x1e376c085141ab53ULL,0x2748774cdf8eeb99ULL,0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL,0x4ed8aa4ae3418acbULL,0x5b9cca4f7763e373ULL,0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL,0x78a5636f43172f60ULL,0x84c87814a1f0ab72ULL,0x8cc702081a6439ecULL,
0x90befffa23631e28ULL,0xa4506cebde82bde9ULL,0xbef9a3f7b2c67915ULL,0xc67178f2e372532bULL,
0xca273eceea26619cULL,0xd186b8c721c0c207ULL,0xeada7dd6cde0eb1eULL,0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL,0x0a637dc5a2c898a6ULL,0x113f9804bef90daeULL,0x1b710b35131c471bULL,
0x28db77f523047d84ULL,0x32caab7b40c72493ULL,0x3c9ebe0a15c9bebcULL,0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL,0x597f299cfc657e2aULL,0x5fcb6fab3ad6faecULL,0x6c44198c4a475817ULL
};
#define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y,x) #define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y, x)
#define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y) #define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y)
#define ROL64c(x,y) (((x)<<(y)) | ((x)>>(64-(y)))) #define ROL64c(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#define ROR64c(x,y) (((x)>>(y)) | ((x)<<(64-(y)))) #define ROR64c(x, y) (((x) >> (y)) | ((x) << (64 - (y))))
#define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y)) #define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n) #define S(x, n) ROR64c(x, n)
#define R(x, n) ((x)>>(n)) #define R(x, n) ((x) >> (n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) #define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf) static ZT_INLINE void sha512_compress(sha512_state* const md, uint8_t* const buf)
{ {
uint64_t S[8], W[80], t0, t1; uint64_t S[8], W[80], t0, t1;
int i; int i;
@ -62,27 +50,27 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
S[i] = md->state[i]; S[i] = md->state[i];
} }
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8*i)); LOAD64H(W[i], buf + (8 * i));
} }
for (i = 16; i < 80; i++) { for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
} }
#define RND(a,b,c,d,e,f,g,h,i) \ #define RND(a, b, c, d, e, f, g, h, i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \ t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \ d += t0; \
h = t0 + t1; h = t0 + t1;
for (i = 0; i < 80; i += 8) { for (i = 0; i < 80; i += 8) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
} }
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
@ -90,7 +78,7 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
} }
} }
static ZT_INLINE void sha384_init(sha512_state *const md) static ZT_INLINE void sha384_init(sha512_state* const md)
{ {
md->curlen = 0; md->curlen = 0;
md->length = 0; md->length = 0;
@ -104,7 +92,7 @@ static ZT_INLINE void sha384_init(sha512_state *const md)
md->state[7] = 0x47b5481dbefa4fa4ULL; md->state[7] = 0x47b5481dbefa4fa4ULL;
} }
static ZT_INLINE void sha512_init(sha512_state *const md) static ZT_INLINE void sha512_init(sha512_state* const md)
{ {
md->curlen = 0; md->curlen = 0;
md->length = 0; md->length = 0;
@ -118,30 +106,31 @@ static ZT_INLINE void sha512_init(sha512_state *const md)
md->state[7] = 0x5be0cd19137e2179ULL; md->state[7] = 0x5be0cd19137e2179ULL;
} }
static void sha512_process(sha512_state *const md,const uint8_t *in,unsigned long inlen) static void sha512_process(sha512_state* const md, const uint8_t* in, unsigned long inlen)
{ {
while (inlen > 0) { while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) { if (md->curlen == 0 && inlen >= 128) {
sha512_compress(md,(uint8_t *)in); sha512_compress(md, (uint8_t*)in);
md->length += 128 * 8; md->length += 128 * 8;
in += 128; in += 128;
inlen -= 128; inlen -= 128;
} else { }
unsigned long n = std::min(inlen,(128 - md->curlen)); else {
Utils::copy(md->buf + md->curlen,in,n); unsigned long n = std::min(inlen, (128 - md->curlen));
Utils::copy(md->buf + md->curlen, in, n);
md->curlen += n; md->curlen += n;
in += n; in += n;
inlen -= n; inlen -= n;
if (md->curlen == 128) { if (md->curlen == 128) {
sha512_compress(md,md->buf); sha512_compress(md, md->buf);
md->length += 8*128; md->length += 8 * 128;
md->curlen = 0; md->curlen = 0;
} }
} }
} }
} }
static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out) static ZT_INLINE void sha512_done(sha512_state* const md, uint8_t* out)
{ {
int i; int i;
@ -160,58 +149,58 @@ static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out)
md->buf[md->curlen++] = (uint8_t)0; md->buf[md->curlen++] = (uint8_t)0;
} }
STORE64H(md->length, md->buf+120); STORE64H(md->length, md->buf + 120);
sha512_compress(md, md->buf); sha512_compress(md, md->buf);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i)); STORE64H(md->state[i], out + (8 * i));
} }
} }
} // anonymous namespace } // anonymous namespace
void SHA512(void *digest,const void *data,unsigned int len) void SHA512(void* digest, const void* data, unsigned int len)
{ {
sha512_state state; sha512_state state;
sha512_init(&state); sha512_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len); sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state,(uint8_t *)digest); sha512_done(&state, (uint8_t*)digest);
} }
void SHA384(void *digest,const void *data,unsigned int len) void SHA384(void* digest, const void* data, unsigned int len)
{ {
uint8_t tmp[64]; uint8_t tmp[64];
sha512_state state; sha512_state state;
sha384_init(&state); sha384_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len); sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state,tmp); sha512_done(&state, tmp);
Utils::copy<48>(digest,tmp); Utils::copy<48>(digest, tmp);
} }
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{ {
uint8_t tmp[64]; uint8_t tmp[64];
sha512_state state; sha512_state state;
sha384_init(&state); sha384_init(&state);
sha512_process(&state,(uint8_t *)data0,(unsigned long)len0); sha512_process(&state, (uint8_t*)data0, (unsigned long)len0);
sha512_process(&state,(uint8_t *)data1,(unsigned long)len1); sha512_process(&state, (uint8_t*)data1, (unsigned long)len1);
sha512_done(&state,tmp); sha512_done(&state, tmp);
Utils::copy<48>(digest,tmp); Utils::copy<48>(digest, tmp);
} }
#endif // !ZT_HAVE_NATIVE_SHA512 #endif // !ZT_HAVE_NATIVE_SHA512
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const unsigned int msglen,uint8_t mac[48]) void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, const unsigned int msglen, uint8_t mac[48])
{ {
uint64_t kInPadded[16]; // input padded key uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg) uint64_t outer[22]; // output padded key | H(input padded key | msg)
const uint64_t k0 = Utils::loadMachineEndian< uint64_t >(key); const uint64_t k0 = Utils::loadMachineEndian<uint64_t>(key);
const uint64_t k1 = Utils::loadMachineEndian< uint64_t >(key + 8); const uint64_t k1 = Utils::loadMachineEndian<uint64_t>(key + 8);
const uint64_t k2 = Utils::loadMachineEndian< uint64_t >(key + 16); const uint64_t k2 = Utils::loadMachineEndian<uint64_t>(key + 16);
const uint64_t k3 = Utils::loadMachineEndian< uint64_t >(key + 24); const uint64_t k3 = Utils::loadMachineEndian<uint64_t>(key + 24);
const uint64_t k4 = Utils::loadMachineEndian< uint64_t >(key + 32); const uint64_t k4 = Utils::loadMachineEndian<uint64_t>(key + 32);
const uint64_t k5 = Utils::loadMachineEndian< uint64_t >(key + 40); const uint64_t k5 = Utils::loadMachineEndian<uint64_t>(key + 40);
const uint64_t ipad = 0x3636363636363636ULL; const uint64_t ipad = 0x3636363636363636ULL;
kInPadded[0] = k0 ^ ipad; kInPadded[0] = k0 ^ ipad;
@ -250,15 +239,15 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const u
outer[15] = opad; outer[15] = opad;
// H(output padded key | H(input padded key | msg)) // H(output padded key | H(input padded key | msg))
SHA384(reinterpret_cast<uint8_t *>(outer) + 128,kInPadded,128,msg,msglen); SHA384(reinterpret_cast<uint8_t*>(outer) + 128, kInPadded, 128, msg, msglen);
SHA384(mac,outer,176); SHA384(mac, outer, 176);
} }
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]) void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const char label, const char context, const uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
{ {
uint8_t kbkdfMsg[13]; uint8_t kbkdfMsg[13];
Utils::storeBigEndian<uint32_t>(kbkdfMsg,(uint32_t)iter); Utils::storeBigEndian<uint32_t>(kbkdfMsg, (uint32_t)iter);
kbkdfMsg[4] = (uint8_t)'Z'; kbkdfMsg[4] = (uint8_t)'Z';
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
@ -273,13 +262,15 @@ void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,c
kbkdfMsg[11] = 0x01; kbkdfMsg[11] = 0x01;
kbkdfMsg[12] = 0x80; kbkdfMsg[12] = 0x80;
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE"); static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE, "sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out); HMACSHA384(key, &kbkdfMsg, sizeof(kbkdfMsg), out);
} }
} // namespace ZeroTier } // namespace ZeroTier
// Internally re-export to included C code, which includes some fast crypto code ported in on some platforms. // Internally re-export to included C code, which includes some fast crypto code ported in on some platforms.
// This eliminates the need to link against a third party SHA512() from this code // This eliminates the need to link against a third party SHA512() from this code
extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len) extern "C" void ZT_sha512internal(void* digest, const void* data, unsigned int len)
{ ZeroTier::SHA512(digest,data,len); } {
ZeroTier::SHA512(digest, data, len);
}

View file

@ -32,34 +32,34 @@ namespace ZeroTier {
// SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS // SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS
#ifdef __APPLE__ #ifdef __APPLE__
#define ZT_HAVE_NATIVE_SHA512 1 #define ZT_HAVE_NATIVE_SHA512 1
static ZT_INLINE void SHA512(void *digest,const void *data,unsigned int len) static ZT_INLINE void SHA512(void* digest, const void* data, unsigned int len)
{ {
CC_SHA512_CTX ctx; CC_SHA512_CTX ctx;
CC_SHA512_Init(&ctx); CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx,data,len); CC_SHA512_Update(&ctx, data, len);
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx); CC_SHA512_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
} }
static ZT_INLINE void SHA384(void *digest,const void *data,unsigned int len) static ZT_INLINE void SHA384(void* digest, const void* data, unsigned int len)
{ {
CC_SHA512_CTX ctx; CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx); CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data,len); CC_SHA384_Update(&ctx, data, len);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx); CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
} }
static ZT_INLINE void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) static ZT_INLINE void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{ {
CC_SHA512_CTX ctx; CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx); CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data0,len0); CC_SHA384_Update(&ctx, data0, len0);
CC_SHA384_Update(&ctx,data1,len1); CC_SHA384_Update(&ctx, data1, len1);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx); CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
} }
#endif #endif
#ifndef ZT_HAVE_NATIVE_SHA512 #ifndef ZT_HAVE_NATIVE_SHA512
void SHA512(void *digest,const void *data,unsigned int len); void SHA512(void* digest, const void* data, unsigned int len);
void SHA384(void *digest,const void *data,unsigned int len); void SHA384(void* digest, const void* data, unsigned int len);
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1); void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1);
#endif #endif
/** /**
@ -70,7 +70,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u
* @param msglen Length of message * @param msglen Length of message
* @param mac Buffer to fill with result * @param mac Buffer to fill with result
*/ */
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigned int msglen,uint8_t mac[48]); void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, unsigned int msglen, uint8_t mac[48]);
/** /**
* Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF * Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF
@ -81,7 +81,7 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigne
* @param iter Key iteration for generation of multiple keys for the same label/context * @param iter Key iteration for generation of multiple keys for the same label/context
* @param out Output to receive derived key * @param out Output to receive derived key
*/ */
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],char label,char context,uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]); void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], char label, char context, uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE]);
} // namespace ZeroTier } // namespace ZeroTier

File diff suppressed because it is too large Load diff

View file

@ -7,15 +7,15 @@
#ifndef ZT_SALSA20_HPP #ifndef ZT_SALSA20_HPP
#define ZT_SALSA20_HPP #define ZT_SALSA20_HPP
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && !defined(__MINGW32__) && !defined(_M_ARM64))) #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (! defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && ! defined(__MINGW32__) && ! defined(_M_ARM64)))
#define ZT_SALSA20_SSE 1 #define ZT_SALSA20_SSE 1
#endif #endif
@ -28,11 +28,15 @@ namespace ZeroTier {
/** /**
* Salsa20 stream cipher * Salsa20 stream cipher
*/ */
class Salsa20 class Salsa20 {
{ public:
public: Salsa20()
Salsa20() {} {
~Salsa20() { Utils::burn(&_state,sizeof(_state)); } }
~Salsa20()
{
Utils::burn(&_state, sizeof(_state));
}
/** /**
* XOR d with s * XOR d with s
@ -45,48 +49,48 @@ public:
* @param s Source bytes to XOR with destination * @param s Source bytes to XOR with destination
* @param len Length of s and d * @param len Length of s and d
*/ */
static inline void memxor(uint8_t *d,const uint8_t *s,unsigned int len) static inline void memxor(uint8_t* d, const uint8_t* s, unsigned int len)
{ {
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
while (len >= 128) { while (len >= 128) {
__m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s)); __m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s));
__m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 16)); __m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 16));
__m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 32)); __m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 32));
__m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 48)); __m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 48));
__m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 64)); __m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 64));
__m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 80)); __m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 80));
__m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 96)); __m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 96));
__m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 112)); __m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 112));
__m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d)); __m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d));
__m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 16)); __m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 16));
__m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 32)); __m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 32));
__m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 48)); __m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 48));
__m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 64)); __m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 64));
__m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 80)); __m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 80));
__m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 96)); __m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 96));
__m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 112)); __m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 112));
d0 = _mm_xor_si128(d0,s0); d0 = _mm_xor_si128(d0, s0);
d1 = _mm_xor_si128(d1,s1); d1 = _mm_xor_si128(d1, s1);
d2 = _mm_xor_si128(d2,s2); d2 = _mm_xor_si128(d2, s2);
d3 = _mm_xor_si128(d3,s3); d3 = _mm_xor_si128(d3, s3);
d4 = _mm_xor_si128(d4,s4); d4 = _mm_xor_si128(d4, s4);
d5 = _mm_xor_si128(d5,s5); d5 = _mm_xor_si128(d5, s5);
d6 = _mm_xor_si128(d6,s6); d6 = _mm_xor_si128(d6, s6);
d7 = _mm_xor_si128(d7,s7); d7 = _mm_xor_si128(d7, s7);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),d0); _mm_storeu_si128(reinterpret_cast<__m128i*>(d), d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 16),d1); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 32),d2); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 48),d3); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 48), d3);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 64),d4); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 64), d4);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 80),d5); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 80), d5);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 96),d6); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 96), d6);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 112),d7); _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 112), d7);
s += 128; s += 128;
d += 128; d += 128;
len -= 128; len -= 128;
} }
while (len >= 16) { while (len >= 16) {
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),_mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i *>(d)),_mm_loadu_si128(reinterpret_cast<const __m128i *>(s)))); _mm_storeu_si128(reinterpret_cast<__m128i*>(d), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i*>(d)), _mm_loadu_si128(reinterpret_cast<const __m128i*>(s))));
s += 16; s += 16;
d += 16; d += 16;
len -= 16; len -= 16;
@ -94,10 +98,10 @@ public:
#else #else
#ifndef ZT_NO_TYPE_PUNNING #ifndef ZT_NO_TYPE_PUNNING
while (len >= 16) { while (len >= 16) {
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s)); (*reinterpret_cast<uint64_t*>(d)) ^= (*reinterpret_cast<const uint64_t*>(s));
s += 8; s += 8;
d += 8; d += 8;
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s)); (*reinterpret_cast<uint64_t*>(d)) ^= (*reinterpret_cast<const uint64_t*>(s));
s += 8; s += 8;
d += 8; d += 8;
len -= 16; len -= 16;
@ -114,9 +118,9 @@ public:
* @param key 256-bit (32 byte) key * @param key 256-bit (32 byte) key
* @param iv 64-bit initialization vector * @param iv 64-bit initialization vector
*/ */
Salsa20(const void *key,const void *iv) Salsa20(const void* key, const void* iv)
{ {
init(key,iv); init(key, iv);
} }
/** /**
@ -125,7 +129,7 @@ public:
* @param key Key bits * @param key Key bits
* @param iv 64-bit initialization vector * @param iv 64-bit initialization vector
*/ */
void init(const void *key,const void *iv); void init(const void* key, const void* iv);
/** /**
* Encrypt/decrypt data using Salsa20/12 * Encrypt/decrypt data using Salsa20/12
@ -134,7 +138,7 @@ public:
* @param out Output buffer * @param out Output buffer
* @param bytes Length of data * @param bytes Length of data
*/ */
void crypt12(const void *in,void *out,unsigned int bytes); void crypt12(const void* in, void* out, unsigned int bytes);
/** /**
* Encrypt/decrypt data using Salsa20/20 * Encrypt/decrypt data using Salsa20/20
@ -143,9 +147,9 @@ public:
* @param out Output buffer * @param out Output buffer
* @param bytes Length of data * @param bytes Length of data
*/ */
void crypt20(const void *in,void *out,unsigned int bytes); void crypt20(const void* in, void* out, unsigned int bytes);
private: private:
union { union {
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
__m128i v[4]; __m128i v[4];

View file

@ -11,66 +11,64 @@
*/ */
/****/ /****/
#include "SelfAwareness.hpp"
#include "Constants.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
#include <set>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <set>
#include <vector> #include <vector>
#include "Constants.hpp"
#include "SelfAwareness.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "Topology.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "Switch.hpp"
#include "Trace.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup // Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000
namespace ZeroTier { namespace ZeroTier {
class _ResetWithinScope class _ResetWithinScope {
{ public:
public: _ResetWithinScope(void* tPtr, int64_t now, int inetAddressFamily, InetAddress::IpScope scope) : _now(now), _tPtr(tPtr), _family(inetAddressFamily), _scope(scope)
_ResetWithinScope(void *tPtr,int64_t now,int inetAddressFamily,InetAddress::IpScope scope) : {
_now(now), }
_tPtr(tPtr),
_family(inetAddressFamily),
_scope(scope) {}
inline void operator()(Topology &t,const SharedPtr<Peer> &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); } inline void operator()(Topology& t, const SharedPtr<Peer>& p)
{
p->resetWithinScope(_tPtr, _scope, _family, _now);
}
private: private:
uint64_t _now; uint64_t _now;
void *_tPtr; void* _tPtr;
int _family; int _family;
InetAddress::IpScope _scope; InetAddress::IpScope _scope;
}; };
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : SelfAwareness::SelfAwareness(const RuntimeEnvironment* renv) : RR(renv), _phy(128)
RR(renv),
_phy(128)
{ {
} }
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now) void SelfAwareness::iam(void* tPtr, const Address& reporter, const int64_t receivedOnLocalSocket, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, bool trusted, int64_t now)
{ {
const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
if ((scope != reporterPhysicalAddress.ipScope())||(scope == InetAddress::IP_SCOPE_NONE)||(scope == InetAddress::IP_SCOPE_LOOPBACK)||(scope == InetAddress::IP_SCOPE_MULTICAST)) { if ((scope != reporterPhysicalAddress.ipScope()) || (scope == InetAddress::IP_SCOPE_NONE) || (scope == InetAddress::IP_SCOPE_LOOPBACK) || (scope == InetAddress::IP_SCOPE_MULTICAST)) {
return; return;
} }
Mutex::Lock _l(_phy_m); Mutex::Lock _l(_phy_m);
PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)]; PhySurfaceEntry& entry = _phy[PhySurfaceKey(reporter, receivedOnLocalSocket, reporterPhysicalAddress, scope)];
if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { if ((trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (! entry.mySurface.ipsEqual(myPhysicalAddress))) {
// Changes to external surface reported by trusted peers causes path reset in this scope // Changes to external surface reported by trusted peers causes path reset in this scope
RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope); RR->t->resettingPathsInScope(tPtr, reporter, reporterPhysicalAddress, myPhysicalAddress, scope);
entry.mySurface = myPhysicalAddress; entry.mySurface = myPhysicalAddress;
entry.ts = now; entry.ts = now;
@ -80,20 +78,21 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
// due to multiple reports of endpoint change. // due to multiple reports of endpoint change.
// Don't use 'entry' after this since hash table gets modified. // Don't use 'entry' after this since hash table gets modified.
{ {
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0; PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k,e)) { while (i.next(k, e)) {
if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) { if ((k->reporterPhysicalAddress != reporterPhysicalAddress) && (k->scope == scope)) {
_phy.erase(*k); _phy.erase(*k);
} }
} }
} }
// Reset all paths within this scope and address family // Reset all paths within this scope and address family
_ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); _ResetWithinScope rset(tPtr, now, myPhysicalAddress.ss_family, (InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope &>(rset); RR->topology->eachPeer<_ResetWithinScope&>(rset);
} else { }
else {
// Otherwise just update DB to use to determine external surface info // Otherwise just update DB to use to determine external surface info
entry.mySurface = myPhysicalAddress; entry.mySurface = myPhysicalAddress;
entry.ts = now; entry.ts = now;
@ -105,10 +104,10 @@ std::vector<InetAddress> SelfAwareness::whoami()
{ {
std::vector<InetAddress> surfaceAddresses; std::vector<InetAddress> surfaceAddresses;
Mutex::Lock _l(_phy_m); Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0; PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k,e)) { while (i.next(k, e)) {
if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) { if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) {
surfaceAddresses.push_back(e->mySurface); surfaceAddresses.push_back(e->mySurface);
} }
@ -119,10 +118,10 @@ std::vector<InetAddress> SelfAwareness::whoami()
void SelfAwareness::clean(int64_t now) void SelfAwareness::clean(int64_t now)
{ {
Mutex::Lock _l(_phy_m); Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0; PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k,e)) { while (i.next(k, e)) {
if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) { if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) {
_phy.erase(*k); _phy.erase(*k);
} }

View file

@ -14,10 +14,10 @@
#ifndef ZT_SELFAWARENESS_HPP #ifndef ZT_SELFAWARENESS_HPP
#define ZT_SELFAWARENESS_HPP #define ZT_SELFAWARENESS_HPP
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -27,10 +27,9 @@ class RuntimeEnvironment;
/** /**
* Tracks changes to this peer's real world addresses * Tracks changes to this peer's real world addresses
*/ */
class SelfAwareness class SelfAwareness {
{ public:
public: SelfAwareness(const RuntimeEnvironment* renv);
SelfAwareness(const RuntimeEnvironment *renv);
/** /**
* Called when a trusted remote peer informs us of our external network address * Called when a trusted remote peer informs us of our external network address
@ -42,7 +41,7 @@ public:
* @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param trusted True if this peer is trusted as an authority to inform us of external address changes
* @param now Current time * @param now Current time
*/ */
void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now); void iam(void* tPtr, const Address& reporter, const int64_t receivedOnLocalSocket, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, bool trusted, int64_t now);
/** /**
* Return all known external surface addresses reported by peers * Return all known external surface addresses reported by peers
@ -58,33 +57,45 @@ public:
*/ */
void clean(int64_t now); void clean(int64_t now);
private: private:
struct PhySurfaceKey struct PhySurfaceKey {
{
Address reporter; Address reporter;
int64_t receivedOnLocalSocket; int64_t receivedOnLocalSocket;
InetAddress reporterPhysicalAddress; InetAddress reporterPhysicalAddress;
InetAddress::IpScope scope; InetAddress::IpScope scope;
PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {} PhySurfaceKey() : reporter(), scope(InetAddress::IP_SCOPE_NONE)
PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {}
inline unsigned long hashCode() const { return ((unsigned long)reporter.toInt() + (unsigned long)scope); }
inline bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); }
};
struct PhySurfaceEntry
{ {
}
PhySurfaceKey(const Address& r, const int64_t rol, const InetAddress& ra, InetAddress::IpScope s) : reporter(r), receivedOnLocalSocket(rol), reporterPhysicalAddress(ra), scope(s)
{
}
inline unsigned long hashCode() const
{
return ((unsigned long)reporter.toInt() + (unsigned long)scope);
}
inline bool operator==(const PhySurfaceKey& k) const
{
return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope));
}
};
struct PhySurfaceEntry {
InetAddress mySurface; InetAddress mySurface;
uint64_t ts; uint64_t ts;
bool trusted; bool trusted;
PhySurfaceEntry() : mySurface(),ts(0),trusted(false) {} PhySurfaceEntry() : mySurface(), ts(0), trusted(false)
PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t),trusted(false) {} {
}
PhySurfaceEntry(const InetAddress& a, const uint64_t t) : mySurface(a), ts(t), trusted(false)
{
}
}; };
const RuntimeEnvironment *RR; const RuntimeEnvironment* RR;
Hashtable< PhySurfaceKey,PhySurfaceEntry > _phy; Hashtable<PhySurfaceKey, PhySurfaceEntry> _phy;
Mutex _phy_m; Mutex _phy_m;
}; };

View file

@ -14,8 +14,8 @@
#ifndef ZT_SHAREDPTR_HPP #ifndef ZT_SHAREDPTR_HPP
#define ZT_SHAREDPTR_HPP #define ZT_SHAREDPTR_HPP
#include "Mutex.hpp"
#include "AtomicCounter.hpp" #include "AtomicCounter.hpp"
#include "Mutex.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -26,13 +26,18 @@ namespace ZeroTier {
* counted must list this as a 'friend' and must have a private instance of * counted must list this as a 'friend' and must have a private instance of
* AtomicCounter called __refCount. * AtomicCounter called __refCount.
*/ */
template<typename T> template <typename T> class SharedPtr {
class SharedPtr public:
{ SharedPtr() : _ptr((T*)0)
public: {
SharedPtr() : _ptr((T *)0) {} }
SharedPtr(T *obj) : _ptr(obj) { ++obj->__refCount; } SharedPtr(T* obj) : _ptr(obj)
SharedPtr(const SharedPtr &sp) : _ptr(sp._getAndInc()) {} {
++obj->__refCount;
}
SharedPtr(const SharedPtr& sp) : _ptr(sp._getAndInc())
{
}
~SharedPtr() ~SharedPtr()
{ {
@ -43,10 +48,10 @@ public:
} }
} }
inline SharedPtr &operator=(const SharedPtr &sp) inline SharedPtr& operator=(const SharedPtr& sp)
{ {
if (_ptr != sp._ptr) { if (_ptr != sp._ptr) {
T *p = sp._getAndInc(); T* p = sp._getAndInc();
if (_ptr) { if (_ptr) {
if (--_ptr->__refCount <= 0) { if (--_ptr->__refCount <= 0) {
delete _ptr; delete _ptr;
@ -65,7 +70,7 @@ public:
* *
* @param ptr Naked pointer to assign * @param ptr Naked pointer to assign
*/ */
inline void set(T *ptr) inline void set(T* ptr)
{ {
zero(); zero();
++ptr->__refCount; ++ptr->__refCount;
@ -77,21 +82,33 @@ public:
* *
* @param with Pointer to swap with * @param with Pointer to swap with
*/ */
inline void swap(SharedPtr &with) inline void swap(SharedPtr& with)
{ {
T *tmp = _ptr; T* tmp = _ptr;
_ptr = with._ptr; _ptr = with._ptr;
with._ptr = tmp; with._ptr = tmp;
} }
inline operator bool() const { return (_ptr != (T *)0); } inline operator bool() const
inline T &operator*() const { return *_ptr; } {
inline T *operator->() const { return _ptr; } return (_ptr != (T*)0);
}
inline T& operator*() const
{
return *_ptr;
}
inline T* operator->() const
{
return _ptr;
}
/** /**
* @return Raw pointer to held object * @return Raw pointer to held object
*/ */
inline T *ptr() const { return _ptr; } inline T* ptr() const
{
return _ptr;
}
/** /**
* Set this pointer to NULL * Set this pointer to NULL
@ -102,7 +119,7 @@ public:
if (--_ptr->__refCount <= 0) { if (--_ptr->__refCount <= 0) {
delete _ptr; delete _ptr;
} }
_ptr = (T *)0; _ptr = (T*)0;
} }
} }
@ -117,22 +134,40 @@ public:
return 0; return 0;
} }
inline bool operator==(const SharedPtr &sp) const { return (_ptr == sp._ptr); } inline bool operator==(const SharedPtr& sp) const
inline bool operator!=(const SharedPtr &sp) const { return (_ptr != sp._ptr); } {
inline bool operator>(const SharedPtr &sp) const { return (_ptr > sp._ptr); } return (_ptr == sp._ptr);
inline bool operator<(const SharedPtr &sp) const { return (_ptr < sp._ptr); } }
inline bool operator>=(const SharedPtr &sp) const { return (_ptr >= sp._ptr); } inline bool operator!=(const SharedPtr& sp) const
inline bool operator<=(const SharedPtr &sp) const { return (_ptr <= sp._ptr); } {
return (_ptr != sp._ptr);
}
inline bool operator>(const SharedPtr& sp) const
{
return (_ptr > sp._ptr);
}
inline bool operator<(const SharedPtr& sp) const
{
return (_ptr < sp._ptr);
}
inline bool operator>=(const SharedPtr& sp) const
{
return (_ptr >= sp._ptr);
}
inline bool operator<=(const SharedPtr& sp) const
{
return (_ptr <= sp._ptr);
}
private: private:
inline T *_getAndInc() const inline T* _getAndInc() const
{ {
if (_ptr) { if (_ptr) {
++_ptr->__refCount; ++_ptr->__refCount;
} }
return _ptr; return _ptr;
} }
T *_ptr; T* _ptr;
}; };
} // namespace ZeroTier } // namespace ZeroTier

File diff suppressed because it is too large Load diff

View file

@ -14,22 +14,22 @@
#ifndef ZT_N_SWITCH_HPP #ifndef ZT_N_SWITCH_HPP
#define ZT_N_SWITCH_HPP #define ZT_N_SWITCH_HPP
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "IncomingPacket.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include "Mutex.hpp"
#include "Network.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include "Topology.hpp"
#include "Utils.hpp"
#include <list>
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include <list>
#include "Constants.hpp"
#include "Mutex.hpp"
#include "MAC.hpp"
#include "Packet.hpp"
#include "Utils.hpp"
#include "InetAddress.hpp"
#include "Topology.hpp"
#include "Network.hpp"
#include "SharedPtr.hpp"
#include "IncomingPacket.hpp"
#include "Hashtable.hpp"
/* Ethernet frame types that might be relevant to us */ /* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800 #define ZT_ETHERTYPE_IPV4 0x0800
@ -54,20 +54,19 @@ class Peer;
* packets from tap devices, and this sends them where they need to go and * packets from tap devices, and this sends them where they need to go and
* wraps/unwraps accordingly. It also handles queues and timeouts and such. * wraps/unwraps accordingly. It also handles queues and timeouts and such.
*/ */
class Switch class Switch {
{
struct ManagedQueue; struct ManagedQueue;
struct TXQueueEntry; struct TXQueueEntry;
friend class SharedPtr<Peer>; friend class SharedPtr<Peer>;
typedef struct { typedef struct {
TXQueueEntry *p; TXQueueEntry* p;
bool ok_to_drop; bool ok_to_drop;
} dqr; } dqr;
public: public:
Switch(const RuntimeEnvironment *renv); Switch(const RuntimeEnvironment* renv);
/** /**
* Called when a packet is received from the real network * Called when a packet is received from the real network
@ -78,7 +77,7 @@ public:
* @param data Packet data * @param data Packet data
* @param len Packet length * @param len Packet length
*/ */
void onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len); void onRemotePacket(void* tPtr, const int64_t localSocket, const InetAddress& fromAddr, const void* data, unsigned int len);
/** /**
* Returns whether our bonding or balancing policy is aware of flows. * Returns whether our bonding or balancing policy is aware of flows.
@ -97,7 +96,7 @@ public:
* @param data Ethernet payload * @param data Ethernet payload
* @param len Frame length * @param len Frame length
*/ */
void onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); void onLocalEthernet(void* tPtr, const SharedPtr<Network>& network, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len);
/** /**
* Determines the next drop schedule for packets in the TX queue * Determines the next drop schedule for packets in the TX queue
@ -114,7 +113,7 @@ public:
* @param q The TX queue that is being dequeued from * @param q The TX queue that is being dequeued from
* @param now Current time * @param now Current time
*/ */
dqr dodequeue(ManagedQueue *q, uint64_t now); dqr dodequeue(ManagedQueue* q, uint64_t now);
/** /**
* Presents a packet to the AQM scheduler. * Presents a packet to the AQM scheduler.
@ -125,14 +124,14 @@ public:
* @param encrypt Encrypt packet payload? (always true except for HELLO) * @param encrypt Encrypt packet payload? (always true except for HELLO)
* @param qosBucket Which bucket the rule-system determined this packet should fall into * @param qosBucket Which bucket the rule-system determined this packet should fall into
*/ */
void aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &packet,bool encrypt,int qosBucket,int32_t flowId = ZT_QOS_NO_FLOW); void aqm_enqueue(void* tPtr, const SharedPtr<Network>& network, Packet& packet, bool encrypt, int qosBucket, int32_t flowId = ZT_QOS_NO_FLOW);
/** /**
* Performs a single AQM cycle and dequeues and transmits all eligible packets on all networks * Performs a single AQM cycle and dequeues and transmits all eligible packets on all networks
* *
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/ */
void aqm_dequeue(void *tPtr); void aqm_dequeue(void* tPtr);
/** /**
* Calls the dequeue mechanism and adjust queue state variables * Calls the dequeue mechanism and adjust queue state variables
@ -141,7 +140,7 @@ public:
* @param isNew Whether or not this queue is in the NEW list * @param isNew Whether or not this queue is in the NEW list
* @param now Current time * @param now Current time
*/ */
Switch::TXQueueEntry * CoDelDequeue(ManagedQueue *q, bool isNew, uint64_t now); Switch::TXQueueEntry* CoDelDequeue(ManagedQueue* q, bool isNew, uint64_t now);
/** /**
* Removes QoS Queues and flow state variables for a specific network. These queues are created * Removes QoS Queues and flow state variables for a specific network. These queues are created
@ -171,7 +170,7 @@ public:
* @param packet Packet to send (buffer may be modified) * @param packet Packet to send (buffer may be modified)
* @param encrypt Encrypt packet payload? (always true except for HELLO) * @param encrypt Encrypt packet payload? (always true except for HELLO)
*/ */
void send(void *tPtr,Packet &packet,bool encrypt,int32_t flowId = ZT_QOS_NO_FLOW); void send(void* tPtr, Packet& packet, bool encrypt, int32_t flowId = ZT_QOS_NO_FLOW);
/** /**
* Request WHOIS on a given address * Request WHOIS on a given address
@ -180,7 +179,7 @@ public:
* @param now Current time * @param now Current time
* @param addr Address to look up * @param addr Address to look up
*/ */
void requestWhois(void *tPtr,const int64_t now,const Address &addr); void requestWhois(void* tPtr, const int64_t now, const Address& addr);
/** /**
* Run any processes that are waiting for this peer's identity * Run any processes that are waiting for this peer's identity
@ -190,7 +189,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer New peer * @param peer New peer
*/ */
void doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer); void doAnythingWaitingForPeer(void* tPtr, const SharedPtr<Peer>& peer);
/** /**
* Perform retries and other periodic timer tasks * Perform retries and other periodic timer tasks
@ -202,26 +201,27 @@ public:
* @param now Current time * @param now Current time
* @return Number of milliseconds until doTimerTasks() should be run again * @return Number of milliseconds until doTimerTasks() should be run again
*/ */
unsigned long doTimerTasks(void *tPtr,int64_t now); unsigned long doTimerTasks(void* tPtr, int64_t now);
private: private:
bool _shouldUnite(const int64_t now,const Address &source,const Address &destination); bool _shouldUnite(const int64_t now, const Address& source, const Address& destination);
bool _trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId = ZT_QOS_NO_FLOW); // packet is modified if return is true bool _trySend(void* tPtr, Packet& packet, bool encrypt, int32_t flowId = ZT_QOS_NO_FLOW); // packet is modified if return is true
void _sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path> viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId); void _sendViaSpecificPath(void* tPtr, SharedPtr<Peer> peer, SharedPtr<Path> viaPath, uint16_t userSpecifiedMtu, int64_t now, Packet& packet, bool encrypt, int32_t flowId);
void _recordOutgoingPacketMetrics(const Packet &p); void _recordOutgoingPacketMetrics(const Packet& p);
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
int64_t _lastBeaconResponse; int64_t _lastBeaconResponse;
volatile int64_t _lastCheckedQueues; volatile int64_t _lastCheckedQueues;
// Time we last sent a WHOIS request for each address // Time we last sent a WHOIS request for each address
Hashtable< Address,int64_t > _lastSentWhoisRequest; Hashtable<Address, int64_t> _lastSentWhoisRequest;
Mutex _lastSentWhoisRequest_m; Mutex _lastSentWhoisRequest_m;
// Packets waiting for WHOIS replies or other decode info or missing fragments // Packets waiting for WHOIS replies or other decode info or missing fragments
struct RXQueueEntry struct RXQueueEntry {
RXQueueEntry() : timestamp(0)
{ {
RXQueueEntry() : timestamp(0) {} }
volatile int64_t timestamp; // 0 if entry is not in use volatile int64_t timestamp; // 0 if entry is not in use
volatile uint64_t packetId; volatile uint64_t packetId;
IncomingPacket frag0; // head of packet IncomingPacket frag0; // head of packet
@ -236,12 +236,12 @@ private:
AtomicCounter _rxQueuePtr; AtomicCounter _rxQueuePtr;
// Returns matching or next available RX queue entry // Returns matching or next available RX queue entry
inline RXQueueEntry *_findRXQueueEntry(uint64_t packetId) inline RXQueueEntry* _findRXQueueEntry(uint64_t packetId)
{ {
const unsigned int current = static_cast<unsigned int>(_rxQueuePtr.load()); const unsigned int current = static_cast<unsigned int>(_rxQueuePtr.load());
for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) { for (unsigned int k = 1; k <= ZT_RX_QUEUE_SIZE; ++k) {
RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]); RXQueueEntry* rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]);
if ((rq->packetId == packetId)&&(rq->timestamp)) { if ((rq->packetId == packetId) && (rq->timestamp)) {
return rq; return rq;
} }
} }
@ -250,21 +250,19 @@ private:
} }
// Returns current entry in rx queue ring buffer and increments ring pointer // Returns current entry in rx queue ring buffer and increments ring pointer
inline RXQueueEntry *_nextRXQueueEntry() inline RXQueueEntry* _nextRXQueueEntry()
{ {
return &(_rxQueue[static_cast<unsigned int>((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]); return &(_rxQueue[static_cast<unsigned int>((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]);
} }
// ZeroTier-layer TX queue entry // ZeroTier-layer TX queue entry
struct TXQueueEntry struct TXQueueEntry {
TXQueueEntry()
{ {
TXQueueEntry() {} }
TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc,int32_t fid) : TXQueueEntry(Address d, uint64_t ct, const Packet& p, bool enc, int32_t fid) : dest(d), creationTime(ct), packet(p), encrypt(enc), flowId(fid)
dest(d), {
creationTime(ct), }
packet(p),
encrypt(enc),
flowId(fid) {}
Address dest; Address dest;
uint64_t creationTime; uint64_t creationTime;
@ -272,40 +270,44 @@ private:
bool encrypt; bool encrypt;
int32_t flowId; int32_t flowId;
}; };
std::list< TXQueueEntry > _txQueue; std::list<TXQueueEntry> _txQueue;
Mutex _txQueue_m; Mutex _txQueue_m;
Mutex _aqm_m; Mutex _aqm_m;
// Tracks sending of VERB_RENDEZVOUS to relaying peers // Tracks sending of VERB_RENDEZVOUS to relaying peers
struct _LastUniteKey struct _LastUniteKey {
_LastUniteKey() : x(0), y(0)
{ {
_LastUniteKey() : x(0),y(0) {} }
_LastUniteKey(const Address &a1,const Address &a2) _LastUniteKey(const Address& a1, const Address& a2)
{ {
if (a1 > a2) { if (a1 > a2) {
x = a2.toInt(); x = a2.toInt();
y = a1.toInt(); y = a1.toInt();
} else { }
else {
x = a1.toInt(); x = a1.toInt();
y = a2.toInt(); y = a2.toInt();
} }
} }
inline unsigned long hashCode() const { return ((unsigned long)x ^ (unsigned long)y); } inline unsigned long hashCode() const
inline bool operator==(const _LastUniteKey &k) const { return ((x == k.x)&&(y == k.y)); } {
uint64_t x,y; return ((unsigned long)x ^ (unsigned long)y);
}
inline bool operator==(const _LastUniteKey& k) const
{
return ((x == k.x) && (y == k.y));
}
uint64_t x, y;
}; };
Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior Hashtable<_LastUniteKey, uint64_t> _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior
Mutex _lastUniteAttempt_m; Mutex _lastUniteAttempt_m;
// Queue with additional flow state variables // Queue with additional flow state variables
struct ManagedQueue struct ManagedQueue {
ManagedQueue(int id) : id(id), byteCredit(ZT_AQM_QUANTUM), byteLength(0), dropping(false)
{ {
ManagedQueue(int id) : }
id(id),
byteCredit(ZT_AQM_QUANTUM),
byteLength(0),
dropping(false)
{}
int id; int id;
int byteCredit; int byteCredit;
int byteLength; int byteLength;
@ -314,17 +316,16 @@ private:
uint64_t drop_next; uint64_t drop_next;
bool dropping; bool dropping;
uint64_t drop_next_time; uint64_t drop_next_time;
std::list< TXQueueEntry *> q; std::list<TXQueueEntry*> q;
}; };
// To implement fq_codel we need to maintain a queue of queues // To implement fq_codel we need to maintain a queue of queues
struct NetworkQoSControlBlock struct NetworkQoSControlBlock {
{
int _currEnqueuedPackets; int _currEnqueuedPackets;
std::vector<ManagedQueue *> newQueues; std::vector<ManagedQueue*> newQueues;
std::vector<ManagedQueue *> oldQueues; std::vector<ManagedQueue*> oldQueues;
std::vector<ManagedQueue *> inactiveQueues; std::vector<ManagedQueue*> inactiveQueues;
}; };
std::map<uint64_t,NetworkQoSControlBlock*> _netQueueControlBlock; std::map<uint64_t, NetworkQoSControlBlock*> _netQueueControlBlock;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -12,30 +12,32 @@
/****/ /****/
#include "Tag.hpp" #include "Tag.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier { namespace ZeroTier {
int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const int Tag::verify(const RuntimeEnvironment* RR, void* tPtr) const
{ {
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) { if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) {
return -1; return -1;
} }
const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (!id) { if (! id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1; return 1;
} }
try { try {
Buffer<(sizeof(Tag) * 2)> tmp; Buffer<(sizeof(Tag) * 2)> tmp;
this->serialize(tmp,true); this->serialize(tmp, true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
} catch ( ... ) { }
catch (...) {
return -1; return -1;
} }
} }

View file

@ -14,18 +14,18 @@
#ifndef ZT_TAG_HPP #ifndef ZT_TAG_HPP
#define ZT_TAG_HPP #define ZT_TAG_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "ECC.hpp"
#include "Identity.hpp"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "ECC.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
@ -47,18 +47,16 @@ class RuntimeEnvironment;
* Unlike capabilities tags are signed only by the issuer and are never * Unlike capabilities tags are signed only by the issuer and are never
* transferable. * transferable.
*/ */
class Tag : public Credential class Tag : public Credential {
{ public:
public: static inline Credential::Type credentialType()
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
Tag() :
_id(0),
_value(0),
_networkId(0),
_ts(0)
{ {
memset(_signature.data,0,sizeof(_signature.data)); return Credential::CREDENTIAL_TYPE_TAG;
}
Tag() : _id(0), _value(0), _networkId(0), _ts(0)
{
memset(_signature.data, 0, sizeof(_signature.data));
} }
/** /**
@ -68,23 +66,35 @@ public:
* @param id Tag ID * @param id Tag ID
* @param value Tag value * @param value Tag value
*/ */
Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) : Tag(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id, const uint32_t value) : _id(id), _value(value), _networkId(nwid), _ts(ts), _issuedTo(issuedTo), _signedBy()
_id(id),
_value(value),
_networkId(nwid),
_ts(ts),
_issuedTo(issuedTo),
_signedBy()
{ {
memset(_signature.data,0,sizeof(_signature.data)); memset(_signature.data, 0, sizeof(_signature.data));
} }
inline uint32_t id() const { return _id; } inline uint32_t id() const
inline const uint32_t &value() const { return _value; } {
inline uint64_t networkId() const { return _networkId; } return _id;
inline int64_t timestamp() const { return _ts; } }
inline const Address &issuedTo() const { return _issuedTo; } inline const uint32_t& value() const
inline const Address &signedBy() const { return _signedBy; } {
return _value;
}
inline uint64_t networkId() const
{
return _networkId;
}
inline int64_t timestamp() const
{
return _ts;
}
inline const Address& issuedTo() const
{
return _issuedTo;
}
inline const Address& signedBy() const
{
return _signedBy;
}
/** /**
* Sign this tag * Sign this tag
@ -92,13 +102,13 @@ public:
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
inline bool sign(const Identity &signer) inline bool sign(const Identity& signer)
{ {
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
Buffer<sizeof(Tag) + 64> tmp; Buffer<sizeof(Tag) + 64> tmp;
_signedBy = signer.address(); _signedBy = signer.address();
this->serialize(tmp,true); this->serialize(tmp, true);
_signature = signer.sign(tmp.data(),tmp.size()); _signature = signer.sign(tmp.data(), tmp.size());
return true; return true;
} }
return false; return false;
@ -111,10 +121,9 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag
*/ */
int verify(const RuntimeEnvironment *RR,void *tPtr) const; int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{ {
if (forSign) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -127,10 +136,10 @@ public:
_issuedTo.appendTo(b); _issuedTo.appendTo(b);
_signedBy.appendTo(b); _signedBy.appendTo(b);
if (!forSign) { if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519 b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_ECC_SIGNATURE_LEN); b.append(_signature.data, ZT_ECC_SIGNATURE_LEN);
} }
b.append((uint16_t)0); // length of additional fields, currently 0 b.append((uint16_t)0); // length of additional fields, currently 0
@ -140,8 +149,7 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
unsigned int p = startAt; unsigned int p = startAt;
@ -157,18 +165,19 @@ public:
_value = b.template at<uint32_t>(p); _value = b.template at<uint32_t>(p);
p += 4; p += 4;
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _issuedTo.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) { if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_ECC_SIGNATURE_LEN) { if (b.template at<uint16_t>(p) != ZT_ECC_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} }
p += 2; p += 2;
memcpy(_signature.data,b.field(p,ZT_ECC_SIGNATURE_LEN),ZT_ECC_SIGNATURE_LEN); memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN);
p += ZT_ECC_SIGNATURE_LEN; p += ZT_ECC_SIGNATURE_LEN;
} else { }
else {
p += 2 + b.template at<uint16_t>(p); p += 2 + b.template at<uint16_t>(p);
} }
@ -181,26 +190,61 @@ public:
} }
// Provides natural sort order by ID // Provides natural sort order by ID
inline bool operator<(const Tag &t) const { return (_id < t._id); } inline bool operator<(const Tag& t) const
{
return (_id < t._id);
}
inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); } inline bool operator==(const Tag& t) const
inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); } {
return (memcmp(this, &t, sizeof(Tag)) == 0);
}
inline bool operator!=(const Tag& t) const
{
return (memcmp(this, &t, sizeof(Tag)) != 0);
}
// For searching sorted arrays or lists of Tags by ID // For searching sorted arrays or lists of Tags by ID
struct IdComparePredicate struct IdComparePredicate {
inline bool operator()(const Tag& a, const Tag& b) const
{ {
inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); } return (a.id() < b.id());
inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); } }
inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); } inline bool operator()(const uint32_t a, const Tag& b) const
inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); } {
inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); } return (a < b.id());
inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); } }
inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); } inline bool operator()(const Tag& a, const uint32_t b) const
inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); } {
inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); } return (a.id() < b);
}
inline bool operator()(const Tag* a, const Tag* b) const
{
return (a->id() < b->id());
}
inline bool operator()(const Tag* a, const Tag& b) const
{
return (a->id() < b.id());
}
inline bool operator()(const Tag& a, const Tag* b) const
{
return (a.id() < b->id());
}
inline bool operator()(const uint32_t a, const Tag* b) const
{
return (a < b->id());
}
inline bool operator()(const Tag* a, const uint32_t b) const
{
return (a->id() < b);
}
inline bool operator()(const uint32_t a, const uint32_t b) const
{
return (a < b);
}
}; };
private: private:
uint32_t _id; uint32_t _id;
uint32_t _value; uint32_t _value;
uint64_t _networkId; uint64_t _networkId;

View file

@ -11,63 +11,79 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "Topology.hpp" #include "Topology.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp" #include "Buffer.hpp"
#include "Constants.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#include "Buffer.hpp" #include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp" #include "Switch.hpp"
namespace ZeroTier { namespace ZeroTier {
#define ZT_DEFAULT_WORLD_LENGTH 570 #define ZT_DEFAULT_WORLD_LENGTH 570
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x7e,0xe9,0x57,0x60,0xcd,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x36,0x00,0x92,0x76,0x37,0xef,0x4d,0x14,0x04,0xa4,0x4d,0x54,0x46,0x84,0x85,0x13,0x79,0x75,0x1f,0xaa,0x79,0xb4,0xc4,0xea,0x85,0x04,0x01,0x75,0xea,0x06,0x58,0x60,0x48,0x24,0x02,0xe1,0xeb,0x34,0x20,0x52,0x00,0x0e,0x62,0x90,0x06,0x1a,0x9b,0xe0,0xcd,0x29,0x3c,0x8b,0x55,0xf1,0xc3,0xd2,0x52,0x48,0x08,0xaf,0xc5,0x49,0x22,0x08,0x0e,0x35,0x39,0xa7,0x5a,0xdd,0xc3,0xce,0xf0,0xf6,0xad,0x26,0x0d,0x58,0x82,0x93,0xbb,0x77,0x86,0xe7,0x1e,0xfa,0x4b,0x90,0x57,0xda,0xd9,0x86,0x7a,0xfe,0x12,0xdd,0x04,0xca,0xfe,0x9e,0xfe,0xb9,0x00,0xcc,0xde,0xf7,0x6b,0xc7,0xb9,0x7d,0xed,0x90,0x4e,0xab,0xc5,0xdf,0x09,0x88,0x6d,0x9c,0x15,0x14,0xa6,0x10,0x03,0x6c,0xb9,0x13,0x9c,0xc2,0x14,0x00,0x1a,0x29,0x58,0x97,0x8e,0xfc,0xec,0x15,0x71,0x2d,0xd3,0x94,0x8c,0x6e,0x6b,0x3a,0x8e,0x89,0x3d,0xf0,0x1f,0xf4,0x93,0xd1,0xf8,0xd9,0x80,0x6a,0x86,0x0c,0x54,0x20,0x57,0x1b,0xf0,0x00,0x02,0x04,0x68,0xc2,0x08,0x86,0x27,0x09,0x06,0x26,0x05,0x98,0x80,0x02,0x00,0x12,0x00,0x00,0x30,0x05,0x71,0x0e,0x34,0x00,0x51,0x27,0x09,0x77,0x8c,0xde,0x71,0x90,0x00,0x3f,0x66,0x81,0xa9,0x9e,0x5a,0xd1,0x89,0x5e,0x9f,0xba,0x33,0xe6,0x21,0x2d,0x44,0x54,0xe1,0x68,0xbc,0xec,0x71,0x12,0x10,0x1b,0xf0,0x00,0x95,0x6e,0xd8,0xe9,0x2e,0x42,0x89,0x2c,0xb6,0xf2,0xec,0x41,0x08,0x81,0xa8,0x4a,0xb1,0x9d,0xa5,0x0e,0x12,0x87,0xba,0x3d,0x92,0x6c,0x3a,0x1f,0x75,0x5c,0xcc,0xf2,0x99,0xa1,0x20,0x70,0x55,0x00,0x02,0x04,0x67,0xc3,0x67,0x42,0x27,0x09,0x06,0x26,0x05,0x98,0x80,0x04,0x00,0x00,0xc3,0x02,0x54,0xf2,0xbc,0xa1,0xf7,0x00,0x19,0x27,0x09,0x62,0xf8,0x65,0xae,0x71,0x00,0xe2,0x07,0x6c,0x57,0xde,0x87,0x0e,0x62,0x88,0xd7,0xd5,0xe7,0x40,0x44,0x08,0xb1,0x54,0x5e,0xfc,0xa3,0x7d,0x67,0xf7,0x7b,0x87,0xe9,0xe5,0x41,0x68,0xc2,0x5d,0x3e,0xf1,0xa9,0xab,0xf2,0x90,0x5e,0xa5,0xe7,0x85,0xc0,0x1d,0xff,0x23,0x88,0x7a,0xd4,0x23,0x2d,0x95,0xc7,0xa8,0xfd,0x2c,0x27,0x11,0x1a,0x72,0xbd,0x15,0x93,0x22,0xdc,0x00,0x02,0x04,0x32,0x07,0xfc,0x8a,0x27,0x09,0x06,0x20,0x01,0x49,0xf0,0xd0,0xdb,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0xca,0xfe,0x04,0xeb,0xa9,0x00,0x6c,0x6a,0x9d,0x1d,0xea,0x55,0xc1,0x61,0x6b,0xfe,0x2a,0x2b,0x8f,0x0f,0xf9,0xa8,0xca,0xca,0xf7,0x03,0x74,0xfb,0x1f,0x39,0xe3,0xbe,0xf8,0x1c,0xbf,0xeb,0xef,0x17,0xb7,0x22,0x82,0x68,0xa0,0xa2,0xa2,0x9d,0x34,0x88,0xc7,0x52,0x56,0x5c,0x6c,0x96,0x5c,0xbd,0x65,0x06,0xec,0x24,0x39,0x7c,0xc8,0xa5,0xd9,0xd1,0x52,0x85,0xa8,0x7f,0x00,0x02,0x04,0x54,0x11,0x35,0x9b,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xd4,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x99,0x93,0x27,0x09}; static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xea, 0xc9, 0x0a, 0x00, 0x00, 0x01, 0x7e, 0xe9, 0x57, 0x60, 0xcd, 0xb8, 0xb3, 0x88, 0xa4, 0x69, 0x22, 0x14, 0x91, 0xaa, 0x9a, 0xcd, 0x66, 0xcc, 0x76, 0x4c, 0xde, 0xfd, 0x56, 0x03, 0x9f, 0x10,
0x67, 0xae, 0x15, 0xe6, 0x9c, 0x6f, 0xb4, 0x2d, 0x7b, 0x55, 0x33, 0x0e, 0x3f, 0xda, 0xac, 0x52, 0x9c, 0x07, 0x92, 0xfd, 0x73, 0x40, 0xa6, 0xaa, 0x21, 0xab, 0xa8, 0xa4, 0x89, 0xfd, 0xae, 0xa4, 0x4a, 0x39, 0xbf, 0x2d, 0x00, 0x65,
0x9a, 0xc9, 0xc8, 0x18, 0xeb, 0x36, 0x00, 0x92, 0x76, 0x37, 0xef, 0x4d, 0x14, 0x04, 0xa4, 0x4d, 0x54, 0x46, 0x84, 0x85, 0x13, 0x79, 0x75, 0x1f, 0xaa, 0x79, 0xb4, 0xc4, 0xea, 0x85, 0x04, 0x01, 0x75, 0xea, 0x06, 0x58, 0x60, 0x48,
0x24, 0x02, 0xe1, 0xeb, 0x34, 0x20, 0x52, 0x00, 0x0e, 0x62, 0x90, 0x06, 0x1a, 0x9b, 0xe0, 0xcd, 0x29, 0x3c, 0x8b, 0x55, 0xf1, 0xc3, 0xd2, 0x52, 0x48, 0x08, 0xaf, 0xc5, 0x49, 0x22, 0x08, 0x0e, 0x35, 0x39, 0xa7, 0x5a, 0xdd, 0xc3,
0xce, 0xf0, 0xf6, 0xad, 0x26, 0x0d, 0x58, 0x82, 0x93, 0xbb, 0x77, 0x86, 0xe7, 0x1e, 0xfa, 0x4b, 0x90, 0x57, 0xda, 0xd9, 0x86, 0x7a, 0xfe, 0x12, 0xdd, 0x04, 0xca, 0xfe, 0x9e, 0xfe, 0xb9, 0x00, 0xcc, 0xde, 0xf7, 0x6b, 0xc7, 0xb9,
0x7d, 0xed, 0x90, 0x4e, 0xab, 0xc5, 0xdf, 0x09, 0x88, 0x6d, 0x9c, 0x15, 0x14, 0xa6, 0x10, 0x03, 0x6c, 0xb9, 0x13, 0x9c, 0xc2, 0x14, 0x00, 0x1a, 0x29, 0x58, 0x97, 0x8e, 0xfc, 0xec, 0x15, 0x71, 0x2d, 0xd3, 0x94, 0x8c, 0x6e, 0x6b,
0x3a, 0x8e, 0x89, 0x3d, 0xf0, 0x1f, 0xf4, 0x93, 0xd1, 0xf8, 0xd9, 0x80, 0x6a, 0x86, 0x0c, 0x54, 0x20, 0x57, 0x1b, 0xf0, 0x00, 0x02, 0x04, 0x68, 0xc2, 0x08, 0x86, 0x27, 0x09, 0x06, 0x26, 0x05, 0x98, 0x80, 0x02, 0x00, 0x12, 0x00,
0x00, 0x30, 0x05, 0x71, 0x0e, 0x34, 0x00, 0x51, 0x27, 0x09, 0x77, 0x8c, 0xde, 0x71, 0x90, 0x00, 0x3f, 0x66, 0x81, 0xa9, 0x9e, 0x5a, 0xd1, 0x89, 0x5e, 0x9f, 0xba, 0x33, 0xe6, 0x21, 0x2d, 0x44, 0x54, 0xe1, 0x68, 0xbc, 0xec, 0x71,
0x12, 0x10, 0x1b, 0xf0, 0x00, 0x95, 0x6e, 0xd8, 0xe9, 0x2e, 0x42, 0x89, 0x2c, 0xb6, 0xf2, 0xec, 0x41, 0x08, 0x81, 0xa8, 0x4a, 0xb1, 0x9d, 0xa5, 0x0e, 0x12, 0x87, 0xba, 0x3d, 0x92, 0x6c, 0x3a, 0x1f, 0x75, 0x5c, 0xcc, 0xf2, 0x99,
0xa1, 0x20, 0x70, 0x55, 0x00, 0x02, 0x04, 0x67, 0xc3, 0x67, 0x42, 0x27, 0x09, 0x06, 0x26, 0x05, 0x98, 0x80, 0x04, 0x00, 0x00, 0xc3, 0x02, 0x54, 0xf2, 0xbc, 0xa1, 0xf7, 0x00, 0x19, 0x27, 0x09, 0x62, 0xf8, 0x65, 0xae, 0x71, 0x00,
0xe2, 0x07, 0x6c, 0x57, 0xde, 0x87, 0x0e, 0x62, 0x88, 0xd7, 0xd5, 0xe7, 0x40, 0x44, 0x08, 0xb1, 0x54, 0x5e, 0xfc, 0xa3, 0x7d, 0x67, 0xf7, 0x7b, 0x87, 0xe9, 0xe5, 0x41, 0x68, 0xc2, 0x5d, 0x3e, 0xf1, 0xa9, 0xab, 0xf2, 0x90, 0x5e,
0xa5, 0xe7, 0x85, 0xc0, 0x1d, 0xff, 0x23, 0x88, 0x7a, 0xd4, 0x23, 0x2d, 0x95, 0xc7, 0xa8, 0xfd, 0x2c, 0x27, 0x11, 0x1a, 0x72, 0xbd, 0x15, 0x93, 0x22, 0xdc, 0x00, 0x02, 0x04, 0x32, 0x07, 0xfc, 0x8a, 0x27, 0x09, 0x06, 0x20, 0x01,
0x49, 0xf0, 0xd0, 0xdb, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x27, 0x09, 0xca, 0xfe, 0x04, 0xeb, 0xa9, 0x00, 0x6c, 0x6a, 0x9d, 0x1d, 0xea, 0x55, 0xc1, 0x61, 0x6b, 0xfe, 0x2a, 0x2b, 0x8f, 0x0f, 0xf9, 0xa8,
0xca, 0xca, 0xf7, 0x03, 0x74, 0xfb, 0x1f, 0x39, 0xe3, 0xbe, 0xf8, 0x1c, 0xbf, 0xeb, 0xef, 0x17, 0xb7, 0x22, 0x82, 0x68, 0xa0, 0xa2, 0xa2, 0x9d, 0x34, 0x88, 0xc7, 0x52, 0x56, 0x5c, 0x6c, 0x96, 0x5c, 0xbd, 0x65, 0x06, 0xec, 0x24,
0x39, 0x7c, 0xc8, 0xa5, 0xd9, 0xd1, 0x52, 0x85, 0xa8, 0x7f, 0x00, 0x02, 0x04, 0x54, 0x11, 0x35, 0x9b, 0x27, 0x09, 0x06, 0x2a, 0x02, 0x6e, 0xa0, 0xd4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x93, 0x27, 0x09
};
Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : Topology::Topology(const RuntimeEnvironment* renv, void* tPtr) : RR(renv), _numConfiguredPhysicalPaths(0), _amUpstream(false)
RR(renv),
_numConfiguredPhysicalPaths(0),
_amUpstream(false)
{ {
uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = 0; idtmp[0] = 0;
idtmp[1] = 0; idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp)); int n = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PLANET, idtmp, tmp, sizeof(tmp));
if (n > 0) { if (n > 0) {
try { try {
World cachedPlanet; World cachedPlanet;
cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n),0); cachedPlanet.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp, (unsigned int)n), 0);
addWorld(tPtr,cachedPlanet,false); addWorld(tPtr, cachedPlanet, false);
} catch ( ... ) {} // ignore invalid cached planets }
catch (...) {
} // ignore invalid cached planets
} }
World defaultPlanet; World defaultPlanet;
{ {
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD, ZT_DEFAULT_WORLD_LENGTH);
defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top defaultPlanet.deserialize(wtmp, 0); // throws on error, which would indicate a bad static variable up top
} }
addWorld(tPtr,defaultPlanet,false); addWorld(tPtr, defaultPlanet, false);
} }
Topology::~Topology() Topology::~Topology()
{ {
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers); Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0; Address* a = (Address*)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0; SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a,p)) { while (i.next(a, p)) {
_savePeer((void *)0,*p); _savePeer((void*)0, *p);
} }
} }
SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer) SharedPtr<Peer> Topology::addPeer(void* tPtr, const SharedPtr<Peer>& peer)
{ {
SharedPtr<Peer> np; SharedPtr<Peer> np;
{ {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &hp = _peers[peer->address()]; SharedPtr<Peer>& hp = _peers[peer->address()];
if (!hp) { if (! hp) {
hp = peer; hp = peer;
} }
np = hp; np = hp;
@ -75,7 +91,7 @@ SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
return np; return np;
} }
SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta) SharedPtr<Peer> Topology::getPeer(void* tPtr, const Address& zta)
{ {
if (zta == RR->identity.address()) { if (zta == RR->identity.address()) {
return SharedPtr<Peer>(); return SharedPtr<Peer>();
@ -83,7 +99,7 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
{ {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta); const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) { if (ap) {
return *ap; return *ap;
} }
@ -94,32 +110,35 @@ SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
uint64_t idbuf[2]; uint64_t idbuf[2];
idbuf[0] = zta.toInt(); idbuf[0] = zta.toInt();
idbuf[1] = 0; idbuf[1] = 0;
int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE); int len = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PEER, idbuf, buf.unsafeData(), ZT_PEER_MAX_SERIALIZED_STATE_SIZE);
if (len > 0) { if (len > 0) {
buf.setSize(len); buf.setSize(len);
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &ap = _peers[zta]; SharedPtr<Peer>& ap = _peers[zta];
if (ap) { if (ap) {
return ap; return ap;
} }
ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); ap = Peer::deserializeFromCache(RR->node->now(), tPtr, buf, RR);
if (!ap) { if (! ap) {
_peers.erase(zta); _peers.erase(zta);
} }
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
} catch ( ... ) {} // ignore invalid identities or other strange failures }
catch (...) {
} // ignore invalid identities or other strange failures
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
Identity Topology::getIdentity(void *tPtr,const Address &zta) Identity Topology::getIdentity(void* tPtr, const Address& zta)
{ {
if (zta == RR->identity.address()) { if (zta == RR->identity.address()) {
return RR->identity; return RR->identity;
} else { }
else {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta); const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) { if (ap) {
return (*ap)->identity(); return (*ap)->identity();
} }
@ -131,13 +150,13 @@ SharedPtr<Peer> Topology::getUpstreamPeer()
{ {
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
unsigned int bestq = ~((unsigned int)0); unsigned int bestq = ~((unsigned int)0);
const SharedPtr<Peer> *best = (const SharedPtr<Peer> *)0; const SharedPtr<Peer>* best = (const SharedPtr<Peer>*)0;
Mutex::Lock _l2(_peers_m); Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l1(_upstreams_m);
for(std::vector<Address>::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { for (std::vector<Address>::const_iterator a(_upstreamAddresses.begin()); a != _upstreamAddresses.end(); ++a) {
const SharedPtr<Peer> *p = _peers.get(*a); const SharedPtr<Peer>* p = _peers.get(*a);
if (p) { if (p) {
const unsigned int q = (*p)->relayQuality(now); const unsigned int q = (*p)->relayQuality(now);
if (q <= bestq) { if (q <= bestq) {
@ -147,25 +166,25 @@ SharedPtr<Peer> Topology::getUpstreamPeer()
} }
} }
if (!best) { if (! best) {
return SharedPtr<Peer>(); return SharedPtr<Peer>();
} }
return *best; return *best;
} }
bool Topology::isUpstream(const Identity &id) const bool Topology::isUpstream(const Identity& id) const
{ {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end()); return (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), id.address()) != _upstreamAddresses.end());
} }
bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const bool Topology::shouldAcceptWorldUpdateFrom(const Address& addr) const
{ {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end()) { if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), addr) != _upstreamAddresses.end()) {
return true; return true;
} }
for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { for (std::vector<std::pair<uint64_t, Address> >::const_iterator s(_moonSeeds.begin()); s != _moonSeeds.end(); ++s) {
if (s->second == addr) { if (s->second == addr) {
return true; return true;
} }
@ -173,11 +192,11 @@ bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const
return false; return false;
} }
ZT_PeerRole Topology::role(const Address &ztaddr) const ZT_PeerRole Topology::role(const Address& ztaddr) const
{ {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { for (std::vector<World::Root>::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) {
if (i->identity.address() == ztaddr) { if (i->identity.address() == ztaddr) {
return ZT_PEER_ROLE_PLANET; return ZT_PEER_ROLE_PLANET;
} }
@ -187,32 +206,32 @@ ZT_PeerRole Topology::role(const Address &ztaddr) const
return ZT_PEER_ROLE_LEAF; return ZT_PEER_ROLE_LEAF;
} }
bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const bool Topology::isProhibitedEndpoint(const Address& ztaddr, const InetAddress& ipaddr) const
{ {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
// For roots the only permitted addresses are those defined. This adds just a little // For roots the only permitted addresses are those defined. This adds just a little
// bit of extra security against spoofing, replaying, etc. // bit of extra security against spoofing, replaying, etc.
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) { for (std::vector<World::Root>::const_iterator r(_planet.roots().begin()); r != _planet.roots().end(); ++r) {
if (r->identity.address() == ztaddr) { if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty()) { if (r->stableEndpoints.empty()) {
return false; // no stable endpoints specified, so allow dynamic paths return false; // no stable endpoints specified, so allow dynamic paths
} }
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { for (std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin()); e != r->stableEndpoints.end(); ++e) {
if (ipaddr.ipsEqual(*e)) { if (ipaddr.ipsEqual(*e)) {
return false; return false;
} }
} }
} }
} }
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) { for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
for(std::vector<World::Root>::const_iterator r(m->roots().begin());r!=m->roots().end();++r) { for (std::vector<World::Root>::const_iterator r(m->roots().begin()); r != m->roots().end(); ++r) {
if (r->identity.address() == ztaddr) { if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty()) { if (r->stableEndpoints.empty()) {
return false; // no stable endpoints specified, so allow dynamic paths return false; // no stable endpoints specified, so allow dynamic paths
} }
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { for (std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin()); e != r->stableEndpoints.end(); ++e) {
if (ipaddr.ipsEqual(*e)) { if (ipaddr.ipsEqual(*e)) {
return false; return false;
} }
@ -226,22 +245,22 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa
return false; return false;
} }
bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) bool Topology::addWorld(void* tPtr, const World& newWorld, bool alwaysAcceptNew)
{ {
if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) { if ((newWorld.type() != World::TYPE_PLANET) && (newWorld.type() != World::TYPE_MOON)) {
return false; return false;
} }
Mutex::Lock _l2(_peers_m); Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l1(_upstreams_m);
World *existing = (World *)0; World* existing = (World*)0;
switch(newWorld.type()) { switch (newWorld.type()) {
case World::TYPE_PLANET: case World::TYPE_PLANET:
existing = &_planet; existing = &_planet;
break; break;
case World::TYPE_MOON: case World::TYPE_MOON:
for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) { for (std::vector<World>::iterator m(_moons.begin()); m != _moons.end(); ++m) {
if (m->id() == newWorld.id()) { if (m->id() == newWorld.id()) {
existing = &(*m); existing = &(*m);
break; break;
@ -255,17 +274,20 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
if (existing) { if (existing) {
if (existing->shouldBeReplacedBy(newWorld)) { if (existing->shouldBeReplacedBy(newWorld)) {
*existing = newWorld; *existing = newWorld;
} else { }
else {
return false; return false;
} }
} else if (newWorld.type() == World::TYPE_MOON) { }
else if (newWorld.type() == World::TYPE_MOON) {
if (alwaysAcceptNew) { if (alwaysAcceptNew) {
_moons.push_back(newWorld); _moons.push_back(newWorld);
existing = &(_moons.back()); existing = &(_moons.back());
} else { }
for(std::vector< std::pair<uint64_t,Address> >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { else {
for (std::vector<std::pair<uint64_t, Address> >::iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) {
if (m->first == newWorld.id()) { if (m->first == newWorld.id()) {
for(std::vector<World::Root>::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) { for (std::vector<World::Root>::const_iterator r(newWorld.roots().begin()); r != newWorld.roots().end(); ++r) {
if (r->identity.address() == m->second) { if (r->identity.address() == m->second) {
_moonSeeds.erase(m); _moonSeeds.erase(m);
_moons.push_back(newWorld); _moons.push_back(newWorld);
@ -279,73 +301,79 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
} }
} }
} }
if (!existing) { if (! existing) {
return false; return false;
} }
} else { }
else {
return false; return false;
} }
try { try {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf; Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf;
existing->serialize(sbuf,false); existing->serialize(sbuf, false);
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = existing->id(); idtmp[0] = existing->id();
idtmp[1] = 0; idtmp[1] = 0;
RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size()); RR->node->stateObjectPut(tPtr, (existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON, idtmp, sbuf.data(), sbuf.size());
} catch ( ... ) {} }
catch (...) {
}
_memoizeUpstreams(tPtr); _memoizeUpstreams(tPtr);
return true; return true;
} }
void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed) void Topology::addMoon(void* tPtr, const uint64_t id, const Address& seed)
{ {
char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = id; idtmp[0] = id;
idtmp[1] = 0; idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp)); int n = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_MOON, idtmp, tmp, sizeof(tmp));
if (n > 0) { if (n > 0) {
try { try {
World w; World w;
w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp,(unsigned int)n)); w.deserialize(Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH>(tmp, (unsigned int)n));
if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) { if ((w.type() == World::TYPE_MOON) && (w.id() == id)) {
addWorld(tPtr,w,true); addWorld(tPtr, w, true);
return; return;
} }
} catch ( ... ) {} }
catch (...) {
}
} }
if (seed) { if (seed) {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair<uint64_t,Address>(id,seed)) == _moonSeeds.end()) { if (std::find(_moonSeeds.begin(), _moonSeeds.end(), std::pair<uint64_t, Address>(id, seed)) == _moonSeeds.end()) {
_moonSeeds.push_back(std::pair<uint64_t,Address>(id,seed)); _moonSeeds.push_back(std::pair<uint64_t, Address>(id, seed));
} }
} }
} }
void Topology::removeMoon(void *tPtr,const uint64_t id) void Topology::removeMoon(void* tPtr, const uint64_t id)
{ {
Mutex::Lock _l2(_peers_m); Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m); Mutex::Lock _l1(_upstreams_m);
std::vector<World> nm; std::vector<World> nm;
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) { for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
if (m->id() != id) { if (m->id() != id) {
nm.push_back(*m); nm.push_back(*m);
} else { }
else {
uint64_t idtmp[2]; uint64_t idtmp[2];
idtmp[0] = id; idtmp[0] = id;
idtmp[1] = 0; idtmp[1] = 0;
RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp); RR->node->stateObjectDelete(tPtr, ZT_STATE_OBJECT_MOON, idtmp);
} }
} }
_moons.swap(nm); _moons.swap(nm);
std::vector< std::pair<uint64_t,Address> > cm; std::vector<std::pair<uint64_t, Address> > cm;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { for (std::vector<std::pair<uint64_t, Address> >::const_iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) {
if (m->first != id) { if (m->first != id) {
cm.push_back(*m); cm.push_back(*m);
} }
@ -355,17 +383,17 @@ void Topology::removeMoon(void *tPtr,const uint64_t id)
_memoizeUpstreams(tPtr); _memoizeUpstreams(tPtr);
} }
void Topology::doPeriodicTasks(void *tPtr,int64_t now) void Topology::doPeriodicTasks(void* tPtr, int64_t now)
{ {
{ {
Mutex::Lock _l1(_peers_m); Mutex::Lock _l1(_peers_m);
Mutex::Lock _l2(_upstreams_m); Mutex::Lock _l2(_upstreams_m);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers); Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0; Address* a = (Address*)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0; SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a,p)) { while (i.next(a, p)) {
if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { if ((! (*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), *a) == _upstreamAddresses.end())) {
_savePeer(tPtr,*p); _savePeer(tPtr, *p);
_peers.erase(*a); _peers.erase(*a);
} }
} }
@ -373,10 +401,10 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
Hashtable< Path::HashKey,SharedPtr<Path> >::Iterator i(_paths); Hashtable<Path::HashKey, SharedPtr<Path> >::Iterator i(_paths);
Path::HashKey *k = (Path::HashKey *)0; Path::HashKey* k = (Path::HashKey*)0;
SharedPtr<Path> *p = (SharedPtr<Path> *)0; SharedPtr<Path>* p = (SharedPtr<Path>*)0;
while (i.next(k,p)) { while (i.next(k, p)) {
if (p->references() <= 1) { if (p->references() <= 1) {
_paths.erase(*k); _paths.erase(*k);
} }
@ -384,43 +412,45 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
} }
} }
void Topology::_memoizeUpstreams(void *tPtr) void Topology::_memoizeUpstreams(void* tPtr)
{ {
// assumes _upstreams_m and _peers_m are locked // assumes _upstreams_m and _peers_m are locked
_upstreamAddresses.clear(); _upstreamAddresses.clear();
_amUpstream = false; _amUpstream = false;
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { for (std::vector<World::Root>::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) {
const Identity &id = i->identity; const Identity& id = i->identity;
if (id == RR->identity) { if (id == RR->identity) {
_amUpstream = true; _amUpstream = true;
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) == _upstreamAddresses.end()) { }
else if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), id.address()) == _upstreamAddresses.end()) {
_upstreamAddresses.push_back(id.address()); _upstreamAddresses.push_back(id.address());
SharedPtr<Peer> &hp = _peers[id.address()]; SharedPtr<Peer>& hp = _peers[id.address()];
if (!hp) { if (! hp) {
hp = new Peer(RR,RR->identity,id); hp = new Peer(RR, RR->identity, id);
} }
} }
} }
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) { for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { for (std::vector<World::Root>::const_iterator i(m->roots().begin()); i != m->roots().end(); ++i) {
if (i->identity == RR->identity) { if (i->identity == RR->identity) {
_amUpstream = true; _amUpstream = true;
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { }
else if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), i->identity.address()) == _upstreamAddresses.end()) {
_upstreamAddresses.push_back(i->identity.address()); _upstreamAddresses.push_back(i->identity.address());
SharedPtr<Peer> &hp = _peers[i->identity.address()]; SharedPtr<Peer>& hp = _peers[i->identity.address()];
if (!hp) { if (! hp) {
hp = new Peer(RR,RR->identity,i->identity); hp = new Peer(RR, RR->identity, i->identity);
} }
} }
} }
} }
std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); std::sort(_upstreamAddresses.begin(), _upstreamAddresses.end());
} }
void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer) void Topology::_savePeer(void* tPtr, const SharedPtr<Peer>& peer)
{ {
try { try {
Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf; Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf;
@ -428,8 +458,10 @@ void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer)
uint64_t tmpid[2]; uint64_t tmpid[2];
tmpid[0] = peer->address().toInt(); tmpid[0] = peer->address().toInt();
tmpid[1] = 0; tmpid[1] = 0;
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_PEER, tmpid, buf.data(), buf.size());
} catch ( ... ) {} // sanity check, discard invalid entries }
catch (...) {
} // sanity check, discard invalid entries
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,25 +14,23 @@
#ifndef ZT_TOPOLOGY_HPP #ifndef ZT_TOPOLOGY_HPP
#define ZT_TOPOLOGY_HPP #define ZT_TOPOLOGY_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "Path.hpp"
#include "Peer.hpp"
#include "World.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <utility> #include <utility>
#include <vector>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Identity.hpp"
#include "Peer.hpp"
#include "Path.hpp"
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Hashtable.hpp"
#include "World.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -41,10 +39,9 @@ class RuntimeEnvironment;
/** /**
* Database of network topology * Database of network topology
*/ */
class Topology class Topology {
{ public:
public: Topology(const RuntimeEnvironment* renv, void* tPtr);
Topology(const RuntimeEnvironment *renv,void *tPtr);
~Topology(); ~Topology();
/** /**
@ -57,7 +54,7 @@ public:
* @param peer Peer to add * @param peer Peer to add
* @return New or existing peer (should replace 'peer') * @return New or existing peer (should replace 'peer')
*/ */
SharedPtr<Peer> addPeer(void *tPtr,const SharedPtr<Peer> &peer); SharedPtr<Peer> addPeer(void* tPtr, const SharedPtr<Peer>& peer);
/** /**
* Get a peer from its address * Get a peer from its address
@ -66,14 +63,14 @@ public:
* @param zta ZeroTier address of peer * @param zta ZeroTier address of peer
* @return Peer or NULL if not found * @return Peer or NULL if not found
*/ */
SharedPtr<Peer> getPeer(void *tPtr,const Address &zta); SharedPtr<Peer> getPeer(void* tPtr, const Address& zta);
/** /**
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param zta ZeroTier address of peer * @param zta ZeroTier address of peer
* @return Identity or NULL identity if not found * @return Identity or NULL identity if not found
*/ */
Identity getIdentity(void *tPtr,const Address &zta); Identity getIdentity(void* tPtr, const Address& zta);
/** /**
* Get a peer only if it is presently in memory (no disk cache) * Get a peer only if it is presently in memory (no disk cache)
@ -85,10 +82,10 @@ public:
* *
* @param zta ZeroTier address * @param zta ZeroTier address
*/ */
inline SharedPtr<Peer> getPeerNoCache(const Address &zta) inline SharedPtr<Peer> getPeerNoCache(const Address& zta)
{ {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta); const SharedPtr<Peer>* const ap = _peers.get(zta);
if (ap) { if (ap) {
return *ap; return *ap;
} }
@ -102,12 +99,12 @@ public:
* @param r Remote address * @param r Remote address
* @return Pointer to canonicalized Path object * @return Pointer to canonicalized Path object
*/ */
inline SharedPtr<Path> getPath(const int64_t l,const InetAddress &r) inline SharedPtr<Path> getPath(const int64_t l, const InetAddress& r)
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
SharedPtr<Path> &p = _paths[Path::HashKey(l,r)]; SharedPtr<Path>& p = _paths[Path::HashKey(l, r)];
if (!p) { if (! p) {
p.set(new Path(l,r)); p.set(new Path(l, r));
} }
return p; return p;
} }
@ -123,19 +120,19 @@ public:
* @param id Identity to check * @param id Identity to check
* @return True if this is a root server or a network preferred relay from one of our networks * @return True if this is a root server or a network preferred relay from one of our networks
*/ */
bool isUpstream(const Identity &id) const; bool isUpstream(const Identity& id) const;
/** /**
* @param addr Address to check * @param addr Address to check
* @return True if we should accept a world update from this address * @return True if we should accept a world update from this address
*/ */
bool shouldAcceptWorldUpdateFrom(const Address &addr) const; bool shouldAcceptWorldUpdateFrom(const Address& addr) const;
/** /**
* @param ztaddr ZeroTier address * @param ztaddr ZeroTier address
* @return Peer role for this device * @return Peer role for this device
*/ */
ZT_PeerRole role(const Address &ztaddr) const; ZT_PeerRole role(const Address& ztaddr) const;
/** /**
* Check for prohibited endpoints * Check for prohibited endpoints
@ -151,39 +148,39 @@ public:
* @param ipaddr IP address * @param ipaddr IP address
* @return True if this ZT/IP pair should not be allowed to be used * @return True if this ZT/IP pair should not be allowed to be used
*/ */
bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; bool isProhibitedEndpoint(const Address& ztaddr, const InetAddress& ipaddr) const;
/** /**
* Gets upstreams to contact and their stable endpoints (if known) * Gets upstreams to contact and their stable endpoints (if known)
* *
* @param eps Hash table to fill with addresses and their stable endpoints * @param eps Hash table to fill with addresses and their stable endpoints
*/ */
inline void getUpstreamsToContact(Hashtable< Address,std::vector<InetAddress> > &eps) const inline void getUpstreamsToContact(Hashtable<Address, std::vector<InetAddress> >& eps) const
{ {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { for (std::vector<World::Root>::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) {
if (i->identity != RR->identity) { if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()]; std::vector<InetAddress>& ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { for (std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin()); j != i->stableEndpoints.end(); ++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end()) { if (std::find(ips.begin(), ips.end(), *j) == ips.end()) {
ips.push_back(*j); ips.push_back(*j);
} }
} }
} }
} }
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) { for (std::vector<World>::const_iterator m(_moons.begin()); m != _moons.end(); ++m) {
for(std::vector<World::Root>::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { for (std::vector<World::Root>::const_iterator i(m->roots().begin()); i != m->roots().end(); ++i) {
if (i->identity != RR->identity) { if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()]; std::vector<InetAddress>& ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { for (std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin()); j != i->stableEndpoints.end(); ++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end()) { if (std::find(ips.begin(), ips.end(), *j) == ips.end()) {
ips.push_back(*j); ips.push_back(*j);
} }
} }
} }
} }
} }
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { for (std::vector<std::pair<uint64_t, Address> >::const_iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) {
eps[m->second]; eps[m->second];
} }
} }
@ -213,8 +210,8 @@ public:
{ {
Mutex::Lock _l(_upstreams_m); Mutex::Lock _l(_upstreams_m);
std::vector<uint64_t> mw; std::vector<uint64_t> mw;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { for (std::vector<std::pair<uint64_t, Address> >::const_iterator s(_moonSeeds.begin()); s != _moonSeeds.end(); ++s) {
if (std::find(mw.begin(),mw.end(),s->first) == mw.end()) { if (std::find(mw.begin(), mw.end(), s->first) == mw.end()) {
mw.push_back(s->first); mw.push_back(s->first);
} }
} }
@ -254,7 +251,7 @@ public:
* @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one * @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one
* @return True if it was valid and newer than current (or totally new for moons) * @return True if it was valid and newer than current (or totally new for moons)
*/ */
bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew); bool addWorld(void* tPtr, const World& newWorld, bool alwaysAcceptNew);
/** /**
* Add a moon * Add a moon
@ -265,7 +262,7 @@ public:
* @param id Moon ID * @param id Moon ID
* @param seed If non-NULL, an address of any member of the moon to contact * @param seed If non-NULL, an address of any member of the moon to contact
*/ */
void addMoon(void *tPtr,const uint64_t id,const Address &seed); void addMoon(void* tPtr, const uint64_t id, const Address& seed);
/** /**
* Remove a moon * Remove a moon
@ -273,12 +270,12 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param id Moon's world ID * @param id Moon's world ID
*/ */
void removeMoon(void *tPtr,const uint64_t id); void removeMoon(void* tPtr, const uint64_t id);
/** /**
* Clean and flush database * Clean and flush database
*/ */
void doPeriodicTasks(void *tPtr,int64_t now); void doPeriodicTasks(void* tPtr, int64_t now);
/** /**
* @param now Current time * @param now Current time
@ -288,11 +285,11 @@ public:
{ {
unsigned long cnt = 0; unsigned long cnt = 0;
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers); Hashtable<Address, SharedPtr<Peer> >::Iterator i(const_cast<Topology*>(this)->_peers);
Address *a = (Address *)0; Address* a = (Address*)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0; SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a,p)) { while (i.next(a, p)) {
const SharedPtr<Path> pp((*p)->getAppropriatePath(now,false)); const SharedPtr<Path> pp((*p)->getAppropriatePath(now, false));
if (pp) { if (pp) {
++cnt; ++cnt;
} }
@ -306,22 +303,21 @@ public:
* @param f Function to apply * @param f Function to apply
* @tparam F Function or function object type * @tparam F Function or function object type
*/ */
template<typename F> template <typename F> inline void eachPeer(F f)
inline void eachPeer(F f)
{ {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers); Hashtable<Address, SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0; Address* a = (Address*)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0; SharedPtr<Peer>* p = (SharedPtr<Peer>*)0;
while (i.next(a,p)) { while (i.next(a, p)) {
f(*this,*((const SharedPtr<Peer> *)p)); f(*this, *((const SharedPtr<Peer>*)p));
} }
} }
/** /**
* @return All currently active peers by address (unsorted) * @return All currently active peers by address (unsorted)
*/ */
inline std::vector< std::pair< Address,SharedPtr<Peer> > > allPeers() const inline std::vector<std::pair<Address, SharedPtr<Peer> > > allPeers() const
{ {
Mutex::Lock _l(_peers_m); Mutex::Lock _l(_peers_m);
return _peers.entries(); return _peers.entries();
@ -330,7 +326,10 @@ public:
/** /**
* @return True if I am a root server in a planet or moon * @return True if I am a root server in a planet or moon
*/ */
inline bool amUpstream() const { return _amUpstream; } inline bool amUpstream() const
{
return _amUpstream;
}
/** /**
* Get info about a path * Get info about a path
@ -341,9 +340,9 @@ public:
* @param mtu Variable set to MTU * @param mtu Variable set to MTU
* @param trustedPathId Variable set to trusted path ID * @param trustedPathId Variable set to trusted path ID
*/ */
inline void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId) inline void getOutboundPathInfo(const InetAddress& physicalAddress, unsigned int& mtu, uint64_t& trustedPathId)
{ {
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) { for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) { if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
trustedPathId = _physicalPathConfig[i].second.trustedPathId; trustedPathId = _physicalPathConfig[i].second.trustedPathId;
mtu = _physicalPathConfig[i].second.mtu; mtu = _physicalPathConfig[i].second.mtu;
@ -358,9 +357,9 @@ public:
* @param physicalAddress Physical endpoint address * @param physicalAddress Physical endpoint address
* @return MTU * @return MTU
*/ */
inline unsigned int getOutboundPathMtu(const InetAddress &physicalAddress) inline unsigned int getOutboundPathMtu(const InetAddress& physicalAddress)
{ {
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) { for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) { if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
return _physicalPathConfig[i].second.mtu; return _physicalPathConfig[i].second.mtu;
} }
@ -374,9 +373,9 @@ public:
* @param physicalAddress Physical address to which we are sending the packet * @param physicalAddress Physical address to which we are sending the packet
* @return Trusted path ID or 0 if none (0 is not a valid trusted path ID) * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
*/ */
inline uint64_t getOutboundPathTrust(const InetAddress &physicalAddress) inline uint64_t getOutboundPathTrust(const InetAddress& physicalAddress)
{ {
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) { for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) { if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
return _physicalPathConfig[i].second.trustedPathId; return _physicalPathConfig[i].second.trustedPathId;
} }
@ -390,10 +389,10 @@ public:
* @param physicalAddress Originating physical address * @param physicalAddress Originating physical address
* @param trustedPathId Trusted path ID from packet (from MAC field) * @param trustedPathId Trusted path ID from packet (from MAC field)
*/ */
inline bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId) inline bool shouldInboundPathBeTrusted(const InetAddress& physicalAddress, const uint64_t trustedPathId)
{ {
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) { for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId)&&(_physicalPathConfig[i].first.containsAddress(physicalAddress))) { if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId) && (_physicalPathConfig[i].first.containsAddress(physicalAddress))) {
return true; return true;
} }
} }
@ -403,13 +402,14 @@ public:
/** /**
* Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration) * Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
*/ */
inline void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig) inline void setPhysicalPathConfiguration(const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig)
{ {
if (!pathNetwork) { if (! pathNetwork) {
_numConfiguredPhysicalPaths = 0; _numConfiguredPhysicalPaths = 0;
} else { }
std::map<InetAddress,ZT_PhysicalPathConfiguration> cpaths; else {
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) { std::map<InetAddress, ZT_PhysicalPathConfiguration> cpaths;
for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) {
cpaths[_physicalPathConfig[i].first] = _physicalPathConfig[i].second; cpaths[_physicalPathConfig[i].first] = _physicalPathConfig[i].second;
} }
@ -418,19 +418,22 @@ public:
if (pc.mtu <= 0) { if (pc.mtu <= 0) {
pc.mtu = ZT_DEFAULT_PHYSMTU; pc.mtu = ZT_DEFAULT_PHYSMTU;
} else if (pc.mtu < ZT_MIN_PHYSMTU) { }
else if (pc.mtu < ZT_MIN_PHYSMTU) {
pc.mtu = ZT_MIN_PHYSMTU; pc.mtu = ZT_MIN_PHYSMTU;
} else if (pc.mtu > ZT_MAX_PHYSMTU) { }
else if (pc.mtu > ZT_MAX_PHYSMTU) {
pc.mtu = ZT_MAX_PHYSMTU; pc.mtu = ZT_MAX_PHYSMTU;
} }
cpaths[*(reinterpret_cast<const InetAddress *>(pathNetwork))] = pc; cpaths[*(reinterpret_cast<const InetAddress*>(pathNetwork))] = pc;
} else { }
cpaths.erase(*(reinterpret_cast<const InetAddress *>(pathNetwork))); else {
cpaths.erase(*(reinterpret_cast<const InetAddress*>(pathNetwork)));
} }
unsigned int cnt = 0; unsigned int cnt = 0;
for(std::map<InetAddress,ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cnt<ZT_MAX_CONFIGURABLE_PATHS));++i) { for (std::map<InetAddress, ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin()); ((i != cpaths.end()) && (cnt < ZT_MAX_CONFIGURABLE_PATHS)); ++i) {
_physicalPathConfig[cnt].first = i->first; _physicalPathConfig[cnt].first = i->first;
_physicalPathConfig[cnt].second = i->second; _physicalPathConfig[cnt].second = i->second;
++cnt; ++cnt;
@ -439,25 +442,25 @@ public:
} }
} }
private: private:
Identity _getIdentity(void *tPtr,const Address &zta); Identity _getIdentity(void* tPtr, const Address& zta);
void _memoizeUpstreams(void *tPtr); void _memoizeUpstreams(void* tPtr);
void _savePeer(void *tPtr,const SharedPtr<Peer> &peer); void _savePeer(void* tPtr, const SharedPtr<Peer>& peer);
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
std::pair<InetAddress,ZT_PhysicalPathConfiguration> _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS]; std::pair<InetAddress, ZT_PhysicalPathConfiguration> _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
volatile unsigned int _numConfiguredPhysicalPaths; volatile unsigned int _numConfiguredPhysicalPaths;
Hashtable< Address,SharedPtr<Peer> > _peers; Hashtable<Address, SharedPtr<Peer> > _peers;
Mutex _peers_m; Mutex _peers_m;
Hashtable< Path::HashKey,SharedPtr<Path> > _paths; Hashtable<Path::HashKey, SharedPtr<Path> > _paths;
Mutex _paths_m; Mutex _paths_m;
World _planet; World _planet;
std::vector<World> _moons; std::vector<World> _moons;
std::vector< std::pair<uint64_t,Address> > _moonSeeds; std::vector<std::pair<uint64_t, Address> > _moonSeeds;
std::vector<Address> _upstreamAddresses; std::vector<Address> _upstreamAddresses;
bool _amUpstream; bool _amUpstream;
Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc.

View file

@ -11,374 +11,411 @@
*/ */
/****/ /****/
//#define ZT_TRACE // #define ZT_TRACE
#include <stdio.h>
#include <stdarg.h>
#include "Trace.hpp" #include "Trace.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp" #include "../include/ZeroTierDebug.h"
#include "Node.hpp" #include "Capability.hpp"
#include "Utils.hpp"
#include "Dictionary.hpp"
#include "CertificateOfMembership.hpp" #include "CertificateOfMembership.hpp"
#include "CertificateOfOwnership.hpp" #include "CertificateOfOwnership.hpp"
#include "Tag.hpp" #include "Dictionary.hpp"
#include "Capability.hpp" #include "Node.hpp"
#include "Revocation.hpp" #include "Revocation.hpp"
#include "../include/ZeroTierDebug.h" #include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Tag.hpp"
#include "Utils.hpp"
#include <stdarg.h>
#include <stdio.h>
namespace ZeroTier { namespace ZeroTier {
#ifdef ZT_TRACE #ifdef ZT_TRACE
static void ZT_LOCAL_TRACE(void *const tPtr,const RuntimeEnvironment *const RR,const char *const fmt,...) static void ZT_LOCAL_TRACE(void* const tPtr, const RuntimeEnvironment* const RR, const char* const fmt, ...)
{ {
char traceMsgBuf[1024]; char traceMsgBuf[1024];
va_list ap; va_list ap;
va_start(ap,fmt); va_start(ap, fmt);
vsnprintf(traceMsgBuf,sizeof(traceMsgBuf),fmt,ap); vsnprintf(traceMsgBuf, sizeof(traceMsgBuf), fmt, ap);
va_end(ap); va_end(ap);
traceMsgBuf[sizeof(traceMsgBuf) - 1] = (char)0; traceMsgBuf[sizeof(traceMsgBuf) - 1] = (char)0;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,traceMsgBuf); RR->node->postEvent(tPtr, ZT_EVENT_TRACE, traceMsgBuf);
} }
#else #else
#define ZT_LOCAL_TRACE(...) #define ZT_LOCAL_TRACE(...)
#endif #endif
void Trace::resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) void Trace::resettingPathsInScope(void* const tPtr, const Address& reporter, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, const InetAddress::IpScope scope)
{ {
char tmp[128]; char tmp[128];
ZT_LOCAL_TRACE(tPtr,RR,"RESET and revalidate paths in scope %d; new phy address %s reported by trusted peer %.10llx",(int)scope,myPhysicalAddress.toIpString(tmp),reporter.toInt()); ZT_LOCAL_TRACE(tPtr, RR, "RESET and revalidate paths in scope %d; new phy address %s reported by trusted peer %.10llx", (int)scope, myPhysicalAddress.toIpString(tmp), reporter.toInt());
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S);
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,reporter); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, reporter);
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,reporterPhysicalAddress.toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, reporterPhysicalAddress.toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR,myPhysicalAddress.toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR, myPhysicalAddress.toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE,(uint64_t)scope); d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE, (uint64_t)scope);
if (_globalTarget) { if (_globalTarget) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
_spamToAllNetworks(tPtr,d,Trace::LEVEL_NORMAL); _spamToAllNetworks(tPtr, d, Trace::LEVEL_NORMAL);
} }
void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb) void Trace::peerConfirmingUnknownPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& path, const uint64_t packetId, const Packet::Verb verb)
{ {
char tmp[128]; char tmp[128];
if (!path) { if (! path) {
return; // sanity check return; // sanity check
} }
ZT_LOCAL_TRACE(tPtr,RR,"trying unknown path %s to %.10llx (packet %.16llx verb %d local socket %lld network %.16llx)",path->address().toString(tmp),peer.address().toInt(),packetId,verb,path->localSocket(),networkId); ZT_LOCAL_TRACE(tPtr, RR, "trying unknown path %s to %.10llx (packet %.16llx verb %d local socket %lld network %.16llx)", path->address().toString(tmp), peer.address().toInt(), packetId, verb, path->localSocket(), networkId);
std::pair<Address,Trace::Level> byn; std::pair<Address, Trace::Level> byn;
if (networkId) { if (networkId) {
Mutex::Lock l(_byNet_m); Mutex::Lock l(_byNet_m);
_byNet.get(networkId,byn); _byNet.get(networkId, byn);
} }
if ((_globalTarget)||(byn.first)) { if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb);
if (networkId) {
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId);
}
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address());
if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
}
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::bondStateMessage(void *const tPtr,char *msg)
{
ZT_LOCAL_TRACE(tPtr,RR,"%s",msg);
}
void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath,const uint64_t packetId)
{
char tmp[128];
if (!newPath) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr,RR,"learned new path %s to %.10llx (packet %.16llx local socket %lld network %.16llx)",newPath->address().toString(tmp),peer.address().toInt(),packetId,newPath->localSocket(),networkId);
std::pair<Address,Trace::Level> byn;
if (networkId) {
Mutex::Lock l(_byNet_m);
_byNet.get(networkId,byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
if (networkId) { if (networkId) {
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId);
} }
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, peer.address());
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket());
}
if (_globalTarget) { if (_globalTarget) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
if (byn.first) { if (byn.first) {
_send(tPtr,d,byn.first); _send(tPtr, d, byn.first);
} }
} }
} }
void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath) void Trace::bondStateMessage(void* const tPtr, char* msg)
{
ZT_LOCAL_TRACE(tPtr, RR, "%s", msg);
}
void Trace::peerLearnedNewPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& newPath, const uint64_t packetId)
{ {
char tmp[128]; char tmp[128];
if (!newPath) { if (! newPath) {
return; // sanity check return; // sanity check
} }
ZT_LOCAL_TRACE(tPtr,RR,"explicit redirect from %.10llx to path %s",peer.address().toInt(),newPath->address().toString(tmp)); ZT_LOCAL_TRACE(tPtr, RR, "learned new path %s to %.10llx (packet %.16llx local socket %lld network %.16llx)", newPath->address().toString(tmp), peer.address().toInt(), packetId, newPath->localSocket(), networkId);
std::pair<Address,Trace::Level> byn; std::pair<Address, Trace::Level> byn;
if (networkId) { if (networkId) {
Mutex::Lock l(_byNet_m); Mutex::Lock l(_byNet_m);
_byNet.get(networkId,byn); _byNet.get(networkId, byn);
} }
if ((_globalTarget)||(byn.first)) { if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId);
if (networkId) { if (networkId) {
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId);
} }
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, peer.address());
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, newPath->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, newPath->localSocket());
if (_globalTarget) { if (_globalTarget) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
if (byn.first) { if (byn.first) {
_send(tPtr,d,byn.first); _send(tPtr, d, byn.first);
} }
} }
} }
void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) void Trace::peerRedirected(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& newPath)
{
char tmp[128];
if (! newPath) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr, RR, "explicit redirect from %.10llx to path %s", peer.address().toInt(), newPath->address().toString(tmp));
std::pair<Address, Trace::Level> byn;
if (networkId) {
Mutex::Lock l(_byNet_m);
_byNet.get(networkId, byn);
}
if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S);
if (networkId) {
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId);
}
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, peer.address());
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, newPath->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, newPath->localSocket());
if (_globalTarget) {
_send(tPtr, d, _globalTarget);
}
if (byn.first) {
_send(tPtr, d, byn.first);
}
}
}
void Trace::outgoingNetworkFrameDropped(void* const tPtr, const SharedPtr<Network>& network, const MAC& sourceMac, const MAC& destMac, const unsigned int etherType, const unsigned int vlanId, const unsigned int frameLen, const char* reason)
{ {
#ifdef ZT_TRACE #ifdef ZT_TRACE
char tmp[128],tmp2[128]; char tmp[128], tmp2[128];
#endif #endif
if (!network) { if (! network) {
return; // sanity check return; // sanity check
} }
ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROP frame %s -> %s etherType %.4x size %u (%s)",network->id(),sourceMac.toString(tmp),destMac.toString(tmp2),etherType,frameLen,(reason) ? reason : "unknown reason"); ZT_LOCAL_TRACE(tPtr, RR, "%.16llx DROP frame %s -> %s etherType %.4x size %u (%s)", network->id(), sourceMac.toString(tmp), destMac.toString(tmp2), etherType, frameLen, (reason) ? reason : "unknown reason");
std::pair<Address,Trace::Level> byn; std::pair<Address, Trace::Level> byn;
{ Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } {
Mutex::Lock l(_byNet_m);
_byNet.get(network->id(), byn);
}
if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) { if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE))) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network->id());
d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC, sourceMac.toInt());
d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC, destMac.toInt());
d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE, (uint64_t)etherType);
d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID, (uint64_t)vlanId);
d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH, (uint64_t)frameLen);
if (reason) { if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
} }
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,byn.first); _send(tPtr, d, byn.first);
} }
} }
} }
void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) void Trace::incomingNetworkAccessDenied(
void* const tPtr,
const SharedPtr<Network>& network,
const SharedPtr<Path>& path,
const uint64_t packetId,
const unsigned int packetLength,
const Address& source,
const Packet::Verb verb,
bool credentialsRequested)
{ {
char tmp[128]; char tmp[128];
if (!network) { if (! network) {
return; // sanity check return; // sanity check
} }
ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DENIED packet from %.10llx(%s) verb %d size %u%s",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength,credentialsRequested ? " (credentials requested)" : " (credentials not requested)"); ZT_LOCAL_TRACE(
tPtr,
RR,
"%.16llx DENIED packet from %.10llx(%s) verb %d size %u%s",
network->id(),
source.toInt(),
(path) ? (path->address().toString(tmp)) : "???",
(int)verb,
packetLength,
credentialsRequested ? " (credentials requested)" : " (credentials not requested)");
std::pair<Address,Trace::Level> byn; std::pair<Address, Trace::Level> byn;
{ Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } {
Mutex::Lock l(_byNet_m);
_byNet.get(network->id(), byn);
}
if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) { if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE))) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb);
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source);
if (path) { if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket());
} }
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network->id());
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,byn.first); _send(tPtr, d, byn.first);
} }
} }
} }
void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason) void Trace::incomingNetworkFrameDropped(
void* const tPtr,
const SharedPtr<Network>& network,
const SharedPtr<Path>& path,
const uint64_t packetId,
const unsigned int packetLength,
const Address& source,
const Packet::Verb verb,
const MAC& sourceMac,
const MAC& destMac,
const char* reason)
{ {
char tmp[128]; char tmp[128];
if (!network) { if (! network) {
return; // sanity check return; // sanity check
} }
ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROPPED frame from %.10llx(%s) verb %d size %u",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength); ZT_LOCAL_TRACE(tPtr, RR, "%.16llx DROPPED frame from %.10llx(%s) verb %d size %u", network->id(), source.toInt(), (path) ? (path->address().toString(tmp)) : "???", (int)verb, packetLength);
std::pair<Address,Trace::Level> byn; std::pair<Address, Trace::Level> byn;
{ Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } {
Mutex::Lock l(_byNet_m);
_byNet.get(network->id(), byn);
}
if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) { if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE))) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb);
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source);
if (path) { if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket());
} }
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network->id());
d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC, sourceMac.toInt());
d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC, destMac.toInt());
if (reason) { if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
} }
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,byn.first); _send(tPtr, d, byn.first);
} }
} }
} }
void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason) void Trace::incomingPacketMessageAuthenticationFailure(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const unsigned int hops, const char* reason)
{ {
char tmp[128]; char tmp[128];
ZT_LOCAL_TRACE(tPtr,RR,"MAC failed for packet %.16llx from %.10llx(%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???"); ZT_LOCAL_TRACE(tPtr, RR, "MAC failed for packet %.16llx from %.10llx(%s)", packetId, source.toInt(), (path) ? path->address().toString(tmp) : "???");
if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS, (uint64_t)hops);
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source);
if (path) { if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket());
} }
if (reason) { if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
} }
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
} }
void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason) void Trace::incomingPacketInvalid(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const unsigned int hops, const Packet::Verb verb, const char* reason)
{ {
char tmp[128]; char tmp[128];
ZT_LOCAL_TRACE(tPtr,RR,"INVALID packet %.16llx from %.10llx(%s) (%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "unknown reason"); ZT_LOCAL_TRACE(tPtr, RR, "INVALID packet %.16llx from %.10llx(%s) (%s)", packetId, source.toInt(), (path) ? path->address().toString(tmp) : "???", (reason) ? reason : "unknown reason");
if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb);
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source);
if (path) { if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket());
} }
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS, (uint64_t)hops);
if (reason) { if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
} }
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
} }
void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const char *reason) void Trace::incomingPacketDroppedHELLO(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const char* reason)
{ {
char tmp[128]; char tmp[128];
ZT_LOCAL_TRACE(tPtr,RR,"DROPPED HELLO from %.10llx(%s) (%s)",source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "???"); ZT_LOCAL_TRACE(tPtr, RR, "DROPPED HELLO from %.10llx(%s) (%s)", source.toInt(), (path) ? path->address().toString(tmp) : "???", (reason) ? reason : "???");
if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId);
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source);
if (path) { if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket());
} }
if (reason) { if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
} }
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
} }
void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller) void Trace::networkConfigRequestSent(void* const tPtr, const Network& network, const Address& controller)
{ {
ZT_LOCAL_TRACE(tPtr,RR,"requesting configuration for network %.16llx",network.id()); ZT_LOCAL_TRACE(tPtr, RR, "requesting configuration for network %.16llx", network.id());
if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network.id());
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID,controller); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID, controller);
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
} }
void Trace::networkFilter( void Trace::networkFilter(
void *const tPtr, void* const tPtr,
const Network &network, const Network& network,
const RuleResultLog &primaryRuleSetLog, const RuleResultLog& primaryRuleSetLog,
const RuleResultLog *const matchingCapabilityRuleSetLog, const RuleResultLog* const matchingCapabilityRuleSetLog,
const Capability *const matchingCapability, const Capability* const matchingCapability,
const Address &ztSource, const Address& ztSource,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *const frameData, const uint8_t* const frameData,
const unsigned int frameLen, const unsigned int frameLen,
const unsigned int etherType, const unsigned int etherType,
const unsigned int vlanId, const unsigned int vlanId,
@ -386,184 +423,187 @@ void Trace::networkFilter(
const bool inbound, const bool inbound,
const int accept) const int accept)
{ {
std::pair<Address,Trace::Level> byn; std::pair<Address, Trace::Level> byn;
{ Mutex::Lock l(_byNet_m); _byNet.get(network.id(),byn); } {
Mutex::Lock l(_byNet_m);
_byNet.get(network.id(), byn);
}
if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES)) ) { if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_RULES)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_RULES))) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network.id());
d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR,ztSource); d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR, ztSource);
d.add(ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR,ztDest); d.add(ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR, ztDest);
d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,macSource.toInt()); d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC, macSource.toInt());
d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,macDest.toInt()); d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC, macDest.toInt());
d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE, (uint64_t)etherType);
d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID, (uint64_t)vlanId);
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE,noTee ? "1" : "0"); d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE, noTee ? "1" : "0");
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND,inbound ? "1" : "0"); d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND, inbound ? "1" : "0");
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT,(int64_t)accept); d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT, (int64_t)accept);
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG,(const char *)primaryRuleSetLog.data(),(int)primaryRuleSetLog.sizeBytes()); d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG, (const char*)primaryRuleSetLog.data(), (int)primaryRuleSetLog.sizeBytes());
if (matchingCapabilityRuleSetLog) { if (matchingCapabilityRuleSetLog) {
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG,(const char *)matchingCapabilityRuleSetLog->data(),(int)matchingCapabilityRuleSetLog->sizeBytes()); d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG, (const char*)matchingCapabilityRuleSetLog->data(), (int)matchingCapabilityRuleSetLog->sizeBytes());
} }
if (matchingCapability) { if (matchingCapability) {
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID,(uint64_t)matchingCapability->id()); d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID, (uint64_t)matchingCapability->id());
} }
d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH, (uint64_t)frameLen);
if (frameLen > 0) { if (frameLen > 0) {
d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen); d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA, (const char*)frameData, (frameLen > 256) ? (int)256 : (int)frameLen);
} }
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES)) { if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_RULES)) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES)) { if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_RULES)) {
_send(tPtr,d,byn.first); _send(tPtr, d, byn.first);
} }
} }
} }
void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) void Trace::credentialRejected(void* const tPtr, const CertificateOfMembership& c, const char* reason)
{ {
std::pair<Address,Trace::Level> byn; std::pair<Address, Trace::Level> byn;
if (c.networkId()) { if (c.networkId()) {
Mutex::Lock l(_byNet_m); Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn); _byNet.get(c.networkId(), byn);
} }
if ((_globalTarget)||(byn.first)) { if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d; Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target());
if (reason) { if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
} }
if (_globalTarget) { if (_globalTarget) {
_send(tPtr,d,_globalTarget); _send(tPtr, d, _globalTarget);
} }
if (byn.first) { if (byn.first) {
_send(tPtr,d,byn.first); _send(tPtr, d, byn.first);
}
}
}
void Trace::credentialRejected(void* const tPtr, const CertificateOfOwnership& c, const char* reason)
{
std::pair<Address, Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(), byn);
}
if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
}
if (_globalTarget) {
_send(tPtr, d, _globalTarget);
}
if (byn.first) {
_send(tPtr, d, byn.first);
}
}
}
void Trace::credentialRejected(void* const tPtr, const Capability& c, const char* reason)
{
std::pair<Address, Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(), byn);
}
if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
}
if (_globalTarget) {
_send(tPtr, d, _globalTarget);
}
if (byn.first) {
_send(tPtr, d, byn.first);
}
}
}
void Trace::credentialRejected(void* const tPtr, const Tag& c, const char* reason)
{
std::pair<Address, Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(), byn);
}
if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO, (uint64_t)c.value());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
}
if (_globalTarget) {
_send(tPtr, d, _globalTarget);
}
if (byn.first) {
_send(tPtr, d, byn.first);
}
}
}
void Trace::credentialRejected(void* const tPtr, const Revocation& c, const char* reason)
{
std::pair<Address, Trace::Level> byn;
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(), byn);
}
if ((_globalTarget) || (byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S);
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET, c.target());
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
}
if (_globalTarget) {
_send(tPtr, d, _globalTarget);
}
if (byn.first) {
_send(tPtr, d, byn.first);
} }
} }
} }
@ -572,14 +612,14 @@ void Trace::updateMemoizedSettings()
{ {
_globalTarget = RR->node->remoteTraceTarget(); _globalTarget = RR->node->remoteTraceTarget();
_globalLevel = RR->node->remoteTraceLevel(); _globalLevel = RR->node->remoteTraceLevel();
const std::vector< SharedPtr<Network> > nws(RR->node->allNetworks()); const std::vector<SharedPtr<Network> > nws(RR->node->allNetworks());
{ {
Mutex::Lock l(_byNet_m); Mutex::Lock l(_byNet_m);
_byNet.clear(); _byNet.clear();
for(std::vector< SharedPtr<Network> >::const_iterator n(nws.begin());n!=nws.end();++n) { for (std::vector<SharedPtr<Network> >::const_iterator n(nws.begin()); n != nws.end(); ++n) {
const Address dest((*n)->config().remoteTraceTarget); const Address dest((*n)->config().remoteTraceTarget);
if (dest) { if (dest) {
std::pair<Address,Trace::Level> &m = _byNet[(*n)->id()]; std::pair<Address, Trace::Level>& m = _byNet[(*n)->id()];
m.first = dest; m.first = dest;
m.second = (*n)->config().remoteTraceLevel; m.second = (*n)->config().remoteTraceLevel;
} }
@ -587,23 +627,23 @@ void Trace::updateMemoizedSettings()
} }
} }
void Trace::_send(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Address &dest) void Trace::_send(void* const tPtr, const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE>& d, const Address& dest)
{ {
Packet outp(dest,RR->identity.address(),Packet::VERB_REMOTE_TRACE); Packet outp(dest, RR->identity.address(), Packet::VERB_REMOTE_TRACE);
outp.appendCString(d.data()); outp.appendCString(d.data());
outp.compress(); outp.compress();
RR->sw->send(tPtr,outp,true); RR->sw->send(tPtr, outp, true);
} }
void Trace::_spamToAllNetworks(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Level level) void Trace::_spamToAllNetworks(void* const tPtr, const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE>& d, const Level level)
{ {
Mutex::Lock l(_byNet_m); Mutex::Lock l(_byNet_m);
Hashtable< uint64_t,std::pair< Address,Trace::Level > >::Iterator i(_byNet); Hashtable<uint64_t, std::pair<Address, Trace::Level> >::Iterator i(_byNet);
uint64_t *k = (uint64_t *)0; uint64_t* k = (uint64_t*)0;
std::pair<Address,Trace::Level> *v = (std::pair<Address,Trace::Level> *)0; std::pair<Address, Trace::Level>* v = (std::pair<Address, Trace::Level>*)0;
while (i.next(k,v)) { while (i.next(k, v)) {
if ((v)&&(v->first)&&((int)v->second >= (int)level)) { if ((v) && (v->first) && ((int)v->second >= (int)level)) {
_send(tPtr,d,v->first); _send(tPtr, d, v->first);
} }
} }
} }

View file

@ -14,21 +14,20 @@
#ifndef ZT_TRACE_HPP #ifndef ZT_TRACE_HPP
#define ZT_TRACE_HPP #define ZT_TRACE_HPP
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "../include/ZeroTierOne.h" #include "../include/ZeroTierOne.h"
#include "Constants.hpp" #include "Constants.hpp"
#include "SharedPtr.hpp"
#include "Packet.hpp"
#include "Credential.hpp" #include "Credential.hpp"
#include "InetAddress.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "Mutex.hpp"
#include "Hashtable.hpp" #include "Hashtable.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
namespace ZeroTier { namespace ZeroTier {
@ -49,20 +48,12 @@ class Capability;
/** /**
* Remote tracing and trace logging handler * Remote tracing and trace logging handler
*/ */
class Trace class Trace {
{ public:
public:
/** /**
* Trace verbosity level * Trace verbosity level
*/ */
enum Level enum Level { LEVEL_NORMAL = 0, LEVEL_VERBOSE = 10, LEVEL_RULES = 15, LEVEL_DEBUG = 20, LEVEL_INSANE = 30 };
{
LEVEL_NORMAL = 0,
LEVEL_VERBOSE = 10,
LEVEL_RULES = 15,
LEVEL_DEBUG = 20,
LEVEL_INSANE = 30
};
/** /**
* Filter rule evaluation result log * Filter rule evaluation result log
@ -73,67 +64,90 @@ public:
* As with four-bit rules an 00 value here means this was not * As with four-bit rules an 00 value here means this was not
* evaluated or was not relevant. * evaluated or was not relevant.
*/ */
class RuleResultLog class RuleResultLog {
{
public: public:
RuleResultLog() {} RuleResultLog()
inline void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches)
{ {
_l[rn >> 1] |= ( ((thisRuleMatches + 1) << 2) | (thisSetMatches + 1) ) << ((rn & 1) << 2);
} }
inline void logSkipped(const unsigned int rn,const uint8_t thisSetMatches)
inline void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches)
{
_l[rn >> 1] |= (((thisRuleMatches + 1) << 2) | (thisSetMatches + 1)) << ((rn & 1) << 2);
}
inline void logSkipped(const unsigned int rn, const uint8_t thisSetMatches)
{ {
_l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2); _l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2);
} }
inline void clear() inline void clear()
{ {
memset(_l,0,sizeof(_l)); memset(_l, 0, sizeof(_l));
} }
inline const uint8_t *data() const { return _l; } inline const uint8_t* data() const
inline unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); } {
return _l;
}
inline unsigned int sizeBytes() const
{
return (ZT_MAX_NETWORK_RULES / 2);
}
private: private:
uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; uint8_t _l[ZT_MAX_NETWORK_RULES / 2];
}; };
Trace(const RuntimeEnvironment *renv) : Trace(const RuntimeEnvironment* renv) : RR(renv), _byNet(8)
RR(renv),
_byNet(8)
{ {
} }
void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); void resettingPathsInScope(void* const tPtr, const Address& reporter, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, const InetAddress::IpScope scope);
void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb); void peerConfirmingUnknownPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& path, const uint64_t packetId, const Packet::Verb verb);
void bondStateMessage(void *const tPtr,char *msg); void bondStateMessage(void* const tPtr, char* msg);
void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath,const uint64_t packetId); void peerLearnedNewPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& newPath, const uint64_t packetId);
void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath); void peerRedirected(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr<Path>& newPath);
void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); void incomingPacketMessageAuthenticationFailure(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const unsigned int hops, const char* reason);
void incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); void incomingPacketInvalid(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const unsigned int hops, const Packet::Verb verb, const char* reason);
void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const char *reason); void incomingPacketDroppedHELLO(void* const tPtr, const SharedPtr<Path>& path, const uint64_t packetId, const Address& source, const char* reason);
void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); void outgoingNetworkFrameDropped(void* const tPtr, const SharedPtr<Network>& network, const MAC& sourceMac, const MAC& destMac, const unsigned int etherType, const unsigned int vlanId, const unsigned int frameLen, const char* reason);
void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); void incomingNetworkAccessDenied(
void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason); void* const tPtr,
const SharedPtr<Network>& network,
const SharedPtr<Path>& path,
const uint64_t packetId,
const unsigned int packetLength,
const Address& source,
const Packet::Verb verb,
bool credentialsRequested);
void incomingNetworkFrameDropped(
void* const tPtr,
const SharedPtr<Network>& network,
const SharedPtr<Path>& path,
const uint64_t packetId,
const unsigned int packetLength,
const Address& source,
const Packet::Verb verb,
const MAC& sourceMac,
const MAC& destMac,
const char* reason);
void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller); void networkConfigRequestSent(void* const tPtr, const Network& network, const Address& controller);
void networkFilter( void networkFilter(
void *const tPtr, void* const tPtr,
const Network &network, const Network& network,
const RuleResultLog &primaryRuleSetLog, const RuleResultLog& primaryRuleSetLog,
const RuleResultLog *const matchingCapabilityRuleSetLog, const RuleResultLog* const matchingCapabilityRuleSetLog,
const Capability *const matchingCapability, const Capability* const matchingCapability,
const Address &ztSource, const Address& ztSource,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *const frameData, const uint8_t* const frameData,
const unsigned int frameLen, const unsigned int frameLen,
const unsigned int etherType, const unsigned int etherType,
const unsigned int vlanId, const unsigned int vlanId,
@ -141,23 +155,23 @@ public:
const bool inbound, const bool inbound,
const int accept); const int accept);
void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason); void credentialRejected(void* const tPtr, const CertificateOfMembership& c, const char* reason);
void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason); void credentialRejected(void* const tPtr, const CertificateOfOwnership& c, const char* reason);
void credentialRejected(void *const tPtr,const Capability &c,const char *reason); void credentialRejected(void* const tPtr, const Capability& c, const char* reason);
void credentialRejected(void *const tPtr,const Tag &c,const char *reason); void credentialRejected(void* const tPtr, const Tag& c, const char* reason);
void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); void credentialRejected(void* const tPtr, const Revocation& c, const char* reason);
void updateMemoizedSettings(); void updateMemoizedSettings();
private: private:
const RuntimeEnvironment *const RR; const RuntimeEnvironment* const RR;
void _send(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Address &dest); void _send(void* const tPtr, const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE>& d, const Address& dest);
void _spamToAllNetworks(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> &d,const Level level); void _spamToAllNetworks(void* const tPtr, const Dictionary<ZT_MAX_REMOTE_TRACE_SIZE>& d, const Level level);
Address _globalTarget; Address _globalTarget;
Trace::Level _globalLevel; Trace::Level _globalLevel;
Hashtable< uint64_t,std::pair< Address,Trace::Level > > _byNet; Hashtable<uint64_t, std::pair<Address, Trace::Level> > _byNet;
Mutex _byNet_m; Mutex _byNet_m;
}; };

View file

@ -11,23 +11,23 @@
*/ */
/****/ /****/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <sys/stat.h>
#include "Constants.hpp" #include "Constants.hpp"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#include <unistd.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <dirent.h> #include <unistd.h>
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
#ifdef __LINUX__ #ifdef __LINUX__
#include <sys/auxv.h> #include <sys/auxv.h>
@ -36,13 +36,13 @@
#endif #endif
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <wincrypt.h>
#include <intrin.h> #include <intrin.h>
#include <wincrypt.h>
#endif #endif
#include "Utils.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "Utils.hpp"
#ifdef __APPLE__ #ifdef __APPLE__
#include <TargetConditionals.h> #include <TargetConditionals.h>
@ -55,8 +55,8 @@
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
#ifdef __LINUX__ #ifdef __LINUX__
#include <sys/auxv.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include <sys/auxv.h>
#endif #endif
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
@ -91,9 +91,9 @@ static inline long getauxval(int caps)
namespace ZeroTier { namespace ZeroTier {
const uint64_t Utils::ZERO256[4] = {0ULL,0ULL,0ULL,0ULL}; const uint64_t Utils::ZERO256[4] = { 0ULL, 0ULL, 0ULL, 0ULL };
const char Utils::HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; const char Utils::HEXCHARS[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
Utils::ARMCapabilities::ARMCapabilities() noexcept Utils::ARMCapabilities::ARMCapabilities() noexcept
@ -109,14 +109,15 @@ Utils::ARMCapabilities::ARMCapabilities() noexcept
#else #else
#ifdef HWCAP2_AES #ifdef HWCAP2_AES
if (sizeof(void *) == 4) { if (sizeof(void*) == 4) {
const long hwcaps2 = getauxval(AT_HWCAP2); const long hwcaps2 = getauxval(AT_HWCAP2);
this->aes = (hwcaps2 & HWCAP2_AES) != 0; this->aes = (hwcaps2 & HWCAP2_AES) != 0;
this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0; this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0;
this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0; this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0;
this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0; this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0;
this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0; this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0;
} else { }
else {
#endif #endif
const long hwcaps = getauxval(AT_HWCAP); const long hwcaps = getauxval(AT_HWCAP);
this->aes = (hwcaps & HWCAP_AES) != 0; this->aes = (hwcaps & HWCAP_AES) != 0;
@ -142,17 +143,13 @@ Utils::CPUIDRegisters::CPUIDRegisters() noexcept
#ifdef __WINDOWS__ #ifdef __WINDOWS__
int regs[4]; int regs[4];
__cpuid(regs,1); __cpuid(regs, 1);
eax = (uint32_t)regs[0]; eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1]; ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2]; ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3]; edx = (uint32_t)regs[3];
#else #else
__asm__ __volatile__ ( __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1), "c"(0));
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(1), "c"(0)
);
#endif #endif
rdrand = ((ecx & (1U << 30U)) != 0); rdrand = ((ecx & (1U << 30U)) != 0);
@ -160,17 +157,13 @@ Utils::CPUIDRegisters::CPUIDRegisters() noexcept
avx = ((ecx & (1U << 25U)) != 0); avx = ((ecx & (1U << 25U)) != 0);
#ifdef __WINDOWS__ #ifdef __WINDOWS__
__cpuid(regs,7); __cpuid(regs, 7);
eax = (uint32_t)regs[0]; eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1]; ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2]; ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3]; edx = (uint32_t)regs[3];
#else #else
__asm__ __volatile__ ( __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0));
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(7), "c"(0)
);
#endif #endif
vaes = aes && avx && ((ecx & (1U << 9U)) != 0); vaes = aes && avx && ((ecx & (1U << 9U)) != 0);
@ -185,40 +178,43 @@ const Utils::CPUIDRegisters Utils::CPUID;
#endif #endif
// Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers. // Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers.
static void _Utils_doBurn(volatile uint8_t *ptr,unsigned int len) static void _Utils_doBurn(volatile uint8_t* ptr, unsigned int len)
{ {
volatile uint8_t *const end = ptr + len; volatile uint8_t* const end = ptr + len;
while (ptr != end) { while (ptr != end) {
*(ptr++) = (uint8_t)0; *(ptr++) = (uint8_t)0;
} }
} }
static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t *,unsigned int) = _Utils_doBurn; static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t*, unsigned int) = _Utils_doBurn;
void Utils::burn(void *ptr,unsigned int len) { (_Utils_doBurn_ptr)((volatile uint8_t *)ptr,len); } void Utils::burn(void* ptr, unsigned int len)
{
(_Utils_doBurn_ptr)((volatile uint8_t*)ptr, len);
}
static unsigned long _Utils_itoa(unsigned long n,char *s) static unsigned long _Utils_itoa(unsigned long n, char* s)
{ {
if (n == 0) { if (n == 0) {
return 0; return 0;
} }
unsigned long pos = _Utils_itoa(n / 10,s); unsigned long pos = _Utils_itoa(n / 10, s);
if (pos >= 22) { // sanity check, should be impossible if (pos >= 22) { // sanity check, should be impossible
pos = 22; pos = 22;
} }
s[pos] = '0' + (char)(n % 10); s[pos] = '0' + (char)(n % 10);
return pos + 1; return pos + 1;
} }
char *Utils::decimal(unsigned long n,char s[24]) char* Utils::decimal(unsigned long n, char s[24])
{ {
if (n == 0) { if (n == 0) {
s[0] = '0'; s[0] = '0';
s[1] = (char)0; s[1] = (char)0;
return s; return s;
} }
s[_Utils_itoa(n,s)] = (char)0; s[_Utils_itoa(n, s)] = (char)0;
return s; return s;
} }
void Utils::getSecureRandom(void *buf,unsigned int bytes) void Utils::getSecureRandom(void* buf, unsigned int bytes)
{ {
static Mutex globalLock; static Mutex globalLock;
static Salsa20 s20; static Salsa20 s20;
@ -235,37 +231,37 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
* a bit of extra entropy and further randomizing the result, and comes * a bit of extra entropy and further randomizing the result, and comes
* at almost no cost and with no real downside if the random source is * at almost no cost and with no real downside if the random source is
* good. */ * good. */
if (!s20Initialized) { if (! s20Initialized) {
s20Initialized = true; s20Initialized = true;
uint64_t s20Key[4]; uint64_t s20Key[4];
s20Key[0] = (uint64_t)time(0); // system clock s20Key[0] = (uint64_t)time(0); // system clock
s20Key[1] = (uint64_t)buf; // address of buf s20Key[1] = (uint64_t)buf; // address of buf
s20Key[2] = (uint64_t)s20Key; // address of s20Key[] s20Key[2] = (uint64_t)s20Key; // address of s20Key[]
s20Key[3] = (uint64_t)&s20; // address of s20 s20Key[3] = (uint64_t)&s20; // address of s20
s20.init(s20Key,s20Key); s20.init(s20Key, s20Key);
} }
#ifdef __WINDOWS__ #ifdef __WINDOWS__
static HCRYPTPROV cryptProvider = NULL; static HCRYPTPROV cryptProvider = NULL;
for(unsigned int i=0;i<bytes;++i) { for (unsigned int i = 0; i < bytes; ++i) {
if (randomPtr >= sizeof(randomBuf)) { if (randomPtr >= sizeof(randomBuf)) {
if (cryptProvider == NULL) { if (cryptProvider == NULL) {
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { if (! CryptAcquireContextA(&cryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n"); fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
exit(1); exit(1);
} }
} }
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) { if (! CryptGenRandom(cryptProvider, (DWORD)sizeof(randomBuf), (BYTE*)randomBuf)) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
exit(1); exit(1);
} }
randomPtr = 0; randomPtr = 0;
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf));
s20.init(randomBuf,randomBuf); s20.init(randomBuf, randomBuf);
} }
((uint8_t *)buf)[i] = randomBuf[randomPtr++]; ((uint8_t*)buf)[i] = randomBuf[randomPtr++];
} }
#else // not __WINDOWS__ #else // not __WINDOWS__
@ -273,34 +269,35 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
static int devURandomFd = -1; static int devURandomFd = -1;
if (devURandomFd < 0) { if (devURandomFd < 0) {
devURandomFd = ::open("/dev/urandom",O_RDONLY); devURandomFd = ::open("/dev/urandom", O_RDONLY);
if (devURandomFd < 0) { if (devURandomFd < 0) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
exit(1); exit(1);
return; return;
} }
} }
for(unsigned int i=0;i<bytes;++i) { for (unsigned int i = 0; i < bytes; ++i) {
if (randomPtr >= sizeof(randomBuf)) { if (randomPtr >= sizeof(randomBuf)) {
for(;;) { for (;;) {
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) { if ((int)::read(devURandomFd, randomBuf, sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
::close(devURandomFd); ::close(devURandomFd);
devURandomFd = ::open("/dev/urandom",O_RDONLY); devURandomFd = ::open("/dev/urandom", O_RDONLY);
if (devURandomFd < 0) { if (devURandomFd < 0) {
fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
exit(1); exit(1);
return; return;
} }
} else { }
else {
break; break;
} }
} }
randomPtr = 0; randomPtr = 0;
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf));
s20.init(randomBuf,randomBuf); s20.init(randomBuf, randomBuf);
} }
((uint8_t *)buf)[i] = randomBuf[randomPtr++]; ((uint8_t*)buf)[i] = randomBuf[randomPtr++];
} }
#endif // __WINDOWS__ or not #endif // __WINDOWS__ or not

View file

@ -14,17 +14,16 @@
#ifndef ZT_UTILS_HPP #ifndef ZT_UTILS_HPP
#define ZT_UTILS_HPP #define ZT_UTILS_HPP
#include <algorithm>
#include <map>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <string> #include <string>
#include <stdexcept> #include <time.h>
#include <vector> #include <vector>
#include <map>
#include <algorithm>
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
#include <sys/endian.h> #include <sys/endian.h>
@ -34,15 +33,9 @@
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U))) #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
#define ZT_CONST_TO_BE_UINT64(x) ( \ #define ZT_CONST_TO_BE_UINT64(x) \
(((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | \ ((((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | (((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | (((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) \
(((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | \ | (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | (((uint64_t)(x) & 0xff00000000000000ULL) >> 56U))
(((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | \
(((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) | \
(((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | \
(((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | \
(((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | \
(((uint64_t)(x) & 0xff00000000000000ULL) >> 56U))
#else #else
#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x)) #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x))
#define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x)) #define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x))
@ -58,14 +51,12 @@ namespace ZeroTier {
/** /**
* Miscellaneous utility functions and global constants * Miscellaneous utility functions and global constants
*/ */
class Utils class Utils {
{ public:
public:
static const uint64_t ZERO256[4]; static const uint64_t ZERO256[4];
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
struct ARMCapabilities struct ARMCapabilities {
{
ARMCapabilities() noexcept; ARMCapabilities() noexcept;
bool aes; bool aes;
@ -78,8 +69,7 @@ public:
#endif #endif
#ifdef ZT_ARCH_X64 #ifdef ZT_ARCH_X64
struct CPUIDRegisters struct CPUIDRegisters {
{
CPUIDRegisters() noexcept; CPUIDRegisters() noexcept;
bool rdrand; bool rdrand;
@ -126,11 +116,11 @@ public:
* @param len Length of strings * @param len Length of strings
* @return True if strings are equal * @return True if strings are equal
*/ */
static inline bool secureEq(const void *a,const void *b,unsigned int len) static inline bool secureEq(const void* a, const void* b, unsigned int len)
{ {
uint8_t diff = 0; uint8_t diff = 0;
for(unsigned int i=0;i<len;++i) { for (unsigned int i = 0; i < len; ++i) {
diff |= ( (reinterpret_cast<const uint8_t *>(a))[i] ^ (reinterpret_cast<const uint8_t *>(b))[i] ); diff |= ((reinterpret_cast<const uint8_t*>(a))[i] ^ (reinterpret_cast<const uint8_t*>(b))[i]);
} }
return (diff == 0); return (diff == 0);
} }
@ -138,16 +128,16 @@ public:
/** /**
* Securely zero memory, avoiding compiler optimizations and such * Securely zero memory, avoiding compiler optimizations and such
*/ */
static void burn(void *ptr,unsigned int len); static void burn(void* ptr, unsigned int len);
/** /**
* @param n Number to convert * @param n Number to convert
* @param s Buffer, at least 24 bytes in size * @param s Buffer, at least 24 bytes in size
* @return String containing 'n' in base 10 form * @return String containing 'n' in base 10 form
*/ */
static char *decimal(unsigned long n,char s[24]); static char* decimal(unsigned long n, char s[24]);
static inline char *hex(uint64_t i,char s[17]) static inline char* hex(uint64_t i, char s[17])
{ {
s[0] = HEXCHARS[(i >> 60) & 0xf]; s[0] = HEXCHARS[(i >> 60) & 0xf];
s[1] = HEXCHARS[(i >> 56) & 0xf]; s[1] = HEXCHARS[(i >> 56) & 0xf];
@ -169,7 +159,7 @@ public:
return s; return s;
} }
static inline char *hex10(uint64_t i,char s[11]) static inline char* hex10(uint64_t i, char s[11])
{ {
s[0] = HEXCHARS[(i >> 36) & 0xf]; s[0] = HEXCHARS[(i >> 36) & 0xf];
s[1] = HEXCHARS[(i >> 32) & 0xf]; s[1] = HEXCHARS[(i >> 32) & 0xf];
@ -185,7 +175,7 @@ public:
return s; return s;
} }
static inline char *hex(uint32_t i,char s[9]) static inline char* hex(uint32_t i, char s[9])
{ {
s[0] = HEXCHARS[(i >> 28) & 0xf]; s[0] = HEXCHARS[(i >> 28) & 0xf];
s[1] = HEXCHARS[(i >> 24) & 0xf]; s[1] = HEXCHARS[(i >> 24) & 0xf];
@ -199,7 +189,7 @@ public:
return s; return s;
} }
static inline char *hex(uint16_t i,char s[5]) static inline char* hex(uint16_t i, char s[5])
{ {
s[0] = HEXCHARS[(i >> 12) & 0xf]; s[0] = HEXCHARS[(i >> 12) & 0xf];
s[1] = HEXCHARS[(i >> 8) & 0xf]; s[1] = HEXCHARS[(i >> 8) & 0xf];
@ -209,7 +199,7 @@ public:
return s; return s;
} }
static inline char *hex(uint8_t i,char s[3]) static inline char* hex(uint8_t i, char s[3])
{ {
s[0] = HEXCHARS[(i >> 4) & 0xf]; s[0] = HEXCHARS[(i >> 4) & 0xf];
s[1] = HEXCHARS[i & 0xf]; s[1] = HEXCHARS[i & 0xf];
@ -217,11 +207,11 @@ public:
return s; return s;
} }
static inline char *hex(const void *d,unsigned int l,char *s) static inline char* hex(const void* d, unsigned int l, char* s)
{ {
char *const save = s; char* const save = s;
for(unsigned int i=0;i<l;++i) { for (unsigned int i = 0; i < l; ++i) {
const unsigned int b = reinterpret_cast<const uint8_t *>(d)[i]; const unsigned int b = reinterpret_cast<const uint8_t*>(d)[i];
*(s++) = HEXCHARS[b >> 4]; *(s++) = HEXCHARS[b >> 4];
*(s++) = HEXCHARS[b & 0xf]; *(s++) = HEXCHARS[b & 0xf];
} }
@ -229,83 +219,91 @@ public:
return save; return save;
} }
static inline unsigned int unhex(const char *h,void *buf,unsigned int buflen) static inline unsigned int unhex(const char* h, void* buf, unsigned int buflen)
{ {
unsigned int l = 0; unsigned int l = 0;
while (l < buflen) { while (l < buflen) {
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++)); uint8_t hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
uint8_t c = 0; uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57)) { // 0..9 if ((hc >= 48) && (hc <= 57)) { // 0..9
c = hc - 48; c = hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { // a..f }
else if ((hc >= 97) && (hc <= 102)) { // a..f
c = hc - 87; c = hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { // A..F }
else if ((hc >= 65) && (hc <= 70)) { // A..F
c = hc - 55; c = hc - 55;
} }
hc = *(reinterpret_cast<const uint8_t *>(h++)); hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
c <<= 4; c <<= 4;
if ((hc >= 48)&&(hc <= 57)) { if ((hc >= 48) && (hc <= 57)) {
c |= hc - 48; c |= hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { }
else if ((hc >= 97) && (hc <= 102)) {
c |= hc - 87; c |= hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { }
else if ((hc >= 65) && (hc <= 70)) {
c |= hc - 55; c |= hc - 55;
} }
reinterpret_cast<uint8_t *>(buf)[l++] = c; reinterpret_cast<uint8_t*>(buf)[l++] = c;
} }
return l; return l;
} }
static inline unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen) static inline unsigned int unhex(const char* h, unsigned int hlen, void* buf, unsigned int buflen)
{ {
unsigned int l = 0; unsigned int l = 0;
const char *hend = h + hlen; const char* hend = h + hlen;
while (l < buflen) { while (l < buflen) {
if (h == hend) { if (h == hend) {
break; break;
} }
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++)); uint8_t hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
uint8_t c = 0; uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57)) { if ((hc >= 48) && (hc <= 57)) {
c = hc - 48; c = hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { }
else if ((hc >= 97) && (hc <= 102)) {
c = hc - 87; c = hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { }
else if ((hc >= 65) && (hc <= 70)) {
c = hc - 55; c = hc - 55;
} }
if (h == hend) { if (h == hend) {
break; break;
} }
hc = *(reinterpret_cast<const uint8_t *>(h++)); hc = *(reinterpret_cast<const uint8_t*>(h++));
if (!hc) { if (! hc) {
break; break;
} }
c <<= 4; c <<= 4;
if ((hc >= 48)&&(hc <= 57)) { if ((hc >= 48) && (hc <= 57)) {
c |= hc - 48; c |= hc - 48;
} else if ((hc >= 97)&&(hc <= 102)) { }
else if ((hc >= 97) && (hc <= 102)) {
c |= hc - 87; c |= hc - 87;
} else if ((hc >= 65)&&(hc <= 70)) { }
else if ((hc >= 65) && (hc <= 70)) {
c |= hc - 55; c |= hc - 55;
} }
reinterpret_cast<uint8_t *>(buf)[l++] = c; reinterpret_cast<uint8_t*>(buf)[l++] = c;
} }
return l; return l;
} }
@ -327,7 +325,7 @@ public:
* @param buf Buffer to fill * @param buf Buffer to fill
* @param bytes Number of random bytes to generate * @param bytes Number of random bytes to generate
*/ */
static void getSecureRandom(void *buf,unsigned int bytes); static void getSecureRandom(void* buf, unsigned int bytes);
/** /**
* Tokenize a string (alias for strtok_r or strtok_s depending on platform) * Tokenize a string (alias for strtok_r or strtok_s depending on platform)
@ -336,54 +334,81 @@ public:
* @param delim Delimiters * @param delim Delimiters
* @param saveptr Pointer to a char * for temporary reentrant storage * @param saveptr Pointer to a char * for temporary reentrant storage
*/ */
static inline char *stok(char *str,const char *delim,char **saveptr) static inline char* stok(char* str, const char* delim, char** saveptr)
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return strtok_s(str,delim,saveptr); return strtok_s(str, delim, saveptr);
#else #else
return strtok_r(str,delim,saveptr); return strtok_r(str, delim, saveptr);
#endif #endif
} }
static inline unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); } static inline unsigned int strToUInt(const char* s)
static inline int strToInt(const char *s) { return (int)strtol(s,(char **)0,10); } {
static inline unsigned long strToULong(const char *s) { return strtoul(s,(char **)0,10); } return (unsigned int)strtoul(s, (char**)0, 10);
static inline long strToLong(const char *s) { return strtol(s,(char **)0,10); } }
static inline double strToDouble(const char *s) { return strtod(s,NULL); } static inline int strToInt(const char* s)
static inline unsigned long long strToU64(const char *s) {
return (int)strtol(s, (char**)0, 10);
}
static inline unsigned long strToULong(const char* s)
{
return strtoul(s, (char**)0, 10);
}
static inline long strToLong(const char* s)
{
return strtol(s, (char**)0, 10);
}
static inline double strToDouble(const char* s)
{
return strtod(s, NULL);
}
static inline unsigned long long strToU64(const char* s)
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,10); return (unsigned long long)_strtoui64(s, (char**)0, 10);
#else #else
return strtoull(s,(char **)0,10); return strtoull(s, (char**)0, 10);
#endif #endif
} }
static inline long long strTo64(const char *s) static inline long long strTo64(const char* s)
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,10); return (long long)_strtoi64(s, (char**)0, 10);
#else #else
return strtoll(s,(char **)0,10); return strtoll(s, (char**)0, 10);
#endif #endif
} }
static inline unsigned int hexStrToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,16); } static inline unsigned int hexStrToUInt(const char* s)
static inline int hexStrToInt(const char *s) { return (int)strtol(s,(char **)0,16); } {
static inline unsigned long hexStrToULong(const char *s) { return strtoul(s,(char **)0,16); } return (unsigned int)strtoul(s, (char**)0, 16);
static inline long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); } }
static inline unsigned long long hexStrToU64(const char *s) static inline int hexStrToInt(const char* s)
{
return (int)strtol(s, (char**)0, 16);
}
static inline unsigned long hexStrToULong(const char* s)
{
return strtoul(s, (char**)0, 16);
}
static inline long hexStrToLong(const char* s)
{
return strtol(s, (char**)0, 16);
}
static inline unsigned long long hexStrToU64(const char* s)
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,(char **)0,16); return (unsigned long long)_strtoui64(s, (char**)0, 16);
#else #else
return strtoull(s,(char **)0,16); return strtoull(s, (char**)0, 16);
#endif #endif
} }
static inline long long hexStrTo64(const char *s) static inline long long hexStrTo64(const char* s)
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return (long long)_strtoi64(s,(char **)0,16); return (long long)_strtoi64(s, (char**)0, 16);
#else #else
return strtoll(s,(char **)0,16); return strtoll(s, (char**)0, 16);
#endif #endif
} }
@ -398,16 +423,16 @@ public:
* @param src Source string (if NULL, dest will receive a zero-length string and true is returned) * @param src Source string (if NULL, dest will receive a zero-length string and true is returned)
* @return True on success, false on overflow (buffer will still be 0-terminated) * @return True on success, false on overflow (buffer will still be 0-terminated)
*/ */
static inline bool scopy(char *dest,unsigned int len,const char *src) static inline bool scopy(char* dest, unsigned int len, const char* src)
{ {
if (!len) { if (! len) {
return false; // sanity check return false; // sanity check
} }
if (!src) { if (! src) {
*dest = (char)0; *dest = (char)0;
return true; return true;
} }
char *end = dest + len; char* end = dest + len;
while ((*dest++ = *src++)) { while ((*dest++ = *src++)) {
if (dest == end) { if (dest == end) {
*(--dest) = (char)0; *(--dest) = (char)0;
@ -438,10 +463,10 @@ public:
*/ */
static inline uint64_t countBits(uint64_t v) static inline uint64_t countBits(uint64_t v)
{ {
v = v - ((v >> 1) & (uint64_t)~(uint64_t)0/3); v = v - ((v >> 1) & (uint64_t)~(uint64_t)0 / 3);
v = (v & (uint64_t)~(uint64_t)0/15*3) + ((v >> 2) & (uint64_t)~(uint64_t)0/15*3); v = (v & (uint64_t)~(uint64_t)0 / 15 * 3) + ((v >> 2) & (uint64_t)~(uint64_t)0 / 15 * 3);
v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0/255*15; v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0 / 255 * 15;
return (uint64_t)(v * ((uint64_t)~(uint64_t)0/255)) >> 56; return (uint64_t)(v * ((uint64_t)~(uint64_t)0 / 255)) >> 56;
} }
/** /**
@ -451,10 +476,10 @@ public:
* @param len Length of memory * @param len Length of memory
* @return True if memory is all zero * @return True if memory is all zero
*/ */
static inline bool isZero(const void *p,unsigned int len) static inline bool isZero(const void* p, unsigned int len)
{ {
for(unsigned int i=0;i<len;++i) { for (unsigned int i = 0; i < len; ++i) {
if (((const unsigned char *)p)[i]) { if (((const unsigned char*)p)[i]) {
return false; return false;
} }
} }
@ -469,24 +494,17 @@ public:
*/ */
static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept
{ {
#ifdef __GNUC__ #ifdef __GNUC__
return __builtin_bswap64(n); return __builtin_bswap64(n);
#else #else
#ifdef _MSC_VER #ifdef _MSC_VER
return (uint64_t)_byteswap_uint64((unsigned __int64)n); return (uint64_t)_byteswap_uint64((unsigned __int64)n);
#else #else
return ( return (
((n & 0x00000000000000ffULL) << 56) | ((n & 0x00000000000000ffULL) << 56) | ((n & 0x000000000000ff00ULL) << 40) | ((n & 0x0000000000ff0000ULL) << 24) | ((n & 0x00000000ff000000ULL) << 8) | ((n & 0x000000ff00000000ULL) >> 8) | ((n & 0x0000ff0000000000ULL) >> 24)
((n & 0x000000000000ff00ULL) << 40) | | ((n & 0x00ff000000000000ULL) >> 40) | ((n & 0xff00000000000000ULL) >> 56));
((n & 0x0000000000ff0000ULL) << 24) | #endif
((n & 0x00000000ff000000ULL) << 8) | #endif
((n & 0x000000ff00000000ULL) >> 8) |
((n & 0x0000ff0000000000ULL) >> 24) |
((n & 0x00ff000000000000ULL) >> 40) |
((n & 0xff00000000000000ULL) >> 56)
);
#endif
#endif
} }
/** /**
@ -497,15 +515,15 @@ public:
*/ */
static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept
{ {
#if defined(__GNUC__) #if defined(__GNUC__)
return __builtin_bswap32(n); return __builtin_bswap32(n);
#else #else
#ifdef _MSC_VER #ifdef _MSC_VER
return (uint32_t)_byteswap_ulong((unsigned long)n); return (uint32_t)_byteswap_ulong((unsigned long)n);
#else #else
return htonl(n); return htonl(n);
#endif #endif
#endif #endif
} }
/** /**
@ -516,122 +534,119 @@ public:
*/ */
static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept
{ {
#if defined(__GNUC__) #if defined(__GNUC__)
return __builtin_bswap16(n); return __builtin_bswap16(n);
#else #else
#ifdef _MSC_VER #ifdef _MSC_VER
return (uint16_t)_byteswap_ushort((unsigned short)n); return (uint16_t)_byteswap_ushort((unsigned short)n);
#else #else
return htons(n); return htons(n);
#endif #endif
#endif #endif
} }
// These are helper adapters to load and swap integer types special cased by size // These are helper adapters to load and swap integer types special cased by size
// to work with all typedef'd variants, signed/unsigned, etc. // to work with all typedef'd variants, signed/unsigned, etc.
template< typename I, unsigned int S > template <typename I, unsigned int S> class _swap_bytes_bysize;
class _swap_bytes_bysize;
template< typename I > template <typename I> class _swap_bytes_bysize<I, 1> {
class _swap_bytes_bysize< I, 1 >
{
public: public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return n; } {
return n;
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 2> {
class _swap_bytes_bysize< I, 2 >
{
public: public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint16_t)n); } {
return (I)swapBytes((uint16_t)n);
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 4> {
class _swap_bytes_bysize< I, 4 >
{
public: public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint32_t)n); } {
return (I)swapBytes((uint32_t)n);
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 8> {
class _swap_bytes_bysize< I, 8 >
{
public: public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint64_t)n); } {
return (I)swapBytes((uint64_t)n);
}
}; };
template< typename I, unsigned int S > template <typename I, unsigned int S> class _load_be_bysize;
class _load_be_bysize;
template< typename I > template <typename I> class _load_be_bysize<I, 1> {
class _load_be_bysize< I, 1 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return p[0]; } {
return p[0];
}
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 2> {
class _load_be_bysize< I, 2 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); } {
return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]);
}
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 4> {
class _load_be_bysize< I, 4 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); } {
return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]);
}
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 8> {
class _load_be_bysize< I, 8 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); } {
return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]);
}
}; };
template< typename I, unsigned int S > template <typename I, unsigned int S> class _load_le_bysize;
class _load_le_bysize;
template< typename I > template <typename I> class _load_le_bysize<I, 1> {
class _load_le_bysize< I, 1 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return p[0]; } {
return p[0];
}
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 2> {
class _load_le_bysize< I, 2 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); } {
return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U));
}
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 4> {
class _load_le_bysize< I, 4 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); } {
return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U));
}
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 8> {
class _load_le_bysize< I, 8 >
{
public: public:
static ZT_INLINE I l(const uint8_t *const p) noexcept static ZT_INLINE I l(const uint8_t* const p) noexcept
{ return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); } {
return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U);
}
}; };
/** /**
@ -641,14 +656,13 @@ public:
* @param n Value to convert * @param n Value to convert
* @return Value in big-endian order * @return Value in big-endian order
*/ */
template< typename I > template <typename I> static ZT_INLINE I hton(const I n) noexcept
static ZT_INLINE I hton(const I n) noexcept
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n); return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else #else
return n; return n;
#endif #endif
} }
/** /**
@ -658,14 +672,13 @@ public:
* @param n Value to convert * @param n Value to convert
* @return Value in host byte order * @return Value in host byte order
*/ */
template< typename I > template <typename I> static ZT_INLINE I ntoh(const I n) noexcept
static ZT_INLINE I ntoh(const I n) noexcept
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n); return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else #else
return n; return n;
#endif #endif
} }
/** /**
@ -675,18 +688,17 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Loaded raw integer * @return Loaded raw integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadMachineEndian(const void* const p) noexcept
static ZT_INLINE I loadMachineEndian(const void *const p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
I tmp; I tmp;
for(int i=0;i<(int)sizeof(I);++i) { for (int i = 0; i < (int)sizeof(I); ++i) {
reinterpret_cast<uint8_t *>(&tmp)[i] = reinterpret_cast<const uint8_t *>(p)[i]; reinterpret_cast<uint8_t*>(&tmp)[i] = reinterpret_cast<const uint8_t*>(p)[i];
} }
return tmp; return tmp;
#else #else
return *reinterpret_cast<const I *>(p); return *reinterpret_cast<const I*>(p);
#endif #endif
} }
/** /**
@ -696,16 +708,15 @@ public:
* @param p Byte array (must be at least sizeof(I)) * @param p Byte array (must be at least sizeof(I))
* @param i Integer to store * @param i Integer to store
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeMachineEndian(void* const p, const I i) noexcept
static ZT_INLINE void storeMachineEndian(void *const p, const I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<sizeof(I);++k) { for (unsigned int k = 0; k < sizeof(I); ++k) {
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k]; reinterpret_cast<uint8_t*>(p)[k] = reinterpret_cast<const uint8_t*>(&i)[k];
} }
#else #else
*reinterpret_cast<I *>(p) = i; *reinterpret_cast<I*>(p) = i;
#endif #endif
} }
/** /**
@ -715,14 +726,13 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer * @return Decoded integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadBigEndian(const void* const p) noexcept
static ZT_INLINE I loadBigEndian(const void *const p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return _load_be_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p)); return _load_be_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else #else
return ntoh(*reinterpret_cast<const I *>(p)); return ntoh(*reinterpret_cast<const I*>(p));
#endif #endif
} }
/** /**
@ -732,14 +742,13 @@ public:
* @param p Byte stream to write (must be at least sizeof(I)) * @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write * #param i Integer to write
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeBigEndian(void* const p, I i) noexcept
static ZT_INLINE void storeBigEndian(void *const p, I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,hton(i)); storeMachineEndian(p, hton(i));
#else #else
*reinterpret_cast<I *>(p) = hton(i); *reinterpret_cast<I*>(p) = hton(i);
#endif #endif
} }
/** /**
@ -749,14 +758,13 @@ public:
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer * @return Decoded integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadLittleEndian(const void* const p) noexcept
static ZT_INLINE I loadLittleEndian(const void *const p) noexcept
{ {
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS) #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
return _load_le_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p)); return _load_le_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else #else
return *reinterpret_cast<const I *>(p); return *reinterpret_cast<const I*>(p);
#endif #endif
} }
/** /**
@ -766,18 +774,17 @@ public:
* @param p Byte stream to write (must be at least sizeof(I)) * @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write * #param i Integer to write
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeLittleEndian(void* const p, const I i) noexcept
static ZT_INLINE void storeLittleEndian(void *const p, const I i) noexcept
{ {
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
storeMachineEndian(p,_swap_bytes_bysize<I,sizeof(I)>::s(i)); storeMachineEndian(p, _swap_bytes_bysize<I, sizeof(I)>::s(i));
#else #else
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,i); storeMachineEndian(p, i);
#else #else
*reinterpret_cast<I *>(p) = i; *reinterpret_cast<I*>(p) = i;
#endif #endif
#endif #endif
} }
/** /**
@ -787,15 +794,14 @@ public:
* @param dest Destination memory * @param dest Destination memory
* @param src Source memory * @param src Source memory
*/ */
template< unsigned long L > template <unsigned long L> static ZT_INLINE void copy(void* dest, const void* src) noexcept
static ZT_INLINE void copy(void *dest, const void *src) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
uintptr_t l = L; uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest) :: "memory"); __asm__ __volatile__("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest)::"memory");
#else #else
memcpy(dest, src, L); memcpy(dest, src, L);
#endif #endif
} }
/** /**
@ -805,13 +811,13 @@ public:
* @param src Source memory * @param src Source memory
* @param len Bytes to copy * @param len Bytes to copy
*/ */
static ZT_INLINE void copy(void *dest, const void *src, unsigned long len) noexcept static ZT_INLINE void copy(void* dest, const void* src, unsigned long len) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest) :: "memory"); __asm__ __volatile__("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest)::"memory");
#else #else
memcpy(dest, src, len); memcpy(dest, src, len);
#endif #endif
} }
/** /**
@ -820,15 +826,14 @@ public:
* @tparam L Size in bytes * @tparam L Size in bytes
* @param dest Memory to zero * @param dest Memory to zero
*/ */
template< unsigned long L > template <unsigned long L> static ZT_INLINE void zero(void* dest) noexcept
static ZT_INLINE void zero(void *dest) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
uintptr_t l = L; uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (l), "+D" (dest) : "a" (0) : "memory"); __asm__ __volatile__("cld ; rep stosb" : "+c"(l), "+D"(dest) : "a"(0) : "memory");
#else #else
memset(dest, 0, L); memset(dest, 0, L);
#endif #endif
} }
/** /**
@ -837,13 +842,13 @@ public:
* @param dest Memory to zero * @param dest Memory to zero
* @param len Size in bytes * @param len Size in bytes
*/ */
static ZT_INLINE void zero(void *dest, unsigned long len) noexcept static ZT_INLINE void zero(void* dest, unsigned long len) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (len), "+D" (dest) : "a" (0) : "memory"); __asm__ __volatile__("cld ; rep stosb" : "+c"(len), "+D"(dest) : "a"(0) : "memory");
#else #else
memset(dest, 0, len); memset(dest, 0, len);
#endif #endif
} }
/** /**

View file

@ -14,14 +14,14 @@
#ifndef ZT_WORLD_HPP #ifndef ZT_WORLD_HPP
#define ZT_WORLD_HPP #define ZT_WORLD_HPP
#include <vector>
#include <string>
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Identity.hpp"
#include "Buffer.hpp" #include "Buffer.hpp"
#include "Constants.hpp"
#include "ECC.hpp" #include "ECC.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include <string>
#include <vector>
/** /**
* Maximum number of roots (sanity limit, okay to increase) * Maximum number of roots (sanity limit, okay to increase)
@ -76,14 +76,12 @@ namespace ZeroTier {
* world ID for Mars and nearby space is defined but not yet used, and a test * world ID for Mars and nearby space is defined but not yet used, and a test
* world ID is provided for testing purposes. * world ID is provided for testing purposes.
*/ */
class World class World {
{ public:
public:
/** /**
* World type -- do not change IDs * World type -- do not change IDs
*/ */
enum Type enum Type {
{
TYPE_NULL = 0, TYPE_NULL = 0,
TYPE_PLANET = 1, // Planets, of which there is currently one (Earth) TYPE_PLANET = 1, // Planets, of which there is currently one (Earth)
TYPE_MOON = 127 // Moons, which are user-created and many TYPE_MOON = 127 // Moons, which are user-created and many
@ -92,53 +90,78 @@ public:
/** /**
* Upstream server definition in world/moon * Upstream server definition in world/moon
*/ */
struct Root struct Root {
{
Identity identity; Identity identity;
std::vector<InetAddress> stableEndpoints; std::vector<InetAddress> stableEndpoints;
inline bool operator==(const Root &r) const { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); } inline bool operator==(const Root& r) const
inline bool operator!=(const Root &r) const { return (!(*this == r)); } {
inline bool operator<(const Root &r) const { return (identity < r.identity); } // for sorting return ((identity == r.identity) && (stableEndpoints == r.stableEndpoints));
}
inline bool operator!=(const Root& r) const
{
return (! (*this == r));
}
inline bool operator<(const Root& r) const
{
return (identity < r.identity);
} // for sorting
}; };
/** /**
* Construct an empty / null World * Construct an empty / null World
*/ */
World() : World() : _id(0), _ts(0), _type(TYPE_NULL)
_id(0), {
_ts(0), }
_type(TYPE_NULL) {}
/** /**
* @return Root servers for this world and their stable endpoints * @return Root servers for this world and their stable endpoints
*/ */
inline const std::vector<World::Root> &roots() const { return _roots; } inline const std::vector<World::Root>& roots() const
{
return _roots;
}
/** /**
* @return World type: planet or moon * @return World type: planet or moon
*/ */
inline Type type() const { return _type; } inline Type type() const
{
return _type;
}
/** /**
* @return World unique identifier * @return World unique identifier
*/ */
inline uint64_t id() const { return _id; } inline uint64_t id() const
{
return _id;
}
/** /**
* @return World definition timestamp * @return World definition timestamp
*/ */
inline uint64_t timestamp() const { return _ts; } inline uint64_t timestamp() const
{
return _ts;
}
/** /**
* @return C25519 signature * @return C25519 signature
*/ */
inline const ECC::Signature &signature() const { return _signature; } inline const ECC::Signature& signature() const
{
return _signature;
}
/** /**
* @return Public key that must sign next update * @return Public key that must sign next update
*/ */
inline const ECC::Public &updatesMustBeSignedBy() const { return _updatesMustBeSignedBy; } inline const ECC::Public& updatesMustBeSignedBy() const
{
return _updatesMustBeSignedBy;
}
/** /**
* Check whether a world update should replace this one * Check whether a world update should replace this one
@ -146,15 +169,15 @@ public:
* @param update Candidate update * @param update Candidate update
* @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL) * @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL)
*/ */
inline bool shouldBeReplacedBy(const World &update) inline bool shouldBeReplacedBy(const World& update)
{ {
if ((_id == 0)||(_type == TYPE_NULL)) { if ((_id == 0) || (_type == TYPE_NULL)) {
return true; return true;
} }
if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) { if ((_id == update._id) && (_ts < update._ts) && (_type == update._type)) {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp; Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
update.serialize(tmp,true); update.serialize(tmp, true);
return ECC::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); return ECC::verify(_updatesMustBeSignedBy, tmp.data(), tmp.size(), update._signature);
} }
return false; return false;
} }
@ -162,10 +185,12 @@ public:
/** /**
* @return True if this World is non-empty * @return True if this World is non-empty
*/ */
inline operator bool() const { return (_type != TYPE_NULL); } inline operator bool() const
{
return (_type != TYPE_NULL);
}
template<unsigned int C> template <unsigned int C> inline void serialize(Buffer<C>& b, bool forSign = false) const
inline void serialize(Buffer<C> &b,bool forSign = false) const
{ {
if (forSign) { if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -174,15 +199,15 @@ public:
b.append((uint8_t)_type); b.append((uint8_t)_type);
b.append((uint64_t)_id); b.append((uint64_t)_id);
b.append((uint64_t)_ts); b.append((uint64_t)_ts);
b.append(_updatesMustBeSignedBy.data,ZT_ECC_PUBLIC_KEY_SET_LEN); b.append(_updatesMustBeSignedBy.data, ZT_ECC_PUBLIC_KEY_SET_LEN);
if (!forSign) { if (! forSign) {
b.append(_signature.data,ZT_ECC_SIGNATURE_LEN); b.append(_signature.data, ZT_ECC_SIGNATURE_LEN);
} }
b.append((uint8_t)_roots.size()); b.append((uint8_t)_roots.size());
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) { for (std::vector<Root>::const_iterator r(_roots.begin()); r != _roots.end(); ++r) {
r->identity.serialize(b); r->identity.serialize(b);
b.append((uint8_t)r->stableEndpoints.size()); b.append((uint8_t)r->stableEndpoints.size());
for(std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) { for (std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin()); ep != r->stableEndpoints.end(); ++ep) {
ep->serialize(b); ep->serialize(b);
} }
} }
@ -195,14 +220,13 @@ public:
} }
} }
template<unsigned int C> template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{ {
unsigned int p = startAt; unsigned int p = startAt;
_roots.clear(); _roots.clear();
switch((Type)b[p++]) { switch ((Type)b[p++]) {
case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid
_type = TYPE_NULL; _type = TYPE_NULL;
break; break;
@ -220,25 +244,25 @@ public:
p += 8; p += 8;
_ts = b.template at<uint64_t>(p); _ts = b.template at<uint64_t>(p);
p += 8; p += 8;
memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_ECC_PUBLIC_KEY_SET_LEN),ZT_ECC_PUBLIC_KEY_SET_LEN); memcpy(_updatesMustBeSignedBy.data, b.field(p, ZT_ECC_PUBLIC_KEY_SET_LEN), ZT_ECC_PUBLIC_KEY_SET_LEN);
p += ZT_ECC_PUBLIC_KEY_SET_LEN; p += ZT_ECC_PUBLIC_KEY_SET_LEN;
memcpy(_signature.data,b.field(p,ZT_ECC_SIGNATURE_LEN),ZT_ECC_SIGNATURE_LEN); memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN);
p += ZT_ECC_SIGNATURE_LEN; p += ZT_ECC_SIGNATURE_LEN;
const unsigned int numRoots = (unsigned int)b[p++]; const unsigned int numRoots = (unsigned int)b[p++];
if (numRoots > ZT_WORLD_MAX_ROOTS) { if (numRoots > ZT_WORLD_MAX_ROOTS) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
} }
for(unsigned int k=0;k<numRoots;++k) { for (unsigned int k = 0; k < numRoots; ++k) {
_roots.push_back(Root()); _roots.push_back(Root());
Root &r = _roots.back(); Root& r = _roots.back();
p += r.identity.deserialize(b,p); p += r.identity.deserialize(b, p);
unsigned int numStableEndpoints = b[p++]; unsigned int numStableEndpoints = b[p++];
if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) { if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
} }
for(unsigned int kk=0;kk<numStableEndpoints;++kk) { for (unsigned int kk = 0; kk < numStableEndpoints; ++kk) {
r.stableEndpoints.push_back(InetAddress()); r.stableEndpoints.push_back(InetAddress());
p += r.stableEndpoints.back().deserialize(b,p); p += r.stableEndpoints.back().deserialize(b, p);
} }
} }
if (_type == TYPE_MOON) { if (_type == TYPE_MOON) {
@ -248,8 +272,16 @@ public:
return (p - startAt); return (p - startAt);
} }
inline bool operator==(const World &w) const { return ((_id == w._id)&&(_ts == w._ts)&&(memcmp(_updatesMustBeSignedBy.data,w._updatesMustBeSignedBy.data,ZT_ECC_PUBLIC_KEY_SET_LEN) == 0)&&(memcmp(_signature.data,w._signature.data,ZT_ECC_SIGNATURE_LEN) == 0)&&(_roots == w._roots)&&(_type == w._type)); } inline bool operator==(const World& w) const
inline bool operator!=(const World &w) const { return (!(*this == w)); } {
return (
(_id == w._id) && (_ts == w._ts) && (memcmp(_updatesMustBeSignedBy.data, w._updatesMustBeSignedBy.data, ZT_ECC_PUBLIC_KEY_SET_LEN) == 0) && (memcmp(_signature.data, w._signature.data, ZT_ECC_SIGNATURE_LEN) == 0)
&& (_roots == w._roots) && (_type == w._type));
}
inline bool operator!=(const World& w) const
{
return (! (*this == w));
}
/** /**
* Create a World object signed with a key pair * Create a World object signed with a key pair
@ -262,7 +294,7 @@ public:
* @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to) * @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to)
* @return Signed World object * @return Signed World object
*/ */
static inline World make(World::Type t,uint64_t id,uint64_t ts,const ECC::Public &sk,const std::vector<World::Root> &roots,const ECC::Pair &signWith) static inline World make(World::Type t, uint64_t id, uint64_t ts, const ECC::Public& sk, const std::vector<World::Root>& roots, const ECC::Pair& signWith)
{ {
World w; World w;
w._id = id; w._id = id;
@ -272,13 +304,13 @@ public:
w._roots = roots; w._roots = roots;
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp; Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
w.serialize(tmp,true); w.serialize(tmp, true);
w._signature = ECC::sign(signWith,tmp.data(),tmp.size()); w._signature = ECC::sign(signWith, tmp.data(), tmp.size());
return w; return w;
} }
protected: protected:
uint64_t _id; uint64_t _id;
uint64_t _ts; uint64_t _ts;
Type _type; Type _type;

View file

@ -11,27 +11,26 @@
*/ */
/****/ /****/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "Arp.hpp" #include "Arp.hpp"
#include "OSUtils.hpp" #include "OSUtils.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
namespace ZeroTier { namespace ZeroTier {
static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x01 }; static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01 };
static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x02 }; static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02 };
Arp::Arp() : Arp::Arp() : _cache(256), _lastCleaned(OSUtils::now())
_cache(256),
_lastCleaned(OSUtils::now())
{ {
} }
void Arp::addLocal(uint32_t ip,const MAC &mac) void Arp::addLocal(uint32_t ip, const MAC& mac)
{ {
_ArpEntry &e = _cache[ip]; _ArpEntry& e = _cache[ip];
e.lastQuerySent = 0; // local IP e.lastQuerySent = 0; // local IP
e.lastResponseReceived = 0; // local IP e.lastResponseReceived = 0; // local IP
e.mac = mac; e.mac = mac;
@ -43,7 +42,7 @@ void Arp::remove(uint32_t ip)
_cache.erase(ip); _cache.erase(ip);
} }
uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest) uint32_t Arp::processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest)
{ {
const uint64_t now = OSUtils::now(); const uint64_t now = OSUtils::now();
uint32_t ip = 0; uint32_t ip = 0;
@ -52,25 +51,26 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
responseDest.zero(); responseDest.zero();
if (len >= 28) { if (len >= 28) {
if (!memcmp(arp,ARP_REQUEST_HEADER,8)) { if (! memcmp(arp, ARP_REQUEST_HEADER, 8)) {
// Respond to ARP requests for locally-known IPs // Respond to ARP requests for locally-known IPs
_ArpEntry *targetEntry = _cache.get(reinterpret_cast<const uint32_t *>(arp)[6]); _ArpEntry* targetEntry = _cache.get(reinterpret_cast<const uint32_t*>(arp)[6]);
if ((targetEntry)&&(targetEntry->local)) { if ((targetEntry) && (targetEntry->local)) {
memcpy(response,ARP_RESPONSE_HEADER,8); memcpy(response, ARP_RESPONSE_HEADER, 8);
targetEntry->mac.copyTo(reinterpret_cast<uint8_t *>(response) + 8,6); targetEntry->mac.copyTo(reinterpret_cast<uint8_t*>(response) + 8, 6);
memcpy(reinterpret_cast<uint8_t *>(response) + 14,reinterpret_cast<const uint8_t *>(arp) + 24,4); memcpy(reinterpret_cast<uint8_t*>(response) + 14, reinterpret_cast<const uint8_t*>(arp) + 24, 4);
memcpy(reinterpret_cast<uint8_t *>(response) + 18,reinterpret_cast<const uint8_t *>(arp) + 8,10); memcpy(reinterpret_cast<uint8_t*>(response) + 18, reinterpret_cast<const uint8_t*>(arp) + 8, 10);
responseLen = 28; responseLen = 28;
responseDest.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6); responseDest.setTo(reinterpret_cast<const uint8_t*>(arp) + 8, 6);
} }
} else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) { }
else if (! memcmp(arp, ARP_RESPONSE_HEADER, 8)) {
// Learn cache entries for remote IPs from relevant ARP replies // Learn cache entries for remote IPs from relevant ARP replies
uint32_t responseIp = 0; uint32_t responseIp = 0;
memcpy(&responseIp,reinterpret_cast<const uint8_t *>(arp) + 14,4); memcpy(&responseIp, reinterpret_cast<const uint8_t*>(arp) + 14, 4);
_ArpEntry *queryEntry = _cache.get(responseIp); _ArpEntry* queryEntry = _cache.get(responseIp);
if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) { if ((queryEntry) && (! queryEntry->local) && ((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
queryEntry->lastResponseReceived = now; queryEntry->lastResponseReceived = now;
queryEntry->mac.setTo(reinterpret_cast<const uint8_t *>(arp) + 8,6); queryEntry->mac.setTo(reinterpret_cast<const uint8_t*>(arp) + 8, 6);
ip = responseIp; ip = responseIp;
} }
} }
@ -78,11 +78,11 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) { if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) {
_lastCleaned = now; _lastCleaned = now;
Hashtable< uint32_t,_ArpEntry >::Iterator i(_cache); Hashtable<uint32_t, _ArpEntry>::Iterator i(_cache);
uint32_t *k = (uint32_t *)0; uint32_t* k = (uint32_t*)0;
_ArpEntry *v = (_ArpEntry *)0; _ArpEntry* v = (_ArpEntry*)0;
while (i.next(k,v)) { while (i.next(k, v)) {
if ((!v->local)&&((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE)) if ((! v->local) && ((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE))
_cache.erase(*k); _cache.erase(*k);
} }
} }
@ -90,27 +90,32 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
return ip; return ip;
} }
MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest) MAC Arp::query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest)
{ {
const uint64_t now = OSUtils::now(); const uint64_t now = OSUtils::now();
_ArpEntry &e = _cache[targetIp]; _ArpEntry& e = _cache[targetIp];
if ( ((e.mac)&&((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || if (((e.mac) && ((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || ((! e.mac) && ((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL))) {
((!e.mac)&&((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL)) ) {
e.lastQuerySent = now; e.lastQuerySent = now;
uint8_t *q = reinterpret_cast<uint8_t *>(query); uint8_t* q = reinterpret_cast<uint8_t*>(query);
memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same memcpy(q, ARP_REQUEST_HEADER, 8);
localMac.copyTo(q,6); q += 6; // sending host MAC address q += 8; // ARP request header information, always the same
memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order) localMac.copyTo(q, 6);
memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find q += 6; // sending host MAC address
memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order) memcpy(q, &localIp, 4);
q += 4; // sending host IP (IP already in big-endian byte order)
memset(q, 0, 6);
q += 6; // sending zeros for target MAC address as thats what we want to find
memcpy(q, &targetIp, 4); // target IP address for resolution (IP already in big-endian byte order)
queryLen = 28; queryLen = 28;
if (e.mac) if (e.mac)
queryDest = e.mac; // confirmation query, send directly to address holder queryDest = e.mac; // confirmation query, send directly to address holder
else queryDest = (uint64_t)0xffffffffffffULL; // broadcast query else
} else { queryDest = (uint64_t)0xffffffffffffULL; // broadcast query
}
else {
queryLen = 0; queryLen = 0;
queryDest.zero(); queryDest.zero();
} }

View file

@ -14,14 +14,13 @@
#ifndef ZT_ARP_HPP #ifndef ZT_ARP_HPP
#define ZT_ARP_HPP #define ZT_ARP_HPP
#include <stdint.h>
#include <utility>
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/Hashtable.hpp" #include "../node/Hashtable.hpp"
#include "../node/MAC.hpp" #include "../node/MAC.hpp"
#include <stdint.h>
#include <utility>
/** /**
* Maximum possible ARP length * Maximum possible ARP length
* *
@ -67,9 +66,8 @@ namespace ZeroTier {
* This class is not thread-safe and must be guarded if used in multi-threaded * This class is not thread-safe and must be guarded if used in multi-threaded
* code. * code.
*/ */
class Arp class Arp {
{ public:
public:
Arp(); Arp();
/** /**
@ -78,7 +76,7 @@ public:
* @param mac Our local MAC address * @param mac Our local MAC address
* @param ip IP in big-endian byte order (sin_addr.s_addr) * @param ip IP in big-endian byte order (sin_addr.s_addr)
*/ */
void addLocal(uint32_t ip,const MAC &mac); void addLocal(uint32_t ip, const MAC& mac);
/** /**
* Delete a local IP entry or a cached ARP entry * Delete a local IP entry or a cached ARP entry
@ -103,7 +101,7 @@ public:
* @param responseDest Destination of response, or set to null if no response * @param responseDest Destination of response, or set to null if no response
* @return IP address learned or 0 if no new IPs in cache * @return IP address learned or 0 if no new IPs in cache
*/ */
uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest); uint32_t processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest);
/** /**
* Get the MAC corresponding to an IP, generating a query if needed * Get the MAC corresponding to an IP, generating a query if needed
@ -122,19 +120,20 @@ public:
* @param queryDest Destination of query, or set to null if no query generated * @param queryDest Destination of query, or set to null if no query generated
* @return MAC or 0 if no cached entry for this IP * @return MAC or 0 if no cached entry for this IP
*/ */
MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest); MAC query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest);
private: private:
struct _ArpEntry struct _ArpEntry {
_ArpEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false)
{ {
_ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {} }
uint64_t lastQuerySent; // Time last query was sent or 0 for local IP uint64_t lastQuerySent; // Time last query was sent or 0 for local IP
uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP
MAC mac; // MAC address of device responsible for IP or null if not known yet MAC mac; // MAC address of device responsible for IP or null if not known yet
bool local; // True if this is a local ARP entry bool local; // True if this is a local ARP entry
}; };
Hashtable< uint32_t,_ArpEntry > _cache; Hashtable<uint32_t, _ArpEntry> _cache;
uint64_t _lastCleaned; uint64_t _lastCleaned;
}; };

View file

@ -11,81 +11,78 @@
*/ */
/****/ /****/
#include <stdint.h> #include "BSDEthernetTap.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h> #include "../node/Constants.hpp"
#include <signal.h> #include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include <fcntl.h> #include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <net/if.h> #include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <map>
#include <net/if.h>
#include <net/if_arp.h> #include <net/if_arp.h>
#include <net/if_dl.h> #include <net/if_dl.h>
#include <net/if_media.h> #include <net/if_media.h>
#include <net/route.h> #include <net/route.h>
#include <netinet/in.h>
#include <pthread_np.h> #include <pthread_np.h>
#include <sched.h> #include <sched.h>
#include <string>
#include <map>
#include <set> #include <set>
#include <algorithm> #include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <utility> #include <utility>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "OSUtils.hpp"
#include "BSDEthernetTap.hpp"
#define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv" #define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv"
#define ZT_TAP_BUF_SIZE (1024 * 16) #define ZT_TAP_BUF_SIZE (1024 * 16)
// ff:ff:ff:ff:ff:ff with no ADI // ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
namespace ZeroTier { namespace ZeroTier {
BSDEthernetTap::BSDEthernetTap( BSDEthernetTap::BSDEthernetTap(
const char *homePath, const char* homePath,
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg) : void* arg)
_handler(handler), : _handler(handler)
_concurrency(concurrency), , _concurrency(concurrency)
_pinning(pinning), , _pinning(pinning)
_arg(arg), , _arg(arg)
_nwid(nwid), , _nwid(nwid)
_mtu(mtu), , _mtu(mtu)
_metric(metric), , _metric(metric)
_fd(0), , _fd(0)
_enabled(true), , _enabled(true)
_lastIfAddrsUpdate(0) , _lastIfAddrsUpdate(0)
{ {
static Mutex globalTapCreateLock; static Mutex globalTapCreateLock;
char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32]; char devpath[64], ethaddr[64], mtustr[32], metstr[32], tmpdevname[32];
Mutex::Lock _gl(globalTapCreateLock); Mutex::Lock _gl(globalTapCreateLock);
@ -108,43 +105,51 @@ BSDEthernetTap::BSDEthernetTap(
_dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]); _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]);
std::vector<std::string> devFiles(OSUtils::listDirectory("/dev")); std::vector<std::string> devFiles(OSUtils::listDirectory("/dev"));
for(int i=9993;i<(9993+128);++i) { for (int i = 9993; i < (9993 + 128); ++i) {
OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i);
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname);
if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { if (std::find(devFiles.begin(), devFiles.end(), std::string(tmpdevname)) == devFiles.end()) {
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s create" ZT_EOL_S, tmpdevname); fprintf(stderr, "DEBUG: ifconfig %s create" ZT_EOL_S, tmpdevname);
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "create", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
} else throw std::runtime_error("fork() failed"); }
else
throw std::runtime_error("fork() failed");
struct stat stattmp; struct stat stattmp;
if (!stat(devpath,&stattmp)) { if (! stat(devpath, &stattmp)) {
cpid = (long)vfork(); cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s name %s" ZT_EOL_S, tmpdevname, _dev.c_str()); fprintf(stderr, "DEBUG: ifconfig %s name %s" ZT_EOL_S, tmpdevname, _dev.c_str());
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "name", _dev.c_str(), (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
if (exitcode) if (exitcode)
throw std::runtime_error("ifconfig rename operation failed"); throw std::runtime_error("ifconfig rename operation failed");
} else throw std::runtime_error("fork() failed"); }
else
throw std::runtime_error("fork() failed");
_fd = ::open(devpath,O_RDWR); _fd = ::open(devpath, O_RDWR);
if (_fd > 0) if (_fd > 0)
break; break;
else throw std::runtime_error("unable to open created tap device"); else
} else { throw std::runtime_error("unable to open created tap device");
}
else {
throw std::runtime_error("cannot find /dev node for newly created tap device"); throw std::runtime_error("cannot find /dev node for newly created tap device");
} }
} }
@ -152,10 +157,10 @@ BSDEthernetTap::BSDEthernetTap(
#else #else
/* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */ /* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */
for(int i=0;i<64;++i) { for (int i = 0; i < 64; ++i) {
OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i);
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname);
_fd = ::open(devpath,O_RDWR); _fd = ::open(devpath, O_RDWR);
if (_fd > 0) { if (_fd > 0) {
_dev = tmpdevname; _dev = tmpdevname;
break; break;
@ -166,25 +171,26 @@ BSDEthernetTap::BSDEthernetTap(
if (_fd <= 0) if (_fd <= 0)
throw std::runtime_error("unable to open TAP device or no more devices available"); throw std::runtime_error("unable to open TAP device or no more devices available");
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) {
::close(_fd); ::close(_fd);
throw std::runtime_error("unable to set flags on file descriptor for TAP device"); throw std::runtime_error("unable to set flags on file descriptor for TAP device");
} }
// Configure MAC address and MTU, bring interface up // Configure MAC address and MTU, bring interface up
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu); OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", _mtu);
OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric); OSUtils::ztsnprintf(metstr, sizeof(metstr), "%u", _metric);
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s lladdr %s mtu %s metric %s up" ZT_EOL_S, _dev.c_str(), ethaddr, mtustr, metstr); fprintf(stderr, "DEBUG: ifconfig %s lladdr %s mtu %s metric %s up" ZT_EOL_S, _dev.c_str(), ethaddr, mtustr, metstr);
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "lladdr", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
if (exitcode) { if (exitcode) {
::close(_fd); ::close(_fd);
throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
@ -192,7 +198,7 @@ BSDEthernetTap::BSDEthernetTap(
} }
// Set close-on-exec so that devices cannot persist if we fork/exec for update // Set close-on-exec so that devices cannot persist if we fork/exec for update
fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
::pipe(_shutdownSignalPipe); ::pipe(_shutdownSignalPipe);
@ -201,7 +207,7 @@ BSDEthernetTap::BSDEthernetTap(
BSDEthernetTap::~BSDEthernetTap() BSDEthernetTap::~BSDEthernetTap()
{ {
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
::close(_fd); ::close(_fd);
::close(_shutdownSignalPipe[0]); ::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]); ::close(_shutdownSignalPipe[1]);
@ -210,14 +216,15 @@ BSDEthernetTap::~BSDEthernetTap()
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str()); fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str());
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "destroy", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
} }
Thread::join(_thread); Thread::join(_thread);
for (std::thread &t : _rxThreads) { for (std::thread& t : _rxThreads) {
t.join(); t.join();
} }
} }
@ -232,7 +239,7 @@ bool BSDEthernetTap::enabled() const
return _enabled; return _enabled;
} }
static bool ___removeIp(const std::string &_dev,const InetAddress &ip) static bool ___removeIp(const std::string& _dev, const InetAddress& ip)
{ {
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
@ -240,29 +247,30 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s inet %s -alias" ZT_EOL_S, _dev.c_str(), ip.toIpString(ipbuf)); fprintf(stderr, "DEBUG: ifconfig %s inet %s -alias" ZT_EOL_S, _dev.c_str(), ip.toIpString(ipbuf));
#endif #endif
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString(ipbuf),"-alias",(const char *)0); execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "inet", ip.toIpString(ipbuf), "-alias", (const char*)0);
_exit(-1); _exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
waitpid(cpid,&exitcode,0); waitpid(cpid, &exitcode, 0);
return (exitcode == 0); return (exitcode == 0);
} }
return false; // never reached, make compiler shut up about return value return false; // never reached, make compiler shut up about return value
} }
bool BSDEthernetTap::addIp(const InetAddress &ip) bool BSDEthernetTap::addIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return false; return false;
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end())
return true; // IP/netmask already assigned return true; // IP/netmask already assigned
// Remove and reconfigure if address is the same but netmask is different // Remove and reconfigure if address is the same but netmask is different
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) { for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { if ((i->ipsEqual(ip)) && (i->netmaskBits() != ip.netmaskBits())) {
if (___removeIp(_dev,*i)) if (___removeIp(_dev, *i))
break; break;
} }
} }
@ -273,23 +281,24 @@ bool BSDEthernetTap::addIp(const InetAddress &ip)
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s %s %s alias" ZT_EOL_S, _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp)); fprintf(stderr, "DEBUG: ifconfig %s %s %s alias" ZT_EOL_S, _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp));
#endif #endif
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString(tmp),"alias",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp), "alias", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
return (exitcode == 0); return (exitcode == 0);
} }
return false; return false;
} }
bool BSDEthernetTap::removeIp(const InetAddress &ip) bool BSDEthernetTap::removeIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return false; return false;
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) {
if (___removeIp(_dev,ip)) if (___removeIp(_dev, ip))
return true; return true;
} }
return false; return false;
@ -304,27 +313,27 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
} }
_lastIfAddrsUpdate = now; _lastIfAddrsUpdate = now;
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa)) if (getifaddrs(&ifa))
return std::vector<InetAddress>(); return std::vector<InetAddress>();
std::vector<InetAddress> r; std::vector<InetAddress> r;
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) { switch (p->ifa_addr->sa_family) {
case AF_INET: { case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break; } break;
case AF_INET6: { case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4]; uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break; } break;
} }
} }
@ -334,24 +343,24 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
if (ifa) if (ifa)
freeifaddrs(ifa); freeifaddrs(ifa);
std::sort(r.begin(),r.end()); std::sort(r.begin(), r.end());
std::unique(r.begin(),r.end()); std::unique(r.begin(), r.end());
_ifaddrs = r; _ifaddrs = r;
return r; return r;
} }
void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void BSDEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{ {
char putBuf[ZT_MAX_MTU + 64]; char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf,6); to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6,6); from.copyTo(putBuf + 6, 6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len); memcpy(putBuf + 14, data, len);
len += 14; len += 14;
::write(_fd,putBuf,len); ::write(_fd, putBuf, len);
} }
} }
@ -360,24 +369,24 @@ std::string BSDEthernetTap::deviceName() const
return _dev; return _dev;
} }
void BSDEthernetTap::setFriendlyName(const char *friendlyName) void BSDEthernetTap::setFriendlyName(const char* friendlyName)
{ {
} }
void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{ {
std::vector<MulticastGroup> newGroups; std::vector<MulticastGroup> newGroups;
#ifndef __OpenBSD__ #ifndef __OpenBSD__
struct ifmaddrs *ifmap = (struct ifmaddrs *)0; struct ifmaddrs* ifmap = (struct ifmaddrs*)0;
if (!getifmaddrs(&ifmap)) { if (! getifmaddrs(&ifmap)) {
struct ifmaddrs *p = ifmap; struct ifmaddrs* p = ifmap;
while (p) { while (p) {
if (p->ifma_addr->sa_family == AF_LINK) { if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
} }
p = p->ifma_next; p = p->ifma_next;
} }
@ -386,18 +395,18 @@ void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std:
#endif // __OpenBSD__ #endif // __OpenBSD__
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip) for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end()); std::sort(newGroups.begin(), newGroups.end());
std::unique(newGroups.begin(),newGroups.end()); std::unique(newGroups.begin(), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m); added.push_back(*m);
} }
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m); removed.push_back(*m);
} }
@ -411,21 +420,21 @@ void BSDEthernetTap::setMtu(unsigned int mtu)
long cpid = (long)vfork(); long cpid = (long)vfork();
if (cpid == 0) { if (cpid == 0) {
char tmp[64]; char tmp[64];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu);
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: ifconfig %s mtu %s" ZT_EOL_S, _dev.c_str(), tmp); fprintf(stderr, "DEBUG: ifconfig %s mtu %s" ZT_EOL_S, _dev.c_str(), tmp);
#endif #endif
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0); execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "mtu", tmp, (const char*)0);
_exit(-1); _exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
waitpid(cpid,&exitcode,0); waitpid(cpid, &exitcode, 0);
} }
} }
} }
void BSDEthernetTap::threadMain() void BSDEthernetTap::threadMain() throw()
throw()
{ {
// Wait for a moment after startup -- wait for Network to finish // Wait for a moment after startup -- wait for Network to finish
// constructing itself. // constructing itself.
@ -433,7 +442,6 @@ void BSDEthernetTap::threadMain()
for (unsigned int i = 0; i < _concurrency; ++i) { for (unsigned int i = 0; i < _concurrency; ++i) {
_rxThreads.push_back(std::thread([this, i, _pinning] { _rxThreads.push_back(std::thread([this, i, _pinning] {
if (_pinning) { if (_pinning) {
int pinCore = i % _concurrency; int pinCore = i % _concurrency;
fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore); fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore);
@ -441,10 +449,9 @@ void BSDEthernetTap::threadMain()
cpu_set_t cpuset; cpu_set_t cpuset;
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
CPU_SET(pinCore, &cpuset); CPU_SET(pinCore, &cpuset);
//int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset); // int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset);
int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
if (rc != 0) if (rc != 0) {
{
fprintf(stderr, "Failed to pin thread %d to core %d: %s\n", i, pinCore, strerror(errno)); fprintf(stderr, "Failed to pin thread %d to core %d: %s\n", i, pinCore, strerror(errno));
exit(1); exit(1);
} }
@ -457,24 +464,25 @@ void BSDEthernetTap::threadMain()
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_ZERO(&nullfds); FD_ZERO(&nullfds);
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1;
r = 0; r = 0;
for(;;) { for (;;) {
FD_SET(_shutdownSignalPipe[0],&readfds); FD_SET(_shutdownSignalPipe[0], &readfds);
FD_SET(_fd,&readfds); FD_SET(_fd, &readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0);
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread
break; break;
if (FD_ISSET(_fd,&readfds)) { if (FD_ISSET(_fd, &readfds)) {
n = (int)::read(_fd,b + r,sizeof(b) - r); n = (int)::read(_fd, b + r, sizeof(b) - r);
if (n < 0) { if (n < 0) {
if ((errno != EINTR)&&(errno != ETIMEDOUT)) if ((errno != EINTR) && (errno != ETIMEDOUT))
break; break;
} else { }
else {
// Some tap drivers like to send the ethernet frame and the // Some tap drivers like to send the ethernet frame and the
// payload in two chunks, so handle that by accumulating // payload in two chunks, so handle that by accumulating
// data until we have at least a frame. // data until we have at least a frame.
@ -484,10 +492,10 @@ void BSDEthernetTap::threadMain()
r = _mtu + 14; r = _mtu + 14;
if (_enabled) { if (_enabled) {
to.setTo(b,6); to.setTo(b, 6);
from.setTo(b + 6,6); from.setTo(b + 6, 6);
unsigned int etherType = ntohs(((const uint16_t *)b)[6]); unsigned int etherType = ntohs(((const uint16_t*)b)[6]);
_handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(b + 14),r - 14); _handler(_arg, (void*)0, _nwid, from, to, etherType, 0, (const void*)(b + 14), r - 14);
} }
r = 0; r = 0;

View file

@ -14,57 +14,56 @@
#ifndef ZT_BSDETHERNETTAP_HPP #ifndef ZT_BSDETHERNETTAP_HPP
#define ZT_BSDETHERNETTAP_HPP #define ZT_BSDETHERNETTAP_HPP
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "Thread.hpp"
#include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <vector>
#include <stdexcept>
#include <thread> #include <thread>
#include <vector>
#include "../node/Constants.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/MAC.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp"
namespace ZeroTier { namespace ZeroTier {
class BSDEthernetTap : public EthernetTap class BSDEthernetTap : public EthernetTap {
{ public:
public:
BSDEthernetTap( BSDEthernetTap(
const char *homePath, const char* homePath,
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg); void* arg);
virtual ~BSDEthernetTap(); virtual ~BSDEthernetTap();
virtual void setEnabled(bool en); virtual void setEnabled(bool en);
virtual bool enabled() const; virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip); virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress &ip); virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const; virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const; virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName); virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu); virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) {} virtual void setDns(const char* domain, const std::vector<InetAddress>& servers)
{
}
void threadMain() void threadMain() throw();
throw();
private: private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void *_arg; void* _arg;
unsigned int _concurrency; unsigned int _concurrency;
bool _pinning; bool _pinning;
uint64_t _nwid; uint64_t _nwid;

View file

@ -22,11 +22,11 @@
#include <string.h> #include <string.h>
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <shlobj.h>
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#include <netioapi.h> #include <netioapi.h>
#include <shlobj.h>
#include <windows.h>
#include <winsock2.h>
#else #else
#include <ifaddrs.h> #include <ifaddrs.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -34,13 +34,13 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#ifdef __LINUX__ #ifdef __LINUX__
#include <linux/if_addr.h>
#include <net/if.h> #include <net/if.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/if_addr.h>
#endif #endif
#endif #endif
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
#include <net/if.h> #include <net/if.h>
#if TARGET_OS_OSX #if TARGET_OS_OSX
#include <netinet6/in6_var.h> #include <netinet6/in6_var.h>
@ -131,7 +131,7 @@ class Binder {
template <typename PHY_HANDLER_TYPE, typename INTERFACE_CHECKER> void refresh(Phy<PHY_HANDLER_TYPE>& phy, unsigned int* ports, unsigned int portCount, const std::vector<InetAddress> explicitBind, INTERFACE_CHECKER& ifChecker) template <typename PHY_HANDLER_TYPE, typename INTERFACE_CHECKER> void refresh(Phy<PHY_HANDLER_TYPE>& phy, unsigned int* ports, unsigned int portCount, const std::vector<InetAddress> explicitBind, INTERFACE_CHECKER& ifChecker)
{ {
std::map<InetAddress, std::string> localIfAddrs; std::map<InetAddress, std::string> localIfAddrs;
PhySocket *udps; PhySocket* udps;
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
bool interfacesEnumerated = true; bool interfacesEnumerated = true;
@ -232,7 +232,7 @@ class Binder {
} }
} }
if ( (flags & IFA_F_TEMPORARY) != 0) { if ((flags & IFA_F_TEMPORARY) != 0) {
continue; continue;
} }
if (devname) { if (devname) {
@ -322,7 +322,7 @@ class Binder {
if (! gotViaProc) { if (! gotViaProc) {
struct ifaddrs* ifatbl = (struct ifaddrs*)0; struct ifaddrs* ifatbl = (struct ifaddrs*)0;
struct ifaddrs* ifa; struct ifaddrs* ifa;
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
// set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6 // set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6
int infoSock = socket(AF_INET6, SOCK_DGRAM, 0); int infoSock = socket(AF_INET6, SOCK_DGRAM, 0);
#endif #endif
@ -331,7 +331,7 @@ class Binder {
while (ifa) { while (ifa) {
if ((ifa->ifa_name) && (ifa->ifa_addr)) { if ((ifa->ifa_name) && (ifa->ifa_addr)) {
InetAddress ip = *(ifa->ifa_addr); InetAddress ip = *(ifa->ifa_addr);
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) && TARGET_OS_OSX #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK) && TARGET_OS_OSX
// Check if the address is an IPv6 Temporary Address, macOS/BSD version // Check if the address is an IPv6 Temporary Address, macOS/BSD version
if (ifa->ifa_addr->sa_family == AF_INET6) { if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr; struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr;
@ -379,7 +379,7 @@ class Binder {
else { else {
interfacesEnumerated = false; interfacesEnumerated = false;
} }
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) #if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK)
close(infoSock); close(infoSock);
#endif #endif
} }

View file

@ -14,11 +14,11 @@
#ifndef ZT_BLOCKINGQUEUE_HPP #ifndef ZT_BLOCKINGQUEUE_HPP
#define ZT_BLOCKINGQUEUE_HPP #define ZT_BLOCKINGQUEUE_HPP
#include <queue>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <atomic> #include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <vector> #include <vector>
namespace ZeroTier { namespace ZeroTier {
@ -28,11 +28,11 @@ namespace ZeroTier {
* *
* Do not use in node/ since we have not gone C++11 there yet. * Do not use in node/ since we have not gone C++11 there yet.
*/ */
template <class T> template <class T> class BlockingQueue {
class BlockingQueue public:
{ BlockingQueue(void) : r(true)
public: {
BlockingQueue(void) : r(true) {} }
inline void post(T t) inline void post(T t)
{ {
@ -41,16 +41,16 @@ public:
c.notify_one(); c.notify_one();
} }
inline void postLimit(T t,const unsigned long limit) inline void postLimit(T t, const unsigned long limit)
{ {
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
for(;;) { for (;;) {
if (q.size() < limit) { if (q.size() < limit) {
q.push(t); q.push(t);
c.notify_one(); c.notify_one();
break; break;
} }
if (!r) if (! r)
break; break;
gc.wait(lock); gc.wait(lock);
} }
@ -64,14 +64,14 @@ public:
gc.notify_all(); gc.notify_all();
} }
inline bool get(T &value) inline bool get(T& value)
{ {
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
if (!r) if (! r)
return false; return false;
while (q.empty()) { while (q.empty()) {
c.wait(lock); c.wait(lock);
if (!r) { if (! r) {
gc.notify_all(); gc.notify_all();
return false; return false;
} }
@ -85,30 +85,25 @@ public:
inline std::vector<T> drain() inline std::vector<T> drain()
{ {
std::vector<T> v; std::vector<T> v;
while (!q.empty()) { while (! q.empty()) {
v.push_back(q.front()); v.push_back(q.front());
q.pop(); q.pop();
} }
return v; return v;
} }
enum TimedWaitResult enum TimedWaitResult { OK, TIMED_OUT, STOP };
{
OK,
TIMED_OUT,
STOP
};
inline TimedWaitResult get(T &value,const unsigned long ms) inline TimedWaitResult get(T& value, const unsigned long ms)
{ {
const std::chrono::milliseconds ms2{ms}; const std::chrono::milliseconds ms2 { ms };
std::unique_lock<std::mutex> lock(m); std::unique_lock<std::mutex> lock(m);
if (!r) if (! r)
return STOP; return STOP;
while (q.empty()) { while (q.empty()) {
if (c.wait_for(lock,ms2) == std::cv_status::timeout) if (c.wait_for(lock, ms2) == std::cv_status::timeout)
return ((r) ? TIMED_OUT : STOP); return ((r) ? TIMED_OUT : STOP);
else if (!r) else if (! r)
return STOP; return STOP;
} }
value = q.front(); value = q.front();
@ -116,14 +111,15 @@ public:
return OK; return OK;
} }
inline size_t size() const { inline size_t size() const
{
return q.size(); return q.size();
} }
private: private:
std::queue<T> q; std::queue<T> q;
mutable std::mutex m; mutable std::mutex m;
mutable std::condition_variable c,gc; mutable std::condition_variable c, gc;
std::atomic_bool r; std::atomic_bool r;
}; };

View file

@ -12,6 +12,7 @@
/****/ /****/
#include "EthernetTap.hpp" #include "EthernetTap.hpp"
#include "OSUtils.hpp" #include "OSUtils.hpp"
#include <stdlib.h> #include <stdlib.h>
@ -20,15 +21,16 @@
#ifdef ZT_SDK #ifdef ZT_SDK
#include "../controller/EmbeddedNetworkController.hpp" #include "../controller/EmbeddedNetworkController.hpp"
#include "../node/Node.hpp"
#include "../include/VirtualTap.hpp" #include "../include/VirtualTap.hpp"
#include "../node/Node.hpp"
#else #else
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/sysctl.h>
#include "MacEthernetTap.hpp" #include "MacEthernetTap.hpp"
#include "MacKextEthernetTap.hpp" #include "MacKextEthernetTap.hpp"
#include <sys/sysctl.h>
#endif // __APPLE__ #endif // __APPLE__
#ifdef __LINUX__ #ifdef __LINUX__
@ -56,45 +58,45 @@
namespace ZeroTier { namespace ZeroTier {
std::shared_ptr<EthernetTap> EthernetTap::newInstance( std::shared_ptr<EthernetTap> EthernetTap::newInstance(
const char *tapDeviceType, // OS-specific, NULL for default const char* tapDeviceType, // OS-specific, NULL for default
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg) void* arg)
{ {
#ifdef ZT_SDK #ifdef ZT_SDK
return std::shared_ptr<EthernetTap>(new VirtualTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new VirtualTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#else // not ZT_SDK #else // not ZT_SDK
#ifdef __APPLE__ #ifdef __APPLE__
char osrelease[256]; char osrelease[256];
size_t size = sizeof(osrelease); size_t size = sizeof(osrelease);
if (sysctlbyname("kern.osrelease",osrelease,&size,nullptr,0) == 0) { if (sysctlbyname("kern.osrelease", osrelease, &size, nullptr, 0) == 0) {
char *dotAt = strchr(osrelease,'.'); char* dotAt = strchr(osrelease, '.');
if (dotAt) { if (dotAt) {
*dotAt = (char)0; *dotAt = (char)0;
// The "feth" virtual Ethernet device type appeared in Darwin 17.x.x. Older versions // The "feth" virtual Ethernet device type appeared in Darwin 17.x.x. Older versions
// (Sierra and earlier) must use the a kernel extension. // (Sierra and earlier) must use the a kernel extension.
if (strtol(osrelease,(char **)0,10) < 17) { if (strtol(osrelease, (char**)0, 10) < 17) {
return std::shared_ptr<EthernetTap>(new MacKextEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new MacKextEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
} else { }
return std::shared_ptr<EthernetTap>(new MacEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); else {
return std::shared_ptr<EthernetTap>(new MacEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
} }
} }
} }
#endif // __APPLE__ #endif // __APPLE__
#ifdef __LINUX__ #ifdef __LINUX__
return std::shared_ptr<EthernetTap>(new LinuxEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new LinuxEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __LINUX__ #endif // __LINUX__
#ifdef __WINDOWS__ #ifdef __WINDOWS__
@ -108,18 +110,8 @@ std::shared_ptr<EthernetTap> EthernetTap::newInstance(
{ {
Mutex::Lock l(_comInit_m); Mutex::Lock l(_comInit_m);
if (!_comInit) { if (! _comInit) {
hres = CoInitializeSecurity( hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
if (FAILED(hres)) { if (FAILED(hres)) {
CoUninitialize(); CoUninitialize();
fprintf(stderr, "WinEthernetTap: Failed to initialize security"); fprintf(stderr, "WinEthernetTap: Failed to initialize security");
@ -128,19 +120,19 @@ std::shared_ptr<EthernetTap> EthernetTap::newInstance(
_comInit = true; _comInit = true;
} }
} }
return std::shared_ptr<EthernetTap>(new WindowsEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new WindowsEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __WINDOWS__ #endif // __WINDOWS__
#ifdef __FreeBSD__ #ifdef __FreeBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __FreeBSD__ #endif // __FreeBSD__
#ifdef __NetBSD__ #ifdef __NetBSD__
return std::shared_ptr<EthernetTap>(new NetBSDEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new NetBSDEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __NetBSD__ #endif // __NetBSD__
#ifdef __OpenBSD__ #ifdef __OpenBSD__
return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); return std::shared_ptr<EthernetTap>(new BSDEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg));
#endif // __OpenBSD__ #endif // __OpenBSD__
#endif // ZT_SDK? #endif // ZT_SDK?
@ -148,13 +140,17 @@ std::shared_ptr<EthernetTap> EthernetTap::newInstance(
return std::shared_ptr<EthernetTap>(); return std::shared_ptr<EthernetTap>();
} }
EthernetTap::EthernetTap() {} EthernetTap::EthernetTap()
EthernetTap::~EthernetTap() {} {
}
EthernetTap::~EthernetTap()
{
}
bool EthernetTap::addIps(std::vector<InetAddress> ips) bool EthernetTap::addIps(std::vector<InetAddress> ips)
{ {
for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) { for (std::vector<InetAddress>::const_iterator i(ips.begin()); i != ips.end(); ++i) {
if (!addIp(*i)) if (! addIp(*i))
return false; return false;
} }
return true; return true;

View file

@ -15,50 +15,49 @@
#define ZT_ETHERNETTAP_HPP #define ZT_ETHERNETTAP_HPP
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp" #include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp" #include "../node/MulticastGroup.hpp"
#include <string>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
#define GETIFADDRS_CACHE_TIME 1000 #define GETIFADDRS_CACHE_TIME 1000
namespace ZeroTier { namespace ZeroTier {
class EthernetTap class EthernetTap {
{ public:
public:
static std::shared_ptr<EthernetTap> newInstance( static std::shared_ptr<EthernetTap> newInstance(
const char *tapDeviceType, // OS-specific, NULL for default const char* tapDeviceType, // OS-specific, NULL for default
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg); void* arg);
EthernetTap(); EthernetTap();
virtual ~EthernetTap(); virtual ~EthernetTap();
virtual void setEnabled(bool en) = 0; virtual void setEnabled(bool en) = 0;
virtual bool enabled() const = 0; virtual bool enabled() const = 0;
virtual bool addIp(const InetAddress &ip) = 0; virtual bool addIp(const InetAddress& ip) = 0;
virtual bool addIps(std::vector<InetAddress> ips); // uses addIp() unless overridden virtual bool addIps(std::vector<InetAddress> ips); // uses addIp() unless overridden
virtual bool removeIp(const InetAddress &ip) = 0; virtual bool removeIp(const InetAddress& ip) = 0;
virtual std::vector<InetAddress> ips() const = 0; virtual std::vector<InetAddress> ips() const = 0;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0; virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) = 0;
virtual std::string deviceName() const = 0; virtual std::string deviceName() const = 0;
virtual void setFriendlyName(const char *friendlyName) = 0; virtual void setFriendlyName(const char* friendlyName) = 0;
virtual std::string friendlyName() const; virtual std::string friendlyName() const;
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) = 0; virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed) = 0;
virtual void setMtu(unsigned int mtu) = 0; virtual void setMtu(unsigned int mtu) = 0;
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) = 0; virtual void setDns(const char* domain, const std::vector<InetAddress>& servers) = 0;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -11,15 +11,16 @@
*/ */
/****/ /****/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "Http.hpp" #include "Http.hpp"
#include "Phy.hpp"
#include "OSUtils.hpp"
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/Utils.hpp" #include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include "Phy.hpp"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef ZT_USE_SYSTEM_HTTP_PARSER #ifdef ZT_USE_SYSTEM_HTTP_PARSER
#include <http_parser.h> #include <http_parser.h>
@ -31,89 +32,86 @@ namespace ZeroTier {
namespace { namespace {
static int ShttpOnMessageBegin(http_parser *parser); static int ShttpOnMessageBegin(http_parser* parser);
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length);
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length); static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length);
#else #else
static int ShttpOnStatus(http_parser *parser); static int ShttpOnStatus(http_parser* parser);
#endif #endif
static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length); static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length); static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnHeadersComplete(http_parser *parser); static int ShttpOnHeadersComplete(http_parser* parser);
static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length); static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length);
static int ShttpOnMessageComplete(http_parser *parser); static int ShttpOnMessageComplete(http_parser* parser);
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1) #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1)
static const struct http_parser_settings HTTP_PARSER_SETTINGS = { static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnStatus, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete };
ShttpOnMessageBegin,
ShttpOnUrl,
ShttpOnStatus,
ShttpOnHeaderField,
ShttpOnValue,
ShttpOnHeadersComplete,
ShttpOnBody,
ShttpOnMessageComplete
};
#else #else
static const struct http_parser_settings HTTP_PARSER_SETTINGS = { static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete };
ShttpOnMessageBegin,
ShttpOnUrl,
ShttpOnHeaderField,
ShttpOnValue,
ShttpOnHeadersComplete,
ShttpOnBody,
ShttpOnMessageComplete
};
#endif #endif
struct HttpPhyHandler struct HttpPhyHandler {
{
// not used // not used
inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) {} inline void phyOnDatagram(PhySocket* sock, void** uptr, const struct sockaddr* localAddr, const struct sockaddr* from, void* data, unsigned long len)
inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {} {
}
inline void phyOnTcpAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN, const struct sockaddr* from)
{
}
inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) inline void phyOnTcpConnect(PhySocket* sock, void** uptr, bool success)
{ {
if (success) { if (success) {
phy->setNotifyWritable(sock,true); phy->setNotifyWritable(sock, true);
} else { }
else {
*responseBody = "connection failed"; *responseBody = "connection failed";
error = true; error = true;
done = true; done = true;
} }
} }
inline void phyOnTcpClose(PhySocket *sock,void **uptr) inline void phyOnTcpClose(PhySocket* sock, void** uptr)
{ {
done = true; done = true;
} }
inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) inline void phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len)
{ {
lastActivity = OSUtils::now(); lastActivity = OSUtils::now();
http_parser_execute(&parser,&HTTP_PARSER_SETTINGS,(const char *)data,len); http_parser_execute(&parser, &HTTP_PARSER_SETTINGS, (const char*)data, len);
if ((parser.upgrade)||(parser.http_errno != HPE_OK)) if ((parser.upgrade) || (parser.http_errno != HPE_OK))
phy->close(sock); phy->close(sock);
} }
inline void phyOnTcpWritable(PhySocket *sock,void **uptr) inline void phyOnTcpWritable(PhySocket* sock, void** uptr)
{ {
if (writePtr < (unsigned long)writeBuf.length()) { if (writePtr < (unsigned long)writeBuf.length()) {
long n = phy->streamSend(sock,writeBuf.data() + writePtr,(unsigned long)writeBuf.length() - writePtr,true); long n = phy->streamSend(sock, writeBuf.data() + writePtr, (unsigned long)writeBuf.length() - writePtr, true);
if (n > 0) if (n > 0)
writePtr += n; writePtr += n;
} }
if (writePtr >= (unsigned long)writeBuf.length()) if (writePtr >= (unsigned long)writeBuf.length())
phy->setNotifyWritable(sock,false); phy->setNotifyWritable(sock, false);
} }
inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} inline void phyOnFileDescriptorActivity(PhySocket* sock, void** uptr, bool readable, bool writable)
{
}
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} inline void phyOnUnixAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN)
inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} {
inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} }
inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} inline void phyOnUnixClose(PhySocket* sock, void** uptr)
{
}
inline void phyOnUnixData(PhySocket* sock, void** uptr, void* data, unsigned long len)
{
}
inline void phyOnUnixWritable(PhySocket* sock, void** uptr)
{
}
#endif // __UNIX_LIKE__ #endif // __UNIX_LIKE__
http_parser parser; http_parser parser;
@ -125,27 +123,27 @@ struct HttpPhyHandler
std::string writeBuf; std::string writeBuf;
unsigned long maxResponseSize; unsigned long maxResponseSize;
std::map<std::string,std::string> *responseHeaders; std::map<std::string, std::string>* responseHeaders;
std::string *responseBody; std::string* responseBody;
bool error; bool error;
bool done; bool done;
Phy<HttpPhyHandler *> *phy; Phy<HttpPhyHandler*>* phy;
PhySocket *sock; PhySocket* sock;
}; };
static int ShttpOnMessageBegin(http_parser *parser) static int ShttpOnMessageBegin(http_parser* parser)
{ {
return 0; return 0;
} }
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length)
{ {
return 0; return 0;
} }
#if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2)
static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length)
#else #else
static int ShttpOnStatus(http_parser *parser) static int ShttpOnStatus(http_parser* parser)
#endif #endif
{ {
/* /*
@ -156,49 +154,49 @@ static int ShttpOnStatus(http_parser *parser)
*/ */
return 0; return 0;
} }
static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length; hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize) if (hh->messageSize > hh->maxResponseSize)
return -1; return -1;
if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) { if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length())) {
(*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
hh->currentHeaderField = ""; hh->currentHeaderField = "";
hh->currentHeaderValue = ""; hh->currentHeaderValue = "";
} }
for(size_t i=0;i<length;++i) for (size_t i = 0; i < length; ++i)
hh->currentHeaderField.push_back(OSUtils::toLower(ptr[i])); hh->currentHeaderField.push_back(OSUtils::toLower(ptr[i]));
return 0; return 0;
} }
static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length; hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize) if (hh->messageSize > hh->maxResponseSize)
return -1; return -1;
hh->currentHeaderValue.append(ptr,length); hh->currentHeaderValue.append(ptr, length);
return 0; return 0;
} }
static int ShttpOnHeadersComplete(http_parser *parser) static int ShttpOnHeadersComplete(http_parser* parser)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length()))
(*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue;
return 0; return 0;
} }
static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->messageSize += (unsigned long)length; hh->messageSize += (unsigned long)length;
if (hh->messageSize > hh->maxResponseSize) if (hh->messageSize > hh->maxResponseSize)
return -1; return -1;
hh->responseBody->append(ptr,length); hh->responseBody->append(ptr, length);
return 0; return 0;
} }
static int ShttpOnMessageComplete(http_parser *parser) static int ShttpOnMessageComplete(http_parser* parser)
{ {
HttpPhyHandler *hh = reinterpret_cast<HttpPhyHandler *>(parser->data); HttpPhyHandler* hh = reinterpret_cast<HttpPhyHandler*>(parser->data);
hh->phy->close(hh->sock); hh->phy->close(hh->sock);
return 0; return 0;
} }
@ -206,16 +204,16 @@ static int ShttpOnMessageComplete(http_parser *parser)
} // anonymous namespace } // anonymous namespace
unsigned int Http::_do( unsigned int Http::_do(
const char *method, const char* method,
unsigned long maxResponseSize, unsigned long maxResponseSize,
unsigned long timeout, unsigned long timeout,
const struct sockaddr *remoteAddress, const struct sockaddr* remoteAddress,
const char *path, const char* path,
const std::map<std::string,std::string> &requestHeaders, const std::map<std::string, std::string>& requestHeaders,
const void *requestBody, const void* requestBody,
unsigned long requestBodyLength, unsigned long requestBodyLength,
std::map<std::string,std::string> &responseHeaders, std::map<std::string, std::string>& responseHeaders,
std::string &responseBody) std::string& responseBody)
{ {
try { try {
responseHeaders.clear(); responseHeaders.clear();
@ -223,31 +221,33 @@ unsigned int Http::_do(
HttpPhyHandler handler; HttpPhyHandler handler;
http_parser_init(&(handler.parser),HTTP_RESPONSE); http_parser_init(&(handler.parser), HTTP_RESPONSE);
handler.parser.data = (void *)&handler; handler.parser.data = (void*)&handler;
handler.messageSize = 0; handler.messageSize = 0;
handler.writePtr = 0; handler.writePtr = 0;
handler.lastActivity = OSUtils::now(); handler.lastActivity = OSUtils::now();
try { try {
char tmp[1024]; char tmp[1024];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s %s HTTP/1.1\r\n",method,path); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s %s HTTP/1.1\r\n", method, path);
handler.writeBuf.append(tmp); handler.writeBuf.append(tmp);
for(std::map<std::string,std::string>::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h) { for (std::map<std::string, std::string>::const_iterator h(requestHeaders.begin()); h != requestHeaders.end(); ++h) {
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s: %s\r\n",h->first.c_str(),h->second.c_str()); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s: %s\r\n", h->first.c_str(), h->second.c_str());
handler.writeBuf.append(tmp); handler.writeBuf.append(tmp);
} }
handler.writeBuf.append("\r\n"); handler.writeBuf.append("\r\n");
if ((requestBody)&&(requestBodyLength)) if ((requestBody) && (requestBodyLength))
handler.writeBuf.append((const char *)requestBody,requestBodyLength); handler.writeBuf.append((const char*)requestBody, requestBodyLength);
} catch ( ... ) { }
catch (...) {
responseBody = "request too large"; responseBody = "request too large";
return 0; return 0;
} }
if (maxResponseSize) { if (maxResponseSize) {
handler.maxResponseSize = maxResponseSize; handler.maxResponseSize = maxResponseSize;
} else { }
else {
handler.maxResponseSize = 2147483647; handler.maxResponseSize = 2147483647;
} }
handler.responseHeaders = &responseHeaders; handler.responseHeaders = &responseHeaders;
@ -255,19 +255,19 @@ unsigned int Http::_do(
handler.error = false; handler.error = false;
handler.done = false; handler.done = false;
Phy<HttpPhyHandler *> phy(&handler,true,true); Phy<HttpPhyHandler*> phy(&handler, true, true);
bool instantConnect = false; bool instantConnect = false;
handler.phy = &phy; handler.phy = &phy;
handler.sock = phy.tcpConnect((const struct sockaddr *)remoteAddress,instantConnect,(void *)0,true); handler.sock = phy.tcpConnect((const struct sockaddr*)remoteAddress, instantConnect, (void*)0, true);
if (!handler.sock) { if (! handler.sock) {
responseBody = "connection failed (2)"; responseBody = "connection failed (2)";
return 0; return 0;
} }
while (!handler.done) { while (! handler.done) {
phy.poll(timeout / 2); phy.poll(timeout / 2);
if ((timeout)&&((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) { if ((timeout) && ((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) {
phy.close(handler.sock); phy.close(handler.sock);
responseBody = "timed out"; responseBody = "timed out";
return 0; return 0;
@ -275,10 +275,12 @@ unsigned int Http::_do(
} }
return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code)); return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code));
} catch (std::exception &exc) { }
catch (std::exception& exc) {
responseBody = exc.what(); responseBody = exc.what();
return 0; return 0;
} catch ( ... ) { }
catch (...) {
responseBody = "unknown exception"; responseBody = "unknown exception";
return 0; return 0;
} }

View file

@ -14,21 +14,21 @@
#ifndef ZT_HTTP_HPP #ifndef ZT_HTTP_HPP
#define ZT_HTTP_HPP #define ZT_HTTP_HPP
#include <string>
#include <map> #include <map>
#include <stdexcept> #include <stdexcept>
#include <string>
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <windows.h>
#else #else
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#endif #endif
namespace ZeroTier { namespace ZeroTier {
@ -36,9 +36,8 @@ namespace ZeroTier {
/** /**
* Simple synchronous HTTP client used for updater and cli * Simple synchronous HTTP client used for updater and cli
*/ */
class Http class Http {
{ public:
public:
/** /**
* Make HTTP GET request * Make HTTP GET request
* *
@ -46,26 +45,16 @@ public:
* *
* @return HTTP status code or 0 on error (responseBody will contain error message) * @return HTTP status code or 0 on error (responseBody will contain error message)
*/ */
static inline unsigned int GET( static inline unsigned int
unsigned long maxResponseSize, GET(unsigned long maxResponseSize,
unsigned long timeout, unsigned long timeout,
const struct sockaddr *remoteAddress, const struct sockaddr* remoteAddress,
const char *path, const char* path,
const std::map<std::string,std::string> &requestHeaders, const std::map<std::string, std::string>& requestHeaders,
std::map<std::string,std::string> &responseHeaders, std::map<std::string, std::string>& responseHeaders,
std::string &responseBody) std::string& responseBody)
{ {
return _do( return _do("GET", maxResponseSize, timeout, remoteAddress, path, requestHeaders, (const void*)0, 0, responseHeaders, responseBody);
"GET",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
(const void *)0,
0,
responseHeaders,
responseBody);
} }
/** /**
@ -75,26 +64,16 @@ public:
* *
* @return HTTP status code or 0 on error (responseBody will contain error message) * @return HTTP status code or 0 on error (responseBody will contain error message)
*/ */
static inline unsigned int DEL( static inline unsigned int
unsigned long maxResponseSize, DEL(unsigned long maxResponseSize,
unsigned long timeout, unsigned long timeout,
const struct sockaddr *remoteAddress, const struct sockaddr* remoteAddress,
const char *path, const char* path,
const std::map<std::string,std::string> &requestHeaders, const std::map<std::string, std::string>& requestHeaders,
std::map<std::string,std::string> &responseHeaders, std::map<std::string, std::string>& responseHeaders,
std::string &responseBody) std::string& responseBody)
{ {
return _do( return _do("DELETE", maxResponseSize, timeout, remoteAddress, path, requestHeaders, (const void*)0, 0, responseHeaders, responseBody);
"DELETE",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
(const void *)0,
0,
responseHeaders,
responseBody);
} }
/** /**
@ -109,25 +88,15 @@ public:
static inline unsigned int POST( static inline unsigned int POST(
unsigned long maxResponseSize, unsigned long maxResponseSize,
unsigned long timeout, unsigned long timeout,
const struct sockaddr *remoteAddress, const struct sockaddr* remoteAddress,
const char *path, const char* path,
const std::map<std::string,std::string> &requestHeaders, const std::map<std::string, std::string>& requestHeaders,
const void *postData, const void* postData,
unsigned long postDataLength, unsigned long postDataLength,
std::map<std::string,std::string> &responseHeaders, std::map<std::string, std::string>& responseHeaders,
std::string &responseBody) std::string& responseBody)
{ {
return _do( return _do("POST", maxResponseSize, timeout, remoteAddress, path, requestHeaders, postData, postDataLength, responseHeaders, responseBody);
"POST",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
postData,
postDataLength,
responseHeaders,
responseBody);
} }
/** /**
@ -139,42 +108,32 @@ public:
* *
* @return HTTP status code or 0 on error (responseBody will contain error message) * @return HTTP status code or 0 on error (responseBody will contain error message)
*/ */
static inline unsigned int PUT( static inline unsigned int
unsigned long maxResponseSize, PUT(unsigned long maxResponseSize,
unsigned long timeout, unsigned long timeout,
const struct sockaddr *remoteAddress, const struct sockaddr* remoteAddress,
const char *path, const char* path,
const std::map<std::string,std::string> &requestHeaders, const std::map<std::string, std::string>& requestHeaders,
const void *postData, const void* postData,
unsigned long postDataLength, unsigned long postDataLength,
std::map<std::string,std::string> &responseHeaders, std::map<std::string, std::string>& responseHeaders,
std::string &responseBody) std::string& responseBody)
{ {
return _do( return _do("PUT", maxResponseSize, timeout, remoteAddress, path, requestHeaders, postData, postDataLength, responseHeaders, responseBody);
"PUT",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
postData,
postDataLength,
responseHeaders,
responseBody);
} }
private: private:
static unsigned int _do( static unsigned int
const char *method, _do(const char* method,
unsigned long maxResponseSize, unsigned long maxResponseSize,
unsigned long timeout, unsigned long timeout,
const struct sockaddr *remoteAddress, const struct sockaddr* remoteAddress,
const char *path, const char* path,
const std::map<std::string,std::string> &requestHeaders, const std::map<std::string, std::string>& requestHeaders,
const void *requestBody, const void* requestBody,
unsigned long requestBodyLength, unsigned long requestBodyLength,
std::map<std::string,std::string> &responseHeaders, std::map<std::string, std::string>& responseHeaders,
std::string &responseBody); std::string& responseBody);
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -19,42 +19,39 @@
#ifdef __LINUX__ #ifdef __LINUX__
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Dictionary.hpp" #include "../node/Dictionary.hpp"
#include "OSUtils.hpp" #include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "LinuxEthernetTap.hpp" #include "LinuxEthernetTap.hpp"
#include "LinuxNetLink.hpp" #include "LinuxNetLink.hpp"
#include "OSUtils.hpp"
#include <algorithm>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <ifaddrs.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <ifaddrs.h>
#include <algorithm>
#include <utility>
#include <string> #include <string>
#include <sys/ioctl.h>
#include <ctype.h> #include <sys/select.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
#include <utility>
#ifndef IFNAMSIZ #ifndef IFNAMSIZ
#define IFNAMSIZ 16 #define IFNAMSIZ 16
@ -63,7 +60,7 @@
#define ZT_TAP_BUF_SIZE (1024 * 16) #define ZT_TAP_BUF_SIZE (1024 * 16)
// ff:ff:ff:ff:ff:ff with no ADI // ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
namespace ZeroTier { namespace ZeroTier {
@ -72,9 +69,10 @@ namespace ZeroTier {
// the tap devices. // the tap devices.
// //
// Returns true if the kernel major version is < 3 // Returns true if the kernel major version is < 3
bool isOldLinuxKernel() { bool isOldLinuxKernel()
{
struct utsname buffer; struct utsname buffer;
char *p; char* p;
long ver[16]; long ver[16];
int i = 0; int i = 0;
if (uname(&buffer) != 0) { if (uname(&buffer) != 0) {
@ -88,7 +86,8 @@ bool isOldLinuxKernel() {
if (isdigit(*p)) { if (isdigit(*p)) {
ver[i] = strtol(p, &p, 10); ver[i] = strtol(p, &p, 10);
i++; i++;
} else { }
else {
p++; p++;
} }
} }
@ -96,8 +95,8 @@ bool isOldLinuxKernel() {
return ver[0] < 3; return ver[0] < 3;
} }
static const char _base32_chars[32] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' }; static const char _base32_chars[32] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7' };
static void _base32_5_to_8(const uint8_t *in,char *out) static void _base32_5_to_8(const uint8_t* in, char* out)
{ {
out[0] = _base32_chars[(in[0]) >> 3]; out[0] = _base32_chars[(in[0]) >> 3];
out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6]; out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6];
@ -110,85 +109,87 @@ static void _base32_5_to_8(const uint8_t *in,char *out)
} }
LinuxEthernetTap::LinuxEthernetTap( LinuxEthernetTap::LinuxEthernetTap(
const char *homePath, const char* homePath,
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg) : void* arg)
_handler(handler), : _handler(handler)
_arg(arg), , _arg(arg)
_nwid(nwid), , _nwid(nwid)
_mac(mac), , _mac(mac)
_homePath(homePath), , _homePath(homePath)
_mtu(mtu), , _mtu(mtu)
_fd(0), , _fd(0)
_enabled(true), , _enabled(true)
_run(true), , _run(true)
_lastIfAddrsUpdate(0) , _lastIfAddrsUpdate(0)
{ {
static std::mutex s_tapCreateLock; static std::mutex s_tapCreateLock;
char procpath[128],nwids[32]; char procpath[128], nwids[32];
struct stat sbuf; struct stat sbuf;
// Create only one tap at a time globally. // Create only one tap at a time globally.
std::lock_guard<std::mutex> tapCreateLock(s_tapCreateLock); std::lock_guard<std::mutex> tapCreateLock(s_tapCreateLock);
// Make sure Linux netlink is initialized. // Make sure Linux netlink is initialized.
(void)LinuxNetLink::getInstance(); (void)LinuxNetLink::getInstance();
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid); OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", nwid);
_fd = ::open("/dev/net/tun",O_RDWR); _fd = ::open("/dev/net/tun", O_RDWR);
if (_fd <= 0) { if (_fd <= 0) {
_fd = ::open("/dev/tun",O_RDWR); _fd = ::open("/dev/tun", O_RDWR);
if (_fd <= 0) if (_fd <= 0)
throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno)); throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno));
} }
struct ifreq ifr; struct ifreq ifr;
memset(&ifr,0,sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
// Restore device names from legacy devicemap, but for new devices we use a base32-based // Restore device names from legacy devicemap, but for new devices we use a base32-based
// canonical device name. // canonical device name.
std::map<std::string,std::string> globalDeviceMap; std::map<std::string, std::string> globalDeviceMap;
FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r"); FILE* devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "r");
if (devmapf) { if (devmapf) {
char buf[256]; char buf[256];
while (fgets(buf,sizeof(buf),devmapf)) { while (fgets(buf, sizeof(buf), devmapf)) {
char *x = (char *)0; char* x = (char*)0;
char *y = (char *)0; char* y = (char*)0;
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) { for (char* f = Utils::stok(buf, "\r\n=", &saveptr); (f); f = Utils::stok((char*)0, "\r\n=", &saveptr)) {
if (!x) x = f; if (! x)
else if (!y) y = f; x = f;
else break; else if (! y)
y = f;
else
break;
} }
if ((x)&&(y)&&(x[0])&&(y[0])) if ((x) && (y) && (x[0]) && (y[0]))
globalDeviceMap[x] = y; globalDeviceMap[x] = y;
} }
fclose(devmapf); fclose(devmapf);
} }
bool recalledDevice = false; bool recalledDevice = false;
std::map<std::string,std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids); std::map<std::string, std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
if (gdmEntry != globalDeviceMap.end()) { if (gdmEntry != globalDeviceMap.end()) {
Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),gdmEntry->second.c_str()); Utils::scopy(ifr.ifr_name, sizeof(ifr.ifr_name), gdmEntry->second.c_str());
OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name);
recalledDevice = (stat(procpath,&sbuf) != 0); recalledDevice = (stat(procpath, &sbuf) != 0);
} }
if (!recalledDevice) { if (! recalledDevice) {
#ifdef __SYNOLOGY__ #ifdef __SYNOLOGY__
int devno = 50; int devno = 50;
do { do {
OSUtils::ztsnprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++); OSUtils::ztsnprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", devno++);
OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name);
} while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist } while (stat(procpath, &sbuf) == 0); // try zt#++ until we find one that does not exist
#else #else
uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network
do { do {
@ -202,29 +203,28 @@ LinuxEthernetTap::LinuxEthernetTap(
tmp2[4] = (uint8_t)(nwid40 & 0xff); tmp2[4] = (uint8_t)(nwid40 & 0xff);
tmp3[0] = 'z'; tmp3[0] = 'z';
tmp3[1] = 't'; tmp3[1] = 't';
_base32_5_to_8(tmp2,tmp3 + 2); _base32_5_to_8(tmp2, tmp3 + 2);
tmp3[10] = (char)0; tmp3[10] = (char)0;
memcpy(ifr.ifr_name,tmp3,11); memcpy(ifr.ifr_name, tmp3, 11);
OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name);
} while (stat(procpath,&sbuf) == 0); } while (stat(procpath, &sbuf) == 0);
#endif #endif
} }
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) { if (ioctl(_fd, TUNSETIFF, (void*)&ifr) < 0) {
::close(_fd); ::close(_fd);
throw std::runtime_error("unable to configure TUN/TAP device for TAP operation"); throw std::runtime_error("unable to configure TUN/TAP device for TAP operation");
} }
::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here ::ioctl(_fd, TUNSETPERSIST, 0); // valgrind may generate a false alarm here
_dev = ifr.ifr_name; _dev = ifr.ifr_name;
::fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); ::fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
(void)::pipe(_shutdownSignalPipe); (void)::pipe(_shutdownSignalPipe);
for (unsigned int i = 0; i < concurrency; ++i) { for (unsigned int i = 0; i < concurrency; ++i) {
_rxThreads.push_back(std::thread([this, i, concurrency, pinning] { _rxThreads.push_back(std::thread([this, i, concurrency, pinning] {
if (pinning) { if (pinning) {
int pinCore = i % concurrency; int pinCore = i % concurrency;
fprintf(stderr, "Pinning tap thread %d to core %d\n", i, pinCore); fprintf(stderr, "Pinning tap thread %d to core %d\n", i, pinCore);
@ -233,8 +233,7 @@ LinuxEthernetTap::LinuxEthernetTap(
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
CPU_SET(pinCore, &cpuset); CPU_SET(pinCore, &cpuset);
int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset);
if (rc != 0) if (rc != 0) {
{
fprintf(stderr, "Failed to pin tap thread %d to core %d: %s\n", i, pinCore, strerror(errno)); fprintf(stderr, "Failed to pin tap thread %d to core %d: %s\n", i, pinCore, strerror(errno));
exit(1); exit(1);
} }
@ -364,11 +363,11 @@ LinuxEthernetTap::LinuxEthernetTap(
LinuxEthernetTap::~LinuxEthernetTap() LinuxEthernetTap::~LinuxEthernetTap()
{ {
_run = false; _run = false;
(void)::write(_shutdownSignalPipe[1],"\0",1); (void)::write(_shutdownSignalPipe[1], "\0", 1);
::close(_fd); ::close(_fd);
::close(_shutdownSignalPipe[0]); ::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]); ::close(_shutdownSignalPipe[1]);
for (std::thread &t : _rxThreads) { for (std::thread& t : _rxThreads) {
t.join(); t.join();
} }
} }
@ -383,7 +382,7 @@ bool LinuxEthernetTap::enabled() const
return _enabled; return _enabled;
} }
static bool ___removeIp(const std::string &_dev,const InetAddress &ip) static bool ___removeIp(const std::string& _dev, const InetAddress& ip)
{ {
LinuxNetLink::getInstance().removeAddress(ip, _dev.c_str()); LinuxNetLink::getInstance().removeAddress(ip, _dev.c_str());
return true; return true;
@ -392,35 +391,34 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
bool LinuxEthernetTap::addIps(std::vector<InetAddress> ips) bool LinuxEthernetTap::addIps(std::vector<InetAddress> ips)
{ {
#ifdef __SYNOLOGY__ #ifdef __SYNOLOGY__
std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-"+_dev; std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-" + _dev;
std::string cfg_contents = "DEVICE="+_dev+"\nBOOTPROTO=static"; std::string cfg_contents = "DEVICE=" + _dev + "\nBOOTPROTO=static";
int ip4=0,ip6=0,ip4_tot=0,ip6_tot=0; int ip4 = 0, ip6 = 0, ip4_tot = 0, ip6_tot = 0;
for(int i=0; i<(int)ips.size(); i++) { for (int i = 0; i < (int)ips.size(); i++) {
if (ips[i].isV4()) if (ips[i].isV4())
ip4_tot++; ip4_tot++;
else else
ip6_tot++; ip6_tot++;
} }
// Assemble and write contents of ifcfg-dev file // Assemble and write contents of ifcfg-dev file
for(int i=0; i<(int)ips.size(); i++) { for (int i = 0; i < (int)ips.size(); i++) {
if (ips[i].isV4()) { if (ips[i].isV4()) {
char iptmp[64],iptmp2[64]; char iptmp[64], iptmp2[64];
std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : ""; std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : "";
cfg_contents += "\nIPADDR"+numstr4+"="+ips[i].toIpString(iptmp) cfg_contents += "\nIPADDR" + numstr4 + "=" + ips[i].toIpString(iptmp) + "\nNETMASK" + numstr4 + "=" + ips[i].netmask().toIpString(iptmp2) + "\n";
+ "\nNETMASK"+numstr4+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
ip4++; ip4++;
} else { }
char iptmp[64],iptmp2[64]; else {
char iptmp[64], iptmp2[64];
std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : ""; std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : "";
cfg_contents += "\nIPV6ADDR"+numstr6+"="+ips[i].toIpString(iptmp) cfg_contents += "\nIPV6ADDR" + numstr6 + "=" + ips[i].toIpString(iptmp) + "\nNETMASK" + numstr6 + "=" + ips[i].netmask().toIpString(iptmp2) + "\n";
+ "\nNETMASK"+numstr6+"="+ips[i].netmask().toIpString(iptmp2)+"\n";
ip6++; ip6++;
} }
} }
OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length()); OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length());
// Finally, add IPs // Finally, add IPs
for(int i=0; i<(int)ips.size(); i++){ for (int i = 0; i < (int)ips.size(); i++) {
LinuxNetLink::getInstance().addAddress(ips[i], _dev.c_str()); LinuxNetLink::getInstance().addAddress(ips[i], _dev.c_str());
} }
return true; return true;
@ -428,19 +426,19 @@ bool LinuxEthernetTap::addIps(std::vector<InetAddress> ips)
return false; return false;
} }
bool LinuxEthernetTap::addIp(const InetAddress &ip) bool LinuxEthernetTap::addIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return false; return false;
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
if (std::binary_search(allIps.begin(),allIps.end(),ip)) if (std::binary_search(allIps.begin(), allIps.end(), ip))
return true; return true;
// Remove and reconfigure if address is the same but netmask is different // Remove and reconfigure if address is the same but netmask is different
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) { for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if (i->ipsEqual(ip)) if (i->ipsEqual(ip))
___removeIp(_dev,*i); ___removeIp(_dev, *i);
} }
LinuxNetLink::getInstance().addAddress(ip, _dev.c_str()); LinuxNetLink::getInstance().addAddress(ip, _dev.c_str());
@ -448,13 +446,13 @@ bool LinuxEthernetTap::addIp(const InetAddress &ip)
return true; return true;
} }
bool LinuxEthernetTap::removeIp(const InetAddress &ip) bool LinuxEthernetTap::removeIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return true; return true;
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) {
if (___removeIp(_dev,ip)) if (___removeIp(_dev, ip))
return true; return true;
} }
return false; return false;
@ -462,7 +460,6 @@ bool LinuxEthernetTap::removeIp(const InetAddress &ip)
std::vector<InetAddress> LinuxEthernetTap::ips() const std::vector<InetAddress> LinuxEthernetTap::ips() const
{ {
uint64_t now = OSUtils::now(); uint64_t now = OSUtils::now();
if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) {
@ -470,27 +467,27 @@ std::vector<InetAddress> LinuxEthernetTap::ips() const
} }
_lastIfAddrsUpdate = now; _lastIfAddrsUpdate = now;
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa)) if (getifaddrs(&ifa))
return std::vector<InetAddress>(); return std::vector<InetAddress>();
std::vector<InetAddress> r; std::vector<InetAddress> r;
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) { switch (p->ifa_addr->sa_family) {
case AF_INET: { case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break; } break;
case AF_INET6: { case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4]; uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break; } break;
} }
} }
@ -500,24 +497,24 @@ std::vector<InetAddress> LinuxEthernetTap::ips() const
if (ifa) if (ifa)
freeifaddrs(ifa); freeifaddrs(ifa);
std::sort(r.begin(),r.end()); std::sort(r.begin(), r.end());
r.erase(std::unique(r.begin(),r.end()),r.end()); r.erase(std::unique(r.begin(), r.end()), r.end());
_ifaddrs = r; _ifaddrs = r;
return r; return r;
} }
void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void LinuxEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{ {
char putBuf[ZT_MAX_MTU + 64]; char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf,6); to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6,6); from.copyTo(putBuf + 6, 6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len); memcpy(putBuf + 14, data, len);
len += 14; len += 14;
(void)::write(_fd,putBuf,len); (void)::write(_fd, putBuf, len);
} }
} }
@ -526,53 +523,53 @@ std::string LinuxEthernetTap::deviceName() const
return _dev; return _dev;
} }
void LinuxEthernetTap::setFriendlyName(const char *friendlyName) void LinuxEthernetTap::setFriendlyName(const char* friendlyName)
{ {
} }
void LinuxEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) void LinuxEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{ {
char *ptr,*ptr2; char *ptr, *ptr2;
unsigned char mac[6]; unsigned char mac[6];
std::vector<MulticastGroup> newGroups; std::vector<MulticastGroup> newGroups;
int fd = ::open("/proc/net/dev_mcast",O_RDONLY); int fd = ::open("/proc/net/dev_mcast", O_RDONLY);
if (fd > 0) { if (fd > 0) {
char buf[131072]; char buf[131072];
int n = (int)::read(fd,buf,sizeof(buf)); int n = (int)::read(fd, buf, sizeof(buf));
if ((n > 0)&&(n < (int)sizeof(buf))) { if ((n > 0) && (n < (int)sizeof(buf))) {
buf[n] = (char)0; buf[n] = (char)0;
for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) { for (char* l = strtok_r(buf, "\r\n", &ptr); (l); l = strtok_r((char*)0, "\r\n", &ptr)) {
int fno = 0; int fno = 0;
char *devname = (char *)0; char* devname = (char*)0;
char *mcastmac = (char *)0; char* mcastmac = (char*)0;
for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) { for (char* f = strtok_r(l, " \t", &ptr2); (f); f = strtok_r((char*)0, " \t", &ptr2)) {
if (fno == 1) if (fno == 1)
devname = f; devname = f;
else if (fno == 4) else if (fno == 4)
mcastmac = f; mcastmac = f;
++fno; ++fno;
} }
if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6)) if ((devname) && (! strcmp(devname, _dev.c_str())) && (mcastmac) && (Utils::unhex(mcastmac, mac, 6) == 6))
newGroups.push_back(MulticastGroup(MAC(mac,6),0)); newGroups.push_back(MulticastGroup(MAC(mac, 6), 0));
} }
} }
::close(fd); ::close(fd);
} }
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip) for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end()); std::sort(newGroups.begin(), newGroups.end());
newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m); added.push_back(*m);
} }
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m); removed.push_back(*m);
} }
@ -583,13 +580,13 @@ void LinuxEthernetTap::setMtu(unsigned int mtu)
{ {
if (_mtu != mtu) { if (_mtu != mtu) {
_mtu = mtu; _mtu = mtu;
int sock = socket(AF_INET,SOCK_DGRAM,0); int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock > 0) { if (sock > 0) {
struct ifreq ifr; struct ifreq ifr;
memset(&ifr,0,sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name,_dev.c_str()); strcpy(ifr.ifr_name, _dev.c_str());
ifr.ifr_ifru.ifru_mtu = (int)mtu; ifr.ifr_ifru.ifru_mtu = (int)mtu;
if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { if (ioctl(sock, SIOCSIFMTU, (void*)&ifr) < 0) {
printf("WARNING: ioctl() failed updating existing Linux tap device (set MTU)\n"); printf("WARNING: ioctl() failed updating existing Linux tap device (set MTU)\n");
} }
close(sock); close(sock);

View file

@ -14,55 +14,56 @@
#ifndef ZT_LINUXETHERNETTAP_HPP #ifndef ZT_LINUXETHERNETTAP_HPP
#define ZT_LINUXETHERNETTAP_HPP #define ZT_LINUXETHERNETTAP_HPP
#include "../node/MulticastGroup.hpp"
#include "BlockingQueue.hpp"
#include "EthernetTap.hpp"
#include <array>
#include <atomic>
#include <mutex>
#include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <vector>
#include <stdexcept>
#include <atomic>
#include <array>
#include <thread> #include <thread>
#include <mutex> #include <vector>
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "BlockingQueue.hpp"
namespace ZeroTier { namespace ZeroTier {
class LinuxEthernetTap : public EthernetTap class LinuxEthernetTap : public EthernetTap {
{ public:
public:
LinuxEthernetTap( LinuxEthernetTap(
const char *homePath, const char* homePath,
unsigned int concurrency, unsigned int concurrency,
bool pinning, bool pinning,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg); void* arg);
virtual ~LinuxEthernetTap(); virtual ~LinuxEthernetTap();
virtual void setEnabled(bool en); virtual void setEnabled(bool en);
virtual bool enabled() const; virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip); virtual bool addIp(const InetAddress& ip);
virtual bool addIps(std::vector<InetAddress> ips); virtual bool addIps(std::vector<InetAddress> ips);
virtual bool removeIp(const InetAddress &ip); virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const; virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const; virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName); virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu); virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers) {} virtual void setDns(const char* domain, const std::vector<InetAddress>& servers)
{
}
private: private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void *_arg; void* _arg;
uint64_t _nwid; uint64_t _nwid;
MAC _mac; MAC _mac;
std::string _homePath; std::string _homePath;

View file

@ -15,14 +15,14 @@
#include <cerrno> #include <cerrno>
//#define ZT_NETLINK_TRACE // #define ZT_NETLINK_TRACE
#ifdef __LINUX__ #ifdef __LINUX__
#include "LinuxNetLink.hpp" #include "LinuxNetLink.hpp"
#include <unistd.h>
#include <linux/if_tun.h> #include <linux/if_tun.h>
#include <unistd.h>
#ifndef IFNAMSIZ #ifndef IFNAMSIZ
#define IFNAMSIZ 16 #define IFNAMSIZ 16
@ -49,21 +49,14 @@ struct nl_adr_req {
char buf[8192]; char buf[8192];
}; };
LinuxNetLink::LinuxNetLink() LinuxNetLink::LinuxNetLink() : _t(), _running(false), _seq(0), _interfaces(), _if_m(), _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)), _la({ 0 })
: _t()
, _running(false)
, _seq(0)
, _interfaces()
, _if_m()
, _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
, _la({0})
{ {
// set socket timeout to 1 sec so we're not permablocking recv() calls // set socket timeout to 1 sec so we're not permablocking recv() calls
_setSocketTimeout(_fd, 1); _setSocketTimeout(_fd, 1);
_la.nl_family = AF_NETLINK; _la.nl_family = AF_NETLINK;
_la.nl_pid = 0; //getpid()+1; _la.nl_pid = 0; // getpid()+1;
_la.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR|RTMGRP_IPV4_ROUTE|RTMGRP_IPV6_ROUTE|RTMGRP_NOTIFY; _la.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NOTIFY;
if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) { if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) {
fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno)); fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno));
::exit(1); ::exit(1);
@ -89,7 +82,7 @@ void LinuxNetLink::_setSocketTimeout(int fd, int seconds)
struct timeval tv; struct timeval tv;
tv.tv_sec = seconds; tv.tv_sec = seconds;
tv.tv_usec = 0; tv.tv_usec = 0;
if(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) != 0) { if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) != 0) {
#ifdef ZT_NETLINK_TRACE #ifdef ZT_NETLINK_TRACE
fprintf(stderr, "setsockopt failed: %s\n", strerror(errno)); fprintf(stderr, "setsockopt failed: %s\n", strerror(errno));
#endif #endif
@ -99,30 +92,30 @@ void LinuxNetLink::_setSocketTimeout(int fd, int seconds)
#define ZT_NL_BUF_SIZE 16384 #define ZT_NL_BUF_SIZE 16384
int LinuxNetLink::_doRecv(int fd) int LinuxNetLink::_doRecv(int fd)
{ {
char *buf = nullptr; char* buf = nullptr;
if (posix_memalign((void **)&buf,16,ZT_NL_BUF_SIZE) != 0) { if (posix_memalign((void**)&buf, 16, ZT_NL_BUF_SIZE) != 0) {
fprintf(stderr,"malloc failed!\n"); fprintf(stderr, "malloc failed!\n");
::exit(1); ::exit(1);
} }
if (!buf) { if (! buf) {
fprintf(stderr,"malloc failed!\n"); fprintf(stderr, "malloc failed!\n");
::exit(1); ::exit(1);
} }
char *p = NULL; char* p = NULL;
struct nlmsghdr *nlp; struct nlmsghdr* nlp;
int nll = 0; int nll = 0;
int rtn = 0; int rtn = 0;
p = buf; p = buf;
for(;;) { for (;;) {
rtn = recv(fd, p, ZT_NL_BUF_SIZE - nll, 0); rtn = recv(fd, p, ZT_NL_BUF_SIZE - nll, 0);
if (rtn > 0) { if (rtn > 0) {
nlp = (struct nlmsghdr *)p; nlp = (struct nlmsghdr*)p;
if(nlp->nlmsg_type == NLMSG_ERROR && (nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) { if (nlp->nlmsg_type == NLMSG_ERROR && (nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) {
struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlp); struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(nlp);
if (err->error != 0) { if (err->error != 0) {
#ifdef ZT_NETLINK_TRACE #ifdef ZT_NETLINK_TRACE
fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error))); fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error)));
@ -137,8 +130,7 @@ int LinuxNetLink::_doRecv(int fd)
break; break;
} }
if( (nlp->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI || (nlp->nlmsg_type == NLMSG_DONE)) if ((nlp->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI || (nlp->nlmsg_type == NLMSG_DONE)) {
{
if (nlp->nlmsg_type == NLMSG_DONE) { if (nlp->nlmsg_type == NLMSG_DONE) {
_processMessage(nlp, nll); _processMessage(nlp, nll);
p = buf; p = buf;
@ -165,7 +157,8 @@ int LinuxNetLink::_doRecv(int fd)
p = buf; p = buf;
nll = 0; nll = 0;
break; break;
} else { }
else {
break; break;
} }
} }
@ -178,7 +171,7 @@ int LinuxNetLink::_doRecv(int fd)
void LinuxNetLink::threadMain() throw() void LinuxNetLink::threadMain() throw()
{ {
int rtn = 0; int rtn = 0;
while(_running) { while (_running) {
rtn = _doRecv(_fd); rtn = _doRecv(_fd);
if (rtn <= 0) { if (rtn <= 0) {
Thread::sleep(250); Thread::sleep(250);
@ -187,12 +180,10 @@ void LinuxNetLink::threadMain() throw()
} }
} }
void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll) void LinuxNetLink::_processMessage(struct nlmsghdr* nlp, int nll)
{ {
for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll)) for (; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll)) {
{ switch (nlp->nlmsg_type) {
switch(nlp->nlmsg_type)
{
case RTM_NEWLINK: case RTM_NEWLINK:
_linkAdded(nlp); _linkAdded(nlp);
break; break;
@ -217,21 +208,20 @@ void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll)
} }
} }
void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp) void LinuxNetLink::_ipAddressAdded(struct nlmsghdr* nlp)
{ {
#ifdef ZT_NETLINK_TRACE #ifdef ZT_NETLINK_TRACE
struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp); struct ifaddrmsg* ifap = (struct ifaddrmsg*)NLMSG_DATA(nlp);
struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap); struct rtattr* rtap = (struct rtattr*)IFA_RTA(ifap);
int ifal = IFA_PAYLOAD(nlp); int ifal = IFA_PAYLOAD(nlp);
char addr[40] = {0}; char addr[40] = { 0 };
char local[40] = {0}; char local[40] = { 0 };
char label[40] = {0}; char label[40] = { 0 };
char bcast[40] = {0}; char bcast[40] = { 0 };
for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal)) for (; RTA_OK(rtap, ifal); rtap = RTA_NEXT(rtap, ifal)) {
{ switch (rtap->rta_type) {
switch(rtap->rta_type) {
case IFA_ADDRESS: case IFA_ADDRESS:
inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40);
break; break;
@ -247,25 +237,24 @@ void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp)
} }
} }
fprintf(stderr,"Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); fprintf(stderr, "Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast);
#endif #endif
} }
void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp) void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr* nlp)
{ {
#ifdef ZT_NETLINK_TRACE #ifdef ZT_NETLINK_TRACE
struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp); struct ifaddrmsg* ifap = (struct ifaddrmsg*)NLMSG_DATA(nlp);
struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap); struct rtattr* rtap = (struct rtattr*)IFA_RTA(ifap);
int ifal = IFA_PAYLOAD(nlp); int ifal = IFA_PAYLOAD(nlp);
char addr[40] = {0}; char addr[40] = { 0 };
char local[40] = {0}; char local[40] = { 0 };
char label[40] = {0}; char label[40] = { 0 };
char bcast[40] = {0}; char bcast[40] = { 0 };
for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal)) for (; RTA_OK(rtap, ifal); rtap = RTA_NEXT(rtap, ifal)) {
{ switch (rtap->rta_type) {
switch(rtap->rta_type) {
case IFA_ADDRESS: case IFA_ADDRESS:
inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40);
break; break;
@ -285,27 +274,25 @@ void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp)
#endif #endif
} }
void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp) void LinuxNetLink::_routeAdded(struct nlmsghdr* nlp)
{ {
char dsts[40] = {0}; char dsts[40] = { 0 };
char gws[40] = {0}; char gws[40] = { 0 };
char srcs[40] = {0}; char srcs[40] = { 0 };
char ifs[16] = {0}; char ifs[16] = { 0 };
char ms[24] = {0}; char ms[24] = { 0 };
struct rtmsg *rtp = (struct rtmsg *)NLMSG_DATA(nlp); struct rtmsg* rtp = (struct rtmsg*)NLMSG_DATA(nlp);
struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); struct rtattr* rtap = (struct rtattr*)RTM_RTA(rtp);
int rtl = RTM_PAYLOAD(nlp); int rtl = RTM_PAYLOAD(nlp);
Route r; Route r;
bool wecare = false; bool wecare = false;
for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl)) for (; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap, rtl)) {
{ switch (rtap->rta_type) {
switch(rtap->rta_type)
{
case RTA_DST: case RTA_DST:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24);
r.target.set(RTA_DATA(rtap), 4, 0); r.target.set(RTA_DATA(rtap), 4, 0);
@ -319,7 +306,7 @@ void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp)
} }
break; break;
case RTA_SRC: case RTA_SRC:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24);
r.src.set(RTA_DATA(rtap), 4, 0); r.src.set(RTA_DATA(rtap), 4, 0);
@ -333,7 +320,7 @@ void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp)
} }
break; break;
case RTA_GATEWAY: case RTA_GATEWAY:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24);
r.via.set(RTA_DATA(rtap), 4, 0); r.via.set(RTA_DATA(rtap), 4, 0);
@ -347,7 +334,7 @@ void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp)
} }
break; break;
case RTA_OIF: case RTA_OIF:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
r.ifidx = *((int*)RTA_DATA(rtap)); r.ifidx = *((int*)RTA_DATA(rtap));
wecare = true; wecare = true;
@ -373,27 +360,25 @@ void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp)
#endif #endif
} }
void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp) void LinuxNetLink::_routeDeleted(struct nlmsghdr* nlp)
{ {
char dsts[40] = {0}; char dsts[40] = { 0 };
char gws[40] = {0}; char gws[40] = { 0 };
char srcs[40] = {0}; char srcs[40] = { 0 };
char ifs[16] = {0}; char ifs[16] = { 0 };
char ms[24] = {0}; char ms[24] = { 0 };
struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp); struct rtmsg* rtp = (struct rtmsg*)NLMSG_DATA(nlp);
struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); struct rtattr* rtap = (struct rtattr*)RTM_RTA(rtp);
int rtl = RTM_PAYLOAD(nlp); int rtl = RTM_PAYLOAD(nlp);
Route r; Route r;
bool wecare = false; bool wecare = false;
for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl)) for (; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap, rtl)) {
{ switch (rtap->rta_type) {
switch(rtap->rta_type)
{
case RTA_DST: case RTA_DST:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24);
r.target.set(RTA_DATA(rtap), 4, 0); r.target.set(RTA_DATA(rtap), 4, 0);
@ -407,7 +392,7 @@ void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp)
} }
break; break;
case RTA_SRC: case RTA_SRC:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24);
r.src.set(RTA_DATA(rtap), 4, 0); r.src.set(RTA_DATA(rtap), 4, 0);
@ -421,7 +406,7 @@ void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp)
} }
break; break;
case RTA_GATEWAY: case RTA_GATEWAY:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24);
r.via.set(RTA_DATA(rtap), 4, 0); r.via.set(RTA_DATA(rtap), 4, 0);
@ -435,7 +420,7 @@ void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp)
} }
break; break;
case RTA_OIF: case RTA_OIF:
switch(rtp->rtm_family) { switch (rtp->rtm_family) {
case AF_INET: case AF_INET:
r.ifidx = *((int*)RTA_DATA(rtap)); r.ifidx = *((int*)RTA_DATA(rtap));
wecare = true; wecare = true;
@ -461,58 +446,23 @@ void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp)
#endif #endif
} }
void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp) void LinuxNetLink::_linkAdded(struct nlmsghdr* nlp)
{ {
unsigned char mac_bin[6] = {0}; unsigned char mac_bin[6] = { 0 };
unsigned int mtu = 0; unsigned int mtu = 0;
char ifname[IFNAMSIZ] = {0}; char ifname[IFNAMSIZ] = { 0 };
struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp); struct ifinfomsg* ifip = (struct ifinfomsg*)NLMSG_DATA(nlp);
struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip); struct rtattr* rtap = (struct rtattr*)IFLA_RTA(ifip);
int ifil = RTM_PAYLOAD(nlp); int ifil = RTM_PAYLOAD(nlp);
const char *ptr = (const char *)0; const char* ptr = (const char*)0;
for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil)) for (; RTA_OK(rtap, ifil); rtap = RTA_NEXT(rtap, ifil)) {
{ switch (rtap->rta_type) {
switch(rtap->rta_type) {
case IFLA_ADDRESS: case IFLA_ADDRESS:
ptr = (const char *)RTA_DATA(rtap); ptr = (const char*)RTA_DATA(rtap);
memcpy(mac_bin, ptr, 6); memcpy(mac_bin, ptr, 6);
break; break;
case IFLA_IFNAME:
ptr = (const char *)RTA_DATA(rtap);
memcpy(ifname, ptr, strlen(ptr));
break;
case IFLA_MTU:
memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int));
break;
}
}
{
Mutex::Lock l(_if_m);
struct iface_entry &entry = _interfaces[ifip->ifi_index];
entry.index = ifip->ifi_index;
memcpy(entry.ifacename, ifname, sizeof(ifname));
snprintf(entry.mac,sizeof(entry.mac),"%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",(unsigned int)mac_bin[0],(unsigned int)mac_bin[1],(unsigned int)mac_bin[2],(unsigned int)mac_bin[3],(unsigned int)mac_bin[4],(unsigned int)mac_bin[5]);
memcpy(entry.mac_bin, mac_bin, 6);
entry.mtu = mtu;
}
}
void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp)
{
unsigned int mtu = 0;
char ifname[40] = {0};
struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp);
struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip);
int ifil = RTM_PAYLOAD(nlp);
const char *ptr = (const char *)0;
for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil))
{
switch(rtap->rta_type) {
case IFLA_IFNAME: case IFLA_IFNAME:
ptr = (const char*)RTA_DATA(rtap); ptr = (const char*)RTA_DATA(rtap);
memcpy(ifname, ptr, strlen(ptr)); memcpy(ifname, ptr, strlen(ptr));
@ -525,7 +475,49 @@ void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp)
{ {
Mutex::Lock l(_if_m); Mutex::Lock l(_if_m);
if(_interfaces.contains(ifip->ifi_index)) { struct iface_entry& entry = _interfaces[ifip->ifi_index];
entry.index = ifip->ifi_index;
memcpy(entry.ifacename, ifname, sizeof(ifname));
snprintf(
entry.mac,
sizeof(entry.mac),
"%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",
(unsigned int)mac_bin[0],
(unsigned int)mac_bin[1],
(unsigned int)mac_bin[2],
(unsigned int)mac_bin[3],
(unsigned int)mac_bin[4],
(unsigned int)mac_bin[5]);
memcpy(entry.mac_bin, mac_bin, 6);
entry.mtu = mtu;
}
}
void LinuxNetLink::_linkDeleted(struct nlmsghdr* nlp)
{
unsigned int mtu = 0;
char ifname[40] = { 0 };
struct ifinfomsg* ifip = (struct ifinfomsg*)NLMSG_DATA(nlp);
struct rtattr* rtap = (struct rtattr*)IFLA_RTA(ifip);
int ifil = RTM_PAYLOAD(nlp);
const char* ptr = (const char*)0;
for (; RTA_OK(rtap, ifil); rtap = RTA_NEXT(rtap, ifil)) {
switch (rtap->rta_type) {
case IFLA_IFNAME:
ptr = (const char*)RTA_DATA(rtap);
memcpy(ifname, ptr, strlen(ptr));
break;
case IFLA_MTU:
memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int));
break;
}
}
{
Mutex::Lock l(_if_m);
if (_interfaces.contains(ifip->ifi_index)) {
_interfaces.erase(ifip->ifi_index); _interfaces.erase(ifip->ifi_index);
} }
} }
@ -543,9 +535,9 @@ void LinuxNetLink::_requestIPv4Routes()
struct sockaddr_nl la; struct sockaddr_nl la;
la.nl_family = AF_NETLINK; la.nl_family = AF_NETLINK;
la.nl_pid = 0; //getpid(); la.nl_pid = 0; // getpid();
la.nl_groups = RTMGRP_IPV4_ROUTE; la.nl_groups = RTMGRP_IPV4_ROUTE;
if(bind(fd, (struct sockaddr*)&la, sizeof(la))) { if (bind(fd, (struct sockaddr*)&la, sizeof(la))) {
fprintf(stderr, "Error binding RTNETLINK (_requestIPv4Routes #1): %s\n", strerror(errno)); fprintf(stderr, "Error binding RTNETLINK (_requestIPv4Routes #1): %s\n", strerror(errno));
close(fd); close(fd);
return; return;
@ -596,9 +588,9 @@ void LinuxNetLink::_requestIPv6Routes()
struct sockaddr_nl la; struct sockaddr_nl la;
la.nl_family = AF_NETLINK; la.nl_family = AF_NETLINK;
la.nl_pid = 0; //getpid(); la.nl_pid = 0; // getpid();
la.nl_groups = RTMGRP_IPV6_ROUTE; la.nl_groups = RTMGRP_IPV6_ROUTE;
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK (_requestIPv6Routes #1): %s\n", strerror(errno)); fprintf(stderr, "Error binding RTNETLINK (_requestIPv6Routes #1): %s\n", strerror(errno));
close(fd); close(fd);
return; return;
@ -649,9 +641,9 @@ void LinuxNetLink::_requestInterfaceList()
struct sockaddr_nl la; struct sockaddr_nl la;
la.nl_family = AF_NETLINK; la.nl_family = AF_NETLINK;
la.nl_pid = 0; //getpid(); la.nl_pid = 0; // getpid();
la.nl_groups = RTMGRP_LINK; la.nl_groups = RTMGRP_LINK;
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK (_requestInterfaceList #1): %s\n", strerror(errno)); fprintf(stderr, "Error binding RTNETLINK (_requestInterfaceList #1): %s\n", strerror(errno));
close(fd); close(fd);
return; return;
@ -688,9 +680,10 @@ void LinuxNetLink::_requestInterfaceList()
close(fd); close(fd);
} }
void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName) void LinuxNetLink::addRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName)
{ {
if (!target) return; if (! target)
return;
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd == -1) { if (fd == -1) {
@ -703,9 +696,9 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
struct sockaddr_nl la; struct sockaddr_nl la;
bzero(&la, sizeof(la)); bzero(&la, sizeof(la));
la.nl_family = AF_NETLINK; la.nl_family = AF_NETLINK;
la.nl_pid = 0; //getpid(); la.nl_pid = 0; // getpid();
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK (addRoute #1): %s\n", strerror(errno)); fprintf(stderr, "Error binding RTNETLINK (addRoute #1): %s\n", strerror(errno));
close(fd); close(fd);
return; return;
@ -722,18 +715,19 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
struct nl_route_req req; struct nl_route_req req;
bzero(&req, sizeof(req)); bzero(&req, sizeof(req));
struct rtattr *rtap = (struct rtattr *)req.buf; struct rtattr* rtap = (struct rtattr*)req.buf;
rtap->rta_type = RTA_DST; rtap->rta_type = RTA_DST;
if (target.isV4()) { if (target.isV4()) {
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr));
} else { }
else {
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr));
} }
rtl += rtap->rta_len; rtl += rtap->rta_len;
if(via) { if (via) {
/* /*
* Setting a metric keeps zerotier routes from taking priority over physical * Setting a metric keeps zerotier routes from taking priority over physical
* At best the computer would use zerotier through the router instead of the LAN. * At best the computer would use zerotier through the router instead of the LAN.
@ -751,24 +745,26 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
memcpy(RTA_DATA(rtap), &ZT_RTE_METRIC, sizeof(ZT_RTE_METRIC)); memcpy(RTA_DATA(rtap), &ZT_RTE_METRIC, sizeof(ZT_RTE_METRIC));
rtl += rtap->rta_len; rtl += rtap->rta_len;
rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = RTA_GATEWAY; rtap->rta_type = RTA_GATEWAY;
if(via.isV4()) { if (via.isV4()) {
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr));
} else { }
else {
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr));
} }
rtl += rtap->rta_len; rtl += rtap->rta_len;
} else if (src) { }
rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); else if (src) {
rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = RTA_SRC; rtap->rta_type = RTA_SRC;
if(src.isV4()) { if (src.isV4()) {
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr));
}
} else { else {
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr));
} }
@ -778,7 +774,7 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
if (ifaceName != NULL) { if (ifaceName != NULL) {
int interface_index = _indexForInterface(ifaceName); int interface_index = _indexForInterface(ifaceName);
if (interface_index != -1) { if (interface_index != -1) {
rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = RTA_OIF; rtap->rta_type = RTA_OIF;
rtap->rta_len = RTA_LENGTH(sizeof(int)); rtap->rta_len = RTA_LENGTH(sizeof(int));
memcpy(RTA_DATA(rtap), &interface_index, sizeof(int)); memcpy(RTA_DATA(rtap), &interface_index, sizeof(int));
@ -821,9 +817,10 @@ void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, c
close(fd); close(fd);
} }
void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName) void LinuxNetLink::delRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName)
{ {
if (!target) return; if (! target)
return;
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd == -1) { if (fd == -1) {
@ -835,9 +832,9 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c
struct sockaddr_nl la; struct sockaddr_nl la;
la.nl_family = AF_NETLINK; la.nl_family = AF_NETLINK;
la.nl_pid = 0; //getpid(); la.nl_pid = 0; // getpid();
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK (delRoute #1): %s\n", strerror(errno)); fprintf(stderr, "Error binding RTNETLINK (delRoute #1): %s\n", strerror(errno));
close(fd); close(fd);
return; return;
@ -854,36 +851,39 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c
struct nl_route_req req; struct nl_route_req req;
bzero(&req, sizeof(req)); bzero(&req, sizeof(req));
struct rtattr *rtap = (struct rtattr *)req.buf; struct rtattr* rtap = (struct rtattr*)req.buf;
rtap->rta_type = RTA_DST; rtap->rta_type = RTA_DST;
if (target.isV4()) { if (target.isV4()) {
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr));
} else { }
else {
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr));
} }
rtl += rtap->rta_len; rtl += rtap->rta_len;
if(via) { if (via) {
rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = RTA_GATEWAY; rtap->rta_type = RTA_GATEWAY;
if(via.isV4()) { if (via.isV4()) {
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr));
} else { }
else {
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr));
} }
rtl += rtap->rta_len; rtl += rtap->rta_len;
} else if (src) { }
rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); else if (src) {
rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = RTA_SRC; rtap->rta_type = RTA_SRC;
if(src.isV4()) { if (src.isV4()) {
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr));
}
} else { else {
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr));
} }
@ -893,7 +893,7 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c
if (ifaceName != NULL) { if (ifaceName != NULL) {
int interface_index = _indexForInterface(ifaceName); int interface_index = _indexForInterface(ifaceName);
if (interface_index != -1) { if (interface_index != -1) {
rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = RTA_OIF; rtap->rta_type = RTA_OIF;
rtap->rta_len = RTA_LENGTH(sizeof(int)); rtap->rta_len = RTA_LENGTH(sizeof(int));
memcpy(RTA_DATA(rtap), &interface_index, sizeof(int)); memcpy(RTA_DATA(rtap), &interface_index, sizeof(int));
@ -936,7 +936,7 @@ void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, c
close(fd); close(fd);
} }
void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface) void LinuxNetLink::addAddress(const InetAddress& addr, const char* iface)
{ {
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd == -1) { if (fd == -1) {
@ -947,16 +947,17 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
_setSocketTimeout(fd); _setSocketTimeout(fd);
struct sockaddr_nl la; struct sockaddr_nl la;
memset(&la,0,sizeof(la)); memset(&la, 0, sizeof(la));
la.nl_family = AF_NETLINK; la.nl_family = AF_NETLINK;
la.nl_pid = 0; //getpid(); la.nl_pid = 0; // getpid();
if (addr.isV4()) { if (addr.isV4()) {
la.nl_groups = RTMGRP_IPV4_IFADDR; la.nl_groups = RTMGRP_IPV4_IFADDR;
} else { }
else {
la.nl_groups = RTMGRP_IPV6_IFADDR; la.nl_groups = RTMGRP_IPV6_IFADDR;
} }
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK (addAddress #1): %s\n", strerror(errno)); fprintf(stderr, "Error binding RTNETLINK (addAddress #1): %s\n", strerror(errno));
close(fd); close(fd);
return; return;
@ -983,9 +984,10 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
struct nl_adr_req req; struct nl_adr_req req;
bzero(&req, sizeof(struct nl_adr_req)); bzero(&req, sizeof(struct nl_adr_req));
struct rtattr *rtap = (struct rtattr *)req.buf;; struct rtattr* rtap = (struct rtattr*)req.buf;
if(addr.isV4()) { ;
struct sockaddr_in *addr_v4 = (struct sockaddr_in*)&addr; if (addr.isV4()) {
struct sockaddr_in* addr_v4 = (struct sockaddr_in*)&addr;
rtap->rta_type = IFA_ADDRESS; rtap->rta_type = IFA_ADDRESS;
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr));
@ -998,24 +1000,25 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
rtl += rtap->rta_len; rtl += rtap->rta_len;
InetAddress broadcast = addr.broadcast(); InetAddress broadcast = addr.broadcast();
if(broadcast) { if (broadcast) {
rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
struct sockaddr_in *bcast = (struct sockaddr_in*)&broadcast; struct sockaddr_in* bcast = (struct sockaddr_in*)&broadcast;
rtap->rta_type = IFA_BROADCAST; rtap->rta_type = IFA_BROADCAST;
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr));
rtl += rtap->rta_len; rtl += rtap->rta_len;
} }
} else { //V6 }
else { // V6
rtap->rta_type = IFA_ADDRESS; rtap->rta_type = IFA_ADDRESS;
struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6*)&addr; struct sockaddr_in6* addr_v6 = (struct sockaddr_in6*)&addr;
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr));
rtl += rtap->rta_len; rtl += rtap->rta_len;
} }
if (iface) { if (iface) {
rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = IFA_LABEL; rtap->rta_type = IFA_LABEL;
rtap->rta_len = RTA_LENGTH(strlen(iface)); rtap->rta_len = RTA_LENGTH(strlen(iface));
memcpy(RTA_DATA(rtap), iface, strlen(iface)); memcpy(RTA_DATA(rtap), iface, strlen(iface));
@ -1054,7 +1057,7 @@ void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface)
close(fd); close(fd);
} }
void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface) void LinuxNetLink::removeAddress(const InetAddress& addr, const char* iface)
{ {
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (fd == -1) { if (fd == -1) {
@ -1066,13 +1069,14 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface)
struct sockaddr_nl la; struct sockaddr_nl la;
la.nl_family = AF_NETLINK; la.nl_family = AF_NETLINK;
la.nl_pid = 0; //getpid(); la.nl_pid = 0; // getpid();
if (addr.isV4()) { if (addr.isV4()) {
la.nl_groups = RTMGRP_IPV4_IFADDR; la.nl_groups = RTMGRP_IPV4_IFADDR;
} else { }
else {
la.nl_groups = RTMGRP_IPV6_IFADDR; la.nl_groups = RTMGRP_IPV6_IFADDR;
} }
if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) {
fprintf(stderr, "Error binding RTNETLINK (removeAddress #1): %s\n", strerror(errno)); fprintf(stderr, "Error binding RTNETLINK (removeAddress #1): %s\n", strerror(errno));
close(fd); close(fd);
return; return;
@ -1095,9 +1099,9 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface)
struct nl_adr_req req; struct nl_adr_req req;
bzero(&req, sizeof(struct nl_adr_req)); bzero(&req, sizeof(struct nl_adr_req));
struct rtattr *rtap = (struct rtattr *)req.buf; struct rtattr* rtap = (struct rtattr*)req.buf;
if(addr.isV4()) { if (addr.isV4()) {
struct sockaddr_in *addr_v4 = (struct sockaddr_in*)&addr; struct sockaddr_in* addr_v4 = (struct sockaddr_in*)&addr;
rtap->rta_type = IFA_ADDRESS; rtap->rta_type = IFA_ADDRESS;
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr));
@ -1110,24 +1114,25 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface)
rtl += rtap->rta_len; rtl += rtap->rta_len;
InetAddress broadcast = addr.broadcast(); InetAddress broadcast = addr.broadcast();
if(broadcast) { if (broadcast) {
rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
struct sockaddr_in *bcast = (struct sockaddr_in*)&broadcast; struct sockaddr_in* bcast = (struct sockaddr_in*)&broadcast;
rtap->rta_type = IFA_BROADCAST; rtap->rta_type = IFA_BROADCAST;
rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr));
memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr)); memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr));
rtl += rtap->rta_len; rtl += rtap->rta_len;
} }
} else { //V6 }
else { // V6
rtap->rta_type = IFA_ADDRESS; rtap->rta_type = IFA_ADDRESS;
struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6*)&addr; struct sockaddr_in6* addr_v6 = (struct sockaddr_in6*)&addr;
rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr));
memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr)); memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr));
rtl += rtap->rta_len; rtl += rtap->rta_len;
} }
if (iface) { if (iface) {
rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len);
rtap->rta_type = IFA_LABEL; rtap->rta_type = IFA_LABEL;
rtap->rta_len = RTA_LENGTH(strlen(iface)); rtap->rta_len = RTA_LENGTH(strlen(iface));
memcpy(RTA_DATA(rtap), iface, strlen(iface)); memcpy(RTA_DATA(rtap), iface, strlen(iface));
@ -1166,18 +1171,19 @@ void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface)
close(fd); close(fd);
} }
bool LinuxNetLink::routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname) bool LinuxNetLink::routeIsSet(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifname)
{ {
Mutex::Lock rl(_routes_m); Mutex::Lock rl(_routes_m);
const std::set<LinuxNetLink::Route> &rs = _routes[target]; const std::set<LinuxNetLink::Route>& rs = _routes[target];
for(std::set<LinuxNetLink::Route>::const_iterator ri(rs.begin());ri!=rs.end();++ri) { for (std::set<LinuxNetLink::Route>::const_iterator ri(rs.begin()); ri != rs.end(); ++ri) {
if ((ri->via == via)&&(ri->src == src)) { if ((ri->via == via) && (ri->src == src)) {
if (ifname) { if (ifname) {
Mutex::Lock ifl(_if_m); Mutex::Lock ifl(_if_m);
const iface_entry *ife = _interfaces.get(ri->ifidx); const iface_entry* ife = _interfaces.get(ri->ifidx);
if ((ife)&&(!strncmp(ife->ifacename,ifname,IFNAMSIZ))) if ((ife) && (! strncmp(ife->ifacename, ifname, IFNAMSIZ)))
return true; return true;
} else { }
else {
return true; return true;
} }
} }
@ -1185,15 +1191,15 @@ bool LinuxNetLink::routeIsSet(const InetAddress &target, const InetAddress &via,
return false; return false;
} }
int LinuxNetLink::_indexForInterface(const char *iface) int LinuxNetLink::_indexForInterface(const char* iface)
{ {
Mutex::Lock l(_if_m); Mutex::Lock l(_if_m);
int interface_index = -1; int interface_index = -1;
Hashtable<int, iface_entry>::Iterator iter(_interfaces); Hashtable<int, iface_entry>::Iterator iter(_interfaces);
int *k = NULL; int* k = NULL;
iface_entry *v = NULL; iface_entry* v = NULL;
while(iter.next(k,v)) { while (iter.next(k, v)) {
if(strcmp(iface, v->ifacename) == 0) { if (strcmp(iface, v->ifacename) == 0) {
interface_index = v->index; interface_index = v->index;
break; break;
} }

View file

@ -18,68 +18,77 @@
#ifdef __LINUX__ #ifdef __LINUX__
#include <vector>
#include <map>
#include <set>
#include <sys/socket.h>
#include <asm/types.h> #include <asm/types.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <map>
#include <set>
#include <sys/socket.h> #include <sys/socket.h>
//#include <linux/if.h> #include <vector>
// #include <linux/if.h>
#include "../node/Hashtable.hpp"
#include "../node/InetAddress.hpp" #include "../node/InetAddress.hpp"
#include "../node/MAC.hpp" #include "../node/MAC.hpp"
#include "Thread.hpp"
#include "../node/Hashtable.hpp"
#include "../node/Mutex.hpp" #include "../node/Mutex.hpp"
#include "Thread.hpp"
namespace ZeroTier { namespace ZeroTier {
/** /**
* Interface with Linux's RTNETLINK * Interface with Linux's RTNETLINK
*/ */
class LinuxNetLink class LinuxNetLink {
{ private:
private:
LinuxNetLink(); LinuxNetLink();
~LinuxNetLink(); ~LinuxNetLink();
public: public:
struct Route { struct Route {
InetAddress target; InetAddress target;
InetAddress via; InetAddress via;
InetAddress src; InetAddress src;
int ifidx; int ifidx;
inline bool operator==(const Route &r) const inline bool operator==(const Route& r) const
{ return ((target == r.target)&&(via == r.via)&&(src == r.src)&&(ifidx == r.ifidx)); } {
inline bool operator!=(const Route &r) const return ((target == r.target) && (via == r.via) && (src == r.src) && (ifidx == r.ifidx));
{ return (!(*this == r)); } }
inline bool operator<(const Route &r) const inline bool operator!=(const Route& r) const
{
return (! (*this == r));
}
inline bool operator<(const Route& r) const
{ {
if (target < r.target) { if (target < r.target) {
return true; return true;
} else if (target == r.target) { }
else if (target == r.target) {
if (via < r.via) { if (via < r.via) {
return true; return true;
} else if (via == r.via) { }
else if (via == r.via) {
if (src < r.src) { if (src < r.src) {
return true; return true;
} else if (src == r.src) { }
else if (src == r.src) {
return (ifidx < r.ifidx); return (ifidx < r.ifidx);
} }
} }
} }
return false; return false;
} }
inline bool operator>(const Route &r) const inline bool operator>(const Route& r) const
{ return (r < *this); } {
inline bool operator<=(const Route &r) const return (r < *this);
{ return !(r < *this); } }
inline bool operator>=(const Route &r) const inline bool operator<=(const Route& r) const
{ return !(*this < r); } {
return ! (r < *this);
}
inline bool operator>=(const Route& r) const
{
return ! (*this < r);
}
}; };
static LinuxNetLink& getInstance() static LinuxNetLink& getInstance()
@ -91,32 +100,32 @@ public:
LinuxNetLink(LinuxNetLink const&) = delete; LinuxNetLink(LinuxNetLink const&) = delete;
void operator=(LinuxNetLink const&) = delete; void operator=(LinuxNetLink const&) = delete;
void addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); void addRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName);
void delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); void delRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName);
void addAddress(const InetAddress &addr, const char *iface); void addAddress(const InetAddress& addr, const char* iface);
void removeAddress(const InetAddress &addr, const char *iface); void removeAddress(const InetAddress& addr, const char* iface);
bool routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname); bool routeIsSet(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifname);
void threadMain() throw(); void threadMain() throw();
private: private:
int _doRecv(int fd); int _doRecv(int fd);
void _processMessage(struct nlmsghdr *nlp, int nll); void _processMessage(struct nlmsghdr* nlp, int nll);
void _routeAdded(struct nlmsghdr *nlp); void _routeAdded(struct nlmsghdr* nlp);
void _routeDeleted(struct nlmsghdr *nlp); void _routeDeleted(struct nlmsghdr* nlp);
void _linkAdded(struct nlmsghdr *nlp); void _linkAdded(struct nlmsghdr* nlp);
void _linkDeleted(struct nlmsghdr *nlp); void _linkDeleted(struct nlmsghdr* nlp);
void _ipAddressAdded(struct nlmsghdr *nlp); void _ipAddressAdded(struct nlmsghdr* nlp);
void _ipAddressDeleted(struct nlmsghdr *nlp); void _ipAddressDeleted(struct nlmsghdr* nlp);
void _requestInterfaceList(); void _requestInterfaceList();
void _requestIPv4Routes(); void _requestIPv4Routes();
void _requestIPv6Routes(); void _requestIPv6Routes();
int _indexForInterface(const char *iface); int _indexForInterface(const char* iface);
void _setSocketTimeout(int fd, int seconds = 1); void _setSocketTimeout(int fd, int seconds = 1);
@ -125,12 +134,14 @@ private:
uint32_t _seq; uint32_t _seq;
std::map< InetAddress,std::set<LinuxNetLink::Route> > _routes; std::map<InetAddress, std::set<LinuxNetLink::Route> > _routes;
Mutex _routes_m; Mutex _routes_m;
struct iface_entry { struct iface_entry {
iface_entry() iface_entry()
{ memset(this,0,sizeof(iface_entry)); } {
memset(this, 0, sizeof(iface_entry));
}
int index; int index;
char ifacename[16]; // IFNAMSIZ on Linux == 16 char ifacename[16]; // IFNAMSIZ on Linux == 16
char mac[18]; char mac[18];
@ -145,7 +156,7 @@ private:
struct sockaddr_nl _la; struct sockaddr_nl _la;
}; };
} } // namespace ZeroTier
#endif #endif

View file

@ -1,23 +1,23 @@
#ifndef MAC_DNS_HELPER #ifndef MAC_DNS_HELPER
#define MAC_DNS_HELPER #define MAC_DNS_HELPER
#include <vector>
#include "../node/InetAddress.hpp" #include "../node/InetAddress.hpp"
#include "../node/MAC.hpp" #include "../node/MAC.hpp"
#include <vector>
namespace ZeroTier { namespace ZeroTier {
class MacDNSHelper class MacDNSHelper {
{ public:
public: static void setDNS(uint64_t nwid, const char* domain, const std::vector<InetAddress>& servers);
static void setDNS(uint64_t nwid, const char *domain, const std::vector<InetAddress> &servers);
static void removeDNS(uint64_t nwid); static void removeDNS(uint64_t nwid);
static bool addIps4(uint64_t nwid, const MAC mac, const char *dev, const std::vector<InetAddress> &addrs); static bool addIps4(uint64_t nwid, const MAC mac, const char* dev, const std::vector<InetAddress>& addrs);
static bool addIps6(uint64_t nwid, const MAC mac, const char *dev, const std::vector<InetAddress> &addrs); static bool addIps6(uint64_t nwid, const MAC mac, const char* dev, const std::vector<InetAddress>& addrs);
static bool removeIps4(uint64_t nwid); static bool removeIps4(uint64_t nwid);
static bool removeIps6(uint64_t nwid); static bool removeIps6(uint64_t nwid);
}; };
} } // namespace ZeroTier
#endif #endif

View file

@ -15,49 +15,45 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Dictionary.hpp" #include "../node/Dictionary.hpp"
#include "OSUtils.hpp" #include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "MacDNSHelper.hpp"
#include "MacEthernetTap.hpp" #include "MacEthernetTap.hpp"
#include "MacEthernetTapAgent.h" #include "MacEthernetTapAgent.h"
#include "MacDNSHelper.hpp" #include "OSUtils.hpp"
#include <algorithm>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <filesystem>
#include <ifaddrs.h>
#include <map>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <set>
#include <signal.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <sys/sysctl.h>
#include <ifaddrs.h>
#include <string> #include <string>
#include <map> #include <sys/cdefs.h>
#include <set> #include <sys/ioctl.h>
#include <algorithm> #include <sys/param.h>
#include <filesystem> #include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
#define MACOS_FETH_MAX_MTU_SYSCTL "net.link.fake.max_mtu" #define MACOS_FETH_MAX_MTU_SYSCTL "net.link.fake.max_mtu"
@ -68,45 +64,45 @@ static bool globalTapInitialized = false;
static bool fethMaxMtuAdjusted = false; static bool fethMaxMtuAdjusted = false;
MacEthernetTap::MacEthernetTap( MacEthernetTap::MacEthernetTap(
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void* data, unsigned int len),
void *arg) : void* arg)
_handler(handler), : _handler(handler)
_arg(arg), , _arg(arg)
_nwid(nwid), , _nwid(nwid)
_homePath(homePath), , _homePath(homePath)
_mtu(mtu), , _mtu(mtu)
_metric(metric), , _metric(metric)
_devNo(0), , _devNo(0)
_agentStdin(-1), , _agentStdin(-1)
_agentStdout(-1), , _agentStdout(-1)
_agentStderr(-1), , _agentStderr(-1)
_agentStdin2(-1), , _agentStdin2(-1)
_agentStdout2(-1), , _agentStdout2(-1)
_agentStderr2(-1), , _agentStderr2(-1)
_agentPid(-1), , _agentPid(-1)
_enabled(true), , _enabled(true)
_lastIfAddrsUpdate(0) , _lastIfAddrsUpdate(0)
{ {
char ethaddr[64],mtustr[16],devnostr[16],devstr[16],metricstr[16]; char ethaddr[64], mtustr[16], devnostr[16], devstr[16], metricstr[16];
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",mtu); OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", mtu);
OSUtils::ztsnprintf(metricstr,sizeof(metricstr),"%u",metric); OSUtils::ztsnprintf(metricstr, sizeof(metricstr), "%u", metric);
std::string agentPath(homePath); std::string agentPath(homePath);
agentPath.push_back(ZT_PATH_SEPARATOR); agentPath.push_back(ZT_PATH_SEPARATOR);
agentPath.append("MacEthernetTapAgent"); agentPath.append("MacEthernetTapAgent");
if (!OSUtils::fileExists(agentPath.c_str())) if (! OSUtils::fileExists(agentPath.c_str()))
throw std::runtime_error("MacEthernetTapAgent not present in ZeroTier home"); throw std::runtime_error("MacEthernetTapAgent not present in ZeroTier home");
Mutex::Lock _gl(globalTapCreateLock); // only make one at a time Mutex::Lock _gl(globalTapCreateLock); // only make one at a time
if (!fethMaxMtuAdjusted) { if (! fethMaxMtuAdjusted) {
fethMaxMtuAdjusted = true; fethMaxMtuAdjusted = true;
int old_mtu = 0; int old_mtu = 0;
size_t old_mtu_len = sizeof(old_mtu); size_t old_mtu_len = sizeof(old_mtu);
@ -116,29 +112,30 @@ MacEthernetTap::MacEthernetTap(
// Destroy all feth devices on first tap start in case ZeroTier did not exit cleanly last time. // Destroy all feth devices on first tap start in case ZeroTier did not exit cleanly last time.
// We leave interfaces less than feth100 alone in case something else is messing with feth devices. // We leave interfaces less than feth100 alone in case something else is messing with feth devices.
if (!globalTapInitialized) { if (! globalTapInitialized) {
globalTapInitialized = true; globalTapInitialized = true;
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
std::set<std::string> deleted; std::set<std::string> deleted;
if (!getifaddrs(&ifa)) { if (! getifaddrs(&ifa)) {
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
int nameLen = (int)strlen(p->ifa_name); int nameLen = (int)strlen(p->ifa_name);
// Delete feth# from feth0 to feth9999, but don't touch >10000. // Delete feth# from feth0 to feth9999, but don't touch >10000.
if ((!strncmp(p->ifa_name,"feth",4))&&(nameLen >= 5)&&(nameLen <= 8)&&(deleted.count(std::string(p->ifa_name)) == 0)) { if ((! strncmp(p->ifa_name, "feth", 4)) && (nameLen >= 5) && (nameLen <= 8) && (deleted.count(std::string(p->ifa_name)) == 0)) {
deleted.insert(std::string(p->ifa_name)); deleted.insert(std::string(p->ifa_name));
const char *args[4]; const char* args[4];
args[0] = "/sbin/ifconfig"; args[0] = "/sbin/ifconfig";
args[1] = p->ifa_name; args[1] = p->ifa_name;
args[2] = "destroy"; args[2] = "destroy";
args[3] = (char *)0; args[3] = (char*)0;
const pid_t pid = vfork(); const pid_t pid = vfork();
if (pid == 0) { if (pid == 0) {
execv(args[0],const_cast<char **>(args)); execv(args[0], const_cast<char**>(args));
_exit(-1); _exit(-1);
} else if (pid > 0) { }
else if (pid > 0) {
int rv = 0; int rv = 0;
waitpid(pid,&rv,0); waitpid(pid, &rv, 0);
} }
} }
p = p->ifa_next; p = p->ifa_next;
@ -148,15 +145,15 @@ MacEthernetTap::MacEthernetTap(
} }
unsigned int devNo = 100 + ((nwid ^ (nwid >> 32) ^ (nwid >> 48)) % 4900); unsigned int devNo = 100 + ((nwid ^ (nwid >> 32) ^ (nwid >> 48)) % 4900);
for(;;) { for (;;) {
OSUtils::ztsnprintf(devnostr,sizeof(devnostr),"%u",devNo); OSUtils::ztsnprintf(devnostr, sizeof(devnostr), "%u", devNo);
OSUtils::ztsnprintf(devstr,sizeof(devstr),"feth%u",devNo); OSUtils::ztsnprintf(devstr, sizeof(devstr), "feth%u", devNo);
bool duplicate = false; bool duplicate = false;
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
if (!getifaddrs(&ifa)) { if (! getifaddrs(&ifa)) {
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if (!strcmp(p->ifa_name,devstr)) { if (! strcmp(p->ifa_name, devstr)) {
duplicate = true; duplicate = true;
break; break;
} }
@ -168,7 +165,8 @@ MacEthernetTap::MacEthernetTap(
devNo = (devNo + 1) % 5000; devNo = (devNo + 1) % 5000;
if (devNo < 100) if (devNo < 100)
devNo = 100; devNo = 100;
} else { }
else {
_dev = devstr; _dev = devstr;
_devNo = devNo; _devNo = devNo;
break; break;
@ -196,29 +194,31 @@ MacEthernetTap::MacEthernetTap(
long apid = (long)fork(); long apid = (long)fork();
if (apid < 0) { if (apid < 0) {
throw std::runtime_error("fork failed"); throw std::runtime_error("fork failed");
} else if (apid == 0) { }
::dup2(agentStdin[0],STDIN_FILENO); else if (apid == 0) {
::dup2(agentStdout[1],STDOUT_FILENO); ::dup2(agentStdin[0], STDIN_FILENO);
::dup2(agentStderr[1],STDERR_FILENO); ::dup2(agentStdout[1], STDOUT_FILENO);
::dup2(agentStderr[1], STDERR_FILENO);
::close(agentStdin[0]); ::close(agentStdin[0]);
::close(agentStdin[1]); ::close(agentStdin[1]);
::close(agentStdout[0]); ::close(agentStdout[0]);
::close(agentStdout[1]); ::close(agentStdout[1]);
::close(agentStderr[0]); ::close(agentStderr[0]);
::close(agentStderr[1]); ::close(agentStderr[1]);
::execl(agentPath.c_str(),agentPath.c_str(),devnostr,ethaddr,mtustr,metricstr,(char *)0); ::execl(agentPath.c_str(), agentPath.c_str(), devnostr, ethaddr, mtustr, metricstr, (char*)0);
::_exit(-1); ::_exit(-1);
} else { }
else {
_agentPid = apid; _agentPid = apid;
// Wait up to 10 seconds for the subprocess to actually create the device. This prevents // Wait up to 10 seconds for the subprocess to actually create the device. This prevents
// things like routes from being created before the device exists. // things like routes from being created before the device exists.
for(int waitLoops=0;;++waitLoops) { for (int waitLoops = 0;; ++waitLoops) {
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
if (!getifaddrs(&ifa)) { if (! getifaddrs(&ifa)) {
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if ((p->ifa_name)&&(!strcmp(devstr, p->ifa_name))) { if ((p->ifa_name) && (! strcmp(devstr, p->ifa_name))) {
waitLoops = -1; waitLoops = -1;
break; break;
} }
@ -228,7 +228,8 @@ MacEthernetTap::MacEthernetTap(
} }
if (waitLoops == -1) { if (waitLoops == -1) {
break; break;
} else if (waitLoops >= 100) { // 10 seconds }
else if (waitLoops >= 100) { // 10 seconds
throw std::runtime_error("feth device creation timed out"); throw std::runtime_error("feth device creation timed out");
} }
Thread::sleep(100); Thread::sleep(100);
@ -241,61 +242,67 @@ MacEthernetTap::MacEthernetTap(
MacEthernetTap::~MacEthernetTap() MacEthernetTap::~MacEthernetTap()
{ {
char tmp[64]; char tmp[64];
const char *args[4]; const char* args[4];
pid_t pid0,pid1; pid_t pid0, pid1;
MacDNSHelper::removeDNS(_nwid); MacDNSHelper::removeDNS(_nwid);
MacDNSHelper::removeIps4(_nwid); MacDNSHelper::removeIps4(_nwid);
MacDNSHelper::removeIps6(_nwid); MacDNSHelper::removeIps6(_nwid);
Mutex::Lock _gl(globalTapCreateLock); Mutex::Lock _gl(globalTapCreateLock);
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
int ec = 0; int ec = 0;
::kill(_agentPid,SIGKILL); ::kill(_agentPid, SIGKILL);
::waitpid(_agentPid,&ec,0); ::waitpid(_agentPid, &ec, 0);
args[0] = "/sbin/ifconfig"; args[0] = "/sbin/ifconfig";
args[1] = _dev.c_str(); args[1] = _dev.c_str();
args[2] = "destroy"; args[2] = "destroy";
args[3] = (char *)0; args[3] = (char*)0;
pid0 = vfork(); pid0 = vfork();
if (pid0 == 0) { if (pid0 == 0) {
execv(args[0],const_cast<char **>(args)); execv(args[0], const_cast<char**>(args));
_exit(-1); _exit(-1);
} }
snprintf(tmp,sizeof(tmp),"feth%u",_devNo + 5000); snprintf(tmp, sizeof(tmp), "feth%u", _devNo + 5000);
//args[0] = "/sbin/ifconfig"; // args[0] = "/sbin/ifconfig";
args[1] = tmp; args[1] = tmp;
//args[2] = "destroy"; // args[2] = "destroy";
//args[3] = (char *)0; // args[3] = (char *)0;
pid1 = vfork(); pid1 = vfork();
if (pid1 == 0) { if (pid1 == 0) {
execv(args[0],const_cast<char **>(args)); execv(args[0], const_cast<char**>(args));
_exit(-1); _exit(-1);
} }
if (pid0 > 0) { if (pid0 > 0) {
int rv = 0; int rv = 0;
waitpid(pid0,&rv,0); waitpid(pid0, &rv, 0);
} }
if (pid1 > 0) { if (pid1 > 0) {
int rv = 0; int rv = 0;
waitpid(pid1,&rv,0); waitpid(pid1, &rv, 0);
} }
Thread::join(_thread); Thread::join(_thread);
} }
void MacEthernetTap::setEnabled(bool en) { _enabled = en; } void MacEthernetTap::setEnabled(bool en)
bool MacEthernetTap::enabled() const { return _enabled; } {
_enabled = en;
}
bool MacEthernetTap::enabled() const
{
return _enabled;
}
bool MacEthernetTap::addIp(const InetAddress &ip) bool MacEthernetTap::addIp(const InetAddress& ip)
{ {
char tmp[128]; char tmp[128];
if (!ip) if (! ip)
return false; return false;
std::string cmd; std::string cmd;
@ -309,18 +316,18 @@ bool MacEthernetTap::addIp(const InetAddress &ip)
uint16_t l = (uint16_t)cmd.length(); uint16_t l = (uint16_t)cmd.length();
_putLock.lock(); _putLock.lock();
write(_agentStdin,&l,2); write(_agentStdin, &l, 2);
write(_agentStdin,cmd.data(),cmd.length()); write(_agentStdin, cmd.data(), cmd.length());
_putLock.unlock(); _putLock.unlock();
return true; return true;
} }
bool MacEthernetTap::removeIp(const InetAddress &ip) bool MacEthernetTap::removeIp(const InetAddress& ip)
{ {
char tmp[128]; char tmp[128];
if (!ip) if (! ip)
return false; return false;
std::string cmd; std::string cmd;
@ -334,8 +341,8 @@ bool MacEthernetTap::removeIp(const InetAddress &ip)
uint16_t l = (uint16_t)cmd.length(); uint16_t l = (uint16_t)cmd.length();
_putLock.lock(); _putLock.lock();
write(_agentStdin,&l,2); write(_agentStdin, &l, 2);
write(_agentStdin,cmd.data(),cmd.length()); write(_agentStdin, cmd.data(), cmd.length());
_putLock.unlock(); _putLock.unlock();
return true; return true;
@ -350,25 +357,25 @@ std::vector<InetAddress> MacEthernetTap::ips() const
} }
_lastIfAddrsUpdate = now; _lastIfAddrsUpdate = now;
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
std::vector<InetAddress> r; std::vector<InetAddress> r;
if (!getifaddrs(&ifa)) { if (! getifaddrs(&ifa)) {
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if ((p->ifa_name)&&(!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)) { if ((p->ifa_name) && (! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr)) {
switch(p->ifa_addr->sa_family) { switch (p->ifa_addr->sa_family) {
case AF_INET: { case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break; } break;
case AF_INET6: { case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4]; uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break; } break;
} }
} }
@ -376,23 +383,23 @@ std::vector<InetAddress> MacEthernetTap::ips() const
} }
freeifaddrs(ifa); freeifaddrs(ifa);
} }
std::sort(r.begin(),r.end()); std::sort(r.begin(), r.end());
r.erase(std::unique(r.begin(),r.end()),r.end()); r.erase(std::unique(r.begin(), r.end()), r.end());
_ifaddrs = r; _ifaddrs = r;
return r; return r;
} }
void MacEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void MacEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{ {
struct iovec iov[3]; struct iovec iov[3];
unsigned char hdr[15]; unsigned char hdr[15];
uint16_t l; uint16_t l;
if ((_agentStdin > 0)&&(len <= _mtu)&&(_enabled)) { if ((_agentStdin > 0) && (len <= _mtu) && (_enabled)) {
hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET; hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET;
to.copyTo(hdr + 1,6); to.copyTo(hdr + 1, 6);
from.copyTo(hdr + 7,6); from.copyTo(hdr + 7, 6);
hdr[13] = (unsigned char)((etherType >> 8) & 0xff); hdr[13] = (unsigned char)((etherType >> 8) & 0xff);
hdr[14] = (unsigned char)(etherType & 0xff); hdr[14] = (unsigned char)(etherType & 0xff);
l = (uint16_t)(len + 15); l = (uint16_t)(len + 15);
@ -400,30 +407,35 @@ void MacEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,co
iov[0].iov_len = 2; iov[0].iov_len = 2;
iov[1].iov_base = hdr; iov[1].iov_base = hdr;
iov[1].iov_len = 15; iov[1].iov_len = 15;
iov[2].iov_base = const_cast<void *>(data); iov[2].iov_base = const_cast<void*>(data);
iov[2].iov_len = len; iov[2].iov_len = len;
_putLock.lock(); _putLock.lock();
writev(_agentStdin,iov,3); writev(_agentStdin, iov, 3);
_putLock.unlock(); _putLock.unlock();
} }
} }
std::string MacEthernetTap::deviceName() const { return _dev; } std::string MacEthernetTap::deviceName() const
void MacEthernetTap::setFriendlyName(const char *friendlyName) {} {
return _dev;
}
void MacEthernetTap::setFriendlyName(const char* friendlyName)
{
}
void MacEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) void MacEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{ {
std::vector<MulticastGroup> newGroups; std::vector<MulticastGroup> newGroups;
struct ifmaddrs *ifmap = (struct ifmaddrs *)0; struct ifmaddrs* ifmap = (struct ifmaddrs*)0;
if (!getifmaddrs(&ifmap)) { if (! getifmaddrs(&ifmap)) {
struct ifmaddrs *p = ifmap; struct ifmaddrs* p = ifmap;
while (p) { while (p) {
if (p->ifma_addr->sa_family == AF_LINK) { if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
} }
p = p->ifma_next; p = p->ifma_next;
} }
@ -431,18 +443,18 @@ void MacEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std:
} }
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip) for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end()); std::sort(newGroups.begin(), newGroups.end());
newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m); added.push_back(*m);
} }
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m); removed.push_back(*m);
} }
@ -457,13 +469,13 @@ void MacEthernetTap::setMtu(unsigned int mtu)
cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG);
cmd.append("mtu"); cmd.append("mtu");
cmd.push_back(0); cmd.push_back(0);
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu);
cmd.append(tmp); cmd.append(tmp);
cmd.push_back(0); cmd.push_back(0);
uint16_t l = (uint16_t)cmd.length(); uint16_t l = (uint16_t)cmd.length();
_putLock.lock(); _putLock.lock();
write(_agentStdin,&l,2); write(_agentStdin, &l, 2);
write(_agentStdin,cmd.data(),cmd.length()); write(_agentStdin, cmd.data(), cmd.length());
_putLock.unlock(); _putLock.unlock();
_mtu = mtu; _mtu = mtu;
} }
@ -471,61 +483,62 @@ void MacEthernetTap::setMtu(unsigned int mtu)
#define ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE 131072 #define ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE 131072
void MacEthernetTap::threadMain() void MacEthernetTap::threadMain() throw()
throw()
{ {
char agentReadBuf[ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE]; char agentReadBuf[ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE];
char agentStderrBuf[256]; char agentStderrBuf[256];
fd_set readfds,nullfds; fd_set readfds, nullfds;
MAC to,from; MAC to, from;
Thread::sleep(250); Thread::sleep(250);
const int nfds = std::max(std::max(_shutdownSignalPipe[0],_agentStdout),_agentStderr) + 1; const int nfds = std::max(std::max(_shutdownSignalPipe[0], _agentStdout), _agentStderr) + 1;
long agentReadPtr = 0; long agentReadPtr = 0;
fcntl(_agentStdout,F_SETFL,fcntl(_agentStdout,F_GETFL)|O_NONBLOCK); fcntl(_agentStdout, F_SETFL, fcntl(_agentStdout, F_GETFL) | O_NONBLOCK);
fcntl(_agentStderr,F_SETFL,fcntl(_agentStderr,F_GETFL)|O_NONBLOCK); fcntl(_agentStderr, F_SETFL, fcntl(_agentStderr, F_GETFL) | O_NONBLOCK);
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_ZERO(&nullfds); FD_ZERO(&nullfds);
for(;;) { for (;;) {
FD_SET(_shutdownSignalPipe[0],&readfds); FD_SET(_shutdownSignalPipe[0], &readfds);
FD_SET(_agentStdout,&readfds); FD_SET(_agentStdout, &readfds);
FD_SET(_agentStderr,&readfds); FD_SET(_agentStderr, &readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0);
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) if (FD_ISSET(_shutdownSignalPipe[0], &readfds))
break; break;
if (FD_ISSET(_agentStdout,&readfds)) { if (FD_ISSET(_agentStdout, &readfds)) {
long n = (long)read(_agentStdout,agentReadBuf + agentReadPtr,ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE - agentReadPtr); long n = (long)read(_agentStdout, agentReadBuf + agentReadPtr, ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE - agentReadPtr);
if (n > 0) { if (n > 0) {
agentReadPtr += n; agentReadPtr += n;
while (agentReadPtr >= 2) { while (agentReadPtr >= 2) {
long len = *((uint16_t *)agentReadBuf); long len = *((uint16_t*)agentReadBuf);
if (agentReadPtr >= (len + 2)) { if (agentReadPtr >= (len + 2)) {
char *msg = agentReadBuf + 2; char* msg = agentReadBuf + 2;
if ((len > 14)&&(_enabled)) { if ((len > 14) && (_enabled)) {
to.setTo(msg,6); to.setTo(msg, 6);
from.setTo(msg + 6,6); from.setTo(msg + 6, 6);
_handler(_arg,(void *)0,_nwid,from,to,ntohs(((const uint16_t *)msg)[6]),0,(const void *)(msg + 14),(unsigned int)len - 14); _handler(_arg, (void*)0, _nwid, from, to, ntohs(((const uint16_t*)msg)[6]), 0, (const void*)(msg + 14), (unsigned int)len - 14);
} }
if (agentReadPtr > (len + 2)) { if (agentReadPtr > (len + 2)) {
memmove(agentReadBuf,agentReadBuf + len + 2,agentReadPtr -= (len + 2)); memmove(agentReadBuf, agentReadBuf + len + 2, agentReadPtr -= (len + 2));
} else { }
else {
agentReadPtr = 0; agentReadPtr = 0;
} }
} else { }
else {
break; break;
} }
} }
} }
} }
if (FD_ISSET(_agentStderr,&readfds)) { if (FD_ISSET(_agentStderr, &readfds)) {
read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf)); read(_agentStderr, agentStderrBuf, sizeof(agentStderrBuf));
/* /*
const ssize_t n = read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf)); const ssize_t n = read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf));
if (n > 0) if (n > 0)
@ -544,7 +557,7 @@ void MacEthernetTap::threadMain()
::close(_shutdownSignalPipe[1]); ::close(_shutdownSignalPipe[1]);
} }
void MacEthernetTap::setDns(const char *domain, const std::vector<InetAddress> &servers) void MacEthernetTap::setDns(const char* domain, const std::vector<InetAddress>& servers)
{ {
MacDNSHelper::setDNS(this->_nwid, domain, servers); MacDNSHelper::setDNS(this->_nwid, domain, servers);
} }

View file

@ -15,55 +15,52 @@
#define ZT_OSXETHERNETTAP_HPP #define ZT_OSXETHERNETTAP_HPP
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp" #include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp" #include "../node/MulticastGroup.hpp"
#include "../node/Mutex.hpp" #include "../node/Mutex.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp" #include "EthernetTap.hpp"
#include "Thread.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <stdexcept> #include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string> #include <string>
#include <vector> #include <vector>
namespace ZeroTier { namespace ZeroTier {
class MacEthernetTap : public EthernetTap class MacEthernetTap : public EthernetTap {
{ public:
public:
MacEthernetTap( MacEthernetTap(
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg); void* arg);
virtual ~MacEthernetTap(); virtual ~MacEthernetTap();
virtual void setEnabled(bool en); virtual void setEnabled(bool en);
virtual bool enabled() const; virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip); virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress &ip); virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const; virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const; virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName); virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu); virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers); virtual void setDns(const char* domain, const std::vector<InetAddress>& servers);
void threadMain() void threadMain() throw();
throw();
private: private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void *_arg; void* _arg;
uint64_t _nwid; uint64_t _nwid;
Thread _thread; Thread _thread;
std::string _homePath; std::string _homePath;
@ -74,12 +71,11 @@ private:
unsigned int _metric; unsigned int _metric;
unsigned int _devNo; unsigned int _devNo;
int _shutdownSignalPipe[2]; int _shutdownSignalPipe[2];
int _agentStdin,_agentStdout,_agentStderr,_agentStdin2,_agentStdout2,_agentStderr2; int _agentStdin, _agentStdout, _agentStderr, _agentStdin2, _agentStdout2, _agentStderr2;
long _agentPid; long _agentPid;
volatile bool _enabled; volatile bool _enabled;
mutable std::vector<InetAddress> _ifaddrs; mutable std::vector<InetAddress> _ifaddrs;
mutable uint64_t _lastIfAddrsUpdate; mutable uint64_t _lastIfAddrsUpdate;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -11,39 +11,36 @@
*/ */
/****/ /****/
#include <stdint.h> #include "MacDNSHelper.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/cdefs.h>
#include <sys/uio.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <net/route.h> #include <errno.h>
#include <fcntl.h>
#include <net/if.h> #include <net/if.h>
#include <net/if_arp.h> #include <net/if_arp.h>
#include <net/if_dl.h> #include <net/if_dl.h>
#include <net/if_media.h> #include <net/if_media.h>
#include <sys/sysctl.h> #include <net/route.h>
#include <netinet6/in6_var.h>
#include <netinet/in_var.h>
#include <netinet/icmp6.h> #include <netinet/icmp6.h>
#include <netinet/in.h>
#include "MacDNSHelper.hpp" #include <netinet/in_var.h>
#include <netinet6/in6_var.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!? // OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!?
struct prf_ra { struct prf_ra {
@ -52,8 +49,8 @@ struct prf_ra {
u_char reserved : 6; u_char reserved : 6;
} prf_ra; } prf_ra;
#include <netinet6/nd6.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <netinet6/nd6.h>
// These are KERNEL_PRIVATE... why? // These are KERNEL_PRIVATE... why?
#ifndef SIOCAUTOCONF_START #ifndef SIOCAUTOCONF_START
@ -70,32 +67,31 @@ struct prf_ra {
// It's here because OSX 10.6 does not have this convenience function. // It's here because OSX 10.6 does not have this convenience function.
#define SALIGN (sizeof(uint32_t) - 1) #define SALIGN (sizeof(uint32_t) - 1)
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
(SALIGN + 1))
#define MAX_SYSCTL_TRY 5 #define MAX_SYSCTL_TRY 5
#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) #define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */ /* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from <sys/socket.h> */
/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */ /* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */
//#define DARWIN_COMPAT // #define DARWIN_COMPAT
//#ifdef DARWIN_COMPAT // #ifdef DARWIN_COMPAT
#define GIM_SYSCTL_MIB NET_RT_IFLIST2 #define GIM_SYSCTL_MIB NET_RT_IFLIST2
#define GIM_RTM_ADDR RTM_NEWMADDR2 #define GIM_RTM_ADDR RTM_NEWMADDR2
//#else // #else
//#define GIM_SYSCTL_MIB NET_RT_IFMALIST // #define GIM_SYSCTL_MIB NET_RT_IFMALIST
//#define GIM_RTM_ADDR RTM_NEWMADDR // #define GIM_RTM_ADDR RTM_NEWMADDR
//#endif // #endif
// Not in 10.6 includes so use our own // Not in 10.6 includes so use our own
struct _intl_ifmaddrs { struct _intl_ifmaddrs {
struct _intl_ifmaddrs *ifma_next; struct _intl_ifmaddrs* ifma_next;
struct sockaddr *ifma_name; struct sockaddr* ifma_name;
struct sockaddr *ifma_addr; struct sockaddr* ifma_addr;
struct sockaddr *ifma_lladdr; struct sockaddr* ifma_lladdr;
}; };
static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif) static inline int _intl_getifmaddrs(struct _intl_ifmaddrs** pif)
{ {
int icnt = 1; int icnt = 1;
int dcnt = 0; int dcnt = 0;
@ -104,14 +100,14 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
size_t needed; size_t needed;
int mib[6]; int mib[6];
int i; int i;
char *buf; char* buf;
char *data; char* data;
char *next; char* next;
char *p; char* p;
struct ifma_msghdr2 *ifmam; struct ifma_msghdr2* ifmam;
struct _intl_ifmaddrs *ifa, *ift; struct _intl_ifmaddrs *ifa, *ift;
struct rt_msghdr *rtm; struct rt_msghdr* rtm;
struct sockaddr *sa; struct sockaddr* sa;
mib[0] = CTL_NET; mib[0] = CTL_NET;
mib[1] = PF_ROUTE; mib[1] = PF_ROUTE;
@ -122,7 +118,7 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
do { do {
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return (-1); return (-1);
if ((buf = (char *)malloc(needed)) == NULL) if ((buf = (char*)malloc(needed)) == NULL)
return (-1); return (-1);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
@ -135,21 +131,20 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
} while (buf == NULL); } while (buf == NULL);
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next; rtm = (struct rt_msghdr*)(void*)next;
if (rtm->rtm_version != RTM_VERSION) if (rtm->rtm_version != RTM_VERSION)
continue; continue;
switch (rtm->rtm_type) { switch (rtm->rtm_type) {
case GIM_RTM_ADDR: case GIM_RTM_ADDR:
ifmam = (struct ifma_msghdr2 *)(void *)rtm; ifmam = (struct ifma_msghdr2*)(void*)rtm;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0) if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break; break;
icnt++; icnt++;
p = (char *)(ifmam + 1); p = (char*)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) { for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs & if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0)
(1 << i)) == 0)
continue; continue;
sa = (struct sockaddr *)(void *)p; sa = (struct sockaddr*)(void*)p;
len = SA_RLEN(sa); len = SA_RLEN(sa);
dcnt += len; dcnt += len;
p += len; p += len;
@ -158,54 +153,50 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
} }
} }
data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); data = (char*)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt);
if (data == NULL) { if (data == NULL) {
free(buf); free(buf);
return (-1); return (-1);
} }
ifa = (struct _intl_ifmaddrs *)(void *)data; ifa = (struct _intl_ifmaddrs*)(void*)data;
data += sizeof(struct _intl_ifmaddrs) * icnt; data += sizeof(struct _intl_ifmaddrs) * icnt;
memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt); memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt);
ift = ifa; ift = ifa;
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next; rtm = (struct rt_msghdr*)(void*)next;
if (rtm->rtm_version != RTM_VERSION) if (rtm->rtm_version != RTM_VERSION)
continue; continue;
switch (rtm->rtm_type) { switch (rtm->rtm_type) {
case GIM_RTM_ADDR: case GIM_RTM_ADDR:
ifmam = (struct ifma_msghdr2 *)(void *)rtm; ifmam = (struct ifma_msghdr2*)(void*)rtm;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0) if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break; break;
p = (char *)(ifmam + 1); p = (char*)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) { for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs & if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0)
(1 << i)) == 0)
continue; continue;
sa = (struct sockaddr *)(void *)p; sa = (struct sockaddr*)(void*)p;
len = SA_RLEN(sa); len = SA_RLEN(sa);
switch (i) { switch (i) {
case RTAX_GATEWAY: case RTAX_GATEWAY:
ift->ifma_lladdr = ift->ifma_lladdr = (struct sockaddr*)(void*)data;
(struct sockaddr *)(void *)data;
memcpy(data, p, len); memcpy(data, p, len);
data += len; data += len;
break; break;
case RTAX_IFP: case RTAX_IFP:
ift->ifma_name = ift->ifma_name = (struct sockaddr*)(void*)data;
(struct sockaddr *)(void *)data;
memcpy(data, p, len); memcpy(data, p, len);
data += len; data += len;
break; break;
case RTAX_IFA: case RTAX_IFA:
ift->ifma_addr = ift->ifma_addr = (struct sockaddr*)(void*)data;
(struct sockaddr *)(void *)data;
memcpy(data, p, len); memcpy(data, p, len);
data += len; data += len;
break; break;
@ -228,14 +219,15 @@ static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif)
ift--; ift--;
ift->ifma_next = NULL; ift->ifma_next = NULL;
*pif = ifa; *pif = ifa;
} else { }
else {
*pif = NULL; *pif = NULL;
free(ifa); free(ifa);
} }
return (0); return (0);
} }
static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp) static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs* ifmp)
{ {
free(ifmp); free(ifmp);
} }
@ -243,34 +235,34 @@ static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#include <string> #include "../node/Constants.hpp"
#include "../node/Dictionary.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "MacKextEthernetTap.hpp"
#include "OSUtils.hpp"
#include <algorithm>
#include <map> #include <map>
#include <set> #include <set>
#include <algorithm> #include <string>
#include "../node/Constants.hpp"
#include "../node/Utils.hpp"
#include "../node/Mutex.hpp"
#include "../node/Dictionary.hpp"
#include "OSUtils.hpp"
#include "MacKextEthernetTap.hpp"
// ff:ff:ff:ff:ff:ff with no ADI // ff:ff:ff:ff:ff:ff with no ADI
static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0);
static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts) static inline bool _setIpv6Stuff(const char* ifname, bool performNUD, bool acceptRouterAdverts)
{ {
struct in6_ndireq nd; struct in6_ndireq nd;
struct in6_ifreq ifr; struct in6_ifreq ifr;
int s = socket(AF_INET6,SOCK_DGRAM,0); int s = socket(AF_INET6, SOCK_DGRAM, 0);
if (s <= 0) if (s <= 0)
return false; return false;
memset(&nd,0,sizeof(nd)); memset(&nd, 0, sizeof(nd));
strncpy(nd.ifname,ifname,sizeof(nd.ifname)); strncpy(nd.ifname, ifname, sizeof(nd.ifname));
if (ioctl(s,SIOCGIFINFO_IN6,&nd)) { if (ioctl(s, SIOCGIFINFO_IN6, &nd)) {
close(s); close(s);
return false; return false;
} }
@ -279,18 +271,19 @@ static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptR
if (performNUD) if (performNUD)
nd.ndi.flags |= ND6_IFF_PERFORMNUD; nd.ndi.flags |= ND6_IFF_PERFORMNUD;
else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; else
nd.ndi.flags &= ~ND6_IFF_PERFORMNUD;
if (oldFlags != (unsigned long)nd.ndi.flags) { if (oldFlags != (unsigned long)nd.ndi.flags) {
if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) { if (ioctl(s, SIOCSIFINFO_FLAGS, &nd)) {
close(s); close(s);
return false; return false;
} }
} }
memset(&ifr,0,sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) { if (ioctl(s, acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP, &ifr)) {
close(s); close(s);
return false; return false;
} }
@ -305,71 +298,76 @@ static long globalTapsRunning = 0;
static Mutex globalTapCreateLock; static Mutex globalTapCreateLock;
MacKextEthernetTap::MacKextEthernetTap( MacKextEthernetTap::MacKextEthernetTap(
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void* data, unsigned int len),
void *arg) : void* arg)
_handler(handler), : _handler(handler)
_arg(arg), , _arg(arg)
_nwid(nwid), , _nwid(nwid)
_homePath(homePath), , _homePath(homePath)
_mtu(mtu), , _mtu(mtu)
_metric(metric), , _metric(metric)
_fd(0), , _fd(0)
_enabled(true) , _enabled(true)
{ {
char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32]; char devpath[64], ethaddr[64], mtustr[32], metstr[32], nwids[32];
struct stat stattmp; struct stat stattmp;
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid); OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", nwid);
Mutex::Lock _gl(globalTapCreateLock); Mutex::Lock _gl(globalTapCreateLock);
if (::stat("/dev/zt0",&stattmp)) { if (::stat("/dev/zt0", &stattmp)) {
long kextpid = (long)fork(); long kextpid = (long)fork();
if (kextpid == 0) { if (kextpid == 0) {
::chdir(homePath); ::chdir(homePath);
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); OSUtils::redirectUnixOutputs("/dev/null", (const char*)0);
::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0); ::execl("/sbin/kextload", "/sbin/kextload", "-q", "-repository", homePath, "tap.kext", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (kextpid > 0) { }
else if (kextpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(kextpid,&exitcode,0); ::waitpid(kextpid, &exitcode, 0);
} }
::usleep(500); // give tap device driver time to start up and try again ::usleep(500); // give tap device driver time to start up and try again
if (::stat("/dev/zt0",&stattmp)) if (::stat("/dev/zt0", &stattmp))
throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext"); throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext");
} }
// Try to reopen the last device we had, if we had one and it's still unused. // Try to reopen the last device we had, if we had one and it's still unused.
std::map<std::string,std::string> globalDeviceMap; std::map<std::string, std::string> globalDeviceMap;
FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r"); FILE* devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "r");
if (devmapf) { if (devmapf) {
char buf[256]; char buf[256];
while (fgets(buf,sizeof(buf),devmapf)) { while (fgets(buf, sizeof(buf), devmapf)) {
char *x = (char *)0; char* x = (char*)0;
char *y = (char *)0; char* y = (char*)0;
char *saveptr = (char *)0; char* saveptr = (char*)0;
for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) { for (char* f = Utils::stok(buf, "\r\n=", &saveptr); (f); f = Utils::stok((char*)0, "\r\n=", &saveptr)) {
if (!x) x = f; if (! x)
else if (!y) y = f; x = f;
else break; else if (! y)
y = f;
else
break;
} }
if ((x)&&(y)&&(x[0])&&(y[0])) if ((x) && (y) && (x[0]) && (y[0]))
globalDeviceMap[x] = y; globalDeviceMap[x] = y;
} }
fclose(devmapf); fclose(devmapf);
} }
bool recalledDevice = false; bool recalledDevice = false;
std::map<std::string,std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids); std::map<std::string, std::string>::const_iterator gdmEntry = globalDeviceMap.find(nwids);
if (gdmEntry != globalDeviceMap.end()) { if (gdmEntry != globalDeviceMap.end()) {
std::string devpath("/dev/"); devpath.append(gdmEntry->second); std::string devpath("/dev/");
if (stat(devpath.c_str(),&stattmp) == 0) { devpath.append(gdmEntry->second);
_fd = ::open(devpath.c_str(),O_RDWR); if (stat(devpath.c_str(), &stattmp) == 0) {
_fd = ::open(devpath.c_str(), O_RDWR);
if (_fd > 0) { if (_fd > 0) {
_dev = gdmEntry->second; _dev = gdmEntry->second;
recalledDevice = true; recalledDevice = true;
@ -378,15 +376,15 @@ MacKextEthernetTap::MacKextEthernetTap(
} }
// Open the first unused tap device if we didn't recall a previous one. // Open the first unused tap device if we didn't recall a previous one.
if (!recalledDevice) { if (! recalledDevice) {
for(int i=0;i<64;++i) { for (int i = 0; i < 64; ++i) {
OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/zt%d",i); OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/zt%d", i);
if (stat(devpath,&stattmp)) if (stat(devpath, &stattmp))
throw std::runtime_error("no more TAP devices available"); throw std::runtime_error("no more TAP devices available");
_fd = ::open(devpath,O_RDWR); _fd = ::open(devpath, O_RDWR);
if (_fd > 0) { if (_fd > 0) {
char foo[16]; char foo[16];
OSUtils::ztsnprintf(foo,sizeof(foo),"zt%d",i); OSUtils::ztsnprintf(foo, sizeof(foo), "zt%d", i);
_dev = foo; _dev = foo;
break; break;
} }
@ -396,43 +394,44 @@ MacKextEthernetTap::MacKextEthernetTap(
if (_fd <= 0) if (_fd <= 0)
throw std::runtime_error("unable to open TAP device or no more devices available"); throw std::runtime_error("unable to open TAP device or no more devices available");
if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) {
::close(_fd); ::close(_fd);
throw std::runtime_error("unable to set flags on file descriptor for TAP device"); throw std::runtime_error("unable to set flags on file descriptor for TAP device");
} }
// Configure MAC address and MTU, bring interface up // Configure MAC address and MTU, bring interface up
OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]);
OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu); OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", _mtu);
OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric); OSUtils::ztsnprintf(metstr, sizeof(metstr), "%u", _metric);
long cpid = (long)fork(); long cpid = (long)fork();
if (cpid == 0) { if (cpid == 0) {
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "lladdr", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
if (exitcode) { if (exitcode) {
::close(_fd); ::close(_fd);
throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface");
} }
} }
_setIpv6Stuff(_dev.c_str(),true,false); _setIpv6Stuff(_dev.c_str(), true, false);
// Set close-on-exec so that devices cannot persist if we fork/exec for update // Set close-on-exec so that devices cannot persist if we fork/exec for update
fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC);
::pipe(_shutdownSignalPipe); ::pipe(_shutdownSignalPipe);
++globalTapsRunning; ++globalTapsRunning;
globalDeviceMap[nwids] = _dev; globalDeviceMap[nwids] = _dev;
devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w"); devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "w");
if (devmapf) { if (devmapf) {
gdmEntry = globalDeviceMap.begin(); gdmEntry = globalDeviceMap.begin();
while (gdmEntry != globalDeviceMap.end()) { while (gdmEntry != globalDeviceMap.end()) {
fprintf(devmapf,"%s=%s\n",gdmEntry->first.c_str(),gdmEntry->second.c_str()); fprintf(devmapf, "%s=%s\n", gdmEntry->first.c_str(), gdmEntry->second.c_str());
++gdmEntry; ++gdmEntry;
} }
fclose(devmapf); fclose(devmapf);
@ -445,9 +444,9 @@ MacKextEthernetTap::~MacKextEthernetTap()
{ {
MacDNSHelper::removeDNS(_nwid); MacDNSHelper::removeDNS(_nwid);
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit
Thread::join(_thread); Thread::join(_thread);
for (std::thread &t : _rxThreads) { for (std::thread& t : _rxThreads) {
t.join(); t.join();
} }
::close(_fd); ::close(_fd);
@ -460,15 +459,16 @@ MacKextEthernetTap::~MacKextEthernetTap()
globalTapsRunning = 0; // sanity check -- should not be possible globalTapsRunning = 0; // sanity check -- should not be possible
char tmp[16384]; char tmp[16384];
sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext"); sprintf(tmp, "%s/%s", _homePath.c_str(), "tap.kext");
long kextpid = (long)fork(); long kextpid = (long)fork();
if (kextpid == 0) { if (kextpid == 0) {
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); OSUtils::redirectUnixOutputs("/dev/null", (const char*)0);
::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0); ::execl("/sbin/kextunload", "/sbin/kextunload", tmp, (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (kextpid > 0) { }
else if (kextpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(kextpid,&exitcode,0); ::waitpid(kextpid, &exitcode, 0);
} }
} }
} }
@ -485,40 +485,42 @@ bool MacKextEthernetTap::enabled() const
return _enabled; return _enabled;
} }
bool MacKextEthernetTap::addIp(const InetAddress &ip) bool MacKextEthernetTap::addIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return false; return false;
long cpid = (long)fork(); long cpid = (long)fork();
if (cpid == 0) { if (cpid == 0) {
char tmp[128]; char tmp[128];
::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toString(tmp),"alias",(const char *)0); ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), (ip.ss_family == AF_INET6) ? "inet6" : "inet", ip.toString(tmp), "alias", (const char*)0);
::_exit(-1); ::_exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(cpid,&exitcode,0); ::waitpid(cpid, &exitcode, 0);
return (exitcode == 0); return (exitcode == 0);
} // else return false... } // else return false...
return false; return false;
} }
bool MacKextEthernetTap::removeIp(const InetAddress &ip) bool MacKextEthernetTap::removeIp(const InetAddress& ip)
{ {
if (!ip) if (! ip)
return true; return true;
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) { for (std::vector<InetAddress>::iterator i(allIps.begin()); i != allIps.end(); ++i) {
if (*i == ip) { if (*i == ip) {
long cpid = (long)fork(); long cpid = (long)fork();
if (cpid == 0) { if (cpid == 0) {
char tmp[128]; char tmp[128];
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toIpString(tmp),"-alias",(const char *)0); execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), (ip.ss_family == AF_INET6) ? "inet6" : "inet", ip.toIpString(tmp), "-alias", (const char*)0);
_exit(-1); _exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
waitpid(cpid,&exitcode,0); waitpid(cpid, &exitcode, 0);
return (exitcode == 0); return (exitcode == 0);
} }
} }
@ -528,27 +530,27 @@ bool MacKextEthernetTap::removeIp(const InetAddress &ip)
std::vector<InetAddress> MacKextEthernetTap::ips() const std::vector<InetAddress> MacKextEthernetTap::ips() const
{ {
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
if (getifaddrs(&ifa)) if (getifaddrs(&ifa))
return std::vector<InetAddress>(); return std::vector<InetAddress>();
std::vector<InetAddress> r; std::vector<InetAddress> r;
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) {
switch(p->ifa_addr->sa_family) { switch (p->ifa_addr->sa_family) {
case AF_INET: { case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr;
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask;
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
} break; } break;
case AF_INET6: { case AF_INET6: {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr;
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask;
uint32_t b[4]; uint32_t b[4];
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); memcpy(b, nm->sin6_addr.s6_addr, sizeof(b));
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
} break; } break;
} }
} }
@ -558,22 +560,22 @@ std::vector<InetAddress> MacKextEthernetTap::ips() const
if (ifa) if (ifa)
freeifaddrs(ifa); freeifaddrs(ifa);
std::sort(r.begin(),r.end()); std::sort(r.begin(), r.end());
r.erase(std::unique(r.begin(),r.end()),r.end()); r.erase(std::unique(r.begin(), r.end()), r.end());
return r; return r;
} }
void MacKextEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void MacKextEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len)
{ {
char putBuf[ZT_MAX_MTU + 64]; char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { if ((_fd > 0) && (len <= _mtu) && (_enabled)) {
to.copyTo(putBuf,6); to.copyTo(putBuf, 6);
from.copyTo(putBuf + 6,6); from.copyTo(putBuf + 6, 6);
*((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType);
memcpy(putBuf + 14,data,len); memcpy(putBuf + 14, data, len);
len += 14; len += 14;
::write(_fd,putBuf,len); ::write(_fd, putBuf, len);
} }
} }
@ -582,23 +584,23 @@ std::string MacKextEthernetTap::deviceName() const
return _dev; return _dev;
} }
void MacKextEthernetTap::setFriendlyName(const char *friendlyName) void MacKextEthernetTap::setFriendlyName(const char* friendlyName)
{ {
} }
void MacKextEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed) void MacKextEthernetTap::scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed)
{ {
std::vector<MulticastGroup> newGroups; std::vector<MulticastGroup> newGroups;
struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0; struct _intl_ifmaddrs* ifmap = (struct _intl_ifmaddrs*)0;
if (!_intl_getifmaddrs(&ifmap)) { if (! _intl_getifmaddrs(&ifmap)) {
struct _intl_ifmaddrs *p = ifmap; struct _intl_ifmaddrs* p = ifmap;
while (p) { while (p) {
if (p->ifma_addr->sa_family == AF_LINK) { if (p->ifma_addr->sa_family == AF_LINK) {
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name;
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr;
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen)))
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0));
} }
p = p->ifma_next; p = p->ifma_next;
} }
@ -606,18 +608,18 @@ void MacKextEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
} }
std::vector<InetAddress> allIps(ips()); std::vector<InetAddress> allIps(ips());
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip) for (std::vector<InetAddress>::iterator ip(allIps.begin()); ip != allIps.end(); ++ip)
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
std::sort(newGroups.begin(),newGroups.end()); std::sort(newGroups.begin(), newGroups.end());
std::unique(newGroups.begin(),newGroups.end()); std::unique(newGroups.begin(), newGroups.end());
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(newGroups.begin()); m != newGroups.end(); ++m) {
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m))
added.push_back(*m); added.push_back(*m);
} }
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { for (std::vector<MulticastGroup>::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) {
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) if (! std::binary_search(newGroups.begin(), newGroups.end(), *m))
removed.push_back(*m); removed.push_back(*m);
} }
@ -631,45 +633,46 @@ void MacKextEthernetTap::setMtu(unsigned int mtu)
long cpid = (long)fork(); long cpid = (long)fork();
if (cpid == 0) { if (cpid == 0) {
char tmp[64]; char tmp[64];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu);
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0); execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "mtu", tmp, (const char*)0);
_exit(-1); _exit(-1);
} else if (cpid > 0) { }
else if (cpid > 0) {
int exitcode = -1; int exitcode = -1;
waitpid(cpid,&exitcode,0); waitpid(cpid, &exitcode, 0);
} }
} }
} }
void MacKextEthernetTap::threadMain() void MacKextEthernetTap::threadMain() throw()
throw()
{ {
fd_set readfds,nullfds; fd_set readfds, nullfds;
MAC to,from; MAC to, from;
int n,nfds,r; int n, nfds, r;
char getBuf[ZT_MAX_MTU + 64]; char getBuf[ZT_MAX_MTU + 64];
Thread::sleep(500); Thread::sleep(500);
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_ZERO(&nullfds); FD_ZERO(&nullfds);
nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1;
r = 0; r = 0;
for(;;) { for (;;) {
FD_SET(_shutdownSignalPipe[0],&readfds); FD_SET(_shutdownSignalPipe[0], &readfds);
FD_SET(_fd,&readfds); FD_SET(_fd, &readfds);
select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0);
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread
break; break;
if (FD_ISSET(_fd,&readfds)) { if (FD_ISSET(_fd, &readfds)) {
n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); n = (int)::read(_fd, getBuf + r, sizeof(getBuf) - r);
if (n < 0) { if (n < 0) {
if ((errno != EINTR)&&(errno != ETIMEDOUT)) if ((errno != EINTR) && (errno != ETIMEDOUT))
break; break;
} else { }
else {
// Some tap drivers like to send the ethernet frame and the // Some tap drivers like to send the ethernet frame and the
// payload in two chunks, so handle that by accumulating // payload in two chunks, so handle that by accumulating
// data until we have at least a frame. // data until we have at least a frame.
@ -679,11 +682,11 @@ void MacKextEthernetTap::threadMain()
r = _mtu + 14; r = _mtu + 14;
if (_enabled) { if (_enabled) {
to.setTo(getBuf,6); to.setTo(getBuf, 6);
from.setTo(getBuf + 6,6); from.setTo(getBuf + 6, 6);
unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); unsigned int etherType = ntohs(((const uint16_t*)getBuf)[6]);
// TODO: VLAN support // TODO: VLAN support
_handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); _handler(_arg, (void*)0, _nwid, from, to, etherType, 0, (const void*)(getBuf + 14), r - 14);
} }
r = 0; r = 0;
@ -693,7 +696,7 @@ void MacKextEthernetTap::threadMain()
} }
} }
void MacKextEthernetTap::setDns(const char *domain, const std::vector<InetAddress> &servers) void MacKextEthernetTap::setDns(const char* domain, const std::vector<InetAddress>& servers)
{ {
MacDNSHelper::setDNS(_nwid, domain, servers); MacDNSHelper::setDNS(_nwid, domain, servers);
} }

View file

@ -14,58 +14,53 @@
#ifndef ZT_MacKextEthernetTap_HPP #ifndef ZT_MacKextEthernetTap_HPP
#define ZT_MacKextEthernetTap_HPP #define ZT_MacKextEthernetTap_HPP
#include <stdio.h> #include "../node/Constants.hpp"
#include <stdlib.h> #include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/MulticastGroup.hpp"
#include "EthernetTap.hpp"
#include "Thread.hpp"
#include <stdexcept> #include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string> #include <string>
#include <vector>
#include <thread> #include <thread>
#include <vector>
#include "../node/Constants.hpp"
#include "../node/MAC.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MulticastGroup.hpp"
#include "Thread.hpp"
#include "EthernetTap.hpp"
namespace ZeroTier { namespace ZeroTier {
class MacKextEthernetTap : public EthernetTap class MacKextEthernetTap : public EthernetTap {
{ public:
public:
MacKextEthernetTap( MacKextEthernetTap(
const char *homePath, const char* homePath,
const MAC &mac, const MAC& mac,
unsigned int mtu, unsigned int mtu,
unsigned int metric, unsigned int metric,
uint64_t nwid, uint64_t nwid,
const char *friendlyName, const char* friendlyName,
void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int),
void *arg); void* arg);
virtual ~MacKextEthernetTap(); virtual ~MacKextEthernetTap();
virtual void setEnabled(bool en); virtual void setEnabled(bool en);
virtual bool enabled() const; virtual bool enabled() const;
virtual bool addIp(const InetAddress &ip); virtual bool addIp(const InetAddress& ip);
virtual bool removeIp(const InetAddress &ip); virtual bool removeIp(const InetAddress& ip);
virtual std::vector<InetAddress> ips() const; virtual std::vector<InetAddress> ips() const;
virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
virtual std::string deviceName() const; virtual std::string deviceName() const;
virtual void setFriendlyName(const char *friendlyName); virtual void setFriendlyName(const char* friendlyName);
virtual void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); virtual void scanMulticastGroups(std::vector<MulticastGroup>& added, std::vector<MulticastGroup>& removed);
virtual void setMtu(unsigned int mtu); virtual void setMtu(unsigned int mtu);
virtual void setDns(const char *domain, const std::vector<InetAddress> &servers); virtual void setDns(const char* domain, const std::vector<InetAddress>& servers);
void threadMain() throw();
void threadMain() private:
throw(); void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int);
void* _arg;
private:
void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
void *_arg;
uint64_t _nwid; uint64_t _nwid;
Thread _thread; Thread _thread;
std::string _homePath; std::string _homePath;

View file

@ -20,20 +20,20 @@
#include <string.h> #include <string.h>
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <winsock2.h>
#include <windows.h>
#include <netioapi.h>
#include <IPHlpApi.h> #include <IPHlpApi.h>
#include <netioapi.h>
#include <windows.h>
#include <winsock2.h>
#endif #endif
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#include <unistd.h> #include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <netinet/in.h> #include <unistd.h>
#include <arpa/inet.h>
#ifndef ZT_SDK #ifndef ZT_SDK
#include <net/route.h> #include <net/route.h>
#endif #endif
@ -45,11 +45,11 @@
#include <ifaddrs.h> #include <ifaddrs.h>
#endif #endif
#include <vector> #include "ManagedRoute.hpp"
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
#include <vector>
#include "ManagedRoute.hpp"
#ifdef __LINUX__ #ifdef __LINUX__
#include "LinuxNetLink.hpp" #include "LinuxNetLink.hpp"
#endif #endif
@ -62,7 +62,7 @@ namespace {
// Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1 // Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1
// If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't' // If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't'
static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right) static void _forkTarget(const InetAddress& t, InetAddress& left, InetAddress& right)
{ {
const unsigned int bits = t.netmaskBits() + 1; const unsigned int bits = t.netmaskBits() + 1;
left = t; left = t;
@ -70,26 +70,28 @@ static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &righ
if (bits <= 32) { if (bits <= 32) {
left.setPort(bits); left.setPort(bits);
right = t; right = t;
reinterpret_cast<struct sockaddr_in *>(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits))); reinterpret_cast<struct sockaddr_in*>(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits)));
right.setPort(bits); right.setPort(bits);
} else { }
else {
right.zero(); right.zero();
} }
} else if (t.ss_family == AF_INET6) { }
else if (t.ss_family == AF_INET6) {
if (bits <= 128) { if (bits <= 128) {
left.setPort(bits); left.setPort(bits);
right = t; right = t;
uint8_t *b = reinterpret_cast<uint8_t *>(reinterpret_cast<struct sockaddr_in6 *>(&right)->sin6_addr.s6_addr); uint8_t* b = reinterpret_cast<uint8_t*>(reinterpret_cast<struct sockaddr_in6*>(&right)->sin6_addr.s6_addr);
b[bits / 8] ^= 1 << (8 - (bits % 8)); b[bits / 8] ^= 1 << (8 - (bits % 8));
right.setPort(bits); right.setPort(bits);
} else { }
else {
right.zero(); right.zero();
} }
} }
} }
struct _RTE struct _RTE {
{
InetAddress target; InetAddress target;
InetAddress via; InetAddress via;
char device[128]; char device[128];
@ -102,7 +104,7 @@ struct _RTE
#define ZT_ROUTING_SUPPORT_FOUND 1 #define ZT_ROUTING_SUPPORT_FOUND 1
#ifndef ZT_SDK #ifndef ZT_SDK
static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains) static std::vector<_RTE> _getRTEs(const InetAddress& target, bool contains)
{ {
std::vector<_RTE> rtes; std::vector<_RTE> rtes;
int mib[6]; int mib[6];
@ -114,29 +116,29 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
mib[3] = 0; mib[3] = 0;
mib[4] = NET_RT_DUMP; mib[4] = NET_RT_DUMP;
mib[5] = 0; mib[5] = 0;
if (!sysctl(mib,6,NULL,&needed,NULL,0)) { if (! sysctl(mib, 6, NULL, &needed, NULL, 0)) {
if (needed <= 0) if (needed <= 0)
return rtes; return rtes;
char *buf = (char *)::malloc(needed); char* buf = (char*)::malloc(needed);
if (buf) { if (buf) {
if (!sysctl(mib,6,buf,&needed,NULL,0)) { if (! sysctl(mib, 6, buf, &needed, NULL, 0)) {
struct rt_msghdr *rtm; struct rt_msghdr* rtm;
for(char *next=buf,*end=buf+needed;next<end;) { for (char *next = buf, *end = buf + needed; next < end;) {
rtm = (struct rt_msghdr *)next; rtm = (struct rt_msghdr*)next;
char *saptr = (char *)(rtm + 1); char* saptr = (char*)(rtm + 1);
char *saend = next + rtm->rtm_msglen; char* saend = next + rtm->rtm_msglen;
InetAddress sa_t,sa_v; InetAddress sa_t, sa_v;
int deviceIndex = -9999; int deviceIndex = -9999;
bool isDefault = false; bool isDefault = false;
if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { if (((rtm->rtm_flags & RTF_LLINFO) == 0) && ((rtm->rtm_flags & RTF_HOST) == 0) && ((rtm->rtm_flags & RTF_UP) != 0) && ((rtm->rtm_flags & RTF_MULTICAST) == 0)) {
int which = 0; int which = 0;
while (saptr < saend) { while (saptr < saend) {
struct sockaddr *sa = (struct sockaddr *)saptr; struct sockaddr* sa = (struct sockaddr*)saptr;
unsigned int salen = sa->sa_len; unsigned int salen = sa->sa_len;
if (!salen) if (! salen)
break; break;
// Skip missing fields in rtm_addrs bit field // Skip missing fields in rtm_addrs bit field
@ -150,32 +152,33 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
break; break;
rtm->rtm_addrs >>= 1; rtm->rtm_addrs >>= 1;
switch(which++) { switch (which++) {
case 0: case 0:
//printf("RTA_DST\n"); // printf("RTA_DST\n");
if (sa->sa_family == AF_INET6) { if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { if ((sin6->sin6_addr.s6_addr[0] == 0xfe) && ((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) {
// BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec. // BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec.
unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff);
sin6->sin6_addr.s6_addr[2] = 0; sin6->sin6_addr.s6_addr[2] = 0;
sin6->sin6_addr.s6_addr[3] = 0; sin6->sin6_addr.s6_addr[3] = 0;
if (!sin6->sin6_scope_id) if (! sin6->sin6_scope_id)
sin6->sin6_scope_id = interfaceIndex; sin6->sin6_scope_id = interfaceIndex;
} }
#ifdef __APPLE__ #ifdef __APPLE__
isDefault = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && !(rtm->rtm_flags & RTF_IFSCOPE); isDefault = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && ! (rtm->rtm_flags & RTF_IFSCOPE);
#endif #endif
} else { }
struct sockaddr_in *sin4 = (struct sockaddr_in *)sa; else {
struct sockaddr_in* sin4 = (struct sockaddr_in*)sa;
isDefault = sin4->sin_addr.s_addr == 0; isDefault = sin4->sin_addr.s_addr == 0;
} }
sa_t = *sa; sa_t = *sa;
break; break;
case 1: case 1:
//printf("RTA_GATEWAY\n"); // printf("RTA_GATEWAY\n");
switch(sa->sa_family) { switch (sa->sa_family) {
case AF_LINK: case AF_LINK:
// deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; // deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index;
case AF_INET: case AF_INET:
@ -185,20 +188,22 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
} }
break; break;
case 2: { case 2: {
//printf("RTA_NETMASK\n"); // printf("RTA_NETMASK\n");
if (sa_t.ss_family == AF_INET6) { if (sa_t.ss_family == AF_INET6) {
salen = sizeof(struct sockaddr_in6); salen = sizeof(struct sockaddr_in6);
unsigned int bits = 0; unsigned int bits = 0;
for(int i=0;i<16;++i) { for (int i = 0; i < 16; ++i) {
unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i]; unsigned char c = (unsigned char)((const struct sockaddr_in6*)sa)->sin6_addr.s6_addr[i];
if (c == 0xff) if (c == 0xff)
bits += 8; bits += 8;
else break; else
break;
} }
sa_t.setPort(bits); sa_t.setPort(bits);
} else if (sa_t.ss_family == AF_INET) { }
else if (sa_t.ss_family == AF_INET) {
salen = sizeof(struct sockaddr_in); salen = sizeof(struct sockaddr_in);
sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr)); sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in*)sa)->sin_addr.s_addr));
} }
} break; } break;
/* /*
@ -220,18 +225,17 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
saptr += salen; saptr += salen;
} }
deviceIndex = rtm->rtm_index; deviceIndex = rtm->rtm_index;
if (((contains) && (sa_t.containsAddress(target))) || (sa_t == target)) {
if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) {
rtes.push_back(_RTE()); rtes.push_back(_RTE());
rtes.back().target = sa_t; rtes.back().target = sa_t;
rtes.back().via = sa_v; rtes.back().via = sa_v;
rtes.back().isDefault = isDefault; rtes.back().isDefault = isDefault;
if (deviceIndex >= 0) { if (deviceIndex >= 0) {
if_indextoname(deviceIndex,rtes.back().device); if_indextoname(deviceIndex, rtes.back().device);
} else { }
else {
rtes.back().device[0] = (char)0; rtes.back().device[0] = (char)0;
} }
rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount; rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount;
@ -250,41 +254,45 @@ static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
} }
#endif #endif
static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface) static void _routeCmd(const char* op, const InetAddress& target, const InetAddress& via, const char* ifscope, const char* localInterface)
{ {
// char f1[1024],f2[1024]; printf("cmd %s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface); // char f1[1024],f2[1024]; printf("cmd %s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface);
long p = (long)fork(); long p = (long)fork();
if (p > 0) { if (p > 0) {
int exitcode = -1; int exitcode = -1;
::waitpid(p,&exitcode,0); ::waitpid(p, &exitcode, 0);
} else if (p == 0) { }
else if (p == 0) {
::close(STDOUT_FILENO); ::close(STDOUT_FILENO);
::close(STDERR_FILENO); ::close(STDERR_FILENO);
char ttmp[64]; char ttmp[64];
char iptmp[64]; char iptmp[64];
if (via) { if (via) {
if ((ifscope)&&(ifscope[0])) { if ((ifscope) && (ifscope[0])) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s" ZT_EOL_S, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp)); fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s" ZT_EOL_S, ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp));
#endif #endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0); ::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, "-ifscope", ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp), (const char*)0);
} else {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s %s %s %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp));
#endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0);
} }
} else if ((localInterface)&&(localInterface[0])) { else {
if ((ifscope)&&(ifscope[0])) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s -interface %s" ZT_EOL_S, op, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface); fprintf(stderr, "DEBUG: route %s %s %s %s" ZT_EOL_S, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp));
#endif #endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0); ::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp), (const char*)0);
} else { }
}
else if ((localInterface) && (localInterface[0])) {
if ((ifscope) && (ifscope[0])) {
#ifdef ZT_TRACE #ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s %s %s -interface %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface); fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s -interface %s" ZT_EOL_S, op, ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), localInterface);
#endif #endif
::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0); ::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, "-ifscope", ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), "-interface", localInterface, (const char*)0);
}
else {
#ifdef ZT_TRACE
fprintf(stderr, "DEBUG: route %s %s %s -interface %s" ZT_EOL_S, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), localInterface);
#endif
::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), "-interface", localInterface, (const char*)0);
} }
} }
::_exit(-1); ::_exit(-1);
@ -303,7 +311,7 @@ static void _routeCmd(const char *op,const InetAddress &target,const InetAddress
#ifdef __WINDOWS__ // -------------------------------------------------------- #ifdef __WINDOWS__ // --------------------------------------------------------
#define ZT_ROUTING_SUPPORT_FOUND 1 #define ZT_ROUTING_SUPPORT_FOUND 1
static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &interfaceIndex,const InetAddress &target,const InetAddress &via) static bool _winRoute(bool del, const NET_LUID& interfaceLuid, const NET_IFINDEX& interfaceIndex, const InetAddress& target, const InetAddress& via)
{ {
MIB_IPFORWARD_ROW2 rtrow; MIB_IPFORWARD_ROW2 rtrow;
InitializeIpForwardEntry(&rtrow); InitializeIpForwardEntry(&rtrow);
@ -312,22 +320,24 @@ static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &
if (target.ss_family == AF_INET) { if (target.ss_family == AF_INET) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET; rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr; rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&target)->sin_addr.S_un.S_addr;
if (via.ss_family == AF_INET) { if (via.ss_family == AF_INET) {
rtrow.NextHop.si_family = AF_INET; rtrow.NextHop.si_family = AF_INET;
rtrow.NextHop.Ipv4.sin_family = AF_INET; rtrow.NextHop.Ipv4.sin_family = AF_INET;
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr; rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&via)->sin_addr.S_un.S_addr;
} }
} else if (target.ss_family == AF_INET6) { }
else if (target.ss_family == AF_INET6) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte,16); memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&target)->sin6_addr.u.Byte, 16);
if (via.ss_family == AF_INET6) { if (via.ss_family == AF_INET6) {
rtrow.NextHop.si_family = AF_INET6; rtrow.NextHop.si_family = AF_INET6;
rtrow.NextHop.Ipv6.sin6_family = AF_INET6; rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte,reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte,16); memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&via)->sin6_addr.u.Byte, 16);
} }
} else { }
else {
return false; return false;
} }
rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
@ -344,19 +354,22 @@ static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &
rtrow.Origin = NlroManual; rtrow.Origin = NlroManual;
if (del) { if (del) {
return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR); return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR);
} else { }
else {
NTSTATUS r = CreateIpForwardEntry2(&rtrow); NTSTATUS r = CreateIpForwardEntry2(&rtrow);
if (r == NO_ERROR) { if (r == NO_ERROR) {
return true; return true;
} else if (r == ERROR_OBJECT_ALREADY_EXISTS) { }
else if (r == ERROR_OBJECT_ALREADY_EXISTS) {
return (SetIpForwardEntry2(&rtrow) == NO_ERROR); return (SetIpForwardEntry2(&rtrow) == NO_ERROR);
} else { }
else {
return false; return false;
} }
} }
} }
static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &interfaceIndex, const InetAddress &target, const InetAddress &via) static bool _winHasRoute(const NET_LUID& interfaceLuid, const NET_IFINDEX& interfaceIndex, const InetAddress& target, const InetAddress& via)
{ {
MIB_IPFORWARD_ROW2 rtrow; MIB_IPFORWARD_ROW2 rtrow;
InitializeIpForwardEntry(&rtrow); InitializeIpForwardEntry(&rtrow);
@ -365,22 +378,24 @@ static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &inter
if (target.ss_family == AF_INET) { if (target.ss_family == AF_INET) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET; rtrow.DestinationPrefix.Prefix.si_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET;
rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&target)->sin_addr.S_un.S_addr; rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&target)->sin_addr.S_un.S_addr;
if (via.ss_family == AF_INET) { if (via.ss_family == AF_INET) {
rtrow.NextHop.si_family = AF_INET; rtrow.NextHop.si_family = AF_INET;
rtrow.NextHop.Ipv4.sin_family = AF_INET; rtrow.NextHop.Ipv4.sin_family = AF_INET;
rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in *>(&via)->sin_addr.S_un.S_addr; rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast<const struct sockaddr_in*>(&via)->sin_addr.S_un.S_addr;
} }
} else if (target.ss_family == AF_INET6) { }
else if (target.ss_family == AF_INET6) {
rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; rtrow.DestinationPrefix.Prefix.si_family = AF_INET6;
rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&target)->sin6_addr.u.Byte, 16); memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&target)->sin6_addr.u.Byte, 16);
if (via.ss_family == AF_INET6) { if (via.ss_family == AF_INET6) {
rtrow.NextHop.si_family = AF_INET6; rtrow.NextHop.si_family = AF_INET6;
rtrow.NextHop.Ipv6.sin6_family = AF_INET6; rtrow.NextHop.Ipv6.sin6_family = AF_INET6;
memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6 *>(&via)->sin6_addr.u.Byte, 16); memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast<const struct sockaddr_in6*>(&via)->sin6_addr.u.Byte, 16);
} }
} else { }
else {
return false; return false;
} }
rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); rtrow.DestinationPrefix.PrefixLength = target.netmaskBits();
@ -391,12 +406,13 @@ static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &inter
#endif // __WINDOWS__ -------------------------------------------------------- #endif // __WINDOWS__ --------------------------------------------------------
#ifndef ZT_ROUTING_SUPPORT_FOUND #ifndef ZT_ROUTING_SUPPORT_FOUND
#error "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS." #error \
"ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS."
#endif #endif
} // anonymous namespace } // anonymous namespace
ManagedRoute::ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device) ManagedRoute::ManagedRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* device)
{ {
_target = target; _target = target;
_via = via; _via = via;
@ -404,17 +420,19 @@ ManagedRoute::ManagedRoute(const InetAddress &target,const InetAddress &via,cons
if (_via.ss_family == AF_INET) { if (_via.ss_family == AF_INET) {
_via.setPort(32); _via.setPort(32);
} else if (_via.ss_family == AF_INET6) { }
else if (_via.ss_family == AF_INET6) {
_via.setPort(128); _via.setPort(128);
} }
if (_src.ss_family == AF_INET) { if (_src.ss_family == AF_INET) {
_src.setPort(32); _src.setPort(32);
} else if (_src.ss_family == AF_INET6) { }
else if (_src.ss_family == AF_INET6) {
_src.setPort(128); _src.setPort(128);
} }
Utils::scopy(_device,sizeof(_device),device); Utils::scopy(_device, sizeof(_device), device);
_systemDevice[0] = (char)0; _systemDevice[0] = (char)0;
} }
@ -442,24 +460,25 @@ bool ManagedRoute::sync()
NET_LUID interfaceLuid; NET_LUID interfaceLuid;
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
NET_IFINDEX interfaceIndex = -1; NET_IFINDEX interfaceIndex = -1;
if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR)
return false; return false;
#endif #endif
InetAddress leftt,rightt; InetAddress leftt, rightt;
if (_target.netmaskBits() == 0) // bifurcate only the default route if (_target.netmaskBits() == 0) // bifurcate only the default route
_forkTarget(_target,leftt,rightt); _forkTarget(_target, leftt, rightt);
else leftt = _target; else
leftt = _target;
#ifdef __BSD__ // ------------------------------------------------------------ #ifdef __BSD__ // ------------------------------------------------------------
if (_device[0]) { if (_device[0]) {
bool haveDevice = false; bool haveDevice = false;
struct ifaddrs *ifa = (struct ifaddrs *)0; struct ifaddrs* ifa = (struct ifaddrs*)0;
if (!getifaddrs(&ifa)) { if (! getifaddrs(&ifa)) {
struct ifaddrs *p = ifa; struct ifaddrs* p = ifa;
while (p) { while (p) {
if ((p->ifa_name)&&(!strcmp(_device, p->ifa_name))) { if ((p->ifa_name) && (! strcmp(_device, p->ifa_name))) {
haveDevice = true; haveDevice = true;
break; break;
} }
@ -467,23 +486,24 @@ bool ManagedRoute::sync()
} }
freeifaddrs(ifa); freeifaddrs(ifa);
} }
if (!haveDevice) if (! haveDevice)
return false; return false;
} }
std::vector<_RTE> rtes(_getRTEs(_target,false)); std::vector<_RTE> rtes(_getRTEs(_target, false));
bool hasRoute = false; bool hasRoute = false;
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) {
hasRoute = _target == r->target && _via.ipOnly() == r->via.ipOnly() && (strcmp(r->device,_device) == 0); hasRoute = _target == r->target && _via.ipOnly() == r->via.ipOnly() && (strcmp(r->device, _device) == 0);
if (hasRoute) { break; } if (hasRoute) {
break;
}
} }
// char buf[255]; // char buf[255];
// fprintf(stderr, "hasRoute %d %s\n", !!hasRoute, _target.toString(buf)); // fprintf(stderr, "hasRoute %d %s\n", !!hasRoute, _target.toString(buf));
if (! hasRoute) {
if (!hasRoute) {
if (_target && _target.netmaskBits() == 0) { // Allow Default if (_target && _target.netmaskBits() == 0) { // Allow Default
InetAddress newSystemVia; InetAddress newSystemVia;
char newSystemDevice[128]; char newSystemDevice[128];
@ -491,70 +511,70 @@ bool ManagedRoute::sync()
// if our routes got deleted // if our routes got deleted
// delete the systemd via that we had added with -ifscope // delete the systemd via that we had added with -ifscope
if (_systemVia && !!_systemDevice[0]) { if (_systemVia && ! ! _systemDevice[0]) {
_routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0); _routeCmd("delete", _target, _systemVia, _systemDevice, (const char*)0);
} }
_systemVia = newSystemVia; _systemVia = newSystemVia;
Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); Utils::scopy(_systemDevice, sizeof(_systemDevice), newSystemDevice);
// If macos has a network hiccup, it deletes what the route we set, and it's own physical routes. // If macos has a network hiccup, it deletes what the route we set, and it's own physical routes.
// if !hasRoute (our 0.0.0.0 has been deleted), the OS has changed stuff // if !hasRoute (our 0.0.0.0 has been deleted), the OS has changed stuff
// So don't assume _systemX are valid anymore. Always get for _system{Via,Device} // So don't assume _systemX are valid anymore. Always get for _system{Via,Device}
// Find system default route that this route should override // Find system default route that this route should override
// We need to put it back when default route is turned off // We need to put it back when default route is turned off
for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) {
if (r->via) { if (r->via) {
if ( r->isDefault == 1 && (strcmp(r->device,_device) != 0) ) { if (r->isDefault == 1 && (strcmp(r->device, _device) != 0)) {
// char buf[255]; // char buf[255];
// fprintf(stderr, "system device1 %s %s\n", r->via.toString(buf), r->device); // fprintf(stderr, "system device1 %s %s\n", r->via.toString(buf), r->device);
newSystemVia = r->via; newSystemVia = r->via;
Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); Utils::scopy(newSystemDevice, sizeof(newSystemDevice), r->device);
break; break;
} }
} }
} }
if (newSystemVia) { _systemVia = newSystemVia; } if (newSystemVia) {
_systemVia = newSystemVia;
}
if (newSystemDevice[0]) { if (newSystemDevice[0]) {
Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); Utils::scopy(_systemDevice, sizeof(_systemDevice), newSystemDevice);
} }
// if there's no newSystemVia, the OS might not have // if there's no newSystemVia, the OS might not have
// ipv4 or ipv6 connectivity. // ipv4 or ipv6 connectivity.
// we should still add our ZeroTier ipv4 or 6 routes though // we should still add our ZeroTier ipv4 or 6 routes though
if (!!_systemVia && !!_systemDevice[0]) { if (! ! _systemVia && ! ! _systemDevice[0]) {
_routeCmd("delete",_target,_systemVia,(const char *)0,(const char *)0); _routeCmd("delete", _target, _systemVia, (const char*)0, (const char*)0);
} }
_routeCmd("add",_target,_via,(const char *)0,(const char *)0); _routeCmd("add", _target, _via, (const char*)0, (const char*)0);
if (!!_systemVia && !!_systemDevice[0]) { if (! ! _systemVia && ! ! _systemDevice[0]) {
_routeCmd("add",_target,_systemVia,_systemDevice,(const char *)0); _routeCmd("add", _target, _systemVia, _systemDevice, (const char*)0);
} }
_applied[_target] = true; _applied[_target] = true;
}
} else { else {
// Do Non-Default route commands // Do Non-Default route commands
_applied[_target] = true; _applied[_target] = true;
_routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); _routeCmd("add", leftt, _via, (const char*)0, (_via) ? (const char*)0 : _device);
} }
} }
#endif // __BSD__ ------------------------------------------------------------ #endif // __BSD__ ------------------------------------------------------------
#ifdef __LINUX__ // ---------------------------------------------------------- #ifdef __LINUX__ // ----------------------------------------------------------
if ((leftt)&&(!LinuxNetLink::getInstance().routeIsSet(leftt,_via,_src,_device))) { if ((leftt) && (! LinuxNetLink::getInstance().routeIsSet(leftt, _via, _src, _device))) {
_applied[leftt] = false; // boolean unused _applied[leftt] = false; // boolean unused
LinuxNetLink::getInstance().addRoute(leftt, _via, _src, _device); LinuxNetLink::getInstance().addRoute(leftt, _via, _src, _device);
} }
if ((rightt)&&(!LinuxNetLink::getInstance().routeIsSet(rightt,_via,_src,_device))) { if ((rightt) && (! LinuxNetLink::getInstance().routeIsSet(rightt, _via, _src, _device))) {
_applied[rightt] = false; // boolean unused _applied[rightt] = false; // boolean unused
LinuxNetLink::getInstance().addRoute(rightt, _via, _src, _device); LinuxNetLink::getInstance().addRoute(rightt, _via, _src, _device);
} }
@ -563,13 +583,13 @@ bool ManagedRoute::sync()
#ifdef __WINDOWS__ // -------------------------------------------------------- #ifdef __WINDOWS__ // --------------------------------------------------------
if ( (!_applied.count(leftt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,leftt,_via)) ) { if ((! _applied.count(leftt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, leftt, _via))) {
_applied[leftt] = false; // boolean unused _applied[leftt] = false; // boolean unused
_winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); _winRoute(false, interfaceLuid, interfaceIndex, leftt, _via);
} }
if ( (rightt) && ( (!_applied.count(rightt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,rightt,_via)) ) ) { if ((rightt) && ((! _applied.count(rightt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, rightt, _via)))) {
_applied[rightt] = false; // boolean unused _applied[rightt] = false; // boolean unused
_winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); _winRoute(false, interfaceLuid, interfaceIndex, rightt, _via);
} }
#endif // __WINDOWS__ -------------------------------------------------------- #endif // __WINDOWS__ --------------------------------------------------------
@ -584,36 +604,36 @@ void ManagedRoute::remove()
NET_LUID interfaceLuid; NET_LUID interfaceLuid;
interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute
NET_IFINDEX interfaceIndex = -1; NET_IFINDEX interfaceIndex = -1;
if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR)
return; return;
#endif #endif
#ifdef __BSD__ #ifdef __BSD__
#endif // __BSD__ ------------------------------------------------------------ #endif // __BSD__ ------------------------------------------------------------
for(std::map<InetAddress,bool>::iterator r(_applied.begin());r!=_applied.end();++r) { for (std::map<InetAddress, bool>::iterator r(_applied.begin()); r != _applied.end(); ++r) {
#ifdef __BSD__ // ------------------------------------------------------------ #ifdef __BSD__ // ------------------------------------------------------------
if (_target && _target.netmaskBits() == 0) { if (_target && _target.netmaskBits() == 0) {
_routeCmd("delete",_target,_via,(const char *)0,(const char *)0); _routeCmd("delete", _target, _via, (const char*)0, (const char*)0);
if (_systemVia && _systemDevice[0]) { if (_systemVia && _systemDevice[0]) {
_routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0); _routeCmd("delete", _target, _systemVia, _systemDevice, (const char*)0);
_routeCmd("add",_target,_systemVia,(const char *)0,(const char *)0);
_routeCmd("add", _target, _systemVia, (const char*)0, (const char*)0);
} }
} else { }
_routeCmd("delete",_target,_via, (const char *)0, _via ? (const char *)0 : _device); else {
_routeCmd("delete", _target, _via, (const char*)0, _via ? (const char*)0 : _device);
} }
break; break;
#endif // __BSD__ ------------------------------------------------------------ #endif // __BSD__ ------------------------------------------------------------
#ifdef __LINUX__ // ---------------------------------------------------------- #ifdef __LINUX__ // ----------------------------------------------------------
//_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device); //_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device);
LinuxNetLink::getInstance().delRoute(r->first,_via,_src,(_via) ? (const char *)0 : _device); LinuxNetLink::getInstance().delRoute(r->first, _via, _src, (_via) ? (const char*)0 : _device);
#endif // __LINUX__ ---------------------------------------------------------- #endif // __LINUX__ ----------------------------------------------------------
#ifdef __WINDOWS__ // -------------------------------------------------------- #ifdef __WINDOWS__ // --------------------------------------------------------
_winRoute(true,interfaceLuid,interfaceIndex,r->first,_via); _winRoute(true, interfaceLuid, interfaceIndex, r->first, _via);
#endif // __WINDOWS__ -------------------------------------------------------- #endif // __WINDOWS__ --------------------------------------------------------
} }

Some files were not shown because too many files have changed in this diff Show more