diff --git a/include/ZeroTierDebug.h b/attic/ZeroTierDebug.h similarity index 100% rename from include/ZeroTierDebug.h rename to attic/ZeroTierDebug.h diff --git a/controller/LFDB.cpp b/controller/LFDB.cpp index 1f7fc2092..caf71f55e 100644 --- a/controller/LFDB.cpp +++ b/controller/LFDB.cpp @@ -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, // hiding record values from anything but the controller or someone who has its key. uint8_t sha384pk[48]; - _myId.hash(sha384pk,true); + _myId.hashWithPrivate(sha384pk); char maskingKey [128]; Utils::hex(sha384pk,32,maskingKey); diff --git a/go/native/GoGlue.cpp b/go/native/GoGlue.cpp index 70006b5b0..f65182a7d 100644 --- a/go/native/GoGlue.cpp +++ b/go/native/GoGlue.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include diff --git a/go/pkg/zerotier/api.go b/go/pkg/zerotier/api.go index c7afde785..6b57fb0e1 100644 --- a/go/pkg/zerotier/api.go +++ b/go/pkg/zerotier/api.go @@ -495,7 +495,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e Port: tcpBindAddr.Port, }) 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 { tcpHttpServer = &http.Server{ MaxHeaderBytes: 4096, diff --git a/go/pkg/zerotier/localconfig.go b/go/pkg/zerotier/localconfig.go index 2e22c8fd3..389d8f795 100644 --- a/go/pkg/zerotier/localconfig.go +++ b/go/pkg/zerotier/localconfig.go @@ -57,7 +57,7 @@ type LocalConfigSettings struct { // PortMapping enables uPnP and NAT-PMP support 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"` // IP/port to bind for TCP access to control API (disabled if null) diff --git a/go/pkg/zerotier/network.go b/go/pkg/zerotier/network.go index 462358fc7..589bb5074 100644 --- a/go/pkg/zerotier/network.go +++ b/go/pkg/zerotier/network.go @@ -203,7 +203,7 @@ func (n *Network) LocalSettings() NetworkLocalSettings { // MulticastSubscribe subscribes to a multicast group 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() n.multicastSubscriptionsLock.Lock() if _, have := n.multicastSubscriptions[k]; have { @@ -217,7 +217,7 @@ func (n *Network) MulticastSubscribe(mg *MulticastGroup) { // MulticastUnsubscribe removes a subscription to a multicast group 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() delete(n.multicastSubscriptions, mg.key()) n.multicastSubscriptionsLock.Unlock() @@ -311,7 +311,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) { k := ipNetToKey(&ip) wantAssignedIPs[k] = true 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) } } @@ -319,7 +319,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) { } for k, ip := range haveAssignedIPs { 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) } } @@ -340,7 +340,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) { k := r.key() wantManagedRoutes[k] = true 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) } } @@ -348,7 +348,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) { } for k, r := range haveManagedRoutes { 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) } } diff --git a/go/pkg/zerotier/node.go b/go/pkg/zerotier/node.go index dbee8a74b..6a10c0031 100644 --- a/go/pkg/zerotier/node.go +++ b/go/pkg/zerotier/node.go @@ -24,6 +24,7 @@ import ( "encoding/hex" "errors" "fmt" + "io" "io/ioutil" "log" "math/rand" @@ -82,29 +83,53 @@ var ( 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 { - networks map[NetworkID]*Network - networksByMAC map[MAC]*Network // locked by networksLock - networksLock sync.RWMutex - interfaceAddresses map[string]net.IP // physical external IPs on the machine + // networks contains networks we have joined, and networksByMAC by their local MAC address + networks map[NetworkID]*Network + networksByMAC map[MAC]*Network // locked by networksLock + networksLock sync.RWMutex + + // interfaceAddresses are physical IPs assigned to the local machine (detected, not configured) + interfaceAddresses map[string]net.IP interfaceAddressesLock sync.Mutex - online uint32 - running uint32 - basePath string - peersPath string - networksPath string - localConfigPath string - localConfig LocalConfig - localConfigLock sync.RWMutex - logW *sizeLimitWriter - log *log.Logger - gn *C.ZT_GoNode - zn *C.ZT_Node - id *Identity - namedSocketApiServer *http.Server - tcpApiServer *http.Server - runWaitGroup sync.WaitGroup + + // online and running are atomic flags set to control and monitor background tasks + online uint32 + running uint32 + + basePath string + peersPath string + networksPath string + localConfigPath string + + // localConfig is the current state of local.conf + localConfig LocalConfig + localConfigLock sync.RWMutex + + // 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 + + // zn is the underlying instance of the ZeroTier core + zn *C.ZT_Node + + // id is the identity of this node + 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 + tcpApiServer *http.Server + + // runWaitGroup is used to wait for all node goroutines on shutdown + runWaitGroup sync.WaitGroup } // NewNode creates and initializes a new instance of the ZeroTier node service @@ -141,13 +166,18 @@ func NewNode(basePath string) (n *Node, err error) { } 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 { 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 { - n.log = nullLogger + n.infoLog = nullLogger } if n.localConfig.Settings.PortSearch { @@ -159,7 +189,7 @@ func NewNode(basePath string) (n *Node, err error) { portCheckCount++ if checkPort(n.localConfig.Settings.PrimaryPort) { 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 } @@ -177,11 +207,11 @@ func NewNode(basePath string) (n *Node, err error) { portCheckCount++ if checkPort(n.localConfig.Settings.SecondaryPort) { 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 } - 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 { n.localConfig.Settings.SecondaryPort = unassignedPrivilegedPorts[randomUInt()%uint(len(unassignedPrivilegedPorts))] } 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 !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) 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 } @@ -215,21 +245,21 @@ func NewNode(basePath string) (n *Node, err error) { nodesByUserPtr[uintptr(unsafe.Pointer(n))] = n nodesByUserPtrLock.Unlock() + // Instantiate GoNode and friends from the land of C/C++ cPath := C.CString(basePath) n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(uintptr(unsafe.Pointer(n)))) C.free(unsafe.Pointer(cPath)) if n.gn == nil { - n.log.Println("FATAL: node initialization failed") + n.infoLog.Println("FATAL: node initialization failed") nodesByUserPtrLock.Lock() delete(nodesByUserPtr, uintptr(unsafe.Pointer(n))) nodesByUserPtrLock.Unlock() return nil, ErrNodeInitFailed } n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn)) - n.id, err = newIdentityFromCIdentity(C.ZT_Node_identity(unsafe.Pointer(n.zn))) if err != nil { - n.log.Printf("FATAL: error obtaining node's identity") + n.infoLog.Printf("FATAL: error obtaining node's identity") nodesByUserPtrLock.Lock() delete(nodesByUserPtr, uintptr(unsafe.Pointer(n))) nodesByUserPtrLock.Unlock() @@ -237,6 +267,8 @@ func NewNode(basePath string) (n *Node, err error) { 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) go func() { defer n.runWaitGroup.Done() @@ -296,7 +328,7 @@ func NewNode(basePath string) (n *Node, err error) { interfaceAddressesChanged = true ipCstr := C.CString(ipn.String()) 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) if pn == 0 { primary = 1 @@ -311,7 +343,7 @@ func NewNode(basePath string) (n *Node, err error) { interfaceAddressesChanged = true ipCstr := C.CString(ipn.String()) 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.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 - if n.localConfig.Settings.LogSizeMax > 0 && n.logW != nil { - _ = n.logW.trim(n.localConfig.Settings.LogSizeMax*1024, 0.5, true) + // Trim infoLog if it's gone over its size limit + if n.localConfig.Settings.LogSizeMax > 0 && n.infoLogW != nil { + _ = n.infoLogW.trim(n.localConfig.Settings.LogSizeMax*1024, 0.5, true) } n.localConfigLock.RUnlock() @@ -440,16 +472,16 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error) restartRequired = true } if lc.Settings.LogSizeMax < 0 { - n.log = nullLogger - _ = n.logW.Close() - n.logW = nil - } else if n.logW != nil { - n.logW, err = sizeLimitWriterOpen(path.Join(n.basePath, "service.log")) + n.infoLog = nullLogger + _ = n.infoLogW.Close() + n.infoLogW = nil + } else if n.infoLogW != nil { + n.infoLogW, err = sizeLimitWriterOpen(path.Join(n.basePath, "service.infoLog")) if err == nil { - n.log = log.New(n.logW, "", log.LstdFlags) + n.infoLog = log.New(n.infoLogW, "", log.LstdFlags) } else { - n.log = nullLogger - n.logW = nil + n.infoLog = nullLogger + n.infoLogW = nil } } @@ -458,12 +490,12 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error) return } -// Join joins a network +// Join a network. // 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) { n.networksLock.RLock() 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 { 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)) 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 } nw, err := newNetwork(n, nwid, &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1}) 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)) return nil, err } @@ -496,14 +528,14 @@ func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*N return nw, nil } -// Leave leaves a network +// Leave a network. func (n *Node) Leave(nwid NetworkID) error { - n.log.Printf("leaving network %.16x", nwid) n.networksLock.Lock() nw := n.networks[nwid] delete(n.networks, nwid) n.networksLock.Unlock() if nw != nil { + n.infoLog.Printf("leaving network %.16x", nwid) nw.leaving() } 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) { if len(traceMessage) > 0 { - n.log.Print("TRACE: " + traceMessage) + n.infoLog.Print("TRACE: " + traceMessage) } } diff --git a/include/ZeroTierCore.h b/include/ZeroTierCore.h index 24904aa2d..d18c75559 100644 --- a/include/ZeroTierCore.h +++ b/include/ZeroTierCore.h @@ -19,6 +19,25 @@ #ifndef 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 #include extern "C" { @@ -26,26 +45,21 @@ extern "C" { #include #endif -/* For struct sockaddr_storage, which is referenced here. */ #if defined(_WIN32) || defined(_WIN64) #include #include #include -#else /* not Windows */ +#else #include #include #include #include -#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 #define ZT_SDK_API #endif -/****************************************************************************/ -/* Core constants */ /****************************************************************************/ /** @@ -174,13 +188,6 @@ extern "C" { */ #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 **********************************************/ /** @@ -269,7 +276,310 @@ extern "C" { #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. * 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, @@ -1164,8 +1474,6 @@ enum ZT_StateObjectType */ typedef void ZT_Node; -/****************************************************************************/ -/* Callbacks used by Node API */ /****************************************************************************/ /** @@ -1357,8 +1665,6 @@ typedef int (*ZT_PathLookupFunction)( struct sockaddr_storage *); /* Result buffer */ /****************************************************************************/ -/* C Node API */ -/****************************************************************************/ /** * 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); +/****************************************************************************/ + /** * 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); +/****************************************************************************/ + /** * Get ZeroTier One version * diff --git a/node/AES.cpp b/node/AES.cpp index 59e39b46b..0243d860a 100644 --- a/node/AES.cpp +++ b/node/AES.cpp @@ -20,7 +20,7 @@ namespace ZeroTier { -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS static inline uint32_t readuint32_t(const void *in) { 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) { _encryptSW((const uint8_t *)ctr,(uint8_t *)cenc); ctr[1] = Utils::hton(++bctr); -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS for(unsigned int k=0;k<16;++k) *(o++) = *(i++) ^ ((uint8_t *)cenc)[k]; #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; 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 *)&y1)[i] ^= *(in++); #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)[15] = 1; _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=8;i<16;++i) out[i] = ((const uint8_t *)&y1)[i-8] ^ ((const uint8_t *)iv2)[i]; #else diff --git a/node/Buf.hpp b/node/Buf.hpp index 945bfb673..e727a7f2c 100644 --- a/node/Buf.hpp +++ b/node/Buf.hpp @@ -145,7 +145,7 @@ public: { const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; ii += 2; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS return ( ((uint16_t)data[s] << 8U) | (uint16_t)data[s + 1]); @@ -164,7 +164,7 @@ public: { const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; ii += 4; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS return ( ((uint32_t)data[s] << 24U) | ((uint32_t)data[s + 1] << 16U) | @@ -185,7 +185,7 @@ public: { const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; ii += 8; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS return ( ((uint64_t)data[s] << 56U) | ((uint64_t)data[s + 1] << 48U) | @@ -340,7 +340,7 @@ public: { const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; ii += 2; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS data[s] = (uint8_t)(n >> 8U); data[s + 1] = (uint8_t)n; #else @@ -358,7 +358,7 @@ public: { const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; ii += 4; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS data[s] = (uint8_t)(n >> 24U); data[s + 1] = (uint8_t)(n >> 16U); data[s + 2] = (uint8_t)(n >> 8U); @@ -378,7 +378,7 @@ public: { const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; ii += 8; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS data[s] = (uint8_t)(n >> 56U); data[s + 1] = (uint8_t)(n >> 48U); data[s + 2] = (uint8_t)(n >> 40U); diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 3432cc12b..6696dea8c 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -25,7 +25,7 @@ #include "Constants.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__)) #else #define ZT_VAR_MAY_ALIAS @@ -171,7 +171,7 @@ public: { if (unlikely((i + sizeof(T)) > _l)) throw ZT_EXCEPTION_OUT_OF_BOUNDS; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS uint8_t *p = reinterpret_cast(_b + i); for(unsigned int x=1;x<=sizeof(T);++x) *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); @@ -193,7 +193,7 @@ public: { if (unlikely((i + sizeof(T)) > _l)) throw ZT_EXCEPTION_OUT_OF_BOUNDS; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS T v = 0; const uint8_t *p = reinterpret_cast(_b + i); for(unsigned int x=0;x C)) throw ZT_EXCEPTION_OUT_OF_BOUNDS; -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS uint8_t *p = reinterpret_cast(_b + _l); for(unsigned int x=1;x<=sizeof(T);++x) *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); diff --git a/node/CMakeLists.txt b/node/CMakeLists.txt index 71a9f5c79..f91ef4499 100644 --- a/node/CMakeLists.txt +++ b/node/CMakeLists.txt @@ -73,6 +73,7 @@ set(core_src SHA512.cpp Switch.cpp Topology.cpp + Trace.cpp Utils.cpp ) diff --git a/node/Capability.hpp b/node/Capability.hpp index 3a7037ee9..55caa403c 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -58,7 +58,7 @@ class Capability : public Credential friend class Credential; 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() : _nwid(0), diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 84811940e..0afc88496 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -69,7 +69,7 @@ class CertificateOfMembership : public Credential friend class Credential; 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 @@ -101,7 +101,7 @@ public: /** * Create an empty certificate of membership */ - inline CertificateOfMembership() : + ZT_ALWAYS_INLINE CertificateOfMembership() : _qualifierCount(0), _signatureLength(0) {} @@ -113,7 +113,7 @@ public: * @param nwid Network ID * @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].value = timestamp; @@ -135,22 +135,22 @@ public: * @param startAt Position to start in buffer */ template - inline CertificateOfMembership(const Buffer &b,unsigned int startAt = 0) { deserialize(b,startAt); } + ZT_ALWAYS_INLINE CertificateOfMembership(const Buffer &b,unsigned int startAt = 0) { deserialize(b,startAt); } /** * @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 */ - 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 */ - inline int64_t timestamp() const + ZT_ALWAYS_INLINE int64_t timestamp() const { for(unsigned int i=0;i<_qualifierCount;++i) { if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) @@ -162,7 +162,7 @@ public: /** * @return Address to which this cert was issued */ - inline Address issuedTo() const + ZT_ALWAYS_INLINE Address issuedTo() const { for(unsigned int i=0;i<_qualifierCount;++i) { if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) @@ -174,7 +174,7 @@ public: /** * @return Network ID for which this cert was issued */ - inline uint64_t networkId() const + ZT_ALWAYS_INLINE uint64_t networkId() const { for(unsigned int i=0;i<_qualifierCount;++i) { if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) @@ -192,7 +192,7 @@ public: * @param value Qualifier value * @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(); 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 @@ -226,7 +226,7 @@ public: * @param other Cert to compare 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 otheridx = 0; @@ -268,7 +268,7 @@ public: * @param with Identity to sign with, must include private key * @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]; unsigned int ptr = 0; @@ -294,17 +294,12 @@ public: * @param RR Runtime environment for looking up peers * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call */ - 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); } + ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); } /** * @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 inline void serialize(Buffer &b) const @@ -369,7 +364,7 @@ public: return (p - startAt); } - inline bool operator==(const CertificateOfMembership &c) const + ZT_ALWAYS_INLINE bool operator==(const CertificateOfMembership &c) const { if (_signedBy != c._signedBy) return false; @@ -385,7 +380,7 @@ public: } 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: struct _Qualifier diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index 039ed14a5..1ea0fdee4 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -46,7 +46,7 @@ class CertificateOfOwnership : public Credential friend class Credential; 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 { @@ -56,12 +56,12 @@ public: THING_IPV6_ADDRESS = 3 }; - inline CertificateOfOwnership() + ZT_ALWAYS_INLINE CertificateOfOwnership() { memset(reinterpret_cast(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(this),0,sizeof(CertificateOfOwnership)); _networkId = nwid; @@ -70,19 +70,19 @@ public: _issuedTo = issuedTo; } - inline uint64_t networkId() const { return _networkId; } - inline int64_t timestamp() const { return _ts; } - inline uint32_t id() const { return _id; } - inline const Address &issuedTo() const { return _issuedTo; } - inline const Address &signer() const { return _signedBy; } - inline const uint8_t *signature() const { return _signature; } - inline unsigned int signatureLength() const { return _signatureLength; } + ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; } + ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; } + ZT_ALWAYS_INLINE uint32_t id() const { return _id; } + ZT_ALWAYS_INLINE const Address &issuedTo() const { return _issuedTo; } + ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; } + ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; } + ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; } - inline unsigned int thingCount() const { return (unsigned int)_thingCount; } - inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } - inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } + ZT_ALWAYS_INLINE unsigned int thingCount() const { return (unsigned int)_thingCount; } + ZT_ALWAYS_INLINE Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } + ZT_ALWAYS_INLINE const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } - inline bool owns(const InetAddress &ip) const + ZT_ALWAYS_INLINE bool owns(const InetAddress &ip) const { if (ip.ss_family == AF_INET) return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast(&ip)->sin_addr.s_addr),4); @@ -91,14 +91,14 @@ public: return false; } - inline bool owns(const MAC &mac) const + ZT_ALWAYS_INLINE bool owns(const MAC &mac) const { uint8_t tmp[6]; mac.copyTo(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 (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; _thingTypes[_thingCount] = THING_MAC_ADDRESS; @@ -124,7 +124,7 @@ public: * @param signer Signing identity, must have private key * @return True if signature was successful */ - inline bool sign(const Identity &signer) + ZT_ALWAYS_INLINE bool sign(const Identity &signer) { if (signer.hasPrivate()) { Buffer tmp; @@ -136,7 +136,7 @@ public: 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 inline void serialize(Buffer &b,const bool forSign = false) const @@ -206,13 +206,13 @@ public: } // 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); } - 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); } + ZT_ALWAYS_INLINE bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } private: - inline bool _owns(const Thing &t,const void *v,unsigned int l) const + ZT_ALWAYS_INLINE bool _owns(const Thing &t,const void *v,unsigned int l) const { for(unsigned int i=0,j=_thingCount;i(&_v.sa)->marshal(data+1); case DNSNAME: p = 7; @@ -116,7 +120,8 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len) switch(_t) { case NIL: return 7; - case INETADDR: + case INETADDR_V4: + case INETADDR_V6: return 7 + reinterpret_cast(&_v.sa)->unmarshal(data+7,len-7); case DNSNAME: if (len < 10) diff --git a/node/Endpoint.hpp b/node/Endpoint.hpp index 943204830..89e88377d 100644 --- a/node/Endpoint.hpp +++ b/node/Endpoint.hpp @@ -40,13 +40,14 @@ class Endpoint public: enum Type { - NIL = 0, // NIL value - INETADDR = 1, // InetAddress (v4 or v6) - DNSNAME = 2, // DNS name and port that resolves to InetAddress - ZEROTIER = 3, // ZeroTier Address (for relaying and meshy behavior) - URL = 4, // URL for http/https/ws/etc. (not implemented yet) - ETHERNET = 5, // 48-bit LAN-local Ethernet address - UNRECOGNIZED = 255 // Unrecognized endpoint type encountered in stream + NIL = 0, // NIL value + INETADDR_V4 = 1, // IPv4 + INETADDR_V6 = 2, // IPv6 + DNSNAME = 3, // DNS name and port that resolves to InetAddress + ZEROTIER = 4, // ZeroTier Address (for relaying and meshy behavior) + 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 }; ZT_ALWAYS_INLINE Endpoint() @@ -56,13 +57,12 @@ public: ZT_ALWAYS_INLINE Endpoint(const Endpoint &ep) { - memcpy(reinterpret_cast(this),&ep,sizeof(Endpoint)); + memcpy(reinterpret_cast(this),reinterpret_cast(&ep),sizeof(Endpoint)); } - explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) : - _t(INETADDR) + explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) { - _v.sa = sa; + *this = sa; } 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) { - _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; return *this; } @@ -101,7 +111,7 @@ public: /** * @return InetAddress or NIL if not of this type */ - ZT_ALWAYS_INLINE const InetAddress &inetAddr() const { return (_t == INETADDR) ? *reinterpret_cast(&_v.sa) : InetAddress::NIL; } + ZT_ALWAYS_INLINE const InetAddress &inetAddr() const { return ((_t == INETADDR_V4)||(_t == INETADDR_V6)) ? *reinterpret_cast(&_v.sa) : InetAddress::NIL; } /** * @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 union { struct sockaddr_storage sa; - ZT_PACKED_STRUCT(struct { + struct { uint16_t port; char name[ZT_ENDPOINT_MAX_NAME_SIZE]; - }) dns; - ZT_PACKED_STRUCT(struct { + } dns; + struct { uint64_t a; uint8_t idh[ZT_IDENTITY_HASH_SIZE]; - }) zt; + } zt; char url[ZT_ENDPOINT_MAX_NAME_SIZE]; uint64_t eth; } _v; diff --git a/node/Identity.cpp b/node/Identity.cpp index 045dca52a..6385d9eef 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -89,6 +89,7 @@ void Identity::generate(const Type t) _type = t; _hasPrivate = true; + _hash[0] = 0; // force hash recompute char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY]; do { @@ -142,24 +143,13 @@ bool Identity::locallyValidate() const return false; } -bool Identity::hash(uint8_t h[48],const bool includePrivate) const +void Identity::hashWithPrivate(uint8_t h[48]) const { switch(_type) { - - case C25519: - if ((_hasPrivate)&&(includePrivate)) - SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); - else SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); - return true; - - case P384: - if ((_hasPrivate)&&(includePrivate)) - SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv)); - else SHA384(h,&_pub,sizeof(_pub)); - return true; - + case C25519: SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); break; + case P384: SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv)); break; + default: memset(h,0,48); } - return false; } 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) { _hasPrivate = false; + _hash[0] = 0; // force hash recompute if (!str) { _address.zero(); @@ -386,6 +377,97 @@ bool Identity::fromString(const char *str) 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 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) { - reinterpret_cast(id)->hash(h,includePrivate != 0); + if (includePrivate) + reinterpret_cast(id)->hashWithPrivate(h); + else memcpy(h,reinterpret_cast(id)->hash(),48); } ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id) diff --git a/node/Identity.hpp b/node/Identity.hpp index 87edc1b02..65aa1deb0 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -101,12 +101,21 @@ public: ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; } /** - * This generates a SHA384 hash of this identity's keys. - * - * @param h Buffer to receive SHA384 of public key(s) - * @param includePrivate If true, hash private key(s) as well + * @return 384-bit/48-byte hash of this identity's public key(s) */ - bool hash(uint8_t h[48],bool includePrivate = false) const; + ZT_ALWAYS_INLINE const uint8_t *hash() const + { + if (_hash[0] == 0) + const_cast(this)->_computeHash(); + return reinterpret_cast(_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) @@ -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]); } - // Marshal interface /////////////////////////////////////////////////////// static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_IDENTITY_MARSHAL_SIZE_MAX; } - inline int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const - { - _address.copyTo(data,ZT_ADDRESS_LENGTH); - switch(_type) { - - case C25519: - data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519; - memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); - if ((includePrivate)&&(_hasPrivate)) { - data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN; - memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); - return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN); - } - data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0; - return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1); - - case P384: - data[ZT_ADDRESS_LENGTH] = (uint8_t)P384; - memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); - if ((includePrivate)&&(_hasPrivate)) { - data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE; - memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE); - data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE] = 0; - return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1); - } - data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0; - data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1] = 0; - return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2); - - } - return -1; - } - inline int unmarshal(const uint8_t *restrict data,const int len) - { - if (len < (ZT_ADDRESS_LENGTH + 1)) - return -1; - unsigned int privlen; - switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) { - - case C25519: - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1)) - return -1; - memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN); - privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN]; - if (privlen == ZT_C25519_PRIVATE_KEY_LEN) { - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN)) - return -1; - _hasPrivate = true; - memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN); - return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN); - } else if (privlen == 0) { - _hasPrivate = false; - return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1); - } - break; - - case P384: - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2)) - return -1; - memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); - privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE]; - if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) { - if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)) - return -1; - _hasPrivate = true; - memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE); - privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE]; - if (len < (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; - } - //////////////////////////////////////////////////////////////////////////// + int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],bool includePrivate = false) const; + int unmarshal(const uint8_t *data,int len); private: + void _computeHash(); // recompute _hash + 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 bool _hasPrivate; ZT_PACKED_STRUCT(struct { // don't re-order these diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e3968d260..2acd557ac 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -35,9 +35,6 @@ namespace ZeroTier { namespace { -////////////////////////////////////////////////////////////////////////////// -// Implementation of each protocol verb // -////////////////////////////////////////////////////////////////////////////// void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid,const SharedPtr &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); 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; } 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; } @@ -87,18 +84,13 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key)) { if (pkt.dearmor(key)) { // ensure packet is authentic, otherwise drop - RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"address collision"); - Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); - 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()); + RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + // TODO: we handle identity collisions differently now } 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 { - 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; @@ -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 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; } @@ -118,30 +110,30 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con // Sanity check: this basically can't happen 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; } // Check rate limits 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; } // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR)); 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; } 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; } // Check that identity's address is valid as per the derivation function 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; } @@ -158,7 +150,7 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con if (ptr < pkt.size()) { ptr += externalSurfaceAddress.deserialize(pkt,ptr); 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; externalSurfaceAddress.deserialize(pkt,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2); 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); } } 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); return false; } @@ -412,7 +405,7 @@ ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment } 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); return false; } @@ -435,19 +428,19 @@ ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); } 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); return true; } } else if (to != network->mac()) { if (to.isMulticast()) { 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); return true; } } 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); return true; } @@ -733,6 +726,7 @@ ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &pkt,const RuntimeEnvironme bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) { const Address sourceAddress(source()); + const SharedPtr peer(RR->topology->get(tPtr,sourceAddress)); try { // 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)) { trusted = true; } 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; } } else if ((c == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -754,54 +749,54 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) return _doHELLO(*this,RR,tPtr,false,_path); } - const SharedPtr peer(RR->topology->get(tPtr,sourceAddress)); - if (peer) { - if (!trusted) { - if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC"); - return true; - } - } - - if (!uncompress()) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),Packet::VERB_NOP,"LZ4 decompression failed"); - return true; - } - - const Packet::Verb v = verb(); - bool r = true; - switch(v) { - //case Packet::VERB_NOP: - default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,0); - break; - case Packet::VERB_HELLO: r = _doHELLO(*this,RR,tPtr,true,_path); break; - case Packet::VERB_ERROR: r = _doERROR(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_OK: r = _doOK(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_WHOIS: r = _doWHOIS(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_RENDEZVOUS: r = _doRENDEZVOUS(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_FRAME: r = _doFRAME(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_EXT_FRAME: r = _doEXT_FRAME(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_ECHO: r = _doECHO(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_NETWORK_CREDENTIALS: r = _doNETWORK_CREDENTIALS(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_NETWORK_CONFIG_REQUEST: r = _doNETWORK_CONFIG_REQUEST(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_NETWORK_CONFIG: r = _doNETWORK_CONFIG(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_MULTICAST_GATHER: r = _doMULTICAST_GATHER(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_PUSH_DIRECT_PATHS: r = _doPUSH_DIRECT_PATHS(*this,RR,tPtr,peer,_path); break; - case Packet::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(*this,RR,tPtr,peer,_path); break; - } - return r; - } else { + if (!peer) { RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress); return false; } + + if (!trusted) { + if (!dearmor(peer->key())) { + RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); + return true; + } + } + + if (!uncompress()) { + RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA); + return true; + } + + const Packet::Verb v = verb(); + bool r = true; + switch(v) { + default: // ignore unknown verbs, but if they pass auth check they are "received" and considered NOPs by peer->receive() + 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); + break; + case Packet::VERB_HELLO: r = _doHELLO(*this,RR,tPtr,true,_path); break; + case Packet::VERB_ERROR: r = _doERROR(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_OK: r = _doOK(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_WHOIS: r = _doWHOIS(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_RENDEZVOUS: r = _doRENDEZVOUS(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_FRAME: r = _doFRAME(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_EXT_FRAME: r = _doEXT_FRAME(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_ECHO: r = _doECHO(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_NETWORK_CREDENTIALS: r = _doNETWORK_CREDENTIALS(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_NETWORK_CONFIG_REQUEST: r = _doNETWORK_CONFIG_REQUEST(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_NETWORK_CONFIG: r = _doNETWORK_CONFIG(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_MULTICAST_GATHER: r = _doMULTICAST_GATHER(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_PUSH_DIRECT_PATHS: r = _doPUSH_DIRECT_PATHS(*this,RR,tPtr,peer,_path); break; + case Packet::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(*this,RR,tPtr,peer,_path); break; + } + return r; } catch (int ztExcCode) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()"); - return true; - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()"); - return true; - } + } 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; } } // namespace ZeroTier diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 25cbd5f2d..0cbe18953 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -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(this)->sin_addr.s_addr); + ta.address[0] = reinterpret_cast(&tmp)[0]; + ta.address[1] = reinterpret_cast(&tmp)[1]; + ta.address[2] = reinterpret_cast(&tmp)[2]; + ta.address[3] = reinterpret_cast(&tmp)[3]; + memset(ta.address + 4,0,sizeof(ta.address) - 4); + ta.port = reinterpret_cast(this)->sin_port; + break; + case AF_INET6: + ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V6; + memcpy(ta.address,reinterpret_cast(this)->sin6_addr.s6_addr,16); + memset(ta.address + 16,0,sizeof(ta.address) - 16); + ta.port = reinterpret_cast(this)->sin6_port; + break; + } + } + /** * Set to null/zero */ diff --git a/node/LZ4.cpp b/node/LZ4.cpp index a69518719..6f76655f9 100644 --- a/node/LZ4.cpp +++ b/node/LZ4.cpp @@ -101,7 +101,7 @@ union LZ4_streamDecode_u { #define HEAPMODE 0 #endif -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS #define LZ4_FORCE_MEMORY_ACCESS 0 #else #define LZ4_FORCE_MEMORY_ACCESS 2 diff --git a/node/Locator.cpp b/node/Locator.cpp index 30b9cee72..01ff74790 100644 --- a/node/Locator.cpp +++ b/node/Locator.cpp @@ -46,8 +46,8 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud int p = 8; if (_ts > 0) { - data[p++] = (uint8_t)(_endpointCount >> 8U); - data[p++] = (uint8_t)_endpointCount; + Utils::storeBigEndian(data + p,(uint16_t)_endpointCount); + p += 2; for (unsigned int i = 0; i < _endpointCount; ++i) { int tmp = _at[i].marshal(data + p); if (tmp < 0) @@ -56,11 +56,14 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud } if (!excludeSignature) { - data[p++] = (uint8_t)(_signatureLength >> 8U); - data[p++] = (uint8_t)_signatureLength; + Utils::storeBigEndian(data + p,(uint16_t)_signatureLength); + p += 2; memcpy(data + p,_signature,_signatureLength); p += (int)_signatureLength; } + + Utils::storeBigEndian(data + p,_flags); + p += 2; } return p; @@ -75,9 +78,8 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len) int p = 8; if (_ts > 0) { - unsigned int ec = (int)data[p++]; - ec <<= 8U; - ec |= data[p++]; + const unsigned int ec = Utils::loadBigEndian(data + p); + p += 2; if (ec > ZT_LOCATOR_MAX_ENDPOINTS) return -1; _endpointCount = ec; @@ -90,9 +92,8 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len) if ((p + 2) > len) return -1; - unsigned int sl = data[p++]; - sl <<= 8U; - sl |= data[p++]; + const unsigned int sl = Utils::loadBigEndian(data + p); + p += 2; if (sl > ZT_SIGNATURE_BUFFER_SIZE) return -1; _signatureLength = sl; @@ -100,6 +101,11 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len) return -1; memcpy(_signature,data + p,sl); p += (int)sl; + + if ((p + 2) > len) + return -1; + _flags = Utils::loadBigEndian(data + p); + p += 2; } else { _ts = 0; } diff --git a/node/Locator.hpp b/node/Locator.hpp index 044bb5003..49e4a6223 100644 --- a/node/Locator.hpp +++ b/node/Locator.hpp @@ -23,7 +23,7 @@ #include "Identity.hpp" #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 { @@ -120,6 +120,7 @@ private: unsigned int _endpointCount; unsigned int _signatureLength; Endpoint _at[ZT_LOCATOR_MAX_ENDPOINTS]; + uint16_t _flags; uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE]; }; diff --git a/node/Membership.cpp b/node/Membership.cpp index 7a7aa8fc2..afe51b2b7 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -20,7 +20,6 @@ #include "Switch.hpp" #include "Packet.hpp" #include "Node.hpp" -#include "Trace.hpp" namespace ZeroTier { @@ -102,17 +101,24 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i _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(nconf,_remoteTags); + _cleanCredImpl(nconf,_remoteCaps); + _cleanCredImpl(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(); 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; } const int64_t oldts = _com.timestamp(); 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; } if ((newts == oldts)&&(_com == com)) @@ -120,27 +126,34 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(com.verify(RR,tPtr)) { 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; case Credential::VERIFY_OK: _com = com; return ADD_ACCEPTED_NEW; 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; case Credential::VERIFY_NEED_IDENTITY: 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 -static Membership::AddCredentialResult _addCredImpl(Hashtable &remoteCreds,const Hashtable &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred) +static ZT_ALWAYS_INLINE Membership::AddCredentialResult _addCredImpl( + Hashtable &remoteCreds, + const Hashtable &revocations, + const RuntimeEnvironment *const RR, + void *const tPtr, + const Identity &sourcePeerIdentity, + const NetworkConfig &nconf, + const C &cred) { C *rc = remoteCreds.get(cred.id()); if (rc) { 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; } if (*rc == cred) @@ -149,13 +162,13 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); 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; } switch(cred.verify(RR,tPtr)) { 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; case 0: if (!rc) @@ -166,30 +179,29 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot 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(_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(_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(_remoteCoos,_revocations,RR,tPtr,sourcePeerIdentity,nconf,coo); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl(_remoteTags,_revocations,RR,tPtr,nconf,tag); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl(_remoteCaps,_revocations,RR,tPtr,nconf,cap); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl(_remoteCoos,_revocations,RR,tPtr,nconf,coo); } - -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev) { int64_t *rt; switch(rev.verify(RR,tPtr)) { 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; case 0: { - const Credential::Type ct = rev.type(); + const ZT_CredentialType ct = rev.typeBeingRevoked(); switch(ct) { - case Credential::CREDENTIAL_TYPE_COM: + case ZT_CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } return ADD_ACCEPTED_REDUNDANT; - case Credential::CREDENTIAL_TYPE_CAPABILITY: - case Credential::CREDENTIAL_TYPE_TAG: - case Credential::CREDENTIAL_TYPE_COO: + case ZT_CREDENTIAL_TYPE_CAPABILITY: + case ZT_CREDENTIAL_TYPE_TAG: + case ZT_CREDENTIAL_TYPE_COO: rt = &(_revocations[credentialKey(ct,rev.credentialId())]); if (*rt < rev.threshold()) { *rt = rev.threshold(); @@ -198,7 +210,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } return ADD_ACCEPTED_REDUNDANT; 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; } } @@ -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(nconf,_remoteTags); - _cleanCredImpl(nconf,_remoteCaps); - _cleanCredImpl(nconf,_remoteCoos); + if ((ip.isV6())&&(nconf.ndpEmulation())) { + const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); + for(unsigned int i=0;isin6_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;isin6_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 diff --git a/node/Membership.hpp b/node/Membership.hpp index 587657e21..3d19c3e4b 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -25,8 +25,6 @@ #include "Revocation.hpp" #include "NetworkConfig.hpp" -#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL - namespace ZeroTier { class RuntimeEnvironment; @@ -61,7 +59,7 @@ public: * @param peerAddress Address of member peer (the one that this Membership describes) * @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 @@ -94,8 +92,8 @@ public: { if (_isUnspoofableAddress(nconf,r)) return true; - uint32_t *k = (uint32_t *)0; - CertificateOfOwnership *v = (CertificateOfOwnership *)0; + uint32_t *k = nullptr; + CertificateOfOwnership *v = nullptr; Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos))); while (i.next(k,v)) { if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r))) @@ -117,12 +115,6 @@ public: 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 * @@ -134,70 +126,20 @@ public: /** * 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); } - /** - * @return Bytes received so far - */ - ZT_ALWAYS_INLINE uint64_t receivedBytes() const { return _received; } - - /** - * @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; } + AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com); + 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); + 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); private: // 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 // 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 InetAddress &ip) const - { - if ((ip.isV6())&&(nconf.ndpEmulation())) { - const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); - for(unsigned int i=0;isin6_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;isin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) { - prefixMatches = false; - break; - } - } - if (prefixMatches) - return true; - break; - } - } - } - return false; - } + bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const; // This compares the remote credential's timestamp to the timestamp in our network config // plus or minus the permitted maximum timestamp delta. @@ -213,10 +155,10 @@ private: } template - inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable &remoteCreds) + ZT_ALWAYS_INLINE void _cleanCredImpl(const NetworkConfig &nconf,Hashtable &remoteCreds) { - uint32_t *k = (uint32_t *)0; - C *v = (C *)0; + uint32_t *k = nullptr; + C *v = nullptr; typename Hashtable::Iterator i(remoteCreds); while (i.next(k,v)) { if (!_isCredentialTimestampValid(nconf,*v)) @@ -233,12 +175,6 @@ private: // Time we last pushed credentials 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 CertificateOfMembership _com; @@ -256,8 +192,8 @@ public: public: ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) : _hti(m._remoteCaps), - _k((uint32_t *)0), - _c((Capability *)0), + _k(nullptr), + _c(nullptr), _m(m), _nconf(nconf) { @@ -269,7 +205,7 @@ public: if (_m._isCredentialTimestampValid(_nconf,*_c)) return _c; } - return (Capability *)0; + return nullptr; } private: diff --git a/node/Network.cpp b/node/Network.cpp index 3d458f0d2..cd274ba84 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -11,12 +11,8 @@ */ /****/ -#include #include #include -#include - -#include "../include/ZeroTierDebug.h" #include "Constants.hpp" #include "Network.hpp" @@ -28,7 +24,6 @@ #include "Buffer.hpp" #include "Packet.hpp" #include "NetworkController.hpp" -#include "Node.hpp" #include "Peer.hpp" #include "Trace.hpp" #include "ScopedPtr.hpp" @@ -40,7 +35,7 @@ namespace ZeroTier { namespace { // 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) return false; @@ -77,7 +72,7 @@ enum _doZtFilterResult DOZTFILTER_SUPER_ACCEPT }; -static _doZtFilterResult _doZtFilter( +_doZtFilterResult _doZtFilter( const RuntimeEnvironment *RR, Trace::RuleResultLog &rrl, const NetworkConfig &nconf, @@ -108,14 +103,14 @@ static _doZtFilterResult _doZtFilter( rrl.clear(); for(unsigned int rn=0;rn= 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; 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 // 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); continue; } @@ -245,7 +240,7 @@ static _doZtFilterResult _doZtFilter( 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])); } 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])); } else { thisRuleMatches = 0; @@ -271,7 +266,7 @@ static _doZtFilterResult _doZtFilter( case ZT_NETWORK_RULE_MATCH_ICMP: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { 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 (rules[rn].v.icmp.type == frameData[ihl]) { 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_DEST_PORT_RANGE: 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; switch(frameData[9]) { // IP protocol number // All these start with 16-bit source and destination port in that order @@ -324,7 +319,7 @@ static _doZtFilterResult _doZtFilter( case 0x88: // UDPLite if (frameLen > (headerLen + 4)) { 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]; } break; @@ -343,7 +338,7 @@ static _doZtFilterResult _doZtFilter( case 0x88: // UDPLite if (frameLen > (pos + 4)) { 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]; } break; @@ -402,15 +397,15 @@ static _doZtFilterResult _doZtFilter( } cf |= ownershipVerificationMask; 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 + 12] & 0x0f)) << 8); + cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0fU)) << 8U); } else if (etherType == ZT_ETHERTYPE_IPV6) { unsigned int pos = 0,proto = 0; if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { if ((proto == 0x06)&&(frameLen > (pos + 14))) { 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; case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: { 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 - if ((rules[rn].v.intRange.format & 0x80) == 0) { + if ((rules[rn].v.intRange.format & 0x80U) == 0) { // Big-endian unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes); const unsigned int eof = idx + bytes; if (eof <= frameLen) { while (idx < eof) { - integer <<= 8; + integer <<= 8U; integer |= frameData[idx++]; } } @@ -510,8 +505,8 @@ static _doZtFilterResult _doZtFilter( const unsigned int eof = idx + bytes; if (eof <= frameLen) { while (idx < eof) { - integer >>= 8; - integer |= ((uint64_t)frameData[idx++]) << 56; + integer >>= 8U; + integer |= ((uint64_t)frameData[idx++]) << 56U; } } integer >>= (64 - bits); @@ -528,9 +523,9 @@ static _doZtFilterResult _doZtFilter( rrl.log(rn,thisRuleMatches,thisSetMatches); - if ((rules[rn].t & 0x40)) - thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); - else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); + if ((rules[rn].t & 0x40U)) + thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U)); + else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U)); } return DOZTFILTER_NO_MATCH; @@ -622,10 +617,10 @@ bool Network::filterOutgoingPacket( const unsigned int vlanId, uint8_t &qosBucket) { + Trace::RuleResultLog rrl,crrl; Address ztFinalDest(ztDest); int localCapabilityIndex = -1; int accept = 0; - Trace::RuleResultLog rrl,crrl; Address cc; unsigned int ccLength = 0; bool ccWatch = false; @@ -674,8 +669,7 @@ bool Network::filterOutgoingPacket( } break; case DOZTFILTER_DROP: - //if (_config.remoteTraceTarget) - // RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); + 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); return false; case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() @@ -688,10 +682,7 @@ bool Network::filterOutgoingPacket( break; } - if (accept) { - if (membership) - membership->logSentBytes(frameLen); - + if (accept != 0) { if ((!noTee)&&(cc)) { Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -715,19 +706,19 @@ bool Network::filterOutgoingPacket( outp.compress(); RR->sw->send(tPtr,outp,true); - //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; // 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; + // DROP locally since we redirected + accept = 0; } - } 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( @@ -810,8 +801,6 @@ int Network::filterIncomingPacket( } if (accept) { - membership.logReceivedBytes(frameLen); - if (cc) { Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(_id); @@ -846,6 +835,24 @@ int Network::filterIncomingPacket( 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::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 &chunk,unsigned int ptr) { if (_destroyed) @@ -861,11 +868,11 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add { Mutex::Lock l1(_config_l); - _IncomingConfigChunk *c = (_IncomingConfigChunk *)0; + _IncomingConfigChunk *c = nullptr; uint64_t chunkId = 0; unsigned long totalLength,chunkIndex; if (ptr < chunk.size()) { - const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0); + const bool fastPropagate = ((chunk[ptr++] & 0x01U) != 0); configUpdateId = chunk.at(ptr); ptr += 8; totalLength = chunk.at(ptr); ptr += 4; chunkIndex = chunk.at(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 if (fastPropagate) { Mutex::Lock l2(_memberships_l); - Address *a = (Address *)0; - Membership *m = (Membership *)0; + Address *a = nullptr; + Membership *m = nullptr; Hashtable::Iterator i(_memberships); while (i.next(a,m)) { 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) return Membership::ADD_REJECTED; @@ -1110,14 +1141,14 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address Mutex::Lock l1(_memberships_l); 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())) { - Address *a = (Address *)0; - Membership *m = (Membership *)0; + Address *a = nullptr; + Membership *m = nullptr; Hashtable::Iterator i(_memberships); 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); outp.append((uint8_t)0x00); // no COM outp.append((uint16_t)0); // no capabilities @@ -1133,15 +1164,44 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address 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) { if (_destroyed) return; - if ((_id >> 56) == 0xff) { - if ((_id & 0xffffff) == 0) { - const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff); - const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff); + if ((_id >> 56U) == 0xff) { + if ((_id & 0xffffffU) == 0) { + const uint16_t startPortRange = (uint16_t)((_id >> 40U) & 0xffff); + const uint16_t endPortRange = (uint16_t)((_id >> 24U) & 0xffff); if (endPortRange >= startPortRange) { ScopedPtr nconf(new NetworkConfig()); @@ -1158,7 +1218,7 @@ void Network::_requestConfiguration(void *tPtr) nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt()); // 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[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; @@ -1170,7 +1230,7 @@ void Network::_requestConfiguration(void *tPtr) // Allow destination ports within range nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; 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[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; 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; // 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[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; @@ -1208,16 +1268,16 @@ void Network::_requestConfiguration(void *tPtr) } else { 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 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]; - ipv4[0] = (uint8_t)((_id >> 48) & 0xff); - ipv4[1] = (uint8_t)((myAddress >> 16) & 0xff); - ipv4[2] = (uint8_t)((myAddress >> 8) & 0xff); - ipv4[3] = (uint8_t)(myAddress & 0xff); + ipv4[0] = (uint8_t)(_id >> 48U); + ipv4[1] = (uint8_t)(myAddress >> 16U); + ipv4[2] = (uint8_t)(myAddress >> 8U); + ipv4[3] = (uint8_t)myAddress; char v4ascii[24]; 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_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 (RR->localNetworkController) { diff --git a/node/Network.hpp b/node/Network.hpp index 295826966..ef07ee6d5 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -58,7 +58,7 @@ public: /** * 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 @@ -76,14 +76,14 @@ public: ~Network(); - inline uint64_t id() const { return _id; } - inline Address controller() const { return Address(_id >> 24); } - inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } - inline bool hasConfig() const { return (_config); } - inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } - inline ZT_VirtualNetworkStatus status() const { return _status(); } - inline const NetworkConfig &config() const { return _config; } - inline const MAC &mac() const { return _mac; } + ZT_ALWAYS_INLINE uint64_t id() const { return _id; } + ZT_ALWAYS_INLINE Address controller() const { return Address(_id >> 24); } + ZT_ALWAYS_INLINE bool multicastEnabled() const { return (_config.multicastLimit > 0); } + ZT_ALWAYS_INLINE bool hasConfig() const { return (_config); } + ZT_ALWAYS_INLINE uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } + ZT_ALWAYS_INLINE ZT_VirtualNetworkStatus status() const { return _status(); } + ZT_ALWAYS_INLINE const NetworkConfig &config() const { return _config; } + ZT_ALWAYS_INLINE const MAC &mac() const { return _mac; } /** * Apply filters to an outgoing packet @@ -107,15 +107,15 @@ public: */ bool filterOutgoingPacket( void *tPtr, - const bool noTee, + bool noTee, const Address &ztSource, const Address &ztDest, const MAC &macSource, const MAC &macDest, const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, + unsigned int frameLen, + unsigned int etherType, + unsigned int vlanId, uint8_t &qosBucket); /** @@ -144,9 +144,9 @@ public: const MAC &macSource, const MAC &macDest, const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId); + unsigned int frameLen, + unsigned int etherType, + unsigned int vlanId); /** * 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 * @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); 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 mg New multicast group */ - inline 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); - } - } + void multicastSubscribe(void *tPtr,const MulticastGroup &mg); /** * Unsubscribe from a multicast group * * @param mg Multicast group */ - inline void multicastUnsubscribe(const MulticastGroup &mg) - { - Mutex::Lock l(_myMulticastGroups_l); - std::vector::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)); - if ( (i != _myMulticastGroups.end()) && (*i == mg) ) - _myMulticastGroups.erase(i); - } + void multicastUnsubscribe(const MulticastGroup &mg); /** * Handle an inbound network config chunk @@ -208,7 +194,7 @@ public: * @param ptr Index of chunk and related fields in packet * @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 &chunk,unsigned int ptr); + uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); /** * Set network configuration @@ -227,12 +213,12 @@ public: /** * 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 */ - 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 @@ -245,7 +231,7 @@ public: /** * 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) @@ -253,18 +239,13 @@ public: * @param mac MAC address * @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); const Address *const br = _remoteBridgeRoutes.get(mac); return ((br) ? *br : Address()); } - /** - * @return True if QoS is in effect for this network - */ - inline bool qosEnabled() { return false; } - /** * Set a bridge route * @@ -280,7 +261,7 @@ public: * @param mg Multicast group * @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); _multicastGroupsBehindMe.set(mg,now); @@ -289,51 +270,27 @@ public: /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(void *tPtr,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); - } + Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com); /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(void *tPtr,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); - } + Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap); /** * Validate a credential and learn it if it passes certificate and other checks */ - inline Membership::AddCredentialResult addCredential(void *tPtr,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); - } + Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag); /** * 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 */ - inline Membership::AddCredentialResult addCredential(void *tPtr,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); - } + Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo); /** * Force push credentials (COM, etc.) to a peer now @@ -342,11 +299,7 @@ public: * @param to Destination peer address * @param now Current time */ - inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now) - { - Mutex::Lock _l(_memberships_l); - _memberships[to].pushCredentials(RR,tPtr,now,to,_config); - } + void pushCredentialsNow(void *tPtr,const Address &to,int64_t now); /** * Push credentials if we haven't done so in a long time @@ -355,7 +308,7 @@ public: * @param to Destination peer address * @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); Mutex::Lock _l(_memberships_l); @@ -370,25 +323,14 @@ public: * This sets the network to completely remove itself on delete. This also prevents the * call of the normal port shutdown event on delete. */ - inline void destroy() - { - _memberships_l.lock(); - _config_l.lock(); - _destroyed = true; - _config_l.unlock(); - _memberships_l.unlock(); - } + void destroy(); /** * Get this network's config for export via the ZT core API * * @param ec Buffer to fill with externally-visible network configuration */ - inline void externalConfig(ZT_VirtualNetworkConfig *ec) const - { - Mutex::Lock _l(_config_l); - _externalConfig(ec); - } + void externalConfig(ZT_VirtualNetworkConfig *ec) const; /** * Iterate through memberships @@ -396,7 +338,7 @@ public: * @param f Function of (const Address,const Membership) */ template - inline void eachMember(F f) + ZT_ALWAYS_INLINE void eachMember(F f) { Mutex::Lock ml(_memberships_l); Hashtable::Iterator i(_memberships); @@ -411,13 +353,12 @@ public: /** * @return Externally usable pointer-to-pointer exported via the core API */ - inline void **userPtr() { return &_uPtr; } + ZT_ALWAYS_INLINE void **userPtr() { return &_uPtr; } private: void _requestConfiguration(void *tPtr); ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked - bool _gate(const SharedPtr &peer); void _announceMulticastGroups(void *tPtr,bool force); void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups); std::vector _allMulticastGroups() const; @@ -433,11 +374,11 @@ private: Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) NetworkConfig _config; - uint64_t _lastConfigUpdate; + volatile uint64_t _lastConfigUpdate; 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 updateId; uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; diff --git a/node/Node.cpp b/node/Node.cpp index 37a2622ab..98e43706a 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -33,10 +33,6 @@ 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) : _RR(this), RR(&_RR), @@ -437,7 +433,7 @@ ZT_PeerList *Node::peers() const p->address = (*pi)->address().toInt(); identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted p->identity = &identities[pl->peerCount]; - (*pi)->identity().hash(p->identityHash,false); + memcpy(p->identityHash,(*pi)->identity().hash(),sizeof(p->identityHash)); if ((*pi)->remoteVersionKnown()) { p->versionMajor = (int)(*pi)->remoteVersionMajor(); p->versionMinor = (int)(*pi)->remoteVersionMinor(); diff --git a/node/Node.hpp b/node/Node.hpp index 074255ff1..01dc5858d 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -264,7 +264,7 @@ public: * @param remoteAddress Remote address * @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 diff --git a/node/OS.hpp b/node/OS.hpp index e1694b170..de356b156 100644 --- a/node/OS.hpp +++ b/node/OS.hpp @@ -28,18 +28,15 @@ // #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__ #endif #endif -#if !defined(__GCC__) && !defined (__clang__) && !defined(__INTEL_COMPILER) -#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop)) +#ifdef _MSC_VER #pragma warning(disable : 4290) #pragma warning(disable : 4996) #pragma warning(disable : 4101) -#else -#define ZT_PACKED_STRUCT(D) D __attribute__((packed)) #endif #if defined(_WIN32) || defined(_WIN64) @@ -98,8 +95,8 @@ // 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))) -#ifndef ZT_NO_TYPE_PUNNING -#define ZT_NO_TYPE_PUNNING +#ifndef ZT_NO_UNALIGNED_ACCESS +#define ZT_NO_UNALIGNED_ACCESS #endif #endif diff --git a/node/Packet.cpp b/node/Packet.cpp index 0e680a3cd..6c1a28506 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -66,7 +66,7 @@ bool Packet::dearmor(const void *key) s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); uint64_t mac[2]; 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)) return false; #else diff --git a/node/Path.hpp b/node/Path.hpp index 361a32b29..4272a29ba 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -111,7 +111,14 @@ public: * * @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 diff --git a/node/Peer.cpp b/node/Peer.cpp index 8fb2b064a..cce2fe535 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -92,9 +92,7 @@ void Peer::received( 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]->address().ipsEqual2(path->address()))) { - // If this is another path to the same place, swap it out as the - // one we just received from may replace an old one but don't - // learn it as a new path. + // Replace older path if everything is the same except the port number. _paths[i] = path; goto path_check_done; } else { @@ -130,7 +128,7 @@ path_check_done: _lastAttemptedP2PInit = now; InetAddress addr; - if (_bootstrap.type() == Endpoint::INETADDR) + if ((_bootstrap.type() == Endpoint::INETADDR_V4)||(_bootstrap.type() == Endpoint::INETADDR_V6)) sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now); if (RR->node->externalPathLookup(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; } - if (_bootstrap.type() == Endpoint::INETADDR) + if ((_bootstrap.type() == Endpoint::INETADDR_V4)||(_bootstrap.type() == Endpoint::INETADDR_V6)) sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now); SharedPtr r(RR->topology->root()); diff --git a/node/Poly1305.cpp b/node/Poly1305.cpp index c4db0f7f0..bab9ac2b7 100644 --- a/node/Poly1305.cpp +++ b/node/Poly1305.cpp @@ -70,7 +70,7 @@ typedef struct poly1305_state_internal_t { unsigned char final; } 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) { return @@ -87,7 +87,7 @@ static inline unsigned long long U8TO64(const unsigned char *p) #define U8TO64(p) (*reinterpret_cast(p)) #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) { p[0] = (v ) & 0xff; diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 3c6e50613..4c324d439 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -44,7 +44,7 @@ class Revocation : public Credential friend class Credential; 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() : _id(0), @@ -54,7 +54,7 @@ public: _flags(0), _target(), _signedBy(), - _type(Credential::CREDENTIAL_TYPE_NULL), + _type(ZT_CREDENTIAL_TYPE_NULL), _signatureLength(0) { } @@ -68,7 +68,7 @@ public: * @param tgt Target node whose credential(s) are 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), _credentialId(cid), _networkId(nwid), @@ -87,7 +87,7 @@ public: ZT_ALWAYS_INLINE int64_t threshold() const { return _threshold; } ZT_ALWAYS_INLINE const Address &target() const { return _target; } 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 unsigned int signatureLength() const { return _signatureLength; } ZT_ALWAYS_INLINE bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } @@ -160,7 +160,7 @@ public: _flags = b.template at(p); p += 8; _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; - _type = (Credential::Type)b[p++]; + _type = (ZT_CredentialType)b[p++]; if (b[p++] == 1) { _signatureLength = b.template at(p); @@ -186,7 +186,7 @@ private: uint64_t _flags; Address _target; Address _signedBy; - Credential::Type _type; + ZT_CredentialType _type; unsigned int _signatureLength; uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE]; }; diff --git a/node/RingBuffer.hpp b/node/RingBuffer.hpp index 882a93e14..de086fe88 100644 --- a/node/RingBuffer.hpp +++ b/node/RingBuffer.hpp @@ -235,64 +235,6 @@ public: } 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> 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 #define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p)))) #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?) diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 483e2df40..18f3fd1fa 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -25,7 +25,7 @@ #include "Trace.hpp" // 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 { @@ -53,11 +53,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : { } -SelfAwareness::~SelfAwareness() -{ -} - -void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now) +void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now) { const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); @@ -65,12 +61,10 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive return; 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)) ) { // 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.ts = now; 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. { Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; + PhySurfaceKey *k = nullptr; + PhySurfaceEntry *e = nullptr; while (i.next(k,e)) { - if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) + if ((k->scope == scope)&&(k->reporterPhysicalAddress != reporterPhysicalAddress)) _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 _ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); RR->topology->eachPeer<_ResetWithinScope &>(rset); + + RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,entry.mySurface,myPhysicalAddress,scope); } else { // Otherwise just update DB to use to determine external surface info 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,std::set > > ipToPortsAndLocalSockets(16); - - { - Mutex::Lock l(_phy_l); - Hashtable::Iterator i(const_cast(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,std::set > &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,std::set > >::Iterator i(ipToPortsAndLocalSockets); - InetAddress *k = nullptr; - std::pair< std::set,std::set > *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 SelfAwareness::externalAddresses(const int64_t now) const { std::multimap r; diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 4fa2cc319..f4aeff521 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -24,6 +24,7 @@ namespace ZeroTier { +class Identity; class RuntimeEnvironment; /** @@ -35,19 +36,18 @@ class SelfAwareness { public: explicit SelfAwareness(const RuntimeEnvironment *renv); - ~SelfAwareness(); /** * 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 reporterPhysicalAddress Physical address that reporting peer seems to 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 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 @@ -56,14 +56,6 @@ public: */ 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. * diff --git a/node/Switch.cpp b/node/Switch.cpp index 358d06b15..959ee348c 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -211,7 +211,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const bool fromBridged; if ((fromBridged = (from != network->mac()))) { 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; } } @@ -235,7 +235,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!network->config().enableBroadcast()) { // 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; } } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { @@ -323,7 +323,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // Check this after NDP emulation, since that has to be allowed in exactly this case 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; } @@ -336,7 +336,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // 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)) { - 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; } @@ -365,7 +365,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const SharedPtr 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)) { - 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; } @@ -392,7 +392,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const // for each ZT destination are also done below. This is the same rationale // and design as for multicast. 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; } @@ -442,7 +442,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const outp.append((uint16_t)etherType); outp.append(data,len); } 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); } } } diff --git a/node/Tag.hpp b/node/Tag.hpp index 484b3e01c..eb5c9e242 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -52,7 +52,7 @@ class Tag : public Credential friend class Credential; 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() : _id(0), diff --git a/node/Trace.cpp b/node/Trace.cpp new file mode 100644 index 000000000..4d720453f --- /dev/null +++ b/node/Trace.cpp @@ -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 diff --git a/node/Trace.hpp b/node/Trace.hpp index 3a00eeec4..fe76b66dc 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -14,29 +14,26 @@ #ifndef ZT_TRACE_HPP #define ZT_TRACE_HPP -#include #include #include #include +#include #include "Constants.hpp" #include "SharedPtr.hpp" -#include "Packet.hpp" -#include "Credential.hpp" -#include "InetAddress.hpp" -#include "Dictionary.hpp" #include "Mutex.hpp" -#include "Hashtable.hpp" +#include "Packet.hpp" +#include "InetAddress.hpp" +#include "Address.hpp" +#include "MAC.hpp" namespace ZeroTier { class RuntimeEnvironment; -class Address; class Identity; class Peer; class Path; class Network; -class MAC; class CertificateOfMembership; class CertificateOfOwnership; class Revocation; @@ -50,117 +47,265 @@ struct NetworkConfig; class Trace { public: - class RuleResultLog + struct RuleResultLog { - public: - ZT_ALWAYS_INLINE RuleResultLog() { this->clear(); } + uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields - 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 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)); } - - ZT_ALWAYS_INLINE const uint8_t *data() const { return _l; } - ZT_ALWAYS_INLINE unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); } - - private: - uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; + 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 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)); + } }; - 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) - { - } - - inline void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &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 &newPath,const uint64_t packetId) - { - } - - inline void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason) - { - } - - inline void incomingPacketInvalid(void *const tPtr,const SharedPtr &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,const uint64_t packetId,const Address &source,const char *reason) - { - } - - inline void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &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,const SharedPtr &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,const SharedPtr &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( + ZT_ALWAYS_INLINE void resettingPathsInScope( void *const tPtr, - const Network &network, - const RuleResultLog &primaryRuleSetLog, - const RuleResultLog *const matchingCapabilityRuleSetLog, - const Capability *const matchingCapability, - const Address &ztSource, - 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) + const Identity &reporter, + const InetAddress &from, + const InetAddress &oldExternal, + const InetAddress &newExternal, + const InetAddress::IpScope scope) { + 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; + 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 diff --git a/node/Utils.cpp b/node/Utils.cpp index 116634a4c..2b3e59ad2 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -331,7 +331,7 @@ uint64_t random() l.lock(); const uint64_t result = ROL64(s1 * 5,7) * 9; - const uint64_t t = s1 << 17; + const uint64_t t = s1 << 17U; s2 ^= s0; s3 ^= s1; s1 ^= s2; diff --git a/node/Utils.hpp b/node/Utils.hpp index 56da5d1f7..ea2ed519f 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -395,7 +395,7 @@ static ZT_ALWAYS_INLINE T ntoh(T n) { return n; } template static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p) { -#ifdef ZT_NO_TYPE_PUNNING +#ifdef ZT_NO_UNALIGNED_ACCESS I x = (I)0; for(unsigned int k=0;k 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(p)[k] = reinterpret_cast(&i)[(sizeof(I)-1)-k]; @@ -422,7 +422,7 @@ static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i) #endif } #else - *reinterpret_cast(p) = Utils::hton(i); + *reinterpret_cast(p) = hton(i); #endif } diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index 41e1b2e4d..dc8c03ecc 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -24,6 +24,10 @@ #include #endif +#ifdef __GCC__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + namespace ZeroTier { unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...) diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 65b38ae74..cd1cb2107 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -203,7 +203,7 @@ public: * @param quot Zero or more quote characters * @return Vector of tokens */ - static std::vector split(const char *s,const char *const sep,const char *esc,const char *quot); + static std::vector 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 @@ -222,9 +222,9 @@ public: #ifndef OMIT_JSON_SUPPORT static nlohmann::json jsonParse(const std::string &buf); 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 jsonIntHex(const nlohmann::json &jv,const uint64_t dfl); - static bool jsonBool(const nlohmann::json &jv,const bool dfl); + static uint64_t jsonInt(const nlohmann::json &jv,uint64_t dfl); + static uint64_t jsonIntHex(const nlohmann::json &jv,uint64_t dfl); + static bool jsonBool(const nlohmann::json &jv,bool dfl); static std::string jsonString(const nlohmann::json &jv,const char *dfl); #endif // OMIT_JSON_SUPPORT };