/* * Copyright (c)2013-2021 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: 2026-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. */ /****/ /** * @file * * Node / Network control interface */ #include "Events.hpp" #include "NodeService.hpp" #include "Signals.hpp" #include "VirtualTap.hpp" #include using namespace ZeroTier; #ifdef __WINDOWS__ #include WSADATA wsaData; #endif #ifdef ZTS_ENABLE_PYTHON #define ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS 1 #endif namespace ZeroTier { #ifdef ZTS_ENABLE_PYTHON #endif #ifdef ZTS_ENABLE_PINVOKE extern void (*_userEventCallback)(void*); #endif #ifdef ZTS_C_API_ONLY extern void (*_userEventCallback)(void*); #endif extern uint8_t allowNetworkCaching; extern uint8_t allowPeerCaching; NodeService* zts_service; Events* zts_events; extern Mutex events_m; Mutex service_m; int init_subsystems() { /** Set up service and callback threads and tell them about one another. * A separate thread is used for callbacks so that if the user fails to * return control it won't affect the core service's operations. */ if (! zts_events) { zts_events = new Events(); } if (zts_events->getState(ZTS_STATE_FREE_CALLED)) { return ZTS_ERR_SERVICE; } #ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS zts_install_signal_handlers(); #endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS if (! zts_service) { #if defined(__WINDOWS__) WSAStartup(MAKEWORD(2, 2), &wsaData); #endif zts_service = new NodeService(); zts_service->setUserEventSystem(zts_events); } return ZTS_ERR_OK; } #ifdef __cplusplus extern "C" { #endif int zts_init_from_storage(const char* path) { ACQUIRE_SERVICE_OFFLINE(); zts_service->setHomePath(path); return ZTS_ERR_OK; } int zts_init_from_memory(const char* keypair, unsigned int len) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->setIdentity(keypair, len); } #ifdef ZTS_ENABLE_PYTHON int zts_init_set_event_handler(PythonDirectorCallbackClass* callback) #endif #ifdef ZTS_ENABLE_PINVOKE int zts_init_set_event_handler(CppCallback callback) #endif #ifdef ZTS_ENABLE_JAVA int zts_init_set_event_handler(jobject obj_ref, jmethodID id) #endif #ifdef ZTS_C_API_ONLY int zts_init_set_event_handler(void (*callback)(void*)) #endif { ACQUIRE_SERVICE_OFFLINE(); #ifdef ZTS_ENABLE_JAVA zts_events->setJavaCallback(obj_ref, id); #else if (! callback) { return ZTS_ERR_ARG; } _userEventCallback = callback; #endif zts_service->enableEvents(); return ZTS_ERR_OK; } int zts_init_set_tcp_relay(const char* tcp_relay_addr, unsigned short tcp_relay_port) { ACQUIRE_SERVICE_OFFLINE(); zts_service->setTcpRelayAddress(tcp_relay_addr, tcp_relay_port); return ZTS_ERR_OK; } int zts_init_allow_tcp_relay(bool enabled) { ACQUIRE_SERVICE_OFFLINE(); zts_service->allowTcpRelay(enabled); return ZTS_ERR_OK; } int zts_init_force_tcp_relay(bool enabled) { ACQUIRE_SERVICE_OFFLINE(); zts_service->forceTcpRelay(enabled); return ZTS_ERR_OK; } int zts_init_blacklist_if(const char* prefix, unsigned int len) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->addInterfacePrefixToBlacklist(prefix, len); } int zts_init_set_roots(const void* roots_data, unsigned int len) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->setRoots(roots_data, len); } int zts_init_set_low_bandwidth_mode(bool enabled) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->setLowBandwidthMode(enabled); } int zts_init_set_port(unsigned short port) { ACQUIRE_SERVICE_OFFLINE(); zts_service->setPrimaryPort(port); return ZTS_ERR_OK; } int zts_init_set_random_port_range(unsigned short start_port, unsigned short end_port) { ACQUIRE_SERVICE_OFFLINE(); zts_service->setRandomPortRange(start_port, end_port); return ZTS_ERR_OK; } int zts_init_allow_secondary_port(unsigned int allowed) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->allowSecondaryPort(allowed); } int zts_init_allow_port_mapping(unsigned int allowed) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->allowPortMapping(allowed); } int zts_init_allow_peer_cache(unsigned int allowed) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->allowPeerCaching(allowed); } int zts_init_allow_net_cache(unsigned int allowed) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->allowNetworkCaching(allowed); } int zts_init_allow_roots_cache(unsigned int allowed) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->allowRootSetCaching(allowed); } int zts_init_allow_id_cache(unsigned int allowed) { ACQUIRE_SERVICE_OFFLINE(); return zts_service->allowIdentityCaching(allowed); } int zts_addr_compute_6plane(const uint64_t net_id, const uint64_t node_id, struct zts_sockaddr_storage* addr) { if (! addr || ! net_id || ! node_id) { return ZTS_ERR_ARG; } InetAddress _6planeAddr = InetAddress::makeIpv66plane(net_id, node_id); struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr; memcpy(in6->sin6_addr.s6_addr, _6planeAddr.rawIpData(), sizeof(struct in6_addr)); return ZTS_ERR_OK; } int zts_addr_compute_rfc4193(const uint64_t net_id, const uint64_t node_id, struct zts_sockaddr_storage* addr) { if (! addr || ! net_id || ! node_id) { return ZTS_ERR_ARG; } InetAddress _rfc4193Addr = InetAddress::makeIpv6rfc4193(net_id, node_id); struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr; memcpy(in6->sin6_addr.s6_addr, _rfc4193Addr.rawIpData(), sizeof(struct in6_addr)); return ZTS_ERR_OK; } int zts_addr_compute_rfc4193_str(uint64_t net_id, uint64_t node_id, char* dst, unsigned int len) { if (! net_id || ! node_id || ! dst || len != ZTS_IP_MAX_STR_LEN) { return ZTS_ERR_ARG; } struct zts_sockaddr_storage ss; int err = ZTS_ERR_OK; if ((err = zts_addr_compute_rfc4193(net_id, node_id, &ss)) != ZTS_ERR_OK) { return err; } struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&ss; zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), dst, ZTS_IP_MAX_STR_LEN); return ZTS_ERR_OK; } int zts_addr_compute_6plane_str(uint64_t net_id, uint64_t node_id, char* dst, unsigned int len) { if (! net_id || ! node_id || ! dst || len != ZTS_IP_MAX_STR_LEN) { return ZTS_ERR_ARG; } struct zts_sockaddr_storage ss; int err = ZTS_ERR_OK; if ((err = zts_addr_compute_6plane(net_id, node_id, &ss)) != ZTS_ERR_OK) { return err; } struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&ss; zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), dst, ZTS_IP_MAX_STR_LEN); return ZTS_ERR_OK; } uint64_t zts_net_compute_adhoc_id(unsigned short start_port, unsigned short end_port) { char net_id_str[ZTS_INET6_ADDRSTRLEN] = { 0 }; OSUtils::ztsnprintf(net_id_str, ZTS_INET6_ADDRSTRLEN, "ff%04x%04x000000", start_port, end_port); return strtoull(net_id_str, NULL, 16); } int zts_id_new(char* key, unsigned int* dst_len) { if (key == NULL || *dst_len != ZT_IDENTITY_STRING_BUFFER_LENGTH) { return ZTS_ERR_ARG; } Identity id; id.generate(); char idtmp[1024] = { 0 }; std::string idser = id.toString(true, idtmp); unsigned int key_pair_len = idser.length(); if (key_pair_len > *dst_len) { return ZTS_ERR_ARG; } memcpy(key, idser.c_str(), key_pair_len); *dst_len = key_pair_len; return ZTS_ERR_OK; } int zts_id_pair_is_valid(const char* key, unsigned int len) { if (key == NULL || len != ZT_IDENTITY_STRING_BUFFER_LENGTH) { return false; } Identity id; if ((strnlen(key, len) > 32) && (key[10] == ':')) { if (id.fromString(key)) { return id.locallyValidate(); } } return false; } int zts_node_get_id_pair(char* key, unsigned int* key_dst_len) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); int err = ZTS_ERR_OK; if ((err = zts_service->getIdentity(key, key_dst_len)) != ZTS_ERR_OK) { return err; } return *key_dst_len > 0 ? ZTS_ERR_OK : ZTS_ERR_GENERAL; } #if defined(__WINDOWS__) DWORD WINAPI cbRun(LPVOID arg) #else void* cbRun(void* arg) #endif { ZTS_UNUSED_ARG(arg); #if defined(__APPLE__) // pthread_setname_np(ZTS_EVENT_CALLBACK_THREAD_NAME); #endif zts_events->run(); //#if ZTS_ENABLE_JAVA // _java_detach_from_thread(); // pthread_exit(0); //#endif return NULL; } int zts_addr_is_assigned(uint64_t net_id, unsigned int family) { ACQUIRE_SERVICE(0); return zts_service->addrIsAssigned(net_id, family); } int zts_addr_get(uint64_t net_id, unsigned int family, struct zts_sockaddr_storage* addr) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getFirstAssignedAddr(net_id, family, addr); } int zts_addr_get_str(uint64_t net_id, unsigned int family, char* dst, unsigned int len) { // No service lock required since zts_addr_get will lock it if (net_id == 0) { return ZTS_ERR_ARG; } if (len < ZTS_INET6_ADDRSTRLEN) { return ZTS_ERR_ARG; } if (family == ZTS_AF_INET) { struct zts_sockaddr_storage ss; int err = ZTS_ERR_OK; if ((err = zts_addr_get(net_id, family, &ss)) != ZTS_ERR_OK) { return err; } struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)&ss; zts_inet_ntop(family, &(in4->sin_addr), dst, ZTS_INET6_ADDRSTRLEN); } if (family == ZTS_AF_INET6) { struct zts_sockaddr_storage ss; int err = ZTS_ERR_OK; if ((err = zts_addr_get(net_id, family, &ss)) != ZTS_ERR_OK) { return err; } struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&ss; zts_inet_ntop(family, &(in6->sin6_addr), dst, ZTS_INET6_ADDRSTRLEN); } return ZTS_ERR_OK; } int zts_addr_get_all(uint64_t net_id, struct zts_sockaddr_storage* addr, unsigned int* count) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getAllAssignedAddr(net_id, addr, count); } int zts_core_lock_obtain() { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); zts_service->obtainLock(); return ZTS_ERR_OK; } int zts_core_lock_release() { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); zts_service->releaseLock(); return ZTS_ERR_OK; } int zts_core_query_addr_count(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->addressCount(net_id); } int zts_core_query_addr(uint64_t net_id, unsigned int idx, char* addr, unsigned int len) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getAddrAtIdx(net_id, idx, addr, len); } int zts_core_query_route_count(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->routeCount(net_id); } int zts_core_query_route( uint64_t net_id, unsigned int idx, char* target, char* via, unsigned int len, uint16_t* flags, uint16_t* metric) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getRouteAtIdx(net_id, idx, target, via, len, flags, metric); } int zts_core_query_path_count(uint64_t peer_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->pathCount(peer_id); } int zts_core_query_path(uint64_t peer_id, unsigned int idx, char* path, unsigned int len) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getPathAtIdx(peer_id, idx, path, len); } int zts_core_query_mc_count(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->multicastSubCount(net_id); } int zts_core_query_mc(uint64_t net_id, unsigned int idx, uint64_t* mac, uint32_t* adi) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getMulticastSubAtIdx(net_id, idx, mac, adi); } int zts_net_join(const uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->join(net_id); } int zts_net_leave(const uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->leave(net_id); } int zts_net_transport_is_ready(const uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->networkIsReady(net_id); } uint64_t zts_net_get_mac(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getMACAddress(net_id); } ZTS_API int ZTCALL zts_net_get_mac_str(uint64_t net_id, char* dst, unsigned int len) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); if (! dst || len < ZTS_MAC_ADDRSTRLEN) { return ZTS_ERR_ARG; } uint64_t mac = zts_service->getMACAddress(net_id); OSUtils::ztsnprintf( dst, ZTS_MAC_ADDRSTRLEN, "%x:%x:%x:%x:%x:%x", (mac >> 40) & 0xFF, (mac >> 32) & 0xFF, (mac >> 24) & 0xFF, (mac >> 16) & 0xFF, (mac >> 8) & 0xFF, (mac >> 0) & 0xFF); return ZTS_ERR_OK; } int zts_net_get_broadcast(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getNetworkBroadcast(net_id); } int zts_net_get_mtu(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getNetworkMTU(net_id); } int zts_net_get_name(uint64_t net_id, char* dst, unsigned int len) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getNetworkName(net_id, dst, len); } int zts_net_get_status(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getNetworkStatus(net_id); } int zts_net_get_type(uint64_t net_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getNetworkType(net_id); } int zts_route_is_assigned(uint64_t net_id, unsigned int family) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->networkHasRoute(net_id, family); } // Start a ZeroTier NodeService background thread #if defined(__WINDOWS__) DWORD WINAPI _runNodeService(LPVOID arg) #else void* _runNodeService(void* arg) #endif { ZTS_UNUSED_ARG(arg); #if defined(__APPLE__) // pthread_setname_np(ZTS_SERVICE_THREAD_NAME); #endif try { zts_service->run(); // Begin shutdown service_m.lock(); zts_events->clrState(ZTS_STATE_NODE_RUNNING); delete zts_service; zts_service = (NodeService*)0; service_m.unlock(); events_m.lock(); zts_util_delay(ZTS_CALLBACK_PROCESSING_INTERVAL * 2); if (zts_events) { zts_events->disable(); } events_m.unlock(); } catch (...) { } #ifndef __WINDOWS__ pthread_exit(0); #endif return NULL; } int zts_node_start() { ACQUIRE_SERVICE_OFFLINE(); // Start TCP/IP stack zts_lwip_driver_init(); // Start callback thread int res = ZTS_ERR_OK; if (zts_events->hasCallback()) { #if defined(__WINDOWS__) HANDLE callbackThread = CreateThread(NULL, 0, cbRun, NULL, 0, NULL); // TODO: Check success #else pthread_t cbThread; if ((res = pthread_create(&cbThread, NULL, cbRun, NULL)) != 0) {} #endif #if defined(__linux__) // pthread_setname_np(cbThread, ZTS_EVENT_CALLBACK_THREAD_NAME); #endif if (res != ZTS_ERR_OK) { zts_events->clrState(ZTS_STATE_CALLBACKS_RUNNING); zts_events->clrCallback(); } zts_events->setState(ZTS_STATE_CALLBACKS_RUNNING); } // Start ZeroTier service #if defined(__WINDOWS__) HANDLE serviceThread = CreateThread(NULL, 0, _runNodeService, (void*)NULL, 0, NULL); // TODO: Check success #else pthread_t service_thread; if ((res = pthread_create(&service_thread, NULL, _runNodeService, (void*)NULL)) != 0) {} #endif #if defined(__linux__) // pthread_setname_np(service_thread, ZTS_SERVICE_THREAD_NAME); #endif if (res != ZTS_ERR_OK) { zts_events->clrState(ZTS_STATE_NODE_RUNNING); } zts_events->setState(ZTS_STATE_NODE_RUNNING); return ZTS_ERR_OK; } int zts_node_is_online() { ACQUIRE_SERVICE(0); return zts_service->nodeIsOnline(); } uint64_t zts_node_get_id() { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getNodeId(); } int zts_node_get_port() { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); return zts_service->getPrimaryPort(); } int zts_node_stop() { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); zts_events->clrState(ZTS_STATE_NODE_RUNNING); zts_service->terminate(); #if defined(__WINDOWS__) WSACleanup(); #endif return ZTS_ERR_OK; } int zts_node_free() { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); zts_events->setState(ZTS_STATE_FREE_CALLED); zts_events->clrState(ZTS_STATE_NODE_RUNNING); zts_service->terminate(); #if defined(__WINDOWS__) WSACleanup(); #endif zts_lwip_driver_shutdown(); delete zts_events; zts_events = (Events*)0; return ZTS_ERR_OK; } int zts_moon_orbit(uint64_t moon_roots_id, uint64_t moon_seed) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); zts_service->orbit(moon_roots_id, moon_seed); return ZTS_ERR_OK; } int zts_moon_deorbit(uint64_t moon_roots_id) { ACQUIRE_SERVICE(ZTS_ERR_SERVICE); zts_service->deorbit(moon_roots_id); return ZTS_ERR_OK; } int zts_stats_get_all(zts_stats_counter_t* dst) { if (! dst) { return ZTS_ERR_ARG; } if (! transport_ok()) { return ZTS_ERR_SERVICE; } #if LWIP_STATS extern struct stats_ lwip_stats; #define lws lwip_stats /* Summarize lwIP's statistics for simplicity at the expense of specificity */ // link dst->link_tx = lws.link.xmit; dst->link_rx = lws.link.recv; dst->link_drop = lws.link.drop; dst->link_err = lws.link.chkerr + lws.link.lenerr + lws.link.memerr + lws.link.rterr + lws.link.proterr + lws.link.opterr + lws.link.err; // etharp dst->etharp_tx = lws.etharp.xmit; dst->etharp_rx = lws.etharp.recv; dst->etharp_drop = lws.etharp.drop; dst->etharp_err = lws.etharp.chkerr + lws.etharp.lenerr + lws.etharp.memerr + lws.etharp.rterr + lws.etharp.proterr + lws.etharp.opterr + lws.etharp.err; // ip4 dst->ip4_tx = lws.ip.xmit; dst->ip4_rx = lws.ip.recv; dst->ip4_drop = lws.ip.drop; dst->ip4_err = lws.ip.chkerr + lws.ip.lenerr + lws.ip.memerr + lws.ip.rterr + lws.ip.proterr + lws.ip.opterr + lws.ip.err + lws.ip_frag.chkerr + lws.ip_frag.lenerr + lws.ip_frag.memerr + lws.ip_frag.rterr + lws.ip_frag.proterr + lws.ip_frag.opterr + lws.ip_frag.err; // ip6 dst->ip6_tx = lws.ip6.xmit; dst->ip6_rx = lws.ip6.recv; dst->ip6_drop = lws.ip6.drop; dst->ip6_err = lws.ip6.chkerr + lws.ip6.lenerr + lws.ip6.memerr + lws.ip6.rterr + lws.ip6.proterr + lws.ip6.opterr + lws.ip6.err + lws.ip6_frag.chkerr + lws.ip6_frag.lenerr + lws.ip6_frag.memerr + lws.ip6_frag.rterr + lws.ip6_frag.proterr + lws.ip6_frag.opterr + lws.ip6_frag.err; // icmp4 dst->icmp4_tx = lws.icmp.xmit; dst->icmp4_rx = lws.icmp.recv; dst->icmp4_drop = lws.icmp.drop; dst->icmp4_err = lws.icmp.chkerr + lws.icmp.lenerr + lws.icmp.memerr + lws.icmp.rterr + lws.icmp.proterr + lws.icmp.opterr + lws.icmp.err; // icmp6 dst->icmp6_tx = lws.icmp6.xmit; dst->icmp6_rx = lws.icmp6.recv; dst->icmp6_drop = lws.icmp6.drop; dst->icmp6_err = lws.icmp6.chkerr + lws.icmp6.lenerr + lws.icmp6.memerr + lws.icmp6.rterr + lws.icmp6.proterr + lws.icmp6.opterr + lws.icmp6.err; // udp dst->udp_tx = lws.udp.xmit; dst->udp_rx = lws.udp.recv; dst->udp_drop = lws.udp.drop; dst->udp_err = lws.udp.chkerr + lws.udp.lenerr + lws.udp.memerr + lws.udp.rterr + lws.udp.proterr + lws.udp.opterr + lws.udp.err; // tcp dst->tcp_tx = lws.tcp.xmit; dst->tcp_rx = lws.tcp.recv; dst->tcp_drop = lws.tcp.drop; dst->tcp_err = lws.tcp.chkerr + lws.tcp.lenerr + lws.tcp.memerr + lws.tcp.rterr + lws.tcp.proterr + lws.tcp.opterr + lws.tcp.err; // nd6 dst->nd6_tx = lws.nd6.xmit; dst->nd6_rx = lws.nd6.recv; dst->nd6_drop = lws.nd6.drop; dst->nd6_err = lws.nd6.chkerr + lws.nd6.lenerr + lws.nd6.memerr + lws.nd6.rterr + lws.nd6.proterr + lws.nd6.opterr + lws.nd6.err; // TODO: Add mem and sys stats return ZTS_ERR_OK; #else return ZTS_ERR_NO_RESULT; #endif #undef lws } #ifdef __cplusplus } #endif } // namespace ZeroTier