1
0
mirror of https://github.com/zerotier/ZeroTierOne.git synced 2025-03-12 04:36:29 -07:00
This commit is contained in:
Grant Limberg 2020-01-13 15:32:31 -08:00
commit 8e1a88c2fb
No known key found for this signature in database
GPG Key ID: 2BA62CCABBB4095A
143 changed files with 8751 additions and 12341 deletions

6
.gitignore vendored

@ -1,5 +1,9 @@
build/
/build
/cmake-build-debug
/cmake-build-release
/version.h
/.idea
/go/.idea
.DS_Store
.Trashes
*.swp

3
.idea/.gitignore generated vendored

@ -1,3 +0,0 @@
# Default ignored files
/workspace.xml

9
.idea/ZeroTierOne.iml generated

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

@ -1,11 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="api">
<words>
<w>apisocket</w>
<w>nwid</w>
<w>secrand</w>
<w>sockaddr</w>
<w>unmarshals</w>
</words>
</dictionary>
</component>

@ -1,10 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

6
.idea/misc.xml generated

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml generated

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ZeroTierOne.iml" filepath="$PROJECT_DIR$/.idea/ZeroTierOne.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

29
.idea/watcherTasks.xml generated

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions">
<TaskOptions isEnabled="true">
<option name="arguments" value="fmt $FilePath$" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="go" />
<option name="immediateSync" value="false" />
<option name="name" value="go fmt" />
<option name="output" value="$FilePath$" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="$GoExecPath$" />
<option name="runOnExternalChanges" value="false" />
<option name="scopeName" value="Project Files" />
<option name="trackOnlyRoot" value="true" />
<option name="workingDir" value="$ProjectFileDir$" />
<envs>
<env name="GOROOT" value="$GOROOT$" />
<env name="GOPATH" value="$GOPATH$" />
<env name="PATH" value="$GoBinDirs$" />
</envs>
</TaskOptions>
</component>
</project>

@ -1,4 +1,5 @@
cmake_minimum_required (VERSION 3.8)
project(zerotier DESCRIPTION "ZeroTier Network Hypervisor" LANGUAGES CXX C)
if(${CMAKE_VERSION} VERSION_LESS 3.15)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
@ -7,33 +8,32 @@ else()
endif()
if(WIN32)
# If building on Windows, set minimum target to Windows 7
set(CMAKE_SYSTEM_VERSION "7" CACHE STRING INTERNAL FORCE)
endif(WIN32)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X Deployment Version")
set(ZEROTIER_ONE_VERSION_MAJOR 2 CACHE INTERNAL "")
set(ZEROTIER_ONE_VERSION_MINOR 0 CACHE INTERNAL "")
set(ZEROTIER_ONE_VERSION_REVISION 0 CACHE INTERNAL "")
set(ZEROTIER_ONE_VERSION_BUILD 0 CACHE INTERNAL "")
configure_file(
${CMAKE_SOURCE_DIR}/version.h.in
${CMAKE_BINARY_DIR}/version.h
)
set(default_build_type "Release")
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
set(default_build_type "Debug")
endif()
#if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
# set(default_build_type "Debug")
#endif()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
option(BUILD_CENTRAL_CONTROLLER "Build ZeroTier Central Controller" OFF)
option(ZT_TRACE "Trace Messages" OFF)
option(ZT_DEBUG_TRACE "Debug Trace Messages" OFF)
if (BUILD_CENTRAL_CONTROLLER)
find_package(PostgreSQL REQUIRED)
set(ENABLE_SSL_SUPPORT OFF)
@ -45,25 +45,21 @@ if (BUILD_CENTRAL_CONTROLLER)
add_subdirectory("ext/librabbitmq")
endif(BUILD_CENTRAL_CONTROLLER)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X Deployment Version")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DZT_TRACE)
endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
project(zerotier
DESCRIPTION "ZeroTier Network Hypervisor"
LANGUAGES CXX C)
if(WIN32)
message("++ Setting Windows Compiler Flags ${CMAKE_BUILD_TYPE}")
add_definitions(-DNOMINMAX)
else(WIN32)
if(APPLE)
message("Setting macOS Compiler Flags ${CMAKE_BUILD_TYPE}")
message("++ Setting MacOS Compiler Flags ${CMAKE_BUILD_TYPE}")
add_compile_options(
-Wall
-Wno-deprecated
-Wno-unused-function
-mmacosx-version-min=10.9
$<$<CONFIG:Debug>:-g>
$<$<CONFIG:DEBUG>:-O0>
@ -79,17 +75,13 @@ else(WIN32)
$<$<CONFIG:RELEASE>:-flto>
)
elseif (
CMAKE_SYSTEM_NAME MATCHES "Linux" OR
CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR
CMAKE_SYSTEM_NAME MATCHES "OpenBSD" OR
CMAKE_SYSTEM_NAME MATCHES "NetBSD"
)
else(APPLE)
message("Setting Linux/BSD Compiler Flags (${CMAKE_BUILD_TYPE})")
message("++ Setting Linux/BSD/Posix Compiler Flags (${CMAKE_BUILD_TYPE})")
add_compile_options(
-Wall
-Wno-deprecated
-Wno-unused-function
$<$<CONFIG:Debug>:-g>
$<$<CONFIG:DEBUG>:-O0>
$<$<CONFIG:RELEASE>:-O3>
@ -110,10 +102,9 @@ if (
CMAKE_SYSTEM_PROCESSOR MATCHES "i586" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "i686"
)
message("Adding SSE and AES-NI flags for processor ${CMAKE_SYSTEM_PROCESSOR}")
message("++ Adding SSE and AES-NI flags for processor ${CMAKE_SYSTEM_PROCESSOR}")
add_compile_options(
-maes
-mmmx
-mrdrnd
-mpclmul
-msse
@ -126,9 +117,6 @@ endif()
if(ZT_TRACE)
add_definitions(-DZT_TRACE)
endif()
if(ZT_DEBUG_TRACE)
add_definitions(-DZT_DEBUG_TRACE)
endif()
add_subdirectory(node)
add_subdirectory(controller)
@ -136,12 +124,6 @@ add_subdirectory(osdep)
add_subdirectory(root)
add_subdirectory(go/native)
#if(WIN32)
# add_subdirectory("windows/WinUI")
# add_subdirectory("windows/copyutil")
# add_definitions(-DNOMINMAX)
#endif(WIN32)
set(
zt_osdep
zt_core
@ -149,25 +131,18 @@ set(
zt_go_native
)
configure_file(
${CMAKE_SOURCE_DIR}/version.h.in
${CMAKE_BINARY_DIR}/version.h
)
#set(src
# one.cpp
# "ext/http-parser/http_parser.c"
#)
#set(headers
# "ext/http-parser/http_parser.h"
#)
if(WIN32)
set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi)
else(WIN32)
set(libs ${libs} pthread)
endif(WIN32)
#if(WIN32)
# add_subdirectory("windows/WinUI")
# add_subdirectory("windows/copyutil")
# add_definitions(-DNOMINMAX)
#endif(WIN32)
#if(WIN32)
# set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi)
# set(src
@ -203,6 +178,6 @@ add_custom_command(
)
add_custom_target(build_zerotier ALL DEPENDS zerotier)
add_executable(zerotier-selftest selftest.cpp)
target_link_libraries(zerotier-selftest ${libs} zt_core zt_osdep)
target_compile_features(zerotier-selftest PUBLIC cxx_std_11)
#add_executable(zerotier-selftest selftest.cpp)
#target_link_libraries(zerotier-selftest ${libs} zt_core zt_osdep)
#target_compile_features(zerotier-selftest PUBLIC cxx_std_11)

@ -1,461 +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.
*/
/****/
#ifndef ZT_BINDER_HPP
#define ZT_BINDER_HPP
#include "../node/Constants.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WINDOWS__
#include <WinSock2.h>
#include <Windows.h>
#include <ShlObj.h>
#include <netioapi.h>
#include <iphlpapi.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ifaddrs.h>
#ifdef __LINUX__
#include <sys/ioctl.h>
#include <net/if.h>
#endif
#endif
#include <string>
#include <vector>
#include <algorithm>
#include <utility>
#include <map>
#include <set>
#include <atomic>
#include "../node/InetAddress.hpp"
#include "../node/Mutex.hpp"
#include "../node/Utils.hpp"
#include "Phy.hpp"
#include "OSUtils.hpp"
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__))
#define ZT_UDP_DESIRED_BUF_SIZE 1048576
#else
#define ZT_UDP_DESIRED_BUF_SIZE 131072
#endif
// Period between refreshes of bindings
#define ZT_BINDER_REFRESH_PERIOD 30000
// Max number of bindings
#define ZT_BINDER_MAX_BINDINGS 256
namespace ZeroTier {
/**
* Enumerates local devices and binds to all potential ZeroTier path endpoints
*
* This replaces binding to wildcard (0.0.0.0 and ::0) with explicit binding
* as part of the path to default gateway support. Under the hood it uses
* different queries on different OSes to enumerate devices, and also exposes
* device enumeration and endpoint IP data for use elsewhere.
*
* On OSes that do not support local port enumeration or where this is not
* meaningful, this degrades to binding to wildcard.
*/
class Binder
{
private:
struct _Binding
{
_Binding() : udpSock((PhySocket *)0),tcpListenSock((PhySocket *)0) {}
PhySocket *udpSock;
PhySocket *tcpListenSock;
InetAddress address;
};
public:
Binder() : _bindingCount(0) {}
/**
* Close all bound ports, should be called on shutdown
*
* @param phy Physical interface
*/
template<typename PHY_HANDLER_TYPE>
void closeAll(Phy<PHY_HANDLER_TYPE> &phy)
{
Mutex::Lock _l(_lock);
for(unsigned int b=0,c=_bindingCount;b<c;++b) {
phy.close(_bindings[b].udpSock,false);
phy.close(_bindings[b].tcpListenSock,false);
}
_bindingCount = 0;
}
/**
* Scan local devices and addresses and rebind TCP and UDP
*
* This should be called after wake from sleep, on detected network device
* changes, on startup, or periodically (e.g. every 30-60s).
*
* @param phy Physical interface
* @param ports Ports to bind on all interfaces
* @param portCount Number of ports
* @param explicitBind If present, override interface IP detection and bind to these (if possible)
* @param ifChecker Interface checker function to see if an interface should be used
* @tparam PHY_HANDLER_TYPE Type for Phy<> template
* @tparam INTERFACE_CHECKER Type for class containing shouldBindInterface() method
*/
template<typename PHY_HANDLER_TYPE,typename INTERFACE_CHECKER>
void refresh(Phy<PHY_HANDLER_TYPE> &phy,unsigned int *ports,unsigned int portCount,const std::vector<InetAddress> explicitBind,INTERFACE_CHECKER &ifChecker)
{
std::map<InetAddress,std::string> localIfAddrs;
PhySocket *udps,*tcps;
Mutex::Lock _l(_lock);
bool interfacesEnumerated = true;
if (explicitBind.empty()) {
#ifdef __WINDOWS__
char aabuf[32768];
ULONG aalen = sizeof(aabuf);
if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER,(void *)0,reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf),&aalen) == NO_ERROR) {
PIP_ADAPTER_ADDRESSES a = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(aabuf);
while (a) {
PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress;
while (ua) {
InetAddress ip(ua->Address.lpSockaddr);
if (ifChecker.shouldBindInterface("",ip)) {
switch(ip.ipScope()) {
default: break;
case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
case InetAddress::IP_SCOPE_GLOBAL:
case InetAddress::IP_SCOPE_SHARED:
case InetAddress::IP_SCOPE_PRIVATE:
for(int x=0;x<(int)portCount;++x) {
ip.setPort(ports[x]);
localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string()));
}
break;
}
}
ua = ua->Next;
}
a = a->Next;
}
}
else {
interfacesEnumerated = false;
}
#else // not __WINDOWS__
/* On Linux we use an alternative method if available since getifaddrs()
* gets very slow when there are lots of network namespaces. This won't
* work unless /proc/PID/net/if_inet6 exists and it may not on some
* embedded systems, so revert to getifaddrs() there. */
#ifdef __LINUX__
char fn[256],tmp[256];
std::set<std::string> ifnames;
const unsigned long pid = (unsigned long)getpid();
// Get all device names
OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/dev",pid);
FILE *procf = fopen(fn,"r");
if (procf) {
while (fgets(tmp,sizeof(tmp),procf)) {
tmp[255] = 0;
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp," \t\r\n:|",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n:|",&saveptr)) {
if ((strcmp(f,"Inter-") != 0)&&(strcmp(f,"face") != 0)&&(f[0] != 0))
ifnames.insert(f);
break; // we only want the first field
}
}
fclose(procf);
}
else {
interfacesEnumerated = false;
}
// Get IPv6 addresses (and any device names we don't already know)
OSUtils::ztsnprintf(fn,sizeof(fn),"/proc/%lu/net/if_inet6",pid);
procf = fopen(fn,"r");
if (procf) {
while (fgets(tmp,sizeof(tmp),procf)) {
tmp[255] = 0;
char *saveptr = (char *)0;
unsigned char ipbits[16];
memset(ipbits,0,sizeof(ipbits));
char *devname = (char *)0;
int n = 0;
for(char *f=Utils::stok(tmp," \t\r\n",&saveptr);(f);f=Utils::stok((char *)0," \t\r\n",&saveptr)) {
switch(n++) {
case 0: // IP in hex
Utils::unhex(f,32,ipbits,16);
break;
case 5: // device name
devname = f;
break;
}
}
if (devname) {
ifnames.insert(devname);
InetAddress ip(ipbits,16,0);
if (ifChecker.shouldBindInterface(devname,ip)) {
switch(ip.ipScope()) {
default: break;
case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
case InetAddress::IP_SCOPE_GLOBAL:
case InetAddress::IP_SCOPE_SHARED:
case InetAddress::IP_SCOPE_PRIVATE:
for(int x=0;x<(int)portCount;++x) {
ip.setPort(ports[x]);
localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(devname)));
}
break;
}
}
}
}
fclose(procf);
}
// Get IPv4 addresses for each device
if (ifnames.size() > 0) {
const int controlfd = (int)socket(AF_INET,SOCK_DGRAM,0);
struct ifconf configuration;
configuration.ifc_len = 0;
configuration.ifc_buf = nullptr;
if (controlfd < 0) goto ip4_address_error;
if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
configuration.ifc_buf = (char*)malloc(configuration.ifc_len);
if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) goto ip4_address_error;
for (int i=0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i ++) {
struct ifreq& request = configuration.ifc_req[i];
struct sockaddr* addr = &request.ifr_ifru.ifru_addr;
if (addr->sa_family != AF_INET) continue;
std::string ifname = request.ifr_ifrn.ifrn_name;
// name can either be just interface name or interface name followed by ':' and arbitrary label
if (ifname.find(':') != std::string::npos)
ifname = ifname.substr(0, ifname.find(':'));
InetAddress ip(&(((struct sockaddr_in *)addr)->sin_addr),4,0);
if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) {
switch(ip.ipScope()) {
default: break;
case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
case InetAddress::IP_SCOPE_GLOBAL:
case InetAddress::IP_SCOPE_SHARED:
case InetAddress::IP_SCOPE_PRIVATE:
for(int x=0;x<(int)portCount;++x) {
ip.setPort(ports[x]);
localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,ifname));
}
break;
}
}
}
ip4_address_error:
free(configuration.ifc_buf);
if (controlfd > 0) close(controlfd);
}
const bool gotViaProc = (localIfAddrs.size() > 0);
#else
const bool gotViaProc = false;
#endif
#if !defined(ZT_SDK) || !defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android
if (!gotViaProc) {
struct ifaddrs *ifatbl = (struct ifaddrs *)0;
struct ifaddrs *ifa;
if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) {
ifa = ifatbl;
while (ifa) {
if ((ifa->ifa_name)&&(ifa->ifa_addr)) {
InetAddress ip = *(ifa->ifa_addr);
if (ifChecker.shouldBindInterface(ifa->ifa_name,ip)) {
switch(ip.ipScope()) {
default: break;
case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
case InetAddress::IP_SCOPE_GLOBAL:
case InetAddress::IP_SCOPE_SHARED:
case InetAddress::IP_SCOPE_PRIVATE:
for(int x=0;x<(int)portCount;++x) {
ip.setPort(ports[x]);
localIfAddrs.insert(std::pair<InetAddress,std::string>(ip,std::string(ifa->ifa_name)));
}
break;
}
}
}
ifa = ifa->ifa_next;
}
freeifaddrs(ifatbl);
}
else {
interfacesEnumerated = false;
}
}
#endif
#endif
} else {
for(std::vector<InetAddress>::const_iterator i(explicitBind.begin());i!=explicitBind.end();++i)
localIfAddrs.insert(std::pair<InetAddress,std::string>(*i,std::string()));
}
// Default to binding to wildcard if we can't enumerate addresses
if (!interfacesEnumerated && localIfAddrs.empty()) {
for(int x=0;x<(int)portCount;++x) {
localIfAddrs.insert(std::pair<InetAddress,std::string>(InetAddress((uint32_t)0,ports[x]),std::string()));
localIfAddrs.insert(std::pair<InetAddress,std::string>(InetAddress((const void *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",16,ports[x]),std::string()));
}
}
const unsigned int oldBindingCount = _bindingCount;
_bindingCount = 0;
// Save bindings that are still valid, close those that are not
for(unsigned int b=0;b<oldBindingCount;++b) {
if (localIfAddrs.find(_bindings[b].address) != localIfAddrs.end()) {
if (_bindingCount != b)
_bindings[(unsigned int)_bindingCount] = _bindings[b];
++_bindingCount;
} else {
PhySocket *const udps = _bindings[b].udpSock;
PhySocket *const tcps = _bindings[b].tcpListenSock;
_bindings[b].udpSock = (PhySocket *)0;
_bindings[b].tcpListenSock = (PhySocket *)0;
phy.close(udps,false);
phy.close(tcps,false);
}
}
// Create new bindings for those not already bound
for(std::map<InetAddress,std::string>::const_iterator ii(localIfAddrs.begin());ii!=localIfAddrs.end();++ii) {
unsigned int bi = 0;
while (bi != _bindingCount) {
if (_bindings[bi].address == ii->first)
break;
++bi;
}
if (bi == _bindingCount) {
udps = phy.udpBind(reinterpret_cast<const struct sockaddr *>(&(ii->first)),(void *)0,ZT_UDP_DESIRED_BUF_SIZE);
tcps = phy.tcpListen(reinterpret_cast<const struct sockaddr *>(&(ii->first)),(void *)0);
if ((udps)&&(tcps)) {
#ifdef __LINUX__
// Bind Linux sockets to their device so routes that we manage do not override physical routes (wish all platforms had this!)
if (ii->second.length() > 0) {
char tmp[256];
Utils::scopy(tmp,sizeof(tmp),ii->second.c_str());
int fd = (int)Phy<PHY_HANDLER_TYPE>::getDescriptor(udps);
if (fd >= 0)
setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp));
fd = (int)Phy<PHY_HANDLER_TYPE>::getDescriptor(tcps);
if (fd >= 0)
setsockopt(fd,SOL_SOCKET,SO_BINDTODEVICE,tmp,strlen(tmp));
}
#endif // __LINUX__
if (_bindingCount < ZT_BINDER_MAX_BINDINGS) {
_bindings[_bindingCount].udpSock = udps;
_bindings[_bindingCount].tcpListenSock = tcps;
_bindings[_bindingCount].address = ii->first;
phy.setIfName(udps,(char*)ii->second.c_str(),(int)ii->second.length());
++_bindingCount;
}
} else {
phy.close(udps,false);
phy.close(tcps,false);
}
}
}
}
/**
* @return All currently bound local interface addresses
*/
inline std::vector<InetAddress> allBoundLocalInterfaceAddresses() const
{
std::vector<InetAddress> aa;
Mutex::Lock _l(_lock);
for(unsigned int b=0,c=_bindingCount;b<c;++b)
aa.push_back(_bindings[b].address);
return aa;
}
/**
* Send from all bound UDP sockets
*/
template<typename PHY_HANDLER_TYPE>
inline bool udpSendAll(Phy<PHY_HANDLER_TYPE> &phy,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
{
bool r = false;
Mutex::Lock _l(_lock);
for(unsigned int b=0,c=_bindingCount;b<c;++b) {
if (ttl) phy.setIp4UdpTtl(_bindings[b].udpSock,ttl);
if (phy.udpSend(_bindings[b].udpSock,(const struct sockaddr *)addr,data,len)) r = true;
if (ttl) phy.setIp4UdpTtl(_bindings[b].udpSock,255);
}
return r;
}
/**
* @param addr Address to check
* @return True if this is a bound local interface address
*/
inline bool isBoundLocalInterfaceAddress(const InetAddress &addr) const
{
Mutex::Lock _l(_lock);
for(unsigned int b=0;b<_bindingCount;++b) {
if (_bindings[b].address == addr)
return true;
}
return false;
}
/**
* Quickly check that a UDP socket is valid
*
* @param udpSock UDP socket to check
* @return True if socket is currently bound/allocated
*/
inline bool isUdpSocketValid(PhySocket *const udpSock)
{
for(unsigned int b=0,c=_bindingCount;b<c;++b) {
if (_bindings[b].udpSock == udpSock)
return (b < _bindingCount); // double check atomic which may have changed
}
return false;
}
private:
_Binding _bindings[ZT_BINDER_MAX_BINDINGS];
std::atomic<unsigned int> _bindingCount;
Mutex _lock;
};
} // namespace ZeroTier
#endif

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

@ -1,182 +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.
*/
/****/
#ifndef ZT_HTTP_HPP
#define ZT_HTTP_HPP
#include <string>
#include <map>
#include <stdexcept>
#if defined(_WIN32) || defined(_WIN64)
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <Windows.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif
namespace ZeroTier {
/**
* Simple synchronous HTTP client used for updater and cli
*/
class Http
{
public:
/**
* Make HTTP GET request
*
* The caller must set all headers, including Host.
*
* @return HTTP status code or 0 on error (responseBody will contain error message)
*/
static inline unsigned int GET(
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
{
return _do(
"GET",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
(const void *)0,
0,
responseHeaders,
responseBody);
}
/**
* Make HTTP DELETE request
*
* The caller must set all headers, including Host.
*
* @return HTTP status code or 0 on error (responseBody will contain error message)
*/
static inline unsigned int DEL(
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
{
return _do(
"DELETE",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
(const void *)0,
0,
responseHeaders,
responseBody);
}
/**
* Make HTTP POST request
*
* It is the responsibility of the caller to set all headers. With POST, the
* Content-Length and Content-Type headers must be set or the POST will not
* work.
*
* @return HTTP status code or 0 on error (responseBody will contain error message)
*/
static inline unsigned int POST(
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
const void *postData,
unsigned long postDataLength,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
{
return _do(
"POST",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
postData,
postDataLength,
responseHeaders,
responseBody);
}
/**
* Make HTTP PUT request
*
* It is the responsibility of the caller to set all headers. With PUT, the
* Content-Length and Content-Type headers must be set or the PUT will not
* work.
*
* @return HTTP status code or 0 on error (responseBody will contain error message)
*/
static inline unsigned int PUT(
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
const void *postData,
unsigned long postDataLength,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody)
{
return _do(
"PUT",
maxResponseSize,
timeout,
remoteAddress,
path,
requestHeaders,
postData,
postDataLength,
responseHeaders,
responseBody);
}
private:
static unsigned int _do(
const char *method,
unsigned long maxResponseSize,
unsigned long timeout,
const struct sockaddr *remoteAddress,
const char *path,
const std::map<std::string,std::string> &requestHeaders,
const void *requestBody,
unsigned long requestBodyLength,
std::map<std::string,std::string> &responseHeaders,
std::string &responseBody);
};
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load Diff

@ -1,14 +0,0 @@
#define ENABLE_STRNATPMPERR
#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 600
#ifdef __APPLE__
#ifndef _DARWIN_C_SOURCE
#define _DARWIN_C_SOURCE
#endif
#endif
#include "../ext/libnatpmp/getgateway.c"
#include "../ext/libnatpmp/wingettimeofday.c"
#include "../ext/libnatpmp/natpmp.c"

@ -1,41 +0,0 @@
#define MINIUPNP_STATICLIB
#define MINIUPNPC_SET_SOCKET_TIMEOUT
#define MINIUPNPC_GET_SRC_ADDR
#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 600
#define MINIUPNPC_VERSION_STRING "2.0"
#define UPNP_VERSION_STRING "UPnP/1.1"
#ifdef __LINUX__
#define OS_STRING "Linux"
#endif
#ifdef __APPLE__
#define OS_STRING "Darwin"
#endif
#ifdef __WINDOWS__
#define OS_STRING "Windows"
#endif
#ifndef OS_STRING
#define OS_STRING "ZeroTier"
#endif
#ifdef __APPLE__
#ifndef _DARWIN_C_SOURCE
#define _DARWIN_C_SOURCE
#endif
#endif
#include "../ext/miniupnpc/connecthostport.c"
#include "../ext/miniupnpc/igd_desc_parse.c"
#include "../ext/miniupnpc/minisoap.c"
#include "../ext/miniupnpc/miniupnpc.c"
#include "../ext/miniupnpc/miniwget.c"
#include "../ext/miniupnpc/minixml.c"
#include "../ext/miniupnpc/portlistingparse.c"
#include "../ext/miniupnpc/receivedata.c"
#include "../ext/miniupnpc/upnpcommands.c"
#include "../ext/miniupnpc/upnpdev.c"
#include "../ext/miniupnpc/upnperrors.c"
#include "../ext/miniupnpc/upnpreplyparse.c"
#include "../ext/miniupnpc/minissdpc.c"

@ -1,334 +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.
*/
/****/
// Uncomment to dump debug messages
//#define ZT_PORTMAPPER_TRACE 1
#ifdef __ANDROID__
#include <android/log.h>
#define PM_TRACE(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "PortMapper", __VA_ARGS__))
#else
#define PM_TRACE(...) fprintf(stderr, __VA_ARGS__)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "../node/Utils.hpp"
#include "OSUtils.hpp"
#include "PortMapper.hpp"
// These must be defined to get rid of dynamic export stuff in libminiupnpc and libnatpmp
#ifdef __WINDOWS__
#ifndef MINIUPNP_STATICLIB
#define MINIUPNP_STATICLIB
#endif
#ifndef STATICLIB
#define STATICLIB
#endif
#endif
#ifdef ZT_USE_SYSTEM_MINIUPNPC
#include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h>
#else
#ifdef __ANDROID__
#include "miniupnpc.h"
#include "upnpcommands.h"
#else
#include "../ext/miniupnpc/miniupnpc.h"
#include "../ext/miniupnpc/upnpcommands.h"
#endif
#endif
#ifdef ZT_USE_SYSTEM_NATPMP
#include <natpmp.h>
#else
#ifdef __ANDROID__
#include "natpmp.h"
#else
#include "../ext/libnatpmp/natpmp.h"
#endif
#endif
namespace ZeroTier {
class PortMapperImpl
{
public:
PortMapperImpl(int localUdpPortToMap,const char *un) :
run(true),
localPort(localUdpPortToMap),
uniqueName(un)
{
}
~PortMapperImpl() {}
void threadMain()
throw()
{
int mode = 0; // 0 == NAT-PMP, 1 == UPnP
#ifdef ZT_PORTMAPPER_TRACE
fprintf(stderr,"PortMapper: started for UDP port %d" ZT_EOL_S,localPort);
#endif
while (run) {
// ---------------------------------------------------------------------
// NAT-PMP mode (preferred)
// ---------------------------------------------------------------------
if (mode == 0) {
natpmp_t natpmp;
natpmpresp_t response;
int r = 0;
bool natPmpSuccess = false;
for(int tries=0;tries<60;++tries) {
int tryPort = (int)localPort + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
memset(&natpmp,0,sizeof(natpmp));
memset(&response,0,sizeof(response));
if (initnatpmp(&natpmp,0,0) != 0) {
mode = 1;
closenatpmp(&natpmp);
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S);
#endif
break;
}
InetAddress publicAddress;
sendpublicaddressrequest(&natpmp);
int64_t myTimeout = OSUtils::now() + 5000;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
if (OSUtils::now() >= myTimeout)
break;
} while (r == NATPMP_TRYAGAIN);
if (r == 0) {
publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0);
} else {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S);
#endif
closenatpmp(&natpmp);
break;
}
sendnewportmappingrequest(&natpmp,NATPMP_PROTOCOL_UDP,localPort,tryPort,(ZT_PORTMAPPER_REFRESH_DELAY * 2) / 1000);
myTimeout = OSUtils::now() + 10000;
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
if (OSUtils::now() >= myTimeout)
break;
} while (r == NATPMP_TRYAGAIN);
if (r == 0) {
publicAddress.setPort(response.pnu.newportmapping.mappedpublicport);
#ifdef ZT_PORTMAPPER_TRACE
char paddr[128];
PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S,(unsigned int)localPort,publicAddress.toString(paddr));
#endif
Mutex::Lock sl(surface_l);
surface.clear();
surface.push_back(publicAddress);
natPmpSuccess = true;
closenatpmp(&natpmp);
break;
} else {
closenatpmp(&natpmp);
// continue
}
}
if (!natPmpSuccess) {
mode = 1;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S);
#endif
}
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// UPnP mode
// ---------------------------------------------------------------------
if (mode == 1) {
char lanaddr[4096];
char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P
char inport[16];
char outport[16];
struct UPNPUrls urls;
struct IGDdatas data;
int upnpError = 0;
UPNPDev *devlist = upnpDiscoverAll(5000,(const char *)0,(const char *)0,0,0,2,&upnpError);
if (devlist) {
#ifdef ZT_PORTMAPPER_TRACE
{
UPNPDev *dev = devlist;
while (dev) {
PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S,dev->descURL,dev->st);
dev = dev->pNext;
}
}
#endif
memset(lanaddr,0,sizeof(lanaddr));
memset(externalip,0,sizeof(externalip));
memset(&urls,0,sizeof(urls));
memset(&data,0,sizeof(data));
OSUtils::ztsnprintf(inport,sizeof(inport),"%d",localPort);
if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S,lanaddr);
#endif
if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S,externalip);
#endif
for(int tries=0;tries<60;++tries) {
int tryPort = (int)localPort + tries;
if (tryPort >= 65535)
tryPort = (tryPort - 65535) + 1025;
OSUtils::ztsnprintf(outport,sizeof(outport),"%u",tryPort);
// First check and see if this port is already mapped to the
// same unique name. If so, keep this mapping and don't try
// to map again since this can break buggy routers. But don't
// fail if this command fails since not all routers support it.
{
char haveIntClient[128]; // 128 == big enough for all these as per miniupnpc "documentation"
char haveIntPort[128];
char haveDesc[128];
char haveEnabled[128];
char haveLeaseDuration[128];
memset(haveIntClient,0,sizeof(haveIntClient));
memset(haveIntPort,0,sizeof(haveIntPort));
memset(haveDesc,0,sizeof(haveDesc));
memset(haveEnabled,0,sizeof(haveEnabled));
memset(haveLeaseDuration,0,sizeof(haveLeaseDuration));
if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
InetAddress tmp(externalip);
tmp.setPort(tryPort);
surface.push_back(tmp);
break;
}
}
// Try to map this port
int mapResult = 0;
if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S,outport);
#endif
Mutex::Lock sl(surface_l);
surface.clear();
InetAddress tmp(externalip);
tmp.setPort(tryPort);
surface.push_back(tmp);
break;
} else {
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S,outport,mapResult);
#endif
Thread::sleep(1000);
}
}
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S);
#endif
}
freeUPNPDevlist(devlist);
} else {
mode = 0;
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S,upnpError);
#endif
}
}
// ---------------------------------------------------------------------
#ifdef ZT_PORTMAPPER_TRACE
PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY);
#endif
Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY);
}
delete this;
}
volatile bool run;
int localPort;
std::string uniqueName;
Mutex surface_l;
std::vector<InetAddress> surface;
};
PortMapper::PortMapper(int localUdpPortToMap,const char *uniqueName)
{
_impl = new PortMapperImpl(localUdpPortToMap,uniqueName);
Thread::start(_impl);
}
PortMapper::~PortMapper()
{
_impl->run = false;
}
std::vector<InetAddress> PortMapper::get() const
{
Mutex::Lock _l(_impl->surface_l);
return _impl->surface;
}
} // namespace ZeroTier

@ -1,62 +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.
*/
/****/
#ifndef ZT_PORTMAPPER_HPP
#define ZT_PORTMAPPER_HPP
#include <vector>
#include "../node/Constants.hpp"
#include "../node/InetAddress.hpp"
#include "../node/Mutex.hpp"
#include "Thread.hpp"
/**
* How frequently should we refresh our UPNP/NAT-PnP/whatever state?
*/
#define ZT_PORTMAPPER_REFRESH_DELAY 120000
namespace ZeroTier {
class PortMapperImpl;
/**
* UPnP/NAT-PnP port mapping "daemon"
*/
class PortMapper
{
friend class PortMapperImpl;
public:
/**
* Create and start port mapper service
*
* @param localUdpPortToMap Port we want visible to the outside world
* @param name Unique name of this endpoint (based on ZeroTier address)
*/
PortMapper(int localUdpPortToMap,const char *uniqueName);
~PortMapper();
/**
* @return All current external mappings for our port
*/
std::vector<InetAddress> get() const;
private:
PortMapperImpl *_impl;
};
} // namespace ZeroTier
#endif

@ -1,182 +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.
*/
/****/
#ifndef ZT_ROOT_HPP
#define ZT_ROOT_HPP
#include "Constants.hpp"
#include "Str.hpp"
#include "ECC384.hpp"
#include "Locator.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
#include "Mutex.hpp"
namespace ZeroTier {
/**
* A root entry pointing to a node capable of global identity lookup and indirect transit
*
* Root entries point to DNS records that contain TXT entries that decode to Locator objects
* pointing to actual root nodes. A default root identity and static addresses can also be
* provided as fallback if DNS is not available.
*
* Note that root identities can change if DNS returns a different result, but that DNS entries
* are authenticated using their own signature scheme. This allows a root DNS name to serve
* up different roots based on factors like location or relative load of different roots.
*
* It's also possible to create a root with no DNS and no DNS validator public key. This root
* will be a static entry pointing to a single root identity and set of physical addresses.
*/
class Root
{
public:
ZT_ALWAYS_INLINE Root() : _dnsPublicKeySize(0) {}
/**
* Create a new root entry
*
* @param dn DNS name
* @param dnspk DNS public key for record validation
* @param dnspksize Size of DNS public key (currently always the size of a NIST P-384 point compressed public key)
* @param dflId Default identity if DNS is not available
* @param dflAddrs Default IP addresses if DNS is not available
*/
template<typename S>
ZT_ALWAYS_INLINE Root(S dn,const uint8_t *const dnspk,const unsigned int dnspksize,const Identity &dflId,const std::vector<InetAddress> &dflAddrs) :
_defaultIdentity(dflId),
_defaultAddresses(dflAddrs),
_dnsName(dn),
_dnsPublicKeySize(dnspksize)
{
if (dnspksize != 0) {
if (dnspksize > sizeof(_dnsPublicKey))
throw ZT_EXCEPTION_INVALID_ARGUMENT;
memcpy(_dnsPublicKey,dnspk,dnspksize);
}
}
/**
* @return Current identity (either default or latest locator)
*/
ZT_ALWAYS_INLINE const Identity id() const
{
if (_lastFetchedLocator.id())
return _lastFetchedLocator.id();
return _defaultIdentity;
}
/**
* @param id Identity to check
* @return True if identity equals this root's current identity
*/
ZT_ALWAYS_INLINE bool is(const Identity &id) const
{
return ((_lastFetchedLocator.id()) ? (id == _lastFetchedLocator.id()) : (id == _defaultIdentity));
}
/**
* @return Current ZeroTier address (either default or latest locator)
*/
ZT_ALWAYS_INLINE const Address address() const
{
if (_lastFetchedLocator.id())
return _lastFetchedLocator.id().address();
return _defaultIdentity.address();
}
/**
* @return DNS name for this root or empty string if static entry with no DNS
*/
ZT_ALWAYS_INLINE const Str dnsName() const { return _dnsName; }
/**
* @return Latest locator or NIL locator object if none
*/
ZT_ALWAYS_INLINE Locator locator() const { return _lastFetchedLocator; }
/**
* @return Timestamp of latest retrieved locator or 0 if none
*/
ZT_ALWAYS_INLINE int64_t locatorTimestamp() const { return _lastFetchedLocator.timestamp(); }
/**
* Update locator, returning true if new locator is valid and newer than existing
*/
ZT_ALWAYS_INLINE bool updateLocator(const Locator &loc)
{
if (!loc.verify())
return false;
if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
_lastFetchedLocator = loc;
return true;
}
return false;
}
/**
* Update this root's locator from a series of TXT records
*/
template<typename I>
ZT_ALWAYS_INLINE bool updateLocatorFromTxt(I start,I end)
{
try {
if (_dnsPublicKeySize != ZT_ECC384_PUBLIC_KEY_SIZE)
return false;
Locator loc;
if (!loc.decodeTxtRecords(start,end,_dnsPublicKey)) // also does verify()
return false;
if ((loc.phy().size() > 0)&&(loc.timestamp() > _lastFetchedLocator.timestamp())) {
_lastFetchedLocator = loc;
return true;
}
return false;
} catch ( ... ) {}
return false;
}
/**
* Pick a random physical IP for this root with the given address family
*
* @param addressFamily AF_INET or AF_INET6
* @return Address or InetAddress::NIL if no addresses exist for the given family
*/
ZT_ALWAYS_INLINE const InetAddress &pickPhysical(const int addressFamily) const
{
std::vector<const InetAddress *> pickList;
const std::vector<InetAddress> *const av = (_lastFetchedLocator) ? &(_lastFetchedLocator.phy()) : &_defaultAddresses;
for(std::vector<InetAddress>::const_iterator i(av->begin());i!=av->end();++i) {
if (addressFamily == (int)i->ss_family) {
pickList.push_back(&(*i));
}
}
if (pickList.size() == 1)
return *pickList[0];
else if (pickList.size() > 1)
return *pickList[(unsigned long)Utils::random() % (unsigned long)pickList.size()];
return InetAddress::NIL;
}
private:
Identity _defaultIdentity;
std::vector<InetAddress> _defaultAddresses;
Str _dnsName;
Locator _lastFetchedLocator;
unsigned int _dnsPublicKeySize;
uint8_t _dnsPublicKey[ZT_ECC384_PUBLIC_KEY_SIZE];
};
} // namespace ZeroTier
#endif

@ -1,18 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
#ifdef __cplusplus
extern "C" {
#endif
extern void *__wrap_memcpy(void *dest,const void *src,size_t n)
{
return memcpy(dest,src,n);
}
#ifdef __cplusplus
}
#endif

@ -1,30 +0,0 @@
package main
import (
"fmt"
"net"
)
func main() {
ifs, err := net.Interfaces()
if err != nil {
fmt.Printf("Error: %s\n", err.Error())
return
}
for _, i := range ifs {
fmt.Printf("name: %s\n", i.Name)
fmt.Printf("hwaddr: %s\n", i.HardwareAddr.String())
fmt.Printf("index: %d\n", i.Index)
fmt.Printf("addrs:\n")
addrs, _ := i.Addrs()
for _, a := range addrs {
fmt.Printf(" %s\n", a.String())
}
fmt.Printf("multicast:\n")
mc, _ := i.MulticastAddrs()
for _, m := range mc {
fmt.Printf(" %s\n", m.String())
}
fmt.Printf("\n")
}
}

File diff suppressed because it is too large Load Diff

111
attic/webview/.clang-format Normal file

@ -0,0 +1,111 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

256
attic/webview/.clang-tidy Normal file

@ -0,0 +1,256 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,*'
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
User: serge
CheckOptions:
- key: bugprone-argument-comment.StrictMode
value: '0'
- key: bugprone-assert-side-effect.AssertMacros
value: assert
- key: bugprone-assert-side-effect.CheckFunctionCalls
value: '0'
- key: bugprone-dangling-handle.HandleClasses
value: 'std::basic_string_view;std::experimental::basic_string_view'
- key: bugprone-string-constructor.LargeLengthThreshold
value: '8388608'
- key: bugprone-string-constructor.WarnOnLargeLength
value: '1'
- key: cert-dcl59-cpp.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: cert-err09-cpp.CheckThrowTemporaries
value: '1'
- key: cert-err61-cpp.CheckThrowTemporaries
value: '1'
- key: cert-oop11-cpp.IncludeStyle
value: llvm
- key: cppcoreguidelines-no-malloc.Allocations
value: '::malloc;::calloc'
- key: cppcoreguidelines-no-malloc.Deallocations
value: '::free'
- key: cppcoreguidelines-no-malloc.Reallocations
value: '::realloc'
- key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
value: '::free;::realloc;::freopen;::fclose'
- key: cppcoreguidelines-owning-memory.LegacyResourceProducers
value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
- key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
value: ''
- key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
value: '0'
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
value: '0'
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
value: '0'
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: '0'
- key: google-build-namespaces.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: google-global-names-in-headers.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: google-readability-braces-around-statements.ShortStatementLines
value: '1'
- key: google-readability-function-size.BranchThreshold
value: '4294967295'
- key: google-readability-function-size.LineThreshold
value: '4294967295'
- key: google-readability-function-size.NestingThreshold
value: '4294967295'
- key: google-readability-function-size.ParameterThreshold
value: '4294967295'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: google-runtime-int.SignedTypePrefix
value: int
- key: google-runtime-int.TypeSuffix
value: ''
- key: google-runtime-int.UnsignedTypePrefix
value: uint
- key: google-runtime-references.WhiteListTypes
value: ''
- key: hicpp-braces-around-statements.ShortStatementLines
value: '0'
- key: hicpp-function-size.BranchThreshold
value: '4294967295'
- key: hicpp-function-size.LineThreshold
value: '4294967295'
- key: hicpp-function-size.NestingThreshold
value: '4294967295'
- key: hicpp-function-size.ParameterThreshold
value: '4294967295'
- key: hicpp-function-size.StatementThreshold
value: '800'
- key: hicpp-member-init.IgnoreArrays
value: '0'
- key: hicpp-move-const-arg.CheckTriviallyCopyableMove
value: '1'
- key: hicpp-named-parameter.IgnoreFailedSplit
value: '0'
- key: hicpp-no-malloc.Allocations
value: '::malloc;::calloc'
- key: hicpp-no-malloc.Deallocations
value: '::free'
- key: hicpp-no-malloc.Reallocations
value: '::realloc'
- key: hicpp-special-member-functions.AllowMissingMoveFunctions
value: '0'
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
value: '0'
- key: hicpp-use-auto.RemoveStars
value: '0'
- key: hicpp-use-emplace.ContainersWithPushBack
value: '::std::vector;::std::list;::std::deque'
- key: hicpp-use-emplace.SmartPointers
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
- key: hicpp-use-emplace.TupleMakeFunctions
value: '::std::make_pair;::std::make_tuple'
- key: hicpp-use-emplace.TupleTypes
value: '::std::pair;::std::tuple'
- key: hicpp-use-equals-default.IgnoreMacros
value: '1'
- key: hicpp-use-noexcept.ReplacementString
value: ''
- key: hicpp-use-noexcept.UseNoexceptFalse
value: '1'
- key: hicpp-use-nullptr.NullMacros
value: ''
- key: llvm-namespace-comment.ShortNamespaceLines
value: '1'
- key: llvm-namespace-comment.SpacesBeforeComments
value: '1'
- key: misc-definitions-in-headers.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: misc-definitions-in-headers.UseHeaderFileExtension
value: '1'
- key: misc-misplaced-widening-cast.CheckImplicitCasts
value: '0'
- key: misc-sizeof-expression.WarnOnSizeOfCompareToConstant
value: '1'
- key: misc-sizeof-expression.WarnOnSizeOfConstant
value: '1'
- key: misc-sizeof-expression.WarnOnSizeOfThis
value: '1'
- key: misc-suspicious-enum-usage.StrictMode
value: '0'
- key: misc-suspicious-missing-comma.MaxConcatenatedTokens
value: '5'
- key: misc-suspicious-missing-comma.RatioThreshold
value: '0.200000'
- key: misc-suspicious-missing-comma.SizeThreshold
value: '5'
- key: misc-suspicious-string-compare.StringCompareLikeFunctions
value: ''
- key: misc-suspicious-string-compare.WarnOnImplicitComparison
value: '1'
- key: misc-suspicious-string-compare.WarnOnLogicalNotComparison
value: '0'
- key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries
value: '1'
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-make-shared.IgnoreMacros
value: '1'
- key: modernize-make-shared.IncludeStyle
value: '0'
- key: modernize-make-shared.MakeSmartPtrFunction
value: 'std::make_shared'
- key: modernize-make-shared.MakeSmartPtrFunctionHeader
value: memory
- key: modernize-make-unique.IgnoreMacros
value: '1'
- key: modernize-make-unique.IncludeStyle
value: '0'
- key: modernize-make-unique.MakeSmartPtrFunction
value: 'std::make_unique'
- key: modernize-make-unique.MakeSmartPtrFunctionHeader
value: memory
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-pass-by-value.ValuesOnly
value: '0'
- key: modernize-raw-string-literal.ReplaceShorterLiterals
value: '0'
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-replace-random-shuffle.IncludeStyle
value: llvm
- key: modernize-use-auto.RemoveStars
value: '0'
- key: modernize-use-default-member-init.IgnoreMacros
value: '1'
- key: modernize-use-default-member-init.UseAssignment
value: '0'
- key: modernize-use-emplace.ContainersWithPushBack
value: '::std::vector;::std::list;::std::deque'
- key: modernize-use-emplace.SmartPointers
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
- key: modernize-use-emplace.TupleMakeFunctions
value: '::std::make_pair;::std::make_tuple'
- key: modernize-use-emplace.TupleTypes
value: '::std::pair;::std::tuple'
- key: modernize-use-equals-default.IgnoreMacros
value: '1'
- key: modernize-use-noexcept.ReplacementString
value: ''
- key: modernize-use-noexcept.UseNoexceptFalse
value: '1'
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
- key: modernize-use-transparent-functors.SafeMode
value: '0'
- key: modernize-use-using.IgnoreMacros
value: '1'
- key: objc-forbidden-subclassing.ForbiddenSuperClassNames
value: 'ABNewPersonViewController;ABPeoplePickerNavigationController;ABPersonViewController;ABUnknownPersonViewController;NSHashTable;NSMapTable;NSPointerArray;NSPointerFunctions;NSTimer;UIActionSheet;UIAlertView;UIImagePickerController;UITextInputMode;UIWebView'
- key: objc-property-declaration.Acronyms
value: 'ASCII;PDF;XML;HTML;URL;RTF;HTTP;TIFF;JPG;PNG;GIF;LZW;ROM;RGB;CMYK;MIDI;FTP'
- key: performance-faster-string-find.StringLikeClasses
value: 'std::basic_string'
- key: performance-for-range-copy.WarnOnAllAutoCopies
value: '0'
- key: performance-inefficient-string-concatenation.StrictMode
value: '0'
- key: performance-inefficient-vector-operation.VectorLikeClasses
value: '::std::vector'
- key: performance-move-const-arg.CheckTriviallyCopyableMove
value: '1'
- key: performance-move-constructor-init.IncludeStyle
value: llvm
- key: performance-type-promotion-in-math-fn.IncludeStyle
value: llvm
- key: performance-unnecessary-value-param.IncludeStyle
value: llvm
- key: readability-braces-around-statements.ShortStatementLines
value: '0'
- key: readability-function-size.BranchThreshold
value: '4294967295'
- key: readability-function-size.LineThreshold
value: '4294967295'
- key: readability-function-size.NestingThreshold
value: '4294967295'
- key: readability-function-size.ParameterThreshold
value: '4294967295'
- key: readability-function-size.StatementThreshold
value: '800'
- key: readability-identifier-naming.IgnoreFailedSplit
value: '0'
- key: readability-implicit-bool-conversion.AllowIntegerConditions
value: '0'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: '0'
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment
value: '0'
- key: readability-simplify-boolean-expr.ChainedConditionalReturn
value: '0'
- key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
value: '3'
...

1
attic/webview/.gitattributes vendored Normal file

@ -0,0 +1 @@
*.h linguist-language=c

7
attic/webview/.gitignore vendored Normal file

@ -0,0 +1,7 @@
# Build atrifacts
/build
/examples/minimal-go/minimal-go
/examples/minimal/minimal
/examples/minimal/minimal.exe
/examples/minimal/build
/examples/timer-cxx/build

19
attic/webview/.travis.yml Normal file

@ -0,0 +1,19 @@
language: go
go:
- 1.x
matrix:
include:
- os: linux
before_install:
- sudo add-apt-repository ppa:webkit-team/ppa -y
- sudo apt-get update
- sudo apt-get install libwebkit2gtk-4.0-dev -y
env: WEBVIEW=gtk
- os: osx
osx_image: xcode8.3
env: WEBVIEW=cocoa
script:
- make example

21
attic/webview/LICENSE Normal file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Serge Zaitsev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

28
attic/webview/Makefile Normal file

@ -0,0 +1,28 @@
WEBVIEW_gtk_FLAGS = -DWEBVIEW_GTK -std=c++14 -Wall -Wextra -pedantic $(shell pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0)
WEBVIEW_cocoa_FLAGS = -DWEBVIEW_COCOA -std=c++14 -Wall -Wextra -pedantic -framework WebKit -mmacosx-version-min=10.11 -DOBJC_OLD_DISPATCH_PROTOTYPES
WEBVIEW_mshtml_FLAGS := -DWEBVIEW_MSHTML -std=c++14 -luser32 -lole32 -loleaut32 -lcomctl32 -luuid -static
WEBVIEW_edge_FLAGS := -DWEBVIEW_EDGE
all:
@echo "make WEBVIEW=... test - build and run tests"
@echo "make WEBVIEW=... lint - run clang-tidy checkers"
@echo "make WEBVIEW=... fmt - run clang-format for all sources"
fmt: webview.h
clang-format -i $^
check-env:
ifndef WEBVIEW_$(WEBVIEW)_FLAGS
$(error "Unknown WEBVIEW value, use WEBVIEW=gtk|cocoa|mshtml|edge")
endif
lint: check-env
clang-tidy example.cc -- $(WEBVIEW_$(WEBVIEW)_FLAGS)
example: check-env example.cc webview.h
$(CXX) example.cc $(WEBVIEW_$(WEBVIEW)_FLAGS) -o example
test: check-env
$(CXX) webview_test.cc $(WEBVIEW_$(WEBVIEW)_FLAGS) -o webview_test
./webview_test
rm webview_test

39
attic/webview/example.cc Normal file

@ -0,0 +1,39 @@
// +build ignore
#include "webview.h"
#ifdef _WIN32
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
#else
int main()
#endif
{
webview::webview w(true, nullptr);
w.set_title("Example");
w.set_size(480, 320, true);
w.bind("noop", [](std::string s) -> std::string { printf("%s\n", s.c_str());return s; });
w.bind("add", [](std::string s) -> std::string {
auto a = std::stoi(webview::json_parse(s, "", 0));
auto b = std::stoi(webview::json_parse(s, "", 1));
return std::to_string(a + b);
});
w.navigate(R"(data:text/html,
<!doctype html>
<html>
<body>hello</body>
<script>
window.onload = function() {
noop('hello').then(function(res) {
console.log('noop res', res);
});
add(1, 2).then(function(res) {
console.log('add res', res);
});
};
</script>
</html>
)");
w.run();
return 0;
}

@ -0,0 +1,15 @@
package main
import (
"github.com/zserge/webview"
)
func main() {
w := webview.New(true)
w.Navigate("https://github.com")
w.SetTitle("Hello")
w.Dispatch(func() {
println("Hello dispatch")
})
w.Run()
}

3
attic/webview/go.mod Normal file

@ -0,0 +1,3 @@
module github.com/zserge/webview
go 1.13

1
attic/webview/webview.cc Normal file

@ -0,0 +1 @@
#include "webview.h"

138
attic/webview/webview.go Normal file

@ -0,0 +1,138 @@
package webview
/*
#cgo linux openbsd freebsd CXXFLAGS: -DWEBVIEW_GTK -std=c++14
#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0
#cgo darwin CXXFLAGS: -DWEBVIEW_COCOA -std=c++14 -DOBJC_OLD_DISPATCH_PROTOTYPES
#cgo darwin LDFLAGS: -framework WebKit
#cgo windows CXXFLAGS: -DWEBVIEW_MSHTML
#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32
#define WEBVIEW_HEADER
#include "webview.h"
#include <stdlib.h>
#include <stdint.h>
extern void _webviewDispatchGoCallback(void *);
static inline void _webview_dispatch_cb(webview_t w, void *arg) {
_webviewDispatchGoCallback(arg);
}
static inline void CgoWebViewDispatch(webview_t w, uintptr_t arg) {
webview_dispatch(w, _webview_dispatch_cb, (void *)arg);
}
*/
import "C"
import (
"runtime"
"sync"
"unsafe"
)
func init() {
// Ensure that main.main is called from the main thread
runtime.LockOSThread()
}
type WebView interface {
Run()
Terminate()
Dispatch(f func())
Navigate(url string)
SetTitle(title string)
Window() unsafe.Pointer
Init(js string)
Eval(js string)
Destroy()
/*
SetBounds(x, y, width, height int)
Bounds() (x, y, width, height int)
Bind(name string, v interface{})
*/
}
type webview struct {
w C.webview_t
}
var (
m sync.Mutex
index uintptr
dispatch = map[uintptr]func(){}
)
func boolToInt(b bool) C.int {
if b {
return 1
}
return 0
}
func New(debug bool) WebView { return NewWindow(debug, nil) }
func NewWindow(debug bool, window unsafe.Pointer) WebView {
w := &webview{}
q
return w
}
func (w *webview) Destroy() {
C.webview_destroy(w.w)
}
func (w *webview) Run() {
C.webview_run(w.w)
}
func (w *webview) Terminate() {
C.webview_terminate(w.w)
}
func (w *webview) Window() unsafe.Pointer {
return C.webview_get_window(w.w)
}
func (w *webview) Navigate(url string) {
s := C.CString(url)
defer C.free(unsafe.Pointer(s))
C.webview_navigate(w.w, s)
}
func (w *webview) SetTitle(title string) {
s := C.CString(title)
defer C.free(unsafe.Pointer(s))
C.webview_set_title(w.w, s)
}
func (w *webview) Init(js string) {
s := C.CString(js)
defer C.free(unsafe.Pointer(s))
C.webview_init(w.w, s)
}
func (w *webview) Eval(js string) {
s := C.CString(js)
defer C.free(unsafe.Pointer(s))
C.webview_eval(w.w, s)
}
func (w *webview) Dispatch(f func()) {
m.Lock()
for ; dispatch[index] != nil; index++ {
}
dispatch[index] = f
m.Unlock()
C.CgoWebViewDispatch(w.w, C.uintptr_t(index))
}
//export _webviewDispatchGoCallback
func _webviewDispatchGoCallback(index unsafe.Pointer) {
var f func()
m.Lock()
f = dispatch[uintptr(index)]
delete(dispatch, uintptr(index))
m.Unlock()
f()
}

1248
attic/webview/webview.h Normal file

File diff suppressed because it is too large Load Diff

@ -0,0 +1,38 @@
// +build ignore
#include "webview.h"
#include <cstring>
#include <cassert>
static void test_terminate() {
webview::webview w(false, nullptr);
w.dispatch([&]() { w.terminate(); });
w.run();
}
static void cb_assert_arg(webview_t w, void *arg) {
assert(w != NULL);
assert(memcmp(arg, "arg", 3) == 0);
}
static void cb_terminate(webview_t w, void *arg) {
assert(arg == NULL);
webview_terminate(w);
}
static void test_c_api() {
webview_t w;
w = webview_create(false, NULL);
webview_set_bounds(w, 100, 100, 480, 320, 0);
webview_set_title(w, "Test");
webview_navigate(w, "https://github.com/zserge/webview");
webview_dispatch(w, cb_assert_arg, (void *)"arg");
webview_dispatch(w, cb_terminate, NULL);
webview_run(w);
webview_destroy(w);
}
int main() {
test_terminate();
test_c_api();
return 0;
}

@ -479,6 +479,7 @@ EmbeddedNetworkController::~EmbeddedNetworkController()
void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender)
{
char tmp[64];
_signingId = signingId;
_sender = sender;
_signingIdAddressString = signingId.address().toString(tmp);
@ -1445,6 +1446,7 @@ void EmbeddedNetworkController::_request(
const bool noAutoAssignIps = OSUtils::jsonBool(member["noAutoAssignIps"],false);
// Set IPv6 static IPs based on NDP emulated schemes if enabled.
if ((v6AssignMode.is_object())&&(!noAutoAssignIps)) {
if ((OSUtils::jsonBool(v6AssignMode["rfc4193"],false))&&(nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
nc->staticIps[nc->staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt());

@ -43,10 +43,10 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
// LF record masking key is the first 32 bytes of SHA512(controller private key) in hex,
// hiding record values from anything but the controller or someone who has its key.
uint8_t sha512pk[64];
_myId.sha512PrivateKey(sha512pk);
uint8_t sha384pk[48];
_myId.hash(sha384pk,true);
char maskingKey [128];
Utils::hex(sha512pk,32,maskingKey);
Utils::hex(sha384pk,32,maskingKey);
httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort,600);
int64_t timeRangeStart = 0;

@ -13,53 +13,6 @@
package cli
import (
"encoding/base64"
"fmt"
"io/ioutil"
"net/url"
"os"
"strings"
"zerotier/pkg/zerotier"
)
// AddRoot CLI command
func AddRoot(basePath, authToken string, args []string) {
if len(args) == 0 {
Help()
os.Exit(0)
}
locData, err := ioutil.ReadFile(args[0])
if err != nil {
locData, err2 := base64.StdEncoding.DecodeString(strings.TrimSpace(args[0]))
if err2 != nil || len(locData) == 0 {
fmt.Printf("ERROR: unable to read locator: %s\n", err.Error())
os.Exit(1)
}
}
loc, err := zerotier.NewLocatorFromBytes(locData)
if err != nil {
fmt.Printf("ERROR: invalid locator '%s' (tried as file and base64 literal): %s\n", args[0], err.Error())
os.Exit(1)
}
var name string
if len(args) > 1 {
if len(args) > 2 {
Help()
os.Exit(1)
}
name = strings.TrimSpace(args[1])
}
var result zerotier.Root
apiPost(basePath, authToken, "/root/"+url.PathEscape(name), &zerotier.Root{
Name: name,
Locator: loc,
}, &result)
fmt.Println(jsonDump(&result))
os.Exit(0)
}

@ -41,12 +41,8 @@ Commands:
status Show ZeroTier service status and config
peers Show VL1 peers
roots Show configured VL1 root servers
addroot <locator> [name] Add a VL1 root
removeroot <name> Remove a VL1 root
locator <command> [args] Locator management commands
new <identity> <address> [...] Create and sign locator for identity
newdnskey Create a secure DNS name and secret
getdns <dns key> <locator> Create secure DNS TXT records
addroot <identity> Add VL1 root server
removeroot <identity|address> Remove VL1 root server
identity <command> [args] Identity management commands
new [c25519|p384] Create new identity (including secret)
getpublic <identity> Extract only public part of identity

@ -1,137 +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.
*/
/****/
package cli
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strings"
"zerotier/pkg/zerotier"
)
func locatorNew(args []string) {
if len(args) < 2 {
Help()
os.Exit(1)
}
identity := readIdentity(args[0])
if !identity.HasPrivate() {
fmt.Println("FATAL: identity does not contain a secret key (required to sign locator)")
os.Exit(1)
}
var virt []*zerotier.Identity
var phys []*zerotier.InetAddress
for i := 1; i < len(args); i++ {
if strings.Contains(args[i], "/") {
a := zerotier.NewInetAddressFromString(args[i])
if a == nil {
fmt.Printf("FATAL: IP/port address '%s' is not valid\n", args[i])
os.Exit(1)
}
phys = append(phys, a)
} else {
a, err := zerotier.NewIdentityFromString(args[i])
if err != nil {
fmt.Printf("FATAL: identity (virtual address) '%s' is not valid: %s\n", args[i], err.Error())
os.Exit(1)
}
virt = append(virt, a)
}
}
loc, err := zerotier.NewLocator(identity, virt, phys)
if err != nil {
fmt.Printf("FATAL: internal error creating locator: %s\n", err.Error())
os.Exit(1)
}
fmt.Println(jsonDump(loc))
os.Exit(0)
}
func locatorNewDNSKey(args []string) {
if len(args) != 0 {
Help()
os.Exit(0)
}
sk, err := zerotier.NewLocatorDNSSigningKey()
if err != nil {
fmt.Printf("FATAL: error creating secure DNS signing key: %s", err.Error())
os.Exit(1)
}
fmt.Println(jsonDump(sk))
os.Exit(0)
}
func locatorGetDNS(args []string) {
if len(args) < 2 {
Help()
os.Exit(1)
}
keyData, err := ioutil.ReadFile(args[0])
if err != nil {
fmt.Printf("FATAL: unable to read secure DNS key file: %s\n", err.Error())
os.Exit(1)
}
var sk zerotier.LocatorDNSSigningKey
err = json.Unmarshal(keyData, &sk)
if err != nil {
fmt.Printf("FATAL: DNS key file invalid: %s", err.Error())
os.Exit(1)
}
locData, err := ioutil.ReadFile(args[1])
if err != nil {
fmt.Printf("FATAL: unable to read locator: %s\n", err.Error())
os.Exit(1)
}
var loc zerotier.Locator
err = json.Unmarshal(locData, &loc)
if err != nil {
fmt.Printf("FATAL: locator invalid: %s", err.Error())
os.Exit(1)
}
txt, err := loc.MakeTXTRecords(&sk)
if err != nil {
fmt.Printf("FATAL: error creating TXT records: %s\n", err.Error())
os.Exit(1)
}
for _, t := range txt {
fmt.Println(t)
}
os.Exit(0)
}
// Locator CLI command
func Locator(args []string) {
if len(args) > 0 {
switch args[0] {
case "new":
locatorNew(args[1:])
case "newdnskey":
locatorNewDNSKey(args[1:])
case "getdns":
locatorGetDNS(args[1:])
}
}
Help()
os.Exit(1)
}

@ -13,51 +13,6 @@
package cli
import (
"fmt"
"os"
"zerotier/pkg/zerotier"
)
// Roots CLI command
func Roots(basePath, authToken string, args []string, jsonOutput bool) {
var roots []zerotier.Root
apiGet(basePath, authToken, "/root", &roots)
if jsonOutput {
fmt.Println(jsonDump(roots))
} else {
fmt.Printf("%32s <address> <physical/virtual>\n", "<name>")
for _, r := range roots {
rn := r.Name
if len(rn) > 32 {
rn = rn[len(rn)-32:]
}
if r.Locator != nil {
if len(r.Locator.Physical) == 0 && len(r.Locator.Virtual) == 0 {
fmt.Printf("%32s %.10x -\n", rn, uint64(r.Locator.Identity.Address()))
} else {
fmt.Printf("%32s %.10x ", rn, uint64(r.Locator.Identity.Address()))
for i, a := range r.Locator.Physical {
if i > 0 {
fmt.Print(",")
}
fmt.Print(a.String())
}
for i, a := range r.Locator.Virtual {
if i > 0 || len(r.Locator.Physical) > 0 {
fmt.Print(",")
}
fmt.Print(a.String())
}
fmt.Printf("\n")
}
} else {
fmt.Printf("%32s - -\n", rn)
}
}
}
os.Exit(0)
}

@ -18,6 +18,7 @@ import (
"os"
"os/signal"
"syscall"
"zerotier/pkg/zerotier"
)

@ -127,8 +127,6 @@ func main() {
case "removeroot":
authTokenRequired(authToken)
cli.RemoveRoot(basePath, authToken, cmdArgs)
case "locator":
cli.Locator(cmdArgs)
case "identity":
cli.Identity(cmdArgs)
case "networks", "listnetworks":

@ -5,4 +5,5 @@ go 1.13
require (
github.com/Microsoft/go-winio v0.4.14
github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95
golang.org/x/sys v0.0.0-20200107162124-548cf772de50 // indirect
)

@ -13,3 +13,5 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190529164535-6a60838ec259 h1:so6Hr/LodwSZ5UQDu/7PmQiDeS112WwtLvU3lpSPZTU=
golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200107162124-548cf772de50 h1:YvQ10rzcqWXLlJZ3XCUoO25savxmscf4+SC+ZqiCHhA=
golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

@ -13,35 +13,25 @@
#include "GoGlue.h"
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include "../../node/Constants.hpp"
#include "../../node/InetAddress.hpp"
#include "../../node/Node.hpp"
#include "../../node/Utils.hpp"
#include "../../node/MAC.hpp"
#include "../../node/Address.hpp"
#include "../../node/Locator.hpp"
#include "../../osdep/OSUtils.hpp"
#include "../../osdep/EthernetTap.hpp"
#include "../../osdep/ManagedRoute.hpp"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#ifndef __WINDOWS__
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#ifdef __BSD__
#include <net/if.h>
#endif
@ -56,7 +46,6 @@
#include <mutex>
#include <map>
#include <vector>
#include <array>
#include <set>
#include <memory>
#include <atomic>
@ -111,10 +100,9 @@ const char *ZT_PLATFORM_DEFAULT_HOMEPATH = defaultHomePath.c_str();
/* These functions are implemented in Go in pkg/ztnode/node-callbacks.go */
extern "C" int goPathCheckFunc(void *,uint64_t,int,const void *,int);
extern "C" int goPathLookupFunc(void *,uint64_t,int,int *,uint8_t [16],int *);
extern "C" int goPathLookupFunc(void *,uint64_t,int,const ZT_Identity *,int *,uint8_t [16],int *);
extern "C" void goStateObjectPutFunc(void *,int,const uint64_t [2],const void *,int);
extern "C" int goStateObjectGetFunc(void *,int,const uint64_t [2],void *,unsigned int);
extern "C" void goDNSResolverFunc(void *,const uint8_t *,int,const char *,uintptr_t);
extern "C" void goVirtualNetworkConfigFunc(void *,ZT_GoTap *,uint64_t,int,const ZT_VirtualNetworkConfig *);
extern "C" void goZtEvent(void *,int,const void *);
extern "C" void goHandleTapAddedMulticastGroup(void *,ZT_GoTap *,uint64_t,uint64_t,uint32_t);
@ -279,6 +267,7 @@ static int ZT_GoNode_PathLookupFunction(
void *uptr,
void *tptr,
uint64_t ztAddress,
const ZT_Identity *id,
int desiredAddressFamily,
struct sockaddr_storage *sa)
{
@ -289,6 +278,7 @@ static int ZT_GoNode_PathLookupFunction(
reinterpret_cast<ZT_GoNode *>(uptr)->goUserPtr,
ztAddress,
desiredAddressFamily,
id,
&family,
ip,
&port
@ -310,20 +300,6 @@ static int ZT_GoNode_PathLookupFunction(
return 0;
}
static void ZT_GoNode_DNSResolver(
ZT_Node *node,
void *uptr,
void *tptr,
const enum ZT_DNSRecordType *types,
unsigned int numTypes,
const char *name,
uintptr_t requestId)
{
uint8_t t[256];
for(unsigned int i=0;(i<numTypes)&&(i<256);++i) t[i] = (uint8_t)types[i];
goDNSResolverFunc(reinterpret_cast<ZT_GoNode *>(uptr)->goUserPtr,t,(int)numTypes,name,requestId);
}
/****************************************************************************/
extern "C" ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr)
@ -336,7 +312,6 @@ extern "C" ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr)
cb.virtualNetworkFrameFunction = &ZT_GoNode_VirtualNetworkFrameFunction;
cb.virtualNetworkConfigFunction = &ZT_GoNode_VirtualNetworkConfigFunction;
cb.eventCallback = &ZT_GoNode_EventCallback;
cb.dnsResolver = &ZT_GoNode_DNSResolver;
cb.pathCheckFunction = &ZT_GoNode_PathCheckFunction;
cb.pathLookupFunction = &ZT_GoNode_PathLookupFunction;
@ -727,133 +702,3 @@ extern "C" int ZT_GoTap_removeRoute(ZT_GoTap *tap,int targetAf,const void *targe
}
return reinterpret_cast<EthernetTap *>(tap)->removeRoute(target,via,metric);
}
/****************************************************************************/
extern "C" const char *ZT_GoIdentity_generate(int type)
{
Identity id;
id.generate((Identity::Type)type);
char *tmp = (char *)malloc(ZT_IDENTITY_STRING_BUFFER_LENGTH);
if (tmp)
id.toString(true,tmp);
return tmp;
}
extern "C" int ZT_GoIdentity_validate(const char *idStr)
{
Identity id;
if (!id.fromString(idStr))
return 0;
if (!id.locallyValidate())
return 0;
return 1;
}
extern "C" int ZT_GoIdentity_sign(const char *idStr,const void *data,unsigned int len,void *sigbuf,unsigned int sigbuflen)
{
Identity id;
if (!id.fromString(idStr))
return 0;
return (int)id.sign(data,len,sigbuf,sigbuflen);
}
extern "C" int ZT_GoIdentity_verify(const char *idStr,const void *data,unsigned int len,const void *sig,unsigned int siglen)
{
Identity id;
if (!id.fromString(idStr))
return 0;
return id.verify(data,len,sig,siglen) ? 1 : 0;
}
/****************************************************************************/
extern "C" int ZT_GoLocator_makeSecureDNSName(char *name,unsigned int nameBufSize,uint8_t *privateKey,unsigned int privateKeyBufSize)
{
if ((privateKeyBufSize < ZT_ECC384_PRIVATE_KEY_SIZE)||(nameBufSize < 256))
return -1;
uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE];
ECC384GenerateKey(pub,privateKey);
const Str n(Locator::makeSecureDnsName(pub));
if (n.length() >= nameBufSize)
return -1;
Utils::scopy(name,nameBufSize,n.c_str());
return ZT_ECC384_PRIVATE_KEY_SIZE;
}
extern "C" int ZT_GoLocator_makeLocator(
uint8_t *buf,
unsigned int bufSize,
int64_t ts,
const char *id,
const struct sockaddr_storage *physicalAddresses,
unsigned int physicalAddressCount,
const char **virtualAddresses,
unsigned int virtualAddressCount)
{
Locator loc;
for(unsigned int i=0;i<physicalAddressCount;++i) {
loc.add(*reinterpret_cast<const InetAddress *>(physicalAddresses + i));
}
for(unsigned int i=0;i<virtualAddressCount;++i) {
Identity id;
if (!id.fromString(virtualAddresses[i]))
return -1;
loc.add(id);
}
Identity signingId;
if (!signingId.fromString(id))
return -1;
if (!signingId.hasPrivate())
return -1;
if (!loc.finish(signingId,ts))
return -1;
Buffer<65536> *tmp = new Buffer<65536>();
loc.serialize(*tmp);
if (tmp->size() > bufSize) {
delete tmp;
return -1;
}
memcpy(buf,tmp->data(),tmp->size());
int s = (int)tmp->size();
delete tmp;
return s;
}
extern "C" int ZT_GoLocator_decodeLocator(const uint8_t *locatorBytes,unsigned int locatorSize,struct ZT_GoLocator_Info *info)
{
Locator loc;
if (!loc.deserialize(locatorBytes,locatorSize))
return -1;
if (!loc.verify())
return -2;
loc.id().toString(false,info->id);
info->phyCount = 0;
info->virtCount = 0;
for(auto p=loc.phy().begin();p!=loc.phy().end();++p)
memcpy(&(info->phy[info->phyCount++]),&(*p),sizeof(struct sockaddr_storage));
for(auto v=loc.virt().begin();v!=loc.virt().end();++v)
v->toString(false,info->virt[info->virtCount++]);
return 1;
}
int ZT_GoLocator_makeSignedTxtRecords(
const uint8_t *locator,
unsigned int locatorSize,
const char *name,
const uint8_t *privateKey,
unsigned int privateKeySize,
char results[256][256])
{
if (privateKeySize != ZT_ECC384_PRIVATE_KEY_SIZE)
return -1;
Locator loc;
if (!loc.deserialize(locator,locatorSize))
return -1;
std::vector<Str> r(loc.makeTxtRecords(privateKey));
if (r.size() > 256)
return -1;
for(unsigned long i=0;i<r.size();++i)
Utils::scopy(results[i],256,r[i].c_str());
return (int)r.size();
}

@ -14,14 +14,22 @@
#ifndef ZT_GONODE_H
#define ZT_GONODE_H
#ifdef __cplusplus
#include <cstdint>
#include <cstdlib>
#include <cstring>
#else
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#endif
#include "../../include/ZeroTierCore.h"
#include "../../node/Constants.hpp"
/****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/* A pointer to an instance of EthernetTap */
typedef void ZT_GoTap;
@ -32,18 +40,8 @@ typedef void ZT_GoTap;
struct ZT_GoNode_Impl;
typedef struct ZT_GoNode_Impl ZT_GoNode;
/****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************/
extern const char *ZT_PLATFORM_DEFAULT_HOMEPATH;
/****************************************************************************/
ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr);
void ZT_GoNode_delete(ZT_GoNode *gn);
@ -60,8 +58,6 @@ ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid);
void ZT_GoNode_leave(ZT_GoNode *gn,uint64_t nwid);
/****************************************************************************/
void ZT_GoTap_setEnabled(ZT_GoTap *tap,int enabled);
int ZT_GoTap_addIp(ZT_GoTap *tap,int af,const void *ip,int netmaskBits);
@ -88,67 +84,6 @@ int ZT_GoTap_addRoute(ZT_GoTap *tap,int targetAf,const void *targetIp,int target
int ZT_GoTap_removeRoute(ZT_GoTap *tap,int targetAf,const void *targetIp,int targetNetmaskBits,int viaAf,const void *viaIp,unsigned int metric);
/****************************************************************************/
const char *ZT_GoIdentity_generate(int type);
int ZT_GoIdentity_validate(const char *idStr);
int ZT_GoIdentity_sign(const char *idStr,const void *data,unsigned int len,void *sigbuf,unsigned int sigbuflen);
int ZT_GoIdentity_verify(const char *idStr,const void *data,unsigned int len,const void *sig,unsigned int siglen);
/****************************************************************************/
struct ZT_GoLocator_Info {
char id[1024];
unsigned int phyCount;
unsigned int virtCount;
struct sockaddr_storage phy[256];
char virt[256][1024];
};
/* Returns length of private key stored in private key buffer on success, -1 on fail */
int ZT_GoLocator_makeSecureDNSName(char name[256],unsigned int nameBufSize,uint8_t *privateKey,unsigned int privateKeyBufSize);
/*
* The id is the full identity described by the locator. It must include
* its secret key to permit the locator to be signed.
*
* Physical addresses must be IPv4 or IPv6 IP/port pairs. Virtual addresses
* must be full ZeroTier identities in string format.
*
* On success this returns the actual number of bytes stored in the buffer.
* On failure -1 is returned.
*/
int ZT_GoLocator_makeLocator(
uint8_t *buf,
unsigned int bufSize,
int64_t ts,
const char *id,
const struct sockaddr_storage *physicalAddresses,
unsigned int physicalAddressCount,
const char **virtualAddresses,
unsigned int virtualAddressCount);
/* Returns >0 on success, fills info structure */
int ZT_GoLocator_decodeLocator(const uint8_t *locatorBytes,unsigned int locatorSize,struct ZT_GoLocator_Info *info);
/*
* The privateKey and privateKeySize are those created by makeSecureDNSName.
* Results is filled and the number of lines of TXT are returned. The value
* -1 is returned on error.
*/
int ZT_GoLocator_makeSignedTxtRecords(
const uint8_t *locator,
unsigned int locatorSize,
const char *name,
const uint8_t *privateKey,
unsigned int privateKeySize,
char results[256][256]);
/****************************************************************************/
#ifdef __cplusplus
}
#endif

@ -460,57 +460,14 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
}
apiSetStandardHeaders(out)
var queriedName string
if len(req.URL.Path) > 6 {
queriedName = req.URL.Path[6:]
}
//var queriedName string
//if len(req.URL.Path) > 6 {
// queriedName = req.URL.Path[6:]
//}
if req.Method == http.MethodDelete {
if len(queriedName) > 0 {
roots := node.Roots()
for _, r := range roots {
if r.Name == queriedName {
node.RemoveRoot(queriedName)
_ = apiSendObj(out, req, http.StatusOK, r)
return
}
}
}
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"root not found"})
} else if req.Method == http.MethodPost || req.Method == http.MethodPut {
if len(queriedName) == 0 {
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"only individual roots can be added or modified with POST/PUT"})
return
}
var r Root
if apiReadObj(out, req, &r) == nil {
if r.Name != queriedName {
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"root name does not match name in path"})
return
}
err := node.SetRoot(r.Name, r.Locator)
if err != nil {
_ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"set/update root failed: " + err.Error()})
} else {
roots := node.Roots()
for _, r := range roots {
if r.Name == queriedName {
_ = apiSendObj(out, req, http.StatusOK, r)
return
}
}
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"set/update root failed: root set but not subsequently found in list"})
}
}
} else if req.Method == http.MethodGet || req.Method == http.MethodHead {
roots := node.Roots()
for _, r := range roots {
if r.Name == queriedName {
_ = apiSendObj(out, req, http.StatusOK, r)
return
}
}
_ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"root not found"})
} else {
out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")
_ = apiSendObj(out, req, http.StatusMethodNotAllowed, &APIErr{"unsupported method: " + req.Method})

@ -13,7 +13,6 @@
package zerotier
//#cgo CFLAGS: -O3
//#include "../../native/GoGlue.h"
import "C"
@ -47,15 +46,26 @@ type Identity struct {
privateKey []byte
}
// NewIdentity generates a new identity of the selected type
func NewIdentity(identityType int) (*Identity, error) {
cIdStr := C.ZT_GoIdentity_generate(C.int(identityType))
if uintptr(unsafe.Pointer(cIdStr)) == 0 {
func newIdentityFromCIdentity(cid unsafe.Pointer) (*Identity, error) {
if uintptr(cid) == 0 {
return nil, ErrInvalidParameter
}
var idStrBuf [4096]byte
idStr := C.ZT_Identity_toString(cid,(*C.char)(unsafe.Pointer(&idStrBuf[0])),4096,1)
if uintptr(unsafe.Pointer(idStr)) == 0 {
return nil, ErrInternal
}
id, err := NewIdentityFromString(C.GoString(cIdStr))
C.free(unsafe.Pointer(cIdStr))
return id, err
return NewIdentityFromString(C.GoString(idStr))
}
// NewIdentity generates a new identity of the selected type
func NewIdentity(identityType int) (*Identity, error) {
cid := C.ZT_Identity_new(C.enum_ZT_Identity_Type(identityType))
if uintptr(unsafe.Pointer(cid)) == 0 {
return nil, ErrInternal
}
defer C.ZT_Identity_delete(cid)
return newIdentityFromCIdentity(cid)
}
// NewIdentityFromString generates a new identity from its string representation.
@ -159,23 +169,35 @@ func (id *Identity) String() string {
func (id *Identity) LocallyValidate() bool {
idCStr := C.CString(id.String())
defer C.free(unsafe.Pointer(idCStr))
return C.ZT_GoIdentity_validate(idCStr) != 0
cid := C.ZT_Identity_fromString(idCStr)
if uintptr(cid) == 0 {
return false
}
defer C.ZT_Identity_delete(cid)
return C.ZT_Identity_validate(cid) != 0
}
// Sign signs a message with this identity
func (id *Identity) Sign(msg []byte) ([]byte, error) {
idCStr := C.CString(id.PrivateKeyString())
var sigbuf [96]byte
defer C.free(unsafe.Pointer(idCStr))
cid := C.ZT_Identity_fromString(idCStr)
if uintptr(cid) == 0 {
return nil, ErrInvalidKey
}
defer C.ZT_Identity_delete(cid)
var dataP unsafe.Pointer
if len(msg) > 0 {
dataP = unsafe.Pointer(&msg[0])
}
siglen := C.ZT_GoIdentity_sign(idCStr, dataP, C.uint(len(msg)), unsafe.Pointer(&sigbuf[0]), C.uint(len(sigbuf)))
C.free(unsafe.Pointer(idCStr))
if siglen <= 0 {
var sig [96]byte
sigLen := C.ZT_Identity_sign(cid,dataP,C.uint(len(msg)),unsafe.Pointer(&sig[0]),96)
if sigLen <= 0 {
return nil, ErrInvalidKey
}
return sigbuf[0:int(siglen)], nil
return sig[0:uint(sigLen)], nil
}
// Verify verifies a signature
@ -183,13 +205,20 @@ func (id *Identity) Verify(msg, sig []byte) bool {
if len(sig) == 0 {
return false
}
idCStr := C.CString(id.String())
defer C.free(unsafe.Pointer(idCStr))
cid := C.ZT_Identity_fromString(idCStr)
if uintptr(cid) == 0 {
return false
}
defer C.ZT_Identity_delete(cid)
var dataP unsafe.Pointer
if len(msg) > 0 {
dataP = unsafe.Pointer(&msg[0])
}
return C.ZT_GoIdentity_verify(idCStr, dataP, C.uint(len(msg)), unsafe.Pointer(&sig[0]), C.uint(len(sig))) != 0
return C.ZT_Identity_verify(cid,dataP,C.uint(len(msg)),unsafe.Pointer(&sig[0]),C.uint(len(sig))) != 0
}
// MarshalJSON marshals this Identity in its string format (private key is never included)

@ -33,7 +33,7 @@ type LocalConfigPhysicalPathConfiguration struct {
// LocalConfigVirtualAddressConfiguration contains settings for virtual addresses
type LocalConfigVirtualAddressConfiguration struct {
// Try is a list of IPs/ports to try for this peer in addition to anything learned from roots or direct path push
Try []InetAddress `json:",omitempty"`
Try []InetAddress `json:"try,omitempty"`
}
// ExternalAddress is an externally visible address

@ -1,191 +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.
*/
/****/
package zerotier
//#cgo CFLAGS: -O3
//#include "../../native/GoGlue.h"
import "C"
import (
"encoding/json"
"unsafe"
)
// LocatorDNSSigningKey is the public (as a secure DNS name) and private keys for entering locators into DNS
type LocatorDNSSigningKey struct {
SecureDNSName string `json:"secureDNSName"`
PrivateKey []byte `json:"privateKey"`
}
// NewLocatorDNSSigningKey creates a new signing key and secure DNS name for storing locators in DNS
func NewLocatorDNSSigningKey() (*LocatorDNSSigningKey, error) {
var nameBuf [256]C.char
var keyBuf [64]byte
keySize := int(C.ZT_GoLocator_makeSecureDNSName(&nameBuf[0], 256, (*C.uint8_t)(unsafe.Pointer(&keyBuf[0])), 128))
if keySize <= 0 {
return nil, ErrInternal
}
var sk LocatorDNSSigningKey
sk.SecureDNSName = C.GoString(&nameBuf[0])
sk.PrivateKey = keyBuf[0:keySize]
return &sk, nil
}
// Locator is a binary serialized record containing information about where a ZeroTier node is located on the network.
// Note that for JSON objects only Bytes needs to be specified. When JSON is deserialized only this field is used
// and the others are always reconstructed from it.
type Locator struct {
// Identity is the full identity of the node being located
Identity *Identity `json:"identity"`
// Physical is a list of static physical network addresses for this node
Physical []*InetAddress `json:"physical,omitempty"`
// Virtual is a list of ZeroTier nodes that can relay to this node
Virtual []*Identity `json:"virtual,omitempty"`
// Bytes is the raw serialized Locator
Bytes []byte `json:"bytes,omitempty"`
}
// NewLocator creates a new locator with the given identity and addresses and the current time as timestamp.
// The identity must include its secret key so that it can sign the final locator.
func NewLocator(id *Identity, virtualAddresses []*Identity, physicalAddresses []*InetAddress) (*Locator, error) {
if !id.HasPrivate() {
return nil, ErrSecretKeyRequired
}
idstr := id.PrivateKeyString()
phy := make([]C.struct_sockaddr_storage, len(physicalAddresses))
virt := make([]*C.char, len(virtualAddresses))
idCstr := C.CString(idstr)
defer func() {
C.free(unsafe.Pointer(idCstr))
for _, v := range virt {
if uintptr(unsafe.Pointer(v)) != 0 {
C.free(unsafe.Pointer(v))
}
}
}()
for i := 0; i < len(physicalAddresses); i++ {
if !makeSockaddrStorage(physicalAddresses[i].IP, physicalAddresses[i].Port, &phy[i]) {
return nil, ErrInvalidParameter
}
}
for i := 0; i < len(virtualAddresses); i++ {
idstr := virtualAddresses[i].String()
virt[i] = C.CString(idstr)
}
var buf [65536]byte
var pPhy *C.struct_sockaddr_storage
var pVirt **C.char
if len(phy) > 0 {
pPhy = &phy[0]
}
if len(virt) > 0 {
pVirt = &virt[0]
}
locSize := C.ZT_GoLocator_makeLocator((*C.uint8_t)(unsafe.Pointer(&buf[0])), 65536, C.int64_t(TimeMs()), idCstr, pPhy, C.uint(len(phy)), pVirt, C.uint(len(virt)))
if locSize <= 0 {
return nil, ErrInvalidParameter
}
r := make([]byte, int(locSize))
copy(r[:], buf[0:int(locSize)])
return &Locator{
Identity: id,
Physical: physicalAddresses,
Virtual: virtualAddresses,
Bytes: r,
}, nil
}
// NewLocatorFromBytes decodes a locator from its serialized byte array form
func NewLocatorFromBytes(b []byte) (*Locator, error) {
if len(b) == 0 {
return nil, ErrInvalidParameter
}
var info C.struct_ZT_GoLocator_Info
res := C.ZT_GoLocator_decodeLocator((*C.uint8_t)(unsafe.Pointer(&b[0])), C.uint(len(b)), &info)
if res == -2 {
return nil, ErrInvalidSignature
} else if res <= 0 {
return nil, ErrInvalidParameter
}
var loc Locator
var err error
loc.Identity, err = NewIdentityFromString(C.GoString(&info.id[0]))
if err != nil {
return nil, err
}
for i := 0; i < int(info.phyCount); i++ {
ua := sockaddrStorageToUDPAddr(&info.phy[i])
if ua != nil {
loc.Physical = append(loc.Physical, &InetAddress{IP: ua.IP, Port: ua.Port})
}
}
for i := 0; i < int(info.virtCount); i++ {
id, err := NewIdentityFromString(C.GoString(&info.virt[i][0]))
if err == nil {
loc.Virtual = append(loc.Virtual, id)
}
}
loc.Bytes = b
return &loc, nil
}
// MakeTXTRecords creates secure DNS TXT records for this locator
func (l *Locator) MakeTXTRecords(key *LocatorDNSSigningKey) ([]string, error) {
if key == nil || len(l.Bytes) == 0 || len(key.PrivateKey) == 0 {
return nil, ErrInvalidParameter
}
var results [256][256]C.char
cName := C.CString(key.SecureDNSName)
defer C.free(unsafe.Pointer(cName))
count := int(C.ZT_GoLocator_makeSignedTxtRecords((*C.uint8_t)(&l.Bytes[0]), C.uint(len(l.Bytes)), cName, (*C.uint8_t)(&key.PrivateKey[0]), C.uint(len(key.PrivateKey)), &results[0]))
if count > 0 {
var t []string
for i := 0; i < int(count); i++ {
t = append(t, C.GoString(&results[i][0]))
}
return t, nil
}
return nil, ErrInternal
}
type locatorForUnmarshal struct {
Bytes []byte `json:"bytes,omitempty"`
}
// UnmarshalJSON unmarshals this Locator from a byte array in JSON.
func (l *Locator) UnmarshalJSON(j []byte) error {
var bytes locatorForUnmarshal
err := json.Unmarshal(j, &bytes)
if err != nil {
return err
}
tmp, err := NewLocatorFromBytes(bytes.Bytes)
if err != nil {
return err
}
*l = *tmp
return nil
}

@ -595,62 +595,6 @@ func (n *Node) Networks() []*Network {
return nws
}
// Roots retrieves a list of root servers on this node and their preferred and online status.
func (n *Node) Roots() []*Root {
var roots []*Root
rl := C.ZT_Node_listRoots(unsafe.Pointer(n.zn), C.int64_t(TimeMs()))
if rl != nil {
for i := 0; i < int(rl.count); i++ {
root := (*C.ZT_Root)(unsafe.Pointer(uintptr(unsafe.Pointer(rl)) + C.sizeof_ZT_RootList))
loc, _ := NewLocatorFromBytes(C.GoBytes(root.locator, C.int(root.locatorSize)))
if loc != nil {
roots = append(roots, &Root{
Name: C.GoString(root.name),
Locator: loc,
})
}
}
C.ZT_Node_freeQueryResult(unsafe.Pointer(n.zn), unsafe.Pointer(rl))
}
return roots
}
// SetRoot sets or updates a root.
// Name can be a DNS name (preferably secure) for DNS fetched locators or can be
// the empty string for static roots. If the name is empty then the locator must
// be non-nil.
func (n *Node) SetRoot(name string, locator *Locator) error {
if len(name) == 0 {
if locator == nil {
return ErrInvalidParameter
}
name = locator.Identity.address.String()
}
var lb []byte
if locator != nil {
lb = locator.Bytes
}
var lbp unsafe.Pointer
if len(lb) > 0 {
lbp = unsafe.Pointer(&lb[0])
}
cn := C.CString(name)
defer C.free(unsafe.Pointer(cn))
if C.ZT_Node_setRoot(unsafe.Pointer(n.zn), cn, lbp, C.uint(len(lb))) != 0 {
return ErrInternal
}
return nil
}
// RemoveRoot removes a root.
// For static roots the name should be the ZeroTier address.
func (n *Node) RemoveRoot(name string) {
cn := C.CString(name)
defer C.free(unsafe.Pointer(cn))
C.ZT_Node_removeRoot(unsafe.Pointer(n.zn), cn)
return
}
// Peers retrieves a list of current peers
func (n *Node) Peers() []*Peer {
var peers []*Peer
@ -665,59 +609,21 @@ func (n *Node) Peers() []*Peer {
p2.Role = int(p.role)
p2.Paths = make([]Path, 0, int(p.pathCount))
usingAllocation := false
for j := uintptr(0); j < uintptr(p.pathCount); j++ {
pt := &p.paths[j]
if pt.alive != 0 {
a := sockaddrStorageToUDPAddr(&pt.address)
if a != nil {
alloc := float32(pt.allocation)
if alloc > 0.0 {
usingAllocation = true
}
p2.Paths = append(p2.Paths, Path{
IP: a.IP,
Port: a.Port,
LastSend: int64(pt.lastSend),
LastReceive: int64(pt.lastReceive),
TrustedPathID: uint64(pt.trustedPathId),
Latency: float32(pt.latency),
PacketDelayVariance: float32(pt.packetDelayVariance),
ThroughputDisturbCoeff: float32(pt.throughputDisturbCoeff),
PacketErrorRatio: float32(pt.packetErrorRatio),
PacketLossRatio: float32(pt.packetLossRatio),
Stability: float32(pt.stability),
Throughput: uint64(pt.throughput),
MaxThroughput: uint64(pt.maxThroughput),
Allocation: alloc,
})
}
}
}
if !usingAllocation { // if all allocations are zero fall back to single path mode that uses the preferred flag
for i, j := 0, uintptr(0); j < uintptr(p.pathCount); j++ {
pt := &p.paths[j]
if pt.alive != 0 {
if pt.preferred == 0 {
p2.Paths[i].Allocation = 0.0
} else {
p2.Paths[i].Allocation = 1.0
}
i++
}
}
}
sort.Slice(p2.Paths, func(a, b int) bool {
pa := &p2.Paths[a]
pb := &p2.Paths[b]
if pb.Allocation < pa.Allocation { // invert order, put highest allocation paths first
return true
}
if pa.Allocation == pb.Allocation {
return pa.LastReceive < pb.LastReceive // then sort by most recent activity
}
return false
})
p2.Clock = TimeMs()
peers = append(peers, p2)
@ -754,10 +660,10 @@ func (n *Node) pathCheck(ztAddress Address, af int, ip net.IP, port int) bool {
return true
}
func (n *Node) pathLookup(ztAddress Address) (net.IP, int) {
func (n *Node) pathLookup(id *Identity) (net.IP, int) {
n.localConfigLock.RLock()
defer n.localConfigLock.RUnlock()
virt := n.localConfig.Virtual[ztAddress]
virt := n.localConfig.Virtual[id.address]
if len(virt.Try) > 0 {
idx := rand.Int() % len(virt.Try)
return virt.Try[idx].IP, virt.Try[idx].Port
@ -831,9 +737,6 @@ func (n *Node) handleTrace(traceMessage string) {
func (n *Node) handleUserMessage(originAddress, messageTypeID uint64, data []byte) {
}
func (n *Node) handleRemoteTrace(originAddress uint64, dictData []byte) {
}
//////////////////////////////////////////////////////////////////////////////
// These are callbacks called by the core and GoGlue stuff to talk to the
@ -860,7 +763,7 @@ func goPathCheckFunc(gn unsafe.Pointer, ztAddress C.uint64_t, af C.int, ip unsaf
}
//export goPathLookupFunc
func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, _ int, familyP, ipP, portP unsafe.Pointer) C.int {
func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, desiredFamily int, identity, familyP, ipP, portP unsafe.Pointer) C.int {
nodesByUserPtrLock.RLock()
node := nodesByUserPtr[uintptr(gn)]
nodesByUserPtrLock.RUnlock()
@ -868,7 +771,11 @@ func goPathLookupFunc(gn unsafe.Pointer, ztAddress C.uint64_t, _ int, familyP, i
return 0
}
ip, port := node.pathLookup(Address(ztAddress))
id, err := newIdentityFromCIdentity(identity)
if err != nil {
return 0
}
ip, port := node.pathLookup(id)
if len(ip) > 0 && port > 0 && port <= 65535 {
ip4 := ip.To4()
if len(ip4) == 4 {
@ -922,38 +829,6 @@ func goStateObjectGetFunc(gn unsafe.Pointer, objType C.int, id, data unsafe.Poin
return -1
}
//export goDNSResolverFunc
func goDNSResolverFunc(gn unsafe.Pointer, dnsRecordTypes unsafe.Pointer, numDNSRecordTypes C.int, name unsafe.Pointer, requestID C.uintptr_t) {
go func() {
nodesByUserPtrLock.RLock()
node := nodesByUserPtr[uintptr(gn)]
nodesByUserPtrLock.RUnlock()
if node == nil {
return
}
recordTypes := C.GoBytes(dnsRecordTypes, numDNSRecordTypes)
recordName := C.GoString((*C.char)(name))
recordNameCStrCopy := C.CString(recordName)
for _, rt := range recordTypes {
switch rt {
case C.ZT_DNS_RECORD_TXT:
recs, _ := net.LookupTXT(recordName)
for _, rec := range recs {
if len(rec) > 0 {
rnCS := C.CString(rec)
C.ZT_Node_processDNSResult(unsafe.Pointer(node.zn), nil, requestID, recordNameCStrCopy, C.ZT_DNS_RECORD_TXT, unsafe.Pointer(rnCS), C.uint(len(rec)), 0)
C.free(unsafe.Pointer(rnCS))
}
}
}
}
C.ZT_Node_processDNSResult(unsafe.Pointer(node.zn), nil, requestID, recordNameCStrCopy, C.ZT_DNS_RECORD__END_OF_RESULTS, nil, 0, 0)
C.free(unsafe.Pointer(recordNameCStrCopy))
}()
}
//export goVirtualNetworkConfigFunc
func goVirtualNetworkConfigFunc(gn, _ unsafe.Pointer, nwid C.uint64_t, op C.int, conf unsafe.Pointer) {
go func() {
@ -1032,9 +907,6 @@ func goZtEvent(gn unsafe.Pointer, eventType C.int, data unsafe.Pointer) {
case C.ZT_EVENT_USER_MESSAGE:
um := (*C.ZT_UserMessage)(data)
node.handleUserMessage(uint64(um.origin), uint64(um.typeId), C.GoBytes(um.data, C.int(um.length)))
case C.ZT_EVENT_REMOTE_TRACE:
rt := (*C.ZT_RemoteTrace)(data)
node.handleRemoteTrace(uint64(rt.origin), C.GoBytes(unsafe.Pointer(rt.data), C.int(rt.len)))
}
}()
}

@ -22,13 +22,4 @@ type Path struct {
LastSend int64 `json:"lastSend"`
LastReceive int64 `json:"lastReceive"`
TrustedPathID uint64 `json:"trustedPathID"`
Latency float32 `json:"latency"`
PacketDelayVariance float32 `json:"packetDelayVariance"`
ThroughputDisturbCoeff float32 `json:"throughputDisturbCoeff"`
PacketErrorRatio float32 `json:"packetErrorRatio"`
PacketLossRatio float32 `json:"packetLossRatio"`
Stability float32 `json:"stability"`
Throughput uint64 `json:"throughput"`
MaxThroughput uint64 `json:"maxThroughput"`
Allocation float32 `json:"allocation"`
}

@ -1,20 +1,8 @@
/*
* 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.
*/
/****/
package zerotier
// Root describes a root server used to find and establish communication with other nodes.
// Root is a root server with one or more permanent IPs.
type Root struct {
Name string `json:"name"`
Locator *Locator `json:"locator,omitempty"`
Identity Identity
DNSName string
PhysicalAddresses []InetAddress
}

@ -1,13 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// System calls for 386, Windows are implemented in runtime/syscall_windows.goc
//
TEXT ·getprocaddress(SB), 7, $0-16
JMP syscall·getprocaddress(SB)
TEXT ·loadlibrary(SB), 7, $0-12
JMP syscall·loadlibrary(SB)

@ -1,13 +0,0 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// System calls for amd64, Windows are implemented in runtime/syscall_windows.goc
//
TEXT ·getprocaddress(SB), 7, $0-32
JMP syscall·getprocaddress(SB)
TEXT ·loadlibrary(SB), 7, $0-24
JMP syscall·loadlibrary(SB)

@ -1,11 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
TEXT ·getprocaddress(SB),NOSPLIT,$0
B syscall·getprocaddress(SB)
TEXT ·loadlibrary(SB),NOSPLIT,$0
B syscall·loadlibrary(SB)

@ -11,6 +11,18 @@ import (
"unsafe"
)
// We need to use LoadLibrary and GetProcAddress from the Go runtime, because
// the these symbols are loaded by the system linker and are required to
// dynamically load additional symbols. Note that in the Go runtime, these
// return syscall.Handle and syscall.Errno, but these are the same, in fact,
// as windows.Handle and windows.Errno, and we intend to keep these the same.
//go:linkname syscall_loadlibrary syscall.loadlibrary
func syscall_loadlibrary(filename *uint16) (handle Handle, err Errno)
//go:linkname syscall_getprocaddress syscall.getprocaddress
func syscall_getprocaddress(handle Handle, procname *uint8) (proc uintptr, err Errno)
// DLLError describes reasons for DLL load failures.
type DLLError struct {
Err error
@ -20,10 +32,6 @@ type DLLError struct {
func (e *DLLError) Error() string { return e.Msg }
// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
// A DLL implements access to a single DLL.
type DLL struct {
Name string
@ -40,7 +48,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
if err != nil {
return nil, err
}
h, e := loadlibrary(namep)
h, e := syscall_loadlibrary(namep)
if e != 0 {
return nil, &DLLError{
Err: e,
@ -50,7 +58,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
}
d := &DLL{
Name: name,
Handle: Handle(h),
Handle: h,
}
return d, nil
}
@ -71,7 +79,7 @@ func (d *DLL) FindProc(name string) (proc *Proc, err error) {
if err != nil {
return nil, err
}
a, e := getprocaddress(uintptr(d.Handle), namep)
a, e := syscall_getprocaddress(d.Handle, namep)
if e != 0 {
return nil, &DLLError{
Err: e,

@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build generate
// +build !go1.12
package windows
//go:generate ./mkerrors.bash zerrors_windows.go
// This file is here to allow bodyless functions with go:linkname for Go 1.11
// and earlier (see https://golang.org/issue/23311).

@ -7,14 +7,13 @@
set -e
shopt -s nullglob
[[ $# -eq 1 ]] || { echo "Usage: $0 OUTPUT_FILE.go" >&2; exit 1; }
winerror="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/winerror.h | sort -Vr | head -n 1)"
[[ -n $winerror ]] || { echo "Unable to find winerror.h" >&2; exit 1; }
declare -A errors
{
echo "// Code generated by 'go generate'; DO NOT EDIT."
echo "// Code generated by 'mkerrors.bash'; DO NOT EDIT."
echo
echo "package windows"
echo "import \"syscall\""
@ -61,4 +60,4 @@ declare -A errors
done < "$winerror"
echo ")"
} | gofmt > "$1"
} | gofmt > "zerrors_windows.go"

@ -0,0 +1,27 @@
#!/bin/bash
# Copyright 2019 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
set -e
shopt -s nullglob
knownfolders="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/um/KnownFolders.h | sort -Vr | head -n 1)"
[[ -n $knownfolders ]] || { echo "Unable to find KnownFolders.h" >&2; exit 1; }
{
echo "// Code generated by 'mkknownfolderids.bash'; DO NOT EDIT."
echo
echo "package windows"
echo "type KNOWNFOLDERID GUID"
echo "var ("
while read -r line; do
[[ $line =~ DEFINE_KNOWN_FOLDER\((FOLDERID_[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+)\) ]] || continue
printf "%s = &KNOWNFOLDERID{0x%08x, 0x%04x, 0x%04x, [8]byte{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}\n" \
"${BASH_REMATCH[1]}" $(( "${BASH_REMATCH[2]}" )) $(( "${BASH_REMATCH[3]}" )) $(( "${BASH_REMATCH[4]}" )) \
$(( "${BASH_REMATCH[5]}" )) $(( "${BASH_REMATCH[6]}" )) $(( "${BASH_REMATCH[7]}" )) $(( "${BASH_REMATCH[8]}" )) \
$(( "${BASH_REMATCH[9]}" )) $(( "${BASH_REMATCH[10]}" )) $(( "${BASH_REMATCH[11]}" )) $(( "${BASH_REMATCH[12]}" ))
done < "$knownfolders"
echo ")"
} | gofmt > "zknownfolderids_windows.go"

@ -6,4 +6,4 @@
package windows
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go

@ -9,14 +9,6 @@ import (
"unsafe"
)
const (
STANDARD_RIGHTS_REQUIRED = 0xf0000
STANDARD_RIGHTS_READ = 0x20000
STANDARD_RIGHTS_WRITE = 0x20000
STANDARD_RIGHTS_EXECUTE = 0x20000
STANDARD_RIGHTS_ALL = 0x1F0000
)
const (
NameUnknown = 0
NameFullyQualifiedDN = 1
@ -235,16 +227,15 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
}
}
// String converts SID to a string format
// suitable for display, storage, or transmission.
func (sid *SID) String() (string, error) {
// String converts SID to a string format suitable for display, storage, or transmission.
func (sid *SID) String() string {
var s *uint16
e := ConvertSidToStringSid(sid, &s)
if e != nil {
return "", e
return ""
}
defer LocalFree((Handle)(unsafe.Pointer(s)))
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:])
}
// Len returns the length, in bytes, of a valid security identifier SID.
@ -603,12 +594,22 @@ type Tokenprimarygroup struct {
type Tokengroups struct {
GroupCount uint32
Groups [1]SIDAndAttributes
Groups [1]SIDAndAttributes // Use AllGroups() for iterating.
}
// AllGroups returns a slice that can be used to iterate over the groups in g.
func (g *Tokengroups) AllGroups() []SIDAndAttributes {
return (*[(1 << 28) - 1]SIDAndAttributes)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount]
}
type Tokenprivileges struct {
PrivilegeCount uint32
Privileges [1]LUIDAndAttributes
Privileges [1]LUIDAndAttributes // Use AllPrivileges() for iterating.
}
// AllPrivileges returns a slice that can be used to iterate over the privileges in p.
func (p *Tokenprivileges) AllPrivileges() []LUIDAndAttributes {
return (*[(1 << 27) - 1]LUIDAndAttributes)(unsafe.Pointer(&p.Privileges[0]))[:p.PrivilegeCount:p.PrivilegeCount]
}
type Tokenmandatorylabel struct {
@ -634,6 +635,8 @@ func (tml *Tokenmandatorylabel) Size() uint32 {
//sys DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes *SecurityAttributes, impersonationLevel uint32, tokenType uint32, newToken *Token) (err error) = advapi32.DuplicateTokenEx
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
//sys getWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetWindowsDirectoryW
//sys getSystemWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemWindowsDirectoryW
// An access token contains the security information for a logon session.
// The system creates an access token when a user logs on, and every
@ -644,21 +647,16 @@ func (tml *Tokenmandatorylabel) Size() uint32 {
// system-related operations on the local computer.
type Token Handle
// OpenCurrentProcessToken opens the access token
// associated with current process. It is a real
// token that needs to be closed, unlike
// GetCurrentProcessToken.
// OpenCurrentProcessToken opens an access token associated with current
// process with TOKEN_QUERY access. It is a real token that needs to be closed.
//
// Deprecated: Explicitly call OpenProcessToken(CurrentProcess(), ...)
// with the desired access instead, or use GetCurrentProcessToken for a
// TOKEN_QUERY token.
func OpenCurrentProcessToken() (Token, error) {
p, e := GetCurrentProcess()
if e != nil {
return 0, e
}
var t Token
e = OpenProcessToken(p, TOKEN_QUERY, &t)
if e != nil {
return 0, e
}
return t, nil
var token Token
err := OpenProcessToken(CurrentProcess(), TOKEN_QUERY, &token)
return token, err
}
// GetCurrentProcessToken returns the access token associated with
@ -775,8 +773,8 @@ func (token Token) GetLinkedToken() (Token, error) {
return linkedToken, nil
}
// GetSystemDirectory retrieves path to current location of the system
// directory, which is typically, though not always, C:\Windows\System32.
// GetSystemDirectory retrieves the path to current location of the system
// directory, which is typically, though not always, `C:\Windows\System32`.
func GetSystemDirectory() (string, error) {
n := uint32(MAX_PATH)
for {
@ -792,6 +790,42 @@ func GetSystemDirectory() (string, error) {
}
}
// GetWindowsDirectory retrieves the path to current location of the Windows
// directory, which is typically, though not always, `C:\Windows`. This may
// be a private user directory in the case that the application is running
// under a terminal server.
func GetWindowsDirectory() (string, error) {
n := uint32(MAX_PATH)
for {
b := make([]uint16, n)
l, e := getWindowsDirectory(&b[0], n)
if e != nil {
return "", e
}
if l <= n {
return UTF16ToString(b[:l]), nil
}
n = l
}
}
// GetSystemWindowsDirectory retrieves the path to current location of the
// Windows directory, which is typically, though not always, `C:\Windows`.
func GetSystemWindowsDirectory() (string, error) {
n := uint32(MAX_PATH)
for {
b := make([]uint16, n)
l, e := getSystemWindowsDirectory(&b[0], n)
if e != nil {
return "", e
}
if l <= n {
return UTF16ToString(b[:l]), nil
}
n = l
}
}
// IsMember reports whether the access token t is a member of the provided SID.
func (t Token) IsMember(sid *SID) (bool, error) {
var b int32
@ -842,3 +876,521 @@ type WTS_SESSION_INFO struct {
//sys WTSQueryUserToken(session uint32, token *Token) (err error) = wtsapi32.WTSQueryUserToken
//sys WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessions **WTS_SESSION_INFO, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW
//sys WTSFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory
type ACL struct {
aclRevision byte
sbz1 byte
aclSize uint16
aceCount uint16
sbz2 uint16
}
type SECURITY_DESCRIPTOR struct {
revision byte
sbz1 byte
control SECURITY_DESCRIPTOR_CONTROL
owner *SID
group *SID
sacl *ACL
dacl *ACL
}
type SecurityAttributes struct {
Length uint32
SecurityDescriptor *SECURITY_DESCRIPTOR
InheritHandle uint32
}
type SE_OBJECT_TYPE uint32
// Constants for type SE_OBJECT_TYPE
const (
SE_UNKNOWN_OBJECT_TYPE = 0
SE_FILE_OBJECT = 1
SE_SERVICE = 2
SE_PRINTER = 3
SE_REGISTRY_KEY = 4
SE_LMSHARE = 5
SE_KERNEL_OBJECT = 6
SE_WINDOW_OBJECT = 7
SE_DS_OBJECT = 8
SE_DS_OBJECT_ALL = 9
SE_PROVIDER_DEFINED_OBJECT = 10
SE_WMIGUID_OBJECT = 11
SE_REGISTRY_WOW64_32KEY = 12
SE_REGISTRY_WOW64_64KEY = 13
)
type SECURITY_INFORMATION uint32
// Constants for type SECURITY_INFORMATION
const (
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
LABEL_SECURITY_INFORMATION = 0x00000010
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
SCOPE_SECURITY_INFORMATION = 0x00000040
BACKUP_SECURITY_INFORMATION = 0x00010000
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
)
type SECURITY_DESCRIPTOR_CONTROL uint16
// Constants for type SECURITY_DESCRIPTOR_CONTROL
const (
SE_OWNER_DEFAULTED = 0x0001
SE_GROUP_DEFAULTED = 0x0002
SE_DACL_PRESENT = 0x0004
SE_DACL_DEFAULTED = 0x0008
SE_SACL_PRESENT = 0x0010
SE_SACL_DEFAULTED = 0x0020
SE_DACL_AUTO_INHERIT_REQ = 0x0100
SE_SACL_AUTO_INHERIT_REQ = 0x0200
SE_DACL_AUTO_INHERITED = 0x0400
SE_SACL_AUTO_INHERITED = 0x0800
SE_DACL_PROTECTED = 0x1000
SE_SACL_PROTECTED = 0x2000
SE_RM_CONTROL_VALID = 0x4000
SE_SELF_RELATIVE = 0x8000
)
type ACCESS_MASK uint32
// Constants for type ACCESS_MASK
const (
DELETE = 0x00010000
READ_CONTROL = 0x00020000
WRITE_DAC = 0x00040000
WRITE_OWNER = 0x00080000
SYNCHRONIZE = 0x00100000
STANDARD_RIGHTS_REQUIRED = 0x000F0000
STANDARD_RIGHTS_READ = READ_CONTROL
STANDARD_RIGHTS_WRITE = READ_CONTROL
STANDARD_RIGHTS_EXECUTE = READ_CONTROL
STANDARD_RIGHTS_ALL = 0x001F0000
SPECIFIC_RIGHTS_ALL = 0x0000FFFF
ACCESS_SYSTEM_SECURITY = 0x01000000
MAXIMUM_ALLOWED = 0x02000000
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
GENERIC_EXECUTE = 0x20000000
GENERIC_ALL = 0x10000000
)
type ACCESS_MODE uint32
// Constants for type ACCESS_MODE
const (
NOT_USED_ACCESS = 0
GRANT_ACCESS = 1
SET_ACCESS = 2
DENY_ACCESS = 3
REVOKE_ACCESS = 4
SET_AUDIT_SUCCESS = 5
SET_AUDIT_FAILURE = 6
)
// Constants for AceFlags and Inheritance fields
const (
NO_INHERITANCE = 0x0
SUB_OBJECTS_ONLY_INHERIT = 0x1
SUB_CONTAINERS_ONLY_INHERIT = 0x2
SUB_CONTAINERS_AND_OBJECTS_INHERIT = 0x3
INHERIT_NO_PROPAGATE = 0x4
INHERIT_ONLY = 0x8
INHERITED_ACCESS_ENTRY = 0x10
INHERITED_PARENT = 0x10000000
INHERITED_GRANDPARENT = 0x20000000
OBJECT_INHERIT_ACE = 0x1
CONTAINER_INHERIT_ACE = 0x2
NO_PROPAGATE_INHERIT_ACE = 0x4
INHERIT_ONLY_ACE = 0x8
INHERITED_ACE = 0x10
VALID_INHERIT_FLAGS = 0x1F
)
type MULTIPLE_TRUSTEE_OPERATION uint32
// Constants for MULTIPLE_TRUSTEE_OPERATION
const (
NO_MULTIPLE_TRUSTEE = 0
TRUSTEE_IS_IMPERSONATE = 1
)
type TRUSTEE_FORM uint32
// Constants for TRUSTEE_FORM
const (
TRUSTEE_IS_SID = 0
TRUSTEE_IS_NAME = 1
TRUSTEE_BAD_FORM = 2
TRUSTEE_IS_OBJECTS_AND_SID = 3
TRUSTEE_IS_OBJECTS_AND_NAME = 4
)
type TRUSTEE_TYPE uint32
// Constants for TRUSTEE_TYPE
const (
TRUSTEE_IS_UNKNOWN = 0
TRUSTEE_IS_USER = 1
TRUSTEE_IS_GROUP = 2
TRUSTEE_IS_DOMAIN = 3
TRUSTEE_IS_ALIAS = 4
TRUSTEE_IS_WELL_KNOWN_GROUP = 5
TRUSTEE_IS_DELETED = 6
TRUSTEE_IS_INVALID = 7
TRUSTEE_IS_COMPUTER = 8
)
// Constants for ObjectsPresent field
const (
ACE_OBJECT_TYPE_PRESENT = 0x1
ACE_INHERITED_OBJECT_TYPE_PRESENT = 0x2
)
type EXPLICIT_ACCESS struct {
AccessPermissions ACCESS_MASK
AccessMode ACCESS_MODE
Inheritance uint32
Trustee TRUSTEE
}
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
type TrusteeValue uintptr
func TrusteeValueFromString(str string) TrusteeValue {
return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str)))
}
func TrusteeValueFromSID(sid *SID) TrusteeValue {
return TrusteeValue(unsafe.Pointer(sid))
}
func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue {
return TrusteeValue(unsafe.Pointer(objectsAndSid))
}
func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue {
return TrusteeValue(unsafe.Pointer(objectsAndName))
}
type TRUSTEE struct {
MultipleTrustee *TRUSTEE
MultipleTrusteeOperation MULTIPLE_TRUSTEE_OPERATION
TrusteeForm TRUSTEE_FORM
TrusteeType TRUSTEE_TYPE
TrusteeValue TrusteeValue
}
type OBJECTS_AND_SID struct {
ObjectsPresent uint32
ObjectTypeGuid GUID
InheritedObjectTypeGuid GUID
Sid *SID
}
type OBJECTS_AND_NAME struct {
ObjectsPresent uint32
ObjectType SE_OBJECT_TYPE
ObjectTypeName *uint16
InheritedObjectTypeName *uint16
Name *uint16
}
//sys getSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetSecurityInfo
//sys SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) = advapi32.SetSecurityInfo
//sys getNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetNamedSecurityInfoW
//sys SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetNamedSecurityInfoW
//sys buildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, countAccessEntries uint32, accessEntries *EXPLICIT_ACCESS, countAuditEntries uint32, auditEntries *EXPLICIT_ACCESS, oldSecurityDescriptor *SECURITY_DESCRIPTOR, sizeNewSecurityDescriptor *uint32, newSecurityDescriptor **SECURITY_DESCRIPTOR) (ret error) = advapi32.BuildSecurityDescriptorW
//sys initializeSecurityDescriptor(absoluteSD *SECURITY_DESCRIPTOR, revision uint32) (err error) = advapi32.InitializeSecurityDescriptor
//sys getSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, control *SECURITY_DESCRIPTOR_CONTROL, revision *uint32) (err error) = advapi32.GetSecurityDescriptorControl
//sys getSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent *bool, dacl **ACL, daclDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorDacl
//sys getSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent *bool, sacl **ACL, saclDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorSacl
//sys getSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner **SID, ownerDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorOwner
//sys getSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group **SID, groupDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorGroup
//sys getSecurityDescriptorLength(sd *SECURITY_DESCRIPTOR) (len uint32) = advapi32.GetSecurityDescriptorLength
//sys getSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) (ret error) [failretval!=0] = advapi32.GetSecurityDescriptorRMControl
//sys isValidSecurityDescriptor(sd *SECURITY_DESCRIPTOR) (isValid bool) = advapi32.IsValidSecurityDescriptor
//sys setSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, controlBitsOfInterest SECURITY_DESCRIPTOR_CONTROL, controlBitsToSet SECURITY_DESCRIPTOR_CONTROL) (err error) = advapi32.SetSecurityDescriptorControl
//sys setSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent bool, dacl *ACL, daclDefaulted bool) (err error) = advapi32.SetSecurityDescriptorDacl
//sys setSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent bool, sacl *ACL, saclDefaulted bool) (err error) = advapi32.SetSecurityDescriptorSacl
//sys setSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner *SID, ownerDefaulted bool) (err error) = advapi32.SetSecurityDescriptorOwner
//sys setSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group *SID, groupDefaulted bool) (err error) = advapi32.SetSecurityDescriptorGroup
//sys setSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) = advapi32.SetSecurityDescriptorRMControl
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd **SECURITY_DESCRIPTOR, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *SECURITY_DESCRIPTOR, revision uint32, securityInformation SECURITY_INFORMATION, str **uint16, strLen *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
//sys makeAbsoluteSD(selfRelativeSD *SECURITY_DESCRIPTOR, absoluteSD *SECURITY_DESCRIPTOR, absoluteSDSize *uint32, dacl *ACL, daclSize *uint32, sacl *ACL, saclSize *uint32, owner *SID, ownerSize *uint32, group *SID, groupSize *uint32) (err error) = advapi32.MakeAbsoluteSD
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
//sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW
// Control returns the security descriptor control bits.
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
err = getSecurityDescriptorControl(sd, &control, &revision)
return
}
// SetControl sets the security descriptor control bits.
func (sd *SECURITY_DESCRIPTOR) SetControl(controlBitsOfInterest SECURITY_DESCRIPTOR_CONTROL, controlBitsToSet SECURITY_DESCRIPTOR_CONTROL) error {
return setSecurityDescriptorControl(sd, controlBitsOfInterest, controlBitsToSet)
}
// RMControl returns the security descriptor resource manager control bits.
func (sd *SECURITY_DESCRIPTOR) RMControl() (control uint8, err error) {
err = getSecurityDescriptorRMControl(sd, &control)
return
}
// SetRMControl sets the security descriptor resource manager control bits.
func (sd *SECURITY_DESCRIPTOR) SetRMControl(rmControl uint8) {
setSecurityDescriptorRMControl(sd, &rmControl)
}
// DACL returns the security descriptor DACL and whether it was defaulted. The dacl return value may be nil
// if a DACL exists but is an "empty DACL", meaning fully permissive. If the DACL does not exist, err returns
// ERROR_OBJECT_NOT_FOUND.
func (sd *SECURITY_DESCRIPTOR) DACL() (dacl *ACL, defaulted bool, err error) {
var present bool
err = getSecurityDescriptorDacl(sd, &present, &dacl, &defaulted)
if !present {
err = ERROR_OBJECT_NOT_FOUND
}
return
}
// SetDACL sets the absolute security descriptor DACL.
func (absoluteSD *SECURITY_DESCRIPTOR) SetDACL(dacl *ACL, present, defaulted bool) error {
return setSecurityDescriptorDacl(absoluteSD, present, dacl, defaulted)
}
// SACL returns the security descriptor SACL and whether it was defaulted. The sacl return value may be nil
// if a SACL exists but is an "empty SACL", meaning fully permissive. If the SACL does not exist, err returns
// ERROR_OBJECT_NOT_FOUND.
func (sd *SECURITY_DESCRIPTOR) SACL() (sacl *ACL, defaulted bool, err error) {
var present bool
err = getSecurityDescriptorSacl(sd, &present, &sacl, &defaulted)
if !present {
err = ERROR_OBJECT_NOT_FOUND
}
return
}
// SetSACL sets the absolute security descriptor SACL.
func (absoluteSD *SECURITY_DESCRIPTOR) SetSACL(sacl *ACL, present, defaulted bool) error {
return setSecurityDescriptorSacl(absoluteSD, present, sacl, defaulted)
}
// Owner returns the security descriptor owner and whether it was defaulted.
func (sd *SECURITY_DESCRIPTOR) Owner() (owner *SID, defaulted bool, err error) {
err = getSecurityDescriptorOwner(sd, &owner, &defaulted)
return
}
// SetOwner sets the absolute security descriptor owner.
func (absoluteSD *SECURITY_DESCRIPTOR) SetOwner(owner *SID, defaulted bool) error {
return setSecurityDescriptorOwner(absoluteSD, owner, defaulted)
}
// Group returns the security descriptor group and whether it was defaulted.
func (sd *SECURITY_DESCRIPTOR) Group() (group *SID, defaulted bool, err error) {
err = getSecurityDescriptorGroup(sd, &group, &defaulted)
return
}
// SetGroup sets the absolute security descriptor owner.
func (absoluteSD *SECURITY_DESCRIPTOR) SetGroup(group *SID, defaulted bool) error {
return setSecurityDescriptorGroup(absoluteSD, group, defaulted)
}
// Length returns the length of the security descriptor.
func (sd *SECURITY_DESCRIPTOR) Length() uint32 {
return getSecurityDescriptorLength(sd)
}
// IsValid returns whether the security descriptor is valid.
func (sd *SECURITY_DESCRIPTOR) IsValid() bool {
return isValidSecurityDescriptor(sd)
}
// String returns the SDDL form of the security descriptor, with a function signature that can be
// used with %v formatting directives.
func (sd *SECURITY_DESCRIPTOR) String() string {
var sddl *uint16
err := convertSecurityDescriptorToStringSecurityDescriptor(sd, 1, 0xff, &sddl, nil)
if err != nil {
return ""
}
defer LocalFree(Handle(unsafe.Pointer(sddl)))
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(sddl))[:])
}
// ToAbsolute converts a self-relative security descriptor into an absolute one.
func (selfRelativeSD *SECURITY_DESCRIPTOR) ToAbsolute() (absoluteSD *SECURITY_DESCRIPTOR, err error) {
control, _, err := selfRelativeSD.Control()
if err != nil {
return
}
if control&SE_SELF_RELATIVE == 0 {
err = ERROR_INVALID_PARAMETER
return
}
var absoluteSDSize, daclSize, saclSize, ownerSize, groupSize uint32
err = makeAbsoluteSD(selfRelativeSD, nil, &absoluteSDSize,
nil, &daclSize, nil, &saclSize, nil, &ownerSize, nil, &groupSize)
switch err {
case ERROR_INSUFFICIENT_BUFFER:
case nil:
// makeAbsoluteSD is expected to fail, but it succeeds.
return nil, ERROR_INTERNAL_ERROR
default:
return nil, err
}
if absoluteSDSize > 0 {
absoluteSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, absoluteSDSize)[0]))
}
var (
dacl *ACL
sacl *ACL
owner *SID
group *SID
)
if daclSize > 0 {
dacl = (*ACL)(unsafe.Pointer(&make([]byte, daclSize)[0]))
}
if saclSize > 0 {
sacl = (*ACL)(unsafe.Pointer(&make([]byte, saclSize)[0]))
}
if ownerSize > 0 {
owner = (*SID)(unsafe.Pointer(&make([]byte, ownerSize)[0]))
}
if groupSize > 0 {
group = (*SID)(unsafe.Pointer(&make([]byte, groupSize)[0]))
}
err = makeAbsoluteSD(selfRelativeSD, absoluteSD, &absoluteSDSize,
dacl, &daclSize, sacl, &saclSize, owner, &ownerSize, group, &groupSize)
return
}
// ToSelfRelative converts an absolute security descriptor into a self-relative one.
func (absoluteSD *SECURITY_DESCRIPTOR) ToSelfRelative() (selfRelativeSD *SECURITY_DESCRIPTOR, err error) {
control, _, err := absoluteSD.Control()
if err != nil {
return
}
if control&SE_SELF_RELATIVE != 0 {
err = ERROR_INVALID_PARAMETER
return
}
var selfRelativeSDSize uint32
err = makeSelfRelativeSD(absoluteSD, nil, &selfRelativeSDSize)
switch err {
case ERROR_INSUFFICIENT_BUFFER:
case nil:
// makeSelfRelativeSD is expected to fail, but it succeeds.
return nil, ERROR_INTERNAL_ERROR
default:
return nil, err
}
if selfRelativeSDSize > 0 {
selfRelativeSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, selfRelativeSDSize)[0]))
}
err = makeSelfRelativeSD(absoluteSD, selfRelativeSD, &selfRelativeSDSize)
return
}
func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() *SECURITY_DESCRIPTOR {
sdBytes := make([]byte, selfRelativeSD.Length())
copy(sdBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(selfRelativeSD))[:len(sdBytes)])
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&sdBytes[0]))
}
// SecurityDescriptorFromString converts an SDDL string describing a security descriptor into a
// self-relative security descriptor object allocated on the Go heap.
func SecurityDescriptorFromString(sddl string) (sd *SECURITY_DESCRIPTOR, err error) {
var winHeapSD *SECURITY_DESCRIPTOR
err = convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &winHeapSD, nil)
if err != nil {
return
}
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
}
// GetSecurityInfo queries the security information for a given handle and returns the self-relative security
// descriptor result on the Go heap.
func GetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
var winHeapSD *SECURITY_DESCRIPTOR
err = getSecurityInfo(handle, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
if err != nil {
return
}
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
}
// GetNamedSecurityInfo queries the security information for a given named object and returns the self-relative security
// descriptor result on the Go heap.
func GetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
var winHeapSD *SECURITY_DESCRIPTOR
err = getNamedSecurityInfo(objectName, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
if err != nil {
return
}
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
}
// BuildSecurityDescriptor makes a new security descriptor using the input trustees, explicit access lists, and
// prior security descriptor to be merged, any of which can be nil, returning the self-relative security descriptor
// result on the Go heap.
func BuildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, accessEntries []EXPLICIT_ACCESS, auditEntries []EXPLICIT_ACCESS, mergedSecurityDescriptor *SECURITY_DESCRIPTOR) (sd *SECURITY_DESCRIPTOR, err error) {
var winHeapSD *SECURITY_DESCRIPTOR
var winHeapSDSize uint32
var firstAccessEntry *EXPLICIT_ACCESS
if len(accessEntries) > 0 {
firstAccessEntry = &accessEntries[0]
}
var firstAuditEntry *EXPLICIT_ACCESS
if len(auditEntries) > 0 {
firstAuditEntry = &auditEntries[0]
}
err = buildSecurityDescriptor(owner, group, uint32(len(accessEntries)), firstAccessEntry, uint32(len(auditEntries)), firstAuditEntry, mergedSecurityDescriptor, &winHeapSDSize, &winHeapSD)
if err != nil {
return
}
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
}
// NewSecurityDescriptor creates and initializes a new absolute security descriptor.
func NewSecurityDescriptor() (absoluteSD *SECURITY_DESCRIPTOR, err error) {
absoluteSD = &SECURITY_DESCRIPTOR{}
err = initializeSecurityDescriptor(absoluteSD, 1)
return
}
// ACLFromEntries returns a new ACL on the Go heap containing a list of explicit entries as well as those of another ACL.
// Both explicitEntries and mergedACL are optional and can be nil.
func ACLFromEntries(explicitEntries []EXPLICIT_ACCESS, mergedACL *ACL) (acl *ACL, err error) {
var firstExplicitEntry *EXPLICIT_ACCESS
if len(explicitEntries) > 0 {
firstExplicitEntry = &explicitEntries[0]
}
var winHeapACL *ACL
err = setEntriesInAcl(uint32(len(explicitEntries)), firstExplicitEntry, mergedACL, &winHeapACL)
if err != nil {
return
}
defer LocalFree(Handle(unsafe.Pointer(winHeapACL)))
aclBytes := make([]byte, winHeapACL.aclSize)
copy(aclBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(winHeapACL))[:len(aclBytes)])
return (*ACL)(unsafe.Pointer(&aclBytes[0])), nil
}

@ -159,6 +159,10 @@ type SERVICE_DESCRIPTION struct {
Description *uint16
}
type SERVICE_DELAYED_AUTO_START_INFO struct {
IsDelayedAutoStartUp uint32
}
type SERVICE_STATUS_PROCESS struct {
ServiceType uint32
CurrentState uint32
@ -200,12 +204,19 @@ type SC_ACTION struct {
Delay uint32
}
type QUERY_SERVICE_LOCK_STATUS struct {
IsLocked uint32
LockOwner *uint16
LockDuration uint32
}
//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
//sys DeleteService(service Handle) (err error) = advapi32.DeleteService
//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW
//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus
//sys QueryServiceLockStatus(mgr Handle, lockStatus *QUERY_SERVICE_LOCK_STATUS, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceLockStatusW
//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService
//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW
//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus

@ -10,6 +10,7 @@ import (
errorspkg "errors"
"sync"
"syscall"
"time"
"unicode/utf16"
"unsafe"
)
@ -56,6 +57,10 @@ const (
FILE_VOLUME_IS_COMPRESSED = 0x00008000
FILE_VOLUME_QUOTAS = 0x00000020
// Flags for LockFileEx.
LOCKFILE_FAIL_IMMEDIATELY = 0x00000001
LOCKFILE_EXCLUSIVE_LOCK = 0x00000002
// Return values of SleepEx and other APC functions
STATUS_USER_APC = 0x000000C0
WAIT_IO_COMPLETION = STATUS_USER_APC
@ -135,6 +140,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) = LoadLibraryExW
//sys FreeLibrary(handle Handle) (err error)
//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
//sys GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
//sys GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) = kernel32.GetModuleHandleExW
//sys GetVersion() (ver uint32, err error)
//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
//sys ExitProcess(exitcode uint32)
@ -159,6 +166,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys DeleteFile(path *uint16) (err error) = DeleteFileW
//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
//sys LockFileEx(file Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *Overlapped) (err error)
//sys UnlockFileEx(file Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *Overlapped) (err error)
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys SetEndOfFile(handle Handle) (err error)
@ -171,13 +180,12 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys CancelIo(s Handle) (err error)
//sys CancelIoEx(s Handle, o *Overlapped) (err error)
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error)
//sys ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) = shell32.ShellExecuteW
//sys OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) (handle Handle, err error)
//sys ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) [failretval<=32] = shell32.ShellExecuteW
//sys shGetKnownFolderPath(id *KNOWNFOLDERID, flags uint32, token Token, path **uint16) (ret error) = shell32.SHGetKnownFolderPath
//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
//sys GetCurrentProcess() (pseudoHandle Handle, err error)
//sys GetCurrentThread() (pseudoHandle Handle, err error)
//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
@ -194,6 +202,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW
//sys CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock
//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
//sys getTickCount64() (ms uint64) = kernel32.GetTickCount64
//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
@ -232,7 +241,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
//sys GetCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
//sys SetConsoleMode(console Handle, mode uint32) (err error) = kernel32.SetConsoleMode
//sys GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) = kernel32.GetConsoleScreenBufferInfo
@ -241,6 +250,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW
//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW
//sys Thread32First(snapshot Handle, threadEntry *ThreadEntry32) (err error)
//sys Thread32Next(snapshot Handle, threadEntry *ThreadEntry32) (err error)
//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error)
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW
@ -252,6 +263,10 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys SetEvent(event Handle) (err error) = kernel32.SetEvent
//sys ResetEvent(event Handle) (err error) = kernel32.ResetEvent
//sys PulseEvent(event Handle) (err error) = kernel32.PulseEvent
//sys CreateMutex(mutexAttrs *SecurityAttributes, initialOwner bool, name *uint16) (handle Handle, err error) = kernel32.CreateMutexW
//sys CreateMutexEx(mutexAttrs *SecurityAttributes, name *uint16, flags uint32, desiredAccess uint32) (handle Handle, err error) = kernel32.CreateMutexExW
//sys OpenMutex(desiredAccess uint32, inheritHandle bool, name *uint16) (handle Handle, err error) = kernel32.OpenMutexW
//sys ReleaseMutex(mutex Handle) (err error) = kernel32.ReleaseMutex
//sys SleepEx(milliseconds uint32, alertable bool) (ret uint32) = kernel32.SleepEx
//sys CreateJobObject(jobAttr *SecurityAttributes, name *uint16) (handle Handle, err error) = kernel32.CreateJobObjectW
//sys AssignProcessToJobObject(job Handle, process Handle) (err error) = kernel32.AssignProcessToJobObject
@ -261,6 +276,10 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys SetPriorityClass(process Handle, priorityClass uint32) (err error) = kernel32.SetPriorityClass
//sys GetPriorityClass(process Handle) (ret uint32, err error) = kernel32.GetPriorityClass
//sys SetInformationJobObject(job Handle, JobObjectInformationClass uint32, JobObjectInformation uintptr, JobObjectInformationLength uint32) (ret int, err error)
//sys GenerateConsoleCtrlEvent(ctrlEvent uint32, processGroupID uint32) (err error)
//sys GetProcessId(process Handle) (id uint32, err error)
//sys OpenThread(desiredAccess uint32, inheritHandle bool, threadId uint32) (handle Handle, err error)
//sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost
// Volume Management Functions
//sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW
@ -271,6 +290,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys FindNextVolumeMountPoint(findVolumeMountPoint Handle, volumeMountPoint *uint16, bufferLength uint32) (err error) = FindNextVolumeMountPointW
//sys FindVolumeClose(findVolume Handle) (err error)
//sys FindVolumeMountPointClose(findVolumeMountPoint Handle) (err error)
//sys GetDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailableToCaller *uint64, totalNumberOfBytes *uint64, totalNumberOfFreeBytes *uint64) (err error) = GetDiskFreeSpaceExW
//sys GetDriveType(rootPathName *uint16) (driveType uint32) = GetDriveTypeW
//sys GetLogicalDrives() (drivesBitMask uint32, err error) [failretval==0]
//sys GetLogicalDriveStrings(bufferLength uint32, buffer *uint16) (n uint32, err error) [failretval==0] = GetLogicalDriveStringsW
@ -283,9 +303,54 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys SetVolumeLabel(rootPathName *uint16, volumeName *uint16) (err error) = SetVolumeLabelW
//sys SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err error) = SetVolumeMountPointW
//sys MessageBox(hwnd Handle, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) [failretval==0] = user32.MessageBoxW
//sys ExitWindowsEx(flags uint32, reason uint32) (err error) = user32.ExitWindowsEx
//sys InitiateSystemShutdownEx(machineName *uint16, message *uint16, timeout uint32, forceAppsClosed bool, rebootAfterShutdown bool, reason uint32) (err error) = advapi32.InitiateSystemShutdownExW
//sys SetProcessShutdownParameters(level uint32, flags uint32) (err error) = kernel32.SetProcessShutdownParameters
//sys GetProcessShutdownParameters(level *uint32, flags *uint32) (err error) = kernel32.GetProcessShutdownParameters
//sys clsidFromString(lpsz *uint16, pclsid *GUID) (ret error) = ole32.CLSIDFromString
//sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int32) (chars int32) = ole32.StringFromGUID2
//sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
//sys CoTaskMemFree(address unsafe.Pointer) = ole32.CoTaskMemFree
//sys rtlGetVersion(info *OsVersionInfoEx) (ret error) = ntdll.RtlGetVersion
//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers
//sys getProcessPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetProcessPreferredUILanguages
//sys getThreadPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetThreadPreferredUILanguages
//sys getUserPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetUserPreferredUILanguages
//sys getSystemPreferredUILanguages(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) (err error) = kernel32.GetSystemPreferredUILanguages
// Process Status API (PSAPI)
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
// syscall interface implementation for other packages
// GetCurrentProcess returns the handle for the current process.
// It is a pseudo handle that does not need to be closed.
// The returned error is always nil.
//
// Deprecated: use CurrentProcess for the same Handle without the nil
// error.
func GetCurrentProcess() (Handle, error) {
return CurrentProcess(), nil
}
// CurrentProcess returns the handle for the current process.
// It is a pseudo handle that does not need to be closed.
func CurrentProcess() Handle { return Handle(^uintptr(1 - 1)) }
// GetCurrentThread returns the handle for the current thread.
// It is a pseudo handle that does not need to be closed.
// The returned error is always nil.
//
// Deprecated: use CurrentThread for the same Handle without the nil
// error.
func GetCurrentThread() (Handle, error) {
return CurrentThread(), nil
}
// CurrentThread returns the handle for the current thread.
// It is a pseudo handle that does not need to be closed.
func CurrentThread() Handle { return Handle(^uintptr(2 - 1)) }
// GetProcAddressByOrdinal retrieves the address of the exported
// function from module by ordinal.
func GetProcAddressByOrdinal(module Handle, ordinal uintptr) (proc uintptr, err error) {
@ -352,7 +417,11 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
default:
createmode = OPEN_EXISTING
}
h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
if perm&S_IWRITE == 0 {
attrs = FILE_ATTRIBUTE_READONLY
}
h, e := CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
return h, e
}
@ -497,6 +566,10 @@ func ComputerName() (name string, err error) {
return string(utf16.Decode(b[0:n])), nil
}
func DurationSinceBoot() time.Duration {
return time.Duration(getTickCount64()) * time.Millisecond
}
func Ftruncate(fd Handle, length int64) (err error) {
curoffset, e := Seek(fd, 0, 1)
if e != nil {
@ -628,6 +701,8 @@ const socket_error = uintptr(^uint32(0))
//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup
//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
//sys sendto(s Handle, buf []byte, flags int32, to unsafe.Pointer, tolen int32) (err error) [failretval==socket_error] = ws2_32.sendto
//sys recvfrom(s Handle, buf []byte, flags int32, from *RawSockaddrAny, fromlen *int32) (n int32, err error) [failretval==-1] = ws2_32.recvfrom
//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
@ -795,7 +870,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
for n < len(pp.Path) && pp.Path[n] != 0 {
n++
}
bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
sa.Name = string(bytes)
return sa, nil
@ -1056,10 +1131,27 @@ func NsecToTimespec(nsec int64) (ts Timespec) {
// TODO(brainman): fix all needed for net
func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, syscall.EWINDOWS }
func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) {
return 0, nil, syscall.EWINDOWS
var rsa RawSockaddrAny
l := int32(unsafe.Sizeof(rsa))
n32, err := recvfrom(fd, p, int32(flags), &rsa, &l)
n = int(n32)
if err != nil {
return
}
from, err = rsa.Sockaddr()
return
}
func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return syscall.EWINDOWS }
func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) {
ptr, l, err := to.sockaddr()
if err != nil {
return err
}
return sendto(fd, p, int32(flags), ptr, l)
}
func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return syscall.EWINDOWS }
// The Linger struct is wrong but we only noticed after Go 1.
@ -1106,7 +1198,7 @@ func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) {
return syscall.EWINDOWS
}
func Getpid() (pid int) { return int(getCurrentProcessId()) }
func Getpid() (pid int) { return int(GetCurrentProcessId()) }
func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
// NOTE(rsc): The Win32finddata struct is wrong for the system call:
@ -1234,3 +1326,129 @@ func Readlink(path string, buf []byte) (n int, err error) {
return n, nil
}
// GUIDFromString parses a string in the form of
// "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" into a GUID.
func GUIDFromString(str string) (GUID, error) {
guid := GUID{}
str16, err := syscall.UTF16PtrFromString(str)
if err != nil {
return guid, err
}
err = clsidFromString(str16, &guid)
if err != nil {
return guid, err
}
return guid, nil
}
// GenerateGUID creates a new random GUID.
func GenerateGUID() (GUID, error) {
guid := GUID{}
err := coCreateGuid(&guid)
if err != nil {
return guid, err
}
return guid, nil
}
// String returns the canonical string form of the GUID,
// in the form of "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}".
func (guid GUID) String() string {
var str [100]uint16
chars := stringFromGUID2(&guid, &str[0], int32(len(str)))
if chars <= 1 {
return ""
}
return string(utf16.Decode(str[:chars-1]))
}
// KnownFolderPath returns a well-known folder path for the current user, specified by one of
// the FOLDERID_ constants, and chosen and optionally created based on a KF_ flag.
func KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, error) {
return Token(0).KnownFolderPath(folderID, flags)
}
// KnownFolderPath returns a well-known folder path for the user token, specified by one of
// the FOLDERID_ constants, and chosen and optionally created based on a KF_ flag.
func (t Token) KnownFolderPath(folderID *KNOWNFOLDERID, flags uint32) (string, error) {
var p *uint16
err := shGetKnownFolderPath(folderID, flags, t, &p)
if err != nil {
return "", err
}
defer CoTaskMemFree(unsafe.Pointer(p))
return UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(p))[:]), nil
}
// RtlGetVersion returns the version of the underlying operating system, ignoring
// manifest semantics but is affected by the application compatibility layer.
func RtlGetVersion() *OsVersionInfoEx {
info := &OsVersionInfoEx{}
info.osVersionInfoSize = uint32(unsafe.Sizeof(*info))
// According to documentation, this function always succeeds.
// The function doesn't even check the validity of the
// osVersionInfoSize member. Disassembling ntdll.dll indicates
// that the documentation is indeed correct about that.
_ = rtlGetVersion(info)
return info
}
// RtlGetNtVersionNumbers returns the version of the underlying operating system,
// ignoring manifest semantics and the application compatibility layer.
func RtlGetNtVersionNumbers() (majorVersion, minorVersion, buildNumber uint32) {
rtlGetNtVersionNumbers(&majorVersion, &minorVersion, &buildNumber)
buildNumber &= 0xffff
return
}
// GetProcessPreferredUILanguages retrieves the process preferred UI languages.
func GetProcessPreferredUILanguages(flags uint32) ([]string, error) {
return getUILanguages(flags, getProcessPreferredUILanguages)
}
// GetThreadPreferredUILanguages retrieves the thread preferred UI languages for the current thread.
func GetThreadPreferredUILanguages(flags uint32) ([]string, error) {
return getUILanguages(flags, getThreadPreferredUILanguages)
}
// GetUserPreferredUILanguages retrieves information about the user preferred UI languages.
func GetUserPreferredUILanguages(flags uint32) ([]string, error) {
return getUILanguages(flags, getUserPreferredUILanguages)
}
// GetSystemPreferredUILanguages retrieves the system preferred UI languages.
func GetSystemPreferredUILanguages(flags uint32) ([]string, error) {
return getUILanguages(flags, getSystemPreferredUILanguages)
}
func getUILanguages(flags uint32, f func(flags uint32, numLanguages *uint32, buf *uint16, bufSize *uint32) error) ([]string, error) {
size := uint32(128)
for {
var numLanguages uint32
buf := make([]uint16, size)
err := f(flags, &numLanguages, &buf[0], &size)
if err == ERROR_INSUFFICIENT_BUFFER {
continue
}
if err != nil {
return nil, err
}
buf = buf[:size]
if numLanguages == 0 || len(buf) == 0 { // GetProcessPreferredUILanguages may return numLanguages==0 with "\0\0"
return []string{}, nil
}
if buf[len(buf)-1] == 0 {
buf = buf[:len(buf)-1] // remove terminating null
}
languages := make([]string, 0, numLanguages)
from := 0
for i, c := range buf {
if c == 0 {
languages = append(languages, string(utf16.Decode(buf[from:i])))
from = i + 1
}
}
return languages, nil
}
}

@ -62,11 +62,6 @@ var signals = [...]string{
}
const (
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
GENERIC_EXECUTE = 0x20000000
GENERIC_ALL = 0x10000000
FILE_LIST_DIRECTORY = 0x00000001
FILE_APPEND_DATA = 0x00000004
FILE_WRITE_ATTRIBUTES = 0x00000100
@ -158,17 +153,43 @@ const (
WAIT_OBJECT_0 = 0x00000000
WAIT_FAILED = 0xFFFFFFFF
PROCESS_TERMINATE = 1
PROCESS_QUERY_INFORMATION = 0x00000400
SYNCHRONIZE = 0x00100000
// Access rights for process.
PROCESS_CREATE_PROCESS = 0x0080
PROCESS_CREATE_THREAD = 0x0002
PROCESS_DUP_HANDLE = 0x0040
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
PROCESS_SET_INFORMATION = 0x0200
PROCESS_SET_QUOTA = 0x0100
PROCESS_SUSPEND_RESUME = 0x0800
PROCESS_TERMINATE = 0x0001
PROCESS_VM_OPERATION = 0x0008
PROCESS_VM_READ = 0x0010
PROCESS_VM_WRITE = 0x0020
// Access rights for thread.
THREAD_DIRECT_IMPERSONATION = 0x0200
THREAD_GET_CONTEXT = 0x0008
THREAD_IMPERSONATE = 0x0100
THREAD_QUERY_INFORMATION = 0x0040
THREAD_QUERY_LIMITED_INFORMATION = 0x0800
THREAD_SET_CONTEXT = 0x0010
THREAD_SET_INFORMATION = 0x0020
THREAD_SET_LIMITED_INFORMATION = 0x0400
THREAD_SET_THREAD_TOKEN = 0x0080
THREAD_SUSPEND_RESUME = 0x0002
THREAD_TERMINATE = 0x0001
FILE_MAP_COPY = 0x01
FILE_MAP_WRITE = 0x02
FILE_MAP_READ = 0x04
FILE_MAP_EXECUTE = 0x20
CTRL_C_EVENT = 0
CTRL_BREAK_EVENT = 1
CTRL_C_EVENT = 0
CTRL_BREAK_EVENT = 1
CTRL_CLOSE_EVENT = 2
CTRL_LOGOFF_EVENT = 5
CTRL_SHUTDOWN_EVENT = 6
// Windows reserves errors >= 1<<29 for application use.
APPLICATION_ERROR = 1 << 29
@ -450,12 +471,6 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
type SecurityAttributes struct {
Length uint32
SecurityDescriptor uintptr
InheritHandle uint32
}
type Overlapped struct {
Internal uintptr
InternalHigh uintptr
@ -629,6 +644,16 @@ type ProcessEntry32 struct {
ExeFile [MAX_PATH]uint16
}
type ThreadEntry32 struct {
Size uint32
Usage uint32
ThreadID uint32
OwnerProcessID uint32
BasePri int32
DeltaPri int32
Flags uint32
}
type Systemtime struct {
Year uint16
Month uint16
@ -665,6 +690,7 @@ const (
SOCK_SEQPACKET = 5
IPPROTO_IP = 0
IPPROTO_ICMP = 1
IPPROTO_IPV6 = 0x29
IPPROTO_TCP = 6
IPPROTO_UDP = 17
@ -676,6 +702,7 @@ const (
SO_BROADCAST = 32
SO_LINGER = 128
SO_RCVBUF = 0x1002
SO_RCVTIMEO = 0x1006
SO_SNDBUF = 0x1001
SO_UPDATE_ACCEPT_CONTEXT = 0x700b
SO_UPDATE_CONNECT_CONTEXT = 0x7010
@ -1147,6 +1174,28 @@ const (
REG_QWORD = REG_QWORD_LITTLE_ENDIAN
)
const (
EVENT_MODIFY_STATE = 0x0002
EVENT_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3
MUTANT_QUERY_STATE = 0x0001
MUTANT_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | MUTANT_QUERY_STATE
SEMAPHORE_MODIFY_STATE = 0x0002
SEMAPHORE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3
TIMER_QUERY_STATE = 0x0001
TIMER_MODIFY_STATE = 0x0002
TIMER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | TIMER_QUERY_STATE | TIMER_MODIFY_STATE
MUTEX_MODIFY_STATE = MUTANT_QUERY_STATE
MUTEX_ALL_ACCESS = MUTANT_ALL_ACCESS
CREATE_EVENT_MANUAL_RESET = 0x1
CREATE_EVENT_INITIAL_SET = 0x2
CREATE_MUTEX_INITIAL_OWNER = 0x1
)
type AddrinfoW struct {
Flags int32
Family int32
@ -1590,3 +1639,141 @@ const (
JobObjectNotificationLimitInformation2 = 34
JobObjectSecurityLimitInformation = 5
)
const (
KF_FLAG_DEFAULT = 0x00000000
KF_FLAG_FORCE_APP_DATA_REDIRECTION = 0x00080000
KF_FLAG_RETURN_FILTER_REDIRECTION_TARGET = 0x00040000
KF_FLAG_FORCE_PACKAGE_REDIRECTION = 0x00020000
KF_FLAG_NO_PACKAGE_REDIRECTION = 0x00010000
KF_FLAG_FORCE_APPCONTAINER_REDIRECTION = 0x00020000
KF_FLAG_NO_APPCONTAINER_REDIRECTION = 0x00010000
KF_FLAG_CREATE = 0x00008000
KF_FLAG_DONT_VERIFY = 0x00004000
KF_FLAG_DONT_UNEXPAND = 0x00002000
KF_FLAG_NO_ALIAS = 0x00001000
KF_FLAG_INIT = 0x00000800
KF_FLAG_DEFAULT_PATH = 0x00000400
KF_FLAG_NOT_PARENT_RELATIVE = 0x00000200
KF_FLAG_SIMPLE_IDLIST = 0x00000100
KF_FLAG_ALIAS_ONLY = 0x80000000
)
type OsVersionInfoEx struct {
osVersionInfoSize uint32
MajorVersion uint32
MinorVersion uint32
BuildNumber uint32
PlatformId uint32
CsdVersion [128]uint16
ServicePackMajor uint16
ServicePackMinor uint16
SuiteMask uint16
ProductType byte
_ byte
}
const (
EWX_LOGOFF = 0x00000000
EWX_SHUTDOWN = 0x00000001
EWX_REBOOT = 0x00000002
EWX_FORCE = 0x00000004
EWX_POWEROFF = 0x00000008
EWX_FORCEIFHUNG = 0x00000010
EWX_QUICKRESOLVE = 0x00000020
EWX_RESTARTAPPS = 0x00000040
EWX_HYBRID_SHUTDOWN = 0x00400000
EWX_BOOTOPTIONS = 0x01000000
SHTDN_REASON_FLAG_COMMENT_REQUIRED = 0x01000000
SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED = 0x02000000
SHTDN_REASON_FLAG_CLEAN_UI = 0x04000000
SHTDN_REASON_FLAG_DIRTY_UI = 0x08000000
SHTDN_REASON_FLAG_USER_DEFINED = 0x40000000
SHTDN_REASON_FLAG_PLANNED = 0x80000000
SHTDN_REASON_MAJOR_OTHER = 0x00000000
SHTDN_REASON_MAJOR_NONE = 0x00000000
SHTDN_REASON_MAJOR_HARDWARE = 0x00010000
SHTDN_REASON_MAJOR_OPERATINGSYSTEM = 0x00020000
SHTDN_REASON_MAJOR_SOFTWARE = 0x00030000
SHTDN_REASON_MAJOR_APPLICATION = 0x00040000
SHTDN_REASON_MAJOR_SYSTEM = 0x00050000
SHTDN_REASON_MAJOR_POWER = 0x00060000
SHTDN_REASON_MAJOR_LEGACY_API = 0x00070000
SHTDN_REASON_MINOR_OTHER = 0x00000000
SHTDN_REASON_MINOR_NONE = 0x000000ff
SHTDN_REASON_MINOR_MAINTENANCE = 0x00000001
SHTDN_REASON_MINOR_INSTALLATION = 0x00000002
SHTDN_REASON_MINOR_UPGRADE = 0x00000003
SHTDN_REASON_MINOR_RECONFIG = 0x00000004
SHTDN_REASON_MINOR_HUNG = 0x00000005
SHTDN_REASON_MINOR_UNSTABLE = 0x00000006
SHTDN_REASON_MINOR_DISK = 0x00000007
SHTDN_REASON_MINOR_PROCESSOR = 0x00000008
SHTDN_REASON_MINOR_NETWORKCARD = 0x00000009
SHTDN_REASON_MINOR_POWER_SUPPLY = 0x0000000a
SHTDN_REASON_MINOR_CORDUNPLUGGED = 0x0000000b
SHTDN_REASON_MINOR_ENVIRONMENT = 0x0000000c
SHTDN_REASON_MINOR_HARDWARE_DRIVER = 0x0000000d
SHTDN_REASON_MINOR_OTHERDRIVER = 0x0000000e
SHTDN_REASON_MINOR_BLUESCREEN = 0x0000000F
SHTDN_REASON_MINOR_SERVICEPACK = 0x00000010
SHTDN_REASON_MINOR_HOTFIX = 0x00000011
SHTDN_REASON_MINOR_SECURITYFIX = 0x00000012
SHTDN_REASON_MINOR_SECURITY = 0x00000013
SHTDN_REASON_MINOR_NETWORK_CONNECTIVITY = 0x00000014
SHTDN_REASON_MINOR_WMI = 0x00000015
SHTDN_REASON_MINOR_SERVICEPACK_UNINSTALL = 0x00000016
SHTDN_REASON_MINOR_HOTFIX_UNINSTALL = 0x00000017
SHTDN_REASON_MINOR_SECURITYFIX_UNINSTALL = 0x00000018
SHTDN_REASON_MINOR_MMC = 0x00000019
SHTDN_REASON_MINOR_SYSTEMRESTORE = 0x0000001a
SHTDN_REASON_MINOR_TERMSRV = 0x00000020
SHTDN_REASON_MINOR_DC_PROMOTION = 0x00000021
SHTDN_REASON_MINOR_DC_DEMOTION = 0x00000022
SHTDN_REASON_UNKNOWN = SHTDN_REASON_MINOR_NONE
SHTDN_REASON_LEGACY_API = SHTDN_REASON_MAJOR_LEGACY_API | SHTDN_REASON_FLAG_PLANNED
SHTDN_REASON_VALID_BIT_MASK = 0xc0ffffff
SHUTDOWN_NORETRY = 0x1
)
// Flags used for GetModuleHandleEx
const (
GET_MODULE_HANDLE_EX_FLAG_PIN = 1
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = 2
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 4
)
// MUI function flag values
const (
MUI_LANGUAGE_ID = 0x4
MUI_LANGUAGE_NAME = 0x8
MUI_MERGE_SYSTEM_FALLBACK = 0x10
MUI_MERGE_USER_FALLBACK = 0x20
MUI_UI_FALLBACK = MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK
MUI_THREAD_LANGUAGES = 0x40
MUI_CONSOLE_FILTER = 0x100
MUI_COMPLEX_SCRIPT_FILTER = 0x200
MUI_RESET_FILTERS = 0x001
MUI_USER_PREFERRED_UI_LANGUAGES = 0x10
MUI_USE_INSTALLED_LANGUAGES = 0x20
MUI_USE_SEARCH_ALL_LANGUAGES = 0x40
MUI_LANG_NEUTRAL_PE_FILE = 0x100
MUI_NON_LANG_NEUTRAL_FILE = 0x200
MUI_MACHINE_LANGUAGE_SETTINGS = 0x400
MUI_FILETYPE_NOT_LANGUAGE_NEUTRAL = 0x001
MUI_FILETYPE_LANGUAGE_NEUTRAL_MAIN = 0x002
MUI_FILETYPE_LANGUAGE_NEUTRAL_MUI = 0x004
MUI_QUERY_TYPE = 0x001
MUI_QUERY_CHECKSUM = 0x002
MUI_QUERY_LANGUAGE_NAME = 0x004
MUI_QUERY_RESOURCE_TYPES = 0x008
MUI_FILEINFO_VERSION = 0x001
MUI_FULL_LANGUAGE = 0x01
MUI_PARTIAL_LANGUAGE = 0x02
MUI_LIP_LANGUAGE = 0x04
MUI_LANGUAGE_INSTALLED = 0x20
MUI_LANGUAGE_LICENSED = 0x40
)

@ -1,4 +1,4 @@
// Code generated by 'go generate'; DO NOT EDIT.
// Code generated by 'mkerrors.bash'; DO NOT EDIT.
package windows

@ -0,0 +1,149 @@
// Code generated by 'mkknownfolderids.bash'; DO NOT EDIT.
package windows
type KNOWNFOLDERID GUID
var (
FOLDERID_NetworkFolder = &KNOWNFOLDERID{0xd20beec4, 0x5ca8, 0x4905, [8]byte{0xae, 0x3b, 0xbf, 0x25, 0x1e, 0xa0, 0x9b, 0x53}}
FOLDERID_ComputerFolder = &KNOWNFOLDERID{0x0ac0837c, 0xbbf8, 0x452a, [8]byte{0x85, 0x0d, 0x79, 0xd0, 0x8e, 0x66, 0x7c, 0xa7}}
FOLDERID_InternetFolder = &KNOWNFOLDERID{0x4d9f7874, 0x4e0c, 0x4904, [8]byte{0x96, 0x7b, 0x40, 0xb0, 0xd2, 0x0c, 0x3e, 0x4b}}
FOLDERID_ControlPanelFolder = &KNOWNFOLDERID{0x82a74aeb, 0xaeb4, 0x465c, [8]byte{0xa0, 0x14, 0xd0, 0x97, 0xee, 0x34, 0x6d, 0x63}}
FOLDERID_PrintersFolder = &KNOWNFOLDERID{0x76fc4e2d, 0xd6ad, 0x4519, [8]byte{0xa6, 0x63, 0x37, 0xbd, 0x56, 0x06, 0x81, 0x85}}
FOLDERID_SyncManagerFolder = &KNOWNFOLDERID{0x43668bf8, 0xc14e, 0x49b2, [8]byte{0x97, 0xc9, 0x74, 0x77, 0x84, 0xd7, 0x84, 0xb7}}
FOLDERID_SyncSetupFolder = &KNOWNFOLDERID{0x0f214138, 0xb1d3, 0x4a90, [8]byte{0xbb, 0xa9, 0x27, 0xcb, 0xc0, 0xc5, 0x38, 0x9a}}
FOLDERID_ConflictFolder = &KNOWNFOLDERID{0x4bfefb45, 0x347d, 0x4006, [8]byte{0xa5, 0xbe, 0xac, 0x0c, 0xb0, 0x56, 0x71, 0x92}}
FOLDERID_SyncResultsFolder = &KNOWNFOLDERID{0x289a9a43, 0xbe44, 0x4057, [8]byte{0xa4, 0x1b, 0x58, 0x7a, 0x76, 0xd7, 0xe7, 0xf9}}
FOLDERID_RecycleBinFolder = &KNOWNFOLDERID{0xb7534046, 0x3ecb, 0x4c18, [8]byte{0xbe, 0x4e, 0x64, 0xcd, 0x4c, 0xb7, 0xd6, 0xac}}
FOLDERID_ConnectionsFolder = &KNOWNFOLDERID{0x6f0cd92b, 0x2e97, 0x45d1, [8]byte{0x88, 0xff, 0xb0, 0xd1, 0x86, 0xb8, 0xde, 0xdd}}
FOLDERID_Fonts = &KNOWNFOLDERID{0xfd228cb7, 0xae11, 0x4ae3, [8]byte{0x86, 0x4c, 0x16, 0xf3, 0x91, 0x0a, 0xb8, 0xfe}}
FOLDERID_Desktop = &KNOWNFOLDERID{0xb4bfcc3a, 0xdb2c, 0x424c, [8]byte{0xb0, 0x29, 0x7f, 0xe9, 0x9a, 0x87, 0xc6, 0x41}}
FOLDERID_Startup = &KNOWNFOLDERID{0xb97d20bb, 0xf46a, 0x4c97, [8]byte{0xba, 0x10, 0x5e, 0x36, 0x08, 0x43, 0x08, 0x54}}
FOLDERID_Programs = &KNOWNFOLDERID{0xa77f5d77, 0x2e2b, 0x44c3, [8]byte{0xa6, 0xa2, 0xab, 0xa6, 0x01, 0x05, 0x4a, 0x51}}
FOLDERID_StartMenu = &KNOWNFOLDERID{0x625b53c3, 0xab48, 0x4ec1, [8]byte{0xba, 0x1f, 0xa1, 0xef, 0x41, 0x46, 0xfc, 0x19}}
FOLDERID_Recent = &KNOWNFOLDERID{0xae50c081, 0xebd2, 0x438a, [8]byte{0x86, 0x55, 0x8a, 0x09, 0x2e, 0x34, 0x98, 0x7a}}
FOLDERID_SendTo = &KNOWNFOLDERID{0x8983036c, 0x27c0, 0x404b, [8]byte{0x8f, 0x08, 0x10, 0x2d, 0x10, 0xdc, 0xfd, 0x74}}
FOLDERID_Documents = &KNOWNFOLDERID{0xfdd39ad0, 0x238f, 0x46af, [8]byte{0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7}}
FOLDERID_Favorites = &KNOWNFOLDERID{0x1777f761, 0x68ad, 0x4d8a, [8]byte{0x87, 0xbd, 0x30, 0xb7, 0x59, 0xfa, 0x33, 0xdd}}
FOLDERID_NetHood = &KNOWNFOLDERID{0xc5abbf53, 0xe17f, 0x4121, [8]byte{0x89, 0x00, 0x86, 0x62, 0x6f, 0xc2, 0xc9, 0x73}}
FOLDERID_PrintHood = &KNOWNFOLDERID{0x9274bd8d, 0xcfd1, 0x41c3, [8]byte{0xb3, 0x5e, 0xb1, 0x3f, 0x55, 0xa7, 0x58, 0xf4}}
FOLDERID_Templates = &KNOWNFOLDERID{0xa63293e8, 0x664e, 0x48db, [8]byte{0xa0, 0x79, 0xdf, 0x75, 0x9e, 0x05, 0x09, 0xf7}}
FOLDERID_CommonStartup = &KNOWNFOLDERID{0x82a5ea35, 0xd9cd, 0x47c5, [8]byte{0x96, 0x29, 0xe1, 0x5d, 0x2f, 0x71, 0x4e, 0x6e}}
FOLDERID_CommonPrograms = &KNOWNFOLDERID{0x0139d44e, 0x6afe, 0x49f2, [8]byte{0x86, 0x90, 0x3d, 0xaf, 0xca, 0xe6, 0xff, 0xb8}}
FOLDERID_CommonStartMenu = &KNOWNFOLDERID{0xa4115719, 0xd62e, 0x491d, [8]byte{0xaa, 0x7c, 0xe7, 0x4b, 0x8b, 0xe3, 0xb0, 0x67}}
FOLDERID_PublicDesktop = &KNOWNFOLDERID{0xc4aa340d, 0xf20f, 0x4863, [8]byte{0xaf, 0xef, 0xf8, 0x7e, 0xf2, 0xe6, 0xba, 0x25}}
FOLDERID_ProgramData = &KNOWNFOLDERID{0x62ab5d82, 0xfdc1, 0x4dc3, [8]byte{0xa9, 0xdd, 0x07, 0x0d, 0x1d, 0x49, 0x5d, 0x97}}
FOLDERID_CommonTemplates = &KNOWNFOLDERID{0xb94237e7, 0x57ac, 0x4347, [8]byte{0x91, 0x51, 0xb0, 0x8c, 0x6c, 0x32, 0xd1, 0xf7}}
FOLDERID_PublicDocuments = &KNOWNFOLDERID{0xed4824af, 0xdce4, 0x45a8, [8]byte{0x81, 0xe2, 0xfc, 0x79, 0x65, 0x08, 0x36, 0x34}}
FOLDERID_RoamingAppData = &KNOWNFOLDERID{0x3eb685db, 0x65f9, 0x4cf6, [8]byte{0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}}
FOLDERID_LocalAppData = &KNOWNFOLDERID{0xf1b32785, 0x6fba, 0x4fcf, [8]byte{0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91}}
FOLDERID_LocalAppDataLow = &KNOWNFOLDERID{0xa520a1a4, 0x1780, 0x4ff6, [8]byte{0xbd, 0x18, 0x16, 0x73, 0x43, 0xc5, 0xaf, 0x16}}
FOLDERID_InternetCache = &KNOWNFOLDERID{0x352481e8, 0x33be, 0x4251, [8]byte{0xba, 0x85, 0x60, 0x07, 0xca, 0xed, 0xcf, 0x9d}}
FOLDERID_Cookies = &KNOWNFOLDERID{0x2b0f765d, 0xc0e9, 0x4171, [8]byte{0x90, 0x8e, 0x08, 0xa6, 0x11, 0xb8, 0x4f, 0xf6}}
FOLDERID_History = &KNOWNFOLDERID{0xd9dc8a3b, 0xb784, 0x432e, [8]byte{0xa7, 0x81, 0x5a, 0x11, 0x30, 0xa7, 0x59, 0x63}}
FOLDERID_System = &KNOWNFOLDERID{0x1ac14e77, 0x02e7, 0x4e5d, [8]byte{0xb7, 0x44, 0x2e, 0xb1, 0xae, 0x51, 0x98, 0xb7}}
FOLDERID_SystemX86 = &KNOWNFOLDERID{0xd65231b0, 0xb2f1, 0x4857, [8]byte{0xa4, 0xce, 0xa8, 0xe7, 0xc6, 0xea, 0x7d, 0x27}}
FOLDERID_Windows = &KNOWNFOLDERID{0xf38bf404, 0x1d43, 0x42f2, [8]byte{0x93, 0x05, 0x67, 0xde, 0x0b, 0x28, 0xfc, 0x23}}
FOLDERID_Profile = &KNOWNFOLDERID{0x5e6c858f, 0x0e22, 0x4760, [8]byte{0x9a, 0xfe, 0xea, 0x33, 0x17, 0xb6, 0x71, 0x73}}
FOLDERID_Pictures = &KNOWNFOLDERID{0x33e28130, 0x4e1e, 0x4676, [8]byte{0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb}}
FOLDERID_ProgramFilesX86 = &KNOWNFOLDERID{0x7c5a40ef, 0xa0fb, 0x4bfc, [8]byte{0x87, 0x4a, 0xc0, 0xf2, 0xe0, 0xb9, 0xfa, 0x8e}}
FOLDERID_ProgramFilesCommonX86 = &KNOWNFOLDERID{0xde974d24, 0xd9c6, 0x4d3e, [8]byte{0xbf, 0x91, 0xf4, 0x45, 0x51, 0x20, 0xb9, 0x17}}
FOLDERID_ProgramFilesX64 = &KNOWNFOLDERID{0x6d809377, 0x6af0, 0x444b, [8]byte{0x89, 0x57, 0xa3, 0x77, 0x3f, 0x02, 0x20, 0x0e}}
FOLDERID_ProgramFilesCommonX64 = &KNOWNFOLDERID{0x6365d5a7, 0x0f0d, 0x45e5, [8]byte{0x87, 0xf6, 0x0d, 0xa5, 0x6b, 0x6a, 0x4f, 0x7d}}
FOLDERID_ProgramFiles = &KNOWNFOLDERID{0x905e63b6, 0xc1bf, 0x494e, [8]byte{0xb2, 0x9c, 0x65, 0xb7, 0x32, 0xd3, 0xd2, 0x1a}}
FOLDERID_ProgramFilesCommon = &KNOWNFOLDERID{0xf7f1ed05, 0x9f6d, 0x47a2, [8]byte{0xaa, 0xae, 0x29, 0xd3, 0x17, 0xc6, 0xf0, 0x66}}
FOLDERID_UserProgramFiles = &KNOWNFOLDERID{0x5cd7aee2, 0x2219, 0x4a67, [8]byte{0xb8, 0x5d, 0x6c, 0x9c, 0xe1, 0x56, 0x60, 0xcb}}
FOLDERID_UserProgramFilesCommon = &KNOWNFOLDERID{0xbcbd3057, 0xca5c, 0x4622, [8]byte{0xb4, 0x2d, 0xbc, 0x56, 0xdb, 0x0a, 0xe5, 0x16}}
FOLDERID_AdminTools = &KNOWNFOLDERID{0x724ef170, 0xa42d, 0x4fef, [8]byte{0x9f, 0x26, 0xb6, 0x0e, 0x84, 0x6f, 0xba, 0x4f}}
FOLDERID_CommonAdminTools = &KNOWNFOLDERID{0xd0384e7d, 0xbac3, 0x4797, [8]byte{0x8f, 0x14, 0xcb, 0xa2, 0x29, 0xb3, 0x92, 0xb5}}
FOLDERID_Music = &KNOWNFOLDERID{0x4bd8d571, 0x6d19, 0x48d3, [8]byte{0xbe, 0x97, 0x42, 0x22, 0x20, 0x08, 0x0e, 0x43}}
FOLDERID_Videos = &KNOWNFOLDERID{0x18989b1d, 0x99b5, 0x455b, [8]byte{0x84, 0x1c, 0xab, 0x7c, 0x74, 0xe4, 0xdd, 0xfc}}
FOLDERID_Ringtones = &KNOWNFOLDERID{0xc870044b, 0xf49e, 0x4126, [8]byte{0xa9, 0xc3, 0xb5, 0x2a, 0x1f, 0xf4, 0x11, 0xe8}}
FOLDERID_PublicPictures = &KNOWNFOLDERID{0xb6ebfb86, 0x6907, 0x413c, [8]byte{0x9a, 0xf7, 0x4f, 0xc2, 0xab, 0xf0, 0x7c, 0xc5}}
FOLDERID_PublicMusic = &KNOWNFOLDERID{0x3214fab5, 0x9757, 0x4298, [8]byte{0xbb, 0x61, 0x92, 0xa9, 0xde, 0xaa, 0x44, 0xff}}
FOLDERID_PublicVideos = &KNOWNFOLDERID{0x2400183a, 0x6185, 0x49fb, [8]byte{0xa2, 0xd8, 0x4a, 0x39, 0x2a, 0x60, 0x2b, 0xa3}}
FOLDERID_PublicRingtones = &KNOWNFOLDERID{0xe555ab60, 0x153b, 0x4d17, [8]byte{0x9f, 0x04, 0xa5, 0xfe, 0x99, 0xfc, 0x15, 0xec}}
FOLDERID_ResourceDir = &KNOWNFOLDERID{0x8ad10c31, 0x2adb, 0x4296, [8]byte{0xa8, 0xf7, 0xe4, 0x70, 0x12, 0x32, 0xc9, 0x72}}
FOLDERID_LocalizedResourcesDir = &KNOWNFOLDERID{0x2a00375e, 0x224c, 0x49de, [8]byte{0xb8, 0xd1, 0x44, 0x0d, 0xf7, 0xef, 0x3d, 0xdc}}
FOLDERID_CommonOEMLinks = &KNOWNFOLDERID{0xc1bae2d0, 0x10df, 0x4334, [8]byte{0xbe, 0xdd, 0x7a, 0xa2, 0x0b, 0x22, 0x7a, 0x9d}}
FOLDERID_CDBurning = &KNOWNFOLDERID{0x9e52ab10, 0xf80d, 0x49df, [8]byte{0xac, 0xb8, 0x43, 0x30, 0xf5, 0x68, 0x78, 0x55}}
FOLDERID_UserProfiles = &KNOWNFOLDERID{0x0762d272, 0xc50a, 0x4bb0, [8]byte{0xa3, 0x82, 0x69, 0x7d, 0xcd, 0x72, 0x9b, 0x80}}
FOLDERID_Playlists = &KNOWNFOLDERID{0xde92c1c7, 0x837f, 0x4f69, [8]byte{0xa3, 0xbb, 0x86, 0xe6, 0x31, 0x20, 0x4a, 0x23}}
FOLDERID_SamplePlaylists = &KNOWNFOLDERID{0x15ca69b3, 0x30ee, 0x49c1, [8]byte{0xac, 0xe1, 0x6b, 0x5e, 0xc3, 0x72, 0xaf, 0xb5}}
FOLDERID_SampleMusic = &KNOWNFOLDERID{0xb250c668, 0xf57d, 0x4ee1, [8]byte{0xa6, 0x3c, 0x29, 0x0e, 0xe7, 0xd1, 0xaa, 0x1f}}
FOLDERID_SamplePictures = &KNOWNFOLDERID{0xc4900540, 0x2379, 0x4c75, [8]byte{0x84, 0x4b, 0x64, 0xe6, 0xfa, 0xf8, 0x71, 0x6b}}
FOLDERID_SampleVideos = &KNOWNFOLDERID{0x859ead94, 0x2e85, 0x48ad, [8]byte{0xa7, 0x1a, 0x09, 0x69, 0xcb, 0x56, 0xa6, 0xcd}}
FOLDERID_PhotoAlbums = &KNOWNFOLDERID{0x69d2cf90, 0xfc33, 0x4fb7, [8]byte{0x9a, 0x0c, 0xeb, 0xb0, 0xf0, 0xfc, 0xb4, 0x3c}}
FOLDERID_Public = &KNOWNFOLDERID{0xdfdf76a2, 0xc82a, 0x4d63, [8]byte{0x90, 0x6a, 0x56, 0x44, 0xac, 0x45, 0x73, 0x85}}
FOLDERID_ChangeRemovePrograms = &KNOWNFOLDERID{0xdf7266ac, 0x9274, 0x4867, [8]byte{0x8d, 0x55, 0x3b, 0xd6, 0x61, 0xde, 0x87, 0x2d}}
FOLDERID_AppUpdates = &KNOWNFOLDERID{0xa305ce99, 0xf527, 0x492b, [8]byte{0x8b, 0x1a, 0x7e, 0x76, 0xfa, 0x98, 0xd6, 0xe4}}
FOLDERID_AddNewPrograms = &KNOWNFOLDERID{0xde61d971, 0x5ebc, 0x4f02, [8]byte{0xa3, 0xa9, 0x6c, 0x82, 0x89, 0x5e, 0x5c, 0x04}}
FOLDERID_Downloads = &KNOWNFOLDERID{0x374de290, 0x123f, 0x4565, [8]byte{0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b}}
FOLDERID_PublicDownloads = &KNOWNFOLDERID{0x3d644c9b, 0x1fb8, 0x4f30, [8]byte{0x9b, 0x45, 0xf6, 0x70, 0x23, 0x5f, 0x79, 0xc0}}
FOLDERID_SavedSearches = &KNOWNFOLDERID{0x7d1d3a04, 0xdebb, 0x4115, [8]byte{0x95, 0xcf, 0x2f, 0x29, 0xda, 0x29, 0x20, 0xda}}
FOLDERID_QuickLaunch = &KNOWNFOLDERID{0x52a4f021, 0x7b75, 0x48a9, [8]byte{0x9f, 0x6b, 0x4b, 0x87, 0xa2, 0x10, 0xbc, 0x8f}}
FOLDERID_Contacts = &KNOWNFOLDERID{0x56784854, 0xc6cb, 0x462b, [8]byte{0x81, 0x69, 0x88, 0xe3, 0x50, 0xac, 0xb8, 0x82}}
FOLDERID_SidebarParts = &KNOWNFOLDERID{0xa75d362e, 0x50fc, 0x4fb7, [8]byte{0xac, 0x2c, 0xa8, 0xbe, 0xaa, 0x31, 0x44, 0x93}}
FOLDERID_SidebarDefaultParts = &KNOWNFOLDERID{0x7b396e54, 0x9ec5, 0x4300, [8]byte{0xbe, 0x0a, 0x24, 0x82, 0xeb, 0xae, 0x1a, 0x26}}
FOLDERID_PublicGameTasks = &KNOWNFOLDERID{0xdebf2536, 0xe1a8, 0x4c59, [8]byte{0xb6, 0xa2, 0x41, 0x45, 0x86, 0x47, 0x6a, 0xea}}
FOLDERID_GameTasks = &KNOWNFOLDERID{0x054fae61, 0x4dd8, 0x4787, [8]byte{0x80, 0xb6, 0x09, 0x02, 0x20, 0xc4, 0xb7, 0x00}}
FOLDERID_SavedGames = &KNOWNFOLDERID{0x4c5c32ff, 0xbb9d, 0x43b0, [8]byte{0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4}}
FOLDERID_Games = &KNOWNFOLDERID{0xcac52c1a, 0xb53d, 0x4edc, [8]byte{0x92, 0xd7, 0x6b, 0x2e, 0x8a, 0xc1, 0x94, 0x34}}
FOLDERID_SEARCH_MAPI = &KNOWNFOLDERID{0x98ec0e18, 0x2098, 0x4d44, [8]byte{0x86, 0x44, 0x66, 0x97, 0x93, 0x15, 0xa2, 0x81}}
FOLDERID_SEARCH_CSC = &KNOWNFOLDERID{0xee32e446, 0x31ca, 0x4aba, [8]byte{0x81, 0x4f, 0xa5, 0xeb, 0xd2, 0xfd, 0x6d, 0x5e}}
FOLDERID_Links = &KNOWNFOLDERID{0xbfb9d5e0, 0xc6a9, 0x404c, [8]byte{0xb2, 0xb2, 0xae, 0x6d, 0xb6, 0xaf, 0x49, 0x68}}
FOLDERID_UsersFiles = &KNOWNFOLDERID{0xf3ce0f7c, 0x4901, 0x4acc, [8]byte{0x86, 0x48, 0xd5, 0xd4, 0x4b, 0x04, 0xef, 0x8f}}
FOLDERID_UsersLibraries = &KNOWNFOLDERID{0xa302545d, 0xdeff, 0x464b, [8]byte{0xab, 0xe8, 0x61, 0xc8, 0x64, 0x8d, 0x93, 0x9b}}
FOLDERID_SearchHome = &KNOWNFOLDERID{0x190337d1, 0xb8ca, 0x4121, [8]byte{0xa6, 0x39, 0x6d, 0x47, 0x2d, 0x16, 0x97, 0x2a}}
FOLDERID_OriginalImages = &KNOWNFOLDERID{0x2c36c0aa, 0x5812, 0x4b87, [8]byte{0xbf, 0xd0, 0x4c, 0xd0, 0xdf, 0xb1, 0x9b, 0x39}}
FOLDERID_DocumentsLibrary = &KNOWNFOLDERID{0x7b0db17d, 0x9cd2, 0x4a93, [8]byte{0x97, 0x33, 0x46, 0xcc, 0x89, 0x02, 0x2e, 0x7c}}
FOLDERID_MusicLibrary = &KNOWNFOLDERID{0x2112ab0a, 0xc86a, 0x4ffe, [8]byte{0xa3, 0x68, 0x0d, 0xe9, 0x6e, 0x47, 0x01, 0x2e}}
FOLDERID_PicturesLibrary = &KNOWNFOLDERID{0xa990ae9f, 0xa03b, 0x4e80, [8]byte{0x94, 0xbc, 0x99, 0x12, 0xd7, 0x50, 0x41, 0x04}}
FOLDERID_VideosLibrary = &KNOWNFOLDERID{0x491e922f, 0x5643, 0x4af4, [8]byte{0xa7, 0xeb, 0x4e, 0x7a, 0x13, 0x8d, 0x81, 0x74}}
FOLDERID_RecordedTVLibrary = &KNOWNFOLDERID{0x1a6fdba2, 0xf42d, 0x4358, [8]byte{0xa7, 0x98, 0xb7, 0x4d, 0x74, 0x59, 0x26, 0xc5}}
FOLDERID_HomeGroup = &KNOWNFOLDERID{0x52528a6b, 0xb9e3, 0x4add, [8]byte{0xb6, 0x0d, 0x58, 0x8c, 0x2d, 0xba, 0x84, 0x2d}}
FOLDERID_HomeGroupCurrentUser = &KNOWNFOLDERID{0x9b74b6a3, 0x0dfd, 0x4f11, [8]byte{0x9e, 0x78, 0x5f, 0x78, 0x00, 0xf2, 0xe7, 0x72}}
FOLDERID_DeviceMetadataStore = &KNOWNFOLDERID{0x5ce4a5e9, 0xe4eb, 0x479d, [8]byte{0xb8, 0x9f, 0x13, 0x0c, 0x02, 0x88, 0x61, 0x55}}
FOLDERID_Libraries = &KNOWNFOLDERID{0x1b3ea5dc, 0xb587, 0x4786, [8]byte{0xb4, 0xef, 0xbd, 0x1d, 0xc3, 0x32, 0xae, 0xae}}
FOLDERID_PublicLibraries = &KNOWNFOLDERID{0x48daf80b, 0xe6cf, 0x4f4e, [8]byte{0xb8, 0x00, 0x0e, 0x69, 0xd8, 0x4e, 0xe3, 0x84}}
FOLDERID_UserPinned = &KNOWNFOLDERID{0x9e3995ab, 0x1f9c, 0x4f13, [8]byte{0xb8, 0x27, 0x48, 0xb2, 0x4b, 0x6c, 0x71, 0x74}}
FOLDERID_ImplicitAppShortcuts = &KNOWNFOLDERID{0xbcb5256f, 0x79f6, 0x4cee, [8]byte{0xb7, 0x25, 0xdc, 0x34, 0xe4, 0x02, 0xfd, 0x46}}
FOLDERID_AccountPictures = &KNOWNFOLDERID{0x008ca0b1, 0x55b4, 0x4c56, [8]byte{0xb8, 0xa8, 0x4d, 0xe4, 0xb2, 0x99, 0xd3, 0xbe}}
FOLDERID_PublicUserTiles = &KNOWNFOLDERID{0x0482af6c, 0x08f1, 0x4c34, [8]byte{0x8c, 0x90, 0xe1, 0x7e, 0xc9, 0x8b, 0x1e, 0x17}}
FOLDERID_AppsFolder = &KNOWNFOLDERID{0x1e87508d, 0x89c2, 0x42f0, [8]byte{0x8a, 0x7e, 0x64, 0x5a, 0x0f, 0x50, 0xca, 0x58}}
FOLDERID_StartMenuAllPrograms = &KNOWNFOLDERID{0xf26305ef, 0x6948, 0x40b9, [8]byte{0xb2, 0x55, 0x81, 0x45, 0x3d, 0x09, 0xc7, 0x85}}
FOLDERID_CommonStartMenuPlaces = &KNOWNFOLDERID{0xa440879f, 0x87a0, 0x4f7d, [8]byte{0xb7, 0x00, 0x02, 0x07, 0xb9, 0x66, 0x19, 0x4a}}
FOLDERID_ApplicationShortcuts = &KNOWNFOLDERID{0xa3918781, 0xe5f2, 0x4890, [8]byte{0xb3, 0xd9, 0xa7, 0xe5, 0x43, 0x32, 0x32, 0x8c}}
FOLDERID_RoamingTiles = &KNOWNFOLDERID{0x00bcfc5a, 0xed94, 0x4e48, [8]byte{0x96, 0xa1, 0x3f, 0x62, 0x17, 0xf2, 0x19, 0x90}}
FOLDERID_RoamedTileImages = &KNOWNFOLDERID{0xaaa8d5a5, 0xf1d6, 0x4259, [8]byte{0xba, 0xa8, 0x78, 0xe7, 0xef, 0x60, 0x83, 0x5e}}
FOLDERID_Screenshots = &KNOWNFOLDERID{0xb7bede81, 0xdf94, 0x4682, [8]byte{0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f}}
FOLDERID_CameraRoll = &KNOWNFOLDERID{0xab5fb87b, 0x7ce2, 0x4f83, [8]byte{0x91, 0x5d, 0x55, 0x08, 0x46, 0xc9, 0x53, 0x7b}}
FOLDERID_SkyDrive = &KNOWNFOLDERID{0xa52bba46, 0xe9e1, 0x435f, [8]byte{0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
FOLDERID_OneDrive = &KNOWNFOLDERID{0xa52bba46, 0xe9e1, 0x435f, [8]byte{0xb3, 0xd9, 0x28, 0xda, 0xa6, 0x48, 0xc0, 0xf6}}
FOLDERID_SkyDriveDocuments = &KNOWNFOLDERID{0x24d89e24, 0x2f19, 0x4534, [8]byte{0x9d, 0xde, 0x6a, 0x66, 0x71, 0xfb, 0xb8, 0xfe}}
FOLDERID_SkyDrivePictures = &KNOWNFOLDERID{0x339719b5, 0x8c47, 0x4894, [8]byte{0x94, 0xc2, 0xd8, 0xf7, 0x7a, 0xdd, 0x44, 0xa6}}
FOLDERID_SkyDriveMusic = &KNOWNFOLDERID{0xc3f2459e, 0x80d6, 0x45dc, [8]byte{0xbf, 0xef, 0x1f, 0x76, 0x9f, 0x2b, 0xe7, 0x30}}
FOLDERID_SkyDriveCameraRoll = &KNOWNFOLDERID{0x767e6811, 0x49cb, 0x4273, [8]byte{0x87, 0xc2, 0x20, 0xf3, 0x55, 0xe1, 0x08, 0x5b}}
FOLDERID_SearchHistory = &KNOWNFOLDERID{0x0d4c3db6, 0x03a3, 0x462f, [8]byte{0xa0, 0xe6, 0x08, 0x92, 0x4c, 0x41, 0xb5, 0xd4}}
FOLDERID_SearchTemplates = &KNOWNFOLDERID{0x7e636bfe, 0xdfa9, 0x4d5e, [8]byte{0xb4, 0x56, 0xd7, 0xb3, 0x98, 0x51, 0xd8, 0xa9}}
FOLDERID_CameraRollLibrary = &KNOWNFOLDERID{0x2b20df75, 0x1eda, 0x4039, [8]byte{0x80, 0x97, 0x38, 0x79, 0x82, 0x27, 0xd5, 0xb7}}
FOLDERID_SavedPictures = &KNOWNFOLDERID{0x3b193882, 0xd3ad, 0x4eab, [8]byte{0x96, 0x5a, 0x69, 0x82, 0x9d, 0x1f, 0xb5, 0x9f}}
FOLDERID_SavedPicturesLibrary = &KNOWNFOLDERID{0xe25b5812, 0xbe88, 0x4bd9, [8]byte{0x94, 0xb0, 0x29, 0x23, 0x34, 0x77, 0xb6, 0xc3}}
FOLDERID_RetailDemo = &KNOWNFOLDERID{0x12d4c69e, 0x24ad, 0x4923, [8]byte{0xbe, 0x19, 0x31, 0x32, 0x1c, 0x43, 0xa7, 0x67}}
FOLDERID_Device = &KNOWNFOLDERID{0x1c2ac1dc, 0x4358, 0x4b6c, [8]byte{0x97, 0x33, 0xaf, 0x21, 0x15, 0x65, 0x76, 0xf0}}
FOLDERID_DevelopmentFiles = &KNOWNFOLDERID{0xdbe8e08e, 0x3053, 0x4bbc, [8]byte{0xb1, 0x83, 0x2a, 0x7b, 0x2b, 0x19, 0x1e, 0x59}}
FOLDERID_Objects3D = &KNOWNFOLDERID{0x31c0dd25, 0x9439, 0x4f12, [8]byte{0xbf, 0x41, 0x7f, 0xf4, 0xed, 0xa3, 0x87, 0x22}}
FOLDERID_AppCaptures = &KNOWNFOLDERID{0xedc0fe71, 0x98d8, 0x4f4a, [8]byte{0xb9, 0x20, 0xc8, 0xdc, 0x13, 0x3c, 0xb1, 0x65}}
FOLDERID_LocalDocuments = &KNOWNFOLDERID{0xf42ee2d3, 0x909f, 0x4907, [8]byte{0x88, 0x71, 0x4c, 0x22, 0xfc, 0x0b, 0xf7, 0x56}}
FOLDERID_LocalPictures = &KNOWNFOLDERID{0x0ddd015d, 0xb06c, 0x45d5, [8]byte{0x8c, 0x4c, 0xf5, 0x97, 0x13, 0x85, 0x46, 0x39}}
FOLDERID_LocalVideos = &KNOWNFOLDERID{0x35286a68, 0x3c57, 0x41a1, [8]byte{0xbb, 0xb1, 0x0e, 0xae, 0x73, 0xd7, 0x6c, 0x95}}
FOLDERID_LocalMusic = &KNOWNFOLDERID{0xa0c69a99, 0x21c8, 0x4671, [8]byte{0x87, 0x03, 0x79, 0x34, 0x16, 0x2f, 0xcf, 0x1d}}
FOLDERID_LocalDownloads = &KNOWNFOLDERID{0x7d83ee9b, 0x2244, 0x4e70, [8]byte{0xb1, 0xf5, 0x53, 0x93, 0x04, 0x2a, 0xf1, 0xe4}}
FOLDERID_RecordedCalls = &KNOWNFOLDERID{0x2f8b40c2, 0x83ed, 0x48ee, [8]byte{0xb3, 0x83, 0xa1, 0xf1, 0x57, 0xec, 0x6f, 0x9a}}
FOLDERID_AllAppMods = &KNOWNFOLDERID{0x7ad67899, 0x66af, 0x43ba, [8]byte{0x91, 0x56, 0x6a, 0xad, 0x42, 0xe6, 0xc5, 0x96}}
FOLDERID_CurrentAppMods = &KNOWNFOLDERID{0x3db40b20, 0x2a30, 0x4dbe, [8]byte{0x91, 0x7e, 0x77, 0x1d, 0xd2, 0x1d, 0xd0, 0x99}}
FOLDERID_AppDataDesktop = &KNOWNFOLDERID{0xb2c5e279, 0x7add, 0x439f, [8]byte{0xb2, 0x8c, 0xc4, 0x1f, 0xe1, 0xbb, 0xf6, 0x72}}
FOLDERID_AppDataDocuments = &KNOWNFOLDERID{0x7be16610, 0x1f7f, 0x44ac, [8]byte{0xbf, 0xf0, 0x83, 0xe1, 0x5f, 0x2f, 0xfc, 0xa1}}
FOLDERID_AppDataFavorites = &KNOWNFOLDERID{0x7cfbefbc, 0xde1f, 0x45aa, [8]byte{0xb8, 0x43, 0xa5, 0x42, 0xac, 0x53, 0x6c, 0xc9}}
FOLDERID_AppDataProgramData = &KNOWNFOLDERID{0x559d40a3, 0xa036, 0x40fa, [8]byte{0xaf, 0x61, 0x84, 0xcb, 0x43, 0x0a, 0x4d, 0x34}}
)

File diff suppressed because it is too large Load Diff

@ -4,5 +4,5 @@ github.com/Microsoft/go-winio/pkg/guid
# github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95
github.com/hectane/go-acl
github.com/hectane/go-acl/api
# golang.org/x/sys v0.0.0-20190529164535-6a60838ec259
# golang.org/x/sys v0.0.0-20200107162124-548cf772de50
golang.org/x/sys/windows

@ -19,7 +19,12 @@
#ifndef ZT_ZEROTIER_API_H
#define ZT_ZEROTIER_API_H
#ifdef __cplusplus
#include <cstdint>
extern "C" {
#else
#include <stdint.h>
#endif
/* For struct sockaddr_storage, which is referenced here. */
#if defined(_WIN32) || defined(_WIN64)
@ -39,10 +44,6 @@
#define ZT_SDK_API
#endif
#ifdef __cplusplus
extern "C" {
#endif
/****************************************************************************/
/* Core constants */
/****************************************************************************/
@ -91,11 +92,6 @@ extern "C" {
*/
#define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM)
/**
* Maximum size of a remote trace message's serialized Dictionary
*/
#define ZT_MAX_REMOTE_TRACE_SIZE 10000
/**
* Maximum length of network short name
*/
@ -258,78 +254,6 @@ extern "C" {
*/
#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL
/****************************************************************************/
// Fields in remote trace dictionaries
#define ZT_REMOTE_TRACE_FIELD__EVENT "event"
#define ZT_REMOTE_TRACE_FIELD__NODE_ID "nodeId"
#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "packetId"
#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "packetVerb"
#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "packetTrustedPathId"
#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "packetTrustedPathApproved"
#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "packetHops"
#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "remoteZtAddr"
#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "remotePhyAddr"
#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "localZtAddr"
#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "localPhyAddr"
#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "localSocket"
#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "phyAddrIpScope"
#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "networkId"
#define ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR "sourceZtAddr"
#define ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR "destZtAddr"
#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "sourceMac"
#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "destMac"
#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "etherType"
#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlanId"
#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "frameLength"
#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "frameData"
#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE "filterNoTee"
#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND "filterInbound"
#define ZT_REMOTE_TRACE_FIELD__FILTER_RESULT "filterResult"
#define ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG "filterBaseRuleLog"
#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG "filterCapRuleLog"
#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID "filterMatchingCapId"
#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credType"
#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credId"
#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credTs"
#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credInfo"
#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "credIssuedTo"
#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "credRevocationTarget"
#define ZT_REMOTE_TRACE_FIELD__REASON "reason"
#define ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID "networkControllerId"
// Event types in remote traces
#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000
#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1001
#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1002
#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1003
#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1004
#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1005
#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO 0x1006
#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED 0x2000
#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED 0x2001
#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED 0x2002
#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED 0x2003
#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED 0x2004
#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT 0x2005
#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE 0x2006
// Event types in remote traces in hex string form
#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000"
#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1001"
#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1002"
#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1003"
#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1004"
#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1005"
#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006"
#define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000"
#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001"
#define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002"
#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003"
#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004"
#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S "2005"
#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S "2006"
/****************************************************************************/
/* Structures and other types */
/****************************************************************************/
@ -397,35 +321,6 @@ enum ZT_ResultCode
*/
#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
*/
@ -499,87 +394,23 @@ enum ZT_Event
*
* Meta-data: ZT_UserMessage structure
*/
ZT_EVENT_USER_MESSAGE = 6,
/**
* Remote trace received
*
* NOTE: any node can fling a VERB_REMOTE_TRACE at you. It's up to you
* to determine if you want to do anything with it or just silently
* drop it on the floor. It's also up to you to handle these securely!
*
* Meta-data: ZT_RemoteTrace structure
*/
ZT_EVENT_REMOTE_TRACE = 7
ZT_EVENT_USER_MESSAGE = 6
};
/**
* A root server
* Identity type codes
*/
typedef struct {
/**
* Name of root
*
* This will be a DNS name for dynamic roots. For static roots
* it will be the ZeroTier address. The presence or absence
* of a dot is used internally as a distinguisher.
*/
const char *name;
/**
* Serialized locator
*/
const void *locator;
/**
* The size of locator in bytes
*/
unsigned int locatorSize;
} 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
enum ZT_Identity_Type
{
/**
* ZeroTier address of sender (in least significant 40 bits only)
*/
uint64_t origin;
/* These values must be the same as in Identity.hpp in the core. */
ZT_IDENTITY_TYPE_C25519 = 0,
ZT_IDENTITY_TYPE_P384 = 1
};
/**
* Null-terminated Dictionary containing key/value pairs sent by origin
*
* This *should* be a dictionary, but the implementation only checks
* that it is a valid non-empty C-style null-terminated string. Be very
* careful to use a well-tested parser to parse this as it represents
* data received from a potentially un-trusted peer on the network.
* Invalid payloads should be dropped.
*
* The contents of data[] may be modified.
*/
const char *data;
/**
* Length of dict[] in bytes, INCLUDING terminating null
*/
unsigned int len;
} ZT_RemoteTrace;
/**
* A ZeroTier identity (opaque)
*/
typedef void ZT_Identity;
/**
* User message used with ZT_EVENT_USER_MESSAGE
@ -624,6 +455,11 @@ typedef struct
*/
uint64_t address;
/**
* Actual identity object for this node
*/
const ZT_Identity *identity;
/**
* Public identity in string-serialized form (safe to send to others)
*
@ -1000,39 +836,6 @@ enum ZT_VirtualNetworkConfigOperation
ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4
};
/**
* What trust hierarchy role does this peer have?
*/
enum ZT_PeerRole
{
ZT_PEER_ROLE_LEAF = 0, // ordinary node
ZT_PEER_ROLE_MOON = 1, // moon root
ZT_PEER_ROLE_PLANET = 2 // planetary root
};
/**
* 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
*/
@ -1180,56 +983,6 @@ typedef struct
*/
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 alive?
*/
@ -1241,6 +994,15 @@ typedef struct
int preferred;
} ZT_PeerPhysicalPath;
/**
* What trust hierarchy role does this peer have?
*/
enum ZT_PeerRole
{
ZT_PEER_ROLE_LEAF = 0, // ordinary node
ZT_PEER_ROLE_ROOT = 1 // root server
};
/**
* Peer status result buffer
*/
@ -1251,6 +1013,11 @@ typedef struct
*/
uint64_t address;
/**
* Peer identity
*/
const ZT_Identity *identity;
/**
* Remote major version or -1 if not known
*/
@ -1281,11 +1048,6 @@ typedef struct
*/
unsigned int pathCount;
/**
* Whether this peer was ever reachable via an aggregate link
*/
int hadAggregateLink;
/**
* Known network paths to peer
*/
@ -1541,8 +1303,9 @@ typedef int (*ZT_PathCheckFunction)(
* (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
* (4) Identity in string form
* (5) Desired address family or -1 for any
* (6) 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
@ -1554,53 +1317,10 @@ typedef int (*ZT_PathLookupFunction)(
void *, /* User ptr */
void *, /* Thread ptr */
uint64_t, /* ZeroTier address (40 bits) */
const ZT_Identity *, /* Full identity of node */
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 */
/****************************************************************************/
@ -1641,17 +1361,12 @@ struct ZT_Node_Callbacks
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
* OPTIONAL: Function to check whether a given physical path should be used for ZeroTier traffic
*/
ZT_PathCheckFunction pathCheckFunction;
/**
* OPTIONAL: Function to get hints to physical paths to ZeroTier addresses
* RECOMMENDED: Function to look up paths to ZeroTier nodes
*/
ZT_PathLookupFunction pathLookupFunction;
};
@ -1750,60 +1465,6 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(
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
*
@ -1884,36 +1545,25 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt
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
* Add a root server (has no effect if already added)
*
* @param node Node instance
* @param now Current time
* @return List of roots, use ZT_Node_freeQueryResult to free this when done
* @param identity Identity of this root server in string format
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now);
ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,const char *identity);
/**
* Add or update a root
* Remove a root server
*
* The node will begin trying to resolve the DNS TXT record for
* this root and possibly obtain it from other peers.
* This removes this node's root designation but does not prevent this node
* from communicating with it or close active paths to it.
*
* @param node Node instance
* @param name DNS name or simply the address in hex form for static roots
* @param locator Binary-serialized locator of NULL if none
* @param locatorSize Size of locator or 0 if none
* @return OK (0) or error code
* @param identity Identity in string format
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize);
/**
* Remove a dynamic root
*
* @param node Node instance
* @param name DNS name of this dynamic root or the address in hex form for static roots
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name);
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *identity);
/**
* Get this node's 40-bit ZeroTier address
@ -2035,6 +1685,115 @@ ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterIns
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
/**
* Generate a new identity
*
* Due to a small amount of proof of work this can be a time consuming and CPU
* intensive operation. It takes less than a second on most desktop-class systems
* but can take longer on e.g. phones.
*
* @param type Type of identity to generate
* @return New identity or NULL on error
*/
ZT_SDK_API ZT_Identity *ZT_Identity_new(enum ZT_Identity_Type type);
/**
* Create a new identity object from a string-serialized identity
*
* @param idStr Identity in string format
* @return Identity object or NULL if the supplied identity string was not valid
*/
ZT_SDK_API ZT_Identity *ZT_Identity_fromString(const char *idStr);
/**
* Validate this identity
*
* This can be slightly time consuming due to address derivation (work) checking.
*
* @return Non-zero if identity is valid
*/
ZT_SDK_API int ZT_Identity_validate(const ZT_Identity *id);
/**
* Sign a data object with this identity
*
* The identity must have a private key or this will fail.
*
* @param id Identity to use to sign
* @param data Data to sign
* @param len Length of data
* @param signature Buffer to store signature
* @param signatureBufferLength Length of buffer (must be at least 96 bytes)
* @return Length of signature in bytes or 0 on failure.
*/
ZT_SDK_API unsigned int ZT_Identity_sign(const ZT_Identity *id,const void *data,unsigned int len,void *signature,unsigned int signatureBufferLength);
/**
* Verify a signature
*
* @param id Identity to use to verify
* @param data Data to verify
* @param len Length of data
* @param signature Signature to check
* @param sigLen Length of signature in bytes
* @return Non-zero if signature is valid
*/
ZT_SDK_API int ZT_Identity_verify(const ZT_Identity *id,const void *data,unsigned int len,const void *signature,unsigned int sigLen);
/**
* Get identity type
*
* @param id Identity to query
* @return Identity type code
*/
ZT_SDK_API enum ZT_Identity_Type ZT_Identity_type(const ZT_Identity *id);
/**
* Convert an identity to its string representation
*
* @param id Identity to convert
* @param buf Buffer to store identity (should be at least about 1024 bytes in length)
* @param capacity Capacity of buffer
* @param includePrivate If true include the private key if present
* @return Pointer to buf or NULL on overflow or other error
*/
ZT_SDK_API char *ZT_Identity_toString(const ZT_Identity *id,char *buf,int capacity,int includePrivate);
/**
* Check whether this identity object also holds a private key
*
* @param id Identity to query
* @return Non-zero if a private key is held
*/
ZT_SDK_API int ZT_Identity_hasPrivate(const ZT_Identity *id);
/**
* Get the ZeroTier address associated with this identity
*
* @param id Identity to query
* @return ZeroTier address (only least significant 40 bits are meaningful, rest will be 0)
*/
ZT_SDK_API uint64_t ZT_Identity_address(const ZT_Identity *id);
/**
* Compute a hash of this identity's public keys (or both public and private if includePrivate is true)
*
* @param id Identity to query
* @param h Buffer for 384-bit hash
* @param includePrivate If true include private keys if any
*/
ZT_SDK_API void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate);
/**
* Delete an identity and free associated memory
*
* This should only be used with identities created via Identity_new
* and Identity_fromString().
*
* @param id Identity to delete
*/
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id);
/**
* Get ZeroTier One version
*

@ -1,168 +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 is done in plain C because the compiler (at least GCC and CLANG) seem
* to do a *slightly* better job optimizing this intrinsic code when compiling
* plain C. C also gives us the register hint keyword, which seems to actually
* make a small difference. */
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <stdint.h>
#include <wmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#define ZT_AES_CTR_AESNI_ROUND(kk) c0 = _mm_aesenc_si128(c0,kk); c1 = _mm_aesenc_si128(c1,kk); c2 = _mm_aesenc_si128(c2,kk); c3 = _mm_aesenc_si128(c3,kk);
void zt_crypt_ctr_aesni(const __m128i key[14],const uint8_t iv[16],const uint8_t *in,unsigned int len,uint8_t *out)
{
/* Because our CTR supports full 128-bit nonces, we must do a full 128-bit (big-endian)
* increment to be compatible with canonical NIST-certified CTR implementations. That's
* because it's possible to have a lot of bit saturation in the least significant 64
* bits, which could on rare occasions actually cause a 64-bit wrap. If this happened
* without carry it would result in incompatibility and quietly dropped packets. The
* probability is low, so this would be a one in billions packet loss bug that would
* probably never be found.
*
* This crazy code does a branch-free 128-bit increment by adding a one or a zero to
* the most significant 64 bits of the 128-bit vector based on whether the add we want
* to do to the least significant 64 bits would overflow. This can be computed by
* NOTing those bits and comparing with what we want to add, since NOT is the same
* as subtracting from uint64_max. This generates branch-free ASM on x64 with most
* good compilers. */
register __m128i swap128 = _mm_set_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
register __m128i ctr0 = _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)iv),swap128);
register uint64_t notctr0msq = ~((uint64_t)_mm_extract_epi64(ctr0,0));
register __m128i ctr1 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 1ULL),1LL)),swap128);
register __m128i ctr2 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 2ULL),2LL)),swap128);
register __m128i ctr3 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 3ULL),3LL)),swap128);
ctr0 = _mm_shuffle_epi8(ctr0,swap128);
register __m128i k0 = key[0];
register __m128i k1 = key[1];
while (len >= 64) {
register __m128i ka = key[2];
register __m128i c0 = _mm_xor_si128(ctr0,k0);
register __m128i c1 = _mm_xor_si128(ctr1,k0);
register __m128i c2 = _mm_xor_si128(ctr2,k0);
register __m128i c3 = _mm_xor_si128(ctr3,k0);
ctr0 = _mm_shuffle_epi8(ctr0,swap128);
notctr0msq = ~((uint64_t)_mm_extract_epi64(ctr0,0));
ctr1 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 5ULL),5LL)),swap128);
ctr2 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 6ULL),6LL)),swap128);
ctr3 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 7ULL),7LL)),swap128);
ctr0 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 4ULL),4LL)),swap128);
register __m128i kb = key[3];
ZT_AES_CTR_AESNI_ROUND(k1);
register __m128i kc = key[4];
ZT_AES_CTR_AESNI_ROUND(ka);
register __m128i kd = key[5];
ZT_AES_CTR_AESNI_ROUND(kb);
ka = key[6];
ZT_AES_CTR_AESNI_ROUND(kc);
kb = key[7];
ZT_AES_CTR_AESNI_ROUND(kd);
kc = key[8];
ZT_AES_CTR_AESNI_ROUND(ka);
kd = key[9];
ZT_AES_CTR_AESNI_ROUND(kb);
ka = key[10];
ZT_AES_CTR_AESNI_ROUND(kc);
kb = key[11];
ZT_AES_CTR_AESNI_ROUND(kd);
kc = key[12];
ZT_AES_CTR_AESNI_ROUND(ka);
kd = key[13];
ZT_AES_CTR_AESNI_ROUND(kb);
ka = key[14];
ZT_AES_CTR_AESNI_ROUND(kc);
ZT_AES_CTR_AESNI_ROUND(kd);
_mm_storeu_si128((__m128i *)out,_mm_xor_si128(_mm_loadu_si128((const __m128i *)in),_mm_aesenclast_si128(c0,ka)));
_mm_storeu_si128((__m128i *)(out + 16),_mm_xor_si128(_mm_loadu_si128((const __m128i *)(in + 16)),_mm_aesenclast_si128(c1,ka)));
_mm_storeu_si128((__m128i *)(out + 32),_mm_xor_si128(_mm_loadu_si128((const __m128i *)(in + 32)),_mm_aesenclast_si128(c2,ka)));
_mm_storeu_si128((__m128i *)(out + 48),_mm_xor_si128(_mm_loadu_si128((const __m128i *)(in + 48)),_mm_aesenclast_si128(c3,ka)));
in += 64;
out += 64;
len -= 64;
}
register __m128i k2 = key[2];
register __m128i k3 = key[3];
register __m128i k4 = key[4];
register __m128i k5 = key[5];
register __m128i k6 = key[6];
register __m128i k7 = key[7];
while (len >= 16) {
register __m128i c0 = _mm_xor_si128(ctr0,k0);
ctr0 = _mm_shuffle_epi8(ctr0,swap128);
ctr0 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)((~((uint64_t)_mm_extract_epi64(ctr0,0))) < 1ULL),1LL)),swap128);
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenc_si128(c0,k2);
c0 = _mm_aesenc_si128(c0,k3);
c0 = _mm_aesenc_si128(c0,k4);
c0 = _mm_aesenc_si128(c0,k5);
c0 = _mm_aesenc_si128(c0,k6);
register __m128i ka = key[8];
c0 = _mm_aesenc_si128(c0,k7);
register __m128i kb = key[9];
c0 = _mm_aesenc_si128(c0,ka);
ka = key[10];
c0 = _mm_aesenc_si128(c0,kb);
kb = key[11];
c0 = _mm_aesenc_si128(c0,ka);
ka = key[12];
c0 = _mm_aesenc_si128(c0,kb);
kb = key[13];
c0 = _mm_aesenc_si128(c0,ka);
ka = key[14];
c0 = _mm_aesenc_si128(c0,kb);
_mm_storeu_si128((__m128i *)out,_mm_xor_si128(_mm_loadu_si128((const __m128i *)in),_mm_aesenclast_si128(c0,ka)));
in += 16;
out += 16;
len -= 16;
}
if (len) {
register __m128i c0 = _mm_xor_si128(ctr0,k0);
k0 = key[8];
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenc_si128(c0,k2);
k1 = key[9];
c0 = _mm_aesenc_si128(c0,k3);
c0 = _mm_aesenc_si128(c0,k4);
k2 = key[10];
c0 = _mm_aesenc_si128(c0,k5);
c0 = _mm_aesenc_si128(c0,k6);
k3 = key[11];
c0 = _mm_aesenc_si128(c0,k7);
c0 = _mm_aesenc_si128(c0,k0);
k0 = key[12];
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenc_si128(c0,k2);
k1 = key[13];
c0 = _mm_aesenc_si128(c0,k3);
c0 = _mm_aesenc_si128(c0,k0);
k2 = key[14];
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenclast_si128(c0,k2);
uint8_t tmp[16];
_mm_storeu_si128((__m128i *)tmp,c0);
for(unsigned int i=0;i<len;++i)
out[i] = in[i] ^ tmp[i];
}
}
#endif

@ -11,12 +11,8 @@
*/
/****/
#include "AES.hpp"
#include "Constants.hpp"
// This file contains the software implementations of AES and GHASH. They're
// only used if your CPU lacks hardware acceleration as the hardware
// accelerated code is 10-20X as fast in most cases.
#include "AES.hpp"
#ifdef __WINDOWS__
#include <intrin.h>
@ -25,7 +21,7 @@
namespace ZeroTier {
#ifdef ZT_NO_TYPE_PUNNING
static ZT_ALWAYS_INLINE uint32_t readuint32_t(const void *in)
static inline uint32_t readuint32_t(const void *in)
{
uint32_t v = ((const uint8_t *)in)[0];
v <<= 8;
@ -36,7 +32,7 @@ static ZT_ALWAYS_INLINE uint32_t readuint32_t(const void *in)
v |= ((const uint8_t *)in)[3];
return v;
}
static ZT_ALWAYS_INLINE void writeuint32_t(void *out,const uint32_t v)
static inline void writeuint32_t(void *out,const uint32_t v)
{
((uint8_t *)out)[0] = (uint8_t)(v >> 24);
((uint8_t *)out)[1] = (uint8_t)(v >> 16);
@ -48,28 +44,6 @@ static ZT_ALWAYS_INLINE void writeuint32_t(void *out,const uint32_t v)
#define writeuint32_t(o,v) (*((uint32_t *)(o)) = Utils::hton(v))
#endif
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
static bool _zt_aesni_supported()
{
#ifdef __WINDOWS__
int regs[4];
__cpuid(regs,1);
return ( (((regs[2] >> 25) & 1) != 0) && (((regs[2] >> 19) & 1) != 0) && (((regs[2] >> 1) & 1) != 0) ); // AES-NI, SSE4.1, PCLMUL
#else
uint32_t eax,ebx,ecx,edx;
__asm__ __volatile__ (
"cpuid"
: "=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)
: "a"(1),"c"(0)
);
return ( ((ecx & (1 << 25)) != 0) && ((ecx & (1 << 19)) != 0) && ((ecx & (1 << 1)) != 0) ); // AES-NI, SSE4.1, PCLMUL
#endif
}
const bool AES::HW_ACCEL = _zt_aesni_supported();
#else
const bool AES::HW_ACCEL = false;
#endif
const uint32_t AES::Te0[256] = { 0xc66363a5,0xf87c7c84,0xee777799,0xf67b7b8d,0xfff2f20d,0xd66b6bbd,0xde6f6fb1,0x91c5c554,0x60303050,0x02010103,0xce6767a9,0x562b2b7d,0xe7fefe19,0xb5d7d762,0x4dababe6,0xec76769a,0x8fcaca45,0x1f82829d,0x89c9c940,0xfa7d7d87,0xeffafa15,0xb25959eb,0x8e4747c9,0xfbf0f00b,0x41adadec,0xb3d4d467,0x5fa2a2fd,0x45afafea,0x239c9cbf,0x53a4a4f7,0xe4727296,0x9bc0c05b,0x75b7b7c2,0xe1fdfd1c,0x3d9393ae,0x4c26266a,0x6c36365a,0x7e3f3f41,0xf5f7f702,0x83cccc4f,0x6834345c,0x51a5a5f4,0xd1e5e534,0xf9f1f108,0xe2717193,0xabd8d873,0x62313153,0x2a15153f,0x0804040c,0x95c7c752,0x46232365,0x9dc3c35e,0x30181828,0x379696a1,0x0a05050f,0x2f9a9ab5,0x0e070709,0x24121236,0x1b80809b,0xdfe2e23d,0xcdebeb26,0x4e272769,0x7fb2b2cd,0xea75759f,0x1209091b,0x1d83839e,0x582c2c74,0x341a1a2e,0x361b1b2d,0xdc6e6eb2,0xb45a5aee,0x5ba0a0fb,0xa45252f6,0x763b3b4d,0xb7d6d661,0x7db3b3ce,0x5229297b,0xdde3e33e,0x5e2f2f71,0x13848497,0xa65353f5,0xb9d1d168,0x00000000,0xc1eded2c,0x40202060,0xe3fcfc1f,0x79b1b1c8,0xb65b5bed,0xd46a6abe,0x8dcbcb46,0x67bebed9,0x7239394b,0x944a4ade,0x984c4cd4,0xb05858e8,0x85cfcf4a,0xbbd0d06b,0xc5efef2a,0x4faaaae5,0xedfbfb16,0x864343c5,0x9a4d4dd7,0x66333355,0x11858594,0x8a4545cf,0xe9f9f910,0x04020206,0xfe7f7f81,0xa05050f0,0x783c3c44,0x259f9fba,0x4ba8a8e3,0xa25151f3,0x5da3a3fe,0x804040c0,0x058f8f8a,0x3f9292ad,0x219d9dbc,0x70383848,0xf1f5f504,0x63bcbcdf,0x77b6b6c1,0xafdada75,0x42212163,0x20101030,0xe5ffff1a,0xfdf3f30e,0xbfd2d26d,0x81cdcd4c,0x180c0c14,0x26131335,0xc3ecec2f,0xbe5f5fe1,0x359797a2,0x884444cc,0x2e171739,0x93c4c457,0x55a7a7f2,0xfc7e7e82,0x7a3d3d47,0xc86464ac,0xba5d5de7,0x3219192b,0xe6737395,0xc06060a0,0x19818198,0x9e4f4fd1,0xa3dcdc7f,0x44222266,0x542a2a7e,0x3b9090ab,0x0b888883,0x8c4646ca,0xc7eeee29,0x6bb8b8d3,0x2814143c,0xa7dede79,0xbc5e5ee2,0x160b0b1d,0xaddbdb76,0xdbe0e03b,0x64323256,0x743a3a4e,0x140a0a1e,0x924949db,0x0c06060a,0x4824246c,0xb85c5ce4,0x9fc2c25d,0xbdd3d36e,0x43acacef,0xc46262a6,0x399191a8,0x319595a4,0xd3e4e437,0xf279798b,0xd5e7e732,0x8bc8c843,0x6e373759,0xda6d6db7,0x018d8d8c,0xb1d5d564,0x9c4e4ed2,0x49a9a9e0,0xd86c6cb4,0xac5656fa,0xf3f4f407,0xcfeaea25,0xca6565af,0xf47a7a8e,0x47aeaee9,0x10080818,0x6fbabad5,0xf0787888,0x4a25256f,0x5c2e2e72,0x381c1c24,0x57a6a6f1,0x73b4b4c7,0x97c6c651,0xcbe8e823,0xa1dddd7c,0xe874749c,0x3e1f1f21,0x964b4bdd,0x61bdbddc,0x0d8b8b86,0x0f8a8a85,0xe0707090,0x7c3e3e42,0x71b5b5c4,0xcc6666aa,0x904848d8,0x06030305,0xf7f6f601,0x1c0e0e12,0xc26161a3,0x6a35355f,0xae5757f9,0x69b9b9d0,0x17868691,0x99c1c158,0x3a1d1d27,0x279e9eb9,0xd9e1e138,0xebf8f813,0x2b9898b3,0x22111133,0xd26969bb,0xa9d9d970,0x078e8e89,0x339494a7,0x2d9b9bb6,0x3c1e1e22,0x15878792,0xc9e9e920,0x87cece49,0xaa5555ff,0x50282878,0xa5dfdf7a,0x038c8c8f,0x59a1a1f8,0x09898980,0x1a0d0d17,0x65bfbfda,0xd7e6e631,0x844242c6,0xd06868b8,0x824141c3,0x299999b0,0x5a2d2d77,0x1e0f0f11,0x7bb0b0cb,0xa85454fc,0x6dbbbbd6,0x2c16163a };
const uint32_t AES::Te1[256] = { 0xa5c66363,0x84f87c7c,0x99ee7777,0x8df67b7b,0x0dfff2f2,0xbdd66b6b,0xb1de6f6f,0x5491c5c5,0x50603030,0x03020101,0xa9ce6767,0x7d562b2b,0x19e7fefe,0x62b5d7d7,0xe64dabab,0x9aec7676,0x458fcaca,0x9d1f8282,0x4089c9c9,0x87fa7d7d,0x15effafa,0xebb25959,0xc98e4747,0x0bfbf0f0,0xec41adad,0x67b3d4d4,0xfd5fa2a2,0xea45afaf,0xbf239c9c,0xf753a4a4,0x96e47272,0x5b9bc0c0,0xc275b7b7,0x1ce1fdfd,0xae3d9393,0x6a4c2626,0x5a6c3636,0x417e3f3f,0x02f5f7f7,0x4f83cccc,0x5c683434,0xf451a5a5,0x34d1e5e5,0x08f9f1f1,0x93e27171,0x73abd8d8,0x53623131,0x3f2a1515,0x0c080404,0x5295c7c7,0x65462323,0x5e9dc3c3,0x28301818,0xa1379696,0x0f0a0505,0xb52f9a9a,0x090e0707,0x36241212,0x9b1b8080,0x3ddfe2e2,0x26cdebeb,0x694e2727,0xcd7fb2b2,0x9fea7575,0x1b120909,0x9e1d8383,0x74582c2c,0x2e341a1a,0x2d361b1b,0xb2dc6e6e,0xeeb45a5a,0xfb5ba0a0,0xf6a45252,0x4d763b3b,0x61b7d6d6,0xce7db3b3,0x7b522929,0x3edde3e3,0x715e2f2f,0x97138484,0xf5a65353,0x68b9d1d1,0x00000000,0x2cc1eded,0x60402020,0x1fe3fcfc,0xc879b1b1,0xedb65b5b,0xbed46a6a,0x468dcbcb,0xd967bebe,0x4b723939,0xde944a4a,0xd4984c4c,0xe8b05858,0x4a85cfcf,0x6bbbd0d0,0x2ac5efef,0xe54faaaa,0x16edfbfb,0xc5864343,0xd79a4d4d,0x55663333,0x94118585,0xcf8a4545,0x10e9f9f9,0x06040202,0x81fe7f7f,0xf0a05050,0x44783c3c,0xba259f9f,0xe34ba8a8,0xf3a25151,0xfe5da3a3,0xc0804040,0x8a058f8f,0xad3f9292,0xbc219d9d,0x48703838,0x04f1f5f5,0xdf63bcbc,0xc177b6b6,0x75afdada,0x63422121,0x30201010,0x1ae5ffff,0x0efdf3f3,0x6dbfd2d2,0x4c81cdcd,0x14180c0c,0x35261313,0x2fc3ecec,0xe1be5f5f,0xa2359797,0xcc884444,0x392e1717,0x5793c4c4,0xf255a7a7,0x82fc7e7e,0x477a3d3d,0xacc86464,0xe7ba5d5d,0x2b321919,0x95e67373,0xa0c06060,0x98198181,0xd19e4f4f,0x7fa3dcdc,0x66442222,0x7e542a2a,0xab3b9090,0x830b8888,0xca8c4646,0x29c7eeee,0xd36bb8b8,0x3c281414,0x79a7dede,0xe2bc5e5e,0x1d160b0b,0x76addbdb,0x3bdbe0e0,0x56643232,0x4e743a3a,0x1e140a0a,0xdb924949,0x0a0c0606,0x6c482424,0xe4b85c5c,0x5d9fc2c2,0x6ebdd3d3,0xef43acac,0xa6c46262,0xa8399191,0xa4319595,0x37d3e4e4,0x8bf27979,0x32d5e7e7,0x438bc8c8,0x596e3737,0xb7da6d6d,0x8c018d8d,0x64b1d5d5,0xd29c4e4e,0xe049a9a9,0xb4d86c6c,0xfaac5656,0x07f3f4f4,0x25cfeaea,0xafca6565,0x8ef47a7a,0xe947aeae,0x18100808,0xd56fbaba,0x88f07878,0x6f4a2525,0x725c2e2e,0x24381c1c,0xf157a6a6,0xc773b4b4,0x5197c6c6,0x23cbe8e8,0x7ca1dddd,0x9ce87474,0x213e1f1f,0xdd964b4b,0xdc61bdbd,0x860d8b8b,0x850f8a8a,0x90e07070,0x427c3e3e,0xc471b5b5,0xaacc6666,0xd8904848,0x05060303,0x01f7f6f6,0x121c0e0e,0xa3c26161,0x5f6a3535,0xf9ae5757,0xd069b9b9,0x91178686,0x5899c1c1,0x273a1d1d,0xb9279e9e,0x38d9e1e1,0x13ebf8f8,0xb32b9898,0x33221111,0xbbd26969,0x70a9d9d9,0x89078e8e,0xa7339494,0xb62d9b9b,0x223c1e1e,0x92158787,0x20c9e9e9,0x4987cece,0xffaa5555,0x78502828,0x7aa5dfdf,0x8f038c8c,0xf859a1a1,0x80098989,0x171a0d0d,0xda65bfbf,0x31d7e6e6,0xc6844242,0xb8d06868,0xc3824141,0xb0299999,0x775a2d2d,0x111e0f0f,0xcb7bb0b0,0xfca85454,0xd66dbbbb,0x3a2c1616 };
const uint32_t AES::Te2[256] = { 0x63a5c663,0x7c84f87c,0x7799ee77,0x7b8df67b,0xf20dfff2,0x6bbdd66b,0x6fb1de6f,0xc55491c5,0x30506030,0x01030201,0x67a9ce67,0x2b7d562b,0xfe19e7fe,0xd762b5d7,0xabe64dab,0x769aec76,0xca458fca,0x829d1f82,0xc94089c9,0x7d87fa7d,0xfa15effa,0x59ebb259,0x47c98e47,0xf00bfbf0,0xadec41ad,0xd467b3d4,0xa2fd5fa2,0xafea45af,0x9cbf239c,0xa4f753a4,0x7296e472,0xc05b9bc0,0xb7c275b7,0xfd1ce1fd,0x93ae3d93,0x266a4c26,0x365a6c36,0x3f417e3f,0xf702f5f7,0xcc4f83cc,0x345c6834,0xa5f451a5,0xe534d1e5,0xf108f9f1,0x7193e271,0xd873abd8,0x31536231,0x153f2a15,0x040c0804,0xc75295c7,0x23654623,0xc35e9dc3,0x18283018,0x96a13796,0x050f0a05,0x9ab52f9a,0x07090e07,0x12362412,0x809b1b80,0xe23ddfe2,0xeb26cdeb,0x27694e27,0xb2cd7fb2,0x759fea75,0x091b1209,0x839e1d83,0x2c74582c,0x1a2e341a,0x1b2d361b,0x6eb2dc6e,0x5aeeb45a,0xa0fb5ba0,0x52f6a452,0x3b4d763b,0xd661b7d6,0xb3ce7db3,0x297b5229,0xe33edde3,0x2f715e2f,0x84971384,0x53f5a653,0xd168b9d1,0x00000000,0xed2cc1ed,0x20604020,0xfc1fe3fc,0xb1c879b1,0x5bedb65b,0x6abed46a,0xcb468dcb,0xbed967be,0x394b7239,0x4ade944a,0x4cd4984c,0x58e8b058,0xcf4a85cf,0xd06bbbd0,0xef2ac5ef,0xaae54faa,0xfb16edfb,0x43c58643,0x4dd79a4d,0x33556633,0x85941185,0x45cf8a45,0xf910e9f9,0x02060402,0x7f81fe7f,0x50f0a050,0x3c44783c,0x9fba259f,0xa8e34ba8,0x51f3a251,0xa3fe5da3,0x40c08040,0x8f8a058f,0x92ad3f92,0x9dbc219d,0x38487038,0xf504f1f5,0xbcdf63bc,0xb6c177b6,0xda75afda,0x21634221,0x10302010,0xff1ae5ff,0xf30efdf3,0xd26dbfd2,0xcd4c81cd,0x0c14180c,0x13352613,0xec2fc3ec,0x5fe1be5f,0x97a23597,0x44cc8844,0x17392e17,0xc45793c4,0xa7f255a7,0x7e82fc7e,0x3d477a3d,0x64acc864,0x5de7ba5d,0x192b3219,0x7395e673,0x60a0c060,0x81981981,0x4fd19e4f,0xdc7fa3dc,0x22664422,0x2a7e542a,0x90ab3b90,0x88830b88,0x46ca8c46,0xee29c7ee,0xb8d36bb8,0x143c2814,0xde79a7de,0x5ee2bc5e,0x0b1d160b,0xdb76addb,0xe03bdbe0,0x32566432,0x3a4e743a,0x0a1e140a,0x49db9249,0x060a0c06,0x246c4824,0x5ce4b85c,0xc25d9fc2,0xd36ebdd3,0xacef43ac,0x62a6c462,0x91a83991,0x95a43195,0xe437d3e4,0x798bf279,0xe732d5e7,0xc8438bc8,0x37596e37,0x6db7da6d,0x8d8c018d,0xd564b1d5,0x4ed29c4e,0xa9e049a9,0x6cb4d86c,0x56faac56,0xf407f3f4,0xea25cfea,0x65afca65,0x7a8ef47a,0xaee947ae,0x08181008,0xbad56fba,0x7888f078,0x256f4a25,0x2e725c2e,0x1c24381c,0xa6f157a6,0xb4c773b4,0xc65197c6,0xe823cbe8,0xdd7ca1dd,0x749ce874,0x1f213e1f,0x4bdd964b,0xbddc61bd,0x8b860d8b,0x8a850f8a,0x7090e070,0x3e427c3e,0xb5c471b5,0x66aacc66,0x48d89048,0x03050603,0xf601f7f6,0x0e121c0e,0x61a3c261,0x355f6a35,0x57f9ae57,0xb9d069b9,0x86911786,0xc15899c1,0x1d273a1d,0x9eb9279e,0xe138d9e1,0xf813ebf8,0x98b32b98,0x11332211,0x69bbd269,0xd970a9d9,0x8e89078e,0x94a73394,0x9bb62d9b,0x1e223c1e,0x87921587,0xe920c9e9,0xce4987ce,0x55ffaa55,0x28785028,0xdf7aa5df,0x8c8f038c,0xa1f859a1,0x89800989,0x0d171a0d,0xbfda65bf,0xe631d7e6,0x42c68442,0x68b8d068,0x41c38241,0x99b02999,0x2d775a2d,0x0f111e0f,0xb0cb7bb0,0x54fca854,0xbbd66dbb,0x163a2c16 };
@ -175,6 +149,39 @@ void AES::_encryptSW(const uint8_t in[16],uint8_t out[16]) const
writeuint32_t(out + 12,(Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2) & 0xff] & 0x000000ff) ^ rk[59]);
}
void AES::_ctrSW(const uint8_t iv[16],const void *in,unsigned int len,void *out) const
{
uint64_t ctr[2],cenc[2];
memcpy(ctr,iv,16);
uint64_t bctr = Utils::ntoh(ctr[1]);
const uint8_t *i = (const uint8_t *)in;
uint8_t *o = (uint8_t *)out;
while (len >= 16) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
ctr[1] = Utils::hton(++bctr);
#ifdef ZT_NO_TYPE_PUNNING
for(unsigned int k=0;k<16;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
#else
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[0];
o += 8;
i += 8;
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[1];
o += 8;
i += 8;
#endif
len -= 16;
}
if (len) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
for(unsigned int k=0;k<len;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
}
}
#if (defined(__GNUC__) || defined(__clang)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64) || defined(__aarch64__))
#if defined(__SIZEOF_INT128__)
@ -183,7 +190,7 @@ typedef unsigned __int128 uint128_t;
typedef unsigned uint128_t __attribute__((mode(TI)));
#endif
static ZT_ALWAYS_INLINE void s_bmul64(const uint64_t x,const uint64_t y,uint64_t &r_high,uint64_t &r_low)
static inline void s_bmul64(const uint64_t x,const uint64_t y,uint64_t &r_high,uint64_t &r_low)
{
static uint128_t m1 = (uint128_t)0x2108421084210842ULL << 64 | 0x1084210842108421ULL;
static uint128_t m2 = (uint128_t)0x4210842108421084ULL << 64 | 0x2108421084210842ULL;
@ -214,7 +221,7 @@ static ZT_ALWAYS_INLINE void s_bmul64(const uint64_t x,const uint64_t y,uint64_t
r_low = (uint64_t)r;
}
static ZT_ALWAYS_INLINE void s_gfmul(const uint64_t h_high,const uint64_t h_low,uint64_t &y0, uint64_t &y1)
static inline void s_gfmul(const uint64_t h_high,const uint64_t h_low,uint64_t &y0, uint64_t &y1)
{
uint64_t z2_low,z2_high,z0_low,z0_high,z1a_low,z1a_high;
uint64_t y_high = Utils::ntoh(y0);
@ -236,7 +243,7 @@ static ZT_ALWAYS_INLINE void s_gfmul(const uint64_t h_high,const uint64_t h_low,
#else
static ZT_ALWAYS_INLINE void s_bmul32(uint32_t x,uint32_t y,uint32_t &r_high,uint32_t &r_low)
static inline void s_bmul32(uint32_t x,uint32_t y,uint32_t &r_high,uint32_t &r_low)
{
const uint32_t m1 = (uint32_t)0x11111111;
const uint32_t m2 = (uint32_t)0x22222222;
@ -263,7 +270,7 @@ static ZT_ALWAYS_INLINE void s_bmul32(uint32_t x,uint32_t y,uint32_t &r_high,uin
r_low = (uint32_t)z;
}
static ZT_ALWAYS_INLINE void s_gfmul(const uint64_t h_high,const uint64_t h_low,uint64_t &y0,uint64_t &y1)
static inline void s_gfmul(const uint64_t h_high,const uint64_t h_low,uint64_t &y0,uint64_t &y1)
{
uint32_t h_high_h = (uint32_t)(h_high >> 32);
uint32_t h_high_l = (uint32_t)h_high;
@ -337,9 +344,8 @@ void AES::_gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y1)[i] ^= *(in++);
#else
y0 ^= *((const uint64_t *)in);
in += 8;
y1 ^= *((const uint64_t *)in);
in += 8;
y1 ^= *((const uint64_t *)(in + 8));
in += 16;
#endif
s_gfmul(h0,h1,y0,y1);
len -= 16;

@ -18,35 +18,24 @@
#include "Utils.hpp"
#include "SHA512.hpp"
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <cstdint>
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <xmmintrin.h>
#include <wmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#define ZT_AES_AESNI 1
// AES-aesni.c
extern "C" void zt_crypt_ctr_aesni(const __m128i key[14],const uint8_t iv[16],const uint8_t *in,unsigned int len,uint8_t *out);
#endif // x64
#define ZT_AES_KEY_SIZE 32
#define ZT_AES_BLOCK_SIZE 16
#endif
namespace ZeroTier {
/**
* AES-256 and pals
* AES-256 and pals including GMAC, CTR, etc.
*/
class AES
{
public:
/**
* This will be true if your platform's type of AES acceleration is supported on this machine
*/
static const bool HW_ACCEL;
ZT_ALWAYS_INLINE AES() {}
ZT_ALWAYS_INLINE AES(const uint8_t key[32]) { this->init(key); }
ZT_ALWAYS_INLINE ~AES() { Utils::burn(&_k,sizeof(_k)); }
@ -57,12 +46,11 @@ public:
ZT_ALWAYS_INLINE void init(const uint8_t key[32])
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
if (likely(Utils::CPUID.aes)) {
_init_aesni(key);
return;
}
#endif
_initSW(key);
}
@ -75,12 +63,11 @@ public:
ZT_ALWAYS_INLINE void encrypt(const uint8_t in[16],uint8_t out[16]) const
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
if (likely(Utils::CPUID.aes)) {
_encrypt_aesni(in,out);
return;
}
#endif
_encryptSW(in,out);
}
@ -95,12 +82,11 @@ public:
ZT_ALWAYS_INLINE void gmac(const uint8_t iv[12],const void *in,const unsigned int len,uint8_t out[16]) const
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
if (likely(Utils::CPUID.aes)) {
_gmac_aesni(iv,(const uint8_t *)in,len,out);
return;
}
#endif
_gmacSW(iv,(const uint8_t *)in,len,out);
}
@ -119,41 +105,12 @@ public:
ZT_ALWAYS_INLINE void ctr(const uint8_t iv[16],const void *in,unsigned int len,void *out) const
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
zt_crypt_ctr_aesni(_k.ni.k,iv,(const uint8_t *)in,len,(uint8_t *)out);
if (likely(Utils::CPUID.aes)) {
_ctr_aesni(_k.ni.k,iv,(const uint8_t *)in,len,(uint8_t *)out);
return;
}
#endif
uint64_t ctr[2],cenc[2];
memcpy(ctr,iv,16);
uint64_t bctr = Utils::ntoh(ctr[1]);
const uint8_t *i = (const uint8_t *)in;
uint8_t *o = (uint8_t *)out;
while (len >= 16) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
ctr[1] = Utils::hton(++bctr);
#ifdef ZT_NO_TYPE_PUNNING
for(unsigned int k=0;k<16;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
#else
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[0];
o += 8;
i += 8;
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[1];
o += 8;
i += 8;
#endif
len -= 16;
}
if (len) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
for(unsigned int k=0;k<len;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
}
_ctrSW(iv,in,len,out);
}
/**
@ -187,7 +144,7 @@ public:
* @param out Output buffer to receive ciphertext
* @param tag Output buffer to receive 64-bit authentication tag
*/
static ZT_ALWAYS_INLINE void gmacSivEncrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[8],const uint8_t pc,const void *in,const unsigned int len,void *out,uint8_t tag[8])
static inline void gmacSivEncrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[8],const uint8_t pc,const void *in,const unsigned int len,void *out,uint8_t tag[8])
{
#ifdef __GNUC__
uint8_t __attribute__ ((aligned (16))) miv[12];
@ -246,7 +203,7 @@ public:
* @param tag Authentication tag supplied with message
* @return True if authentication tags match and message appears authentic
*/
static ZT_ALWAYS_INLINE bool gmacSivDecrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[8],const uint8_t pc,const void *in,const unsigned int len,void *out,const uint8_t tag[8])
static inline bool gmacSivDecrypt(const AES &k1,const AES &k2,const AES &k3,const AES &k4,const uint8_t iv[8],const uint8_t pc,const void *in,const unsigned int len,void *out,const uint8_t tag[8])
{
#ifdef __GNUC__
uint8_t __attribute__ ((aligned (16))) miv[12];
@ -307,7 +264,7 @@ public:
* @param k3 CTR IV keyed hash key
* @param k4 AES-CTR key
*/
static ZT_ALWAYS_INLINE void initGmacCtrKeys(const uint8_t masterKey[32],AES &k1,AES &k2,AES &k3,AES &k4)
static inline void initGmacCtrKeys(const uint8_t masterKey[32],AES &k1,AES &k2,AES &k3,AES &k4)
{
uint8_t k[32];
KBKDFHMACSHA384(masterKey,ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K1,0,0,k);
@ -329,6 +286,7 @@ private:
void _initSW(const uint8_t key[32]);
void _encryptSW(const uint8_t in[16],uint8_t out[16]) const;
void _ctrSW(const uint8_t iv[16],const void *in,unsigned int len,void *out) const;
void _gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_t out[16]) const;
/**************************************************************************/
@ -529,7 +487,7 @@ private:
_mm_storeu_si128((__m128i *)out,_mm_aesenclast_si128(tmp,_k.ni.k[14]));
}
static ZT_ALWAYS_INLINE __m128i _mult_block_aesni(__m128i shuf,__m128i h,__m128i y)
static ZT_ALWAYS_INLINE inline __m128i _mult_block_aesni(__m128i shuf,__m128i h,__m128i y)
{
y = _mm_shuffle_epi8(y,shuf);
__m128i t1 = _mm_clmulepi64_si128(h,y,0x00);
@ -569,7 +527,7 @@ private:
t4 = _mm_xor_si128(t4,t5);
return _mm_shuffle_epi8(t4,shuf);
}
static ZT_ALWAYS_INLINE __m128i _ghash_aesni(__m128i shuf,__m128i h,__m128i y,__m128i x) { return _mult_block_aesni(shuf,h,_mm_xor_si128(y,x)); }
static inline __m128i _ghash_aesni(__m128i shuf,__m128i h,__m128i y,__m128i x) { return _mult_block_aesni(shuf,h,_mm_xor_si128(y,x)); }
ZT_ALWAYS_INLINE void _gmac_aesni(const uint8_t iv[12],const uint8_t *in,const unsigned int len,uint8_t out[16]) const
{
@ -687,6 +645,148 @@ private:
t = _mm_aesenclast_si128(t,_k.ni.k[14]);
_mm_storeu_si128((__m128i *)out,_mm_xor_si128(y,t));
}
#define ZT_AES_CTR_AESNI_ROUND(kk) c0 = _mm_aesenc_si128(c0,kk); c1 = _mm_aesenc_si128(c1,kk); c2 = _mm_aesenc_si128(c2,kk); c3 = _mm_aesenc_si128(c3,kk);
static ZT_ALWAYS_INLINE void _ctr_aesni(const __m128i key[14],const uint8_t iv[16],const uint8_t *in,unsigned int len,uint8_t *out)
{
/* Because our CTR supports full 128-bit nonces, we must do a full 128-bit (big-endian)
* increment to be compatible with canonical NIST-certified CTR implementations. That's
* because it's possible to have a lot of bit saturation in the least significant 64
* bits, which could on rare occasions actually cause a 64-bit wrap. If this happened
* without carry it would result in incompatibility and quietly dropped packets. The
* probability is low, so this would be a one in billions packet loss bug that would
* probably never be found.
*
* This crazy code does a branch-free 128-bit increment by adding a one or a zero to
* the most significant 64 bits of the 128-bit vector based on whether the add we want
* to do to the least significant 64 bits would overflow. This can be computed by
* NOTing those bits and comparing with what we want to add, since NOT is the same
* as subtracting from uint64_max. This generates branch-free ASM on x64 with most
* good compilers. */
__m128i swap128 = _mm_set_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
__m128i ctr0 = _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)iv),swap128);
uint64_t notctr0msq = ~((uint64_t)_mm_extract_epi64(ctr0,0));
__m128i ctr1 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 1ULL),1LL)),swap128);
__m128i ctr2 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 2ULL),2LL)),swap128);
__m128i ctr3 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 3ULL),3LL)),swap128);
ctr0 = _mm_shuffle_epi8(ctr0,swap128);
__m128i k0 = key[0];
__m128i k1 = key[1];
while (len >= 64) {
__m128i ka = key[2];
__m128i c0 = _mm_xor_si128(ctr0,k0);
__m128i c1 = _mm_xor_si128(ctr1,k0);
__m128i c2 = _mm_xor_si128(ctr2,k0);
__m128i c3 = _mm_xor_si128(ctr3,k0);
ctr0 = _mm_shuffle_epi8(ctr0,swap128);
notctr0msq = ~((uint64_t)_mm_extract_epi64(ctr0,0));
ctr1 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 5ULL),5LL)),swap128);
ctr2 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 6ULL),6LL)),swap128);
ctr3 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 7ULL),7LL)),swap128);
ctr0 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)(notctr0msq < 4ULL),4LL)),swap128);
__m128i kb = key[3];
ZT_AES_CTR_AESNI_ROUND(k1);
__m128i kc = key[4];
ZT_AES_CTR_AESNI_ROUND(ka);
__m128i kd = key[5];
ZT_AES_CTR_AESNI_ROUND(kb);
ka = key[6];
ZT_AES_CTR_AESNI_ROUND(kc);
kb = key[7];
ZT_AES_CTR_AESNI_ROUND(kd);
kc = key[8];
ZT_AES_CTR_AESNI_ROUND(ka);
kd = key[9];
ZT_AES_CTR_AESNI_ROUND(kb);
ka = key[10];
ZT_AES_CTR_AESNI_ROUND(kc);
kb = key[11];
ZT_AES_CTR_AESNI_ROUND(kd);
kc = key[12];
ZT_AES_CTR_AESNI_ROUND(ka);
kd = key[13];
ZT_AES_CTR_AESNI_ROUND(kb);
ka = key[14];
ZT_AES_CTR_AESNI_ROUND(kc);
ZT_AES_CTR_AESNI_ROUND(kd);
_mm_storeu_si128((__m128i *)out,_mm_xor_si128(_mm_loadu_si128((const __m128i *)in),_mm_aesenclast_si128(c0,ka)));
_mm_storeu_si128((__m128i *)(out + 16),_mm_xor_si128(_mm_loadu_si128((const __m128i *)(in + 16)),_mm_aesenclast_si128(c1,ka)));
_mm_storeu_si128((__m128i *)(out + 32),_mm_xor_si128(_mm_loadu_si128((const __m128i *)(in + 32)),_mm_aesenclast_si128(c2,ka)));
_mm_storeu_si128((__m128i *)(out + 48),_mm_xor_si128(_mm_loadu_si128((const __m128i *)(in + 48)),_mm_aesenclast_si128(c3,ka)));
in += 64;
out += 64;
len -= 64;
}
__m128i k2 = key[2];
__m128i k3 = key[3];
__m128i k4 = key[4];
__m128i k5 = key[5];
__m128i k6 = key[6];
__m128i k7 = key[7];
while (len >= 16) {
__m128i c0 = _mm_xor_si128(ctr0,k0);
ctr0 = _mm_shuffle_epi8(ctr0,swap128);
ctr0 = _mm_shuffle_epi8(_mm_add_epi64(ctr0,_mm_set_epi64x((long long)((~((uint64_t)_mm_extract_epi64(ctr0,0))) < 1ULL),1LL)),swap128);
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenc_si128(c0,k2);
c0 = _mm_aesenc_si128(c0,k3);
c0 = _mm_aesenc_si128(c0,k4);
c0 = _mm_aesenc_si128(c0,k5);
c0 = _mm_aesenc_si128(c0,k6);
__m128i ka = key[8];
c0 = _mm_aesenc_si128(c0,k7);
__m128i kb = key[9];
c0 = _mm_aesenc_si128(c0,ka);
ka = key[10];
c0 = _mm_aesenc_si128(c0,kb);
kb = key[11];
c0 = _mm_aesenc_si128(c0,ka);
ka = key[12];
c0 = _mm_aesenc_si128(c0,kb);
kb = key[13];
c0 = _mm_aesenc_si128(c0,ka);
ka = key[14];
c0 = _mm_aesenc_si128(c0,kb);
_mm_storeu_si128((__m128i *)out,_mm_xor_si128(_mm_loadu_si128((const __m128i *)in),_mm_aesenclast_si128(c0,ka)));
in += 16;
out += 16;
len -= 16;
}
if (len) {
__m128i c0 = _mm_xor_si128(ctr0,k0);
k0 = key[8];
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenc_si128(c0,k2);
k1 = key[9];
c0 = _mm_aesenc_si128(c0,k3);
c0 = _mm_aesenc_si128(c0,k4);
k2 = key[10];
c0 = _mm_aesenc_si128(c0,k5);
c0 = _mm_aesenc_si128(c0,k6);
k3 = key[11];
c0 = _mm_aesenc_si128(c0,k7);
c0 = _mm_aesenc_si128(c0,k0);
k0 = key[12];
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenc_si128(c0,k2);
k1 = key[13];
c0 = _mm_aesenc_si128(c0,k3);
c0 = _mm_aesenc_si128(c0,k0);
k2 = key[14];
c0 = _mm_aesenc_si128(c0,k1);
c0 = _mm_aesenclast_si128(c0,k2);
uint8_t tmp[16];
_mm_storeu_si128((__m128i *)tmp,c0);
for(unsigned int i=0;i<len;++i)
out[i] = in[i] ^ tmp[i];
}
}
#endif /* ZT_AES_AESNI ******************************************************/
};

@ -14,12 +14,15 @@
#ifndef ZT_ADDRESS_HPP
#define ZT_ADDRESS_HPP
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <algorithm>
#include "Constants.hpp"
#include "Utils.hpp"
@ -34,8 +37,7 @@ class Address
{
public:
ZT_ALWAYS_INLINE Address() : _a(0) {}
ZT_ALWAYS_INLINE Address(const Address &a) : _a(a._a) {}
ZT_ALWAYS_INLINE Address(uint64_t a) : _a(a & 0xffffffffffULL) {}
explicit ZT_ALWAYS_INLINE Address(uint64_t a) : _a(a & 0xffffffffffULL) {}
/**
* @param bits Raw address -- 5 bytes, big-endian byte order
@ -43,7 +45,6 @@ public:
*/
ZT_ALWAYS_INLINE Address(const void *bits,unsigned int len) { setTo(bits,len); }
ZT_ALWAYS_INLINE Address &operator=(const Address &a) { _a = a._a; return *this; }
ZT_ALWAYS_INLINE Address &operator=(const uint64_t a) { _a = (a & 0xffffffffffULL); return *this; }
/**
@ -105,18 +106,13 @@ public:
/**
* @return Hash code for use with Hashtable
*/
ZT_ALWAYS_INLINE unsigned long hashCode() const { return reinterpret_cast<unsigned long>(_a); }
ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)_a; }
/**
* @return Hexadecimal string
*/
ZT_ALWAYS_INLINE char *toString(char buf[11]) const { return Utils::hex10(_a,buf); }
/**
* @return True if this address is not zero
*/
ZT_ALWAYS_INLINE operator bool() const { return (_a != 0); }
/**
* Check if this address is reserved
*
@ -126,7 +122,7 @@ public:
*
* @return True if address is reserved and may not be used
*/
ZT_ALWAYS_INLINE bool isReserved() const { return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); }
ZT_ALWAYS_INLINE bool isReserved() const { return ((!_a)||((_a >> 32U) == ZT_ADDRESS_RESERVED_PREFIX)); }
/**
* @param i Value from 0 to 4 (inclusive)
@ -134,9 +130,10 @@ public:
*/
ZT_ALWAYS_INLINE uint8_t operator[](unsigned int i) const { return (uint8_t)(_a >> (32 - (i * 8))); }
ZT_ALWAYS_INLINE operator unsigned int() const { return reinterpret_cast<unsigned int>(_a); }
ZT_ALWAYS_INLINE operator unsigned long() const { return reinterpret_cast<unsigned long>(_a); }
ZT_ALWAYS_INLINE operator unsigned long long() const { return reinterpret_cast<unsigned long long>(_a); }
ZT_ALWAYS_INLINE operator bool() const { return (_a != 0); }
ZT_ALWAYS_INLINE operator unsigned int() const { return (unsigned int)_a; }
ZT_ALWAYS_INLINE operator unsigned long() const { return (unsigned long)_a; }
ZT_ALWAYS_INLINE operator unsigned long long() const { return (unsigned long long)_a; }
ZT_ALWAYS_INLINE void zero() { _a = 0; }
@ -154,6 +151,90 @@ public:
ZT_ALWAYS_INLINE bool operator>=(const Address &a) const { return (_a >= a._a); }
ZT_ALWAYS_INLINE bool operator<=(const Address &a) const { return (_a <= a._a); }
#if 0
/**
* Create a list of the first N bits of a list of unique addresses with N as the minimum unique size
*
* The list is stored in a space-efficient packed bit format.
*
* @param start Starting Address iterator/pointer
* @param end Ending Address iterator/pointer
* @param list Pointer to location to write list
* @param listCapacityBytes Number of bytes available for list
* @return Number of bytes written or -1 on overflow or other error
* @tparam I Input iterator type
*/
template<typename I>
static inline int createMinPrefixList(I start,I end,uint8_t *list,const int listCapacityBytes)
{
std::vector<Address> sortedAddrs(start,end);
if (sortedAddrs.empty())
return 0;
if (listCapacityBytes == 0)
return -1;
std::sort(sortedAddrs.begin(),sortedAddrs.end());
unsigned int bits = (unsigned int)fmaxf(log2f((float)(sortedAddrs.size() * 2)),3.0F);
uint64_t mask;
try_additional_bits: {
mask = 0xffffffffffffffffULL >> (64 - bits);
std::vector<Address>::iterator a(sortedAddrs.begin());
uint64_t aa = *(a++) & mask;
aa |= (uint64_t)(aa == 0);
uint64_t lastMaskedAddress = aa;
while (a != sortedAddrs.end()) {
aa = *(a++) & mask;
aa |= (uint64_t)(aa == 0);
if (aa == lastMaskedAddress) {
++bits;
goto try_additional_bits;
}
lastMaskedAddress = aa;
}
}
int l = 0;
unsigned int bitPtr = 0;
for(I a(start);a!=end;) {
uint64_t aa = *(a++) & mask;
aa |= (uint64_t)(aa == 0);
unsigned int br = bits;
if (bitPtr > 0) {
unsigned int w = 8 - bitPtr;
if (w > br) w = br;
list[l] = (list[l] << w) | (((uint8_t)aa) & (0xff >> (8 - w)));
bitPtr += w;
if (bitPtr == 8) {
bitPtr = 0;
if (l >= listCapacityBytes)
return -1;
++l;
}
aa >>= w;
br -= w;
}
while (br >= 8) {
if (l >= listCapacityBytes)
return -1;
list[l++] = (uint8_t)aa;
br -= 8;
aa >>= 8;
}
if (br > 0) {
list[l] = (uint8_t)aa;
bitPtr = br;
}
}
if (bitPtr > 0) {
if (l >= listCapacityBytes)
return -1;
++l;
}
return l;
}
#endif
private:
uint64_t _a;
};

@ -24,25 +24,30 @@ namespace ZeroTier {
/**
* Simple atomic counter supporting increment and decrement
*
* This is used as the reference counter in reference counted objects that
* work with SharedPtr<>.
*/
class AtomicCounter
{
public:
ZT_ALWAYS_INLINE AtomicCounter() { _v = 0; }
ZT_ALWAYS_INLINE AtomicCounter() : _v(0) {}
ZT_ALWAYS_INLINE int load() const
{
#ifdef __GNUC__
return __sync_or_and_fetch(const_cast<int *>(&_v),0);
return _v;
#else
return _v.load();
#endif
}
ZT_ALWAYS_INLINE void zero() { _v = 0; }
ZT_ALWAYS_INLINE int operator++()
{
#ifdef __GNUC__
return __sync_add_and_fetch(&_v,1);
return __sync_add_and_fetch((int *)&_v,1);
#else
return ++_v;
#endif
@ -51,7 +56,7 @@ public:
ZT_ALWAYS_INLINE int operator--()
{
#ifdef __GNUC__
return __sync_sub_and_fetch(&_v,1);
return __sync_sub_and_fetch((int *)&_v,1);
#else
return --_v;
#endif
@ -62,7 +67,7 @@ private:
ZT_ALWAYS_INLINE const AtomicCounter &operator=(const AtomicCounter &) { return *this; }
#ifdef __GNUC__
int _v;
volatile int _v;
#else
std::atomic_int _v;
#endif

116
node/Buf.cpp Normal file

@ -0,0 +1,116 @@
/*
* Copyright (c)2019 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2023-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#include "Buf.hpp"
#ifndef __GNUC__
#include <atomic>
#endif
namespace ZeroTier {
#ifdef __GNUC__
static uintptr_t s_pool = 0;
#else
static std::atomic<uintptr_t> s_pool(0);
#endif
void Buf::operator delete(void *ptr,std::size_t sz)
{
if (ptr) {
uintptr_t bb;
const uintptr_t locked = ~((uintptr_t)0);
for (;;) {
#ifdef __GNUC__
bb = __sync_fetch_and_or(&s_pool,locked); // get value of s_pool and "lock" by filling with all 1's
#else
bb = s_pool.fetch_or(locked);
#endif
if (bb != locked)
break;
}
((Buf *)ptr)->__nextInPool = bb;
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,(uintptr_t)ptr);
#else
s_pool.store((uintptr_t)ptr);
#endif
}
}
SharedPtr<Buf> Buf::get()
{
uintptr_t bb;
const uintptr_t locked = ~((uintptr_t)0);
for (;;) {
#ifdef __GNUC__
bb = __sync_fetch_and_or(&s_pool,locked); // get value of s_pool and "lock" by filling with all 1's
#else
bb = s_pool.fetch_or(locked);
#endif
if (bb != locked)
break;
}
Buf *b;
if (bb == 0) {
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,bb);
#else
s_pool.store(bb);
#endif
b = (Buf *)malloc(sizeof(Buf));
if (!b)
return SharedPtr<Buf>();
} else {
b = (Buf *)bb;
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,b->__nextInPool);
#else
s_pool.store(b->__nextInPool);
#endif
}
b->__refCount.zero();
return SharedPtr<Buf>(b);
}
void Buf::freePool()
{
uintptr_t bb;
const uintptr_t locked = ~((uintptr_t)0);
for (;;) {
#ifdef __GNUC__
bb = __sync_fetch_and_or(&s_pool,locked); // get value of s_pool and "lock" by filling with all 1's
#else
bb = s_pool.fetch_or(locked);
#endif
if (bb != locked)
break;
}
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,(uintptr_t)0);
#else
s_pool.store((uintptr_t)0);
#endif
while (bb != 0) {
uintptr_t next = ((Buf *)bb)->__nextInPool;
free((void *)bb);
bb = next;
}
}
} // namespace ZeroTier

472
node/Buf.hpp Normal file

@ -0,0 +1,472 @@
/*
* 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.
*/
/****/
#ifndef ZT_BUF_HPP
#define ZT_BUF_HPP
#include "Constants.hpp"
#include "AtomicCounter.hpp"
#include "Utils.hpp"
#include "SharedPtr.hpp"
#include "Mutex.hpp"
#include <cstdint>
#include <cstring>
#include <cstdlib>
// Buffers are 16384 bytes in size because this is the smallest size that can hold any packet
// and is a power of two. It needs to be a power of two because masking is significantly faster
// than integer division modulus.
#define ZT_BUF_MEM_SIZE 0x00004000
#define ZT_BUF_MEM_MASK 0x00003fffU
namespace ZeroTier {
/**
* Buffer and methods for branch-free bounds-checked data assembly and parsing
*
* This implements an extremely fast buffer for packet assembly and parsing that avoids
* branching whenever possible. To be safe it must be used correctly!
*
* The read methods are prefixed by 'r', and write methods with 'w'. All methods take
* an iterator, which is just an int that should be initialized to 0 (or whatever starting
* position is desired). All read methods will advance the iterator regardless of outcome.
*
* Read and write methods fail silently in the event of overflow. They do not corrupt or
* access memory outside the bounds of Buf, but will otherwise produce undefined results.
*
* IT IS THE RESPONSIBILITY OF THE USER of this class to use the readOverflow() and
* writeOverflow() static methods to check the iterator for overflow after each series
* of reads and writes and BEFORE ANY PARSING or other decisions are made on the basis
* of the data obtained from a buffer. Failure to do so can result in bugs due
* to parsing and branching on undefined or corrupt data.
*
* ^^ THIS IS VERY IMPORTANT ^^
*
* A typical packet assembly consists of repeated calls to the write methods followed by
* a check to writeOverflow() before final packet armoring and transport. A typical packet
* disassembly and parsing consists of a series of read calls to obtain the packet's
* fields followed by a call to readOverflow() to check that these fields are valid. The
* packet is discarded if readOverflow() returns true. Some packet parsers may make
* additional reads and in this case readOverflow() must be checked after each set of
* reads to ensure that overflow did not occur.
*
* Buf uses a lock-free pool for extremely fast allocation and deallocation.
*/
class Buf
{
friend class SharedPtr<Buf>;
private:
// Direct construction isn't allowed; use get().
ZT_ALWAYS_INLINE Buf()
{}
ZT_ALWAYS_INLINE Buf(const Buf &b)
{}
public:
static void operator delete(void *ptr,std::size_t sz);
/**
* Get obtains a buffer from the pool or allocates a new buffer if the pool is empty
*
* @return Buffer
*/
static SharedPtr<Buf> get();
/**
* Free buffers in the pool
*
* New buffers will be created and the pool repopulated if get() is called
* and outstanding buffers will still be returned to the pool. This just
* frees buffers currently held in reserve.
*/
static void freePool();
/**
* Check for overflow beyond the size of the buffer
*
* This is used to check for overflow when writing. It returns true if the iterator
* has passed beyond the capacity of the buffer.
*
* @param ii Iterator to check
* @return True if iterator has read past the size of the buffer
*/
static ZT_ALWAYS_INLINE bool writeOverflow(const int &ii)
{ return ((ii - ZT_BUF_MEM_SIZE) > 0); }
/**
* Check for overflow beyond the size of the data that should be in the buffer
*
* This is used to check for overflow when reading, with the second argument being the
* size of the meaningful data actually present in the buffer.
*
* @param ii Iterator to check
* @param size Size of data that should be in buffer
* @return True if iterator has read past the size of the data
*/
static ZT_ALWAYS_INLINE bool readOverflow(const int &ii,const unsigned int size)
{ return ((ii - (int)size) > 0); }
////////////////////////////////////////////////////////////////////////////
// Read methods
////////////////////////////////////////////////////////////////////////////
/**
* Read a byte
*
* @param ii Iterator
* @return Byte (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint8_t rI8(int &ii) const
{
const unsigned int s = (unsigned int)ii++;
return data[s & ZT_BUF_MEM_MASK];
}
/**
* Read a 16-bit integer
*
* @param ii Integer
* @return Integer (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint16_t rI16(int &ii) const
{
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 2;
#ifdef ZT_NO_TYPE_PUNNING
return (
((uint16_t)data[s] << 8U) |
(uint16_t)data[s + 1]);
#else
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(data + s));
#endif
}
/**
* Read a 32-bit integer
*
* @param ii Integer
* @return Integer (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint32_t rI32(int &ii) const
{
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 4;
#ifdef ZT_NO_TYPE_PUNNING
return (
((uint32_t)data[s] << 24U) |
((uint32_t)data[s + 1] << 16U) |
((uint32_t)data[s + 2] << 8U) |
(uint32_t)data[s + 3]);
#else
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(data + s));
#endif
}
/**
* Read a 64-bit integer
*
* @param ii Integer
* @return Integer (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint64_t rI64(int &ii) const
{
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 8;
#ifdef ZT_NO_TYPE_PUNNING
return (
((uint64_t)data[s] << 56U) |
((uint64_t)data[s + 1] << 48U) |
((uint64_t)data[s + 2] << 40U) |
((uint64_t)data[s + 3] << 32U) |
((uint64_t)data[s + 4] << 24U) |
((uint64_t)data[s + 5] << 16U) |
((uint64_t)data[s + 6] << 8U) |
(uint64_t)data[s + 7]);
#else
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(data + s));
#endif
}
/**
* Read an object supporting the marshal/unmarshal interface
*
* If the return value is negative the object's state is undefined. A return value of
* zero typically also indicates a problem, though this may depend on the object type.
*
* Since objects may be invalid even if there is no overflow, it's important to check
* the return value of this function in all cases and discard invalid packets as it
* indicates.
*
* @tparam T Object type
* @param ii Iterator
* @param obj Object to read
* @return Bytes read or a negative value on unmarshal error (passed from object) or overflow
*/
template<typename T>
ZT_ALWAYS_INLINE int rO(int &ii,T &obj) const
{
if (ii < ZT_BUF_MEM_SIZE) {
int ms = obj.unmarshal(data + ii,ZT_BUF_MEM_SIZE - ii);
if (ms > 0)
ii += ms;
return ms;
}
return -1;
}
/**
* Read a C-style string from the buffer, making a copy and advancing the iterator
*
* Use this if the buffer's memory may get changed between reading and processing
* what is read.
*
* @param ii Iterator
* @param buf Buffer to receive string
* @param bufSize Capacity of buffer in bytes
* @return Pointer to buf or NULL on overflow or error
*/
ZT_ALWAYS_INLINE char *rS(int &ii,char *const buf,const unsigned int bufSize) const
{
const char *const s = (const char *)(data + ii);
const int sii = ii;
while (ii < ZT_BUF_MEM_SIZE) {
if (data[ii++] == 0) {
memcpy(buf,s,ii - sii);
return buf;
}
}
return nullptr;
}
/**
* Obtain a pointer to a C-style string in the buffer without copying and advance the iterator
*
* The iterator is advanced even if this fails and returns NULL so that readOverflow()
* will indicate that an overflow occurred. As with other reads the string's contents are
* undefined if readOverflow() returns true.
*
* This version avoids a copy and so is faster if the buffer won't be modified between
* reading and processing.
*
* @param ii Iterator
* @return Pointer to null-terminated C-style string or NULL on overflow or error
*/
ZT_ALWAYS_INLINE const char *rSnc(int &ii) const
{
const char *const s = (const char *)(data + ii);
while (ii < ZT_BUF_MEM_SIZE) {
if (data[ii++] == 0)
return s;
}
return nullptr;
}
/**
* Read a byte array from the buffer, making a copy and advancing the iterator
*
* Use this if the buffer's memory may get changed between reading and processing
* what is read.
*
* @param ii Iterator
* @param bytes Buffer to contain data to read
* @param len Length of buffer
* @return Pointer to data or NULL on overflow or error
*/
ZT_ALWAYS_INLINE void *rB(int &ii,void *bytes,unsigned int len) const
{
const void *const b = (const void *)(data + ii);
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE) {
memcpy(bytes,b,len);
return bytes;
}
return nullptr;
}
/**
* Obtain a pointer to a field in the buffer without copying and advance the iterator
*
* The iterator is advanced even if this fails and returns NULL so that readOverflow()
* will indicate that an overflow occurred.
*
* This version avoids a copy and so is faster if the buffer won't be modified between
* reading and processing.
*
* @param ii Iterator
* @param len Length of data field to obtain a pointer to
* @return Pointer to field or NULL on overflow
*/
ZT_ALWAYS_INLINE const void *rBnc(int &ii,unsigned int len) const
{
const void *const b = (const void *)(data + ii);
return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr;
}
////////////////////////////////////////////////////////////////////////////
// Write methods
////////////////////////////////////////////////////////////////////////////
/**
* Write a byte
*
* @param ii Iterator
* @param n Byte
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint8_t n)
{
const unsigned int s = (unsigned int)ii++;
data[s & ZT_BUF_MEM_MASK] = n;
}
/**
* Write a 16-bit integer in big-endian byte order
*
* @param ii Iterator
* @param n Integer
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint16_t n)
{
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 2;
#ifdef ZT_NO_TYPE_PUNNING
data[s] = (uint8_t)(n >> 8U);
data[s + 1] = (uint8_t)n;
#else
*reinterpret_cast<uint16_t *>(data + s) = Utils::hton(n);
#endif
}
/**
* Write a 32-bit integer in big-endian byte order
*
* @param ii Iterator
* @param n Integer
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint32_t n)
{
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 4;
#ifdef ZT_NO_TYPE_PUNNING
data[s] = (uint8_t)(n >> 24U);
data[s + 1] = (uint8_t)(n >> 16U);
data[s + 2] = (uint8_t)(n >> 8U);
data[s + 3] = (uint8_t)n;
#else
*reinterpret_cast<uint32_t *>(data + s) = Utils::hton(n);
#endif
}
/**
* Write a 64-bit integer in big-endian byte order
*
* @param ii Iterator
* @param n Integer
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint64_t n)
{
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 8;
#ifdef ZT_NO_TYPE_PUNNING
data[s] = (uint8_t)(n >> 56U);
data[s + 1] = (uint8_t)(n >> 48U);
data[s + 2] = (uint8_t)(n >> 40U);
data[s + 3] = (uint8_t)(n >> 32U);
data[s + 4] = (uint8_t)(n >> 24U);
data[s + 5] = (uint8_t)(n >> 16U);
data[s + 6] = (uint8_t)(n >> 8U);
data[s + 7] = (uint8_t)n;
#else
*reinterpret_cast<uint64_t *>(data + s) = Utils::hton(n);
#endif
}
/**
* Write an object implementing the marshal interface
*
* @tparam T Object type
* @param ii Iterator
* @param t Object to write
*/
template<typename T>
ZT_ALWAYS_INLINE void wO(int &ii,T &t)
{
const unsigned int s = (unsigned int)ii;
if ((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE) {
int ms = t.marshal(data + s);
if (ms > 0)
ii += ms;
} else {
ii += T::marshalSizeMax(); // mark as overflowed even if we didn't do anything
}
}
/**
* Write a C-style null-terminated string (including the trailing zero)
*
* @param ii Iterator
* @param s String to write (writes an empty string if this is NULL)
*/
ZT_ALWAYS_INLINE void wS(int &ii,const char *s)
{
if (s) {
char c;
do {
c = *(s++);
wI(ii,(uint8_t)c);
} while (c);
} else {
wI(ii,(uint8_t)0);
}
}
/**
* Write a byte array
*
* @param ii Iterator
* @param bytes Bytes to write
* @param len Size of data in bytes
*/
ZT_ALWAYS_INLINE void wB(int &ii,const void *const bytes,const unsigned int len)
{
unsigned int s = (unsigned int)ii;
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE)
memcpy(data + s,bytes,len);
}
////////////////////////////////////////////////////////////////////////////
ZT_ALWAYS_INLINE Buf &operator=(const Buf &b)
{
if (&b != this)
memcpy(data,b.data,ZT_BUF_MEM_SIZE);
return *this;
}
/**
* Raw buffer
*
* The extra eight bytes permit silent overflow of integer types without reading or writing
* beyond Buf's memory and without branching or extra masks. They can be ignored otherwise.
*/
uint8_t data[ZT_BUF_MEM_SIZE + 8];
private:
volatile uintptr_t __nextInPool;
AtomicCounter __refCount;
};
} // namespace ZeroTier
#endif

@ -7,16 +7,11 @@ Derived from public domain code by D. J. Bernstein.
// Modified very slightly for ZeroTier One by Adam Ierymenko
// This code remains in the public domain.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <cstdint>
#include <cstring>
#include "Constants.hpp"
#include "C25519.hpp"
#include "SHA512.hpp"
#include "Buffer.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#ifdef __WINDOWS__
#pragma warning(disable: 4146)
@ -28,10 +23,7 @@ Derived from public domain code by D. J. Bernstein.
namespace {
#define crypto_int32 int32_t
#define crypto_uint32 uint32_t
#define crypto_int64 int64_t
#define crypto_uint64 uint64_t
#define crypto_hash_sha512_BYTES 64
//////////////////////////////////////////////////////////////////////////////
@ -41,7 +33,7 @@ typedef uint8_t u8;
typedef int32_t s32;
typedef int64_t limb;
static ZT_ALWAYS_INLINE void fsum(limb *output, const limb *in) {
static inline void fsum(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; i += 2) {
output[0+i] = output[0+i] + in[0+i];
@ -49,21 +41,21 @@ static ZT_ALWAYS_INLINE void fsum(limb *output, const limb *in) {
}
}
static ZT_ALWAYS_INLINE void fdifference(limb *output, const limb *in) {
static inline void fdifference(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] - output[i];
}
}
static ZT_ALWAYS_INLINE void fscalar_product(limb *output, const limb *in, const limb scalar) {
static inline void fscalar_product(limb *output, const limb *in, const limb scalar) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] * scalar;
}
}
static ZT_ALWAYS_INLINE void fproduct(limb *output, const limb *in2, const limb *in) {
static inline void fproduct(limb *output, const limb *in2, const limb *in) {
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
((limb) ((s32) in2[1])) * ((s32) in[0]);
@ -166,7 +158,7 @@ static ZT_ALWAYS_INLINE void fproduct(limb *output, const limb *in2, const limb
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
}
static ZT_ALWAYS_INLINE void freduce_degree(limb *output) {
static inline void freduce_degree(limb *output) {
output[8] += output[18] << 4;
output[8] += output[18] << 1;
output[8] += output[18];
@ -200,7 +192,7 @@ static ZT_ALWAYS_INLINE void freduce_degree(limb *output) {
#error "This code only works on a two's complement system"
#endif
static ZT_ALWAYS_INLINE limb div_by_2_26(const limb v)
static inline limb div_by_2_26(const limb v)
{
/* High word of v; no shift needed. */
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
@ -212,7 +204,7 @@ static ZT_ALWAYS_INLINE limb div_by_2_26(const limb v)
return (v + roundoff) >> 26;
}
static ZT_ALWAYS_INLINE limb div_by_2_25(const limb v)
static inline limb div_by_2_25(const limb v)
{
/* High word of v; no shift needed*/
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
@ -224,7 +216,7 @@ static ZT_ALWAYS_INLINE limb div_by_2_25(const limb v)
return (v + roundoff) >> 25;
}
static ZT_ALWAYS_INLINE void freduce_coefficients(limb *output) {
static inline void freduce_coefficients(limb *output) {
unsigned i;
output[10] = 0;
@ -277,7 +269,7 @@ static inline void fmul(limb *output, const limb *in, const limb *in2) {
memcpy(output, t, sizeof(limb) * 10);
}
static ZT_ALWAYS_INLINE void fsquare_inner(limb *output, const limb *in) {
static inline void fsquare_inner(limb *output, const limb *in) {
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
@ -347,7 +339,7 @@ static inline void fsquare(limb *output, const limb *in) {
memcpy(output, t, sizeof(limb) * 10);
}
static ZT_ALWAYS_INLINE void fexpand(limb *output, const u8 *input) {
static inline void fexpand(limb *output, const u8 *input) {
#define F(n,start,shift,mask) \
output[n] = ((((limb) input[start + 0]) | \
((limb) input[start + 1]) << 8 | \
@ -370,7 +362,7 @@ static ZT_ALWAYS_INLINE void fexpand(limb *output, const u8 *input) {
#error "This code only works when >> does sign-extension on negative numbers"
#endif
static ZT_ALWAYS_INLINE s32 s32_eq(s32 a, s32 b) {
static inline s32 s32_eq(s32 a, s32 b) {
a = ~(a ^ b);
a &= a << 16;
a &= a << 8;
@ -380,7 +372,7 @@ static ZT_ALWAYS_INLINE s32 s32_eq(s32 a, s32 b) {
return a >> 31;
}
static ZT_ALWAYS_INLINE s32 s32_gte(s32 a, s32 b) {
static inline s32 s32_gte(s32 a, s32 b) {
a -= b;
/* a >= 0 iff a >= b. */
return ~(a >> 31);
@ -560,7 +552,7 @@ static inline void fmonty(limb *x2, limb *z2, /* output 2Q */
/* |z2|i| < 2^26 */
}
static ZT_ALWAYS_INLINE void swap_conditional(limb a[19], limb b[19], limb iswap) {
static inline void swap_conditional(limb a[19], limb b[19], limb iswap) {
unsigned i;
const s32 swap = (s32) -iswap;
@ -701,7 +693,7 @@ static inline void crypto_scalarmult(u8 *mypublic, const u8 *secret, const u8 *b
}
static const unsigned char base[32] = {9};
static ZT_ALWAYS_INLINE void crypto_scalarmult_base(unsigned char *q,const unsigned char *n) { crypto_scalarmult(q,n,base); }
static inline void crypto_scalarmult_base(unsigned char *q,const unsigned char *n) { crypto_scalarmult(q,n,base); }
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@ -759,7 +751,7 @@ typedef struct
static inline void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y);
static ZT_ALWAYS_INLINE crypto_uint32 equal(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
static inline crypto_uint32 equal(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
{
crypto_uint32 x = a ^ b; /* 0: yes; 1..65535: no */
x -= 1; /* 4294967295: yes; 0..65534: no */
@ -767,7 +759,7 @@ static ZT_ALWAYS_INLINE crypto_uint32 equal(crypto_uint32 a,crypto_uint32 b) /*
return x;
}
static ZT_ALWAYS_INLINE crypto_uint32 ge(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
static inline crypto_uint32 ge(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
{
unsigned int x = a;
x -= (unsigned int) b; /* 0..65535: yes; 4294901761..4294967295: no */
@ -776,10 +768,10 @@ static ZT_ALWAYS_INLINE crypto_uint32 ge(crypto_uint32 a,crypto_uint32 b) /* 16-
return x;
}
static ZT_ALWAYS_INLINE crypto_uint32 times19(crypto_uint32 a) { return (a << 4) + (a << 1) + a; }
static ZT_ALWAYS_INLINE crypto_uint32 times38(crypto_uint32 a) { return (a << 5) + (a << 2) + (a << 1); }
static inline crypto_uint32 times19(crypto_uint32 a) { return (a << 4) + (a << 1) + a; }
static inline crypto_uint32 times38(crypto_uint32 a) { return (a << 5) + (a << 2) + (a << 1); }
static ZT_ALWAYS_INLINE void reduce_add_sub(fe25519 *r)
static inline void reduce_add_sub(fe25519 *r)
{
int i,rep;
for(rep=0;rep<4;rep++)
@ -797,7 +789,7 @@ static ZT_ALWAYS_INLINE void reduce_add_sub(fe25519 *r)
}
}
static ZT_ALWAYS_INLINE void reduce_mul(fe25519 *r)
static inline void reduce_mul(fe25519 *r)
{
int i,rep;
for(rep=0;rep<2;rep++)
@ -815,7 +807,7 @@ static ZT_ALWAYS_INLINE void reduce_mul(fe25519 *r)
}
}
static ZT_ALWAYS_INLINE void fe25519_freeze(fe25519 *r)
static inline void fe25519_freeze(fe25519 *r)
{
int i;
crypto_uint32 mm = equal(r->v[31],127);
@ -831,14 +823,14 @@ static ZT_ALWAYS_INLINE void fe25519_freeze(fe25519 *r)
r->v[0] -= mm&237;
}
static ZT_ALWAYS_INLINE void fe25519_unpack(fe25519 *r, const unsigned char x[32])
static inline void fe25519_unpack(fe25519 *r, const unsigned char x[32])
{
int i;
for(i=0;i<32;i++) r->v[i] = x[i];
r->v[31] &= 127;
}
static ZT_ALWAYS_INLINE void fe25519_pack(unsigned char r[32], const fe25519 *x)
static inline void fe25519_pack(unsigned char r[32], const fe25519 *x)
{
int i;
fe25519 y = *x;
@ -859,7 +851,7 @@ static inline int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y)
return 1;
}
static ZT_ALWAYS_INLINE void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b)
static inline void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b)
{
int i;
crypto_uint32 mask = b;
@ -867,27 +859,27 @@ static ZT_ALWAYS_INLINE void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned
for(i=0;i<32;i++) r->v[i] ^= mask & (x->v[i] ^ r->v[i]);
}
static ZT_ALWAYS_INLINE unsigned char fe25519_getparity(const fe25519 *x)
static inline unsigned char fe25519_getparity(const fe25519 *x)
{
fe25519 t = *x;
fe25519_freeze(&t);
return t.v[0] & 1;
}
static ZT_ALWAYS_INLINE void fe25519_setone(fe25519 *r)
static inline void fe25519_setone(fe25519 *r)
{
int i;
r->v[0] = 1;
for(i=1;i<32;i++) r->v[i]=0;
}
static ZT_ALWAYS_INLINE void fe25519_setzero(fe25519 *r)
static inline void fe25519_setzero(fe25519 *r)
{
int i;
for(i=0;i<32;i++) r->v[i]=0;
}
static ZT_ALWAYS_INLINE void fe25519_neg(fe25519 *r, const fe25519 *x)
static inline void fe25519_neg(fe25519 *r, const fe25519 *x)
{
fe25519 t;
int i;
@ -896,14 +888,14 @@ static ZT_ALWAYS_INLINE void fe25519_neg(fe25519 *r, const fe25519 *x)
fe25519_sub(r, r, &t);
}
static ZT_ALWAYS_INLINE void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y)
static inline void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y)
{
int i;
for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
reduce_add_sub(r);
}
static ZT_ALWAYS_INLINE void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y)
static inline void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y)
{
int i;
crypto_uint32 t[32];
@ -914,7 +906,7 @@ static ZT_ALWAYS_INLINE void fe25519_sub(fe25519 *r, const fe25519 *x, const fe2
reduce_add_sub(r);
}
static ZT_ALWAYS_INLINE void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y)
static inline void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y)
{
int i,j;
crypto_uint32 t[63];
@ -931,7 +923,7 @@ static ZT_ALWAYS_INLINE void fe25519_mul(fe25519 *r, const fe25519 *x, const fe2
reduce_mul(r);
}
static ZT_ALWAYS_INLINE void fe25519_square(fe25519 *r, const fe25519 *x) { fe25519_mul(r, x, x); }
static inline void fe25519_square(fe25519 *r, const fe25519 *x) { fe25519_mul(r, x, x); }
static inline void fe25519_invert(fe25519 *r, const fe25519 *x)
{
@ -1057,7 +1049,7 @@ static inline void fe25519_pow2523(fe25519 *r, const fe25519 *x)
static const crypto_uint32 m[32] = {0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
static const crypto_uint32 mu[33] = {0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F};
static ZT_ALWAYS_INLINE crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
static inline crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
{
unsigned int x = a;
x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */
@ -1065,7 +1057,7 @@ static ZT_ALWAYS_INLINE crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-
return x;
}
static ZT_ALWAYS_INLINE void reduce_add_sub(sc25519 *r)
static inline void reduce_add_sub(sc25519 *r)
{
crypto_uint32 pb = 0;
crypto_uint32 b;
@ -1144,7 +1136,7 @@ static inline void sc25519_from64bytes(sc25519 *r, const unsigned char x[64])
barrett_reduce(r, t);
}
static ZT_ALWAYS_INLINE void sc25519_to32bytes(unsigned char r[32], const sc25519 *x)
static inline void sc25519_to32bytes(unsigned char r[32], const sc25519 *x)
{
int i;
for(i=0;i<32;i++) r[i] = x->v[i];
@ -1181,7 +1173,7 @@ static inline void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y)
barrett_reduce(r, t);
}
static ZT_ALWAYS_INLINE void sc25519_window3(signed char r[85], const sc25519 *s)
static inline void sc25519_window3(signed char r[85], const sc25519 *s)
{
char carry;
int i;
@ -1218,7 +1210,7 @@ static ZT_ALWAYS_INLINE void sc25519_window3(signed char r[85], const sc25519 *s
r[84] += carry;
}
static ZT_ALWAYS_INLINE void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2)
static inline void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2)
{
int i;
for(i=0;i<31;i++)
@ -2107,21 +2099,21 @@ static const ge25519_aff ge25519_base_multiples_affine[425] = {
{{0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51}}}
};
static ZT_ALWAYS_INLINE void p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p)
static inline void p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p)
{
fe25519_mul(&r->x, &p->x, &p->t);
fe25519_mul(&r->y, &p->y, &p->z);
fe25519_mul(&r->z, &p->z, &p->t);
}
static ZT_ALWAYS_INLINE void p1p1_to_p2_2(ge25519_p3 *r, const ge25519_p1p1 *p)
static inline void p1p1_to_p2_2(ge25519_p3 *r, const ge25519_p1p1 *p)
{
fe25519_mul(&r->x, &p->x, &p->t);
fe25519_mul(&r->y, &p->y, &p->z);
fe25519_mul(&r->z, &p->z, &p->t);
}
static ZT_ALWAYS_INLINE void p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p)
static inline void p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p)
{
p1p1_to_p2_2(r, p);
fe25519_mul(&r->t, &p->x, &p->y);
@ -2190,13 +2182,13 @@ static inline void dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p)
}
/* Constant-time version of: if(b) r = p */
static ZT_ALWAYS_INLINE void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b)
static inline void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b)
{
fe25519_cmov(&r->x, &p->x, b);
fe25519_cmov(&r->y, &p->y, b);
}
static ZT_ALWAYS_INLINE unsigned char equal(signed char b,signed char c)
static inline unsigned char equal(signed char b,signed char c)
{
unsigned char ub = b;
unsigned char uc = c;
@ -2207,7 +2199,7 @@ static ZT_ALWAYS_INLINE unsigned char equal(signed char b,signed char c)
return (unsigned char)y;
}
static ZT_ALWAYS_INLINE unsigned char negative(signed char b)
static inline unsigned char negative(signed char b)
{
unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
x >>= 63; /* 1: yes; 0: no */
@ -2356,7 +2348,7 @@ static inline void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s)
}
}
static ZT_ALWAYS_INLINE void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen)
static inline void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen)
{
unsigned long long i;

@ -32,7 +32,7 @@ public:
/**
* Generate a C25519 elliptic curve key pair
*/
static ZT_ALWAYS_INLINE void generate(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
static inline void generate(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
{
Utils::getSecureRandom(priv,ZT_C25519_PRIVATE_KEY_LEN);
_calcPubDH(pub,priv);
@ -53,7 +53,7 @@ public:
* @tparam F Type of 'cond'
*/
template<typename F>
static ZT_ALWAYS_INLINE void generateSatisfying(F cond,uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
static inline void generateSatisfying(F cond,uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
{
Utils::getSecureRandom(priv,ZT_C25519_PRIVATE_KEY_LEN);
_calcPubED(pub,priv); // do Ed25519 key -- bytes 32-63 of pub and priv

@ -7,8 +7,8 @@ endif(WIN32)
set(core_headers
Address.hpp
AES.hpp
AtomicCounter.hpp
Buf.hpp
Buffer.hpp
C25519.hpp
Capability.hpp
@ -29,6 +29,7 @@ set(core_headers
Network.hpp
NetworkConfig.hpp
Node.hpp
OS.hpp
Packet.hpp
Path.hpp
Peer.hpp
@ -50,13 +51,14 @@ set(core_headers
set(core_src
AES.cpp
AES-aesni.c
Buf.cpp
C25519.cpp
Credential.cpp
ECC384.cpp
Identity.cpp
IncomingPacket.cpp
InetAddress.cpp
Locator.cpp
Membership.cpp
Network.cpp
NetworkConfig.cpp
@ -69,23 +71,10 @@ set(core_src
SelfAwareness.cpp
SHA512.cpp
Switch.cpp
Trace.cpp
Topology.cpp
Utils.cpp
)
add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers})
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR})
#if(UNIX)
# set_source_files_properties(
# AES.cpp
# AES-aesni.c
# ECC384.cpp
# Salsa20.cpp
# C25519.cpp
# Poly1305.cpp
# PROPERTIES
# COMPILE_FLAGS "-Wall -O3"
# )
#endif(UNIX)

@ -14,9 +14,9 @@
#ifndef ZT_CAPABILITY_HPP
#define ZT_CAPABILITY_HPP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "Constants.hpp"
#include "Credential.hpp"
@ -61,7 +61,7 @@ class Capability : public Credential
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; }
ZT_ALWAYS_INLINE Capability() :
inline Capability() :
_nwid(0),
_ts(0),
_id(0),
@ -80,7 +80,7 @@ public:
* @param rules Network flow rules for this capability
* @param ruleCount Number of flow rules
*/
ZT_ALWAYS_INLINE Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) :
inline Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) :
_nwid(nwid),
_ts(ts),
_id(id),
@ -94,32 +94,32 @@ public:
/**
* @return Rules -- see ruleCount() for size of array
*/
ZT_ALWAYS_INLINE const ZT_VirtualNetworkRule *rules() const { return _rules; }
inline const ZT_VirtualNetworkRule *rules() const { return _rules; }
/**
* @return Number of rules in rules()
*/
ZT_ALWAYS_INLINE unsigned int ruleCount() const { return _ruleCount; }
inline unsigned int ruleCount() const { return _ruleCount; }
/**
* @return ID and evaluation order of this capability in network
*/
ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
inline uint32_t id() const { return _id; }
/**
* @return Network ID for which this capability was issued
*/
ZT_ALWAYS_INLINE uint64_t networkId() const { return _nwid; }
inline uint64_t networkId() const { return _nwid; }
/**
* @return Timestamp
*/
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
inline int64_t timestamp() const { return _ts; }
/**
* @return Last 'to' address in chain of custody
*/
ZT_ALWAYS_INLINE Address issuedTo() const
inline Address issuedTo() const
{
Address i2;
for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
@ -165,7 +165,7 @@ public:
*
* @param RR Runtime environment to provide for peer lookup, etc.
*/
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C>
static inline void serializeRules(Buffer<C> &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
@ -460,10 +460,10 @@ public:
}
// Provides natural sort order by ID
ZT_ALWAYS_INLINE bool operator<(const Capability &c) const { return (_id < c._id); }
inline bool operator<(const Capability &c) const { return (_id < c._id); }
ZT_ALWAYS_INLINE bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); }
ZT_ALWAYS_INLINE bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); }
inline bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); }
inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); }
private:
uint64_t _nwid;

@ -14,8 +14,8 @@
#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
#define ZT_CERTIFICATEOFMEMBERSHIP_HPP
#include <stdint.h>
#include <string.h>
#include <cstdint>
#include <cstring>
#include <string>
#include <stdexcept>
@ -69,7 +69,7 @@ class CertificateOfMembership : public Credential
friend class Credential;
public:
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; }
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; }
/**
* Reserved qualifier IDs
@ -101,7 +101,7 @@ public:
/**
* Create an empty certificate of membership
*/
ZT_ALWAYS_INLINE CertificateOfMembership() :
inline CertificateOfMembership() :
_qualifierCount(0),
_signatureLength(0) {}
@ -113,7 +113,7 @@ public:
* @param nwid Network ID
* @param issuedTo Certificate recipient
*/
ZT_ALWAYS_INLINE CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
inline CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
{
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = timestamp;
@ -135,22 +135,22 @@ public:
* @param startAt Position to start in buffer
*/
template<unsigned int C>
ZT_ALWAYS_INLINE CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
inline CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
/**
* @return True if there's something here
*/
ZT_ALWAYS_INLINE operator bool() const { return (_qualifierCount != 0); }
inline operator bool() const { return (_qualifierCount != 0); }
/**
* @return Credential ID, always 0 for COMs
*/
ZT_ALWAYS_INLINE uint32_t id() const { return 0; }
inline uint32_t id() const { return 0; }
/**
* @return Timestamp for this cert and maximum delta for timestamp
*/
ZT_ALWAYS_INLINE int64_t timestamp() const
inline int64_t timestamp() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)
@ -162,7 +162,7 @@ public:
/**
* @return Address to which this cert was issued
*/
ZT_ALWAYS_INLINE Address issuedTo() const
inline Address issuedTo() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO)
@ -174,7 +174,7 @@ public:
/**
* @return Network ID for which this cert was issued
*/
ZT_ALWAYS_INLINE uint64_t networkId() const
inline uint64_t networkId() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID)
@ -211,7 +211,7 @@ public:
}
}
ZT_ALWAYS_INLINE void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
/**
* Compare two certificates for parameter agreement
@ -294,17 +294,17 @@ public:
* @param RR Runtime environment for looking up peers
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
/**
* @return True if signed
*/
ZT_ALWAYS_INLINE bool isSigned() const { return (_signedBy); }
inline bool isSigned() const { return (_signedBy); }
/**
* @return Address that signed this certificate or null address if none
*/
ZT_ALWAYS_INLINE const Address &signedBy() const { return _signedBy; }
inline const Address &signedBy() const { return _signedBy; }
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
@ -369,7 +369,7 @@ public:
return (p - startAt);
}
ZT_ALWAYS_INLINE bool operator==(const CertificateOfMembership &c) const
inline bool operator==(const CertificateOfMembership &c) const
{
if (_signedBy != c._signedBy)
return false;
@ -385,7 +385,7 @@ public:
}
return (memcmp(_signature,c._signature,_signatureLength) == 0);
}
ZT_ALWAYS_INLINE bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
private:
struct _Qualifier

@ -14,10 +14,10 @@
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
#define ZT_CERTIFICATEOFOWNERSHIP_HPP
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "Constants.hpp"
#include "Credential.hpp"
@ -46,7 +46,7 @@ class CertificateOfOwnership : public Credential
friend class Credential;
public:
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
enum Thing
{
@ -56,12 +56,12 @@ public:
THING_IPV6_ADDRESS = 3
};
ZT_ALWAYS_INLINE CertificateOfOwnership()
inline CertificateOfOwnership()
{
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
}
ZT_ALWAYS_INLINE CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id)
inline CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id)
{
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
_networkId = nwid;
@ -70,19 +70,19 @@ public:
_issuedTo = issuedTo;
}
ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
ZT_ALWAYS_INLINE const Address &issuedTo() const { return _issuedTo; }
ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
inline uint64_t networkId() const { return _networkId; }
inline int64_t timestamp() const { return _ts; }
inline uint32_t id() const { return _id; }
inline const Address &issuedTo() const { return _issuedTo; }
inline const Address &signer() const { return _signedBy; }
inline const uint8_t *signature() const { return _signature; }
inline unsigned int signatureLength() const { return _signatureLength; }
ZT_ALWAYS_INLINE unsigned int thingCount() const { return (unsigned int)_thingCount; }
ZT_ALWAYS_INLINE Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; }
ZT_ALWAYS_INLINE const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
inline unsigned int thingCount() const { return (unsigned int)_thingCount; }
inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; }
inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
ZT_ALWAYS_INLINE bool owns(const InetAddress &ip) const
inline bool owns(const InetAddress &ip) const
{
if (ip.ss_family == AF_INET)
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
@ -91,7 +91,7 @@ public:
return false;
}
ZT_ALWAYS_INLINE bool owns(const MAC &mac) const
inline bool owns(const MAC &mac) const
{
uint8_t tmp[6];
mac.copyTo(tmp,6);
@ -136,7 +136,7 @@ public:
return false;
}
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
@ -206,10 +206,10 @@ public:
}
// Provides natural sort order by ID
ZT_ALWAYS_INLINE bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
ZT_ALWAYS_INLINE bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); }
ZT_ALWAYS_INLINE bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); }
inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
private:
inline bool _owns(const Thing &t,const void *v,unsigned int l) const

@ -14,11 +14,8 @@
#ifndef ZT_CONSTANTS_HPP
#define ZT_CONSTANTS_HPP
/****************************************************************************/
/* Core includes and OS/platform setup stuff */
/****************************************************************************/
#include "../include/ZeroTierCore.h"
#include "OS.hpp"
#if __has_include("version.h")
#include "version.h"
@ -29,187 +26,25 @@
#define ZEROTIER_ONE_VERSION_BUILD 255
#endif
//
// This include file also auto-detects and canonicalizes some environment
// information defines:
//
// __LINUX__
// __APPLE__
// __BSD__ (OSX also defines this)
// __UNIX_LIKE__ (Linux, BSD, etc.)
// __WINDOWS__
//
// Also makes sure __BYTE_ORDER is defined reasonably.
//
// Hack: make sure __GCC__ is defined on old GCC compilers
#ifndef __GCC__
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
#define __GCC__
#endif
#endif
#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
#ifndef __LINUX__
#define __LINUX__
#endif
#ifndef __UNIX_LIKE__
#define __UNIX_LIKE__
#endif
#include <endian.h>
#endif
#ifdef __APPLE__
#include <TargetConditionals.h>
#ifndef __UNIX_LIKE__
#define __UNIX_LIKE__
#endif
#ifndef __BSD__
#define __BSD__
#endif
#include <machine/endian.h>
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#ifndef __UNIX_LIKE__
#define __UNIX_LIKE__
#endif
#ifndef __BSD__
#define __BSD__
#endif
#include <sys/endian.h>
#ifndef __BYTE_ORDER
#define __BYTE_ORDER _BYTE_ORDER
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
#define __BIG_ENDIAN _BIG_ENDIAN
#endif
#endif
#if defined(_WIN32) || defined(_WIN64)
#ifndef __WINDOWS__
#define __WINDOWS__
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#pragma warning(disable : 4290)
#pragma warning(disable : 4996)
#pragma warning(disable : 4101)
#undef __UNIX_LIKE__
#undef __BSD__
#include <WinSock2.h>
#include <Windows.h>
#endif
#ifdef __NetBSD__
#ifndef RTF_MULTICAST
#define RTF_MULTICAST 0x20000000
#endif
#endif
// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86 and x86_64.
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#ifndef ZT_NO_TYPE_PUNNING
#define ZT_NO_TYPE_PUNNING
#endif
#endif
// Assume little endian if not defined on Mac and Windows as these don't run on any BE architectures.
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
#undef __BYTE_ORDER
#undef __LITTLE_ENDIAN
#undef __BIG_ENDIAN
#define __BIG_ENDIAN 4321
#define __LITTLE_ENDIAN 1234
#define __BYTE_ORDER 1234
#endif
#ifndef __BYTE_ORDER
#include <endian.h>
#endif
#ifdef __WINDOWS__
#define ZT_PATH_SEPARATOR '\\'
#define ZT_PATH_SEPARATOR_S "\\"
#define ZT_EOL_S "\r\n"
#else
#define ZT_PATH_SEPARATOR '/'
#define ZT_PATH_SEPARATOR_S "/"
#define ZT_EOL_S "\n"
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
#define ZT_ALWAYS_INLINE inline __attribute__((always_inline))
#ifndef likely
#define likely(x) __builtin_expect((x),1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect((x),0)
#endif
#else
#ifndef likely
#define ZT_ALWAYS_INLINE inline
#define likely(x) (x)
#endif
#ifndef unlikely
#define unlikely(x) (x)
#endif
#endif
#if defined(__WINDOWS__) && !defined(__GNUC__) && !defined (__clang__) && !defined(__INTEL_COMPILER)
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
#else
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
#endif
#if __cplusplus > 199711L
#ifndef __CPP11__
#define __CPP11__
#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
/****************************************************************************/
/* Internal ZeroTier constants */
/****************************************************************************/
/**
* Length of a ZeroTier address in bytes
*/
#define ZT_ADDRESS_LENGTH 5
/**
* Length of a hexadecimal ZeroTier address
*/
#define ZT_ADDRESS_LENGTH_HEX 10
/**
* Addresses beginning with this byte are reserved for the joy of in-band signaling
*/
#define ZT_ADDRESS_RESERVED_PREFIX 0xff
/**
* Secure DNS name for ZeroTier's default root
*
* This resolves via GeoDNS to the (probably) nearest actual root server's locator.
* Maximum DNS or URL name size for an Endpoint (set so that max marshaled endpoint size is 64 bytes)
*/
#define ZT_DEFAULT_ROOT_NAME "ztl-aj4zes4l6zumq64na6borruuvd6diw2koxrjcaatolcekt2gj5rrhric.ztl-6lhxeo7n3z7kzkgcqzj3ndliaq.zerotier.network"
#define ZT_ENDPOINT_MAX_NAME_SIZE 61
/**
* Default locator for default root
*
* This is used before the root has been successfully fetched, or if DNS is unavailable.
* Size of an identity hash (SHA384)
*/
#define ZT_DEFAULT_ROOT_LOCATOR "AAAAAW2OuYyfOkbxvzAAduZvqzPihUmmLuIGTRhDJzwsMAukXD8gvvAtutIlcju1mpu0sTU1cwlhruz1oWOs5HfM6wcnAluZrBSlFmoJowAEBLm0DVInCQS5tA1SAbsGKgJuoMgVAAAAAAAAAAAAACcJBioCbqDIFQAAAAAAAAAAAAABuwAAYDvTNB2snbn7TYom4PBTh/ohRgCnI2/A/nfKakGCb+2hGJTtxTCiGTzKZdbjd0vyKAKQLJxhj7RaoCo3XjPn8w9nDEmhdNCgCM/IITCJIzc9tEKFsSQnJY4VmB3dopBAfQAA"
#define ZT_IDENTITY_HASH_SIZE 48
/**
* Default virtual network MTU (not physical)
@ -282,246 +117,34 @@
#define ZT_RELAY_MAX_HOPS 4
/**
* Expire time for multicast 'likes' and indirect multicast memberships in ms
*/
#define ZT_MULTICAST_LIKE_EXPIRE 600000
/**
* Period for multicast LIKE re-announcements to connected nodes
*/
#define ZT_MULTICAST_ANNOUNCE_PERIOD 60000
/**
* Period for multicast GATHER on multicast groups
*/
#define ZT_MULTICAST_GATHER_PERIOD ZT_MULTICAST_ANNOUNCE_PERIOD
/**
* Period for multicast GATHER if there are no known recipients
*/
#define ZT_MULTICAST_GATHER_PERIOD_WHEN_NO_RECIPIENTS 2500
/**
* Timeout for outgoing multicasts
*
* This is how long we wait for explicit or implicit gather results.
*/
#define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000
/**
* How frequently to check for changes to the system's network interfaces. When
* the service decides to use this constant it's because we want to react more
* quickly to new interfaces that pop up or go down.
*/
#define ZT_MULTIPATH_BINDER_REFRESH_PERIOD 5000
/**
* Packets are only used for QoS/ACK statistical sampling if their packet ID is divisible by
* this integer. This is to provide a mechanism for both peers to agree on which packets need
* special treatment without having to exchange information. Changing this value would be
* a breaking change and would necessitate a protocol version upgrade. Since each incoming and
* outgoing packet ID is checked against this value its evaluation is of the form:
* (id & (divisor - 1)) == 0, thus the divisor must be a power of 2.
*
* This value is set at (16) so that given a normally-distributed RNG output we will sample
* 1/16th (or ~6.25%) of packets.
*/
#define ZT_PATH_QOS_ACK_PROTOCOL_DIVISOR 0x10
/**
* Time horizon for VERB_QOS_MEASUREMENT and VERB_ACK packet processing cutoff
*/
#define ZT_PATH_QOS_ACK_CUTOFF_TIME 30000
/**
* Maximum number of VERB_QOS_MEASUREMENT and VERB_ACK packets allowed to be
* processed within cutoff time. Separate totals are kept for each type but
* the limit is the same for both.
*
* This limits how often this peer will compute statistical estimates
* of various QoS measures from a VERB_QOS_MEASUREMENT or VERB_ACK packets to
* CUTOFF_LIMIT times per CUTOFF_TIME milliseconds per peer to prevent
* this from being useful for DOS amplification attacks.
*/
#define ZT_PATH_QOS_ACK_CUTOFF_LIMIT 128
/**
* Path choice history window size. This is used to keep track of which paths were
* previously selected so that we can maintain a target allocation over time.
*/
#define ZT_MULTIPATH_PROPORTION_WIN_SZ 128
/**
* Interval used for rate-limiting the computation of path quality estimates.
*/
#define ZT_PATH_QUALITY_COMPUTE_INTERVAL 1000
/**
* Number of samples to consider when computing real-time path statistics
*/
#define ZT_PATH_QUALITY_METRIC_REALTIME_CONSIDERATION_WIN_SZ 128
/**
* Number of samples to consider when computing performing long-term path quality analysis.
* By default this value is set to ZT_PATH_QUALITY_METRIC_REALTIME_CONSIDERATION_WIN_SZ but can
* be set to any value greater than that to observe longer-term path quality behavior.
*/
#define ZT_PATH_QUALITY_METRIC_WIN_SZ ZT_PATH_QUALITY_METRIC_REALTIME_CONSIDERATION_WIN_SZ
/**
* Maximum acceptable Packet Delay Variance (PDV) over a path
*/
#define ZT_PATH_MAX_PDV 1000
/**
* Maximum acceptable time interval between expectation and receipt of at least one ACK over a path
*/
#define ZT_PATH_MAX_AGE 30000
/**
* Maximum acceptable mean latency over a path
*/
#define ZT_PATH_MAX_MEAN_LATENCY 1000
/**
* How much each factor contributes to the "stability" score of a path
*/
#define ZT_PATH_CONTRIB_PDV (1.0 / 3.0)
#define ZT_PATH_CONTRIB_LATENCY (1.0 / 3.0)
#define ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE (1.0 / 3.0)
/**
* How much each factor contributes to the "quality" score of a path
*/
#define ZT_PATH_CONTRIB_STABILITY (0.75 / 3.0)
#define ZT_PATH_CONTRIB_THROUGHPUT (1.50 / 3.0)
#define ZT_PATH_CONTRIB_SCOPE (0.75 / 3.0)
/**
* How often a QoS packet is sent
*/
#define ZT_PATH_QOS_INTERVAL 3000
/**
* Min and max acceptable sizes for a VERB_QOS_MEASUREMENT packet
*/
#define ZT_PATH_MIN_QOS_PACKET_SZ 8 + 1
#define ZT_PATH_MAX_QOS_PACKET_SZ 1400
/**
* How many ID:sojourn time pairs in a single QoS packet
*/
#define ZT_PATH_QOS_TABLE_SIZE ((ZT_PATH_MAX_QOS_PACKET_SZ * 8) / (64 + 16))
/**
* Maximum number of outgoing packets we monitor for QoS information
*/
#define ZT_PATH_MAX_OUTSTANDING_QOS_RECORDS 128
/**
* Timeout for QoS records
*/
#define ZT_PATH_QOS_TIMEOUT (ZT_PATH_QOS_INTERVAL * 2)
/**
* How often the service tests the path throughput
*/
#define ZT_PATH_THROUGHPUT_MEASUREMENT_INTERVAL (ZT_PATH_ACK_INTERVAL * 8)
/**
* Minimum amount of time between each ACK packet
*/
#define ZT_PATH_ACK_INTERVAL 1000
/**
* How often an aggregate link statistics report is emitted into this tracing system
*/
#define ZT_PATH_AGGREGATE_STATS_REPORT_INTERVAL 60000
/**
* How much an aggregate link's component paths can vary from their target allocation
* before the link is considered to be in a state of imbalance.
*/
#define ZT_PATH_IMBALANCE_THRESHOLD 0.20
/**
* Max allowable time spent in any queue
*/
#define ZT_QOS_TARGET 5 // ms
/**
* Time period where the time spent in the queue by a packet should fall below
* target at least once
*/
#define ZT_QOS_INTERVAL 100 // ms
/**
* The number of bytes that each queue is allowed to send during each DRR cycle.
* This approximates a single-byte-based fairness queuing scheme
*/
#define ZT_QOS_QUANTUM ZT_DEFAULT_MTU
/**
* The maximum total number of packets that can be queued among all
* active/inactive, old/new queues
*/
#define ZT_QOS_MAX_ENQUEUED_PACKETS 1024
/**
* Number of QoS queues (buckets)
*/
#define ZT_QOS_NUM_BUCKETS 9
/**
* All unspecified traffic is put in this bucket. Anything in a bucket with a smaller
* value is de-prioritized. Anything in a bucket with a higher value is prioritized over
* other traffic.
*/
#define ZT_QOS_DEFAULT_BUCKET 0
/**
* Do not accept HELLOs over a given path more often than this
*/
#define ZT_PATH_HELLO_RATE_LIMIT 1000
/**
* Delay between full-fledge pings of directly connected peers
* Period between keepalives sent to paths if no other traffic has been sent
*
* 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." 30 seconds is faster than really necessary.
*/
#define ZT_PEER_PING_PERIOD 30000
#define ZT_PATH_KEEPALIVE_PERIOD 30000
/**
* Delay between refreshes of locators via DNS or other methods
* Timeout for path aliveness (measured from last receive)
*/
#define ZT_DYNAMIC_ROOT_UPDATE_PERIOD 120000
#define ZT_PATH_ACTIVITY_TIMEOUT ((ZT_PATH_KEEPALIVE_PERIOD * 2) + 5000)
/**
* Delay between full HELLO messages between peers
*/
#define ZT_PEER_PING_PERIOD 60000
/**
* Timeout for overall peer activity (measured from last receive)
*/
#ifndef ZT_SDK
#define ZT_PEER_ACTIVITY_TIMEOUT 500000
#else
#define ZT_PEER_ACTIVITY_TIMEOUT 30000
#endif
#define ZT_PEER_ACTIVITY_TIMEOUT ((ZT_PEER_PING_PERIOD * 2) + 5000)
/**
* Rescan for best/fastest root every N milliseconds
* Maximum interval between sort/prioritize of paths for a peer
*/
#define ZT_FIND_BEST_ROOT_PERIOD 2000
/**
* General rate limit timeout for multiple packet types (HELLO, etc.)
*/
#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 500
/**
* General limit for max RTT for requests over the network
*/
#define ZT_GENERAL_RTT_LIMIT 5000
#define ZT_PEER_PRIORITIZE_PATHS_INTERVAL 5000
/**
* Delay between requests for updated network autoconf information
@ -531,15 +154,6 @@
*/
#define ZT_NETWORK_AUTOCONF_DELAY 60000
/**
* Minimum interval between attempts by relays to unite peers
*
* When a relay gets a packet destined for another peer, it sends both peers
* a RENDEZVOUS message no more than this often. This instructs the peers
* to attempt NAT-t and gives each the other's corresponding IP:port pair.
*/
#define ZT_MIN_UNITE_INTERVAL 30000
/**
* Sanity limit on maximum bridge routes
*
@ -566,34 +180,10 @@
*/
#define ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH 120000
/**
* Time horizon for push direct paths cutoff
*/
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 30000
/**
* Maximum number of direct path pushes within cutoff time
*
* This limits response to PUSH_DIRECT_PATHS to CUTOFF_LIMIT responses
* per CUTOFF_TIME milliseconds per peer to prevent this from being
* useful for DOS amplification attacks.
*/
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 8
/**
* Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
*/
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 8
/**
* Time horizon for VERB_NETWORK_CREDENTIALS cutoff
*/
#define ZT_PEER_CREDENTIALS_CUTOFF_TIME 60000
/**
* Maximum number of VERB_NETWORK_CREDENTIALS within cutoff time
*/
#define ZT_PEER_CREDEITIALS_CUTOFF_LIMIT 15
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
/**
* WHOIS rate limit (we allow these to be pretty fast)
@ -632,12 +222,7 @@
*/
#define ZT_SIGNATURE_BUFFER_SIZE 96
/**
* Desired / recommended min stack size for threads (used on some platforms to reset thread stack size)
*/
#define ZT_THREAD_MIN_STACK_SIZE 1048576
// Internal cryptographic algorithm IDs
// Internal cryptographic algorithm IDs (these match relevant identity types)
#define ZT_CRYPTO_ALG_C25519 0
#define ZT_CRYPTO_ALG_P384 1
@ -651,4 +236,9 @@
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN 202
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203
/* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800
#define ZT_ETHERTYPE_ARP 0x0806
#define ZT_ETHERTYPE_IPV6 0x86dd
#endif

@ -26,7 +26,7 @@
namespace ZeroTier {
template<typename CRED>
static ZT_ALWAYS_INLINE Credential::VerifyResult _credVerify(const RuntimeEnvironment *const RR,void *tPtr,CRED credential)
static inline Credential::VerifyResult _credVerify(const RuntimeEnvironment *const RR,void *tPtr,CRED credential)
{
const Address signedBy(credential.signer());
const uint64_t networkId = credential.networkId();

@ -18,10 +18,10 @@
#include <memory>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include "Constants.hpp"

@ -19,7 +19,7 @@
#include "Buffer.hpp"
#include "Address.hpp"
#include <stdint.h>
#include <cstdint>
namespace ZeroTier {
@ -49,9 +49,9 @@ template<unsigned int C>
class Dictionary
{
public:
ZT_ALWAYS_INLINE Dictionary() { memset(_d,0,sizeof(_d)); }
ZT_ALWAYS_INLINE Dictionary(const char *s) { this->load(s); }
ZT_ALWAYS_INLINE Dictionary(const char *s,unsigned int len)
inline Dictionary() { memset(_d,0,sizeof(_d)); }
inline Dictionary(const char *s) { this->load(s); }
inline Dictionary(const char *s,unsigned int len)
{
for(unsigned int i=0;i<C;++i) {
if ((s)&&(i < len)) {
@ -62,15 +62,15 @@ public:
}
_d[C - 1] = (char)0;
}
ZT_ALWAYS_INLINE Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); }
inline Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); }
ZT_ALWAYS_INLINE Dictionary &operator=(const Dictionary &d)
inline Dictionary &operator=(const Dictionary &d)
{
memcpy(_d,d._d,C);
return *this;
}
ZT_ALWAYS_INLINE operator bool() const { return (_d[0] != 0); }
inline operator bool() const { return (_d[0] != 0); }
/**
* Load a dictionary from a C-string
@ -78,7 +78,7 @@ public:
* @param s Dictionary in string form
* @return False if 's' was longer than our capacity
*/
ZT_ALWAYS_INLINE bool load(const char *s)
inline bool load(const char *s)
{
for(unsigned int i=0;i<C;++i) {
if (s) {
@ -94,12 +94,12 @@ public:
/**
* Delete all entries
*/
ZT_ALWAYS_INLINE void clear() { memset(_d,0,sizeof(_d)); }
inline void clear() { memset(_d,0,sizeof(_d)); }
/**
* @return Size of dictionary in bytes not including terminating NULL
*/
ZT_ALWAYS_INLINE unsigned int sizeBytes() const
inline unsigned int sizeBytes() const
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i])
@ -217,7 +217,7 @@ public:
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
ZT_ALWAYS_INLINE bool get(const char *key,Buffer<BC> &dest) const
inline bool get(const char *key,Buffer<BC> &dest) const
{
const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),BC);
if (r >= 0) {
@ -236,7 +236,7 @@ public:
* @param dfl Default value if not found in dictionary
* @return Boolean value of key or 'dfl' if not found
*/
ZT_ALWAYS_INLINE bool getB(const char *key,bool dfl = false) const
inline bool getB(const char *key,bool dfl = false) const
{
char tmp[4];
if (this->get(key,tmp,sizeof(tmp)) >= 0)
@ -251,7 +251,7 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
ZT_ALWAYS_INLINE uint64_t getUI(const char *key,uint64_t dfl = 0) const
inline uint64_t getUI(const char *key,uint64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1)
@ -266,7 +266,7 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
ZT_ALWAYS_INLINE int64_t getI(const char *key,int64_t dfl = 0) const
inline int64_t getI(const char *key,int64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1)
@ -366,7 +366,7 @@ public:
/**
* Add a boolean as a '1' or a '0'
*/
ZT_ALWAYS_INLINE bool add(const char *key,bool value)
inline bool add(const char *key,bool value)
{
return this->add(key,(value) ? "1" : "0",1);
}
@ -374,7 +374,7 @@ public:
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
ZT_ALWAYS_INLINE bool add(const char *key,uint64_t value)
inline bool add(const char *key,uint64_t value)
{
char tmp[32];
return this->add(key,Utils::hex(value,tmp),-1);
@ -383,7 +383,7 @@ public:
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
ZT_ALWAYS_INLINE bool add(const char *key,int64_t value)
inline bool add(const char *key,int64_t value)
{
char tmp[32];
if (value >= 0) {
@ -397,7 +397,7 @@ public:
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
ZT_ALWAYS_INLINE bool add(const char *key,const Address &a)
inline bool add(const char *key,const Address &a)
{
char tmp[32];
return this->add(key,Utils::hex(a.toInt(),tmp),-1);
@ -409,7 +409,7 @@ public:
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
ZT_ALWAYS_INLINE bool add(const char *key,const Buffer<BC> &value)
inline bool add(const char *key,const Buffer<BC> &value)
{
return this->add(key,(const char *)value.data(),(int)value.size());
}
@ -418,7 +418,7 @@ public:
* @param key Key to check
* @return True if key is present
*/
ZT_ALWAYS_INLINE bool contains(const char *key) const
inline bool contains(const char *key) const
{
char tmp[2];
return (this->get(key,tmp,2) >= 0);
@ -427,10 +427,10 @@ public:
/**
* @return Value of C template parameter
*/
ZT_ALWAYS_INLINE unsigned int capacity() const { return C; }
inline unsigned int capacity() const { return C; }
ZT_ALWAYS_INLINE const char *data() const { return _d; }
ZT_ALWAYS_INLINE char *unsafeData() { return _d; }
inline const char *data() const { return _d; }
inline char *unsafeData() { return _d; }
private:
char _d[C];

@ -4,10 +4,9 @@
// This code is under the BSD 2-clause license, not ZeroTier's license
//////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include "Constants.hpp"
#include "ECC384.hpp"
@ -141,7 +140,7 @@ static ZT_ALWAYS_INLINE void vli_set(uint64_t *p_dest, uint64_t *p_src)
}
/* Returns sign of p_left - p_right. */
static ZT_ALWAYS_INLINE int vli_cmp(uint64_t *p_left, uint64_t *p_right)
static inline int vli_cmp(uint64_t *p_left, uint64_t *p_right)
{
int i;
for(i = NUM_ECC_DIGITS-1; i >= 0; --i)
@ -376,7 +375,7 @@ static inline void vli_square(uint64_t *p_result, uint64_t *p_left)
/* Computes p_result = (p_left + p_right) % p_mod.
Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */
static ZT_ALWAYS_INLINE void vli_modAdd(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, uint64_t *p_mod)
static inline void vli_modAdd(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, uint64_t *p_mod)
{
uint64_t l_carry = vli_add(p_result, p_left, p_right);
if(l_carry || vli_cmp(p_result, p_mod) >= 0)
@ -387,7 +386,7 @@ static ZT_ALWAYS_INLINE void vli_modAdd(uint64_t *p_result, uint64_t *p_left, ui
/* Computes p_result = (p_left - p_right) % p_mod.
Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */
static ZT_ALWAYS_INLINE void vli_modSub(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, uint64_t *p_mod)
static inline void vli_modSub(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, uint64_t *p_mod)
{
uint64_t l_borrow = vli_sub(p_result, p_left, p_right);
if(l_borrow)

248
node/Endpoint.hpp Normal file

@ -0,0 +1,248 @@
/*
* 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.
*/
/****/
#ifndef ZT_ENDPOINT_HPP
#define ZT_ENDPOINT_HPP
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Address.hpp"
#include "Utils.hpp"
#define ZT_ENDPOINT_MARSHAL_SIZE_MAX (ZT_ENDPOINT_MAX_NAME_SIZE+3)
namespace ZeroTier {
/**
* Endpoint variant specifying some form of network endpoint
*/
class Endpoint
{
public:
enum Type
{
NIL = 0, // NIL value
INETADDR = 1, // InetAddress (v4 or v6)
DNSNAME = 2, // DNS name and port that resolves to InetAddress
ZEROTIER = 3, // ZeroTier Address (for relaying and meshy behavior)
URL = 4, // URL for http/https/ws/etc. (not implemented yet)
ETHERNET = 5 // 48-bit LAN-local Ethernet address
};
ZT_ALWAYS_INLINE Endpoint() { memset(reinterpret_cast<void *>(this),0,sizeof(Endpoint)); }
explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) : _t(INETADDR) { _v.sa = sa; }
ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) : _t(ZEROTIER) { _v.zt.a = zt.toInt(); memcpy(_v.zt.idh,identityHash,ZT_IDENTITY_HASH_SIZE); }
ZT_ALWAYS_INLINE Endpoint(const char *name,const int port) : _t(DNSNAME) { Utils::scopy(_v.dns.name,sizeof(_v.dns.name),name); _v.dns.port = port; }
explicit ZT_ALWAYS_INLINE Endpoint(const char *url) : _t(URL) { Utils::scopy(_v.url,sizeof(_v.url),url); }
ZT_ALWAYS_INLINE const InetAddress *sockaddr() const { return (_t == INETADDR) ? reinterpret_cast<const InetAddress *>(&_v.sa) : nullptr; }
ZT_ALWAYS_INLINE const char *dnsName() const { return (_t == DNSNAME) ? _v.dns.name : nullptr; }
ZT_ALWAYS_INLINE int dnsPort() const { return (_t == DNSNAME) ? _v.dns.port : -1; }
ZT_ALWAYS_INLINE Address ztAddress() const { return (_t == ZEROTIER) ? Address(_v.zt.a) : Address(); }
ZT_ALWAYS_INLINE const uint8_t *ztIdentityHash() const { return (_t == ZEROTIER) ? _v.zt.idh : nullptr; }
ZT_ALWAYS_INLINE const char *url() const { return (_t == URL) ? _v.url : nullptr; }
ZT_ALWAYS_INLINE MAC ethernet() const { return (_t == ETHERNET) ? MAC(_v.eth) : MAC(); }
ZT_ALWAYS_INLINE Type type() const { return _t; }
ZT_ALWAYS_INLINE bool operator==(const Endpoint &ep) const
{
if (_t == ep._t) {
switch(_t) {
case INETADDR: return (*sockaddr() == *ep.sockaddr());
case DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0));
case ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0));
case URL: return (strcmp(_v.url,ep._v.url) == 0);
case ETHERNET: return (_v.eth == ep._v.eth);
default: return true;
}
}
return false;
}
ZT_ALWAYS_INLINE bool operator!=(const Endpoint &ep) const { return (!(*this == ep)); }
ZT_ALWAYS_INLINE bool operator<(const Endpoint &ep) const
{
if ((int)_t < (int)ep._t) {
return true;
} else if (_t == ep._t) {
int ncmp;
switch(_t) {
case INETADDR: return (*sockaddr() < *ep.sockaddr());
case DNSNAME:
ncmp = strcmp(_v.dns.name,ep._v.dns.name);
return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
case ZEROTIER: return (_v.zt.a < ep._v.zt.a) ? true : ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) < 0));
case URL: return (strcmp(_v.url,ep._v.url) < 0);
case ETHERNET: return (_v.eth < ep._v.eth);
default: return false;
}
}
return false;
}
ZT_ALWAYS_INLINE bool operator>(const Endpoint &ep) const { return (ep < *this); }
ZT_ALWAYS_INLINE bool operator<=(const Endpoint &ep) const { return !(ep < *this); }
ZT_ALWAYS_INLINE bool operator>=(const Endpoint &ep) const { return !(*this < ep); }
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
inline int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const
{
int p;
switch(_t) {
case INETADDR:
data[0] = (uint8_t)INETADDR;
return 1 + reinterpret_cast<const InetAddress *>(&_v.sa)->marshal(data+1);
case DNSNAME:
data[0] = (uint8_t)DNSNAME;
p = 1;
for (;;) {
if ((data[p] = (uint8_t)_v.dns.name[p-1]) == 0)
break;
++p;
if (p == (ZT_ENDPOINT_MAX_NAME_SIZE+1))
return -1;
}
data[p++] = (uint8_t)(_v.dns.port >> 8U);
data[p++] = (uint8_t)_v.dns.port;
return p;
case ZEROTIER:
data[0] = (uint8_t)ZEROTIER;
data[1] = (uint8_t)(_v.zt.a >> 32U);
data[2] = (uint8_t)(_v.zt.a >> 24U);
data[3] = (uint8_t)(_v.zt.a >> 16U);
data[4] = (uint8_t)(_v.zt.a >> 8U);
data[5] = (uint8_t)_v.zt.a;
memcpy(data + 6,_v.zt.idh,ZT_IDENTITY_HASH_SIZE);
return (ZT_IDENTITY_HASH_SIZE + 6);
case URL:
data[0] = (uint8_t)URL;
p = 1;
for (;;) {
if ((data[p] = (uint8_t)_v.url[p-1]) == 0)
break;
++p;
if (p == (ZT_ENDPOINT_MAX_NAME_SIZE+1))
return -1;
}
return p;
case ETHERNET:
data[0] = (uint8_t)ETHERNET;
data[1] = (uint8_t)(_v.eth >> 40U);
data[2] = (uint8_t)(_v.eth >> 32U);
data[3] = (uint8_t)(_v.eth >> 24U);
data[4] = (uint8_t)(_v.eth >> 16U);
data[5] = (uint8_t)(_v.eth >> 8U);
data[6] = (uint8_t)_v.eth;
return 7;
default:
data[0] = (uint8_t)NIL;
return 1;
}
}
inline int unmarshal(const uint8_t *restrict data,const int len)
{
if (len <= 0)
return -1;
int p;
switch((Type)data[0]) {
case NIL:
_t = NIL;
return 1;
case INETADDR:
_t = INETADDR;
return reinterpret_cast<InetAddress *>(&_v.sa)->unmarshal(data+1,len-1);
case DNSNAME:
if (len < 4)
return -1;
_t = DNSNAME;
p = 1;
for (;;) {
if ((_v.dns.name[p-1] = (char)data[p]) == 0) {
++p;
break;
}
++p;
if ((p >= (ZT_ENDPOINT_MAX_NAME_SIZE+1))||(p >= (len-2)))
return -1;
}
_v.dns.port = (uint16_t)(((unsigned int)data[p++]) << 8U);
_v.dns.port |= (uint16_t)data[p++];
return p;
case ZEROTIER:
if (len < (ZT_IDENTITY_HASH_SIZE + 6))
return -1;
_t = ZEROTIER;
_v.zt.a = ((uint64_t)data[1]) << 32U;
_v.zt.a |= ((uint64_t)data[2]) << 24U;
_v.zt.a |= ((uint64_t)data[3]) << 16U;
_v.zt.a |= ((uint64_t)data[4]) << 8U;
_v.zt.a |= (uint64_t)data[5];
memcpy(_v.zt.idh,data + 6,ZT_IDENTITY_HASH_SIZE);
return (ZT_IDENTITY_HASH_SIZE + 6);
case URL:
if (len < 2)
return -1;
_t = URL;
p = 1;
for (;;) {
if ((_v.url[p-1] = (char)data[p]) == 0) {
++p;
break;
}
++p;
if ((p >= (ZT_ENDPOINT_MAX_NAME_SIZE+1))||(p >= len))
return -1;
}
return p;
case ETHERNET:
if (len < 7)
return -1;
_t = ZEROTIER;
_v.eth = ((uint64_t)data[1]) << 40U;
_v.eth |= ((uint64_t)data[2]) << 32U;
_v.eth |= ((uint64_t)data[3]) << 24U;
_v.eth |= ((uint64_t)data[4]) << 16U;
_v.eth |= ((uint64_t)data[5]) << 8U;
_v.eth |= (uint64_t)data[6];
return 7;
}
return false;
}
////////////////////////////////////////////////////////////////////////////
private:
Type _t;
union {
struct sockaddr_storage sa;
struct {
char name[ZT_ENDPOINT_MAX_NAME_SIZE];
uint16_t port;
} dns;
struct {
uint64_t a;
uint8_t idh[ZT_IDENTITY_HASH_SIZE];
} zt;
char url[ZT_ENDPOINT_MAX_NAME_SIZE];
uint64_t eth;
} _v;
};
} // namespace ZeroTier
#endif

@ -94,7 +94,7 @@ public:
/**
* @param bc Initial capacity in buckets (default: 32, must be nonzero)
*/
ZT_ALWAYS_INLINE Hashtable(unsigned long bc = 32) :
inline Hashtable(unsigned long bc = 32) :
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
_bc(bc),
_s(0)
@ -105,7 +105,7 @@ public:
_t[i] = (_Bucket *)0;
}
ZT_ALWAYS_INLINE Hashtable(const Hashtable<K,V> &ht) :
inline Hashtable(const Hashtable<K,V> &ht) :
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * ht._bc))),
_bc(ht._bc),
_s(ht._s)
@ -125,13 +125,13 @@ public:
}
}
ZT_ALWAYS_INLINE ~Hashtable()
inline ~Hashtable()
{
this->clear();
::free(_t);
}
ZT_ALWAYS_INLINE Hashtable &operator=(const Hashtable<K,V> &ht)
inline Hashtable &operator=(const Hashtable<K,V> &ht)
{
this->clear();
if (ht._s) {
@ -149,7 +149,7 @@ public:
/**
* Erase all entries
*/
ZT_ALWAYS_INLINE void clear()
inline void clear()
{
if (_s) {
for(unsigned long i=0;i<_bc;++i) {
@ -168,7 +168,7 @@ public:
/**
* @return Vector of all keys
*/
ZT_ALWAYS_INLINE typename std::vector<K> keys() const
inline typename std::vector<K> keys() const
{
typename std::vector<K> k;
if (_s) {
@ -191,7 +191,7 @@ public:
* @tparam Type of V (generally inferred)
*/
template<typename C>
ZT_ALWAYS_INLINE void appendKeys(C &v) const
inline void appendKeys(C &v) const
{
if (_s) {
for(unsigned long i=0;i<_bc;++i) {
@ -207,7 +207,7 @@ public:
/**
* @return Vector of all entries (pairs of K,V)
*/
ZT_ALWAYS_INLINE typename std::vector< std::pair<K,V> > entries() const
inline typename std::vector< std::pair<K,V> > entries() const
{
typename std::vector< std::pair<K,V> > k;
if (_s) {
@ -227,7 +227,7 @@ public:
* @param k Key
* @return Pointer to value or NULL if not found
*/
ZT_ALWAYS_INLINE V *get(const K k)
inline V *get(const K k)
{
_Bucket *b = _t[_hc(k) % _bc];
while (b) {
@ -237,14 +237,14 @@ public:
}
return (V *)0;
}
ZT_ALWAYS_INLINE const V *get(const K k) const { return const_cast<Hashtable *>(this)->get(k); }
inline const V *get(const K k) const { return const_cast<Hashtable *>(this)->get(k); }
/**
* @param k Key
* @param v Value to fill with result
* @return True if value was found and set (if false, v is not modified)
*/
ZT_ALWAYS_INLINE bool get(const K &k,V &v) const
inline bool get(const K &k,V &v) const
{
_Bucket *b = _t[_hc(k) % _bc];
while (b) {
@ -261,7 +261,7 @@ public:
* @param k Key to check
* @return True if key is present
*/
ZT_ALWAYS_INLINE bool contains(const K &k) const
inline bool contains(const K &k) const
{
_Bucket *b = _t[_hc(k) % _bc];
while (b) {
@ -276,7 +276,7 @@ public:
* @param k Key
* @return True if value was present
*/
ZT_ALWAYS_INLINE bool erase(const K &k)
inline bool erase(const K &k)
{
const unsigned long bidx = _hc(k) % _bc;
_Bucket *lastb = (_Bucket *)0;
@ -301,7 +301,7 @@ public:
* @param v Value
* @return Reference to value in table
*/
ZT_ALWAYS_INLINE V &set(const K &k,const V &v)
inline V &set(const K &k,const V &v)
{
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
@ -331,7 +331,7 @@ public:
* @param k Key
* @return Value, possibly newly created
*/
ZT_ALWAYS_INLINE V &operator[](const K k)
inline V &operator[](const K k)
{
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
@ -376,7 +376,7 @@ private:
static ZT_ALWAYS_INLINE unsigned long _hc(void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
static ZT_ALWAYS_INLINE unsigned long _hc(const void *p) { return ((unsigned long)((uintptr_t)p) * (unsigned long)0x9e3779b1); }
ZT_ALWAYS_INLINE void _grow()
inline void _grow()
{
const unsigned long nc = _bc * 2;
_Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc));

@ -11,10 +11,8 @@
*/
/****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <cstring>
#include <cstdint>
#include "Constants.hpp"
#include "Identity.hpp"
@ -100,8 +98,13 @@ void Identity::generate(const Type t)
delete [] genmem;
if (t == P384) {
// We sign with both because in pure FIPS environments we might have to say
// that we do not rely on any non-FIPS algorithms, or may even have to disable
// them.
ECC384GenerateKey(_pub.p384,_priv.p384);
C25519::sign(_priv.c25519,_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.p384s);
C25519::sign(_priv.c25519,_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.c25519s);
SHA384(digest,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE);
ECC384ECDSASign(_priv.p384,digest,_pub.p384s);
}
}
@ -116,7 +119,10 @@ bool Identity::locallyValidate() const
case C25519:
break;
case P384:
if (!C25519::verify(_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.p384s,ZT_C25519_SIGNATURE_LEN))
if (!C25519::verify(_pub.c25519,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE,_pub.c25519s,ZT_C25519_SIGNATURE_LEN))
return false;
SHA384(digest,&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE);
if (!ECC384ECDSAVerify(_pub.p384,digest,_pub.p384s))
return false;
default:
return false;
@ -135,6 +141,108 @@ bool Identity::locallyValidate() const
return false;
}
bool Identity::hash(uint8_t h[48],const bool includePrivate) const
{
switch(_type) {
case C25519:
if ((_hasPrivate)&&(includePrivate))
SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
else SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
return true;
case P384:
if ((_hasPrivate)&&(includePrivate))
SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv));
else SHA384(h,&_pub,sizeof(_pub));
return true;
}
return false;
}
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
{
if (_hasPrivate) {
switch(_type) {
case C25519:
if (siglen >= ZT_C25519_SIGNATURE_LEN) {
C25519::sign(_priv.c25519,_pub.c25519,data,len,sig);
return ZT_C25519_SIGNATURE_LEN;
}
case P384:
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
// When signing with P384 we also hash the C25519 public key as an
// extra measure to ensure that only this identity can verify.
uint8_t h[48];
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
return ZT_ECC384_SIGNATURE_SIZE;
}
}
}
return 0;
}
bool Identity::verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
{
switch(_type) {
case C25519:
return C25519::verify(_pub.c25519,data,len,sig,siglen);
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
}
break;
}
return false;
}
bool Identity::agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const
{
uint8_t rawkey[128];
uint8_t h[64];
if (_hasPrivate) {
if (_type == C25519) {
if ((id._type == C25519)||(id._type == P384)) {
// If we are a C25519 key we can agree with another C25519 key or with only the
// C25519 portion of a type 1 P-384 key.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
return true;
}
} else if (_type == P384) {
if (id._type == P384) {
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
return true;
} else if (id._type == C25519) {
// If the other identity is a C25519 identity we can agree using only that type.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
return true;
}
}
}
return false;
}
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{
switch(_type) {
@ -224,7 +332,7 @@ bool Identity::fromString(const char *str)
switch(_type) {
case C25519:
if (Utils::unhex(f,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
if (Utils::unhex(f,strlen(f),_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
_address.zero();
return false;
}
@ -245,7 +353,7 @@ bool Identity::fromString(const char *str)
switch(_type) {
case C25519:
if (Utils::unhex(f,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
if (Utils::unhex(f,strlen(f),_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
_address.zero();
return false;
} else {
@ -278,3 +386,99 @@ bool Identity::fromString(const char *str)
}
} // namespace ZeroTier
extern "C" {
ZT_Identity *ZT_Identity_new(enum ZT_Identity_Type type)
{
if ((type != ZT_IDENTITY_TYPE_C25519)&&(type != ZT_IDENTITY_TYPE_P384))
return nullptr;
try {
ZeroTier::Identity *id = new ZeroTier::Identity();
id->generate((ZeroTier::Identity::Type)type);
return reinterpret_cast<ZT_Identity *>(id);
} catch ( ... ) {
return nullptr;
}
}
ZT_Identity *ZT_Identity_fromString(const char *idStr)
{
if (!idStr)
return nullptr;
try {
ZeroTier::Identity *id = new ZeroTier::Identity();
if (!id->fromString(idStr)) {
delete id;
return nullptr;
}
return reinterpret_cast<ZT_Identity *>(id);
} catch ( ... ) {
return nullptr;
}
}
int ZT_Identity_validate(const ZT_Identity *id)
{
if (!id)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->locallyValidate() ? 1 : 0;
}
unsigned int ZT_Identity_sign(const ZT_Identity *id,const void *data,unsigned int len,void *signature,unsigned int signatureBufferLength)
{
if (!id)
return 0;
if (signatureBufferLength < ZT_SIGNATURE_BUFFER_SIZE)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->sign(data,len,signature,signatureBufferLength);
}
int ZT_Identity_verify(const ZT_Identity *id,const void *data,unsigned int len,const void *signature,unsigned int sigLen)
{
if ((!id)||(!signature)||(!sigLen))
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->verify(data,len,signature,sigLen) ? 1 : 0;
}
enum ZT_Identity_Type ZT_Identity_type(const ZT_Identity *id)
{
if (!id)
return (ZT_Identity_Type)0;
return (enum ZT_Identity_Type)reinterpret_cast<const ZeroTier::Identity *>(id)->type();
}
char *ZT_Identity_toString(const ZT_Identity *id,char *buf,int capacity,int includePrivate)
{
if ((!id)||(!buf)||(capacity < ZT_IDENTITY_STRING_BUFFER_LENGTH))
return nullptr;
reinterpret_cast<const ZeroTier::Identity *>(id)->toString(includePrivate != 0,buf);
return buf;
}
int ZT_Identity_hasPrivate(const ZT_Identity *id)
{
if (!id)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->hasPrivate() ? 1 : 0;
}
uint64_t ZT_Identity_address(const ZT_Identity *id)
{
if (!id)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->address().toInt();
}
void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate)
{
reinterpret_cast<const ZeroTier::Identity *>(id)->hash(h,includePrivate != 0);
}
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)
{
if (id)
delete reinterpret_cast<ZeroTier::Identity *>(id);
}
}

@ -14,8 +14,8 @@
#ifndef ZT_IDENTITY_HPP
#define ZT_IDENTITY_HPP
#include <stdio.h>
#include <stdlib.h>
#include <cstdio>
#include <cstdlib>
#include "Constants.hpp"
#include "Utils.hpp"
@ -27,6 +27,11 @@
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE)
#define ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE)
#define ZT_IDENTITY_MARSHAL_SIZE_MAX (ZT_ADDRESS_LENGTH + 4 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE)
namespace ZeroTier {
/**
@ -52,15 +57,17 @@ public:
};
ZT_ALWAYS_INLINE Identity() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
ZT_ALWAYS_INLINE Identity(const char *str)
{
if (!fromString(str))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
template<unsigned int C>
ZT_ALWAYS_INLINE Identity(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
ZT_ALWAYS_INLINE ~Identity() { Utils::burn(reinterpret_cast<void *>(&this->_priv),sizeof(this->_priv)); }
ZT_ALWAYS_INLINE ~Identity() { Utils::burn(reinterpret_cast<void *>(this),sizeof(Identity)); }
/**
* Construct identity from string
*
* If the identity is not basically valid (no deep checking is done) the result will
* be a null identity.
*
* @param str Identity in canonical string format
*/
explicit ZT_ALWAYS_INLINE Identity(const char *str) { fromString(str); }
/**
* Set identity to NIL value (all zero)
@ -68,18 +75,18 @@ public:
ZT_ALWAYS_INLINE void zero() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
/**
* @return Identity type
* @return Identity type (undefined if identity is null or invalid)
*/
ZT_ALWAYS_INLINE Type type() const { return _type; }
/**
* Generate a new identity (address, key pair)
*
* This is a time consuming operation.
* This is a time consuming operation taking up to 5-10 seconds on some slower systems.
*
* @param t Type of identity to generate
*/
void generate(const Type t);
void generate(Type t);
/**
* Check the validity of this identity's pairing of key to address
@ -94,41 +101,12 @@ public:
ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; }
/**
* Compute the SHA512 hash of our private key (if we have one)
* This generates a SHA384 hash of this identity's keys.
*
* @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length)
* @return True on success, false if no private key
*/
ZT_ALWAYS_INLINE bool sha512PrivateKey(void *const sha) const
{
if (_hasPrivate) {
switch(_type) {
case C25519:
SHA512(sha,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
return true;
case P384:
SHA512(sha,&_priv,sizeof(_priv));
return true;
}
}
return false;
}
/**
* @param h Buffer to receive SHA384 of public key(s)
* @param includePrivate If true, hash private key(s) as well
*/
ZT_ALWAYS_INLINE bool hash(uint8_t h[48]) const
{
switch(_type) {
case C25519:
SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
return true;
case P384:
SHA384(h,&_pub,sizeof(_pub));
return true;
}
return false;
}
bool hash(uint8_t h[48],bool includePrivate = false) const;
/**
* Sign a message with this identity (private key required)
@ -142,31 +120,7 @@ public:
* @param siglen Length of buffer
* @return Number of bytes actually written to sig or 0 on error
*/
ZT_ALWAYS_INLINE unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
{
if (_hasPrivate) {
switch(_type) {
case C25519:
if (siglen >= ZT_C25519_SIGNATURE_LEN) {
C25519::sign(_priv.c25519,_pub.c25519,data,len,sig);
return ZT_C25519_SIGNATURE_LEN;
}
case P384:
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
// Signature hash includes the C25519/Ed25519 public key after the message.
// This is an added guard against divorcing these two bound keys.
uint8_t h[48];
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
return ZT_ECC384_SIGNATURE_SIZE;
}
}
}
return 0;
}
unsigned int sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const;
/**
* Verify a message signature against this identity
@ -177,21 +131,7 @@ public:
* @param siglen Length of signature in bytes
* @return True if signature validates and data integrity checks
*/
ZT_ALWAYS_INLINE bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
{
switch(_type) {
case C25519:
return C25519::verify(_pub.c25519,data,len,sig,siglen);
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
}
break;
}
return false;
}
bool verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const;
/**
* Shortcut method to perform key agreement with another identity
@ -202,78 +142,21 @@ public:
* @param key Result parameter to fill with key bytes
* @return Was agreement successful?
*/
ZT_ALWAYS_INLINE bool agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const
{
uint8_t rawkey[128];
uint8_t h[64];
if (_hasPrivate) {
if (_type == C25519) {
if ((id._type == C25519)||(id._type == P384)) {
// If we are a C25519 key we can agree with another C25519 key or with only the
// C25519 portion of a type 1 P-384 key.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
return true;
}
} else if (_type == P384) {
if (id._type == P384) {
// Perform key agreement over both curves for the same reason that C25519 public
// keys are included in P-384 signature inputs: to bind the keys together so
// that a type 1 identity with the same C25519 public key (and therefore address)
// but a different P-384 key will not work.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
return true;
} else if (id._type == C25519) {
// If the other identity is a C25519 identity we can agree using only that type.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
SHA512(h,rawkey,ZT_C25519_SHARED_KEY_LEN);
memcpy(key,h,ZT_PEER_SECRET_KEY_LENGTH);
return true;
}
}
}
return false;
}
bool agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) const;
/**
* @return This identity's address
*/
ZT_ALWAYS_INLINE const Address &address() const { return _address; }
/**
* Attempt to generate an older type identity from a newer type
*
* If this identity has its private key this is not transferred to
* the downgraded identity.
*
* @param dest Destination to fill with downgraded identity
* @param toType Desired identity type
*/
ZT_ALWAYS_INLINE bool downgrade(Identity &dest,const Type toType)
{
if ((_type == P384)&&(toType == C25519)) {
dest._address = _address;
dest._type = C25519;
dest._hasPrivate = false;
memcpy(dest._pub.c25519,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
return true;
}
return false;
}
/**
* Serialize this identity (binary)
*
* @param b Destination buffer to append to
* @param includePrivate If true, include private key component (if present) (default: false)
* @throws std::out_of_range Buffer too small
*/
template<unsigned int C>
ZT_ALWAYS_INLINE void serialize(Buffer<C> &b,bool includePrivate = false) const
inline void serialize(Buffer<C> &b,bool includePrivate = false) const
{
_address.appendTo(b);
switch(_type) {
@ -291,9 +174,7 @@ public:
case P384:
b.append((uint8_t)P384);
b.append(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
b.append(_pub.p384,ZT_ECC384_PUBLIC_KEY_SIZE);
b.append(_pub.p384s,ZT_C25519_SIGNATURE_LEN);
b.append(&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
if ((_hasPrivate)&&(includePrivate)) {
b.append((uint8_t)(ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE));
b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
@ -301,7 +182,7 @@ public:
} else {
b.append((uint8_t)0);
}
b.append((uint16_t)0); // size of additional fields
b.append((uint8_t)0); // size of additional fields (should have included such a thing in v0!)
break;
}
@ -316,11 +197,9 @@ public:
* @param b Buffer containing serialized data
* @param startAt Index within buffer of serialized data (default: 0)
* @return Length of serialized data read from buffer
* @throws std::out_of_range Serialized data invalid
* @throws std::invalid_argument Serialized data invalid
*/
template<unsigned int C>
ZT_ALWAYS_INLINE unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
_hasPrivate = false;
unsigned int p = startAt;
@ -347,12 +226,8 @@ public:
break;
case P384:
memcpy(_pub.c25519,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
memcpy(_pub.p384,b.field(p,ZT_ECC384_PUBLIC_KEY_SIZE),ZT_ECC384_PUBLIC_KEY_SIZE);
p += ZT_ECC384_PUBLIC_KEY_SIZE;
memcpy(_pub.p384s,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_ECC384_SIGNATURE_SIZE;
memcpy(&_pub,b.field(p,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE),ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
p += ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE;
pkl = (unsigned int)b[p++];
if (pkl) {
if (pkl != (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE))
@ -365,7 +240,7 @@ public:
} else {
_hasPrivate = false;
}
p += b.template at<uint16_t>(p) + 2;
p += b.template at<uint8_t>(p) + 2;
break;
default:
@ -381,7 +256,7 @@ public:
*
* @param includePrivate If true, include private key (if it exists)
* @param buf Buffer to store string
* @return ASCII string representation of identity
* @return ASCII string representation of identity (pointer to buf)
*/
char *toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
@ -399,18 +274,15 @@ public:
/**
* @return True if this identity contains something
*/
ZT_ALWAYS_INLINE operator bool() const { return (_address); }
explicit ZT_ALWAYS_INLINE operator bool() const { return (_address); }
ZT_ALWAYS_INLINE bool operator==(const Identity &id) const
{
if ((_address == id._address)&&(_type == id._type)) {
switch(_type) {
case C25519:
return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) == 0);
case P384:
return (memcmp(&_pub,&id._pub,sizeof(_pub)) == 0);
default:
return false;
case C25519: return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) == 0);
// case P384:
default: return (memcmp(&_pub,&id._pub,sizeof(_pub)) == 0);
}
}
return false;
@ -424,10 +296,9 @@ public:
return true;
if (_type == id._type) {
switch(_type) {
case C25519:
return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) < 0);
case P384:
return (memcmp(&_pub,&id._pub,sizeof(_pub)) < 0);
case C25519: return (memcmp(_pub.c25519,id._pub.c25519,ZT_C25519_PUBLIC_KEY_LEN) < 0);
// case P384:
default: return (memcmp(&_pub,&id._pub,sizeof(_pub)) < 0);
}
}
}
@ -440,18 +311,102 @@ public:
ZT_ALWAYS_INLINE unsigned long hashCode() const { return ((unsigned long)_address.toInt() + (unsigned long)_pub.c25519[0] + (unsigned long)_pub.c25519[1] + (unsigned long)_pub.c25519[2]); }
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
inline int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const
{
_address.copyTo(data,ZT_ADDRESS_LENGTH);
switch(_type) {
case C25519:
data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
if ((includePrivate)&&(_hasPrivate)) {
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN;
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
}
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
case P384:
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
if ((includePrivate)&&(_hasPrivate)) {
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE;
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE] = 0;
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1);
}
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1] = 0;
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
}
return -1;
}
inline int unmarshal(const uint8_t *restrict data,const int len)
{
if (len < (ZT_ADDRESS_LENGTH + 1))
return -1;
unsigned int privlen;
switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
case C25519:
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
return -1;
memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
if (privlen == ZT_C25519_PRIVATE_KEY_LEN) {
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
return -1;
_hasPrivate = true;
memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN);
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
} else if (privlen == 0) {
_hasPrivate = false;
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
}
break;
case P384:
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2))
return -1;
memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1))
return -1;
_hasPrivate = true;
memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE];
if (len < (privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)))
return -1;
return (int)(privlen + (unsigned int)(ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1));
} else if (privlen == 0) {
_hasPrivate = false;
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
}
break;
}
return -1;
}
////////////////////////////////////////////////////////////////////////////
private:
Address _address;
Type _type;
Type _type; // _type determines which fields in _priv and _pub are used
bool _hasPrivate;
ZT_PACKED_STRUCT(struct { // don't re-order these
uint8_t c25519[ZT_C25519_PRIVATE_KEY_LEN];
uint8_t p384[ZT_ECC384_PRIVATE_KEY_SIZE];
}) _priv;
ZT_PACKED_STRUCT(struct { // don't re-order these
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN];
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE];
uint8_t p384s[ZT_C25519_SIGNATURE_LEN]; // signature of both keys with ed25519 to confirm type 0 extension to type 1
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN]; // Curve25519 and Ed25519 public keys
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE]; // NIST P-384 public key
uint8_t c25519s[ZT_C25519_SIGNATURE_LEN]; // signature of both keys with ed25519
uint8_t p384s[ZT_ECC384_SIGNATURE_SIZE]; // signature of both keys with p384
}) _pub;
};

File diff suppressed because it is too large Load Diff

@ -14,8 +14,6 @@
#ifndef ZT_INCOMINGPACKET_HPP
#define ZT_INCOMINGPACKET_HPP
#include <stdexcept>
#include "Packet.hpp"
#include "Path.hpp"
#include "Utils.hpp"
@ -43,17 +41,10 @@ namespace ZeroTier {
class RuntimeEnvironment;
class Network;
/**
* Subclass of packet that handles the decoding of it
*/
class IncomingPacket : public Packet
{
public:
ZT_ALWAYS_INLINE IncomingPacket() :
Packet(),
_receiveTime(0)
{
}
ZT_ALWAYS_INLINE IncomingPacket() : Packet(),_receiveTime(0),_path() {}
/**
* Create a new packet-in-decode
@ -108,30 +99,6 @@ public:
ZT_ALWAYS_INLINE uint64_t receiveTime() const { return _receiveTime; }
private:
// These are called internally to handle packet contents once it has
// been authenticated, decrypted, decompressed, and classified.
bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid);
uint64_t _receiveTime;
SharedPtr<Path> _path;
};

@ -11,11 +11,8 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <string>
#include <cstring>
#include <cstdint>
#include "Constants.hpp"
#include "InetAddress.hpp"
@ -33,20 +30,20 @@ InetAddress::IpScope InetAddress::ipScope() const
case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
switch(ip >> 24) {
switch(ip >> 24U) {
case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x0b: //return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15: //return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: //return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: //return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a: //return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c: //return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d: //return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e: //return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33: //return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37: //return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
case 0x64:
if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE; // 100.64.0.0/10
@ -164,7 +161,7 @@ bool InetAddress::fromString(const char *ipSlashPort)
unsigned int port = 0;
if (*portAt) {
*(portAt++) = (char)0;
port = Utils::strToUInt(portAt) & 0xffff;
port = Utils::strToUInt(portAt) & 0xffffU;
}
if (strchr(buf,':')) {
@ -189,7 +186,7 @@ InetAddress InetAddress::netmask() const
InetAddress r(*this);
switch(r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
break;
case AF_INET6: {
uint64_t nm[2];
@ -211,7 +208,7 @@ InetAddress InetAddress::broadcast() const
{
if (ss_family == AF_INET) {
InetAddress r(*this);
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffffU >> netmaskBits()));
return r;
}
return InetAddress();
@ -222,7 +219,7 @@ InetAddress InetAddress::network() const
InetAddress r(*this);
switch(r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
break;
case AF_INET6: {
uint64_t nm[2];
@ -294,7 +291,7 @@ bool InetAddress::isNetwork() const
if (bits >= 32)
return false;
uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
return ((ip & (0xffffffff >> bits)) == 0);
return ((ip & (0xffffffffU >> bits)) == 0);
}
case AF_INET6: {
unsigned int bits = netmaskBits();
@ -304,7 +301,7 @@ bool InetAddress::isNetwork() const
return false;
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
unsigned int p = bits / 8;
if ((ip[p++] & (0xff >> (bits % 8))) != 0)
if ((ip[p++] & (0xffU >> (bits % 8))) != 0)
return false;
while (p < 16) {
if (ip[p++])
@ -378,48 +375,49 @@ bool InetAddress::operator<(const InetAddress &a) const
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
{
struct sockaddr_in6 sin6;
sin6.sin6_family = AF_INET6;
sin6.sin6_addr.s6_addr[0] = 0xfe;
sin6.sin6_addr.s6_addr[1] = 0x80;
sin6.sin6_addr.s6_addr[2] = 0x00;
sin6.sin6_addr.s6_addr[3] = 0x00;
sin6.sin6_addr.s6_addr[4] = 0x00;
sin6.sin6_addr.s6_addr[5] = 0x00;
sin6.sin6_addr.s6_addr[6] = 0x00;
sin6.sin6_addr.s6_addr[7] = 0x00;
sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd;
sin6.sin6_addr.s6_addr[9] = mac[1];
sin6.sin6_addr.s6_addr[10] = mac[2];
sin6.sin6_addr.s6_addr[11] = 0xff;
sin6.sin6_addr.s6_addr[12] = 0xfe;
sin6.sin6_addr.s6_addr[13] = mac[3];
sin6.sin6_addr.s6_addr[14] = mac[4];
sin6.sin6_addr.s6_addr[15] = mac[5];
sin6.sin6_port = Utils::hton((uint16_t)64);
return InetAddress(sin6);
InetAddress r;
sockaddr_in6 *const sin6 = reinterpret_cast<sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfe;
sin6->sin6_addr.s6_addr[1] = 0x80;
sin6->sin6_addr.s6_addr[2] = 0x00;
sin6->sin6_addr.s6_addr[3] = 0x00;
sin6->sin6_addr.s6_addr[4] = 0x00;
sin6->sin6_addr.s6_addr[5] = 0x00;
sin6->sin6_addr.s6_addr[6] = 0x00;
sin6->sin6_addr.s6_addr[7] = 0x00;
sin6->sin6_addr.s6_addr[8] = mac[0] & 0xfdU;
sin6->sin6_addr.s6_addr[9] = mac[1];
sin6->sin6_addr.s6_addr[10] = mac[2];
sin6->sin6_addr.s6_addr[11] = 0xff;
sin6->sin6_addr.s6_addr[12] = 0xfe;
sin6->sin6_addr.s6_addr[13] = mac[3];
sin6->sin6_addr.s6_addr[14] = mac[4];
sin6->sin6_addr.s6_addr[15] = mac[5];
sin6->sin6_port = Utils::hton((uint16_t)64);
return r;
}
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
{
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
sockaddr_in6 *const sin6 = reinterpret_cast<sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfd;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40);
sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32);
sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8);
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56U);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48U);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40U);
sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32U);
sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24U);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16U);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8U);
sin6->sin6_addr.s6_addr[8] = (uint8_t)nwid;
sin6->sin6_addr.s6_addr[9] = 0x99;
sin6->sin6_addr.s6_addr[10] = 0x93;
sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32);
sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24);
sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16);
sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8);
sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32U);
sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24U);
sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16U);
sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8U);
sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress;
sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that
return r;
@ -427,19 +425,19 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
{
nwid ^= (nwid >> 32);
nwid ^= (nwid >> 32U);
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
sockaddr_in6 *const sin6 = reinterpret_cast<sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfc;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8);
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16U);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8U);
sin6->sin6_addr.s6_addr[4] = (uint8_t)nwid;
sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16);
sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8);
sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32U);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24U);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16U);
sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8U);
sin6->sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress;
sin6->sin6_addr.s6_addr[15] = 0x01;
sin6->sin6_port = Utils::hton((uint16_t)40);

@ -14,12 +14,13 @@
#ifndef ZT_INETADDRESS_HPP
#define ZT_INETADDRESS_HPP
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Utils.hpp"
#include "MAC.hpp"
#include "Buffer.hpp"
@ -41,6 +42,16 @@ namespace ZeroTier {
*/
struct InetAddress : public sockaddr_storage
{
private:
template<typename SA>
ZT_ALWAYS_INLINE void copySockaddrToThis(const SA *sa)
{
memcpy(reinterpret_cast<void *>(this),sa,sizeof(SA));
if (sizeof(SA) < sizeof(InetAddress))
memset(reinterpret_cast<char *>(this) + sizeof(SA),0,sizeof(InetAddress) - sizeof(SA));
}
public:
/**
* Loopback IPv4 address (no port)
*/
@ -75,123 +86,86 @@ struct InetAddress : public sockaddr_storage
IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
};
// Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core
// but this is safe to put here.
struct Hasher
{
ZT_ALWAYS_INLINE std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); }
};
// Hasher for unordered sets and maps in C++11
struct Hasher { ZT_ALWAYS_INLINE std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); } };
ZT_ALWAYS_INLINE InetAddress() { memset(this,0,sizeof(InetAddress)); }
ZT_ALWAYS_INLINE InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); }
ZT_ALWAYS_INLINE InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 &sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 *sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress() { memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress)); }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr &sa) { *this = sa; }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr *sa) { *this = sa; }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in &sa) { *this = sa; }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in *sa) { *this = sa; }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 &sa) { *this = sa; }
explicit ZT_ALWAYS_INLINE InetAddress(const struct sockaddr_in6 *sa) { *this = sa; }
ZT_ALWAYS_INLINE InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); }
ZT_ALWAYS_INLINE InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); }
ZT_ALWAYS_INLINE InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); }
explicit ZT_ALWAYS_INLINE InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); }
ZT_ALWAYS_INLINE void clear() { memset(this,0,sizeof(InetAddress)); }
ZT_ALWAYS_INLINE InetAddress &operator=(const InetAddress &a)
{
if (&a != this)
memcpy(this,&a,sizeof(InetAddress));
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const InetAddress *a)
{
if (a != this)
memcpy(this,a,sizeof(InetAddress));
return *this;
}
ZT_ALWAYS_INLINE void clear() { memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress)); }
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage &ss)
{
if (reinterpret_cast<const InetAddress *>(&ss) != this)
memcpy(this,&ss,sizeof(InetAddress));
memcpy(reinterpret_cast<void *>(this),&ss,sizeof(InetAddress));
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_storage *ss)
{
if (reinterpret_cast<const InetAddress *>(ss) != this)
memcpy(this,ss,sizeof(InetAddress));
if (ss)
memcpy(reinterpret_cast<void *>(this),ss,sizeof(InetAddress));
else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in &sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in));
}
copySockaddrToThis(&sa);
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in *sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in));
}
if (sa)
copySockaddrToThis(sa);
else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 &sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in6));
}
copySockaddrToThis(&sa);
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr_in6 *sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in6));
}
if (sa)
copySockaddrToThis(sa);
else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr &sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
switch(sa.sa_family) {
case AF_INET:
memcpy(this,&sa,sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(this,&sa,sizeof(struct sockaddr_in6));
break;
}
}
if (sa.sa_family == AF_INET)
copySockaddrToThis(reinterpret_cast<const sockaddr_in *>(&sa));
else if (sa.sa_family == AF_INET6)
copySockaddrToThis(reinterpret_cast<const sockaddr_in6 *>(&sa));
else memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
return *this;
}
ZT_ALWAYS_INLINE InetAddress &operator=(const struct sockaddr *sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
switch(sa->sa_family) {
case AF_INET:
memcpy(this,sa,sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(this,sa,sizeof(struct sockaddr_in6));
break;
}
if (sa) {
if (sa->sa_family == AF_INET)
copySockaddrToThis(reinterpret_cast<const sockaddr_in *>(sa));
else if (sa->sa_family == AF_INET6)
copySockaddrToThis(reinterpret_cast<const sockaddr_in6 *>(sa));
return *this;
}
memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
return *this;
}
@ -468,16 +442,16 @@ struct InetAddress : public sockaddr_storage
unsigned long h = 0;
switch(ss_family) {
case AF_INET:
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
h ^= (h >> 14);
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00U) >> 8U;
h ^= (h >> 14U);
break;
case AF_INET6: {
const uint8_t *ip = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
h = ((unsigned long)ip[0]); h <<= 1;
h += ((unsigned long)ip[1]); h <<= 1;
h += ((unsigned long)ip[2]); h <<= 1;
h += ((unsigned long)ip[3]); h <<= 1;
h += ((unsigned long)ip[4]); h <<= 1;
h = ((unsigned long)ip[0]); h <<= 1U;
h += ((unsigned long)ip[1]); h <<= 1U;
h += ((unsigned long)ip[2]); h <<= 1U;
h += ((unsigned long)ip[3]); h <<= 1U;
h += ((unsigned long)ip[4]); h <<= 1U;
h += ((unsigned long)ip[5]);
} break;
}
@ -487,10 +461,85 @@ struct InetAddress : public sockaddr_storage
/**
* @return True if address family is non-zero
*/
ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
explicit ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return 19; }
inline int marshal(uint8_t data[19]) const
{
unsigned int port;
switch(ss_family) {
case AF_INET:
port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in *>(this)->sin_port);
data[0] = 4;
data[1] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[0];
data[2] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[1];
data[3] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[2];
data[4] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[3];
data[5] = (uint8_t)(port >> 8U);
data[6] = (uint8_t)port;
return 7;
case AF_INET6:
port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in6 *>(this)->sin6_port);
data[0] = 6;
for(int i=0;i<16;++i)
data[i+1] = reinterpret_cast<const sockaddr_in6 *>(this)->sin6_addr.s6_addr[i];
data[17] = (uint8_t)(port >> 8U);
data[18] = (uint8_t)port;
return 19;
default:
data[0] = 0;
return 1;
}
}
inline int unmarshal(const uint8_t *restrict data,const int len)
{
#ifdef ZT_NO_TYPE_PUNNING
uint16_t tmp;
#endif
if (len <= 0)
return -1;
switch(data[0]) {
case 0:
return 1;
case 4:
if (len < 7)
return -1;
memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
reinterpret_cast<sockaddr_in *>(this)->sin_family = AF_INET;
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[0] = data[1];
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[1] = data[2];
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[2] = data[3];
reinterpret_cast<uint8_t *>(&(reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr))[3] = data[4];
#ifdef ZT_NO_TYPE_PUNNING
memcpy(&tmp,data + 5,2);
reinterpret_cast<sockaddr_in *>(this)->sin_port = tmp;
#else
reinterpret_cast<sockaddr_in *>(this)->sin_port = *((const uint16_t *)(data + 5));
#endif
return 7;
case 6:
if (len < 19)
return -1;
memset(reinterpret_cast<void *>(this),0,sizeof(InetAddress));
reinterpret_cast<sockaddr_in6 *>(this)->sin6_family = AF_INET6;
for(int i=0;i<16;i++)
(reinterpret_cast<sockaddr_in6 *>(this)->sin6_addr.s6_addr)[i] = data[i+1];
#ifdef ZT_NO_TYPE_PUNNING
memcpy(&tmp,data + 17,2);
reinterpret_cast<sockaddr_in *>(this)->sin_port = tmp;
#else
reinterpret_cast<sockaddr_in *>(this)->sin_port = *((const uint16_t *)(data + 17));
#endif
return 19;
default:
return -1;
}
}
////////////////////////////////////////////////////////////////////////////
template<unsigned int C>
ZT_ALWAYS_INLINE void serialize(Buffer<C> &b) const
inline void serialize(Buffer<C> &b) const
{
// This is used in the protocol and must be the same as describe in places
// like VERB_HELLO in Packet.hpp.
@ -512,7 +561,7 @@ struct InetAddress : public sockaddr_storage
}
template<unsigned int C>
ZT_ALWAYS_INLINE unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
memset(this,0,sizeof(InetAddress));
unsigned int p = startAt;
@ -607,6 +656,13 @@ struct InetAddress : public sockaddr_storage
static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress);
};
static ZT_ALWAYS_INLINE InetAddress *asInetAddress(sockaddr_in *p) { return reinterpret_cast<InetAddress *>(p); }
static ZT_ALWAYS_INLINE InetAddress *asInetAddress(sockaddr_in6 *p) { return reinterpret_cast<InetAddress *>(p); }
static ZT_ALWAYS_INLINE InetAddress *asInetAddress(sockaddr *p) { return reinterpret_cast<InetAddress *>(p); }
static ZT_ALWAYS_INLINE const InetAddress *asInetAddress(const sockaddr_in *p) { return reinterpret_cast<const InetAddress *>(p); }
static ZT_ALWAYS_INLINE const InetAddress *asInetAddress(const sockaddr_in6 *p) { return reinterpret_cast<const InetAddress *>(p); }
static ZT_ALWAYS_INLINE const InetAddress *asInetAddress(const sockaddr *p) { return reinterpret_cast<const InetAddress *>(p); }
} // namespace ZeroTier
#endif

106
node/Locator.cpp Normal file

@ -0,0 +1,106 @@
/*
* Copyright (c)2019 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2023-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#include "Locator.hpp"
namespace ZeroTier {
bool Locator::sign(const int64_t ts,const Identity &id)
{
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
if (!id.hasPrivate())
return false;
_ts = ts;
if (_endpointCount > 0)
std::sort(_at,_at + _endpointCount);
const unsigned int signLen = marshal(signData,true);
_signatureLength = id.sign(signData, signLen, _signature, sizeof(_signature));
return (_signatureLength > 0);
}
bool Locator::verify(const Identity &id) const
{
if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return false;
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const unsigned int signLen = marshal(signData,true);
return id.verify(signData,signLen,_signature,_signatureLength);
}
int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature) const
{
if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return -1;
Utils::putUInt64(data,(uint64_t)_ts);
int p = 8;
data[p++] = (uint8_t)(_endpointCount >> 8U);
data[p++] = (uint8_t)_endpointCount;
for(unsigned int i=0;i<_endpointCount;++i) {
int tmp = _at[i].marshal(data + p);
if (tmp < 0)
return -1;
p += tmp;
}
if (!excludeSignature) {
data[p++] = (uint8_t)(_signatureLength >> 8U);
data[p++] = (uint8_t)_signatureLength;
memcpy(data + p,_signature,_signatureLength);
p += (int)_signatureLength;
}
return p;
}
int Locator::unmarshal(const uint8_t *restrict data,const int len)
{
if (len <= (8 + 48))
return -1;
_ts = (int64_t)Utils::readUInt64(data);
int p = 8;
if ((p + 2) > len)
return -1;
unsigned int ec = (int)data[p++];
ec <<= 8U;
ec |= data[p++];
if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
return -1;
_endpointCount = ec;
for(int i=0;i<ec;++i) {
int tmp = _at[i].unmarshal(data + p,len - p);
if (tmp < 0)
return -1;
p += tmp;
}
if ((p + 2) > len)
return -1;
unsigned int sl = data[p++];
sl <<= 8U;
sl |= data[p++];
if (sl > ZT_SIGNATURE_BUFFER_SIZE)
return -1;
_signatureLength = sl;
if ((p + sl) > len)
return -1;
memcpy(_signature,data + p,sl);
p += (int)sl;
return p;
}
} // namespace ZeroTier

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