From 3ceb2257e55239c87e27c4b1b721f47f6705bf07 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 19 Sep 2019 09:47:12 -0700 Subject: [PATCH] Plumb through roots via API. --- include/ZeroTierCore.h | 2108 ++++++++++++++++++++++++++++++++++++++++ include/ZeroTierOne.h | 2047 +------------------------------------- node/Constants.hpp | 22 +- node/Locator.hpp | 2 + node/Network.cpp | 2 +- node/Node.cpp | 208 +++- node/Node.hpp | 14 + node/Topology.hpp | 142 ++- service/OneService.cpp | 5 +- 9 files changed, 2480 insertions(+), 2070 deletions(-) create mode 100644 include/ZeroTierCore.h mode change 100644 => 120000 include/ZeroTierOne.h diff --git a/include/ZeroTierCore.h b/include/ZeroTierCore.h new file mode 100644 index 000000000..ab7ce51fa --- /dev/null +++ b/include/ZeroTierCore.h @@ -0,0 +1,2108 @@ +/* + * Copyright (c)2019 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2023-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +/* + * This defines the external C API for ZeroTier's core network virtualization + * engine. + */ + +#ifndef ZT_ZEROTIER_API_H +#define ZT_ZEROTIER_API_H + +#include + +/* For struct sockaddr_storage, which is referenced here. */ +#if defined(_WIN32) || defined(_WIN64) +#include +#include +#include +#else /* not Windows */ +#include +#include +#include +#include +#endif /* Windows or not */ + +/* This symbol may be defined in a build environment or before including this + * header if you need to prepend something to function specifications. */ +#ifndef ZT_SDK_API +#define ZT_SDK_API +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************/ +/* Core constants */ +/****************************************************************************/ + +/** + * Default UDP port for devices running a ZeroTier endpoint + */ +#define ZT_DEFAULT_PORT 9993 + +/** + * Minimum MTU, which is the minimum allowed by IPv6 and several specs + */ +#define ZT_MIN_MTU 1280 + +/** + * Maximum MTU for ZeroTier virtual networks + */ +#define ZT_MAX_MTU 10000 + +/** + * Minimum UDP payload size allowed + */ +#define ZT_MIN_PHYSMTU 1400 + +/** + * Default UDP payload size (physical path MTU) not including UDP and IP overhead + * + * This is small enough for PPPoE and for Google Cloud's bizarrely tiny MTUs. + * A 2800 byte payload still fits into two packets, so this should not impact + * real world throughput at all vs the previous default of 1444. + */ +#define ZT_DEFAULT_PHYSMTU 1432 + +/** + * Maximum physical UDP payload + */ +#define ZT_MAX_PHYSPAYLOAD 10100 + +/** + * Headroom for max physical MTU + */ +#define ZT_MAX_HEADROOM 224 + +/** + * Maximum payload MTU for UDP packets + */ +#define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM) + +/** + * Maximum size of a remote trace message's serialized Dictionary + */ +#define ZT_MAX_REMOTE_TRACE_SIZE 10000 + +/** + * Maximum length of network short name + */ +#define ZT_MAX_NETWORK_SHORT_NAME_LENGTH 127 + +/** + * Maximum number of pushed routes on a network (via ZT in-band mechanisms) + */ +#define ZT_MAX_NETWORK_ROUTES 64 + +/** + * Maximum number of statically assigned IP addresses (via ZT in-band mechanisms) + */ +#define ZT_MAX_ZT_ASSIGNED_ADDRESSES 32 + +/** + * Maximum number of "specialists" on a network -- bridges, anchors, etc. + */ +#define ZT_MAX_NETWORK_SPECIALISTS 256 + +/** + * Rules engine revision ID, which specifies rules engine capabilities + */ +#define ZT_RULES_ENGINE_REVISION 1 + +/** + * Maximum number of base (non-capability) network rules + */ +#define ZT_MAX_NETWORK_RULES 1024 + +/** + * Maximum number of capabilities per network per member + */ +#define ZT_MAX_NETWORK_CAPABILITIES 128 + +/** + * Maximum number of tags per network per member + */ +#define ZT_MAX_NETWORK_TAGS 128 + +/** + * Maximum number of direct network paths to a given peer + */ +#define ZT_MAX_PEER_NETWORK_PATHS 16 + +/** + * Maximum number of path configurations that can be set + */ +#define ZT_MAX_CONFIGURABLE_PATHS 32 + +/** + * Maximum number of rules per capability object + */ +#define ZT_MAX_CAPABILITY_RULES 64 + +/** + * Maximum number of certificates of ownership to assign to a single network member + */ +#define ZT_MAX_CERTIFICATES_OF_OWNERSHIP 4 + +/** + * Global maximum length for capability chain of custody (including initial issue) + */ +#define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7 + +/** + * Maximum number of multicast group subscriptions on a local virtual network interface + */ +#define ZT_MAX_MULTICAST_SUBSCRIPTIONS 1024 + +/** + * Maximum value for link quality (min is 0) + */ +#define ZT_PATH_LINK_QUALITY_MAX 255 + +/* Rule specification contants **********************************************/ + +/** + * Packet characteristics flag: packet direction, 1 if inbound 0 if outbound + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_INBOUND 0x8000000000000000ULL + +/** + * Packet characteristics flag: multicast or broadcast destination MAC + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST 0x4000000000000000ULL + +/** + * Packet characteristics flag: broadcast destination MAC + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST 0x2000000000000000ULL + +/** + * Packet characteristics flag: sending IP address has a certificate of ownership + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED 0x1000000000000000ULL + +/** + * Packet characteristics flag: sending MAC address has a certificate of ownership + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED 0x0800000000000000ULL + +/** + * Packet characteristics flag: TCP left-most reserved bit + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_0 0x0000000000000800ULL + +/** + * Packet characteristics flag: TCP middle reserved bit + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_1 0x0000000000000400ULL + +/** + * Packet characteristics flag: TCP right-most reserved bit + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_2 0x0000000000000200ULL + +/** + * Packet characteristics flag: TCP NS flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_NS 0x0000000000000100ULL + +/** + * Packet characteristics flag: TCP CWR flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_CWR 0x0000000000000080ULL + +/** + * Packet characteristics flag: TCP ECE flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ECE 0x0000000000000040ULL + +/** + * Packet characteristics flag: TCP URG flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_URG 0x0000000000000020ULL + +/** + * Packet characteristics flag: TCP ACK flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK 0x0000000000000010ULL + +/** + * Packet characteristics flag: TCP PSH flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_PSH 0x0000000000000008ULL + +/** + * Packet characteristics flag: TCP RST flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RST 0x0000000000000004ULL + +/** + * Packet characteristics flag: TCP SYN flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN 0x0000000000000002ULL + +/** + * Packet characteristics flag: TCP FIN flag + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL + +/****************************************************************************/ + +// Fields in remote trace dictionaries +#define ZT_REMOTE_TRACE_FIELD__EVENT "event" +#define ZT_REMOTE_TRACE_FIELD__NODE_ID "nodeId" +#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "packetId" +#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "packetVerb" +#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "packetTrustedPathId" +#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "packetTrustedPathApproved" +#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "packetHops" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "remoteZtAddr" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "remotePhyAddr" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "localZtAddr" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "localPhyAddr" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "localSocket" +#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "phyAddrIpScope" +#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "networkId" +#define ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR "sourceZtAddr" +#define ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR "destZtAddr" +#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "sourceMac" +#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "destMac" +#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "etherType" +#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlanId" +#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "frameLength" +#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "frameData" +#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE "filterNoTee" +#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND "filterInbound" +#define ZT_REMOTE_TRACE_FIELD__FILTER_RESULT "filterResult" +#define ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG "filterBaseRuleLog" +#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG "filterCapRuleLog" +#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID "filterMatchingCapId" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credType" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credId" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credTs" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credInfo" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "credIssuedTo" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "credRevocationTarget" +#define ZT_REMOTE_TRACE_FIELD__REASON "reason" +#define ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID "networkControllerId" + +// Event types in remote traces +#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000 +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1001 +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1002 +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1003 +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1004 +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1005 +#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO 0x1006 +#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED 0x2000 +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED 0x2001 +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED 0x2002 +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED 0x2003 +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED 0x2004 +#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT 0x2005 +#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE 0x2006 + +// Event types in remote traces in hex string form +#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1001" +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1002" +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1003" +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1004" +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1005" +#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" +#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000" +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001" +#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" +#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S "2005" +#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S "2006" + +/****************************************************************************/ +/* Structures and other types */ +/****************************************************************************/ + +/** + * Function return code: OK (0) or error results + * + * Use ZT_ResultCode_isFatal() to check for a fatal error. If a fatal error + * occurs, the node should be considered to not be working correctly. These + * indicate serious problems like an inaccessible data store or a compile + * problem. + */ +enum ZT_ResultCode +{ + /** + * Operation completed normally + */ + ZT_RESULT_OK = 0, + + /** + * Call produced no error but no action was taken + */ + ZT_RESULT_OK_IGNORED = 1, + + // Fatal errors (>100, <1000) + + /** + * Ran out of memory + */ + ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 100, + + /** + * Data store is not writable or has failed + */ + ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 101, + + /** + * Internal error (e.g. unexpected exception indicating bug or build problem) + */ + ZT_RESULT_FATAL_ERROR_INTERNAL = 102, + + // Non-fatal errors (>1000) + + /** + * Network ID not valid + */ + ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, + + /** + * The requested operation is not supported on this version or build + */ + ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, + + /** + * The requested operation was given a bad parameter or was called in an invalid state + */ + ZT_RESULT_ERROR_BAD_PARAMETER = 1002 +}; + +/** + * Macro to check for a fatal error result code + * + * @param x Result code + * @return True if result code indicates a fatal error + */ +#define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100)&&(((int)(x)) < 1000)) + +/** + * The multipath algorithm in use by this node. + */ +enum ZT_MultipathMode +{ + /** + * No active multipath. + * + * Traffic is merely sent over the strongest path. That being + * said, this mode will automatically failover in the event that a link goes down. + */ + ZT_MULTIPATH_NONE = 0, + + /** + * Traffic is randomly distributed among all active paths. + * + * Will cease sending traffic over links that appear to be stale. + */ + ZT_MULTIPATH_RANDOM = 1, + + /** + * Traffic is allocated across all active paths in proportion to their strength and + * reliability. + * + * Will cease sending traffic over links that appear to be stale. + */ + ZT_MULTIPATH_PROPORTIONALLY_BALANCED = 2, +}; + +/** + * Status codes sent to status update callback when things happen + */ +enum ZT_Event +{ + /** + * Node has been initialized + * + * This is the first event generated, and is always sent. It may occur + * before Node's constructor returns. + * + * Meta-data: none + */ + ZT_EVENT_UP = 0, + + /** + * Node appears offline + * + * This indicates that the node doesn't seem to be able to reach anything, + * or hasn't for a while. It's not a hard instantaneous thing. + * + * Meta-data: none + */ + ZT_EVENT_OFFLINE = 1, + + /** + * Node appears online + * + * This indicates that the node was offline but now seems to be able to + * reach something. Like OFFLINE it's not a hard instantaneous thing but + * more of an indicator for UI reporting purposes. + * + * Meta-data: none + */ + ZT_EVENT_ONLINE = 2, + + /** + * Node is shutting down + * + * This is generated within Node's destructor when it is being shut down. + * It's done for convenience in case you want to clean up anything during + * node shutdown in your node event handler. + * + * Meta-data: none + */ + ZT_EVENT_DOWN = 3, + + // 4 once signaled identity collision but this is no longer an error + + /** + * Trace (debugging) message + * + * These events are only generated if this is a TRACE-enabled build. + * This is for local debug traces, not remote trace diagnostics. + * + * Meta-data: C string, TRACE message + */ + ZT_EVENT_TRACE = 5, + + /** + * VERB_USER_MESSAGE received + * + * These are generated when a VERB_USER_MESSAGE packet is received via + * ZeroTier VL1. This can be used for below-VL2 in-band application + * specific signaling over the ZeroTier protocol. + * + * It's up to you to ensure that you handle these in a way that does + * not introduce a remote security vulnerability into your app! If + * your USER_MESSAGE code has a buffer overflow or other vulnerability + * then your app will be vulnerable and this is not ZT's fault. :) + * + * Meta-data: ZT_UserMessage structure + */ + ZT_EVENT_USER_MESSAGE = 6, + + /** + * Remote trace received + * + * NOTE: any node can fling a VERB_REMOTE_TRACE at you. It's up to you + * to determine if you want to do anything with it or just silently + * drop it on the floor. It's also up to you to handle these securely! + * + * Meta-data: ZT_RemoteTrace structure + */ + ZT_EVENT_REMOTE_TRACE = 7 +}; + +/** + * A root server + */ +typedef struct { + /** + * DNS name for dynamic roots or NULL for static roots + * + * If this is a static root this will be NULL and identity + * will never be NULL. For dynamic roots identity can be NULL + * if the name of this root has never been properly resolved. + */ + const char *dnsName; + + /** + * Current public identity or NULL if not known (only possible with dynamic roots) + */ + const char *identity; + + /** + * Current physical address(es) of this root + */ + const struct sockaddr_storage *addresses; + + /** + * Number of physical addresses + */ + unsigned int addressCount; + + /** + * If true, this is the current preferred root + */ + int preferred; + + /** + * If true, this root server appears online + */ + int online; +} ZT_Root; + +/** + * List of root servers + */ +typedef struct { + /** + * Number of root servers + */ + unsigned int count; + + /** + * Array of root servers + */ + ZT_Root roots[]; +} ZT_RootList; + +/** + * Payload of REMOTE_TRACE event + */ +typedef struct +{ + /** + * ZeroTier address of sender (in least significant 40 bits only) + */ + uint64_t origin; + + /** + * Null-terminated Dictionary containing key/value pairs sent by origin + * + * This *should* be a dictionary, but the implementation only checks + * that it is a valid non-empty C-style null-terminated string. Be very + * careful to use a well-tested parser to parse this as it represents + * data received from a potentially un-trusted peer on the network. + * Invalid payloads should be dropped. + * + * The contents of data[] may be modified. + */ + const char *data; + + /** + * Length of dict[] in bytes, INCLUDING terminating null + */ + unsigned int len; +} ZT_RemoteTrace; + +/** + * User message used with ZT_EVENT_USER_MESSAGE + * + * These are direct VL1 P2P messages for application use. Encryption and + * authentication in the ZeroTier protocol will guarantee the origin + * address and message content, but you are responsible for any other + * levels of authentication or access control that are required. Any node + * in the world can send you a user message! (Unless your network is air + * gapped.) + */ +typedef struct +{ + /** + * ZeroTier address of sender (least significant 40 bits) + */ + uint64_t origin; + + /** + * User message type ID + */ + uint64_t typeId; + + /** + * User message data (not including type ID) + */ + const void *data; + + /** + * Length of data in bytes + */ + unsigned int length; +} ZT_UserMessage; + +/** + * Current node status + */ +typedef struct +{ + /** + * 40-bit ZeroTier address of this node + */ + uint64_t address; + + /** + * Public identity in string-serialized form (safe to send to others) + * + * This pointer will remain valid as long as the node exists. + */ + const char *publicIdentity; + + /** + * Full identity including secret key in string-serialized form + * + * This pointer will remain valid as long as the node exists. + */ + const char *secretIdentity; + + /** + * True if some kind of connectivity appears available + */ + int online; +} ZT_NodeStatus; + +/** + * Virtual network status codes + */ +enum ZT_VirtualNetworkStatus +{ + /** + * Waiting for network configuration (also means revision == 0) + */ + ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION = 0, + + /** + * Configuration received and we are authorized + */ + ZT_NETWORK_STATUS_OK = 1, + + /** + * Netconf master told us 'nope' + */ + ZT_NETWORK_STATUS_ACCESS_DENIED = 2, + + /** + * Netconf master exists, but this virtual network does not + */ + ZT_NETWORK_STATUS_NOT_FOUND = 3, + + /** + * Initialization of network failed or other internal error + */ + ZT_NETWORK_STATUS_PORT_ERROR = 4, + + /** + * ZeroTier core version too old + */ + ZT_NETWORK_STATUS_CLIENT_TOO_OLD = 5 +}; + +/** + * Virtual network type codes + */ +enum ZT_VirtualNetworkType +{ + /** + * Private networks are authorized via certificates of membership + */ + ZT_NETWORK_TYPE_PRIVATE = 0, + + /** + * Public networks have no access control -- they'll always be AUTHORIZED + */ + ZT_NETWORK_TYPE_PUBLIC = 1 +}; + +/** + * The type of a virtual network rules table entry + * + * These must be from 0 to 63 since the most significant two bits of each + * rule type are NOT (MSB) and AND/OR. + * + * Each rule is composed of zero or more MATCHes followed by an ACTION. + * An ACTION with no MATCHes is always taken. + */ +enum ZT_VirtualNetworkRuleType +{ + // 0 to 15 reserved for actions + + /** + * Drop frame + */ + ZT_NETWORK_RULE_ACTION_DROP = 0, + + /** + * Accept and pass frame + */ + ZT_NETWORK_RULE_ACTION_ACCEPT = 1, + + /** + * Forward a copy of this frame to an observer (by ZT address) + */ + ZT_NETWORK_RULE_ACTION_TEE = 2, + + /** + * Exactly like TEE but mandates ACKs from observer + */ + ZT_NETWORK_RULE_ACTION_WATCH = 3, + + /** + * Drop and redirect this frame to another node (by ZT address) + */ + ZT_NETWORK_RULE_ACTION_REDIRECT = 4, + + /** + * Stop evaluating rule set (drops unless there are capabilities, etc.) + */ + ZT_NETWORK_RULE_ACTION_BREAK = 5, + + /** + * Place a matching frame in the specified QoS bucket + */ + ZT_NETWORK_RULE_ACTION_PRIORITY = 6, + + /** + * Maximum ID for an ACTION, anything higher is a MATCH + */ + ZT_NETWORK_RULE_ACTION__MAX_ID = 15, + + // 16 to 63 reserved for match criteria + + ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS = 24, + ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS = 25, + ZT_NETWORK_RULE_MATCH_VLAN_ID = 26, + ZT_NETWORK_RULE_MATCH_VLAN_PCP = 27, + ZT_NETWORK_RULE_MATCH_VLAN_DEI = 28, + ZT_NETWORK_RULE_MATCH_MAC_SOURCE = 29, + ZT_NETWORK_RULE_MATCH_MAC_DEST = 30, + ZT_NETWORK_RULE_MATCH_IPV4_SOURCE = 31, + ZT_NETWORK_RULE_MATCH_IPV4_DEST = 32, + ZT_NETWORK_RULE_MATCH_IPV6_SOURCE = 33, + ZT_NETWORK_RULE_MATCH_IPV6_DEST = 34, + ZT_NETWORK_RULE_MATCH_IP_TOS = 35, + ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 36, + ZT_NETWORK_RULE_MATCH_ETHERTYPE = 37, + ZT_NETWORK_RULE_MATCH_ICMP = 38, + ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 39, + ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 40, + ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 41, + ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 42, + ZT_NETWORK_RULE_MATCH_RANDOM = 43, + ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 44, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 45, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, + ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, + ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49, + ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50, + ZT_NETWORK_RULE_MATCH_INTEGER_RANGE = 51, + + /** + * Maximum ID allowed for a MATCH entry in the rules table + */ + ZT_NETWORK_RULE_MATCH__MAX_ID = 63 +}; + +/** + * Network flow rule + * + * Rules are stored in a table in which one or more match entries is followed + * by an action. If more than one match precedes an action, the rule is + * the AND of all matches. An action with no match is always taken since it + * matches anything. If nothing matches, the default action is DROP. + * + * 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. + */ +typedef struct +{ + /** + * Type and flags + * + * Bits are: NOTTTTTT + * + * N - If true, sense of match is inverted (no effect on actions) + * O - If true, result is ORed with previous instead of ANDed (no effect on actions) + * T - Rule or action type + * + * AND with 0x3f to get type, 0x80 to get NOT bit, and 0x40 to get OR bit. + */ + uint8_t t; + + /** + * Union containing the value of this rule -- which field is used depends on 't' + */ + union { + /** + * IPv6 address in big-endian / network byte order and netmask bits + */ + struct { + uint8_t ip[16]; + uint8_t mask; + } ipv6; + + /** + * IPv4 address in big-endian / network byte order + */ + struct { + uint32_t ip; + uint8_t mask; + } ipv4; + + /** + * Integer range match in packet payload + * + * This allows matching of ranges of integers up to 64 bits wide where + * the range is +/- INT32_MAX. It's packed this way so it fits in 16 + * bytes and doesn't enlarge the overall size of this union. + */ + struct { + uint64_t start; // integer range start + uint32_t end; // end of integer range (relative to start, inclusive, 0 for equality w/start) + uint16_t idx; // index in packet of integer + uint8_t format; // bits in integer (range 1-64, ((format&63)+1)) and endianness (MSB 1 for little, 0 for big) + } intRange; + + /** + * Packet characteristic flags being matched + */ + uint64_t characteristics; + + /** + * IP port range -- start-end inclusive -- host byte order + */ + uint16_t port[2]; + + /** + * 40-bit ZeroTier address (in least significant bits, host byte order) + */ + uint64_t zt; + + /** + * 0 = never, UINT32_MAX = always + */ + uint32_t randomProbability; + + /** + * 48-bit Ethernet MAC address in big-endian order + */ + uint8_t mac[6]; + + /** + * VLAN ID in host byte order + */ + uint16_t vlanId; + + /** + * VLAN PCP (least significant 3 bits) + */ + uint8_t vlanPcp; + + /** + * VLAN DEI (single bit / boolean) + */ + uint8_t vlanDei; + + /** + * Ethernet type in host byte order + */ + uint16_t etherType; + + /** + * IP protocol + */ + uint8_t ipProtocol; + + /** + * IP type of service a.k.a. DSCP field + */ + struct { + uint8_t mask; + uint8_t value[2]; + } ipTos; + + /** + * Ethernet packet size in host byte order (start-end, inclusive) + */ + uint16_t frameSize[2]; + + /** + * ICMP type and code + */ + struct { + uint8_t type; // ICMP type, always matched + uint8_t code; // ICMP code if matched + uint8_t flags; // flag 0x01 means also match code, otherwise only match type + } icmp; + + /** + * For tag-related rules + */ + struct { + uint32_t id; + uint32_t value; + } tag; + + /** + * Destinations for TEE and REDIRECT + */ + struct { + uint64_t address; + uint32_t flags; + uint16_t length; + } fwd; + + /** + * Quality of Service (QoS) bucket we want a frame to be placed in + */ + uint8_t qosBucket; + } v; +} ZT_VirtualNetworkRule; + +/** + * A route to be pushed on a virtual network + */ +typedef struct +{ + /** + * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default + */ + struct sockaddr_storage target; + + /** + * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) + */ + struct sockaddr_storage via; + + /** + * Route flags + */ + uint16_t flags; + + /** + * Route metric (not currently used) + */ + uint16_t metric; +} ZT_VirtualNetworkRoute; + +/** + * An Ethernet multicast group + */ +typedef struct +{ + /** + * MAC address (least significant 48 bits) + */ + uint64_t mac; + + /** + * Additional distinguishing information (usually zero) + */ + unsigned long adi; +} ZT_MulticastGroup; + +/** + * Virtual network configuration update type + */ +enum ZT_VirtualNetworkConfigOperation +{ + /** + * Network is coming up (either for the first time or after service restart) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP = 1, + + /** + * Network configuration has been updated + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE = 2, + + /** + * Network is going down (not permanently) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN = 3, + + /** + * Network is going down permanently (leave/delete) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 +}; + +/** + * What trust hierarchy role does this peer have? + */ +enum ZT_PeerRole +{ + ZT_PEER_ROLE_LEAF = 0, // ordinary node + ZT_PEER_ROLE_MOON = 1, // moon root + ZT_PEER_ROLE_PLANET = 2 // planetary root +}; + +/** + * DNS record types for reporting DNS results + * + * These integer IDs (other than end of results) are the same as the DNS protocol's + * internal IDs. Not all of these are used by ZeroTier, and not all DNS record types + * are listed here. These are just common ones that are used now or may be used in + * the future for some purpose. + */ +enum ZT_DNSRecordType +{ + ZT_DNS_RECORD__END_OF_RESULTS = 0, + ZT_DNS_RECORD_A = 1, + ZT_DNS_RECORD_NS = 2, + ZT_DNS_RECORD_CNAME = 5, + ZT_DNS_RECORD_PTR = 12, + ZT_DNS_RECORD_MX = 15, + ZT_DNS_RECORD_TXT = 16, + ZT_DNS_RECORD_AAAA = 28, + ZT_DNS_RECORD_LOC = 29, + ZT_DNS_RECORD_SRV = 33, + ZT_DNS_RECORD_DNAME = 39 +}; + +/** + * Virtual network configuration + */ +typedef struct +{ + /** + * 64-bit ZeroTier network ID + */ + uint64_t nwid; + + /** + * Ethernet MAC (48 bits) that should be assigned to port + */ + uint64_t mac; + + /** + * Network name (from network configuration master) + */ + char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; + + /** + * Network configuration request status + */ + enum ZT_VirtualNetworkStatus status; + + /** + * Network type + */ + enum ZT_VirtualNetworkType type; + + /** + * Maximum interface MTU + */ + unsigned int mtu; + + /** + * If nonzero, the network this port belongs to indicates DHCP availability + * + * This is a suggestion. The underlying implementation is free to ignore it + * for security or other reasons. This is simply a netconf parameter that + * means 'DHCP is available on this network.' + */ + int dhcp; + + /** + * If nonzero, this port is allowed to bridge to other networks + * + * This is informational. If this is false (0), bridged packets will simply + * be dropped and bridging won't work. + */ + int bridge; + + /** + * If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic + */ + int broadcastEnabled; + + /** + * If the network is in PORT_ERROR state, this is the (negative) error code most recently reported + */ + int portError; + + /** + * Revision number as reported by controller or 0 if still waiting for config + */ + unsigned long netconfRevision; + + /** + * Number of assigned addresses + */ + unsigned int assignedAddressCount; + + /** + * ZeroTier-assigned addresses (in sockaddr_storage structures) + * + * For IP, the port number of the sockaddr_XX structure contains the number + * of bits in the address netmask. Only the IP address and port are used. + * Other fields like interface number can be ignored. + * + * This is only used for ZeroTier-managed address assignments sent by the + * virtual network's configuration master. + */ + struct sockaddr_storage assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; + + /** + * Number of ZT-pushed routes + */ + unsigned int routeCount; + + /** + * Routes (excluding those implied by assigned addresses and their masks) + */ + ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; + + /** + * Number of multicast groups subscribed + */ + unsigned int multicastSubscriptionCount; + + /** + * Multicast groups to which this network's device is subscribed + */ + struct { + uint64_t mac; /* MAC in lower 48 bits */ + uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */ + } multicastSubscriptions[ZT_MAX_MULTICAST_SUBSCRIPTIONS]; +} ZT_VirtualNetworkConfig; + +/** + * A list of networks + */ +typedef struct +{ + ZT_VirtualNetworkConfig *networks; + unsigned long networkCount; +} ZT_VirtualNetworkList; + +/** + * Physical path configuration + */ +typedef struct { + /** + * If non-zero set this physical network path to be trusted to disable encryption and authentication + */ + uint64_t trustedPathId; + + /** + * Physical path MTU from ZT_MIN_PHYSMTU and ZT_MAX_PHYSMTU or <= 0 to use default + */ + int mtu; +} ZT_PhysicalPathConfiguration; + +/** + * Physical network path to a peer + */ +typedef struct +{ + /** + * Address of endpoint + */ + struct sockaddr_storage address; + + /** + * Time of last send in milliseconds or 0 for never + */ + uint64_t lastSend; + + /** + * Time of last receive in milliseconds or 0 for never + */ + uint64_t lastReceive; + + /** + * Is this a trusted path? If so this will be its nonzero ID. + */ + uint64_t trustedPathId; + + /** + * One-way latency + */ + float latency; + + /** + * How much latency varies over time + */ + float packetDelayVariance; + + /** + * How much observed throughput varies over time + */ + float throughputDisturbCoeff; + + /** + * Packet Error Ratio (PER) + */ + float packetErrorRatio; + + /** + * Packet Loss Ratio (PLR) + */ + float packetLossRatio; + + /** + * Stability of the path + */ + float stability; + + /** + * Current throughput (moving average) + */ + uint64_t throughput; + + /** + * Maximum observed throughput for this path + */ + uint64_t maxThroughput; + + /** + * Percentage of traffic allocated to this path + */ + float allocation; + + /** + * Name of physical interface (for monitoring) + */ + char *ifname; + + /** + * Is path expired? + */ + int expired; + + /** + * Is path preferred? + */ + int preferred; +} ZT_PeerPhysicalPath; + +/** + * Peer status result buffer + */ +typedef struct +{ + /** + * ZeroTier address (40 bits) + */ + uint64_t address; + + /** + * Remote major version or -1 if not known + */ + int versionMajor; + + /** + * Remote minor version or -1 if not known + */ + int versionMinor; + + /** + * Remote revision or -1 if not known + */ + int versionRev; + + /** + * Last measured latency in milliseconds or -1 if unknown + */ + int latency; + + /** + * What trust hierarchy role does this device have? + */ + enum ZT_PeerRole role; + + /** + * Number of paths (size of paths[]) + */ + unsigned int pathCount; + + /** + * Whether this peer was ever reachable via an aggregate link + */ + bool hadAggregateLink; + + /** + * Known network paths to peer + */ + ZT_PeerPhysicalPath paths[ZT_MAX_PEER_NETWORK_PATHS]; +} ZT_Peer; + +/** + * List of peers + */ +typedef struct +{ + ZT_Peer *peers; + unsigned long peerCount; +} ZT_PeerList; + +/** + * ZeroTier core state objects + */ +enum ZT_StateObjectType +{ + /** + * Null object -- ignored + */ + ZT_STATE_OBJECT_NULL = 0, + + /** + * Public address and public key + * + * Object ID: this node's address if known, or 0 if unknown (first query) + * Canonical path: /identity.public + * Persistence: required + */ + ZT_STATE_OBJECT_IDENTITY_PUBLIC = 1, + + /** + * Full identity with secret key + * + * Object ID: this node's address if known, or 0 if unknown (first query) + * Canonical path: /identity.secret + * Persistence: required, should be stored with restricted permissions e.g. mode 0600 on *nix + */ + ZT_STATE_OBJECT_IDENTITY_SECRET = 2, + + /** + * Peer and related state + * + * Object ID: peer address + * Canonical path: /peers.d/ (10-digit address + * Persistence: optional, can be cleared at any time + */ + ZT_STATE_OBJECT_PEER = 5, + + /** + * Network configuration + * + * Object ID: peer address + * Canonical path: /networks.d/.conf (16-digit hex ID) + * Persistence: required if network memberships should persist + */ + ZT_STATE_OBJECT_NETWORK_CONFIG = 6, + + /** + * Root list + * + * Object ID: 0 + * Canonical path: /roots + * Persitence: required if root settings should persist + */ + ZT_STATE_OBJECT_ROOT_LIST = 7 +}; + +/** + * An instance of a ZeroTier One node (opaque) + */ +typedef void ZT_Node; + +/****************************************************************************/ +/* Callbacks used by Node API */ +/****************************************************************************/ + +/** + * Callback called to update virtual network port configuration + * + * This can be called at any time to update the configuration of a virtual + * network port. The parameter after the network ID specifies whether this + * port is being brought up, updated, brought down, or permanently deleted. + * + * This in turn should be used by the underlying implementation to create + * and configure tap devices at the OS (or virtual network stack) layer. + * + * The supplied config pointer is not guaranteed to remain valid, so make + * a copy if you want one. + * + * This should not call multicastSubscribe() or other network-modifying + * methods, as this could cause a deadlock in multithreaded or interrupt + * driven environments. + * + * This must return 0 on success. It can return any OS-dependent error code + * on failure, and this results in the network being placed into the + * PORT_ERROR state. + */ +typedef int (*ZT_VirtualNetworkConfigFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + uint64_t, /* Network ID */ + void **, /* Modifiable network user PTR */ + enum ZT_VirtualNetworkConfigOperation, /* Config operation */ + const ZT_VirtualNetworkConfig *); /* Network configuration */ + +/** + * Function to send a frame out to a virtual network port + * + * Parameters: (1) node, (2) user ptr, (3) network ID, (4) source MAC, + * (5) destination MAC, (6) ethertype, (7) VLAN ID, (8) frame data, + * (9) frame length. + */ +typedef void (*ZT_VirtualNetworkFrameFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + uint64_t, /* Network ID */ + void **, /* Modifiable network user PTR */ + uint64_t, /* Source MAC */ + uint64_t, /* Destination MAC */ + unsigned int, /* Ethernet type */ + unsigned int, /* VLAN ID (0 for none) */ + const void *, /* Frame data */ + unsigned int); /* Frame length */ + +/** + * Callback for events + * + * Events are generated when the node's status changes in a significant way + * and on certain non-fatal errors and events of interest. The final void + * parameter points to event meta-data. The type of event meta-data (and + * whether it is present at all) is event type dependent. See the comments + * in the definition of ZT_Event. + */ +typedef void (*ZT_EventCallback)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + enum ZT_Event, /* Event type */ + const void *); /* Event payload (if applicable) */ + +/** + * Callback for storing and/or publishing state information + * + * See ZT_StateObjectType docs for information about each state object type + * and when and if it needs to be persisted. + * + * An object of length -1 is sent to indicate that an object should be + * deleted. + */ +typedef void (*ZT_StatePutFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + enum ZT_StateObjectType, /* State object type */ + const uint64_t [2], /* State object ID (if applicable) */ + const void *, /* State object data */ + int); /* Length of data or -1 to delete */ + +/** + * Callback for retrieving stored state information + * + * This function should return the number of bytes actually stored to the + * buffer or -1 if the state object was not found or the buffer was too + * small to store it. + */ +typedef int (*ZT_StateGetFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + enum ZT_StateObjectType, /* State object type */ + const uint64_t [2], /* State object ID (if applicable) */ + void *, /* Buffer to store state object data */ + unsigned int); /* Length of data buffer in bytes */ + +/** + * Function to send a ZeroTier packet out over the physical wire (L2/L3) + * + * Parameters: + * (1) Node + * (2) User pointer + * (3) Local socket or -1 for "all" or "any" + * (4) Remote address + * (5) Packet data + * (6) Packet length + * (7) Desired IP TTL or 0 to use default + * + * If there is only one local socket, the local socket can be ignored. + * If the local socket is -1, the packet should be sent out from all + * bound local sockets or a random bound local socket. + * + * If TTL is nonzero, packets should have their IP TTL value set to this + * value if possible. If this is not possible it is acceptable to ignore + * this value and send anyway with normal or default TTL. + * + * The function must return zero on success and may return any error code + * on failure. Note that success does not (of course) guarantee packet + * delivery. It only means that the packet appears to have been sent. + */ +typedef int (*ZT_WirePacketSendFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + int64_t, /* Local socket */ + const struct sockaddr_storage *, /* Remote address */ + const void *, /* Packet data */ + unsigned int, /* Packet length */ + unsigned int); /* TTL or 0 to use default */ + +/** + * Function to check whether a path should be used for ZeroTier traffic + * + * Parameters: + * (1) Node + * (2) User pointer + * (3) ZeroTier address or 0 for none/any + * (4) Local socket or -1 if unknown + * (5) Remote address + * + * This function must return nonzero (true) if the path should be used. + * + * If no path check function is specified, ZeroTier will still exclude paths + * that overlap with ZeroTier-assigned and managed IP address blocks. But the + * use of a path check function is recommended to ensure that recursion does + * not occur in cases where addresses are assigned by the OS or managed by + * an out of band mechanism like DHCP. The path check function should examine + * all configured ZeroTier interfaces and check to ensure that the supplied + * addresses will not result in ZeroTier traffic being sent over a ZeroTier + * interface (recursion). + */ +typedef int (*ZT_PathCheckFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + uint64_t, /* ZeroTier address */ + int64_t, /* Local socket or -1 if unknown */ + const struct sockaddr_storage *); /* Remote address */ + +/** + * Function to get physical addresses for ZeroTier peers + * + * Parameters: + * (1) Node + * (2) User pointer + * (3) ZeroTier address (least significant 40 bits) + * (4) Desired address family or -1 for any + * (5) Buffer to fill with result + * + * If provided this function will be occasionally called to get physical + * addresses that might be tried to reach a ZeroTier address. It must + * return a nonzero (true) value if the result buffer has been filled + * with an address. + */ +typedef int (*ZT_PathLookupFunction)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + uint64_t, /* ZeroTier address (40 bits) */ + int, /* Desired ss_family or -1 for any */ + struct sockaddr_storage *); /* Result buffer */ + +/** + * Function to request an asynchronous DNS TXT lookup + * + * Parameters: + * (1) Node + * (2) User pointer + * (3) Thread pointer + * (4) Array of DNS record types we want + * (5) Number of DNS record types in array + * (6) DNS name to fetch + * (7) DNS request ID to supply to ZT_Node_processDNSResult() + * + * DNS is not handled in the core because every platform and runtime + * typically has its own DNS functions or libraries and these may need + * to interface with OS or network services in your local environment. + * Instead this function and its result submission counterpart are + * provided so you can provide a DNS implementation. + * + * If this callback is set in your callback struct to a NULL value, + * DNS will not be available. The ZeroTier protocol is designed to + * work in the absence of DNS but you may not get optimal results. For + * example you may default to root servers that are not geographically + * optimal or your node may cease to function if a root server's IP + * changes and there's no way to signal this. + * + * This function requests resolution of a DNS record. The result + * submission method ZT_Node_processDNSResult() must be called at + * least once in response. See its documentation. + * + * Right now ZeroTier only requests resolution of TXT records, but + * it's possible that this will change in the future. + * + * It's safe to call processDNSResult() from within your handler + * for this function. + */ +typedef void (*ZT_DNSResolver)( + ZT_Node *, /* Node */ + void *, /* User ptr */ + void *, /* Thread ptr */ + const enum ZT_DNSRecordType *, /* DNS record type(s) to fetch */ + unsigned int, /* Number of DNS record type(s) */ + const char *, /* DNS name to fetch */ + uintptr_t); /* Request ID for returning results */ + +/****************************************************************************/ +/* C Node API */ +/****************************************************************************/ + +/** + * Structure for configuring ZeroTier core callback functions + */ +struct ZT_Node_Callbacks +{ + /** + * REQUIRED: Function to store and/or replicate state objects + */ + ZT_StatePutFunction statePutFunction; + + /** + * REQUIRED: Function to retrieve state objects from an object store + */ + ZT_StateGetFunction stateGetFunction; + + /** + * REQUIRED: Function to send packets over the physical wire + */ + ZT_WirePacketSendFunction wirePacketSendFunction; + + /** + * REQUIRED: Function to inject frames into a virtual network's TAP + */ + ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; + + /** + * REQUIRED: Function to be called when virtual networks are configured or changed + */ + ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; + + /** + * REQUIRED: Function to be called to notify external code of important events + */ + ZT_EventCallback eventCallback; + + /** + * STRONGLY RECOMMENDED: Function to request a DNS lookup + */ + ZT_DNSResolver dnsResolver; + + /** + * OPTIONAL: Function to check whether a given physical path should be used + */ + ZT_PathCheckFunction pathCheckFunction; + + /** + * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses + */ + ZT_PathLookupFunction pathLookupFunction; +}; + +/** + * Create a new ZeroTier node + * + * This will attempt to load its identity via the state get function in the + * callback struct. If that fails it will generate a new identity and store + * it. Identity generation can take anywhere from a few hundred milliseconds + * to a few seconds depending on your CPU speed. + * + * @param node Result: pointer is set to new node instance on success + * @param uptr User pointer to pass to functions/callbacks + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call + * @param callbacks Callback function configuration + * @param now Current clock in milliseconds + * @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); + +/** + * Delete a node and free all resources it consumes + * + * If you are using multiple threads, all other threads must be shut down + * first. This can crash if processXXX() methods are in progress. + * + * @param node Node to delete + */ +ZT_SDK_API void ZT_Node_delete(ZT_Node *node); + +/** + * Process a packet received from the physical wire + * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call + * @param now Current clock in milliseconds + * @param localSocket Local socket (you can use 0 if only one local socket is bound and ignore this) + * @param remoteAddress Origin of packet + * @param packetData Packet data + * @param packetLength Packet length + * @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 + */ +ZT_SDK_API enum ZT_ResultCode 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); + +/** + * Process a frame from a virtual network port (tap) + * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call + * @param now Current clock in milliseconds + * @param nwid ZeroTier 64-bit virtual network ID + * @param sourceMac Source MAC address (least significant 48 bits) + * @param destMac Destination MAC address (least significant 48 bits) + * @param etherType 16-bit Ethernet frame type + * @param vlanId 10-bit VLAN ID or 0 if none + * @param frameData Frame payload data + * @param frameLength Frame payload length + * @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 + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( + ZT_Node *node, + void *tptr, + int64_t now, + uint64_t nwid, + uint64_t sourceMac, + uint64_t destMac, + unsigned int etherType, + unsigned int vlanId, + const void *frameData, + unsigned int frameLength, + volatile int64_t *nextBackgroundTaskDeadline); + +/** + * Perform periodic background operations + * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call + * @param now Current clock in milliseconds + * @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 + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks( + ZT_Node *node, + void *tptr, + int64_t now, + volatile int64_t *nextBackgroundTaskDeadline); + +/** + * Submit the result(s) of a requested DNS query + * + * This MUST be called at least once after the node requsts DNS resolution. + * If there are no results or DNS is not implemented or available, just + * send one ZT_DNS_RECORD__END_OF_RESULTS to signal that no results were + * obtained. + * + * If result is non-NULL but resultLength is zero then result is assumed to + * be a C string terminated by a zero. Passing an unterminated string with a + * zero resultLength will result in a crash. + * + * The results of A and AAAA records can be returned as either strings or + * binary IP address bytes (network byte order). If the result is a string, + * resultLength must be 0 to signal that result is a C string. Otherwise for + * A resultLength must be 4 and for AAAA it must be 16 if the result is + * in binary format. + * + * The Node implementation makes an effort to ignore obviously invalid + * submissions like an AAAA record in bianry form with length 25, but this + * is not guaranteed. It's possible to crash your program by calling this + * with garbage inputs. + * + * Results may be submitted in any order and order should not be assumed + * to have any meaning. + * + * The ZT_DNS_RECORD__END_OF_RESULTS pseudo-response must be sent after all + * results have been submitted. The result and resultLength paramters are + * ignored for this type ID. + * + * It is safe to call this function from inside the DNS request callback, + * such as to return a locally cached result or a result from some kind + * of local database. It's also safe to call this function from threads + * other than the one that received the DNS request. + * + * @param node Node instance that requested DNS resolution + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call + * @param dnsRequestID Request ID supplied to DNS request callback + * @param name DNS name + * @param recordType Record type of this result + * @param result Result (content depends on record type) + * @param resultLength Length of result + * @param resultIsString If non-zero, IP results for A and AAAA records are being given as C strings not binary IPs + */ +ZT_SDK_API void ZT_Node_processDNSResult( + ZT_Node *node, + void *tptr, + uintptr_t dnsRequestID, + const char *name, + enum ZT_DNSRecordType recordType, + const void *result, + unsigned int resultLength, + int resultIsString); + +/** + * Join a network + * + * This may generate calls to the port config callback before it returns, + * or these may be differed if a netconf is not available yet. + * + * If we are already a member of the network, nothing is done and OK is + * returned. + * + * @param node Node instance + * @param nwid 64-bit ZeroTier network ID + * @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 + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr); + +/** + * Leave a network + * + * If a port has been configured for this network this will generate a call + * to the port config callback with a NULL second parameter to indicate that + * the port is now deleted. + * + * The uptr parameter is optional and is NULL by default. If it is not NULL, + * the pointer it points to is set to this network's uptr on success. + * + * @param node Node instance + * @param nwid 64-bit network ID + * @param uptr Target pointer is set to uptr (if not NULL) + * @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); + +/** + * Subscribe to an Ethernet multicast group + * + * ADI stands for additional distinguishing information. This defaults to zero + * and is rarely used. Right now its only use is to enable IPv4 ARP to scale, + * and this must be done. + * + * For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the + * broadcast address) but with an ADI equal to each IPv4 address in host + * byte order. This converts ARP from a non-scalable broadcast protocol to + * a scalable multicast protocol with perfect address specificity. + * + * If this is not done, ARP will not work reliably. + * + * Multiple calls to subscribe to the same multicast address will have no + * effect. It is perfectly safe to do this. + * + * This does not generate an update call to networkConfigCallback(). + * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call + * @param nwid 64-bit network ID + * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) + * @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 + */ +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) + * + * If multicastGroup is zero (0), this will unsubscribe from all groups. If + * you are not subscribed to a group this has no effect. + * + * This does not generate an update call to networkConfigCallback(). + * + * @param node Node instance + * @param nwid 64-bit network ID + * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) + * @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 + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); + +/** + * List roots for this node + * + * @param node Node instance + * @param now Current time + * @return List of roots, use ZT_Node_freeQueryResult to free this when done + */ +ZT_SDK_API ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now); + +/** + * Set a static root + * + * @param node Node instance + * @param identity Public identity of static root + * @param addresses Physical address(es) of root + * @param addressCount Number of physical addresses + * @return OK (0) or error code + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount); + +/** + * Set a dynamic root + * + * The node will begin trying to resolve the DNS TXT record for + * this root and possibly obtain it from other peers. + * + * @param node Node instance + * @param dnsName DNS name whose TXT record(s) contain the latest Locator for this root + * @param defaultLocator Binary-serialized default locator of NULL if none (used if TXT records are not retrievable) + * @param defaultLocatorSize Size of default locator or 0 if none + * @return OK (0) or error code + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_setDynamicRoot(ZT_Node *node,const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize); + +/** + * Remove a static root + * + * @param node Node instance + * @param identity Public identity of this root + * @return OK (0) or error code + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_removeStaticRoot(ZT_Node *node,const char *identity); + +/** + * Remove a dynamic root + * + * @param node Node instance + * @param dnsName DNS name of this dynamic root + * @return OK (0) or error code + */ +ZT_SDK_API enum ZT_ResultCode ZT_Node_removeDynamicRoot(ZT_Node *node,const char *dnsName); + +/** + * Get this node's 40-bit ZeroTier address + * + * @param node Node instance + * @return ZeroTier address (least significant 40 bits of 64-bit int) + */ +ZT_SDK_API uint64_t ZT_Node_address(ZT_Node *node); + +/** + * Get the status of this node + * + * @param node Node instance + * @param status Buffer to fill with current node status + */ +ZT_SDK_API void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status); + +/** + * Get a list of known peer nodes + * + * The pointer returned here must be freed with freeQueryResult() + * when you are done with it. + * + * @param node Node instance + * @return List of known peers or NULL on failure + */ +ZT_SDK_API ZT_PeerList *ZT_Node_peers(ZT_Node *node); + +/** + * Get the status of a virtual network + * + * The pointer returned here must be freed with freeQueryResult() + * when you are done with it. + * + * @param node Node instance + * @param nwid 64-bit network ID + * @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); + +/** + * Enumerate and get status of all networks + * + * @param node Node instance + * @return List of networks or NULL on failure + */ +ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node); + +/** + * Free a query result buffer + * + * Use this to free the return values of listNetworks(), listPeers(), etc. + * + * @param node Node instance + * @param qr Query result buffer + */ +ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); + +/** + * Add a local interface address + * + * This is used to make ZeroTier aware of those local interface addresses + * that you wish to use for ZeroTier communication. This is optional, and if + * it is not used ZeroTier will rely upon upstream peers (and roots) to + * perform empirical address discovery and NAT traversal. But the use of this + * method is recommended as it improves peer discovery when both peers are + * on the same LAN. + * + * It is the responsibility of the caller to take care that these are never + * ZeroTier interface addresses, whether these are assigned by ZeroTier or + * are otherwise assigned to an interface managed by this ZeroTier instance. + * This can cause recursion or other undesirable behavior. + * + * This returns a boolean indicating whether or not the address was + * accepted. ZeroTier will only communicate over certain address types + * and (for IP) address classes. + * + * @param addr Local interface address + * @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); + +/** + * Clear local interface addresses + */ +ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); + +/** + * Send a VERB_USER_MESSAGE to another ZeroTier node + * + * There is no delivery guarantee here. Failure can occur if the message is + * too large or if dest is not a valid ZeroTier address. + * + * @param node Node instance + * @param tptr Thread pointer to pass to functions/callbacks resulting from this call + * @param dest Destination ZeroTier address + * @param typeId VERB_USER_MESSAGE type ID + * @param data Payload data to attach to user message + * @param len Length of data in bytes + * @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); + +/** + * Set a network controller instance for this node + * + * Normal nodes should not need to use this. This is for nodes with + * special compiled-in support for acting as network configuration + * masters / controllers. + * + * The supplied instance must be a C++ object that inherits from the + * NetworkConfigMaster base class in node/. No type checking is performed, + * so a pointer to anything else will result in a crash. + * + * @param node ZertTier One node + * @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable + * @return OK (0) or error code if a fatal error condition has occurred + */ +ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterInstance); + +/** + * Set configuration for a given physical path + * + * @param node Node instance + * @param pathNetwork Network/CIDR of path or NULL to clear the cache and reset all paths to default + * @param pathConfig Path configuration or NULL to erase this entry and therefore reset it to NULL + * @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); + +/** + * Get ZeroTier One version + * + * @param major Result: major version + * @param minor Result: minor version + * @param revision Result: revision + */ +ZT_SDK_API void ZT_version(int *major,int *minor,int *revision); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h deleted file mode 100644 index 8c1a7a6c2..000000000 --- a/include/ZeroTierOne.h +++ /dev/null @@ -1,2046 +0,0 @@ -/* - * Copyright (c)2019 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2023-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -/* - * This defines the external C API for ZeroTier's core network virtualization - * engine. - */ - -#ifndef ZT_ZEROTIER_API_H -#define ZT_ZEROTIER_API_H - -#include - -/* For struct sockaddr_storage, which is referenced here. */ -#if defined(_WIN32) || defined(_WIN64) -#include -#include -#include -#else /* not Windows */ -#include -#include -#include -#include -#endif /* Windows or not */ - -/* This symbol may be defined in a build environment or before including this - * header if you need to prepend something to function specifications. */ -#ifndef ZT_SDK_API -#define ZT_SDK_API -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/****************************************************************************/ -/* Core constants */ -/****************************************************************************/ - -/** - * Default UDP port for devices running a ZeroTier endpoint - */ -#define ZT_DEFAULT_PORT 9993 - -/** - * Minimum MTU, which is the minimum allowed by IPv6 and several specs - */ -#define ZT_MIN_MTU 1280 - -/** - * Maximum MTU for ZeroTier virtual networks - */ -#define ZT_MAX_MTU 10000 - -/** - * Minimum UDP payload size allowed - */ -#define ZT_MIN_PHYSMTU 1400 - -/** - * Default UDP payload size (physical path MTU) not including UDP and IP overhead - * - * This is small enough for PPPoE and for Google Cloud's bizarrely tiny MTUs. - * A 2800 byte payload still fits into two packets, so this should not impact - * real world throughput at all vs the previous default of 1444. - */ -#define ZT_DEFAULT_PHYSMTU 1432 - -/** - * Maximum physical UDP payload - */ -#define ZT_MAX_PHYSPAYLOAD 10100 - -/** - * Headroom for max physical MTU - */ -#define ZT_MAX_HEADROOM 224 - -/** - * Maximum payload MTU for UDP packets - */ -#define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM) - -/** - * Maximum size of a remote trace message's serialized Dictionary - */ -#define ZT_MAX_REMOTE_TRACE_SIZE 10000 - -/** - * Maximum length of network short name - */ -#define ZT_MAX_NETWORK_SHORT_NAME_LENGTH 127 - -/** - * Maximum number of pushed routes on a network (via ZT in-band mechanisms) - */ -#define ZT_MAX_NETWORK_ROUTES 64 - -/** - * Maximum number of statically assigned IP addresses (via ZT in-band mechanisms) - */ -#define ZT_MAX_ZT_ASSIGNED_ADDRESSES 32 - -/** - * Maximum number of "specialists" on a network -- bridges, anchors, etc. - */ -#define ZT_MAX_NETWORK_SPECIALISTS 256 - -/** - * Rules engine revision ID, which specifies rules engine capabilities - */ -#define ZT_RULES_ENGINE_REVISION 1 - -/** - * Maximum number of base (non-capability) network rules - */ -#define ZT_MAX_NETWORK_RULES 1024 - -/** - * Maximum number of capabilities per network per member - */ -#define ZT_MAX_NETWORK_CAPABILITIES 128 - -/** - * Maximum number of tags per network per member - */ -#define ZT_MAX_NETWORK_TAGS 128 - -/** - * Maximum number of direct network paths to a given peer - */ -#define ZT_MAX_PEER_NETWORK_PATHS 16 - -/** - * Maximum number of path configurations that can be set - */ -#define ZT_MAX_CONFIGURABLE_PATHS 32 - -/** - * Maximum number of rules per capability object - */ -#define ZT_MAX_CAPABILITY_RULES 64 - -/** - * Maximum number of certificates of ownership to assign to a single network member - */ -#define ZT_MAX_CERTIFICATES_OF_OWNERSHIP 4 - -/** - * Global maximum length for capability chain of custody (including initial issue) - */ -#define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7 - -/** - * Maximum number of multicast group subscriptions on a local virtual network interface - */ -#define ZT_MAX_MULTICAST_SUBSCRIPTIONS 1024 - -/** - * Maximum value for link quality (min is 0) - */ -#define ZT_PATH_LINK_QUALITY_MAX 255 - -/* Rule specification contants **********************************************/ - -/** - * Packet characteristics flag: packet direction, 1 if inbound 0 if outbound - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_INBOUND 0x8000000000000000ULL - -/** - * Packet characteristics flag: multicast or broadcast destination MAC - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST 0x4000000000000000ULL - -/** - * Packet characteristics flag: broadcast destination MAC - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST 0x2000000000000000ULL - -/** - * Packet characteristics flag: sending IP address has a certificate of ownership - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED 0x1000000000000000ULL - -/** - * Packet characteristics flag: sending MAC address has a certificate of ownership - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED 0x0800000000000000ULL - -/** - * Packet characteristics flag: TCP left-most reserved bit - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_0 0x0000000000000800ULL - -/** - * Packet characteristics flag: TCP middle reserved bit - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_1 0x0000000000000400ULL - -/** - * Packet characteristics flag: TCP right-most reserved bit - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RESERVED_2 0x0000000000000200ULL - -/** - * Packet characteristics flag: TCP NS flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_NS 0x0000000000000100ULL - -/** - * Packet characteristics flag: TCP CWR flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_CWR 0x0000000000000080ULL - -/** - * Packet characteristics flag: TCP ECE flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ECE 0x0000000000000040ULL - -/** - * Packet characteristics flag: TCP URG flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_URG 0x0000000000000020ULL - -/** - * Packet characteristics flag: TCP ACK flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK 0x0000000000000010ULL - -/** - * Packet characteristics flag: TCP PSH flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_PSH 0x0000000000000008ULL - -/** - * Packet characteristics flag: TCP RST flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_RST 0x0000000000000004ULL - -/** - * Packet characteristics flag: TCP SYN flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN 0x0000000000000002ULL - -/** - * Packet characteristics flag: TCP FIN flag - */ -#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL - -/****************************************************************************/ - -// Fields in remote trace dictionaries -#define ZT_REMOTE_TRACE_FIELD__EVENT "event" -#define ZT_REMOTE_TRACE_FIELD__NODE_ID "nodeId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "packetId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "packetVerb" -#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "packetTrustedPathId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "packetTrustedPathApproved" -#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "packetHops" -#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "remoteZtAddr" -#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "remotePhyAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "localZtAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "localPhyAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "localSocket" -#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "phyAddrIpScope" -#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "networkId" -#define ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR "sourceZtAddr" -#define ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR "destZtAddr" -#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "sourceMac" -#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "destMac" -#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "etherType" -#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlanId" -#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "frameLength" -#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "frameData" -#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE "filterNoTee" -#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND "filterInbound" -#define ZT_REMOTE_TRACE_FIELD__FILTER_RESULT "filterResult" -#define ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG "filterBaseRuleLog" -#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG "filterCapRuleLog" -#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID "filterMatchingCapId" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credType" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credId" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credTs" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credInfo" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "credIssuedTo" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "credRevocationTarget" -#define ZT_REMOTE_TRACE_FIELD__REASON "reason" -#define ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID "networkControllerId" - -// Event types in remote traces -#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000 -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1001 -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1002 -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1003 -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1004 -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1005 -#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO 0x1006 -#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED 0x2000 -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED 0x2001 -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED 0x2002 -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED 0x2003 -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED 0x2004 -#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT 0x2005 -#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE 0x2006 - -// Event types in remote traces in hex string form -#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1001" -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1002" -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1003" -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1004" -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1005" -#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" -#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000" -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001" -#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002" -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" -#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S "2005" -#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S "2006" - -/****************************************************************************/ -/* Structures and other types */ -/****************************************************************************/ - -/** - * Function return code: OK (0) or error results - * - * Use ZT_ResultCode_isFatal() to check for a fatal error. If a fatal error - * occurs, the node should be considered to not be working correctly. These - * indicate serious problems like an inaccessible data store or a compile - * problem. - */ -enum ZT_ResultCode -{ - /** - * Operation completed normally - */ - ZT_RESULT_OK = 0, - - /** - * Call produced no error but no action was taken - */ - ZT_RESULT_OK_IGNORED = 1, - - // Fatal errors (>100, <1000) - - /** - * Ran out of memory - */ - ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 100, - - /** - * Data store is not writable or has failed - */ - ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 101, - - /** - * Internal error (e.g. unexpected exception indicating bug or build problem) - */ - ZT_RESULT_FATAL_ERROR_INTERNAL = 102, - - // Non-fatal errors (>1000) - - /** - * Network ID not valid - */ - ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, - - /** - * The requested operation is not supported on this version or build - */ - ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, - - /** - * The requested operation was given a bad parameter or was called in an invalid state - */ - ZT_RESULT_ERROR_BAD_PARAMETER = 1002 -}; - -/** - * Macro to check for a fatal error result code - * - * @param x Result code - * @return True if result code indicates a fatal error - */ -#define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100)&&(((int)(x)) < 1000)) - -/** - * The multipath algorithm in use by this node. - */ -enum ZT_MultipathMode -{ - /** - * No active multipath. - * - * Traffic is merely sent over the strongest path. That being - * said, this mode will automatically failover in the event that a link goes down. - */ - ZT_MULTIPATH_NONE = 0, - - /** - * Traffic is randomly distributed among all active paths. - * - * Will cease sending traffic over links that appear to be stale. - */ - ZT_MULTIPATH_RANDOM = 1, - - /** - * Traffic is allocated across all active paths in proportion to their strength and - * reliability. - * - * Will cease sending traffic over links that appear to be stale. - */ - ZT_MULTIPATH_PROPORTIONALLY_BALANCED = 2, -}; - -/** - * Status codes sent to status update callback when things happen - */ -enum ZT_Event -{ - /** - * Node has been initialized - * - * This is the first event generated, and is always sent. It may occur - * before Node's constructor returns. - * - * Meta-data: none - */ - ZT_EVENT_UP = 0, - - /** - * Node appears offline - * - * This indicates that the node doesn't seem to be able to reach anything, - * or hasn't for a while. It's not a hard instantaneous thing. - * - * Meta-data: none - */ - ZT_EVENT_OFFLINE = 1, - - /** - * Node appears online - * - * This indicates that the node was offline but now seems to be able to - * reach something. Like OFFLINE it's not a hard instantaneous thing but - * more of an indicator for UI reporting purposes. - * - * Meta-data: none - */ - ZT_EVENT_ONLINE = 2, - - /** - * Node is shutting down - * - * This is generated within Node's destructor when it is being shut down. - * It's done for convenience in case you want to clean up anything during - * node shutdown in your node event handler. - * - * Meta-data: none - */ - ZT_EVENT_DOWN = 3, - - // 4 once signaled identity collision but this is no longer an error - - /** - * Trace (debugging) message - * - * These events are only generated if this is a TRACE-enabled build. - * This is for local debug traces, not remote trace diagnostics. - * - * Meta-data: C string, TRACE message - */ - ZT_EVENT_TRACE = 5, - - /** - * VERB_USER_MESSAGE received - * - * These are generated when a VERB_USER_MESSAGE packet is received via - * ZeroTier VL1. This can be used for below-VL2 in-band application - * specific signaling over the ZeroTier protocol. - * - * It's up to you to ensure that you handle these in a way that does - * not introduce a remote security vulnerability into your app! If - * your USER_MESSAGE code has a buffer overflow or other vulnerability - * then your app will be vulnerable and this is not ZT's fault. :) - * - * Meta-data: ZT_UserMessage structure - */ - ZT_EVENT_USER_MESSAGE = 6, - - /** - * Remote trace received - * - * NOTE: any node can fling a VERB_REMOTE_TRACE at you. It's up to you - * to determine if you want to do anything with it or just silently - * drop it on the floor. It's also up to you to handle these securely! - * - * Meta-data: ZT_RemoteTrace structure - */ - ZT_EVENT_REMOTE_TRACE = 7 -}; - -/** - * Payload of REMOTE_TRACE event - */ -typedef struct -{ - /** - * ZeroTier address of sender (in least significant 40 bits only) - */ - uint64_t origin; - - /** - * Null-terminated Dictionary containing key/value pairs sent by origin - * - * This *should* be a dictionary, but the implementation only checks - * that it is a valid non-empty C-style null-terminated string. Be very - * careful to use a well-tested parser to parse this as it represents - * data received from a potentially un-trusted peer on the network. - * Invalid payloads should be dropped. - * - * The contents of data[] may be modified. - */ - const char *data; - - /** - * Length of dict[] in bytes, INCLUDING terminating null - */ - unsigned int len; -} ZT_RemoteTrace; - -/** - * User message used with ZT_EVENT_USER_MESSAGE - * - * These are direct VL1 P2P messages for application use. Encryption and - * authentication in the ZeroTier protocol will guarantee the origin - * address and message content, but you are responsible for any other - * levels of authentication or access control that are required. Any node - * in the world can send you a user message! (Unless your network is air - * gapped.) - */ -typedef struct -{ - /** - * ZeroTier address of sender (least significant 40 bits) - */ - uint64_t origin; - - /** - * User message type ID - */ - uint64_t typeId; - - /** - * User message data (not including type ID) - */ - const void *data; - - /** - * Length of data in bytes - */ - unsigned int length; -} ZT_UserMessage; - -/** - * Current node status - */ -typedef struct -{ - /** - * 40-bit ZeroTier address of this node - */ - uint64_t address; - - /** - * Public identity in string-serialized form (safe to send to others) - * - * This pointer will remain valid as long as the node exists. - */ - const char *publicIdentity; - - /** - * Full identity including secret key in string-serialized form - * - * This pointer will remain valid as long as the node exists. - */ - const char *secretIdentity; - - /** - * True if some kind of connectivity appears available - */ - int online; -} ZT_NodeStatus; - -/** - * Virtual network status codes - */ -enum ZT_VirtualNetworkStatus -{ - /** - * Waiting for network configuration (also means revision == 0) - */ - ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION = 0, - - /** - * Configuration received and we are authorized - */ - ZT_NETWORK_STATUS_OK = 1, - - /** - * Netconf master told us 'nope' - */ - ZT_NETWORK_STATUS_ACCESS_DENIED = 2, - - /** - * Netconf master exists, but this virtual network does not - */ - ZT_NETWORK_STATUS_NOT_FOUND = 3, - - /** - * Initialization of network failed or other internal error - */ - ZT_NETWORK_STATUS_PORT_ERROR = 4, - - /** - * ZeroTier core version too old - */ - ZT_NETWORK_STATUS_CLIENT_TOO_OLD = 5 -}; - -/** - * Virtual network type codes - */ -enum ZT_VirtualNetworkType -{ - /** - * Private networks are authorized via certificates of membership - */ - ZT_NETWORK_TYPE_PRIVATE = 0, - - /** - * Public networks have no access control -- they'll always be AUTHORIZED - */ - ZT_NETWORK_TYPE_PUBLIC = 1 -}; - -/** - * The type of a virtual network rules table entry - * - * These must be from 0 to 63 since the most significant two bits of each - * rule type are NOT (MSB) and AND/OR. - * - * Each rule is composed of zero or more MATCHes followed by an ACTION. - * An ACTION with no MATCHes is always taken. - */ -enum ZT_VirtualNetworkRuleType -{ - // 0 to 15 reserved for actions - - /** - * Drop frame - */ - ZT_NETWORK_RULE_ACTION_DROP = 0, - - /** - * Accept and pass frame - */ - ZT_NETWORK_RULE_ACTION_ACCEPT = 1, - - /** - * Forward a copy of this frame to an observer (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_TEE = 2, - - /** - * Exactly like TEE but mandates ACKs from observer - */ - ZT_NETWORK_RULE_ACTION_WATCH = 3, - - /** - * Drop and redirect this frame to another node (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_REDIRECT = 4, - - /** - * Stop evaluating rule set (drops unless there are capabilities, etc.) - */ - ZT_NETWORK_RULE_ACTION_BREAK = 5, - - /** - * Place a matching frame in the specified QoS bucket - */ - ZT_NETWORK_RULE_ACTION_PRIORITY = 6, - - /** - * Maximum ID for an ACTION, anything higher is a MATCH - */ - ZT_NETWORK_RULE_ACTION__MAX_ID = 15, - - // 16 to 63 reserved for match criteria - - ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS = 24, - ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS = 25, - ZT_NETWORK_RULE_MATCH_VLAN_ID = 26, - ZT_NETWORK_RULE_MATCH_VLAN_PCP = 27, - ZT_NETWORK_RULE_MATCH_VLAN_DEI = 28, - ZT_NETWORK_RULE_MATCH_MAC_SOURCE = 29, - ZT_NETWORK_RULE_MATCH_MAC_DEST = 30, - ZT_NETWORK_RULE_MATCH_IPV4_SOURCE = 31, - ZT_NETWORK_RULE_MATCH_IPV4_DEST = 32, - ZT_NETWORK_RULE_MATCH_IPV6_SOURCE = 33, - ZT_NETWORK_RULE_MATCH_IPV6_DEST = 34, - ZT_NETWORK_RULE_MATCH_IP_TOS = 35, - ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 36, - ZT_NETWORK_RULE_MATCH_ETHERTYPE = 37, - ZT_NETWORK_RULE_MATCH_ICMP = 38, - ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 39, - ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 40, - ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 41, - ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 42, - ZT_NETWORK_RULE_MATCH_RANDOM = 43, - ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 44, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 45, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, - ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, - ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49, - ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50, - ZT_NETWORK_RULE_MATCH_INTEGER_RANGE = 51, - - /** - * Maximum ID allowed for a MATCH entry in the rules table - */ - ZT_NETWORK_RULE_MATCH__MAX_ID = 63 -}; - -/** - * Network flow rule - * - * Rules are stored in a table in which one or more match entries is followed - * by an action. If more than one match precedes an action, the rule is - * the AND of all matches. An action with no match is always taken since it - * matches anything. If nothing matches, the default action is DROP. - * - * 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. - */ -typedef struct -{ - /** - * Type and flags - * - * Bits are: NOTTTTTT - * - * N - If true, sense of match is inverted (no effect on actions) - * O - If true, result is ORed with previous instead of ANDed (no effect on actions) - * T - Rule or action type - * - * AND with 0x3f to get type, 0x80 to get NOT bit, and 0x40 to get OR bit. - */ - uint8_t t; - - /** - * Union containing the value of this rule -- which field is used depends on 't' - */ - union { - /** - * IPv6 address in big-endian / network byte order and netmask bits - */ - struct { - uint8_t ip[16]; - uint8_t mask; - } ipv6; - - /** - * IPv4 address in big-endian / network byte order - */ - struct { - uint32_t ip; - uint8_t mask; - } ipv4; - - /** - * Integer range match in packet payload - * - * This allows matching of ranges of integers up to 64 bits wide where - * the range is +/- INT32_MAX. It's packed this way so it fits in 16 - * bytes and doesn't enlarge the overall size of this union. - */ - struct { - uint64_t start; // integer range start - uint32_t end; // end of integer range (relative to start, inclusive, 0 for equality w/start) - uint16_t idx; // index in packet of integer - uint8_t format; // bits in integer (range 1-64, ((format&63)+1)) and endianness (MSB 1 for little, 0 for big) - } intRange; - - /** - * Packet characteristic flags being matched - */ - uint64_t characteristics; - - /** - * IP port range -- start-end inclusive -- host byte order - */ - uint16_t port[2]; - - /** - * 40-bit ZeroTier address (in least significant bits, host byte order) - */ - uint64_t zt; - - /** - * 0 = never, UINT32_MAX = always - */ - uint32_t randomProbability; - - /** - * 48-bit Ethernet MAC address in big-endian order - */ - uint8_t mac[6]; - - /** - * VLAN ID in host byte order - */ - uint16_t vlanId; - - /** - * VLAN PCP (least significant 3 bits) - */ - uint8_t vlanPcp; - - /** - * VLAN DEI (single bit / boolean) - */ - uint8_t vlanDei; - - /** - * Ethernet type in host byte order - */ - uint16_t etherType; - - /** - * IP protocol - */ - uint8_t ipProtocol; - - /** - * IP type of service a.k.a. DSCP field - */ - struct { - uint8_t mask; - uint8_t value[2]; - } ipTos; - - /** - * Ethernet packet size in host byte order (start-end, inclusive) - */ - uint16_t frameSize[2]; - - /** - * ICMP type and code - */ - struct { - uint8_t type; // ICMP type, always matched - uint8_t code; // ICMP code if matched - uint8_t flags; // flag 0x01 means also match code, otherwise only match type - } icmp; - - /** - * For tag-related rules - */ - struct { - uint32_t id; - uint32_t value; - } tag; - - /** - * Destinations for TEE and REDIRECT - */ - struct { - uint64_t address; - uint32_t flags; - uint16_t length; - } fwd; - - /** - * Quality of Service (QoS) bucket we want a frame to be placed in - */ - uint8_t qosBucket; - } v; -} ZT_VirtualNetworkRule; - -/** - * A route to be pushed on a virtual network - */ -typedef struct -{ - /** - * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default - */ - struct sockaddr_storage target; - - /** - * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) - */ - struct sockaddr_storage via; - - /** - * Route flags - */ - uint16_t flags; - - /** - * Route metric (not currently used) - */ - uint16_t metric; -} ZT_VirtualNetworkRoute; - -/** - * An Ethernet multicast group - */ -typedef struct -{ - /** - * MAC address (least significant 48 bits) - */ - uint64_t mac; - - /** - * Additional distinguishing information (usually zero) - */ - unsigned long adi; -} ZT_MulticastGroup; - -/** - * Virtual network configuration update type - */ -enum ZT_VirtualNetworkConfigOperation -{ - /** - * Network is coming up (either for the first time or after service restart) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP = 1, - - /** - * Network configuration has been updated - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE = 2, - - /** - * Network is going down (not permanently) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN = 3, - - /** - * Network is going down permanently (leave/delete) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 -}; - -/** - * What trust hierarchy role does this peer have? - */ -enum ZT_PeerRole -{ - ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_MOON = 1, // moon root - ZT_PEER_ROLE_PLANET = 2 // planetary root -}; - -/** - * Vendor ID - */ -enum ZT_Vendor -{ - ZT_VENDOR_UNSPECIFIED = 0, - ZT_VENDOR_ZEROTIER = 1 -}; - -/** - * Platform type - */ -enum ZT_Platform -{ - ZT_PLATFORM_UNSPECIFIED = 0, - ZT_PLATFORM_LINUX = 1, - ZT_PLATFORM_WINDOWS = 2, - ZT_PLATFORM_MACOS = 3, - ZT_PLATFORM_ANDROID = 4, - ZT_PLATFORM_IOS = 5, - ZT_PLATFORM_SOLARIS_SMARTOS = 6, - ZT_PLATFORM_FREEBSD = 7, - ZT_PLATFORM_NETBSD = 8, - ZT_PLATFORM_OPENBSD = 9, - ZT_PLATFORM_RISCOS = 10, - ZT_PLATFORM_VXWORKS = 11, - ZT_PLATFORM_FREERTOS = 12, - ZT_PLATFORM_SYSBIOS = 13, - ZT_PLATFORM_HURD = 14, - ZT_PLATFORM_WEB = 15 -}; - -/** - * Architecture type - */ -enum ZT_Architecture -{ - ZT_ARCHITECTURE_UNSPECIFIED = 0, - ZT_ARCHITECTURE_X86 = 1, - ZT_ARCHITECTURE_X64 = 2, - ZT_ARCHITECTURE_ARM32 = 3, - ZT_ARCHITECTURE_ARM64 = 4, - ZT_ARCHITECTURE_MIPS32 = 5, - ZT_ARCHITECTURE_MIPS64 = 6, - ZT_ARCHITECTURE_POWER32 = 7, - ZT_ARCHITECTURE_POWER64 = 8, - ZT_ARCHITECTURE_OPENRISC32 = 9, - ZT_ARCHITECTURE_OPENRISC64 = 10, - ZT_ARCHITECTURE_SPARC32 = 11, - ZT_ARCHITECTURE_SPARC64 = 12, - ZT_ARCHITECTURE_DOTNET_CLR = 13, - ZT_ARCHITECTURE_JAVA_JVM = 14, - ZT_ARCHITECTURE_WEB = 15, - ZT_ARCHITECTURE_S390X = 16 -}; - -/** - * DNS record types for reporting DNS results - * - * These integer IDs (other than end of results) are the same as the DNS protocol's - * internal IDs. Not all of these are used by ZeroTier, and not all DNS record types - * are listed here. These are just common ones that are used now or may be used in - * the future for some purpose. - */ -enum ZT_DNSRecordType -{ - ZT_DNS_RECORD__END_OF_RESULTS = 0, - ZT_DNS_RECORD_A = 1, - ZT_DNS_RECORD_NS = 2, - ZT_DNS_RECORD_CNAME = 5, - ZT_DNS_RECORD_PTR = 12, - ZT_DNS_RECORD_MX = 15, - ZT_DNS_RECORD_TXT = 16, - ZT_DNS_RECORD_AAAA = 28, - ZT_DNS_RECORD_LOC = 29, - ZT_DNS_RECORD_SRV = 33, - ZT_DNS_RECORD_DNAME = 39 -}; - -/** - * Virtual network configuration - */ -typedef struct -{ - /** - * 64-bit ZeroTier network ID - */ - uint64_t nwid; - - /** - * Ethernet MAC (48 bits) that should be assigned to port - */ - uint64_t mac; - - /** - * Network name (from network configuration master) - */ - char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; - - /** - * Network configuration request status - */ - enum ZT_VirtualNetworkStatus status; - - /** - * Network type - */ - enum ZT_VirtualNetworkType type; - - /** - * Maximum interface MTU - */ - unsigned int mtu; - - /** - * If nonzero, the network this port belongs to indicates DHCP availability - * - * This is a suggestion. The underlying implementation is free to ignore it - * for security or other reasons. This is simply a netconf parameter that - * means 'DHCP is available on this network.' - */ - int dhcp; - - /** - * If nonzero, this port is allowed to bridge to other networks - * - * This is informational. If this is false (0), bridged packets will simply - * be dropped and bridging won't work. - */ - int bridge; - - /** - * If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic - */ - int broadcastEnabled; - - /** - * If the network is in PORT_ERROR state, this is the (negative) error code most recently reported - */ - int portError; - - /** - * Revision number as reported by controller or 0 if still waiting for config - */ - unsigned long netconfRevision; - - /** - * Number of assigned addresses - */ - unsigned int assignedAddressCount; - - /** - * ZeroTier-assigned addresses (in sockaddr_storage structures) - * - * For IP, the port number of the sockaddr_XX structure contains the number - * of bits in the address netmask. Only the IP address and port are used. - * Other fields like interface number can be ignored. - * - * This is only used for ZeroTier-managed address assignments sent by the - * virtual network's configuration master. - */ - struct sockaddr_storage assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; - - /** - * Number of ZT-pushed routes - */ - unsigned int routeCount; - - /** - * Routes (excluding those implied by assigned addresses and their masks) - */ - ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; - - /** - * Number of multicast groups subscribed - */ - unsigned int multicastSubscriptionCount; - - /** - * Multicast groups to which this network's device is subscribed - */ - struct { - uint64_t mac; /* MAC in lower 48 bits */ - uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */ - } multicastSubscriptions[ZT_MAX_MULTICAST_SUBSCRIPTIONS]; -} ZT_VirtualNetworkConfig; - -/** - * A list of networks - */ -typedef struct -{ - ZT_VirtualNetworkConfig *networks; - unsigned long networkCount; -} ZT_VirtualNetworkList; - -/** - * Physical path configuration - */ -typedef struct { - /** - * If non-zero set this physical network path to be trusted to disable encryption and authentication - */ - uint64_t trustedPathId; - - /** - * Physical path MTU from ZT_MIN_PHYSMTU and ZT_MAX_PHYSMTU or <= 0 to use default - */ - int mtu; -} ZT_PhysicalPathConfiguration; - -/** - * Physical network path to a peer - */ -typedef struct -{ - /** - * Address of endpoint - */ - struct sockaddr_storage address; - - /** - * Time of last send in milliseconds or 0 for never - */ - uint64_t lastSend; - - /** - * Time of last receive in milliseconds or 0 for never - */ - uint64_t lastReceive; - - /** - * Is this a trusted path? If so this will be its nonzero ID. - */ - uint64_t trustedPathId; - - /** - * One-way latency - */ - float latency; - - /** - * How much latency varies over time - */ - float packetDelayVariance; - - /** - * How much observed throughput varies over time - */ - float throughputDisturbCoeff; - - /** - * Packet Error Ratio (PER) - */ - float packetErrorRatio; - - /** - * Packet Loss Ratio (PLR) - */ - float packetLossRatio; - - /** - * Stability of the path - */ - float stability; - - /** - * Current throughput (moving average) - */ - uint64_t throughput; - - /** - * Maximum observed throughput for this path - */ - uint64_t maxThroughput; - - /** - * Percentage of traffic allocated to this path - */ - float allocation; - - /** - * Name of physical interface (for monitoring) - */ - char *ifname; - - /** - * Is path expired? - */ - int expired; - - /** - * Is path preferred? - */ - int preferred; -} ZT_PeerPhysicalPath; - -/** - * Peer status result buffer - */ -typedef struct -{ - /** - * ZeroTier address (40 bits) - */ - uint64_t address; - - /** - * Remote major version or -1 if not known - */ - int versionMajor; - - /** - * Remote minor version or -1 if not known - */ - int versionMinor; - - /** - * Remote revision or -1 if not known - */ - int versionRev; - - /** - * Last measured latency in milliseconds or -1 if unknown - */ - int latency; - - /** - * What trust hierarchy role does this device have? - */ - enum ZT_PeerRole role; - - /** - * Number of paths (size of paths[]) - */ - unsigned int pathCount; - - /** - * Whether this peer was ever reachable via an aggregate link - */ - bool hadAggregateLink; - - /** - * Known network paths to peer - */ - ZT_PeerPhysicalPath paths[ZT_MAX_PEER_NETWORK_PATHS]; -} ZT_Peer; - -/** - * List of peers - */ -typedef struct -{ - ZT_Peer *peers; - unsigned long peerCount; -} ZT_PeerList; - -/** - * ZeroTier core state objects - */ -enum ZT_StateObjectType -{ - /** - * Null object -- ignored - */ - ZT_STATE_OBJECT_NULL = 0, - - /** - * Public address and public key - * - * Object ID: this node's address if known, or 0 if unknown (first query) - * Canonical path: /identity.public - * Persistence: required - */ - ZT_STATE_OBJECT_IDENTITY_PUBLIC = 1, - - /** - * Full identity with secret key - * - * Object ID: this node's address if known, or 0 if unknown (first query) - * Canonical path: /identity.secret - * Persistence: required, should be stored with restricted permissions e.g. mode 0600 on *nix - */ - ZT_STATE_OBJECT_IDENTITY_SECRET = 2, - - /** - * Peer and related state - * - * Object ID: peer address - * Canonical path: /peers.d/ (10-digit address - * Persistence: optional, can be cleared at any time - */ - ZT_STATE_OBJECT_PEER = 5, - - /** - * Network configuration - * - * Object ID: peer address - * Canonical path: /networks.d/.conf (16-digit hex ID) - * Persistence: required if network memberships should persist - */ - ZT_STATE_OBJECT_NETWORK_CONFIG = 6 -}; - -/** - * An instance of a ZeroTier One node (opaque) - */ -typedef void ZT_Node; - -/****************************************************************************/ -/* Callbacks used by Node API */ -/****************************************************************************/ - -/** - * Callback called to update virtual network port configuration - * - * This can be called at any time to update the configuration of a virtual - * network port. The parameter after the network ID specifies whether this - * port is being brought up, updated, brought down, or permanently deleted. - * - * This in turn should be used by the underlying implementation to create - * and configure tap devices at the OS (or virtual network stack) layer. - * - * The supplied config pointer is not guaranteed to remain valid, so make - * a copy if you want one. - * - * This should not call multicastSubscribe() or other network-modifying - * methods, as this could cause a deadlock in multithreaded or interrupt - * driven environments. - * - * This must return 0 on success. It can return any OS-dependent error code - * on failure, and this results in the network being placed into the - * PORT_ERROR state. - */ -typedef int (*ZT_VirtualNetworkConfigFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - enum ZT_VirtualNetworkConfigOperation, /* Config operation */ - const ZT_VirtualNetworkConfig *); /* Network configuration */ - -/** - * Function to send a frame out to a virtual network port - * - * Parameters: (1) node, (2) user ptr, (3) network ID, (4) source MAC, - * (5) destination MAC, (6) ethertype, (7) VLAN ID, (8) frame data, - * (9) frame length. - */ -typedef void (*ZT_VirtualNetworkFrameFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - uint64_t, /* Source MAC */ - uint64_t, /* Destination MAC */ - unsigned int, /* Ethernet type */ - unsigned int, /* VLAN ID (0 for none) */ - const void *, /* Frame data */ - unsigned int); /* Frame length */ - -/** - * Callback for events - * - * Events are generated when the node's status changes in a significant way - * and on certain non-fatal errors and events of interest. The final void - * parameter points to event meta-data. The type of event meta-data (and - * whether it is present at all) is event type dependent. See the comments - * in the definition of ZT_Event. - */ -typedef void (*ZT_EventCallback)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_Event, /* Event type */ - const void *); /* Event payload (if applicable) */ - -/** - * Callback for storing and/or publishing state information - * - * See ZT_StateObjectType docs for information about each state object type - * and when and if it needs to be persisted. - * - * An object of length -1 is sent to indicate that an object should be - * deleted. - */ -typedef void (*ZT_StatePutFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_StateObjectType, /* State object type */ - const uint64_t [2], /* State object ID (if applicable) */ - const void *, /* State object data */ - int); /* Length of data or -1 to delete */ - -/** - * Callback for retrieving stored state information - * - * This function should return the number of bytes actually stored to the - * buffer or -1 if the state object was not found or the buffer was too - * small to store it. - */ -typedef int (*ZT_StateGetFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_StateObjectType, /* State object type */ - const uint64_t [2], /* State object ID (if applicable) */ - void *, /* Buffer to store state object data */ - unsigned int); /* Length of data buffer in bytes */ - -/** - * Function to send a ZeroTier packet out over the physical wire (L2/L3) - * - * Parameters: - * (1) Node - * (2) User pointer - * (3) Local socket or -1 for "all" or "any" - * (4) Remote address - * (5) Packet data - * (6) Packet length - * (7) Desired IP TTL or 0 to use default - * - * If there is only one local socket, the local socket can be ignored. - * If the local socket is -1, the packet should be sent out from all - * bound local sockets or a random bound local socket. - * - * If TTL is nonzero, packets should have their IP TTL value set to this - * value if possible. If this is not possible it is acceptable to ignore - * this value and send anyway with normal or default TTL. - * - * The function must return zero on success and may return any error code - * on failure. Note that success does not (of course) guarantee packet - * delivery. It only means that the packet appears to have been sent. - */ -typedef int (*ZT_WirePacketSendFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - int64_t, /* Local socket */ - const struct sockaddr_storage *, /* Remote address */ - const void *, /* Packet data */ - unsigned int, /* Packet length */ - unsigned int); /* TTL or 0 to use default */ - -/** - * Function to check whether a path should be used for ZeroTier traffic - * - * Parameters: - * (1) Node - * (2) User pointer - * (3) ZeroTier address or 0 for none/any - * (4) Local socket or -1 if unknown - * (5) Remote address - * - * This function must return nonzero (true) if the path should be used. - * - * If no path check function is specified, ZeroTier will still exclude paths - * that overlap with ZeroTier-assigned and managed IP address blocks. But the - * use of a path check function is recommended to ensure that recursion does - * not occur in cases where addresses are assigned by the OS or managed by - * an out of band mechanism like DHCP. The path check function should examine - * all configured ZeroTier interfaces and check to ensure that the supplied - * addresses will not result in ZeroTier traffic being sent over a ZeroTier - * interface (recursion). - */ -typedef int (*ZT_PathCheckFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address */ - int64_t, /* Local socket or -1 if unknown */ - const struct sockaddr_storage *); /* Remote address */ - -/** - * Function to get physical addresses for ZeroTier peers - * - * Parameters: - * (1) Node - * (2) User pointer - * (3) ZeroTier address (least significant 40 bits) - * (4) Desired address family or -1 for any - * (5) Buffer to fill with result - * - * If provided this function will be occasionally called to get physical - * addresses that might be tried to reach a ZeroTier address. It must - * return a nonzero (true) value if the result buffer has been filled - * with an address. - */ -typedef int (*ZT_PathLookupFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address (40 bits) */ - int, /* Desired ss_family or -1 for any */ - struct sockaddr_storage *); /* Result buffer */ - -/** - * Function to request an asynchronous DNS TXT lookup - * - * Parameters: - * (1) Node - * (2) User pointer - * (3) Thread pointer - * (4) Array of DNS record types we want - * (5) Number of DNS record types in array - * (6) DNS name to fetch - * (7) DNS request ID to supply to ZT_Node_processDNSResult() - * - * DNS is not handled in the core because every platform and runtime - * typically has its own DNS functions or libraries and these may need - * to interface with OS or network services in your local environment. - * Instead this function and its result submission counterpart are - * provided so you can provide a DNS implementation. - * - * If this callback is set in your callback struct to a NULL value, - * DNS will not be available. The ZeroTier protocol is designed to - * work in the absence of DNS but you may not get optimal results. For - * example you may default to root servers that are not geographically - * optimal or your node may cease to function if a root server's IP - * changes and there's no way to signal this. - * - * This function requests resolution of a DNS record. The result - * submission method ZT_Node_processDNSResult() must be called at - * least once in response. See its documentation. - * - * Right now ZeroTier only requests resolution of TXT records, but - * it's possible that this will change in the future. - * - * It's safe to call processDNSResult() from within your handler - * for this function. - */ -typedef void (*ZT_DNSResolver)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_DNSRecordType *, /* DNS record type(s) to fetch */ - unsigned int, /* Number of DNS record type(s) */ - const char *, /* DNS name to fetch */ - uintptr_t); /* Request ID for returning results */ - -/****************************************************************************/ -/* C Node API */ -/****************************************************************************/ - -/** - * Structure for configuring ZeroTier core callback functions - */ -struct ZT_Node_Callbacks -{ - /** - * REQUIRED: Function to store and/or replicate state objects - */ - ZT_StatePutFunction statePutFunction; - - /** - * REQUIRED: Function to retrieve state objects from an object store - */ - ZT_StateGetFunction stateGetFunction; - - /** - * REQUIRED: Function to send packets over the physical wire - */ - ZT_WirePacketSendFunction wirePacketSendFunction; - - /** - * REQUIRED: Function to inject frames into a virtual network's TAP - */ - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; - - /** - * REQUIRED: Function to be called when virtual networks are configured or changed - */ - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; - - /** - * REQUIRED: Function to be called to notify external code of important events - */ - ZT_EventCallback eventCallback; - - /** - * STRONGLY RECOMMENDED: Function to request a DNS lookup - */ - ZT_DNSResolver dnsResolver; - - /** - * OPTIONAL: Function to check whether a given physical path should be used - */ - ZT_PathCheckFunction pathCheckFunction; - - /** - * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses - */ - ZT_PathLookupFunction pathLookupFunction; -}; - -/** - * Create a new ZeroTier node - * - * This will attempt to load its identity via the state get function in the - * callback struct. If that fails it will generate a new identity and store - * it. Identity generation can take anywhere from a few hundred milliseconds - * to a few seconds depending on your CPU speed. - * - * @param node Result: pointer is set to new node instance on success - * @param uptr User pointer to pass to functions/callbacks - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param callbacks Callback function configuration - * @param now Current clock in milliseconds - * @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); - -/** - * Delete a node and free all resources it consumes - * - * If you are using multiple threads, all other threads must be shut down - * first. This can crash if processXXX() methods are in progress. - * - * @param node Node to delete - */ -ZT_SDK_API void ZT_Node_delete(ZT_Node *node); - -/** - * Process a packet received from the physical wire - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param now Current clock in milliseconds - * @param localSocket Local socket (you can use 0 if only one local socket is bound and ignore this) - * @param remoteAddress Origin of packet - * @param packetData Packet data - * @param packetLength Packet length - * @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 - */ -ZT_SDK_API enum ZT_ResultCode 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); - -/** - * Process a frame from a virtual network port (tap) - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param now Current clock in milliseconds - * @param nwid ZeroTier 64-bit virtual network ID - * @param sourceMac Source MAC address (least significant 48 bits) - * @param destMac Destination MAC address (least significant 48 bits) - * @param etherType 16-bit Ethernet frame type - * @param vlanId 10-bit VLAN ID or 0 if none - * @param frameData Frame payload data - * @param frameLength Frame payload length - * @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 - */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( - ZT_Node *node, - void *tptr, - int64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile int64_t *nextBackgroundTaskDeadline); - -/** - * Perform periodic background operations - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param now Current clock in milliseconds - * @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 - */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks( - ZT_Node *node, - void *tptr, - int64_t now, - volatile int64_t *nextBackgroundTaskDeadline); - -/** - * Submit the result(s) of a requested DNS query - * - * This MUST be called at least once after the node requsts DNS resolution. - * If there are no results or DNS is not implemented or available, just - * send one ZT_DNS_RECORD__END_OF_RESULTS to signal that no results were - * obtained. - * - * If result is non-NULL but resultLength is zero then result is assumed to - * be a C string terminated by a zero. Passing an unterminated string with a - * zero resultLength will result in a crash. - * - * The results of A and AAAA records can be returned as either strings or - * binary IP address bytes (network byte order). If the result is a string, - * resultLength must be 0 to signal that result is a C string. Otherwise for - * A resultLength must be 4 and for AAAA it must be 16 if the result is - * in binary format. - * - * The Node implementation makes an effort to ignore obviously invalid - * submissions like an AAAA record in bianry form with length 25, but this - * is not guaranteed. It's possible to crash your program by calling this - * with garbage inputs. - * - * Results may be submitted in any order and order should not be assumed - * to have any meaning. - * - * The ZT_DNS_RECORD__END_OF_RESULTS pseudo-response must be sent after all - * results have been submitted. The result and resultLength paramters are - * ignored for this type ID. - * - * It is safe to call this function from inside the DNS request callback, - * such as to return a locally cached result or a result from some kind - * of local database. It's also safe to call this function from threads - * other than the one that received the DNS request. - * - * @param node Node instance that requested DNS resolution - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param dnsRequestID Request ID supplied to DNS request callback - * @param recordType Record type of this result - * @param result Result (content depends on record type) - * @param resultLength Length of result - * @param resultIsString If non-zero, IP results for A and AAAA records are being given as C strings not binary IPs - */ -ZT_SDK_API void ZT_Node_processDNSResult( - ZT_Node *node, - void *tptr, - uintptr_t dnsRequestID, - enum ZT_DNSRecordType recordType, - const void *result, - unsigned int resultLength); - -/** - * Join a network - * - * This may generate calls to the port config callback before it returns, - * or these may be differed if a netconf is not available yet. - * - * If we are already a member of the network, nothing is done and OK is - * returned. - * - * @param node Node instance - * @param nwid 64-bit ZeroTier network ID - * @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 - */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr); - -/** - * Leave a network - * - * If a port has been configured for this network this will generate a call - * to the port config callback with a NULL second parameter to indicate that - * the port is now deleted. - * - * The uptr parameter is optional and is NULL by default. If it is not NULL, - * the pointer it points to is set to this network's uptr on success. - * - * @param node Node instance - * @param nwid 64-bit network ID - * @param uptr Target pointer is set to uptr (if not NULL) - * @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); - -/** - * Subscribe to an Ethernet multicast group - * - * ADI stands for additional distinguishing information. This defaults to zero - * and is rarely used. Right now its only use is to enable IPv4 ARP to scale, - * and this must be done. - * - * For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the - * broadcast address) but with an ADI equal to each IPv4 address in host - * byte order. This converts ARP from a non-scalable broadcast protocol to - * a scalable multicast protocol with perfect address specificity. - * - * If this is not done, ARP will not work reliably. - * - * Multiple calls to subscribe to the same multicast address will have no - * effect. It is perfectly safe to do this. - * - * This does not generate an update call to networkConfigCallback(). - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @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 - */ -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) - * - * If multicastGroup is zero (0), this will unsubscribe from all groups. If - * you are not subscribed to a group this has no effect. - * - * This does not generate an update call to networkConfigCallback(). - * - * @param node Node instance - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @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 - */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - -/** - * Get this node's 40-bit ZeroTier address - * - * @param node Node instance - * @return ZeroTier address (least significant 40 bits of 64-bit int) - */ -ZT_SDK_API uint64_t ZT_Node_address(ZT_Node *node); - -/** - * Get the status of this node - * - * @param node Node instance - * @param status Buffer to fill with current node status - */ -ZT_SDK_API void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status); - -/** - * Get a list of known peer nodes - * - * The pointer returned here must be freed with freeQueryResult() - * when you are done with it. - * - * @param node Node instance - * @return List of known peers or NULL on failure - */ -ZT_SDK_API ZT_PeerList *ZT_Node_peers(ZT_Node *node); - -/** - * Get the status of a virtual network - * - * The pointer returned here must be freed with freeQueryResult() - * when you are done with it. - * - * @param node Node instance - * @param nwid 64-bit network ID - * @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); - -/** - * Enumerate and get status of all networks - * - * @param node Node instance - * @return List of networks or NULL on failure - */ -ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node); - -/** - * Free a query result buffer - * - * Use this to free the return values of listNetworks(), listPeers(), etc. - * - * @param node Node instance - * @param qr Query result buffer - */ -ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); - -/** - * Add a local interface address - * - * This is used to make ZeroTier aware of those local interface addresses - * that you wish to use for ZeroTier communication. This is optional, and if - * it is not used ZeroTier will rely upon upstream peers (and roots) to - * perform empirical address discovery and NAT traversal. But the use of this - * method is recommended as it improves peer discovery when both peers are - * on the same LAN. - * - * It is the responsibility of the caller to take care that these are never - * ZeroTier interface addresses, whether these are assigned by ZeroTier or - * are otherwise assigned to an interface managed by this ZeroTier instance. - * This can cause recursion or other undesirable behavior. - * - * This returns a boolean indicating whether or not the address was - * accepted. ZeroTier will only communicate over certain address types - * and (for IP) address classes. - * - * @param addr Local interface address - * @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); - -/** - * Clear local interface addresses - */ -ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); - -/** - * Send a VERB_USER_MESSAGE to another ZeroTier node - * - * There is no delivery guarantee here. Failure can occur if the message is - * too large or if dest is not a valid ZeroTier address. - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param dest Destination ZeroTier address - * @param typeId VERB_USER_MESSAGE type ID - * @param data Payload data to attach to user message - * @param len Length of data in bytes - * @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); - -/** - * Set a network controller instance for this node - * - * Normal nodes should not need to use this. This is for nodes with - * special compiled-in support for acting as network configuration - * masters / controllers. - * - * The supplied instance must be a C++ object that inherits from the - * NetworkConfigMaster base class in node/. No type checking is performed, - * so a pointer to anything else will result in a crash. - * - * @param node ZertTier One node - * @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable - * @return OK (0) or error code if a fatal error condition has occurred - */ -ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterInstance); - -/** - * Set configuration for a given physical path - * - * @param node Node instance - * @param pathNetwork Network/CIDR of path or NULL to clear the cache and reset all paths to default - * @param pathConfig Path configuration or NULL to erase this entry and therefore reset it to NULL - * @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); - -/** - * Get ZeroTier One version - * - * @param major Result: major version - * @param minor Result: minor version - * @param revision Result: revision - */ -ZT_SDK_API void ZT_version(int *major,int *minor,int *revision); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h new file mode 120000 index 000000000..9f6d7e3a1 --- /dev/null +++ b/include/ZeroTierOne.h @@ -0,0 +1 @@ +ZeroTierCore.h \ No newline at end of file diff --git a/node/Constants.hpp b/node/Constants.hpp index 5e0c0cc41..79191f14c 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -14,7 +14,7 @@ #ifndef ZT_CONSTANTS_HPP #define ZT_CONSTANTS_HPP -#include "../include/ZeroTierOne.h" +#include "../include/ZeroTierCore.h" #if __has_include("version.h") #include "version.h" @@ -163,6 +163,17 @@ #endif #endif +#ifdef SOCKET +#define ZT_SOCKET SOCKET +#else +#define ZT_SOCKET int +#endif +#ifdef INVALID_SOCKET +#define ZT_INVALID_SOCKET INVALID_SOCKET +#else +#define ZT_INVALID_SOCKET -1 +#endif + /** * Length of a ZeroTier address in bytes */ @@ -452,9 +463,14 @@ * See https://conferences.sigcomm.org/imc/2010/papers/p260.pdf for * some real world data on NAT UDP timeouts. From the paper: "the * lowest measured timeout when a binding has seen bidirectional - * traffic is 54 sec." We use 45 to be a bit under this. + * traffic is 54 sec." 30 seconds is faster than really necessary. */ -#define ZT_PEER_PING_PERIOD 45000 +#define ZT_PEER_PING_PERIOD 30000 + +/** + * Delay between refreshes of locators via DNS or other methods + */ +#define ZT_DYNAMIC_ROOT_UPDATE_PERIOD 120000 /** * Timeout for overall peer activity (measured from last receive) diff --git a/node/Locator.hpp b/node/Locator.hpp index dc21abe47..97b3150be 100644 --- a/node/Locator.hpp +++ b/node/Locator.hpp @@ -243,6 +243,8 @@ public: * record signing public key. False is returned if the TXT records are invalid, * incomplete, or fail signature check. If true is returned this Locator object * now contains the contents of the supplied TXT records. + * + * @return True if new Locator is valid */ template inline bool decodeTxtRecords(const Str &dnsName,I start,I end) diff --git a/node/Network.cpp b/node/Network.cpp index cf9edaa72..9f685411b 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1270,7 +1270,7 @@ void Network::_requestConfiguration(void *tPtr) const Address ctrl(controller()); ScopedPtr< Dictionary > rmd(new Dictionary()); - rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR,(uint64_t)ZT_VENDOR_ZEROTIER); + rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR,(uint64_t)1); // 1 == ZeroTier, no other vendors at the moment rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION); rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR); rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MINOR); diff --git a/node/Node.cpp b/node/Node.cpp index e4fc90937..33ea617f2 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -49,12 +49,12 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64 _now(now), _lastPing(0), _lastHousekeepingRun(0), - _lastNetworkHousekeepingRun(0) + _lastNetworkHousekeepingRun(0), + _lastDynamicRootUpdate(0), + _online(false) { memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); - _online = false; - memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); @@ -173,6 +173,35 @@ ZT_ResultCode Node::processVirtualNetworkFrame( } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } +// This is passed as the argument to the DNS request handler and +// aggregates results. +struct _processBackgroundTasks_dnsResultAccumulator +{ + _processBackgroundTasks_dnsResultAccumulator(const Str &n) : dnsName(n) {} + Str dnsName; + std::vector txtRecords; +}; + +static const ZT_DNSRecordType s_txtRecordType[1] = { ZT_DNS_RECORD_TXT }; + +struct _processBackgroundTasks_check_dynamicRoots +{ + ZT_Node_Callbacks *cb; + Node *n; + void *uPtr; + void *tPtr; + bool updateAll; + + ZT_ALWAYS_INLINE bool operator()(const Str &dnsName,const Locator &loc) + { + if ((updateAll)||(!loc)) { + _processBackgroundTasks_dnsResultAccumulator *dnsReq = new _processBackgroundTasks_dnsResultAccumulator(dnsName); + cb->dnsResolver(reinterpret_cast(n),uPtr,tPtr,s_txtRecordType,1,dnsName.c_str(),(uintptr_t)dnsReq); + } + return true; + } +}; + struct _processBackgroundTasks_ping_eachRoot { Hashtable< void *,bool > roots; @@ -227,18 +256,37 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 if ((now - _lastPing) >= ZT_PEER_PING_PERIOD) { _lastPing = now; try { + // Periodically refresh locators for dynamic roots from their DNS names. + if (_cb.dnsResolver) { + _processBackgroundTasks_check_dynamicRoots cr; + cr.cb = &_cb; + cr.n = this; + cr.uPtr = _uPtr; + cr.tPtr = tptr; + if ((now - _lastDynamicRootUpdate) >= ZT_DYNAMIC_ROOT_UPDATE_PERIOD) { + _lastDynamicRootUpdate = now; + cr.updateAll = true; + } else { + cr.updateAll = false; + } + RR->topology->eachDynamicRoot(cr); + } + + // Ping each root explicitly no matter what _processBackgroundTasks_ping_eachRoot rf; rf.now = now; rf.tPtr = tptr; rf.online = false; RR->topology->eachRoot(rf); + // Ping peers that are active and we want to keep alive _processBackgroundTasks_ping_eachPeer pf; pf.now = now; pf.tPtr = tptr; pf.roots = &rf.roots; RR->topology->eachPeer(pf); + // Update online status based on whether we can reach a root if (rf.online != _online) { _online = rf.online; postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); @@ -298,6 +346,30 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64 return ZT_RESULT_OK; } +void Node::processDNSResult( + void *tptr, + uintptr_t dnsRequestID, + const char *name, + enum ZT_DNSRecordType recordType, + const void *result, + unsigned int resultLength, + int resultIsString) +{ + if (dnsRequestID) { + _processBackgroundTasks_dnsResultAccumulator *const acc = reinterpret_cast<_processBackgroundTasks_dnsResultAccumulator *>(dnsRequestID); + if (recordType == ZT_DNS_RECORD_TXT) { + if (result) + acc->txtRecords.emplace_back(reinterpret_cast(result)); + } else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) { + Locator loc; + if (loc.decodeTxtRecords(acc->dnsName,acc->txtRecords.begin(),acc->txtRecords.end())) { + RR->topology->setDynamicRoot(acc->dnsName,loc); + delete acc; + } + } + } +} + ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr) { Mutex::Lock _l(_networks_m); @@ -357,6 +429,68 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; } +ZT_RootList *Node::listRoots(int64_t now) +{ + return RR->topology->apiRoots(now); +} + +enum ZT_ResultCode Node::setStaticRoot(const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount) +{ + if (!identity) + return ZT_RESULT_ERROR_BAD_PARAMETER; + Identity id; + if (id.fromString(identity)) { + if (id) { + std::vector addrs; + for(unsigned int i=0;itopology->setStaticRoot(identity,addrs); + return ZT_RESULT_OK; + } + } + return ZT_RESULT_ERROR_BAD_PARAMETER; +} + +enum ZT_ResultCode Node::setDynamicRoot(const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize) +{ + if (!dnsName) + return ZT_RESULT_ERROR_BAD_PARAMETER; + if (strlen(dnsName) >= 256) + return ZT_RESULT_ERROR_BAD_PARAMETER; + try { + Locator loc; + if ((defaultLocator)&&(defaultLocatorSize > 0)&&(defaultLocatorSize < 65535)) { + ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>()); + locbuf->append(defaultLocator,defaultLocatorSize); + loc.deserialize(*locbuf,0); + if (!loc.verify()) + loc = Locator(); + } + return RR->topology->setDynamicRoot(Str(dnsName),loc) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED; + } catch ( ... ) { + return ZT_RESULT_ERROR_BAD_PARAMETER; + } +} + +enum ZT_ResultCode Node::removeStaticRoot(const char *identity) +{ + if (identity) { + Identity id; + if (id.fromString(identity)) + RR->topology->removeStaticRoot(id); + } + return ZT_RESULT_OK; +} + +enum ZT_ResultCode Node::removeDynamicRoot(const char *dnsName) +{ + try { + if (dnsName) + RR->topology->removeDynamicRoot(Str(dnsName)); + } catch ( ... ) {} + return ZT_RESULT_OK; +} + uint64_t Node::address() const { return RR->identity.address().toInt(); @@ -726,6 +860,21 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64 } } +void ZT_Node_processDNSResult( + ZT_Node *node, + void *tptr, + uintptr_t dnsRequestID, + const char *name, + enum ZT_DNSRecordType recordType, + const void *result, + unsigned int resultLength, + int resultIsString) +{ + try { + reinterpret_cast(node)->processDNSResult(tptr,dnsRequestID,name,recordType,result,resultLength,resultIsString); + } catch ( ... ) {} +} + enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr) { try { @@ -770,6 +919,59 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint } } +ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now) +{ + try { + return reinterpret_cast(node)->listRoots(now); + } catch ( ... ) { + return nullptr; + } +} + +enum ZT_ResultCode ZT_Node_setStaticRoot(ZT_Node *node,const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount) +{ + try { + return reinterpret_cast(node)->setStaticRoot(identity,addresses,addressCount); + } catch (std::bad_alloc &exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +enum ZT_ResultCode ZT_Node_setDynamicRoot(ZT_Node *node,const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize) +{ + try { + return reinterpret_cast(node)->setDynamicRoot(dnsName,defaultLocator,defaultLocatorSize); + } catch (std::bad_alloc &exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +enum ZT_ResultCode ZT_Node_removeStaticRoot(ZT_Node *node,const char *identity) +{ + try { + return reinterpret_cast(node)->removeStaticRoot(identity); + } catch (std::bad_alloc &exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +enum ZT_ResultCode ZT_Node_removeDynamicRoot(ZT_Node *node,const char *dnsName) +{ + try { + return reinterpret_cast(node)->removeDynamicRoot(dnsName); + } catch (std::bad_alloc &exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + uint64_t ZT_Node_address(ZT_Node *node) { return reinterpret_cast(node)->address(); diff --git a/node/Node.hpp b/node/Node.hpp index c9cf7327b..4e55c35e1 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -80,10 +80,23 @@ public: unsigned int frameLength, volatile int64_t *nextBackgroundTaskDeadline); ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); + void processDNSResult( + void *tptr, + uintptr_t dnsRequestID, + const char *name, + enum ZT_DNSRecordType recordType, + const void *result, + unsigned int resultLength, + int resultIsString); ZT_ResultCode join(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 multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); + ZT_RootList *listRoots(int64_t now); + enum ZT_ResultCode setStaticRoot(const char *identity,const struct sockaddr_storage *addresses,unsigned int addressCount); + enum ZT_ResultCode setDynamicRoot(const char *dnsName,const void *defaultLocator,unsigned int defaultLocatorSize); + enum ZT_ResultCode removeStaticRoot(const char *identity); + enum ZT_ResultCode removeDynamicRoot(const char *dnsName); uint64_t address() const; void status(ZT_NodeStatus *status) const; ZT_PeerList *peers() const; @@ -289,6 +302,7 @@ private: int64_t _lastPing; int64_t _lastHousekeepingRun; int64_t _lastNetworkHousekeepingRun; + int64_t _lastDynamicRootUpdate; bool _online; }; diff --git a/node/Topology.hpp b/node/Topology.hpp index a67720921..5bb3416c5 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -72,7 +72,7 @@ private: Str *k = (Str *)0; Locator *v = (Locator *)0; while (i.next(k,v)) { - if (v->id()) + if (*v) _dynamicRootIdentities.set(v->id(),true); } } @@ -211,7 +211,7 @@ public: * @param now Current time * @return Number of peers with active direct paths */ - ZT_ALWAYS_INLINE unsigned long countActive(int64_t now) const + inline unsigned long countActive(int64_t now) const { unsigned long cnt = 0; Mutex::Lock _l(_peers_l); @@ -340,7 +340,7 @@ public: * @param id Static root's identity * @param addrs Static root's IP address(es) */ - ZT_ALWAYS_INLINE void setStaticRoot(const Identity &id,const std::vector &addrs) + inline void setStaticRoot(const Identity &id,const std::vector &addrs) { Mutex::Lock l(_staticRoots_l); _staticRoots[id] = addrs; @@ -351,7 +351,7 @@ public: * * @param id Identity to remove */ - ZT_ALWAYS_INLINE void removeStaticRoot(const Identity &id) + inline void removeStaticRoot(const Identity &id) { Mutex::Lock l(_staticRoots_l); _staticRoots.erase(id); @@ -360,19 +360,28 @@ public: /** * Clear all static roots */ - ZT_ALWAYS_INLINE void removeStaticRoot() + inline void removeStaticRoot() { Mutex::Lock l(_staticRoots_l); _staticRoots.clear(); } /** - * @return Names of dynamic roots currently known by the system + * Iterate through all dynamic roots + * + * @param f Function of (Str,Locator) */ - ZT_ALWAYS_INLINE std::vector dynamicRootNames() const + template + ZT_ALWAYS_INLINE void eachDynamicRoot(F f) const { Mutex::Lock l(_dynamicRoots_l); - return _dynamicRoots.keys(); + Str *k = (Str *)0; + Locator *v = (Locator *)0; + Hashtable< Str,Locator >::Iterator i(const_cast(this)->_dynamicRoots); + while (i.next(k,v)) { + if (!f(*k,*v)) + break; + } } /** @@ -382,15 +391,20 @@ public: * * @param dnsName DNS name used to retrive root * @param latestLocator Latest locator - * @return True if locator is newer + * @return True if locator is newer or if a new entry was created */ - ZT_ALWAYS_INLINE bool setDynamicRoot(const Str &dnsName,const Locator &latestLocator) + inline bool setDynamicRoot(const Str &dnsName,const Locator &latestLocator) { Mutex::Lock l(_dynamicRoots_l); - Locator &ll = _dynamicRoots[dnsName]; - if (ll.timestamp() < latestLocator.timestamp()) { - ll = latestLocator; - _updateDynamicRootIdentities(); + if (latestLocator) { + Locator &ll = _dynamicRoots[dnsName]; + if (ll.timestamp() < latestLocator.timestamp()) { + ll = latestLocator; + _updateDynamicRootIdentities(); + return true; + } + } else if (!_dynamicRoots.contains(dnsName)) { + _dynamicRoots[dnsName]; return true; } return false; @@ -401,7 +415,7 @@ public: * * @param dnsName DNS name to remove */ - ZT_ALWAYS_INLINE void removeDynamicRoot(const Str &dnsName) + inline void removeDynamicRoot(const Str &dnsName) { Mutex::Lock l(_dynamicRoots_l); _dynamicRoots.erase(dnsName); @@ -411,13 +425,109 @@ public: /** * Remove all dynamic roots */ - ZT_ALWAYS_INLINE void clearDynamicRoots() + inline void clearDynamicRoots() { Mutex::Lock l(_dynamicRoots_l); _dynamicRoots.clear(); _dynamicRootIdentities.clear(); } + /** + * @param Current time + * @return ZT_RootList as returned by the external CAPI + */ + inline ZT_RootList *apiRoots(const int64_t now) const + { + Mutex::Lock l1(_staticRoots_l); + Mutex::Lock l2(_dynamicRoots_l); + + // The memory allocated here has room for all roots plus the maximum size + // of their DNS names, identities, and up to 16 physical addresses. Most + // roots will have two: one V4 and one V6. + const unsigned int totalRoots = _staticRoots.size() + _dynamicRoots.size(); + ZT_RootList *rl = reinterpret_cast(malloc(sizeof(ZT_RootList) + (sizeof(ZT_Root) * totalRoots) + ((sizeof(struct sockaddr_storage) * ZT_MAX_PEER_NETWORK_PATHS) * totalRoots) + ((ZT_IDENTITY_STRING_BUFFER_LENGTH + 1024) * totalRoots))); + if (!rl) { + return nullptr; + } + + unsigned int c = 0; + char *nameBufPtr = reinterpret_cast(rl) + sizeof(ZT_RootList) + (sizeof(ZT_Root) * totalRoots); + struct sockaddr_storage *addrBuf = reinterpret_cast(nameBufPtr); + nameBufPtr += (sizeof(struct sockaddr_storage) * ZT_MAX_PEER_NETWORK_PATHS) * totalRoots; + + _bestRoot_l.lock(); + const Peer *const bestRootPtr = _bestRoot.ptr(); + _bestRoot_l.unlock(); + + { + Str *k = (Str *)0; + Locator *v = (Locator *)0; + Hashtable< Str,Locator >::Iterator i(const_cast(this)->_dynamicRoots); + while (i.next(k,v)) { + rl->roots[c].dnsName = nameBufPtr; + const char *p = k->c_str(); + while (*p) + *(nameBufPtr++) = *(p++); + *(nameBufPtr++) = (char)0; + + if (v->id()) { + rl->roots[c].identity = nameBufPtr; + v->id().toString(false,nameBufPtr); + nameBufPtr += strlen(nameBufPtr) + 1; + } + + rl->roots[c].addresses = addrBuf; + unsigned int ac = 0; + for(unsigned int j=(unsigned int)v->phy().size();(acphy()[ac]; + rl->roots[c].addressCount = ac; + + _peers_l.lock(); + const SharedPtr *psptr = _peers.get(v->id().address()); + if (psptr) { + rl->roots[c].preferred = (psptr->ptr() == bestRootPtr) ? 1 : 0; + rl->roots[c].online = (*psptr)->alive(now) ? 1 : 0; + } + _peers_l.unlock(); + + ++c; + } + } + + { + Hashtable< Identity,std::vector >::Iterator i(const_cast(this)->_staticRoots); + Identity *k = (Identity *)0; + std::vector *v = (std::vector *)0; + while (i.next(k,v)) { + rl->roots[c].dnsName = nullptr; + + rl->roots[c].identity = nameBufPtr; + k->toString(false,nameBufPtr); + nameBufPtr += strlen(nameBufPtr) + 1; + + rl->roots[c].addresses = addrBuf; + unsigned int ac = 0; + for(unsigned int j=(unsigned int)v->size();(acroots[c].addressCount = ac; + + _peers_l.lock(); + const SharedPtr *psptr = _peers.get(k->address()); + if (psptr) { + rl->roots[c].preferred = (psptr->ptr() == bestRootPtr) ? 1 : 0; + rl->roots[c].online = (*psptr)->alive(now) ? 1 : 0; + } + _peers_l.unlock(); + + ++c; + } + } + + rl->count = c; + + return rl; + } + /** * Get the best relay to a given address, which may or may not be a root * diff --git a/service/OneService.cpp b/service/OneService.cpp index 9709b0f35..58fe24cf6 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -25,7 +25,7 @@ #include #include -#include "../include/ZeroTierOne.h" +#include "../include/ZeroTierCore.h" #include "../node/Constants.hpp" #include "../node/Mutex.hpp" @@ -1844,6 +1844,9 @@ public: OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); break; + case ZT_STATE_OBJECT_ROOT_LIST: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "roots",_homePath.c_str()); + break; default: return; }