Loads of refactoring, integration of new version of Trace.

This commit is contained in:
Adam Ierymenko 2020-01-23 13:05:33 -08:00
parent e6273b3300
commit 33bb61c63d
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
52 changed files with 1603 additions and 910 deletions

View file

@ -44,7 +44,7 @@ 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, // 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. // hiding record values from anything but the controller or someone who has its key.
uint8_t sha384pk[48]; uint8_t sha384pk[48];
_myId.hash(sha384pk,true); _myId.hashWithPrivate(sha384pk);
char maskingKey [128]; char maskingKey [128];
Utils::hex(sha384pk,32,maskingKey); Utils::hex(sha384pk,32,maskingKey);

View file

@ -46,7 +46,6 @@
#include <mutex> #include <mutex>
#include <map> #include <map>
#include <vector> #include <vector>
#include <set>
#include <memory> #include <memory>
#include <atomic> #include <atomic>

View file

@ -495,7 +495,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
Port: tcpBindAddr.Port, Port: tcpBindAddr.Port,
}) })
if err != nil { if err != nil {
node.log.Printf("ERROR: unable to start API HTTP server at TCP bind address %s: %s (continuing anyway)", tcpBindAddr.String(), err.Error()) node.infoLog.Printf("ERROR: unable to start API HTTP server at TCP bind address %s: %s (named socket listener startd, continuing anyway)", tcpBindAddr.String(), err.Error())
} else { } else {
tcpHttpServer = &http.Server{ tcpHttpServer = &http.Server{
MaxHeaderBytes: 4096, MaxHeaderBytes: 4096,

View file

@ -57,7 +57,7 @@ type LocalConfigSettings struct {
// PortMapping enables uPnP and NAT-PMP support // PortMapping enables uPnP and NAT-PMP support
PortMapping bool `json:"portMapping"` PortMapping bool `json:"portMapping"`
// LogSizeMax is the maximum size of the log in kilobytes or 0 for no limit and -1 to disable logging // LogSizeMax is the maximum size of the infoLog in kilobytes or 0 for no limit and -1 to disable logging
LogSizeMax int `json:"logSizeMax"` LogSizeMax int `json:"logSizeMax"`
// IP/port to bind for TCP access to control API (disabled if null) // IP/port to bind for TCP access to control API (disabled if null)

View file

@ -203,7 +203,7 @@ func (n *Network) LocalSettings() NetworkLocalSettings {
// MulticastSubscribe subscribes to a multicast group // MulticastSubscribe subscribes to a multicast group
func (n *Network) MulticastSubscribe(mg *MulticastGroup) { func (n *Network) MulticastSubscribe(mg *MulticastGroup) {
n.node.log.Printf("%.16x joined multicast group %s", uint64(n.id), mg.String()) n.node.infoLog.Printf("%.16x joined multicast group %s", uint64(n.id), mg.String())
k := mg.key() k := mg.key()
n.multicastSubscriptionsLock.Lock() n.multicastSubscriptionsLock.Lock()
if _, have := n.multicastSubscriptions[k]; have { if _, have := n.multicastSubscriptions[k]; have {
@ -217,7 +217,7 @@ func (n *Network) MulticastSubscribe(mg *MulticastGroup) {
// MulticastUnsubscribe removes a subscription to a multicast group // MulticastUnsubscribe removes a subscription to a multicast group
func (n *Network) MulticastUnsubscribe(mg *MulticastGroup) { func (n *Network) MulticastUnsubscribe(mg *MulticastGroup) {
n.node.log.Printf("%.16x left multicast group %s", uint64(n.id), mg.String()) n.node.infoLog.Printf("%.16x left multicast group %s", uint64(n.id), mg.String())
n.multicastSubscriptionsLock.Lock() n.multicastSubscriptionsLock.Lock()
delete(n.multicastSubscriptions, mg.key()) delete(n.multicastSubscriptions, mg.key())
n.multicastSubscriptionsLock.Unlock() n.multicastSubscriptionsLock.Unlock()
@ -311,7 +311,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
k := ipNetToKey(&ip) k := ipNetToKey(&ip)
wantAssignedIPs[k] = true wantAssignedIPs[k] = true
if _, have := haveAssignedIPs[k]; !have { if _, have := haveAssignedIPs[k]; !have {
n.node.log.Printf("%.16x adding managed IP %s", uint64(n.id), ip.String()) n.node.infoLog.Printf("%.16x adding managed IP %s", uint64(n.id), ip.String())
_ = n.tap.AddIP(&ip) _ = n.tap.AddIP(&ip)
} }
} }
@ -319,7 +319,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
} }
for k, ip := range haveAssignedIPs { for k, ip := range haveAssignedIPs {
if _, want := wantAssignedIPs[k]; !want { if _, want := wantAssignedIPs[k]; !want {
n.node.log.Printf("%.16x removing managed IP %s", uint64(n.id), ip.String()) n.node.infoLog.Printf("%.16x removing managed IP %s", uint64(n.id), ip.String())
_ = n.tap.RemoveIP(ip) _ = n.tap.RemoveIP(ip)
} }
} }
@ -340,7 +340,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
k := r.key() k := r.key()
wantManagedRoutes[k] = true wantManagedRoutes[k] = true
if _, have := haveManagedRoutes[k]; !have { if _, have := haveManagedRoutes[k]; !have {
n.node.log.Printf("%.16x adding managed route %s", uint64(n.id), r.String()) n.node.infoLog.Printf("%.16x adding managed route %s", uint64(n.id), r.String())
_ = n.tap.AddRoute(&r) _ = n.tap.AddRoute(&r)
} }
} }
@ -348,7 +348,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
} }
for k, r := range haveManagedRoutes { for k, r := range haveManagedRoutes {
if _, want := wantManagedRoutes[k]; !want { if _, want := wantManagedRoutes[k]; !want {
n.node.log.Printf("%.16x removing managed route %s", uint64(n.id), r.String()) n.node.infoLog.Printf("%.16x removing managed route %s", uint64(n.id), r.String())
_ = n.tap.RemoveRoute(r) _ = n.tap.RemoveRoute(r)
} }
} }

View file

@ -24,6 +24,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"math/rand" "math/rand"
@ -82,28 +83,52 @@ var (
nodesByUserPtrLock sync.RWMutex nodesByUserPtrLock sync.RWMutex
) )
// Node is an instance of the ZeroTier core node and related C++ I/O code // Node is an instance of a virtual port on the global switch.
type Node struct { type Node struct {
// networks contains networks we have joined, and networksByMAC by their local MAC address
networks map[NetworkID]*Network networks map[NetworkID]*Network
networksByMAC map[MAC]*Network // locked by networksLock networksByMAC map[MAC]*Network // locked by networksLock
networksLock sync.RWMutex networksLock sync.RWMutex
interfaceAddresses map[string]net.IP // physical external IPs on the machine
// interfaceAddresses are physical IPs assigned to the local machine (detected, not configured)
interfaceAddresses map[string]net.IP
interfaceAddressesLock sync.Mutex interfaceAddressesLock sync.Mutex
// online and running are atomic flags set to control and monitor background tasks
online uint32 online uint32
running uint32 running uint32
basePath string basePath string
peersPath string peersPath string
networksPath string networksPath string
localConfigPath string localConfigPath string
// localConfig is the current state of local.conf
localConfig LocalConfig localConfig LocalConfig
localConfigLock sync.RWMutex localConfigLock sync.RWMutex
logW *sizeLimitWriter
log *log.Logger // logs for information, errors, and trace output
infoLogW *sizeLimitWriter
errLogW *sizeLimitWriter
traceLogW io.Writer
infoLog *log.Logger
errLog *log.Logger
traceLog *log.Logger
// gn is the instance of GoNode, the Go wrapper and multithreaded I/O engine
gn *C.ZT_GoNode gn *C.ZT_GoNode
// zn is the underlying instance of the ZeroTier core
zn *C.ZT_Node zn *C.ZT_Node
// id is the identity of this node
id *Identity id *Identity
// HTTP server instances: one for a named socket (Unix domain or Windows named pipe) and one on a local TCP socket
namedSocketApiServer *http.Server namedSocketApiServer *http.Server
tcpApiServer *http.Server tcpApiServer *http.Server
// runWaitGroup is used to wait for all node goroutines on shutdown
runWaitGroup sync.WaitGroup runWaitGroup sync.WaitGroup
} }
@ -141,13 +166,18 @@ func NewNode(basePath string) (n *Node, err error) {
} }
if n.localConfig.Settings.LogSizeMax >= 0 { if n.localConfig.Settings.LogSizeMax >= 0 {
n.logW, err = sizeLimitWriterOpen(path.Join(basePath, "node.log")) n.infoLogW, err = sizeLimitWriterOpen(path.Join(basePath, "info.log"))
if err != nil { if err != nil {
return return
} }
n.log = log.New(n.logW, "", log.LstdFlags) n.errLogW, err = sizeLimitWriterOpen(path.Join(basePath, "error.log"))
if err != nil {
return
}
n.infoLog = log.New(n.infoLogW, "", log.LstdFlags)
n.errLog = log.New(n.errLogW, "", log.LstdFlags)
} else { } else {
n.log = nullLogger n.infoLog = nullLogger
} }
if n.localConfig.Settings.PortSearch { if n.localConfig.Settings.PortSearch {
@ -159,7 +189,7 @@ func NewNode(basePath string) (n *Node, err error) {
portCheckCount++ portCheckCount++
if checkPort(n.localConfig.Settings.PrimaryPort) { if checkPort(n.localConfig.Settings.PrimaryPort) {
if n.localConfig.Settings.PrimaryPort != origPort { if n.localConfig.Settings.PrimaryPort != origPort {
n.log.Printf("primary port %d unavailable, found port %d and saved in local.conf", origPort, n.localConfig.Settings.PrimaryPort) n.infoLog.Printf("primary port %d unavailable, found port %d and saved in local.conf", origPort, n.localConfig.Settings.PrimaryPort)
} }
break break
} }
@ -177,11 +207,11 @@ func NewNode(basePath string) (n *Node, err error) {
portCheckCount++ portCheckCount++
if checkPort(n.localConfig.Settings.SecondaryPort) { if checkPort(n.localConfig.Settings.SecondaryPort) {
if n.localConfig.Settings.SecondaryPort != origPort { if n.localConfig.Settings.SecondaryPort != origPort {
n.log.Printf("secondary port %d unavailable, found port %d (port search enabled)", origPort, n.localConfig.Settings.SecondaryPort) n.infoLog.Printf("secondary port %d unavailable, found port %d (port search enabled)", origPort, n.localConfig.Settings.SecondaryPort)
} }
break break
} }
n.log.Printf("secondary port %d unavailable, trying a random port (port search enabled)", n.localConfig.Settings.SecondaryPort) n.infoLog.Printf("secondary port %d unavailable, trying a random port (port search enabled)", n.localConfig.Settings.SecondaryPort)
if portCheckCount <= 64 { if portCheckCount <= 64 {
n.localConfig.Settings.SecondaryPort = unassignedPrivilegedPorts[randomUInt()%uint(len(unassignedPrivilegedPorts))] n.localConfig.Settings.SecondaryPort = unassignedPrivilegedPorts[randomUInt()%uint(len(unassignedPrivilegedPorts))]
} else { } else {
@ -200,14 +230,14 @@ func NewNode(basePath string) (n *Node, err error) {
} }
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 { if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
if !checkPort(n.localConfig.Settings.SecondaryPort) { if !checkPort(n.localConfig.Settings.SecondaryPort) {
n.log.Printf("WARNING: unable to bind secondary port %d",n.localConfig.Settings.SecondaryPort) n.infoLog.Printf("WARNING: unable to bind secondary port %d", n.localConfig.Settings.SecondaryPort)
} }
} }
} }
n.namedSocketApiServer, n.tcpApiServer, err = createAPIServer(basePath, n) n.namedSocketApiServer, n.tcpApiServer, err = createAPIServer(basePath, n)
if err != nil { if err != nil {
n.log.Printf("FATAL: unable to start API server: %s", err.Error()) n.infoLog.Printf("FATAL: unable to start API server: %s", err.Error())
return nil, err return nil, err
} }
@ -215,21 +245,21 @@ func NewNode(basePath string) (n *Node, err error) {
nodesByUserPtr[uintptr(unsafe.Pointer(n))] = n nodesByUserPtr[uintptr(unsafe.Pointer(n))] = n
nodesByUserPtrLock.Unlock() nodesByUserPtrLock.Unlock()
// Instantiate GoNode and friends from the land of C/C++
cPath := C.CString(basePath) cPath := C.CString(basePath)
n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(uintptr(unsafe.Pointer(n)))) n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(uintptr(unsafe.Pointer(n))))
C.free(unsafe.Pointer(cPath)) C.free(unsafe.Pointer(cPath))
if n.gn == nil { if n.gn == nil {
n.log.Println("FATAL: node initialization failed") n.infoLog.Println("FATAL: node initialization failed")
nodesByUserPtrLock.Lock() nodesByUserPtrLock.Lock()
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n))) delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
nodesByUserPtrLock.Unlock() nodesByUserPtrLock.Unlock()
return nil, ErrNodeInitFailed return nil, ErrNodeInitFailed
} }
n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn)) n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn))
n.id, err = newIdentityFromCIdentity(C.ZT_Node_identity(unsafe.Pointer(n.zn))) n.id, err = newIdentityFromCIdentity(C.ZT_Node_identity(unsafe.Pointer(n.zn)))
if err != nil { if err != nil {
n.log.Printf("FATAL: error obtaining node's identity") n.infoLog.Printf("FATAL: error obtaining node's identity")
nodesByUserPtrLock.Lock() nodesByUserPtrLock.Lock()
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n))) delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
nodesByUserPtrLock.Unlock() nodesByUserPtrLock.Unlock()
@ -237,6 +267,8 @@ func NewNode(basePath string) (n *Node, err error) {
return nil, err return nil, err
} }
// Background maintenance goroutine that handles polling for local network changes, cleaning internal data
// structures, syncing local config changes, and numerous other things that must happen from time to time.
n.runWaitGroup.Add(1) n.runWaitGroup.Add(1)
go func() { go func() {
defer n.runWaitGroup.Done() defer n.runWaitGroup.Done()
@ -296,7 +328,7 @@ func NewNode(basePath string) (n *Node, err error) {
interfaceAddressesChanged = true interfaceAddressesChanged = true
ipCstr := C.CString(ipn.String()) ipCstr := C.CString(ipn.String())
for pn, p := range ports { for pn, p := range ports {
n.log.Printf("UDP binding to port %d on interface %s", p, astr) n.infoLog.Printf("UDP binding to port %d on interface %s", p, astr)
primary := C.int(0) primary := C.int(0)
if pn == 0 { if pn == 0 {
primary = 1 primary = 1
@ -311,7 +343,7 @@ func NewNode(basePath string) (n *Node, err error) {
interfaceAddressesChanged = true interfaceAddressesChanged = true
ipCstr := C.CString(ipn.String()) ipCstr := C.CString(ipn.String())
for _, p := range ports { for _, p := range ports {
n.log.Printf("UDP closing socket bound to port %d on interface %s", p, astr) n.infoLog.Printf("UDP closing socket bound to port %d on interface %s", p, astr)
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(p)) C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(p))
} }
C.free(unsafe.Pointer(ipCstr)) C.free(unsafe.Pointer(ipCstr))
@ -360,9 +392,9 @@ func NewNode(basePath string) (n *Node, err error) {
} }
} }
// Trim log if it's gone over its size limit // Trim infoLog if it's gone over its size limit
if n.localConfig.Settings.LogSizeMax > 0 && n.logW != nil { if n.localConfig.Settings.LogSizeMax > 0 && n.infoLogW != nil {
_ = n.logW.trim(n.localConfig.Settings.LogSizeMax*1024, 0.5, true) _ = n.infoLogW.trim(n.localConfig.Settings.LogSizeMax*1024, 0.5, true)
} }
n.localConfigLock.RUnlock() n.localConfigLock.RUnlock()
@ -440,16 +472,16 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error)
restartRequired = true restartRequired = true
} }
if lc.Settings.LogSizeMax < 0 { if lc.Settings.LogSizeMax < 0 {
n.log = nullLogger n.infoLog = nullLogger
_ = n.logW.Close() _ = n.infoLogW.Close()
n.logW = nil n.infoLogW = nil
} else if n.logW != nil { } else if n.infoLogW != nil {
n.logW, err = sizeLimitWriterOpen(path.Join(n.basePath, "service.log")) n.infoLogW, err = sizeLimitWriterOpen(path.Join(n.basePath, "service.infoLog"))
if err == nil { if err == nil {
n.log = log.New(n.logW, "", log.LstdFlags) n.infoLog = log.New(n.infoLogW, "", log.LstdFlags)
} else { } else {
n.log = nullLogger n.infoLog = nullLogger
n.logW = nil n.infoLogW = nil
} }
} }
@ -458,12 +490,12 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error)
return return
} }
// Join joins a network // Join a network.
// If tap is nil, the default system tap for this OS/platform is used (if available). // If tap is nil, the default system tap for this OS/platform is used (if available).
func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*Network, error) { func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*Network, error) {
n.networksLock.RLock() n.networksLock.RLock()
if nw, have := n.networks[nwid]; have { if nw, have := n.networks[nwid]; have {
n.log.Printf("join network %.16x ignored: already a member", nwid) n.infoLog.Printf("join network %.16x ignored: already a member", nwid)
if settings != nil { if settings != nil {
nw.SetLocalSettings(settings) nw.SetLocalSettings(settings)
} }
@ -476,13 +508,13 @@ func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*N
} }
ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid)) ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid))
if ntap == nil { if ntap == nil {
n.log.Printf("join network %.16x failed: tap device failed to initialize (check drivers / kernel modules)", uint64(nwid)) n.infoLog.Printf("join network %.16x failed: tap device failed to initialize (check drivers / kernel modules)", uint64(nwid))
return nil, ErrTapInitFailed return nil, ErrTapInitFailed
} }
nw, err := newNetwork(n, nwid, &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1}) nw, err := newNetwork(n, nwid, &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1})
if err != nil { if err != nil {
n.log.Printf("join network %.16x failed: network failed to initialize: %s", nwid, err.Error()) n.infoLog.Printf("join network %.16x failed: network failed to initialize: %s", nwid, err.Error())
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid)) C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
return nil, err return nil, err
} }
@ -496,14 +528,14 @@ func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*N
return nw, nil return nw, nil
} }
// Leave leaves a network // Leave a network.
func (n *Node) Leave(nwid NetworkID) error { func (n *Node) Leave(nwid NetworkID) error {
n.log.Printf("leaving network %.16x", nwid)
n.networksLock.Lock() n.networksLock.Lock()
nw := n.networks[nwid] nw := n.networks[nwid]
delete(n.networks, nwid) delete(n.networks, nwid)
n.networksLock.Unlock() n.networksLock.Unlock()
if nw != nil { if nw != nil {
n.infoLog.Printf("leaving network %.16x", nwid)
nw.leaving() nw.leaving()
} }
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid)) C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
@ -668,7 +700,7 @@ func (n *Node) stateObjectGet(objType int, id [2]uint64) ([]byte, bool) {
func (n *Node) handleTrace(traceMessage string) { func (n *Node) handleTrace(traceMessage string) {
if len(traceMessage) > 0 { if len(traceMessage) > 0 {
n.log.Print("TRACE: " + traceMessage) n.infoLog.Print("TRACE: " + traceMessage)
} }
} }

View file

@ -19,6 +19,25 @@
#ifndef ZT_ZEROTIER_API_H #ifndef ZT_ZEROTIER_API_H
#define ZT_ZEROTIER_API_H #define ZT_ZEROTIER_API_H
/* ZT_PACKED_STRUCT encloses structs whose contents should be bit-packed.
* Nearly all compilers support this. These macros detect the compiler and
* define it correctly for gcc/icc/clang or MSC. */
#ifndef ZT_PACKED_STRUCT
#if defined(__GCC__) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__INTEL_COMPILER) || defined(__clang__)
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
#define ZT_PACKED_STRUCT_START
#define ZT_PACKED_STRUCT_END __attribute__((packed))
#endif
#ifdef _MSC_VER
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
#define ZT_PACKED_STRUCT_START __pragma(pack(push,1))
#define ZT_PACKED_STRUCT_END __pragma(pack(pop))
#endif
#endif
#ifndef ZT_PACKED_STRUCT
#error Missing a macro to define ZT_PACKED_STRUCT for your compiler.
#endif
#ifdef __cplusplus #ifdef __cplusplus
#include <cstdint> #include <cstdint>
extern "C" { extern "C" {
@ -26,26 +45,21 @@ extern "C" {
#include <stdint.h> #include <stdint.h>
#endif #endif
/* For struct sockaddr_storage, which is referenced here. */
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#include <WinSock2.h> #include <WinSock2.h>
#include <WS2tcpip.h> #include <WS2tcpip.h>
#include <Windows.h> #include <Windows.h>
#else /* not Windows */ #else
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#endif /* Windows or not */ #endif
/* This symbol may be defined in a build environment or before including this
* header if you need to prepend something to function specifications. */
#ifndef ZT_SDK_API #ifndef ZT_SDK_API
#define ZT_SDK_API #define ZT_SDK_API
#endif #endif
/****************************************************************************/
/* Core constants */
/****************************************************************************/ /****************************************************************************/
/** /**
@ -174,13 +188,6 @@ extern "C" {
*/ */
#define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7 #define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7
/**
* Maximum number of multicast group subscriptions on a local virtual network interface
*
* This coincides with many operating systems' maximum values and is rather huge.
*/
#define ZT_MAX_MULTICAST_SUBSCRIPTIONS 1024
/* Rule specification contants **********************************************/ /* Rule specification contants **********************************************/
/** /**
@ -269,7 +276,310 @@ extern "C" {
#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL #define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL
/****************************************************************************/ /****************************************************************************/
/* Structures and other types */
/**
* Credential type IDs
*
* These are mostly used internally but are declared here so they can be used
* in trace messages.
*/
enum ZT_CredentialType
{
ZT_CREDENTIAL_TYPE_NULL = 0,
ZT_CREDENTIAL_TYPE_COM = 1,
ZT_CREDENTIAL_TYPE_CAPABILITY = 2,
ZT_CREDENTIAL_TYPE_TAG = 3,
ZT_CREDENTIAL_TYPE_COO = 4,
ZT_CREDENTIAL_TYPE_REVOCATION = 6
};
/* Trace events are sent and received as packed structures of a fixed size.
* Normally we don't use this form of brittle encoding but in this case the
* performance benefit is non-trivial as events are generated in critical
* areas of the code.
*
* NOTE: all integer fields larger than one byte are stored in big-endian
* "network" byte order in these structures. */
/**
* Flag indicating that VL1 tracing should be generated
*/
#define ZT_TRACE_FLAG_VL1 0x01
/**
* Flag indicating that VL2 (virtual network) tracing should be generated
*/
#define ZT_TRACE_FLAG_VL2 0x02
/**
* Flag indicating that VL2 network filter tracing should be generated (separate because this can be very verbose)
*/
#define ZT_TRACE_FLAG_VL2_FILTER 0x04
/**
* Flag indicating that VL2 multicast propagation should be reported
*/
#define ZT_TRACE_FLAG_VL2_MULTICAST 0x08
/**
* Trace event types
*
* All trace event structures start with a size and type.
*/
enum ZT_TraceEventType
{
/* VL1 events related to the peer-to-peer layer */
ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE = 1,
ZT_TRACE_VL1_TRYING_NEW_PATH = 2,
ZT_TRACE_VL1_LEARNED_NEW_PATH = 3,
ZT_TRACE_VL1_INCOMING_PACKET_DROPPED = 4,
/* VL2 events relate to virtual networks, packet filtering, and authentication */
ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100,
ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101,
ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED = 102,
ZT_TRACE_VL2_NETWORK_FILTER = 103
};
/**
* Trace VL1 packet drop reasons
*/
enum ZT_TracePacketDropReason
{
ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED = 0,
ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD = 1,
ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET = 2,
ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED = 3,
ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 4,
ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 5,
ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA = 6,
ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 7
};
/**
* Trace VL2 frame drop reasons
*/
enum ZT_TraceFrameDropReason
{
ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED = 0,
ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE = 1,
ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL = 2,
ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED = 3,
ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED = 4,
ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED = 5,
ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION = 6,
ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED = 7
};
/**
* Address types for ZT_TraceEventPathAddress
*
* These are currently the same as the types in Endpoint.hpp and should remain so
* if possible for consistency. Not all of these are used (yet?) but they are defined
* for possible future use and the structure is sized to support them.
*/
enum ZT_TraceEventPathAddressType
{
ZT_TRACE_EVENT_PATH_TYPE_NIL = 0, /* none/empty */
ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V4 = 1, /* 4-byte IPv4 */
ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V6 = 2, /* 16-byte IPv6 */
ZT_TRACE_EVENT_PATH_TYPE_DNSNAME = 3, /* C string */
ZT_TRACE_EVENT_PATH_TYPE_ZEROTIER = 4, /* 5-byte ZeroTier + 48-byte identity hash */
ZT_TRACE_EVENT_PATH_TYPE_URL = 5, /* C string */
ZT_TRACE_EVENT_PATH_TYPE_ETHERNET = 6 /* 6-byte Ethernet */
};
/**
* Reasons for trying new paths
*/
enum ZT_TraceTryingNewPathReason
{
ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH = 1,
ZT_TRACE_TRYING_NEW_PATH_REASON_RECEIVED_PUSH_DIRECT_PATHS = 2,
ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS = 3
};
/**
* Reasons for credential rejection
*/
enum ZT_TraceCredentialRejectionReason
{
ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED = 1,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED = 2,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST = 3,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID = 4
};
/**
* Physical path address from a trace event
*
* This is a special packed address format that roughly mirrors Endpoint in the core
* and is designed to support both present and future address types.
*/
ZT_PACKED_STRUCT(struct ZT_TraceEventPathAddress
{
uint8_t type; /* ZT_TraceEventPathAddressType */
uint8_t address[63]; /* Type-dependent address: 4-byte IPv4, 16-byte IPV6, etc. */
uint16_t port; /* UDP/TCP port for address types for which this is meaningful */
});
/**
* Header for all trace events
*
* All packet types begin with these fields in this order.
*/
ZT_PACKED_STRUCT(struct ZT_TraceEvent
{
uint16_t evSize; /* sizeof(ZT_TraceEvent_XX structure) (inclusive size in bytes) */
uint16_t evType; /* ZT_TraceEventType */
});
/* Temporary macros to make it easier to declare all ZT_TraceEvent's sub-types */
#define _ZT_TRACE_EVENT_STRUCT_START(e) ZT_PACKED_STRUCT_START struct ZT_TraceEvent_##e { \
uint16_t evSize; \
uint16_t evType;
#define _ZT_TRACE_EVENT_STRUCT_END() } ZT_PACKED_STRUCT_END;
/**
* Node is resetting all paths in a given address scope
*
* This happens when the node detects and external surface IP addressing change
* via a trusted (usually root) peer. It's used to renegotiate links when nodes
* move around on the network.
*/
_ZT_TRACE_EVENT_STRUCT_START(VL1_RESETTING_PATHS_IN_SCOPE)
uint64_t reporter; /* ZeroTier address that triggered the reset */
uint8_t reporterIdentityHash[48]; /* full identity hash of triggering node's identity */
struct ZT_TraceEventPathAddress from; /* physical origin of triggering packet */
struct ZT_TraceEventPathAddress oldExternal; /* previous detected external address */
struct ZT_TraceEventPathAddress newExternal; /* new detected external address */
uint8_t scope; /* IP scope being reset */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* Node is trying a new path
*
* Paths are tried in response to PUSH_DIRECT_PATHS, RENDEZVOUS, and other places
* we might hear of them. A node tries a path by sending a trial message to it.
*/
_ZT_TRACE_EVENT_STRUCT_START(VL1_TRYING_NEW_PATH)
uint64_t address; /* short address of node we're trying to reach */
uint8_t identityHash[48]; /* identity hash of node we're trying to reach */
struct ZT_TraceEventPathAddress physicalAddress; /* physical address being tried */
struct ZT_TraceEventPathAddress triggerAddress; /* physical origin of triggering packet */
uint64_t triggeringPacketId; /* packet ID of triggering packet */
uint8_t triggeringPacketVerb; /* packet verb of triggering packet */
uint64_t triggeredByAddress; /* short address of node triggering attempt */
uint8_t triggeredByIdentityHash[48]; /* full identity hash of node triggering attempt */
uint8_t reason; /* ZT_TraceTryingNewPathReason */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* Node has learned a new path to another node
*/
_ZT_TRACE_EVENT_STRUCT_START(VL1_LEARNED_NEW_PATH)
uint64_t packetId; /* packet ID of confirming packet */
uint64_t address; /* short address of learned peer */
uint8_t identityHash[48]; /* full identity hash of learned peer */
struct ZT_TraceEventPathAddress physicalAddress; /* physical address learned */
struct ZT_TraceEventPathAddress replaced; /* if non-empty, an older address that was replaced */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* An incoming packet was dropped at the VL1 level
*
* This indicates a packet that passed MAC check but was dropped for some other
* reason such as rate limits, being malformed, etc.
*/
_ZT_TRACE_EVENT_STRUCT_START(VL1_INCOMING_PACKET_DROPPED)
uint64_t packetId; /* packet ID of failed packet */
uint64_t networkId; /* VL2 network ID or 0 if unrelated to a network or unknown */
uint64_t address; /* short address that sent packet */
uint8_t identityHash[48]; /* full identity hash of sending node */
struct ZT_TraceEventPathAddress physicalAddress; /* physical origin address of packet */
uint8_t hops; /* hop count of packet */
uint8_t verb; /* packet verb */
uint8_t reason; /* ZT_TracePacketDropReason */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* Node declined to send a packet read from a local network port/tap
*/
_ZT_TRACE_EVENT_STRUCT_START(VL2_OUTGOING_FRAME_DROPPED)
uint64_t networkId; /* network ID */
uint64_t sourceMac; /* source MAC address */
uint64_t destMac; /* destination MAC address */
uint16_t etherType; /* Ethernet type of frame */
uint16_t frameLength; /* length of dropped frame */
uint8_t frameHead[64]; /* first up to 64 bytes of dropped frame */
uint8_t reason; /* ZT_TraceFrameDropReason */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* An incoming frame was dropped
*/
_ZT_TRACE_EVENT_STRUCT_START(VL2_INCOMING_FRAME_DROPPED)
uint64_t packetId; /* VL1 packet ID */
uint64_t networkId; /* VL2 network ID */
uint64_t sourceMac; /* 48-bit source MAC */
uint64_t destMac; /* 48-bit destination MAC */
uint64_t address; /* short address of sending peer */
struct ZT_TraceEventPathAddress physicalAddress; /* physical source address of packet */
uint8_t hops; /* hop count of packet */
uint16_t frameLength; /* length of frame in bytes */
uint8_t frameHead[64]; /* first up to 64 bytes of dropped frame */
uint8_t verb; /* packet verb indicating how frame was sent */
uint8_t credentialRequestSent; /* if non-zero a request for credentials was sent */
uint8_t reason; /* ZT_TraceFrameDropReason */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* Node is requesting a new network config and certificate from a network controller
*/
_ZT_TRACE_EVENT_STRUCT_START(VL2_NETWORK_CONFIG_REQUESTED)
uint64_t networkId; /* VL2 network ID */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* Network filter trace results
*
* These are generated when filter tracing is enabled to allow filters to be debugged.
* Format for rule set logs is documented elsewhere.
*/
_ZT_TRACE_EVENT_STRUCT_START(VL2_NETWORK_FILTER)
uint64_t networkId; /* VL2 network ID */
uint8_t primaryRuleSetLog[512]; /* primary rule set log */
uint8_t matchingCapabilityRuleSetLog[512]; /* capability rule set log (if any) */
uint32_t matchingCapabilityId; /* capability ID or 0 if none */
int64_t matchingCapabilityTimestamp; /* capability timestamp or 0 if none */
uint64_t source; /* source ZeroTier address */
uint64_t dest; /* destination ZeroTier address */
uint64_t sourceMac; /* packet source MAC */
uint64_t destMac; /* packet destination MAC */
uint16_t frameLength; /* length of filtered frame */
uint8_t frameHead[64]; /* first up to 64 bytes of filtered frame */
uint16_t etherType; /* frame Ethernet type */
uint16_t vlanId; /* frame VLAN ID (currently unused, always 0) */
uint8_t noTee; /* if true noTee flag was set in filter */
uint8_t inbound; /* direction: 1 for inbound, 0 for outbound */
int8_t accept; /* 0: drop, 1: accept, 2: "super-accept" */
_ZT_TRACE_EVENT_STRUCT_END()
/**
* An incoming credential from a peer was rejected
*/
_ZT_TRACE_EVENT_STRUCT_START(VL2_CREDENTIAL_REJECTED)
uint64_t networkId; /* VL2 network ID */
uint64_t address; /* short address of sender */
uint32_t credentialId; /* credential ID */
int64_t credentialTimestamp; /* credential timestamp */
uint8_t credentialType; /* credential type */
uint8_t reason; /* ZT_TraceCredentialRejectionReason */
_ZT_TRACE_EVENT_STRUCT_END()
#undef _ZT_TRACE_EVENT_STRUCT_START
#undef _ZT_TRACE_EVENT_STRUCT_END
/****************************************************************************/ /****************************************************************************/
/** /**
@ -390,7 +700,7 @@ enum ZT_Event
* These events are only generated if this is a TRACE-enabled build. * These events are only generated if this is a TRACE-enabled build.
* This is for local debug traces, not remote trace diagnostics. * This is for local debug traces, not remote trace diagnostics.
* *
* Meta-data: C string, TRACE message * Meta-data: struct of type ZT_Trace_*
*/ */
ZT_EVENT_TRACE = 5, ZT_EVENT_TRACE = 5,
@ -1164,8 +1474,6 @@ enum ZT_StateObjectType
*/ */
typedef void ZT_Node; typedef void ZT_Node;
/****************************************************************************/
/* Callbacks used by Node API */
/****************************************************************************/ /****************************************************************************/
/** /**
@ -1357,8 +1665,6 @@ typedef int (*ZT_PathLookupFunction)(
struct sockaddr_storage *); /* Result buffer */ struct sockaddr_storage *); /* Result buffer */
/****************************************************************************/ /****************************************************************************/
/* C Node API */
/****************************************************************************/
/** /**
* Structure for configuring ZeroTier core callback functions * Structure for configuring ZeroTier core callback functions
@ -1735,6 +2041,8 @@ ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterIns
*/ */
ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
/****************************************************************************/
/** /**
* Generate a new identity * Generate a new identity
* *
@ -1844,6 +2152,8 @@ ZT_SDK_API void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int include
*/ */
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id); ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id);
/****************************************************************************/
/** /**
* Get ZeroTier One version * Get ZeroTier One version
* *

View file

@ -20,7 +20,7 @@
namespace ZeroTier { namespace ZeroTier {
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
static 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]; uint32_t v = ((const uint8_t *)in)[0];
@ -161,7 +161,7 @@ void AES::_ctrSW(const uint8_t iv[16],const void *in,unsigned int len,void *out)
while (len >= 16) { while (len >= 16) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc); _encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
ctr[1] = Utils::hton(++bctr); ctr[1] = Utils::hton(++bctr);
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<16;++k) for(unsigned int k=0;k<16;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k]; *(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
#else #else
@ -339,7 +339,7 @@ void AES::_gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_
uint64_t y0 = 0,y1 = 0; uint64_t y0 = 0,y1 = 0;
while (len >= 16) { while (len >= 16) {
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y0)[i] ^= *(in++); for(unsigned int i=0;i<8;++i) ((uint8_t *)&y0)[i] ^= *(in++);
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y1)[i] ^= *(in++); for(unsigned int i=0;i<8;++i) ((uint8_t *)&y1)[i] ^= *(in++);
#else #else
@ -369,7 +369,7 @@ void AES::_gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_
((uint8_t *)iv2)[14] = 0; ((uint8_t *)iv2)[14] = 0;
((uint8_t *)iv2)[15] = 1; ((uint8_t *)iv2)[15] = 1;
_encryptSW((const uint8_t *)iv2,(uint8_t *)iv2); _encryptSW((const uint8_t *)iv2,(uint8_t *)iv2);
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int i=0;i<8;++i) out[i] = ((const uint8_t *)&y0)[i] ^ ((const uint8_t *)iv2)[i]; for(unsigned int i=0;i<8;++i) out[i] = ((const uint8_t *)&y0)[i] ^ ((const uint8_t *)iv2)[i];
for(unsigned int i=8;i<16;++i) out[i] = ((const uint8_t *)&y1)[i-8] ^ ((const uint8_t *)iv2)[i]; for(unsigned int i=8;i<16;++i) out[i] = ((const uint8_t *)&y1)[i-8] ^ ((const uint8_t *)iv2)[i];
#else #else

View file

@ -145,7 +145,7 @@ public:
{ {
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 2; ii += 2;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint16_t)data[s] << 8U) | ((uint16_t)data[s] << 8U) |
(uint16_t)data[s + 1]); (uint16_t)data[s + 1]);
@ -164,7 +164,7 @@ public:
{ {
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 4; ii += 4;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint32_t)data[s] << 24U) | ((uint32_t)data[s] << 24U) |
((uint32_t)data[s + 1] << 16U) | ((uint32_t)data[s + 1] << 16U) |
@ -185,7 +185,7 @@ public:
{ {
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 8; ii += 8;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint64_t)data[s] << 56U) | ((uint64_t)data[s] << 56U) |
((uint64_t)data[s + 1] << 48U) | ((uint64_t)data[s + 1] << 48U) |
@ -340,7 +340,7 @@ public:
{ {
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 2; ii += 2;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
data[s] = (uint8_t)(n >> 8U); data[s] = (uint8_t)(n >> 8U);
data[s + 1] = (uint8_t)n; data[s + 1] = (uint8_t)n;
#else #else
@ -358,7 +358,7 @@ public:
{ {
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 4; ii += 4;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
data[s] = (uint8_t)(n >> 24U); data[s] = (uint8_t)(n >> 24U);
data[s + 1] = (uint8_t)(n >> 16U); data[s + 1] = (uint8_t)(n >> 16U);
data[s + 2] = (uint8_t)(n >> 8U); data[s + 2] = (uint8_t)(n >> 8U);
@ -378,7 +378,7 @@ public:
{ {
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 8; ii += 8;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
data[s] = (uint8_t)(n >> 56U); data[s] = (uint8_t)(n >> 56U);
data[s + 1] = (uint8_t)(n >> 48U); data[s + 1] = (uint8_t)(n >> 48U);
data[s + 2] = (uint8_t)(n >> 40U); data[s + 2] = (uint8_t)(n >> 40U);

View file

@ -25,7 +25,7 @@
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING)) #if defined(__GNUC__) && (!defined(ZT_NO_UNALIGNED_ACCESS))
#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__)) #define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
#else #else
#define ZT_VAR_MAY_ALIAS #define ZT_VAR_MAY_ALIAS
@ -171,7 +171,7 @@ public:
{ {
if (unlikely((i + sizeof(T)) > _l)) if (unlikely((i + sizeof(T)) > _l))
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i); uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
for(unsigned int x=1;x<=sizeof(T);++x) for(unsigned int x=1;x<=sizeof(T);++x)
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
@ -193,7 +193,7 @@ public:
{ {
if (unlikely((i + sizeof(T)) > _l)) if (unlikely((i + sizeof(T)) > _l))
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
T v = 0; T v = 0;
const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i); const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
for(unsigned int x=0;x<sizeof(T);++x) { for(unsigned int x=0;x<sizeof(T);++x) {
@ -219,7 +219,7 @@ public:
{ {
if (unlikely((_l + sizeof(T)) > C)) if (unlikely((_l + sizeof(T)) > C))
throw ZT_EXCEPTION_OUT_OF_BOUNDS; throw ZT_EXCEPTION_OUT_OF_BOUNDS;
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l); uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
for(unsigned int x=1;x<=sizeof(T);++x) for(unsigned int x=1;x<=sizeof(T);++x)
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));

View file

@ -73,6 +73,7 @@ set(core_src
SHA512.cpp SHA512.cpp
Switch.cpp Switch.cpp
Topology.cpp Topology.cpp
Trace.cpp
Utils.cpp Utils.cpp
) )

View file

@ -58,7 +58,7 @@ class Capability : public Credential
friend class Credential; friend class Credential;
public: public:
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; } static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_CAPABILITY; }
ZT_ALWAYS_INLINE Capability() : ZT_ALWAYS_INLINE Capability() :
_nwid(0), _nwid(0),

View file

@ -69,7 +69,7 @@ class CertificateOfMembership : public Credential
friend class Credential; friend class Credential;
public: public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; } static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_COM; }
/** /**
* Reserved qualifier IDs * Reserved qualifier IDs
@ -101,7 +101,7 @@ public:
/** /**
* Create an empty certificate of membership * Create an empty certificate of membership
*/ */
inline CertificateOfMembership() : ZT_ALWAYS_INLINE CertificateOfMembership() :
_qualifierCount(0), _qualifierCount(0),
_signatureLength(0) {} _signatureLength(0) {}
@ -113,7 +113,7 @@ public:
* @param nwid Network ID * @param nwid Network ID
* @param issuedTo Certificate recipient * @param issuedTo Certificate recipient
*/ */
inline CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo) ZT_ALWAYS_INLINE CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
{ {
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP; _qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = timestamp; _qualifiers[0].value = timestamp;
@ -135,22 +135,22 @@ public:
* @param startAt Position to start in buffer * @param startAt Position to start in buffer
*/ */
template<unsigned int C> template<unsigned int C>
inline CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); } ZT_ALWAYS_INLINE CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
/** /**
* @return True if there's something here * @return True if there's something here
*/ */
inline operator bool() const { return (_qualifierCount != 0); } ZT_ALWAYS_INLINE operator bool() const { return (_qualifierCount != 0); }
/** /**
* @return Credential ID, always 0 for COMs * @return Credential ID, always 0 for COMs
*/ */
inline uint32_t id() const { return 0; } ZT_ALWAYS_INLINE uint32_t id() const { return 0; }
/** /**
* @return Timestamp for this cert and maximum delta for timestamp * @return Timestamp for this cert and maximum delta for timestamp
*/ */
inline int64_t timestamp() const ZT_ALWAYS_INLINE int64_t timestamp() const
{ {
for(unsigned int i=0;i<_qualifierCount;++i) { for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)
@ -162,7 +162,7 @@ public:
/** /**
* @return Address to which this cert was issued * @return Address to which this cert was issued
*/ */
inline Address issuedTo() const ZT_ALWAYS_INLINE Address issuedTo() const
{ {
for(unsigned int i=0;i<_qualifierCount;++i) { for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO)
@ -174,7 +174,7 @@ public:
/** /**
* @return Network ID for which this cert was issued * @return Network ID for which this cert was issued
*/ */
inline uint64_t networkId() const ZT_ALWAYS_INLINE uint64_t networkId() const
{ {
for(unsigned int i=0;i<_qualifierCount;++i) { for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID)
@ -192,7 +192,7 @@ public:
* @param value Qualifier value * @param value Qualifier value
* @param maxDelta Qualifier maximum allowed difference (absolute value of difference) * @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
*/ */
inline void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta) ZT_ALWAYS_INLINE void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
{ {
_signedBy.zero(); _signedBy.zero();
for(unsigned int i=0;i<_qualifierCount;++i) { for(unsigned int i=0;i<_qualifierCount;++i) {
@ -211,7 +211,7 @@ public:
} }
} }
inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); } ZT_ALWAYS_INLINE void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
/** /**
* Compare two certificates for parameter agreement * Compare two certificates for parameter agreement
@ -226,7 +226,7 @@ public:
* @param other Cert to compare with * @param other Cert to compare with
* @return True if certs agree and 'other' may be communicated with * @return True if certs agree and 'other' may be communicated with
*/ */
inline bool agreesWith(const CertificateOfMembership &other) const ZT_ALWAYS_INLINE bool agreesWith(const CertificateOfMembership &other) const
{ {
unsigned int myidx = 0; unsigned int myidx = 0;
unsigned int otheridx = 0; unsigned int otheridx = 0;
@ -268,7 +268,7 @@ public:
* @param with Identity to sign with, must include private key * @param with Identity to sign with, must include private key
* @return True if signature was successful * @return True if signature was successful
*/ */
inline bool sign(const Identity &with) ZT_ALWAYS_INLINE bool sign(const Identity &with)
{ {
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0; unsigned int ptr = 0;
@ -294,17 +294,12 @@ public:
* @param RR Runtime environment for looking up peers * @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 * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/ */
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); } ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
/**
* @return True if signed
*/
inline bool isSigned() const { return (_signedBy); }
/** /**
* @return Address that signed this certificate or null address if none * @return Address that signed this certificate or null address if none
*/ */
inline const Address &signedBy() const { return _signedBy; } ZT_ALWAYS_INLINE const Address &signedBy() const { return _signedBy; }
template<unsigned int C> template<unsigned int C>
inline void serialize(Buffer<C> &b) const inline void serialize(Buffer<C> &b) const
@ -369,7 +364,7 @@ public:
return (p - startAt); return (p - startAt);
} }
inline bool operator==(const CertificateOfMembership &c) const ZT_ALWAYS_INLINE bool operator==(const CertificateOfMembership &c) const
{ {
if (_signedBy != c._signedBy) if (_signedBy != c._signedBy)
return false; return false;
@ -385,7 +380,7 @@ public:
} }
return (memcmp(_signature,c._signature,_signatureLength) == 0); return (memcmp(_signature,c._signature,_signatureLength) == 0);
} }
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); } ZT_ALWAYS_INLINE bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
private: private:
struct _Qualifier struct _Qualifier

View file

@ -46,7 +46,7 @@ class CertificateOfOwnership : public Credential
friend class Credential; friend class Credential;
public: public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; } static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_COO; }
enum Thing enum Thing
{ {
@ -56,12 +56,12 @@ public:
THING_IPV6_ADDRESS = 3 THING_IPV6_ADDRESS = 3
}; };
inline CertificateOfOwnership() ZT_ALWAYS_INLINE CertificateOfOwnership()
{ {
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership)); memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
} }
inline CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id) ZT_ALWAYS_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)); memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
_networkId = nwid; _networkId = nwid;
@ -70,19 +70,19 @@ public:
_issuedTo = issuedTo; _issuedTo = issuedTo;
} }
inline uint64_t networkId() const { return _networkId; } ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
inline int64_t timestamp() const { return _ts; } ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
inline uint32_t id() const { return _id; } ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
inline const Address &issuedTo() const { return _issuedTo; } ZT_ALWAYS_INLINE const Address &issuedTo() const { return _issuedTo; }
inline const Address &signer() const { return _signedBy; } ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
inline const uint8_t *signature() const { return _signature; } ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
inline unsigned int signatureLength() const { return _signatureLength; } ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
inline unsigned int thingCount() const { return (unsigned int)_thingCount; } ZT_ALWAYS_INLINE unsigned int thingCount() const { return (unsigned int)_thingCount; }
inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } ZT_ALWAYS_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 const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
inline bool owns(const InetAddress &ip) const ZT_ALWAYS_INLINE bool owns(const InetAddress &ip) const
{ {
if (ip.ss_family == AF_INET) if (ip.ss_family == AF_INET)
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4); return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
@ -91,14 +91,14 @@ public:
return false; return false;
} }
inline bool owns(const MAC &mac) const ZT_ALWAYS_INLINE bool owns(const MAC &mac) const
{ {
uint8_t tmp[6]; uint8_t tmp[6];
mac.copyTo(tmp,6); mac.copyTo(tmp,6);
return this->_owns(THING_MAC_ADDRESS,tmp,6); return this->_owns(THING_MAC_ADDRESS,tmp,6);
} }
inline void addThing(const InetAddress &ip) ZT_ALWAYS_INLINE void addThing(const InetAddress &ip)
{ {
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (ip.ss_family == AF_INET) { if (ip.ss_family == AF_INET) {
@ -112,7 +112,7 @@ public:
} }
} }
inline void addThing(const MAC &mac) ZT_ALWAYS_INLINE void addThing(const MAC &mac)
{ {
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return; if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
_thingTypes[_thingCount] = THING_MAC_ADDRESS; _thingTypes[_thingCount] = THING_MAC_ADDRESS;
@ -124,7 +124,7 @@ public:
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
inline bool sign(const Identity &signer) ZT_ALWAYS_INLINE bool sign(const Identity &signer)
{ {
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp; Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
@ -136,7 +136,7 @@ public:
return false; return false;
} }
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); } ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C> template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const inline void serialize(Buffer<C> &b,const bool forSign = false) const
@ -206,13 +206,13 @@ public:
} }
// Provides natural sort order by ID // Provides natural sort order by ID
inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); } ZT_ALWAYS_INLINE bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); } 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); } ZT_ALWAYS_INLINE bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
private: private:
inline bool _owns(const Thing &t,const void *v,unsigned int l) const ZT_ALWAYS_INLINE bool _owns(const Thing &t,const void *v,unsigned int l) const
{ {
for(unsigned int i=0,j=_thingCount;i<j;++i) { for(unsigned int i=0,j=_thingCount;i<j;++i) {
if (_thingTypes[i] == (uint8_t)t) { if (_thingTypes[i] == (uint8_t)t) {

View file

@ -118,18 +118,18 @@
/** /**
* Period between keepalives sent to paths if no other traffic has been sent * 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_PATH_KEEPALIVE_PERIOD 30000 #define ZT_PATH_KEEPALIVE_PERIOD 20000
/** /**
* Timeout for path aliveness (measured from last receive) * Timeout for path alive-ness (measured from last receive)
*/ */
#define ZT_PATH_ACTIVITY_TIMEOUT ((ZT_PATH_KEEPALIVE_PERIOD * 2) + 5000) #define ZT_PATH_ALIVE_TIMEOUT ((ZT_PATH_KEEPALIVE_PERIOD * 2) + 5000)
/**
* Timeout for path active-ness (measured from last receive)
*/
#define ZT_PATH_ACTIVITY_TIMEOUT (ZT_PATH_KEEPALIVE_PERIOD + 5000)
/** /**
* Delay between full HELLO messages between peers * Delay between full HELLO messages between peers
@ -137,12 +137,12 @@
#define ZT_PEER_PING_PERIOD 60000 #define ZT_PEER_PING_PERIOD 60000
/** /**
* Timeout for overall peer activity (measured from last receive) * Timeout for peer alive-ness (measured from last receive)
*/ */
#define ZT_PEER_ALIVE_TIMEOUT ((ZT_PEER_PING_PERIOD * 2) + 5000) #define ZT_PEER_ALIVE_TIMEOUT ((ZT_PEER_PING_PERIOD * 2) + 5000)
/** /**
* Timeout for overall peer activity (measured from last receive) * Timeout for peer active-ness (measured from last receive)
*/ */
#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_PING_PERIOD + 5000) #define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_PING_PERIOD + 5000)

View file

@ -40,19 +40,6 @@ class RuntimeEnvironment;
class Credential class Credential
{ {
public: public:
/**
* Do not change type code IDs -- these are used in Revocation objects and elsewhere
*/
enum Type
{
CREDENTIAL_TYPE_NULL = 0,
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
CREDENTIAL_TYPE_CAPABILITY = 2,
CREDENTIAL_TYPE_TAG = 3,
CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership
CREDENTIAL_TYPE_REVOCATION = 6
};
/** /**
* Result of verify() operations * Result of verify() operations
*/ */

View file

@ -19,12 +19,13 @@ bool Endpoint::operator==(const Endpoint &ep) const
{ {
if (_t == ep._t) { if (_t == ep._t) {
switch(_t) { switch(_t) {
case INETADDR: return (inetAddr() == ep.inetAddr()); default: return true;
case INETADDR_V4:
case INETADDR_V6: return (inetAddr() == ep.inetAddr());
case DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0)); 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 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 URL: return (strcmp(_v.url,ep._v.url) == 0);
case ETHERNET: return (_v.eth == ep._v.eth); case ETHERNET: return (_v.eth == ep._v.eth);
default: return true;
} }
} }
return false; return false;
@ -37,7 +38,9 @@ bool Endpoint::operator<(const Endpoint &ep) const
} else if (_t == ep._t) { } else if (_t == ep._t) {
int ncmp; int ncmp;
switch(_t) { switch(_t) {
case INETADDR: return (inetAddr() < ep.inetAddr()); case INETADDR_V4:
case INETADDR_V6:
return (inetAddr() < ep.inetAddr());
case DNSNAME: case DNSNAME:
ncmp = strcmp(_v.dns.name,ep._v.dns.name); ncmp = strcmp(_v.dns.name,ep._v.dns.name);
return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port)); return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
@ -58,7 +61,8 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const
Utils::storeBigEndian(data + 3,(int16_t)_l[1]); Utils::storeBigEndian(data + 3,(int16_t)_l[1]);
Utils::storeBigEndian(data + 5,(int16_t)_l[2]); Utils::storeBigEndian(data + 5,(int16_t)_l[2]);
switch(_t) { switch(_t) {
case INETADDR: case INETADDR_V4:
case INETADDR_V6:
return 7 + reinterpret_cast<const InetAddress *>(&_v.sa)->marshal(data+1); return 7 + reinterpret_cast<const InetAddress *>(&_v.sa)->marshal(data+1);
case DNSNAME: case DNSNAME:
p = 7; p = 7;
@ -116,7 +120,8 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len)
switch(_t) { switch(_t) {
case NIL: case NIL:
return 7; return 7;
case INETADDR: case INETADDR_V4:
case INETADDR_V6:
return 7 + reinterpret_cast<InetAddress *>(&_v.sa)->unmarshal(data+7,len-7); return 7 + reinterpret_cast<InetAddress *>(&_v.sa)->unmarshal(data+7,len-7);
case DNSNAME: case DNSNAME:
if (len < 10) if (len < 10)

View file

@ -41,11 +41,12 @@ public:
enum Type enum Type
{ {
NIL = 0, // NIL value NIL = 0, // NIL value
INETADDR = 1, // InetAddress (v4 or v6) INETADDR_V4 = 1, // IPv4
DNSNAME = 2, // DNS name and port that resolves to InetAddress INETADDR_V6 = 2, // IPv6
ZEROTIER = 3, // ZeroTier Address (for relaying and meshy behavior) DNSNAME = 3, // DNS name and port that resolves to InetAddress
URL = 4, // URL for http/https/ws/etc. (not implemented yet) ZEROTIER = 4, // ZeroTier Address (for relaying and meshy behavior)
ETHERNET = 5, // 48-bit LAN-local Ethernet address URL = 5, // URL for http/https/ws/etc. (not implemented yet)
ETHERNET = 6, // 48-bit LAN-local Ethernet address
UNRECOGNIZED = 255 // Unrecognized endpoint type encountered in stream UNRECOGNIZED = 255 // Unrecognized endpoint type encountered in stream
}; };
@ -56,13 +57,12 @@ public:
ZT_ALWAYS_INLINE Endpoint(const Endpoint &ep) ZT_ALWAYS_INLINE Endpoint(const Endpoint &ep)
{ {
memcpy(reinterpret_cast<void *>(this),&ep,sizeof(Endpoint)); memcpy(reinterpret_cast<void *>(this),reinterpret_cast<const void *>(&ep),sizeof(Endpoint));
} }
explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) : explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa)
_t(INETADDR)
{ {
_v.sa = sa; *this = sa;
} }
ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) : ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) :
@ -93,7 +93,17 @@ public:
ZT_ALWAYS_INLINE Endpoint &operator=(const InetAddress &sa) ZT_ALWAYS_INLINE Endpoint &operator=(const InetAddress &sa)
{ {
_t = INETADDR; switch(sa.ss_family) {
case AF_INET:
_t = INETADDR_V4;
break;
case AF_INET6:
_t = INETADDR_V6;
break;
default:
_t = NIL;
return *this;
}
_v.sa = sa; _v.sa = sa;
return *this; return *this;
} }
@ -101,7 +111,7 @@ public:
/** /**
* @return InetAddress or NIL if not of this type * @return InetAddress or NIL if not of this type
*/ */
ZT_ALWAYS_INLINE const InetAddress &inetAddr() const { return (_t == INETADDR) ? *reinterpret_cast<const InetAddress *>(&_v.sa) : InetAddress::NIL; } ZT_ALWAYS_INLINE const InetAddress &inetAddr() const { return ((_t == INETADDR_V4)||(_t == INETADDR_V6)) ? *reinterpret_cast<const InetAddress *>(&_v.sa) : InetAddress::NIL; }
/** /**
* @return DNS name or empty string if not of this type * @return DNS name or empty string if not of this type
@ -156,14 +166,14 @@ private:
int _l[3]; // X,Y,Z location in kilometers from the nearest gravitational center of mass int _l[3]; // X,Y,Z location in kilometers from the nearest gravitational center of mass
union { union {
struct sockaddr_storage sa; struct sockaddr_storage sa;
ZT_PACKED_STRUCT(struct { struct {
uint16_t port; uint16_t port;
char name[ZT_ENDPOINT_MAX_NAME_SIZE]; char name[ZT_ENDPOINT_MAX_NAME_SIZE];
}) dns; } dns;
ZT_PACKED_STRUCT(struct { struct {
uint64_t a; uint64_t a;
uint8_t idh[ZT_IDENTITY_HASH_SIZE]; uint8_t idh[ZT_IDENTITY_HASH_SIZE];
}) zt; } zt;
char url[ZT_ENDPOINT_MAX_NAME_SIZE]; char url[ZT_ENDPOINT_MAX_NAME_SIZE];
uint64_t eth; uint64_t eth;
} _v; } _v;

View file

@ -89,6 +89,7 @@ void Identity::generate(const Type t)
_type = t; _type = t;
_hasPrivate = true; _hasPrivate = true;
_hash[0] = 0; // force hash recompute
char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY]; char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY];
do { do {
@ -142,24 +143,13 @@ bool Identity::locallyValidate() const
return false; return false;
} }
bool Identity::hash(uint8_t h[48],const bool includePrivate) const void Identity::hashWithPrivate(uint8_t h[48]) const
{ {
switch(_type) { switch(_type) {
case C25519: SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); break;
case C25519: case P384: SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv)); break;
if ((_hasPrivate)&&(includePrivate)) default: memset(h,0,48);
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 unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
@ -293,6 +283,7 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
bool Identity::fromString(const char *str) bool Identity::fromString(const char *str)
{ {
_hasPrivate = false; _hasPrivate = false;
_hash[0] = 0; // force hash recompute
if (!str) { if (!str) {
_address.zero(); _address.zero();
@ -386,6 +377,97 @@ bool Identity::fromString(const char *str)
return true; return true;
} }
int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate) 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;
}
int Identity::unmarshal(const uint8_t *data,const int len)
{
if (len < (ZT_ADDRESS_LENGTH + 1))
return -1;
_hash[0] = 0; // force hash recompute
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 < (int)(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;
}
void Identity::_computeHash()
{
switch(_type) {
case C25519: SHA384(_hash,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); break;
case P384: SHA384(_hash,&_pub,sizeof(_pub)); break;
default: memset(_hash,0,48);
}
}
} // namespace ZeroTier } // namespace ZeroTier
extern "C" { extern "C" {
@ -473,7 +555,9 @@ uint64_t ZT_Identity_address(const ZT_Identity *id)
void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate) void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate)
{ {
reinterpret_cast<const ZeroTier::Identity *>(id)->hash(h,includePrivate != 0); if (includePrivate)
reinterpret_cast<const ZeroTier::Identity *>(id)->hashWithPrivate(h);
else memcpy(h,reinterpret_cast<const ZeroTier::Identity *>(id)->hash(),48);
} }
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id) ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)

View file

@ -101,12 +101,21 @@ public:
ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; } ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; }
/** /**
* This generates a SHA384 hash of this identity's keys. * @return 384-bit/48-byte hash of this identity's public key(s)
*
* @param h Buffer to receive SHA384 of public key(s)
* @param includePrivate If true, hash private key(s) as well
*/ */
bool hash(uint8_t h[48],bool includePrivate = false) const; ZT_ALWAYS_INLINE const uint8_t *hash() const
{
if (_hash[0] == 0)
const_cast<Identity *>(this)->_computeHash();
return reinterpret_cast<const uint8_t *>(_hash);
}
/**
* Compute a hash of this identity's public and private keys
*
* @param h Buffer to store SHA384 hash
*/
void hashWithPrivate(uint8_t h[48]) const;
/** /**
* Sign a message with this identity (private key required) * Sign a message with this identity (private key required)
@ -311,91 +320,15 @@ 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]); } 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; } 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 int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],bool includePrivate = false) const;
{ int unmarshal(const uint8_t *data,int len);
_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 < (int)(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: private:
void _computeHash(); // recompute _hash
Address _address; Address _address;
uint64_t _hash[6]; // hash of public key memo-ized for performance, recalculated when _hash[0] == 0
Type _type; // _type determines which fields in _priv and _pub are used Type _type; // _type determines which fields in _priv and _pub are used
bool _hasPrivate; bool _hasPrivate;
ZT_PACKED_STRUCT(struct { // don't re-order these ZT_PACKED_STRUCT(struct { // don't re-order these

View file

@ -35,9 +35,6 @@
namespace ZeroTier { namespace ZeroTier {
namespace { namespace {
//////////////////////////////////////////////////////////////////////////////
// Implementation of each protocol verb //
//////////////////////////////////////////////////////////////////////////////
void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid,const SharedPtr<Path> &path) void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid,const SharedPtr<Path> &path)
{ {
@ -65,11 +62,11 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(pkt,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(pkt,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
if (protoVersion < ZT_PROTO_VERSION_MIN) { if (protoVersion < ZT_PROTO_VERSION_MIN) {
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"protocol version too old"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD);
return true; return true;
} }
if (fromAddress != id.address()) { if (fromAddress != id.address()) {
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"identity/address mismatch"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
return true; return true;
} }
@ -87,18 +84,13 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
if (RR->identity.agree(id,key)) { if (RR->identity.agree(id,key)) {
if (pkt.dearmor(key)) { // ensure packet is authentic, otherwise drop if (pkt.dearmor(key)) { // ensure packet is authentic, otherwise drop
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"address collision"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); // TODO: we handle identity collisions differently now
outp.append((uint8_t)Packet::VERB_HELLO);
outp.append((uint64_t)pid);
outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION);
outp.armor(key,true);
path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
} else { } else {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid MAC"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
} }
} else { } else {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid identity"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
} }
return true; return true;
@ -106,7 +98,7 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
// Identity is the same as the one we already have -- check packet integrity // Identity is the same as the one we already have -- check packet integrity
if (!pkt.dearmor(peer->key())) { if (!pkt.dearmor(peer->key())) {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid MAC"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
return true; return true;
} }
@ -118,30 +110,30 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
// Sanity check: this basically can't happen // Sanity check: this basically can't happen
if (alreadyAuthenticated) { if (alreadyAuthenticated) {
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"illegal alreadyAuthenticated state"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
return true; return true;
} }
// Check rate limits // Check rate limits
if (!RR->node->rateGateIdentityVerification(now,path->address())) { if (!RR->node->rateGateIdentityVerification(now,path->address())) {
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"rate limit exceeded"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
return true; return true;
} }
// Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap)
SharedPtr<Peer> newPeer(new Peer(RR)); SharedPtr<Peer> newPeer(new Peer(RR));
if (!newPeer->init(RR->identity,id)) { if (!newPeer->init(RR->identity,id)) {
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"error initializing peer"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
return true; return true;
} }
if (!pkt.dearmor(newPeer->key())) { if (!pkt.dearmor(newPeer->key())) {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid MAC"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
return true; return true;
} }
// Check that identity's address is valid as per the derivation function // Check that identity's address is valid as per the derivation function
if (!id.locallyValidate()) { if (!id.locallyValidate()) {
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"invalid identity"); RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
return true; return true;
} }
@ -158,7 +150,7 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
if (ptr < pkt.size()) { if (ptr < pkt.size()) {
ptr += externalSurfaceAddress.deserialize(pkt,ptr); ptr += externalSurfaceAddress.deserialize(pkt,ptr);
if ((externalSurfaceAddress)&&(pkt.hops() == 0)) if ((externalSurfaceAddress)&&(pkt.hops() == 0))
RR->sa->iam(tPtr,id.address(),path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now); RR->sa->iam(tPtr,id,path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
} }
} }
@ -270,7 +262,7 @@ ZT_ALWAYS_INLINE bool _doOK(IncomingPacket &pkt,const RuntimeEnvironment *const
InetAddress externalSurfaceAddress; InetAddress externalSurfaceAddress;
externalSurfaceAddress.deserialize(pkt,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2); externalSurfaceAddress.deserialize(pkt,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2);
if (externalSurfaceAddress) if (externalSurfaceAddress)
RR->sa->iam(tPtr,peer->address(),path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(peer->identity()),RR->node->now()); RR->sa->iam(tPtr,peer->identity(),path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(peer->identity()),RR->node->now());
} }
} }
@ -388,6 +380,7 @@ ZT_ALWAYS_INLINE bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *con
RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen);
} }
} else { } else {
RR->t->incomingNetworkFrameDropped(tPtr,nwid,MAC(),MAC(),peer->identity(),path->address(),pkt.hops(),0,nullptr,Packet::VERB_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED);
_sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path); _sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path);
return false; return false;
} }
@ -412,7 +405,7 @@ ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment
} }
if (!network->gate(tPtr,peer)) { if (!network->gate(tPtr,peer)) {
RR->t->incomingNetworkAccessDenied(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,true); RR->t->incomingNetworkFrameDropped(tPtr,nwid,MAC(),MAC(),peer->identity(),path->address(),pkt.hops(),0,nullptr,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED);
_sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path); _sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path);
return false; return false;
} }
@ -435,19 +428,19 @@ ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment
if (network->config().permitsBridging(peer->address())) { if (network->config().permitsBridging(peer->address())) {
network->learnBridgeRoute(from,peer->address()); network->learnBridgeRoute(from,peer->address());
} else { } else {
RR->t->incomingNetworkFrameDropped(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (remote)"); RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),path->address(),pkt.hops(),(uint16_t)frameLen,frameData,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE);
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid); peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
return true; return true;
} }
} else if (to != network->mac()) { } else if (to != network->mac()) {
if (to.isMulticast()) { if (to.isMulticast()) {
if (network->config().multicastLimit == 0) { if (network->config().multicastLimit == 0) {
RR->t->incomingNetworkFrameDropped(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"multicast disabled"); RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),path->address(),pkt.hops(),(uint16_t)frameLen,frameData,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED);
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid); peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
return true; return true;
} }
} else if (!network->config().permitsBridging(RR->identity.address())) { } else if (!network->config().permitsBridging(RR->identity.address())) {
RR->t->incomingNetworkFrameDropped(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (local)"); RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),path->address(),pkt.hops(),(uint16_t)frameLen,frameData,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL);
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid); peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
return true; return true;
} }
@ -733,6 +726,7 @@ ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &pkt,const RuntimeEnvironme
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
{ {
const Address sourceAddress(source()); const Address sourceAddress(source());
const SharedPtr<Peer> peer(RR->topology->get(tPtr,sourceAddress));
try { try {
// Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear) // Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
@ -746,7 +740,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) {
trusted = true; trusted = true;
} else { } else {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted"); if (peer)
RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
return true; return true;
} }
} else if ((c == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { } else if ((c == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
@ -754,25 +749,30 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
return _doHELLO(*this,RR,tPtr,false,_path); return _doHELLO(*this,RR,tPtr,false,_path);
} }
const SharedPtr<Peer> peer(RR->topology->get(tPtr,sourceAddress)); if (!peer) {
if (peer) { RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress);
return false;
}
if (!trusted) { if (!trusted) {
if (!dearmor(peer->key())) { if (!dearmor(peer->key())) {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC"); RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
return true; return true;
} }
} }
if (!uncompress()) { if (!uncompress()) {
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),Packet::VERB_NOP,"LZ4 decompression failed"); RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
return true; return true;
} }
const Packet::Verb v = verb(); const Packet::Verb v = verb();
bool r = true; bool r = true;
switch(v) { switch(v) {
//case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" and considered NOPs by peer->receive()
default: // ignore unknown verbs, but if they pass auth check they are "received" RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
// fall through
case Packet::VERB_NOP:
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,0); peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,0);
break; break;
case Packet::VERB_HELLO: r = _doHELLO(*this,RR,tPtr,true,_path); break; case Packet::VERB_HELLO: r = _doHELLO(*this,RR,tPtr,true,_path); break;
@ -791,17 +791,12 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
case Packet::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(*this,RR,tPtr,peer,_path); break; case Packet::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(*this,RR,tPtr,peer,_path); break;
} }
return r; return r;
} else {
RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress);
return false;
}
} catch (int ztExcCode) { } catch (int ztExcCode) {
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()"); } catch ( ... ) {}
if (peer)
RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
return true; return true;
} catch ( ... ) {
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()");
return true;
}
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -419,6 +419,37 @@ public:
} }
} }
/**
* Fill out a ZT_TraceEventPathAddress from this InetAddress
*
* @param ta ZT_TraceEventPathAddress to fill
*/
ZT_ALWAYS_INLINE void forTrace(ZT_TraceEventPathAddress &ta) const
{
uint32_t tmp;
switch(ss_family) {
default:
memset(&ta,0,sizeof(ZT_TraceEventPathAddress));
break;
case AF_INET:
ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V4;
tmp = (uint32_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
ta.address[0] = reinterpret_cast<const uint8_t *>(&tmp)[0];
ta.address[1] = reinterpret_cast<const uint8_t *>(&tmp)[1];
ta.address[2] = reinterpret_cast<const uint8_t *>(&tmp)[2];
ta.address[3] = reinterpret_cast<const uint8_t *>(&tmp)[3];
memset(ta.address + 4,0,sizeof(ta.address) - 4);
ta.port = reinterpret_cast<const struct sockaddr_in *>(this)->sin_port;
break;
case AF_INET6:
ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V6;
memcpy(ta.address,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
memset(ta.address + 16,0,sizeof(ta.address) - 16);
ta.port = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
break;
}
}
/** /**
* Set to null/zero * Set to null/zero
*/ */

View file

@ -101,7 +101,7 @@ union LZ4_streamDecode_u {
#define HEAPMODE 0 #define HEAPMODE 0
#endif #endif
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
#define LZ4_FORCE_MEMORY_ACCESS 0 #define LZ4_FORCE_MEMORY_ACCESS 0
#else #else
#define LZ4_FORCE_MEMORY_ACCESS 2 #define LZ4_FORCE_MEMORY_ACCESS 2

View file

@ -46,8 +46,8 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud
int p = 8; int p = 8;
if (_ts > 0) { if (_ts > 0) {
data[p++] = (uint8_t)(_endpointCount >> 8U); Utils::storeBigEndian(data + p,(uint16_t)_endpointCount);
data[p++] = (uint8_t)_endpointCount; p += 2;
for (unsigned int i = 0; i < _endpointCount; ++i) { for (unsigned int i = 0; i < _endpointCount; ++i) {
int tmp = _at[i].marshal(data + p); int tmp = _at[i].marshal(data + p);
if (tmp < 0) if (tmp < 0)
@ -56,11 +56,14 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud
} }
if (!excludeSignature) { if (!excludeSignature) {
data[p++] = (uint8_t)(_signatureLength >> 8U); Utils::storeBigEndian(data + p,(uint16_t)_signatureLength);
data[p++] = (uint8_t)_signatureLength; p += 2;
memcpy(data + p,_signature,_signatureLength); memcpy(data + p,_signature,_signatureLength);
p += (int)_signatureLength; p += (int)_signatureLength;
} }
Utils::storeBigEndian(data + p,_flags);
p += 2;
} }
return p; return p;
@ -75,9 +78,8 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len)
int p = 8; int p = 8;
if (_ts > 0) { if (_ts > 0) {
unsigned int ec = (int)data[p++]; const unsigned int ec = Utils::loadBigEndian<uint16_t>(data + p);
ec <<= 8U; p += 2;
ec |= data[p++];
if (ec > ZT_LOCATOR_MAX_ENDPOINTS) if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
return -1; return -1;
_endpointCount = ec; _endpointCount = ec;
@ -90,9 +92,8 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len)
if ((p + 2) > len) if ((p + 2) > len)
return -1; return -1;
unsigned int sl = data[p++]; const unsigned int sl = Utils::loadBigEndian<uint16_t>(data + p);
sl <<= 8U; p += 2;
sl |= data[p++];
if (sl > ZT_SIGNATURE_BUFFER_SIZE) if (sl > ZT_SIGNATURE_BUFFER_SIZE)
return -1; return -1;
_signatureLength = sl; _signatureLength = sl;
@ -100,6 +101,11 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len)
return -1; return -1;
memcpy(_signature,data + p,sl); memcpy(_signature,data + p,sl);
p += (int)sl; p += (int)sl;
if ((p + 2) > len)
return -1;
_flags = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
} else { } else {
_ts = 0; _ts = 0;
} }

View file

@ -23,7 +23,7 @@
#include "Identity.hpp" #include "Identity.hpp"
#define ZT_LOCATOR_MAX_ENDPOINTS 8 #define ZT_LOCATOR_MAX_ENDPOINTS 8
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + ZT_SIGNATURE_BUFFER_SIZE) #define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE)
namespace ZeroTier { namespace ZeroTier {
@ -120,6 +120,7 @@ private:
unsigned int _endpointCount; unsigned int _endpointCount;
unsigned int _signatureLength; unsigned int _signatureLength;
Endpoint _at[ZT_LOCATOR_MAX_ENDPOINTS]; Endpoint _at[ZT_LOCATOR_MAX_ENDPOINTS];
uint16_t _flags;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE]; uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
}; };

View file

@ -20,7 +20,6 @@
#include "Switch.hpp" #include "Switch.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Trace.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -102,17 +101,24 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
_lastPushedCredentials = now; _lastPushedCredentials = now;
} }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) void Membership::clean(const int64_t now,const NetworkConfig &nconf)
{
_cleanCredImpl<Tag>(nconf,_remoteTags);
_cleanCredImpl<Capability>(nconf,_remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com)
{ {
const int64_t newts = com.timestamp(); const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) { if (newts <= _comRevocationThreshold) {
RR->t->credentialRejected(tPtr,com,"revoked"); RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
return ADD_REJECTED; return ADD_REJECTED;
} }
const int64_t oldts = _com.timestamp(); const int64_t oldts = _com.timestamp();
if (newts < oldts) { if (newts < oldts) {
RR->t->credentialRejected(tPtr,com,"old"); RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
return ADD_REJECTED; return ADD_REJECTED;
} }
if ((newts == oldts)&&(_com == com)) if ((newts == oldts)&&(_com == com))
@ -120,27 +126,34 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
switch(com.verify(RR,tPtr)) { switch(com.verify(RR,tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,com,"invalid"); RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
case Credential::VERIFY_OK: case Credential::VERIFY_OK:
_com = com; _com = com;
return ADD_ACCEPTED_NEW; return ADD_ACCEPTED_NEW;
case Credential::VERIFY_BAD_SIGNATURE: case Credential::VERIFY_BAD_SIGNATURE:
RR->t->credentialRejected(tPtr,com,"invalid"); RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED);
return ADD_REJECTED; return ADD_REJECTED;
case Credential::VERIFY_NEED_IDENTITY: case Credential::VERIFY_NEED_IDENTITY:
return ADD_DEFERRED_FOR_WHOIS; return ADD_DEFERRED_FOR_WHOIS;
} }
} }
// Template out addCredential() for many cred types to avoid copypasta // 3/5 of the credential types have identical addCredential() code
template<typename C> template<typename C>
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remoteCreds,const Hashtable<uint64_t,int64_t> &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred) static ZT_ALWAYS_INLINE Membership::AddCredentialResult _addCredImpl(
Hashtable<uint32_t,C> &remoteCreds,
const Hashtable<uint64_t,int64_t> &revocations,
const RuntimeEnvironment *const RR,
void *const tPtr,
const Identity &sourcePeerIdentity,
const NetworkConfig &nconf,
const C &cred)
{ {
C *rc = remoteCreds.get(cred.id()); C *rc = remoteCreds.get(cred.id());
if (rc) { if (rc) {
if (rc->timestamp() > cred.timestamp()) { if (rc->timestamp() > cred.timestamp()) {
RR->t->credentialRejected(tPtr,cred,"old"); RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
if (*rc == cred) if (*rc == cred)
@ -149,13 +162,13 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
if ((rt)&&(*rt >= cred.timestamp())) { if ((rt)&&(*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr,cred,"revoked"); RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
} }
switch(cred.verify(RR,tPtr)) { switch(cred.verify(RR,tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,cred,"invalid"); RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
case 0: case 0:
if (!rc) if (!rc)
@ -166,30 +179,29 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
return Membership::ADD_DEFERRED_FOR_WHOIS; return Membership::ADD_DEFERRED_FOR_WHOIS;
} }
} }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,sourcePeerIdentity,nconf,tag); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,sourcePeerIdentity,nconf,cap); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,sourcePeerIdentity,nconf,coo); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,nconf,tag); } Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev)
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,nconf,cap); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,nconf,coo); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev)
{ {
int64_t *rt; int64_t *rt;
switch(rev.verify(RR,tPtr)) { switch(rev.verify(RR,tPtr)) {
default: default:
RR->t->credentialRejected(tPtr,rev,"invalid"); RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return ADD_REJECTED; return ADD_REJECTED;
case 0: { case 0: {
const Credential::Type ct = rev.type(); const ZT_CredentialType ct = rev.typeBeingRevoked();
switch(ct) { switch(ct) {
case Credential::CREDENTIAL_TYPE_COM: case ZT_CREDENTIAL_TYPE_COM:
if (rev.threshold() > _comRevocationThreshold) { if (rev.threshold() > _comRevocationThreshold) {
_comRevocationThreshold = rev.threshold(); _comRevocationThreshold = rev.threshold();
return ADD_ACCEPTED_NEW; return ADD_ACCEPTED_NEW;
} }
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
case Credential::CREDENTIAL_TYPE_CAPABILITY: case ZT_CREDENTIAL_TYPE_CAPABILITY:
case Credential::CREDENTIAL_TYPE_TAG: case ZT_CREDENTIAL_TYPE_TAG:
case Credential::CREDENTIAL_TYPE_COO: case ZT_CREDENTIAL_TYPE_COO:
rt = &(_revocations[credentialKey(ct,rev.credentialId())]); rt = &(_revocations[credentialKey(ct,rev.credentialId())]);
if (*rt < rev.threshold()) { if (*rt < rev.threshold()) {
*rt = rev.threshold(); *rt = rev.threshold();
@ -198,7 +210,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
default: default:
RR->t->credentialRejected(tPtr,rev,"invalid"); RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return ADD_REJECTED; return ADD_REJECTED;
} }
} }
@ -207,11 +219,42 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
} }
} }
void Membership::clean(const int64_t now,const NetworkConfig &nconf) bool Membership::_isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
{ {
_cleanCredImpl<Tag>(nconf,_remoteTags); if ((ip.isV6())&&(nconf.ndpEmulation())) {
_cleanCredImpl<Capability>(nconf,_remoteCaps); const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos); for(unsigned int i=0;i<nconf.staticIpCount;++i) {
if (nconf.staticIps[i].ipsEqual(sixpl)) {
bool prefixMatches = true;
for(unsigned int j=0;j<5;++j) { // check for match on /40
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
}
if (prefixMatches)
return true;
break;
}
}
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
if (nconf.staticIps[i].ipsEqual(rfc4193)) {
bool prefixMatches = true;
for(unsigned int j=0;j<11;++j) { // check for match on /88
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
}
if (prefixMatches)
return true;
break;
}
}
}
return false;
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -25,8 +25,6 @@
#include "Revocation.hpp" #include "Revocation.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
@ -61,7 +59,7 @@ public:
* @param peerAddress Address of member peer (the one that this Membership describes) * @param peerAddress Address of member peer (the one that this Membership describes)
* @param nconf My network config * @param nconf My network config
*/ */
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf); void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,int64_t now,const Address &peerAddress,const NetworkConfig &nconf);
/** /**
* @return Time we last pushed credentials to this member * @return Time we last pushed credentials to this member
@ -94,8 +92,8 @@ public:
{ {
if (_isUnspoofableAddress(nconf,r)) if (_isUnspoofableAddress(nconf,r))
return true; return true;
uint32_t *k = (uint32_t *)0; uint32_t *k = nullptr;
CertificateOfOwnership *v = (CertificateOfOwnership *)0; CertificateOfOwnership *v = nullptr;
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos))); Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
while (i.next(k,v)) { while (i.next(k,v)) {
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r))) if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
@ -117,12 +115,6 @@ public:
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0); return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
} }
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com);
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag);
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap);
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
/** /**
* Clean internal databases of stale entries * Clean internal databases of stale entries
* *
@ -134,70 +126,20 @@ public:
/** /**
* Generates a key for internal use in indexing credentials by type and credential ID * Generates a key for internal use in indexing credentials by type and credential ID
*/ */
static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); } static ZT_ALWAYS_INLINE uint64_t credentialKey(const ZT_CredentialType &t,const uint32_t i) { return (((uint64_t)t << 32U) | (uint64_t)i); }
/** AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com);
* @return Bytes received so far AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag);
*/ AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap);
ZT_ALWAYS_INLINE uint64_t receivedBytes() const { return _received; } AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev);
/**
* @return Bytes sent so far
*/
ZT_ALWAYS_INLINE uint64_t sentBytes() const { return _sent; }
/**
* @param bytes Bytes received
*/
ZT_ALWAYS_INLINE void logReceivedBytes(const unsigned int bytes) { _received = (uint64_t)bytes; }
/**
* @param bytes Bytes sent
*/
ZT_ALWAYS_INLINE void logSentBytes(const unsigned int bytes) { _sent = (uint64_t)bytes; }
private: private:
// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT // This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
// address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to // address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
// always return true for them. A certificate is not required for these. // always return true for them. A certificate is not required for these.
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; } ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const;
{
if ((ip.isV6())&&(nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
if (nconf.staticIps[i].ipsEqual(sixpl)) {
bool prefixMatches = true;
for(unsigned int j=0;j<5;++j) { // check for match on /40
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
}
if (prefixMatches)
return true;
break;
}
}
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
if (nconf.staticIps[i].ipsEqual(rfc4193)) {
bool prefixMatches = true;
for(unsigned int j=0;j<11;++j) { // check for match on /88
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
}
if (prefixMatches)
return true;
break;
}
}
}
return false;
}
// This compares the remote credential's timestamp to the timestamp in our network config // This compares the remote credential's timestamp to the timestamp in our network config
// plus or minus the permitted maximum timestamp delta. // plus or minus the permitted maximum timestamp delta.
@ -213,10 +155,10 @@ private:
} }
template<typename C> template<typename C>
inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds) ZT_ALWAYS_INLINE void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
{ {
uint32_t *k = (uint32_t *)0; uint32_t *k = nullptr;
C *v = (C *)0; C *v = nullptr;
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds); typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
while (i.next(k,v)) { while (i.next(k,v)) {
if (!_isCredentialTimestampValid(nconf,*v)) if (!_isCredentialTimestampValid(nconf,*v))
@ -233,12 +175,6 @@ private:
// Time we last pushed credentials // Time we last pushed credentials
int64_t _lastPushedCredentials; int64_t _lastPushedCredentials;
// Number of Ethernet frame bytes received
uint64_t _received;
// Number of Ethernet frame bytes sent
uint64_t _sent;
// Remote member's latest network COM // Remote member's latest network COM
CertificateOfMembership _com; CertificateOfMembership _com;
@ -256,8 +192,8 @@ public:
public: public:
ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) : ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
_hti(m._remoteCaps), _hti(m._remoteCaps),
_k((uint32_t *)0), _k(nullptr),
_c((Capability *)0), _c(nullptr),
_m(m), _m(m),
_nconf(nconf) _nconf(nconf)
{ {
@ -269,7 +205,7 @@ public:
if (_m._isCredentialTimestampValid(_nconf,*_c)) if (_m._isCredentialTimestampValid(_nconf,*_c))
return _c; return _c;
} }
return (Capability *)0; return nullptr;
} }
private: private:

View file

@ -11,12 +11,8 @@
*/ */
/****/ /****/
#include <cstdio>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <cmath>
#include "../include/ZeroTierDebug.h"
#include "Constants.hpp" #include "Constants.hpp"
#include "Network.hpp" #include "Network.hpp"
@ -28,7 +24,6 @@
#include "Buffer.hpp" #include "Buffer.hpp"
#include "Packet.hpp" #include "Packet.hpp"
#include "NetworkController.hpp" #include "NetworkController.hpp"
#include "Node.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "Trace.hpp" #include "Trace.hpp"
#include "ScopedPtr.hpp" #include "ScopedPtr.hpp"
@ -40,7 +35,7 @@ namespace ZeroTier {
namespace { namespace {
// Returns true if packet appears valid; pos and proto will be set // Returns true if packet appears valid; pos and proto will be set
static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto) bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
{ {
if (frameLen < 40) if (frameLen < 40)
return false; return false;
@ -77,7 +72,7 @@ enum _doZtFilterResult
DOZTFILTER_SUPER_ACCEPT DOZTFILTER_SUPER_ACCEPT
}; };
static _doZtFilterResult _doZtFilter( _doZtFilterResult _doZtFilter(
const RuntimeEnvironment *RR, const RuntimeEnvironment *RR,
Trace::RuleResultLog &rrl, Trace::RuleResultLog &rrl,
const NetworkConfig &nconf, const NetworkConfig &nconf,
@ -108,14 +103,14 @@ static _doZtFilterResult _doZtFilter(
rrl.clear(); rrl.clear();
for(unsigned int rn=0;rn<ruleCount;++rn) { for(unsigned int rn=0;rn<ruleCount;++rn) {
const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3f); const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3fU);
// First check if this is an ACTION // First check if this is an ACTION
if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) { if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) {
if (thisSetMatches) { if (thisSetMatches) {
switch(rt) { switch(rt) {
case ZT_NETWORK_RULE_ACTION_PRIORITY: case ZT_NETWORK_RULE_ACTION_PRIORITY:
qosBucket = (rules[rn].v.qosBucket >= 0 || rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority) qosBucket = (rules[rn].v.qosBucket >= 0 && rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority)
return DOZTFILTER_ACCEPT; return DOZTFILTER_ACCEPT;
case ZT_NETWORK_RULE_ACTION_DROP: case ZT_NETWORK_RULE_ACTION_DROP:
@ -180,7 +175,7 @@ static _doZtFilterResult _doZtFilter(
// Circuit breaker: no need to evaluate an AND if the set's match state // Circuit breaker: no need to evaluate an AND if the set's match state
// is currently false since anything AND false is false. // is currently false since anything AND false is false.
if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) { if ((!thisSetMatches)&&(!(rules[rn].t & 0x40U))) {
rrl.logSkipped(rn,thisSetMatches); rrl.logSkipped(rn,thisSetMatches);
continue; continue;
} }
@ -245,7 +240,7 @@ static _doZtFilterResult _doZtFilter(
const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask;
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask; const uint8_t tosMasked = (((frameData[0] << 4U) & 0xf0U) | ((frameData[1] >> 4U) & 0x0fU)) & rules[rn].v.ipTos.mask;
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
} else { } else {
thisRuleMatches = 0; thisRuleMatches = 0;
@ -271,7 +266,7 @@ static _doZtFilterResult _doZtFilter(
case ZT_NETWORK_RULE_MATCH_ICMP: case ZT_NETWORK_RULE_MATCH_ICMP:
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
if (frameData[9] == 0x01) { // IP protocol == ICMP if (frameData[9] == 0x01) { // IP protocol == ICMP
const unsigned int ihl = (frameData[0] & 0xf) * 4; const unsigned int ihl = (frameData[0] & 0xfU) * 4;
if (frameLen >= (ihl + 2)) { if (frameLen >= (ihl + 2)) {
if (rules[rn].v.icmp.type == frameData[ihl]) { if (rules[rn].v.icmp.type == frameData[ihl]) {
if ((rules[rn].v.icmp.flags & 0x01) != 0) { if ((rules[rn].v.icmp.flags & 0x01) != 0) {
@ -314,7 +309,7 @@ static _doZtFilterResult _doZtFilter(
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
const unsigned int headerLen = 4 * (frameData[0] & 0xf); const unsigned int headerLen = 4 * (frameData[0] & 0xfU);
int p = -1; int p = -1;
switch(frameData[9]) { // IP protocol number switch(frameData[9]) { // IP protocol number
// All these start with 16-bit source and destination port in that order // All these start with 16-bit source and destination port in that order
@ -324,7 +319,7 @@ static _doZtFilterResult _doZtFilter(
case 0x88: // UDPLite case 0x88: // UDPLite
if (frameLen > (headerLen + 4)) { if (frameLen > (headerLen + 4)) {
unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0); unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0);
p = (int)frameData[pos++] << 8; p = (int)(frameData[pos++] << 8U);
p |= (int)frameData[pos]; p |= (int)frameData[pos];
} }
break; break;
@ -343,7 +338,7 @@ static _doZtFilterResult _doZtFilter(
case 0x88: // UDPLite case 0x88: // UDPLite
if (frameLen > (pos + 4)) { if (frameLen > (pos + 4)) {
if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2; if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2;
p = (int)frameData[pos++] << 8; p = (int)(frameData[pos++] << 8U);
p |= (int)frameData[pos]; p |= (int)frameData[pos];
} }
break; break;
@ -402,15 +397,15 @@ static _doZtFilterResult _doZtFilter(
} }
cf |= ownershipVerificationMask; cf |= ownershipVerificationMask;
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)&&(frameData[9] == 0x06)) { if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)&&(frameData[9] == 0x06)) {
const unsigned int headerLen = 4 * (frameData[0] & 0xf); const unsigned int headerLen = 4 * (frameData[0] & 0xfU);
cf |= (uint64_t)frameData[headerLen + 13]; cf |= (uint64_t)frameData[headerLen + 13];
cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0f)) << 8); cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0fU)) << 8U);
} else if (etherType == ZT_ETHERTYPE_IPV6) { } else if (etherType == ZT_ETHERTYPE_IPV6) {
unsigned int pos = 0,proto = 0; unsigned int pos = 0,proto = 0;
if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
if ((proto == 0x06)&&(frameLen > (pos + 14))) { if ((proto == 0x06)&&(frameLen > (pos + 14))) {
cf |= (uint64_t)frameData[pos + 13]; cf |= (uint64_t)frameData[pos + 13];
cf |= (((uint64_t)(frameData[pos + 12] & 0x0f)) << 8); cf |= (((uint64_t)(frameData[pos + 12] & 0x0fU)) << 8U);
} }
} }
} }
@ -491,15 +486,15 @@ static _doZtFilterResult _doZtFilter(
} break; } break;
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: { case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: {
uint64_t integer = 0; uint64_t integer = 0;
const unsigned int bits = (rules[rn].v.intRange.format & 63) + 1; const unsigned int bits = (rules[rn].v.intRange.format & 63U) + 1;
const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8 const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8
if ((rules[rn].v.intRange.format & 0x80) == 0) { if ((rules[rn].v.intRange.format & 0x80U) == 0) {
// Big-endian // Big-endian
unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes); unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes);
const unsigned int eof = idx + bytes; const unsigned int eof = idx + bytes;
if (eof <= frameLen) { if (eof <= frameLen) {
while (idx < eof) { while (idx < eof) {
integer <<= 8; integer <<= 8U;
integer |= frameData[idx++]; integer |= frameData[idx++];
} }
} }
@ -510,8 +505,8 @@ static _doZtFilterResult _doZtFilter(
const unsigned int eof = idx + bytes; const unsigned int eof = idx + bytes;
if (eof <= frameLen) { if (eof <= frameLen) {
while (idx < eof) { while (idx < eof) {
integer >>= 8; integer >>= 8U;
integer |= ((uint64_t)frameData[idx++]) << 56; integer |= ((uint64_t)frameData[idx++]) << 56U;
} }
} }
integer >>= (64 - bits); integer >>= (64 - bits);
@ -528,9 +523,9 @@ static _doZtFilterResult _doZtFilter(
rrl.log(rn,thisRuleMatches,thisSetMatches); rrl.log(rn,thisRuleMatches,thisSetMatches);
if ((rules[rn].t & 0x40)) if ((rules[rn].t & 0x40U))
thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U));
else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U));
} }
return DOZTFILTER_NO_MATCH; return DOZTFILTER_NO_MATCH;
@ -622,10 +617,10 @@ bool Network::filterOutgoingPacket(
const unsigned int vlanId, const unsigned int vlanId,
uint8_t &qosBucket) uint8_t &qosBucket)
{ {
Trace::RuleResultLog rrl,crrl;
Address ztFinalDest(ztDest); Address ztFinalDest(ztDest);
int localCapabilityIndex = -1; int localCapabilityIndex = -1;
int accept = 0; int accept = 0;
Trace::RuleResultLog rrl,crrl;
Address cc; Address cc;
unsigned int ccLength = 0; unsigned int ccLength = 0;
bool ccWatch = false; bool ccWatch = false;
@ -674,8 +669,7 @@ bool Network::filterOutgoingPacket(
} break; } break;
case DOZTFILTER_DROP: case DOZTFILTER_DROP:
//if (_config.remoteTraceTarget) RR->t->networkFilter(tPtr,_id,rrl.l,nullptr,0,0,ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,0);
// RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
return false; return false;
case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
@ -688,10 +682,7 @@ bool Network::filterOutgoingPacket(
break; break;
} }
if (accept) { if (accept != 0) {
if (membership)
membership->logSentBytes(frameLen);
if ((!noTee)&&(cc)) { if ((!noTee)&&(cc)) {
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id); outp.append(_id);
@ -715,19 +706,19 @@ bool Network::filterOutgoingPacket(
outp.compress(); outp.compress();
RR->sw->send(tPtr,outp,true); RR->sw->send(tPtr,outp,true);
//if (_config.remoteTraceTarget) // DROP locally since we redirected
// RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); accept = 0;
return false; // DROP locally, since we redirected
} else {
//if (_config.remoteTraceTarget)
// RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1);
return true;
} }
} else {
//if (_config.remoteTraceTarget)
// RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
return false;
} }
if (localCapabilityIndex >= 0) {
const Capability &cap = _config.capabilities[localCapabilityIndex];
RR->t->networkFilter(tPtr,_id,rrl.l,crrl.l,cap.id(),cap.timestamp(),ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,accept);
} else {
RR->t->networkFilter(tPtr,_id,rrl.l,nullptr,0,0,ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,accept);
}
return (accept != 0);
} }
int Network::filterIncomingPacket( int Network::filterIncomingPacket(
@ -810,8 +801,6 @@ int Network::filterIncomingPacket(
} }
if (accept) { if (accept) {
membership.logReceivedBytes(frameLen);
if (cc) { if (cc) {
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id); outp.append(_id);
@ -846,6 +835,24 @@ int Network::filterIncomingPacket(
return accept; return accept;
} }
void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg)
{
Mutex::Lock l(_myMulticastGroups_l);
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
Mutex::Lock l2(_memberships_l);
_announceMulticastGroups(tPtr,true);
}
}
void Network::multicastUnsubscribe(const MulticastGroup &mg)
{
Mutex::Lock l(_myMulticastGroups_l);
std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
if ( (i != _myMulticastGroups.end()) && (*i == mg) )
_myMulticastGroups.erase(i);
}
uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr) uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr)
{ {
if (_destroyed) if (_destroyed)
@ -861,11 +868,11 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
{ {
Mutex::Lock l1(_config_l); Mutex::Lock l1(_config_l);
_IncomingConfigChunk *c = (_IncomingConfigChunk *)0; _IncomingConfigChunk *c = nullptr;
uint64_t chunkId = 0; uint64_t chunkId = 0;
unsigned long totalLength,chunkIndex; unsigned long totalLength,chunkIndex;
if (ptr < chunk.size()) { if (ptr < chunk.size()) {
const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0); const bool fastPropagate = ((chunk[ptr++] & 0x01U) != 0);
configUpdateId = chunk.at<uint64_t>(ptr); ptr += 8; configUpdateId = chunk.at<uint64_t>(ptr); ptr += 8;
totalLength = chunk.at<uint32_t>(ptr); ptr += 4; totalLength = chunk.at<uint32_t>(ptr); ptr += 4;
chunkIndex = chunk.at<uint32_t>(ptr); ptr += 4; chunkIndex = chunk.at<uint32_t>(ptr); ptr += 4;
@ -906,8 +913,8 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
// New properly verified chunks can be flooded "virally" through the network // New properly verified chunks can be flooded "virally" through the network
if (fastPropagate) { if (fastPropagate) {
Mutex::Lock l2(_memberships_l); Mutex::Lock l2(_memberships_l);
Address *a = (Address *)0; Address *a = nullptr;
Membership *m = (Membership *)0; Membership *m = nullptr;
Hashtable<Address,Membership>::Iterator i(_memberships); Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) { while (i.next(a,m)) {
if ((*a != source)&&(*a != controller())) { if ((*a != source)&&(*a != controller())) {
@ -1102,7 +1109,31 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
} }
} }
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev) Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com)
{
if (com.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[com.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,com);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap)
{
if (cap.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[cap.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,cap);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag)
{
if (tag.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[tag.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,tag);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Revocation &rev)
{ {
if (rev.networkId() != _id) if (rev.networkId() != _id)
return Membership::ADD_REJECTED; return Membership::ADD_REJECTED;
@ -1110,14 +1141,14 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address
Mutex::Lock l1(_memberships_l); Mutex::Lock l1(_memberships_l);
Membership &m = _memberships[rev.target()]; Membership &m = _memberships[rev.target()];
const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,rev); const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,sourcePeerIdentity,_config,rev);
if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) {
Address *a = (Address *)0; Address *a = nullptr;
Membership *m = (Membership *)0; Membership *m = nullptr;
Hashtable<Address,Membership>::Iterator i(_memberships); Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) { while (i.next(a,m)) {
if ((*a != sentFrom)&&(*a != rev.signer())) { if ((*a != sourcePeerIdentity.address())&&(*a != rev.signer())) {
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
outp.append((uint8_t)0x00); // no COM outp.append((uint8_t)0x00); // no COM
outp.append((uint16_t)0); // no capabilities outp.append((uint16_t)0); // no capabilities
@ -1133,15 +1164,44 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address
return result; return result;
} }
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo)
{
if (coo.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[coo.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,coo);
}
void Network::pushCredentialsNow(void *tPtr,const Address &to,const int64_t now)
{
Mutex::Lock _l(_memberships_l);
_memberships[to].pushCredentials(RR,tPtr,now,to,_config);
}
void Network::destroy()
{
_memberships_l.lock();
_config_l.lock();
_destroyed = true;
_config_l.unlock();
_memberships_l.unlock();
}
void Network::externalConfig(ZT_VirtualNetworkConfig *ec) const
{
Mutex::Lock _l(_config_l);
_externalConfig(ec);
}
void Network::_requestConfiguration(void *tPtr) void Network::_requestConfiguration(void *tPtr)
{ {
if (_destroyed) if (_destroyed)
return; return;
if ((_id >> 56) == 0xff) { if ((_id >> 56U) == 0xff) {
if ((_id & 0xffffff) == 0) { if ((_id & 0xffffffU) == 0) {
const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff); const uint16_t startPortRange = (uint16_t)((_id >> 40U) & 0xffff);
const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff); const uint16_t endPortRange = (uint16_t)((_id >> 24U) & 0xffff);
if (endPortRange >= startPortRange) { if (endPortRange >= startPortRange) {
ScopedPtr<NetworkConfig> nconf(new NetworkConfig()); ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
@ -1158,7 +1218,7 @@ void Network::_requestConfiguration(void *tPtr)
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt()); nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
// Drop everything but IPv6 // Drop everything but IPv6
nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80; // NOT nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80U; // NOT
nconf->rules[0].v.etherType = 0x86dd; // IPv6 nconf->rules[0].v.etherType = 0x86dd; // IPv6
nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP;
@ -1170,7 +1230,7 @@ void Network::_requestConfiguration(void *tPtr)
// Allow destination ports within range // Allow destination ports within range
nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL;
nconf->rules[4].v.ipProtocol = 0x11; // UDP nconf->rules[4].v.ipProtocol = 0x11; // UDP
nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40; // OR nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40U; // OR
nconf->rules[5].v.ipProtocol = 0x06; // TCP nconf->rules[5].v.ipProtocol = 0x06; // TCP
nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE;
nconf->rules[6].v.port[0] = startPortRange; nconf->rules[6].v.port[0] = startPortRange;
@ -1178,7 +1238,7 @@ void Network::_requestConfiguration(void *tPtr)
nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
// Allow non-SYN TCP packets to permit non-connection-initiating traffic // Allow non-SYN TCP packets to permit non-connection-initiating traffic
nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80; // NOT nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80U; // NOT
nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN;
nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
@ -1208,16 +1268,16 @@ void Network::_requestConfiguration(void *tPtr)
} else { } else {
this->setNotFound(); this->setNotFound();
} }
} else if ((_id & 0xff) == 0x01) { } else if ((_id & 0xffU) == 0x01) {
// ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication // ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication
const uint64_t myAddress = RR->identity.address().toInt(); const uint64_t myAddress = RR->identity.address().toInt();
const uint64_t networkHub = (_id >> 8) & 0xffffffffffULL; const uint64_t networkHub = (_id >> 8U) & 0xffffffffffULL;
uint8_t ipv4[4]; uint8_t ipv4[4];
ipv4[0] = (uint8_t)((_id >> 48) & 0xff); ipv4[0] = (uint8_t)(_id >> 48U);
ipv4[1] = (uint8_t)((myAddress >> 16) & 0xff); ipv4[1] = (uint8_t)(myAddress >> 16U);
ipv4[2] = (uint8_t)((myAddress >> 8) & 0xff); ipv4[2] = (uint8_t)(myAddress >> 8U);
ipv4[3] = (uint8_t)(myAddress & 0xff); ipv4[3] = (uint8_t)myAddress;
char v4ascii[24]; char v4ascii[24];
Utils::decimal(ipv4[0],v4ascii); Utils::decimal(ipv4[0],v4ascii);
@ -1282,7 +1342,7 @@ void Network::_requestConfiguration(void *tPtr)
rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0); rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0);
rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION); rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION);
RR->t->networkConfigRequestSent(tPtr,*this,ctrl); RR->t->networkConfigRequestSent(tPtr,_id);
if (ctrl == RR->identity.address()) { if (ctrl == RR->identity.address()) {
if (RR->localNetworkController) { if (RR->localNetworkController) {

View file

@ -58,7 +58,7 @@ public:
/** /**
* Compute primary controller device ID from network ID * Compute primary controller device ID from network ID
*/ */
static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); } static ZT_ALWAYS_INLINE Address controllerFor(uint64_t nwid) { return Address(nwid >> 24U); }
/** /**
* Construct a new network * Construct a new network
@ -76,14 +76,14 @@ public:
~Network(); ~Network();
inline uint64_t id() const { return _id; } ZT_ALWAYS_INLINE uint64_t id() const { return _id; }
inline Address controller() const { return Address(_id >> 24); } ZT_ALWAYS_INLINE Address controller() const { return Address(_id >> 24); }
inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } ZT_ALWAYS_INLINE bool multicastEnabled() const { return (_config.multicastLimit > 0); }
inline bool hasConfig() const { return (_config); } ZT_ALWAYS_INLINE bool hasConfig() const { return (_config); }
inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } ZT_ALWAYS_INLINE uint64_t lastConfigUpdate() const { return _lastConfigUpdate; }
inline ZT_VirtualNetworkStatus status() const { return _status(); } ZT_ALWAYS_INLINE ZT_VirtualNetworkStatus status() const { return _status(); }
inline const NetworkConfig &config() const { return _config; } ZT_ALWAYS_INLINE const NetworkConfig &config() const { return _config; }
inline const MAC &mac() const { return _mac; } ZT_ALWAYS_INLINE const MAC &mac() const { return _mac; }
/** /**
* Apply filters to an outgoing packet * Apply filters to an outgoing packet
@ -107,15 +107,15 @@ public:
*/ */
bool filterOutgoingPacket( bool filterOutgoingPacket(
void *tPtr, void *tPtr,
const bool noTee, bool noTee,
const Address &ztSource, const Address &ztSource,
const Address &ztDest, const Address &ztDest,
const MAC &macSource, const MAC &macSource,
const MAC &macDest, const MAC &macDest,
const uint8_t *frameData, const uint8_t *frameData,
const unsigned int frameLen, unsigned int frameLen,
const unsigned int etherType, unsigned int etherType,
const unsigned int vlanId, unsigned int vlanId,
uint8_t &qosBucket); uint8_t &qosBucket);
/** /**
@ -144,9 +144,9 @@ public:
const MAC &macSource, const MAC &macSource,
const MAC &macDest, const MAC &macDest,
const uint8_t *frameData, const uint8_t *frameData,
const unsigned int frameLen, unsigned int frameLen,
const unsigned int etherType, unsigned int etherType,
const unsigned int vlanId); unsigned int vlanId);
/** /**
* Check whether we are subscribed to a multicast group * Check whether we are subscribed to a multicast group
@ -155,7 +155,7 @@ public:
* @param includeBridgedGroups If true, also check groups we've learned via bridging * @param includeBridgedGroups If true, also check groups we've learned via bridging
* @return True if this network endpoint / peer is a member * @return True if this network endpoint / peer is a member
*/ */
inline bool subscribedToMulticastGroup(const MulticastGroup &mg,const bool includeBridgedGroups) const ZT_ALWAYS_INLINE bool subscribedToMulticastGroup(const MulticastGroup &mg,const bool includeBridgedGroups) const
{ {
Mutex::Lock l(_myMulticastGroups_l); Mutex::Lock l(_myMulticastGroups_l);
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
@ -171,28 +171,14 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param mg New multicast group * @param mg New multicast group
*/ */
inline void multicastSubscribe(void *tPtr,const MulticastGroup &mg) void multicastSubscribe(void *tPtr,const MulticastGroup &mg);
{
Mutex::Lock l(_myMulticastGroups_l);
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
Mutex::Lock l2(_memberships_l);
_announceMulticastGroups(tPtr,true);
}
}
/** /**
* Unsubscribe from a multicast group * Unsubscribe from a multicast group
* *
* @param mg Multicast group * @param mg Multicast group
*/ */
inline void multicastUnsubscribe(const MulticastGroup &mg) void multicastUnsubscribe(const MulticastGroup &mg);
{
Mutex::Lock l(_myMulticastGroups_l);
std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
if ( (i != _myMulticastGroups.end()) && (*i == mg) )
_myMulticastGroups.erase(i);
}
/** /**
* Handle an inbound network config chunk * Handle an inbound network config chunk
@ -208,7 +194,7 @@ public:
* @param ptr Index of chunk and related fields in packet * @param ptr Index of chunk and related fields in packet
* @return Update ID if update was fully assembled and accepted or 0 otherwise * @return Update ID if update was fully assembled and accepted or 0 otherwise
*/ */
uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr); uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr);
/** /**
* Set network configuration * Set network configuration
@ -227,12 +213,12 @@ public:
/** /**
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
*/ */
inline void setAccessDenied() { _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; } ZT_ALWAYS_INLINE void setAccessDenied() { _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; }
/** /**
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
*/ */
inline void setNotFound() { _netconfFailure = NETCONF_FAILURE_NOT_FOUND; } ZT_ALWAYS_INLINE void setNotFound() { _netconfFailure = NETCONF_FAILURE_NOT_FOUND; }
/** /**
* Determine whether this peer is permitted to communicate on this network * Determine whether this peer is permitted to communicate on this network
@ -245,7 +231,7 @@ public:
/** /**
* Do periodic cleanup and housekeeping tasks * Do periodic cleanup and housekeeping tasks
*/ */
void doPeriodicTasks(void *tPtr,const int64_t now); void doPeriodicTasks(void *tPtr,int64_t now);
/** /**
* Find the node on this network that has this MAC behind it (if any) * Find the node on this network that has this MAC behind it (if any)
@ -253,18 +239,13 @@ public:
* @param mac MAC address * @param mac MAC address
* @return ZeroTier address of bridge to this MAC * @return ZeroTier address of bridge to this MAC
*/ */
inline Address findBridgeTo(const MAC &mac) const ZT_ALWAYS_INLINE Address findBridgeTo(const MAC &mac) const
{ {
Mutex::Lock _l(_remoteBridgeRoutes_l); Mutex::Lock _l(_remoteBridgeRoutes_l);
const Address *const br = _remoteBridgeRoutes.get(mac); const Address *const br = _remoteBridgeRoutes.get(mac);
return ((br) ? *br : Address()); return ((br) ? *br : Address());
} }
/**
* @return True if QoS is in effect for this network
*/
inline bool qosEnabled() { return false; }
/** /**
* Set a bridge route * Set a bridge route
* *
@ -280,7 +261,7 @@ public:
* @param mg Multicast group * @param mg Multicast group
* @param now Current time * @param now Current time
*/ */
inline void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now) ZT_ALWAYS_INLINE void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now)
{ {
Mutex::Lock l(_myMulticastGroups_l); Mutex::Lock l(_myMulticastGroups_l);
_multicastGroupsBehindMe.set(mg,now); _multicastGroupsBehindMe.set(mg,now);
@ -289,51 +270,27 @@ public:
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com) Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com);
{
if (com.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[com.issuedTo()].addCredential(RR,tPtr,_config,com);
}
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap) Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap);
{
if (cap.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[cap.issuedTo()].addCredential(RR,tPtr,_config,cap);
}
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag) Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag);
{
if (tag.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[tag.issuedTo()].addCredential(RR,tPtr,_config,tag);
}
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev); Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Revocation &rev);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo) Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo);
{
if (coo.networkId() != _id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[coo.issuedTo()].addCredential(RR,tPtr,_config,coo);
}
/** /**
* Force push credentials (COM, etc.) to a peer now * Force push credentials (COM, etc.) to a peer now
@ -342,11 +299,7 @@ public:
* @param to Destination peer address * @param to Destination peer address
* @param now Current time * @param now Current time
*/ */
inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now) void pushCredentialsNow(void *tPtr,const Address &to,int64_t now);
{
Mutex::Lock _l(_memberships_l);
_memberships[to].pushCredentials(RR,tPtr,now,to,_config);
}
/** /**
* Push credentials if we haven't done so in a long time * Push credentials if we haven't done so in a long time
@ -355,7 +308,7 @@ public:
* @param to Destination peer address * @param to Destination peer address
* @param now Current time * @param now Current time
*/ */
inline void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now) ZT_ALWAYS_INLINE void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now)
{ {
const int64_t tout = std::min(_config.credentialTimeMaxDelta,(int64_t)ZT_PEER_ACTIVITY_TIMEOUT); const int64_t tout = std::min(_config.credentialTimeMaxDelta,(int64_t)ZT_PEER_ACTIVITY_TIMEOUT);
Mutex::Lock _l(_memberships_l); Mutex::Lock _l(_memberships_l);
@ -370,25 +323,14 @@ public:
* This sets the network to completely remove itself on delete. This also prevents the * This sets the network to completely remove itself on delete. This also prevents the
* call of the normal port shutdown event on delete. * call of the normal port shutdown event on delete.
*/ */
inline void destroy() void destroy();
{
_memberships_l.lock();
_config_l.lock();
_destroyed = true;
_config_l.unlock();
_memberships_l.unlock();
}
/** /**
* Get this network's config for export via the ZT core API * Get this network's config for export via the ZT core API
* *
* @param ec Buffer to fill with externally-visible network configuration * @param ec Buffer to fill with externally-visible network configuration
*/ */
inline void externalConfig(ZT_VirtualNetworkConfig *ec) const void externalConfig(ZT_VirtualNetworkConfig *ec) const;
{
Mutex::Lock _l(_config_l);
_externalConfig(ec);
}
/** /**
* Iterate through memberships * Iterate through memberships
@ -396,7 +338,7 @@ public:
* @param f Function of (const Address,const Membership) * @param f Function of (const Address,const Membership)
*/ */
template<typename F> template<typename F>
inline void eachMember(F f) ZT_ALWAYS_INLINE void eachMember(F f)
{ {
Mutex::Lock ml(_memberships_l); Mutex::Lock ml(_memberships_l);
Hashtable<Address,Membership>::Iterator i(_memberships); Hashtable<Address,Membership>::Iterator i(_memberships);
@ -411,13 +353,12 @@ public:
/** /**
* @return Externally usable pointer-to-pointer exported via the core API * @return Externally usable pointer-to-pointer exported via the core API
*/ */
inline void **userPtr() { return &_uPtr; } ZT_ALWAYS_INLINE void **userPtr() { return &_uPtr; }
private: private:
void _requestConfiguration(void *tPtr); void _requestConfiguration(void *tPtr);
ZT_VirtualNetworkStatus _status() const; ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer> &peer);
void _announceMulticastGroups(void *tPtr,bool force); void _announceMulticastGroups(void *tPtr,bool force);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups); void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
std::vector<MulticastGroup> _allMulticastGroups() const; std::vector<MulticastGroup> _allMulticastGroups() const;
@ -433,11 +374,11 @@ private:
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
NetworkConfig _config; NetworkConfig _config;
uint64_t _lastConfigUpdate; volatile uint64_t _lastConfigUpdate;
struct _IncomingConfigChunk struct _IncomingConfigChunk
{ {
inline _IncomingConfigChunk() : ts(0),updateId(0),haveChunks(0),haveBytes(0),data() {} ZT_ALWAYS_INLINE _IncomingConfigChunk() : ts(0),updateId(0),haveChunks(0),haveBytes(0),data() {}
uint64_t ts; uint64_t ts;
uint64_t updateId; uint64_t updateId;
uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];

View file

@ -33,10 +33,6 @@
namespace ZeroTier { namespace ZeroTier {
/****************************************************************************/
/* Public Node interface (C++, exposed via CAPI bindings) */
/****************************************************************************/
Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64_t now) : Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64_t now) :
_RR(this), _RR(this),
RR(&_RR), RR(&_RR),
@ -437,7 +433,7 @@ ZT_PeerList *Node::peers() const
p->address = (*pi)->address().toInt(); p->address = (*pi)->address().toInt();
identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted
p->identity = &identities[pl->peerCount]; p->identity = &identities[pl->peerCount];
(*pi)->identity().hash(p->identityHash,false); memcpy(p->identityHash,(*pi)->identity().hash(),sizeof(p->identityHash));
if ((*pi)->remoteVersionKnown()) { if ((*pi)->remoteVersionKnown()) {
p->versionMajor = (int)(*pi)->remoteVersionMajor(); p->versionMajor = (int)(*pi)->remoteVersionMajor();
p->versionMinor = (int)(*pi)->remoteVersionMinor(); p->versionMinor = (int)(*pi)->remoteVersionMinor();

View file

@ -264,7 +264,7 @@ public:
* @param remoteAddress Remote address * @param remoteAddress Remote address
* @return True if path should be used * @return True if path should be used
*/ */
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,const int64_t localSocket,const InetAddress &remoteAddress); bool shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,int64_t localSocket,const InetAddress &remoteAddress);
/** /**
* Query callback for a physical address for a peer * Query callback for a physical address for a peer

View file

@ -28,18 +28,15 @@
// //
#ifndef __GCC__ #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) #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) || defined(__INTEL_COMPILER) || defined(__clang__)
#define __GCC__ #define __GCC__
#endif #endif
#endif #endif
#if !defined(__GCC__) && !defined (__clang__) && !defined(__INTEL_COMPILER) #ifdef _MSC_VER
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
#pragma warning(disable : 4290) #pragma warning(disable : 4290)
#pragma warning(disable : 4996) #pragma warning(disable : 4996)
#pragma warning(disable : 4101) #pragma warning(disable : 4101)
#else
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
#endif #endif
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
@ -98,8 +95,8 @@
// Avoid unaligned type casts on all but x86/x64 architecture. // Avoid unaligned type casts on all but x86/x64 architecture.
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386))) #if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#ifndef ZT_NO_TYPE_PUNNING #ifndef ZT_NO_UNALIGNED_ACCESS
#define ZT_NO_TYPE_PUNNING #define ZT_NO_UNALIGNED_ACCESS
#endif #endif
#endif #endif

View file

@ -66,7 +66,7 @@ bool Packet::dearmor(const void *key)
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
uint64_t mac[2]; uint64_t mac[2];
poly1305(mac,payload,payloadLen,macKey); poly1305(mac,payload,payloadLen,macKey);
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
return false; return false;
#else #else

View file

@ -111,7 +111,14 @@ public:
* *
* @param now Current time * @param now Current time
*/ */
ZT_ALWAYS_INLINE bool alive(const int64_t now) const { return ((now - _lastIn) < ZT_PATH_ACTIVITY_TIMEOUT); } ZT_ALWAYS_INLINE bool alive(const int64_t now) const { return ((now - _lastIn) < ZT_PATH_ALIVE_TIMEOUT); }
/**
* Check if path is considered active
*
* @param now Current time
*/
ZT_ALWAYS_INLINE bool active(const int64_t now) const { return ((now - _lastIn) < ZT_PATH_ACTIVITY_TIMEOUT); }
/** /**
* @return Physical address * @return Physical address

View file

@ -92,9 +92,7 @@ void Peer::received(
if ((_paths[i]->address().ss_family == path->address().ss_family) && if ((_paths[i]->address().ss_family == path->address().ss_family) &&
(_paths[i]->localSocket() == path->localSocket()) && // TODO: should be localInterface when multipath is integrated (_paths[i]->localSocket() == path->localSocket()) && // TODO: should be localInterface when multipath is integrated
(_paths[i]->address().ipsEqual2(path->address()))) { (_paths[i]->address().ipsEqual2(path->address()))) {
// If this is another path to the same place, swap it out as the // Replace older path if everything is the same except the port number.
// one we just received from may replace an old one but don't
// learn it as a new path.
_paths[i] = path; _paths[i] = path;
goto path_check_done; goto path_check_done;
} else { } else {
@ -130,7 +128,7 @@ path_check_done:
_lastAttemptedP2PInit = now; _lastAttemptedP2PInit = now;
InetAddress addr; InetAddress addr;
if (_bootstrap.type() == Endpoint::INETADDR) if ((_bootstrap.type() == Endpoint::INETADDR_V4)||(_bootstrap.type() == Endpoint::INETADDR_V6))
sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now); sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now);
if (RR->node->externalPathLookup(tPtr,_id,-1,addr)) { if (RR->node->externalPathLookup(tPtr,_id,-1,addr)) {
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,-1,addr)) if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,-1,addr))
@ -256,7 +254,7 @@ void Peer::ping(void *tPtr,int64_t now,const bool pingAllAddressTypes)
return; return;
} }
if (_bootstrap.type() == Endpoint::INETADDR) if ((_bootstrap.type() == Endpoint::INETADDR_V4)||(_bootstrap.type() == Endpoint::INETADDR_V6))
sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now); sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now);
SharedPtr<Peer> r(RR->topology->root()); SharedPtr<Peer> r(RR->topology->root());

View file

@ -70,7 +70,7 @@ typedef struct poly1305_state_internal_t {
unsigned char final; unsigned char final;
} poly1305_state_internal_t; } poly1305_state_internal_t;
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) #if defined(ZT_NO_UNALIGNED_ACCESS) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline unsigned long long U8TO64(const unsigned char *p) static inline unsigned long long U8TO64(const unsigned char *p)
{ {
return return
@ -87,7 +87,7 @@ static inline unsigned long long U8TO64(const unsigned char *p)
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p)) #define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p))
#endif #endif
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) #if defined(ZT_NO_UNALIGNED_ACCESS) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline void U64TO8(unsigned char *p, unsigned long long v) static inline void U64TO8(unsigned char *p, unsigned long long v)
{ {
p[0] = (v ) & 0xff; p[0] = (v ) & 0xff;

View file

@ -44,7 +44,7 @@ class Revocation : public Credential
friend class Credential; friend class Credential;
public: public:
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; } static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_REVOCATION; }
ZT_ALWAYS_INLINE Revocation() : ZT_ALWAYS_INLINE Revocation() :
_id(0), _id(0),
@ -54,7 +54,7 @@ public:
_flags(0), _flags(0),
_target(), _target(),
_signedBy(), _signedBy(),
_type(Credential::CREDENTIAL_TYPE_NULL), _type(ZT_CREDENTIAL_TYPE_NULL),
_signatureLength(0) _signatureLength(0)
{ {
} }
@ -68,7 +68,7 @@ public:
* @param tgt Target node whose credential(s) are being revoked * @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked * @param ct Credential type being revoked
*/ */
ZT_ALWAYS_INLINE Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) : ZT_ALWAYS_INLINE Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const ZT_CredentialType ct) :
_id(i), _id(i),
_credentialId(cid), _credentialId(cid),
_networkId(nwid), _networkId(nwid),
@ -87,7 +87,7 @@ public:
ZT_ALWAYS_INLINE int64_t threshold() const { return _threshold; } ZT_ALWAYS_INLINE int64_t threshold() const { return _threshold; }
ZT_ALWAYS_INLINE const Address &target() const { return _target; } ZT_ALWAYS_INLINE const Address &target() const { return _target; }
ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; } ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
ZT_ALWAYS_INLINE Credential::Type type() const { return _type; } ZT_ALWAYS_INLINE ZT_CredentialType typeBeingRevoked() const { return _type; }
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; } ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; } ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
ZT_ALWAYS_INLINE bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } ZT_ALWAYS_INLINE bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
@ -160,7 +160,7 @@ public:
_flags = b.template at<uint64_t>(p); p += 8; _flags = b.template at<uint64_t>(p); p += 8;
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; _target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_type = (Credential::Type)b[p++]; _type = (ZT_CredentialType)b[p++];
if (b[p++] == 1) { if (b[p++] == 1) {
_signatureLength = b.template at<uint16_t>(p); _signatureLength = b.template at<uint16_t>(p);
@ -186,7 +186,7 @@ private:
uint64_t _flags; uint64_t _flags;
Address _target; Address _target;
Address _signedBy; Address _signedBy;
Credential::Type _type; ZT_CredentialType _type;
unsigned int _signatureLength; unsigned int _signatureLength;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE]; uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
}; };

View file

@ -235,64 +235,6 @@ public:
} }
return curr_cnt ? subtotal / (float)curr_cnt : 0; return curr_cnt ? subtotal / (float)curr_cnt : 0;
} }
/**
* @return The sample standard deviation of element values
*/
inline float stddev() { return sqrt(variance()); }
/**
* @return The variance of element values
*/
inline float variance()
{
size_t iterator = begin;
float cached_mean = mean();
size_t curr_cnt = count();
T sum_of_squared_deviations = 0;
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
float deviation = (buf[i] - cached_mean);
sum_of_squared_deviations += (T)(deviation*deviation);
}
float variance = (float)sum_of_squared_deviations / (float)(S - 1);
return variance;
}
/**
* @return The number of elements of zero value
*/
inline size_t zeroCount()
{
size_t iterator = begin;
size_t zeros = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == 0) {
zeros++;
}
}
return zeros;
}
/**
* @param value Value to match against in buffer
* @return The number of values held in the ring buffer which match a given value
*/
inline size_t countValue(T value)
{
size_t iterator = begin;
size_t cnt = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == value) {
cnt++;
}
}
return cnt;
}
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -218,7 +218,7 @@ void HMACSHA384(const uint8_t key[32],const void *msg,const unsigned int msglen,
uint64_t kInPadded[16]; // input padded key uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg) uint64_t outer[22]; // output padded key | H(input padded key | msg)
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
for(int i=0;i<32;++i) ((uint8_t *)kInPadded)[i] = key[i] ^ 0x36; for(int i=0;i<32;++i) ((uint8_t *)kInPadded)[i] = key[i] ^ 0x36;
for(int i=4;i<16;++i) kInPadded[i] = 0x3636363636363636ULL; for(int i=4;i<16;++i) kInPadded[i] = 0x3636363636363636ULL;
for(int i=0;i<32;++i) ((uint8_t *)outer)[i] = key[i] ^ 0x5c; for(int i=0;i<32;++i) ((uint8_t *)outer)[i] = key[i] ^ 0x5c;

View file

@ -32,12 +32,6 @@
#define ZT_HMACSHA384_LEN 48 #define ZT_HMACSHA384_LEN 48
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_HMAC_SHA_384 'H'
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K1 '1'
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K2 '2'
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K3 '3'
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K4 '4'
namespace ZeroTier { namespace ZeroTier {
#ifdef __APPLE__ #ifdef __APPLE__
@ -108,7 +102,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u
* @param msglen Length of message * @param msglen Length of message
* @param mac Buffer to fill with result * @param mac Buffer to fill with result
*/ */
void HMACSHA384(const uint8_t key[32],const void *msg,const unsigned int msglen,uint8_t mac[48]); void HMACSHA384(const uint8_t key[32],const void *msg,unsigned int msglen,uint8_t mac[48]);
/** /**
* Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF * Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF
@ -119,7 +113,7 @@ void HMACSHA384(const uint8_t key[32],const void *msg,const unsigned int msglen,
* @param iter Key iteration for generation of multiple keys for the same label/context * @param iter Key iteration for generation of multiple keys for the same label/context
* @param out Output to receive derived key * @param out Output to receive derived key
*/ */
void KBKDFHMACSHA384(const uint8_t key[32],const char label,const char context,const uint32_t iter,uint8_t out[32]); void KBKDFHMACSHA384(const uint8_t key[32],char label,char context,uint32_t iter,uint8_t out[32]);
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -19,7 +19,7 @@
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
// Slower version that does not use type punning // Slower version that does not use type punning
#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) #define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) )
static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); }
@ -27,7 +27,7 @@ static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (ui
// Fast version that just does 32-bit load/store // Fast version that just does 32-bit load/store
#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p)))) #define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p))))
#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v) #define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v)
#endif // ZT_NO_TYPE_PUNNING #endif // ZT_NO_UNALIGNED_ACCESS
#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?) #else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?)

View file

@ -25,7 +25,7 @@
#include "Trace.hpp" #include "Trace.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup // Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 300000
namespace ZeroTier { namespace ZeroTier {
@ -53,11 +53,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
{ {
} }
SelfAwareness::~SelfAwareness() void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now)
{
}
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now)
{ {
const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
@ -65,12 +61,10 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
return; return;
Mutex::Lock l(_phy_l); Mutex::Lock l(_phy_l);
PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)]; PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter.address(),receivedOnLocalSocket,reporterPhysicalAddress,scope)];
if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
// Changes to external surface reported by trusted peers causes path reset in this scope // Changes to external surface reported by trusted peers causes path reset in this scope
RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope);
entry.mySurface = myPhysicalAddress; entry.mySurface = myPhysicalAddress;
entry.ts = now; entry.ts = now;
entry.trusted = trusted; entry.trusted = trusted;
@ -80,10 +74,10 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
// Don't use 'entry' after this since hash table gets modified. // Don't use 'entry' after this since hash table gets modified.
{ {
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceKey *k = nullptr;
PhySurfaceEntry *e = (PhySurfaceEntry *)0; PhySurfaceEntry *e = nullptr;
while (i.next(k,e)) { while (i.next(k,e)) {
if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) if ((k->scope == scope)&&(k->reporterPhysicalAddress != reporterPhysicalAddress))
_phy.erase(*k); _phy.erase(*k);
} }
} }
@ -91,6 +85,8 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
// Reset all paths within this scope and address family // Reset all paths within this scope and address family
_ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); _ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope &>(rset); RR->topology->eachPeer<_ResetWithinScope &>(rset);
RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,entry.mySurface,myPhysicalAddress,scope);
} else { } else {
// Otherwise just update DB to use to determine external surface info // Otherwise just update DB to use to determine external surface info
entry.mySurface = myPhysicalAddress; entry.mySurface = myPhysicalAddress;
@ -111,35 +107,6 @@ void SelfAwareness::clean(int64_t now)
} }
} }
bool SelfAwareness::symmetricNat(const int64_t now) const
{
Hashtable< InetAddress,std::pair< std::set<int>,std::set<int64_t> > > ipToPortsAndLocalSockets(16);
{
Mutex::Lock l(_phy_l);
Hashtable<PhySurfaceKey,PhySurfaceEntry>::Iterator i(const_cast<SelfAwareness *>(this)->_phy);
PhySurfaceKey *k = nullptr;
PhySurfaceEntry *e = nullptr;
while (i.next(k,e)) {
if ((now - e->ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) {
std::pair< std::set<int>,std::set<int64_t> > &ii = ipToPortsAndLocalSockets[e->mySurface.ipOnly()];
ii.first.insert(e->mySurface.port());
if (k->receivedOnLocalSocket != -1)
ii.second.insert(k->receivedOnLocalSocket);
}
}
}
Hashtable< InetAddress,std::pair< std::set<int>,std::set<int64_t> > >::Iterator i(ipToPortsAndLocalSockets);
InetAddress *k = nullptr;
std::pair< std::set<int>,std::set<int64_t> > *v = nullptr;
while (i.next(k,v)) {
if (v->first.size() > v->second.size()) // more external ports than local sockets for a given external IP
return true;
}
return false;
}
std::multimap<unsigned long,InetAddress> SelfAwareness::externalAddresses(const int64_t now) const std::multimap<unsigned long,InetAddress> SelfAwareness::externalAddresses(const int64_t now) const
{ {
std::multimap<unsigned long,InetAddress> r; std::multimap<unsigned long,InetAddress> r;

View file

@ -24,6 +24,7 @@
namespace ZeroTier { namespace ZeroTier {
class Identity;
class RuntimeEnvironment; class RuntimeEnvironment;
/** /**
@ -35,19 +36,18 @@ class SelfAwareness
{ {
public: public:
explicit SelfAwareness(const RuntimeEnvironment *renv); explicit SelfAwareness(const RuntimeEnvironment *renv);
~SelfAwareness();
/** /**
* Called when a remote peer informs us of our external network address * Called when a remote peer informs us of our external network address
* *
* @param reporter ZeroTier address of reporting peer * @param reporter Identity of reporting peer
* @param receivedOnLocalAddress Local address on which report was received * @param receivedOnLocalAddress Local address on which report was received
* @param reporterPhysicalAddress Physical address that reporting peer seems to have * @param reporterPhysicalAddress Physical address that reporting peer seems to have
* @param myPhysicalAddress Physical address that peer says we have * @param myPhysicalAddress Physical address that peer says we have
* @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param trusted True if this peer is trusted as an authority to inform us of external address changes
* @param now Current time * @param now Current time
*/ */
void iam(void *tPtr,const Address &reporter,int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now); void iam(void *tPtr,const Identity &reporter,int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now);
/** /**
* Clean up database periodically * Clean up database periodically
@ -56,14 +56,6 @@ public:
*/ */
void clean(int64_t now); void clean(int64_t now);
/**
* Check whether this node appears to be behind a symmetric NAT
*
* @param now Current time
* @return True if it looks like we're behind a symmetric NAT
*/
bool symmetricNat(int64_t now) const;
/** /**
* Get external address consensus, which is the statistical "mode" of external addresses. * Get external address consensus, which is the statistical "mode" of external addresses.
* *

View file

@ -211,7 +211,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
bool fromBridged; bool fromBridged;
if ((fromBridged = (from != network->mac()))) { if ((fromBridged = (from != network->mac()))) {
if (!network->config().permitsBridging(RR->identity.address())) { if (!network->config().permitsBridging(RR->identity.address())) {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"not a bridge"); RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL);
return; return;
} }
} }
@ -235,7 +235,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0));
} else if (!network->config().enableBroadcast()) { } else if (!network->config().enableBroadcast()) {
// Don't transmit broadcasts if this network doesn't want them // Don't transmit broadcasts if this network doesn't want them
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"broadcast disabled"); RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED);
return; return;
} }
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) {
@ -323,7 +323,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
// Check this after NDP emulation, since that has to be allowed in exactly this case // Check this after NDP emulation, since that has to be allowed in exactly this case
if (network->config().multicastLimit == 0) { if (network->config().multicastLimit == 0) {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"multicast disabled"); RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED);
return; return;
} }
@ -336,7 +336,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
// First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates.
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) { if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
return; return;
} }
@ -365,7 +365,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
SharedPtr<Peer> toPeer(RR->topology->get(tPtr,toZT)); SharedPtr<Peer> toPeer(RR->topology->get(tPtr,toZT));
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) { if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
return; return;
} }
@ -392,7 +392,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
// for each ZT destination are also done below. This is the same rationale // for each ZT destination are also done below. This is the same rationale
// and design as for multicast. // and design as for multicast.
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) { if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
return; return;
} }
@ -442,7 +442,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
outp.append((uint16_t)etherType); outp.append((uint16_t)etherType);
outp.append(data,len); outp.append(data,len);
} else { } else {
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION);
} }
} }
} }

View file

@ -52,7 +52,7 @@ class Tag : public Credential
friend class Credential; friend class Credential;
public: public:
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; } static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_TAG; }
ZT_ALWAYS_INLINE Tag() : ZT_ALWAYS_INLINE Tag() :
_id(0), _id(0),

282
node/Trace.cpp Normal file
View file

@ -0,0 +1,282 @@
/*
* Copyright (c)2013-2020 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: 2024-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 "Trace.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "Peer.hpp"
// Macro to avoid calling hton() on values known at compile time.
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
#else
#define CONST_TO_BE_UINT16(x) ((uint16_t)(x))
#endif
namespace ZeroTier {
Trace::Trace(const RuntimeEnvironment *renv) :
RR(renv),
_vl1(false),
_vl2(false),
_vl2Filter(false),
_vl2Multicast(false),
_eventBufSize(0)
{
}
void Trace::_resettingPathsInScope(
void *const tPtr,
const Identity &reporter,
const InetAddress &from,
const InetAddress &oldExternal,
const InetAddress &newExternal,
const InetAddress::IpScope scope)
{
ZT_TraceEvent_VL1_RESETTING_PATHS_IN_SCOPE ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE);
from.forTrace(ev.from);
oldExternal.forTrace(ev.oldExternal);
newExternal.forTrace(ev.newExternal);
ev.scope = (uint8_t)scope;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_tryingNewPath(
void *const tPtr,
const Identity &trying,
const InetAddress &physicalAddress,
const InetAddress &triggerAddress,
uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb,
uint64_t triggeredByAddress,
const uint8_t *triggeredByIdentityHash,
ZT_TraceTryingNewPathReason reason)
{
ZT_TraceEvent_VL1_TRYING_NEW_PATH ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH);
ev.address = Utils::hton(trying.address().toInt());
memcpy(ev.identityHash,trying.hash(),48);
physicalAddress.forTrace(ev.physicalAddress);
triggerAddress.forTrace(ev.triggerAddress);
ev.triggeringPacketId = Utils::hton(triggeringPacketId);
ev.triggeringPacketVerb = triggeringPacketVerb;
ev.triggeredByAddress = Utils::hton(triggeredByAddress);
if (triggeredByIdentityHash)
memcpy(ev.triggeredByIdentityHash,triggeredByIdentityHash,48);
else memset(ev.triggeredByIdentityHash,0,48);
ev.reason = (uint8_t)reason;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_learnedNewPath(
void *const tPtr,
uint64_t packetId,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
const InetAddress &replaced)
{
ZT_TraceEvent_VL1_LEARNED_NEW_PATH ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_LEARNED_NEW_PATH);
ev.packetId = Utils::hton(packetId);
ev.address = Utils::hton(peerIdentity.address().toInt());
memcpy(ev.identityHash,peerIdentity.hash(),48);
physicalAddress.forTrace(ev.physicalAddress);
replaced.forTrace(ev.replaced);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_incomingPacketDropped(
void *const tPtr,
uint64_t packetId,
uint64_t networkId,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
uint8_t verb,
ZT_TracePacketDropReason reason)
{
ZT_TraceEvent_VL1_INCOMING_PACKET_DROPPED ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_INCOMING_PACKET_DROPPED);
ev.packetId = Utils::hton(packetId);
ev.networkId = Utils::hton(networkId);
ev.address = Utils::hton(peerIdentity.address().toInt());
memcpy(ev.identityHash,peerIdentity.hash(),48);
physicalAddress.forTrace(ev.physicalAddress);
ev.hops = hops;
ev.verb = verb;
ev.reason = (uint8_t)reason;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_outgoingNetworkFrameDropped(
void *const tPtr,
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
uint16_t etherType,
uint16_t frameLength,
const uint8_t *frameData,
ZT_TraceFrameDropReason reason)
{
ZT_TraceEvent_VL2_OUTGOING_FRAME_DROPPED ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED);
ev.networkId = Utils::hton(networkId);
ev.sourceMac = Utils::hton(sourceMac.toInt());
ev.destMac = Utils::hton(destMac.toInt());
ev.etherType = Utils::hton(etherType);
ev.frameLength = Utils::hton(frameLength);
if (frameData) {
unsigned int l = frameLength;
if (l > sizeof(ev.frameHead))
l = sizeof(ev.frameHead);
memcpy(ev.frameHead,frameData,l);
memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
}
ev.reason = (uint8_t)reason;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_incomingNetworkFrameDropped(
void *const tPtr,
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
uint16_t frameLength,
const uint8_t *frameData,
uint8_t verb,
bool credentialRequestSent,
ZT_TraceFrameDropReason reason)
{
ZT_TraceEvent_VL2_INCOMING_FRAME_DROPPED ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_INCOMING_FRAME_DROPPED);
ev.networkId = Utils::hton(networkId);
ev.sourceMac = Utils::hton(sourceMac.toInt());
ev.destMac = Utils::hton(destMac.toInt());
ev.address = Utils::hton(peerIdentity.address().toInt());
physicalAddress.forTrace(ev.physicalAddress);
ev.hops = hops;
ev.frameLength = Utils::hton(frameLength);
if (frameData) {
unsigned int l = frameLength;
if (l > sizeof(ev.frameHead))
l = sizeof(ev.frameHead);
memcpy(ev.frameHead,frameData,l);
memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
}
ev.verb = verb;
ev.credentialRequestSent = (uint8_t)credentialRequestSent;
ev.reason = (uint8_t)reason;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_networkConfigRequestSent(
void *const tPtr,
uint64_t networkId)
{
ZT_TraceEvent_VL2_NETWORK_CONFIG_REQUESTED ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED);
ev.networkId = Utils::hton(networkId);
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_networkFilter(
void *const tPtr,
uint64_t networkId,
const uint8_t primaryRuleSetLog[512],
const uint8_t matchingCapabilityRuleSetLog[512],
uint32_t matchingCapabilityId,
int64_t matchingCapabilityTimestamp,
const Address &source,
const Address &dest,
const MAC &sourceMac,
const MAC &destMac,
uint16_t frameLength,
const uint8_t *frameData,
uint16_t etherType,
uint16_t vlanId,
bool noTee,
bool inbound,
int accept)
{
ZT_TraceEvent_VL2_NETWORK_FILTER ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER);
ev.networkId = Utils::hton(networkId);
memcpy(ev.primaryRuleSetLog,primaryRuleSetLog,sizeof(ev.primaryRuleSetLog));
if (matchingCapabilityRuleSetLog)
memcpy(ev.matchingCapabilityRuleSetLog,matchingCapabilityRuleSetLog,sizeof(ev.matchingCapabilityRuleSetLog));
else memset(ev.matchingCapabilityRuleSetLog,0,sizeof(ev.matchingCapabilityRuleSetLog));
ev.matchingCapabilityId = Utils::hton(matchingCapabilityId);
ev.matchingCapabilityTimestamp = Utils::hton(matchingCapabilityTimestamp);
ev.source = Utils::hton(source.toInt());
ev.dest = Utils::hton(dest.toInt());
ev.sourceMac = Utils::hton(sourceMac.toInt());
ev.destMac = Utils::hton(destMac.toInt());
ev.frameLength = Utils::hton(frameLength);
if (frameData) {
unsigned int l = frameLength;
if (l > sizeof(ev.frameHead))
l = sizeof(ev.frameHead);
memcpy(ev.frameHead,frameData,l);
memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
}
ev.etherType = Utils::hton(etherType);
ev.vlanId = Utils::hton(vlanId);
ev.noTee = (uint8_t)noTee;
ev.inbound = (uint8_t)inbound;
ev.accept = (int8_t)accept;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
void Trace::_credentialRejected(
void *const tPtr,
uint64_t networkId,
const Address &address,
uint32_t credentialId,
int64_t credentialTimestamp,
uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason)
{
ZT_TraceEvent_VL2_CREDENTIAL_REJECTED ev;
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER);
ev.networkId = Utils::hton(networkId);
ev.address = Utils::hton(address.toInt());
ev.credentialId = Utils::hton(credentialId);
ev.credentialTimestamp = Utils::hton(credentialTimestamp);
ev.credentialType = credentialType;
ev.reason = (uint8_t)reason;
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
}
} // namespace ZeroTier

View file

@ -14,29 +14,26 @@
#ifndef ZT_TRACE_HPP #ifndef ZT_TRACE_HPP
#define ZT_TRACE_HPP #define ZT_TRACE_HPP
#include <cstdio>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <vector>
#include "Constants.hpp" #include "Constants.hpp"
#include "SharedPtr.hpp" #include "SharedPtr.hpp"
#include "Packet.hpp"
#include "Credential.hpp"
#include "InetAddress.hpp"
#include "Dictionary.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "Hashtable.hpp" #include "Packet.hpp"
#include "InetAddress.hpp"
#include "Address.hpp"
#include "MAC.hpp"
namespace ZeroTier { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;
class Address;
class Identity; class Identity;
class Peer; class Peer;
class Path; class Path;
class Network; class Network;
class MAC;
class CertificateOfMembership; class CertificateOfMembership;
class CertificateOfOwnership; class CertificateOfOwnership;
class Revocation; class Revocation;
@ -50,117 +47,265 @@ struct NetworkConfig;
class Trace class Trace
{ {
public: public:
class RuleResultLog struct RuleResultLog
{ {
public: uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields
ZT_ALWAYS_INLINE RuleResultLog() { this->clear(); }
ZT_ALWAYS_INLINE void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches) { _l[rn >> 1U] |= ( ((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U) ) << ((rn & 1U) << 2U); } ZT_ALWAYS_INLINE void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches)
ZT_ALWAYS_INLINE void logSkipped(const unsigned int rn,const uint8_t thisSetMatches) { _l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U); } {
ZT_ALWAYS_INLINE void clear() { memset(_l,0,sizeof(_l)); } l[rn >> 1U] |= ( ((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U) ) << ((rn & 1U) << 2U);
}
ZT_ALWAYS_INLINE const uint8_t *data() const { return _l; } ZT_ALWAYS_INLINE void logSkipped(const unsigned int rn,const uint8_t thisSetMatches)
ZT_ALWAYS_INLINE unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); } {
l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U);
private: }
uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; ZT_ALWAYS_INLINE void clear()
{
memset(l,0,sizeof(l));
}
}; };
inline Trace(const RuntimeEnvironment *renv) explicit Trace(const RuntimeEnvironment *renv);
{
}
inline void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) ZT_ALWAYS_INLINE void resettingPathsInScope(
{
}
inline void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb)
{
}
inline void peerLinkNowRedundant(void *const tPtr,Peer &peer)
{
}
inline void peerLinkNoLongerRedundant(void *const tPtr,Peer &peer)
{
}
inline void peerLinkAggregateStatistics(void *const tPtr,Peer &peer)
{
}
inline void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath,const uint64_t packetId)
{
}
inline void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason)
{
}
inline void incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason)
{
}
inline void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const char *reason)
{
}
inline void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason)
{
}
inline void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested)
{
}
inline void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason)
{
}
inline void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller)
{
}
inline void networkFilter(
void *const tPtr, void *const tPtr,
const Network &network, const Identity &reporter,
const RuleResultLog &primaryRuleSetLog, const InetAddress &from,
const RuleResultLog *const matchingCapabilityRuleSetLog, const InetAddress &oldExternal,
const Capability *const matchingCapability, const InetAddress &newExternal,
const Address &ztSource, const InetAddress::IpScope scope)
const Address &ztDest,
const MAC &macSource,
const MAC &macDest,
const uint8_t *const frameData,
const unsigned int frameLen,
const unsigned int etherType,
const unsigned int vlanId,
const bool noTee,
const bool inbound,
const int accept)
{ {
if (_vl1) _resettingPathsInScope(tPtr,reporter,from,oldExternal,newExternal,scope);
} }
inline void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) ZT_ALWAYS_INLINE void tryingNewPath(
void *const tPtr,
const Identity &trying,
const InetAddress &physicalAddress,
const InetAddress &triggerAddress,
uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb,
uint64_t triggeredByAddress,
const uint8_t *triggeredByIdentityHash,
ZT_TraceTryingNewPathReason reason)
{ {
if (_vl1) _tryingNewPath(tPtr,trying,physicalAddress,triggerAddress,triggeringPacketId,triggeringPacketVerb,triggeredByAddress,triggeredByIdentityHash,reason);
} }
inline void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason) ZT_ALWAYS_INLINE void learnedNewPath(
void *const tPtr,
uint64_t packetId,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
const InetAddress &replaced)
{ {
if (_vl1) _learnedNewPath(tPtr,packetId,peerIdentity,physicalAddress,replaced);
} }
inline void credentialRejected(void *const tPtr,const Capability &c,const char *reason) ZT_ALWAYS_INLINE void incomingPacketDropped(
void *const tPtr,
uint64_t packetId,
uint64_t networkId,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
uint8_t verb,
const ZT_TracePacketDropReason reason)
{ {
if (_vl1) _incomingPacketDropped(tPtr,packetId,networkId,peerIdentity,physicalAddress,hops,verb,reason);
} }
inline void credentialRejected(void *const tPtr,const Tag &c,const char *reason) ZT_ALWAYS_INLINE void outgoingNetworkFrameDropped(
void *const tPtr,
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
uint16_t etherType,
uint16_t frameLength,
const uint8_t *frameData,
ZT_TraceFrameDropReason reason)
{ {
if (_vl2) _outgoingNetworkFrameDropped(tPtr,networkId,sourceMac,destMac,etherType,frameLength,frameData,reason);
} }
inline void credentialRejected(void *const tPtr,const Revocation &c,const char *reason) ZT_ALWAYS_INLINE void incomingNetworkFrameDropped(
void *const tPtr,
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
uint16_t frameLength,
const uint8_t *frameData,
uint8_t verb,
bool credentialRequestSent,
ZT_TraceFrameDropReason reason)
{ {
if (_vl2) _incomingNetworkFrameDropped(tPtr,networkId,sourceMac,destMac,peerIdentity,physicalAddress,hops,frameLength,frameData,verb,credentialRequestSent,reason);
} }
ZT_ALWAYS_INLINE void networkConfigRequestSent(
void *const tPtr,
uint64_t networkId)
{
if (_vl2) _networkConfigRequestSent(tPtr,networkId);
}
ZT_ALWAYS_INLINE void networkFilter(
void *const tPtr,
uint64_t networkId,
const uint8_t primaryRuleSetLog[512],
const uint8_t matchingCapabilityRuleSetLog[512],
uint32_t matchingCapabilityId,
int64_t matchingCapabilityTimestamp,
const Address &source,
const Address &dest,
const MAC &sourceMac,
const MAC &destMac,
uint16_t frameLength,
const uint8_t *frameData,
uint16_t etherType,
uint16_t vlanId,
bool noTee,
bool inbound,
int accept)
{
if (_vl2Filter) {
_networkFilter(
tPtr,
networkId,
primaryRuleSetLog,
matchingCapabilityRuleSetLog,
matchingCapabilityId,
matchingCapabilityTimestamp,
source,
dest,
sourceMac,
destMac,
frameLength,
frameData,
etherType,
vlanId,
noTee,
inbound,
accept);
}
}
ZT_ALWAYS_INLINE void credentialRejected(
void *const tPtr,
uint64_t networkId,
const Address &address,
uint32_t credentialId,
int64_t credentialTimestamp,
uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason)
{
if (_vl2) _credentialRejected(tPtr,networkId,address,credentialId,credentialTimestamp,credentialType,reason);
}
private:
void _resettingPathsInScope(
void *tPtr,
const Identity &reporter,
const InetAddress &from,
const InetAddress &oldExternal,
const InetAddress &newExternal,
InetAddress::IpScope scope);
void _tryingNewPath(
void *tPtr,
const Identity &trying,
const InetAddress &physicalAddress,
const InetAddress &triggerAddress,
uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb,
uint64_t triggeredByAddress,
const uint8_t *triggeredByIdentityHash,
ZT_TraceTryingNewPathReason reason);
void _learnedNewPath(
void *tPtr,
uint64_t packetId,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
const InetAddress &replaced);
void _incomingPacketDropped(
void *tPtr,
uint64_t packetId,
uint64_t networkId,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
uint8_t verb,
ZT_TracePacketDropReason reason);
void _outgoingNetworkFrameDropped(
void *tPtr,
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
uint16_t etherType,
uint16_t frameLength,
const uint8_t *frameData,
ZT_TraceFrameDropReason reason);
void _incomingNetworkFrameDropped(
void *const tPtr,
uint64_t networkId,
const MAC &sourceMac,
const MAC &destMac,
const Identity &peerIdentity,
const InetAddress &physicalAddress,
uint8_t hops,
uint16_t frameLength,
const uint8_t *frameData,
uint8_t verb,
bool credentialRequestSent,
ZT_TraceFrameDropReason reason);
void _networkConfigRequestSent(
void *tPtr,
uint64_t networkId);
void _networkFilter(
void *tPtr,
uint64_t networkId,
const uint8_t primaryRuleSetLog[512],
const uint8_t matchingCapabilityRuleSetLog[512],
uint32_t matchingCapabilityId,
int64_t matchingCapabilityTimestamp,
const Address &source,
const Address &dest,
const MAC &sourceMac,
const MAC &destMac,
uint16_t frameLength,
const uint8_t *frameData,
uint16_t etherType,
uint16_t vlanId,
bool noTee,
bool inbound,
int accept);
void _credentialRejected(
void *tPtr,
uint64_t networkId,
const Address &address,
uint32_t credentialId,
int64_t credentialTimestamp,
uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason);
const RuntimeEnvironment *const RR;
volatile bool _vl1,_vl2,_vl2Filter,_vl2Multicast;
struct _MonitoringPeer
{
int64_t _timeSet;
unsigned int _traceTypes;
SharedPtr<Peer> peer;
Mutex lock;
};
uint8_t _eventBuf[8192]; // must be less than ZT_PROTO_MAX_PACKET_LENGTH
unsigned int _eventBufSize;
std::vector<_MonitoringPeer> _monitoringPeers;
RWMutex _monitoringPeers_l;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -331,7 +331,7 @@ uint64_t random()
l.lock(); l.lock();
const uint64_t result = ROL64(s1 * 5,7) * 9; const uint64_t result = ROL64(s1 * 5,7) * 9;
const uint64_t t = s1 << 17; const uint64_t t = s1 << 17U;
s2 ^= s0; s2 ^= s0;
s3 ^= s1; s3 ^= s1;
s1 ^= s2; s1 ^= s2;

View file

@ -395,7 +395,7 @@ static ZT_ALWAYS_INLINE T ntoh(T n) { return n; }
template<typename I> template<typename I>
static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p) static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p)
{ {
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
I x = (I)0; I x = (I)0;
for(unsigned int k=0;k<sizeof(I);++k) { for(unsigned int k=0;k<sizeof(I);++k) {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
@ -413,7 +413,7 @@ static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p)
template<typename I> template<typename I>
static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i) static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i)
{ {
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<sizeof(I);++k) { for(unsigned int k=0;k<sizeof(I);++k) {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[(sizeof(I)-1)-k]; reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[(sizeof(I)-1)-k];
@ -422,7 +422,7 @@ static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i)
#endif #endif
} }
#else #else
*reinterpret_cast<I *>(p) = Utils::hton(i); *reinterpret_cast<I *>(p) = hton(i);
#endif #endif
} }

View file

@ -24,6 +24,10 @@
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#ifdef __GCC__
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
namespace ZeroTier { namespace ZeroTier {
unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...) unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)

View file

@ -203,7 +203,7 @@ public:
* @param quot Zero or more quote characters * @param quot Zero or more quote characters
* @return Vector of tokens * @return Vector of tokens
*/ */
static std::vector<std::string> split(const char *s,const char *const sep,const char *esc,const char *quot); static std::vector<std::string> split(const char *s,const char *sep,const char *esc,const char *quot);
/** /**
* Write a block of data to disk, replacing any current file contents * Write a block of data to disk, replacing any current file contents
@ -222,9 +222,9 @@ public:
#ifndef OMIT_JSON_SUPPORT #ifndef OMIT_JSON_SUPPORT
static nlohmann::json jsonParse(const std::string &buf); static nlohmann::json jsonParse(const std::string &buf);
static std::string jsonDump(const nlohmann::json &j,int indentation = 1); static std::string jsonDump(const nlohmann::json &j,int indentation = 1);
static uint64_t jsonInt(const nlohmann::json &jv,const uint64_t dfl); static uint64_t jsonInt(const nlohmann::json &jv,uint64_t dfl);
static uint64_t jsonIntHex(const nlohmann::json &jv,const uint64_t dfl); static uint64_t jsonIntHex(const nlohmann::json &jv,uint64_t dfl);
static bool jsonBool(const nlohmann::json &jv,const bool dfl); static bool jsonBool(const nlohmann::json &jv,bool dfl);
static std::string jsonString(const nlohmann::json &jv,const char *dfl); static std::string jsonString(const nlohmann::json &jv,const char *dfl);
#endif // OMIT_JSON_SUPPORT #endif // OMIT_JSON_SUPPORT
}; };