mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 13:03:45 +02:00
Loads of refactoring, integration of new version of Trace.
This commit is contained in:
parent
e6273b3300
commit
33bb61c63d
52 changed files with 1603 additions and 910 deletions
|
@ -44,7 +44,7 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
|
||||||
// LF record masking key is the first 32 bytes of SHA512(controller private key) in hex,
|
// LF record masking key is the first 32 bytes of SHA512(controller private key) in hex,
|
||||||
// hiding record values from anything but the controller or someone who has its key.
|
// hiding record values from anything but the controller or someone who has its key.
|
||||||
uint8_t sha384pk[48];
|
uint8_t sha384pk[48];
|
||||||
_myId.hash(sha384pk,true);
|
_myId.hashWithPrivate(sha384pk);
|
||||||
char maskingKey [128];
|
char maskingKey [128];
|
||||||
Utils::hex(sha384pk,32,maskingKey);
|
Utils::hex(sha384pk,32,maskingKey);
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
|
|
@ -495,7 +495,7 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e
|
||||||
Port: tcpBindAddr.Port,
|
Port: tcpBindAddr.Port,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
node.log.Printf("ERROR: unable to start API HTTP server at TCP bind address %s: %s (continuing anyway)", tcpBindAddr.String(), err.Error())
|
node.infoLog.Printf("ERROR: unable to start API HTTP server at TCP bind address %s: %s (named socket listener startd, continuing anyway)", tcpBindAddr.String(), err.Error())
|
||||||
} else {
|
} else {
|
||||||
tcpHttpServer = &http.Server{
|
tcpHttpServer = &http.Server{
|
||||||
MaxHeaderBytes: 4096,
|
MaxHeaderBytes: 4096,
|
||||||
|
|
|
@ -57,7 +57,7 @@ type LocalConfigSettings struct {
|
||||||
// PortMapping enables uPnP and NAT-PMP support
|
// PortMapping enables uPnP and NAT-PMP support
|
||||||
PortMapping bool `json:"portMapping"`
|
PortMapping bool `json:"portMapping"`
|
||||||
|
|
||||||
// LogSizeMax is the maximum size of the log in kilobytes or 0 for no limit and -1 to disable logging
|
// LogSizeMax is the maximum size of the infoLog in kilobytes or 0 for no limit and -1 to disable logging
|
||||||
LogSizeMax int `json:"logSizeMax"`
|
LogSizeMax int `json:"logSizeMax"`
|
||||||
|
|
||||||
// IP/port to bind for TCP access to control API (disabled if null)
|
// IP/port to bind for TCP access to control API (disabled if null)
|
||||||
|
|
|
@ -203,7 +203,7 @@ func (n *Network) LocalSettings() NetworkLocalSettings {
|
||||||
|
|
||||||
// MulticastSubscribe subscribes to a multicast group
|
// MulticastSubscribe subscribes to a multicast group
|
||||||
func (n *Network) MulticastSubscribe(mg *MulticastGroup) {
|
func (n *Network) MulticastSubscribe(mg *MulticastGroup) {
|
||||||
n.node.log.Printf("%.16x joined multicast group %s", uint64(n.id), mg.String())
|
n.node.infoLog.Printf("%.16x joined multicast group %s", uint64(n.id), mg.String())
|
||||||
k := mg.key()
|
k := mg.key()
|
||||||
n.multicastSubscriptionsLock.Lock()
|
n.multicastSubscriptionsLock.Lock()
|
||||||
if _, have := n.multicastSubscriptions[k]; have {
|
if _, have := n.multicastSubscriptions[k]; have {
|
||||||
|
@ -217,7 +217,7 @@ func (n *Network) MulticastSubscribe(mg *MulticastGroup) {
|
||||||
|
|
||||||
// MulticastUnsubscribe removes a subscription to a multicast group
|
// MulticastUnsubscribe removes a subscription to a multicast group
|
||||||
func (n *Network) MulticastUnsubscribe(mg *MulticastGroup) {
|
func (n *Network) MulticastUnsubscribe(mg *MulticastGroup) {
|
||||||
n.node.log.Printf("%.16x left multicast group %s", uint64(n.id), mg.String())
|
n.node.infoLog.Printf("%.16x left multicast group %s", uint64(n.id), mg.String())
|
||||||
n.multicastSubscriptionsLock.Lock()
|
n.multicastSubscriptionsLock.Lock()
|
||||||
delete(n.multicastSubscriptions, mg.key())
|
delete(n.multicastSubscriptions, mg.key())
|
||||||
n.multicastSubscriptionsLock.Unlock()
|
n.multicastSubscriptionsLock.Unlock()
|
||||||
|
@ -311,7 +311,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
|
||||||
k := ipNetToKey(&ip)
|
k := ipNetToKey(&ip)
|
||||||
wantAssignedIPs[k] = true
|
wantAssignedIPs[k] = true
|
||||||
if _, have := haveAssignedIPs[k]; !have {
|
if _, have := haveAssignedIPs[k]; !have {
|
||||||
n.node.log.Printf("%.16x adding managed IP %s", uint64(n.id), ip.String())
|
n.node.infoLog.Printf("%.16x adding managed IP %s", uint64(n.id), ip.String())
|
||||||
_ = n.tap.AddIP(&ip)
|
_ = n.tap.AddIP(&ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
|
||||||
}
|
}
|
||||||
for k, ip := range haveAssignedIPs {
|
for k, ip := range haveAssignedIPs {
|
||||||
if _, want := wantAssignedIPs[k]; !want {
|
if _, want := wantAssignedIPs[k]; !want {
|
||||||
n.node.log.Printf("%.16x removing managed IP %s", uint64(n.id), ip.String())
|
n.node.infoLog.Printf("%.16x removing managed IP %s", uint64(n.id), ip.String())
|
||||||
_ = n.tap.RemoveIP(ip)
|
_ = n.tap.RemoveIP(ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
|
||||||
k := r.key()
|
k := r.key()
|
||||||
wantManagedRoutes[k] = true
|
wantManagedRoutes[k] = true
|
||||||
if _, have := haveManagedRoutes[k]; !have {
|
if _, have := haveManagedRoutes[k]; !have {
|
||||||
n.node.log.Printf("%.16x adding managed route %s", uint64(n.id), r.String())
|
n.node.infoLog.Printf("%.16x adding managed route %s", uint64(n.id), r.String())
|
||||||
_ = n.tap.AddRoute(&r)
|
_ = n.tap.AddRoute(&r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,7 +348,7 @@ func (n *Network) updateConfig(nc *NetworkConfig, ls *NetworkLocalSettings) {
|
||||||
}
|
}
|
||||||
for k, r := range haveManagedRoutes {
|
for k, r := range haveManagedRoutes {
|
||||||
if _, want := wantManagedRoutes[k]; !want {
|
if _, want := wantManagedRoutes[k]; !want {
|
||||||
n.node.log.Printf("%.16x removing managed route %s", uint64(n.id), r.String())
|
n.node.infoLog.Printf("%.16x removing managed route %s", uint64(n.id), r.String())
|
||||||
_ = n.tap.RemoveRoute(r)
|
_ = n.tap.RemoveRoute(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
@ -82,29 +83,53 @@ var (
|
||||||
nodesByUserPtrLock sync.RWMutex
|
nodesByUserPtrLock sync.RWMutex
|
||||||
)
|
)
|
||||||
|
|
||||||
// Node is an instance of the ZeroTier core node and related C++ I/O code
|
// Node is an instance of a virtual port on the global switch.
|
||||||
type Node struct {
|
type Node struct {
|
||||||
networks map[NetworkID]*Network
|
// networks contains networks we have joined, and networksByMAC by their local MAC address
|
||||||
networksByMAC map[MAC]*Network // locked by networksLock
|
networks map[NetworkID]*Network
|
||||||
networksLock sync.RWMutex
|
networksByMAC map[MAC]*Network // locked by networksLock
|
||||||
interfaceAddresses map[string]net.IP // physical external IPs on the machine
|
networksLock sync.RWMutex
|
||||||
|
|
||||||
|
// interfaceAddresses are physical IPs assigned to the local machine (detected, not configured)
|
||||||
|
interfaceAddresses map[string]net.IP
|
||||||
interfaceAddressesLock sync.Mutex
|
interfaceAddressesLock sync.Mutex
|
||||||
online uint32
|
|
||||||
running uint32
|
// online and running are atomic flags set to control and monitor background tasks
|
||||||
basePath string
|
online uint32
|
||||||
peersPath string
|
running uint32
|
||||||
networksPath string
|
|
||||||
localConfigPath string
|
basePath string
|
||||||
localConfig LocalConfig
|
peersPath string
|
||||||
localConfigLock sync.RWMutex
|
networksPath string
|
||||||
logW *sizeLimitWriter
|
localConfigPath string
|
||||||
log *log.Logger
|
|
||||||
gn *C.ZT_GoNode
|
// localConfig is the current state of local.conf
|
||||||
zn *C.ZT_Node
|
localConfig LocalConfig
|
||||||
id *Identity
|
localConfigLock sync.RWMutex
|
||||||
namedSocketApiServer *http.Server
|
|
||||||
tcpApiServer *http.Server
|
// logs for information, errors, and trace output
|
||||||
runWaitGroup sync.WaitGroup
|
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
|
// 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 {
|
if n.localConfig.Settings.LogSizeMax >= 0 {
|
||||||
n.logW, err = sizeLimitWriterOpen(path.Join(basePath, "node.log"))
|
n.infoLogW, err = sizeLimitWriterOpen(path.Join(basePath, "info.log"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n.log = log.New(n.logW, "", log.LstdFlags)
|
n.errLogW, err = sizeLimitWriterOpen(path.Join(basePath, "error.log"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n.infoLog = log.New(n.infoLogW, "", log.LstdFlags)
|
||||||
|
n.errLog = log.New(n.errLogW, "", log.LstdFlags)
|
||||||
} else {
|
} else {
|
||||||
n.log = nullLogger
|
n.infoLog = nullLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.localConfig.Settings.PortSearch {
|
if n.localConfig.Settings.PortSearch {
|
||||||
|
@ -159,7 +189,7 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
portCheckCount++
|
portCheckCount++
|
||||||
if checkPort(n.localConfig.Settings.PrimaryPort) {
|
if checkPort(n.localConfig.Settings.PrimaryPort) {
|
||||||
if n.localConfig.Settings.PrimaryPort != origPort {
|
if n.localConfig.Settings.PrimaryPort != origPort {
|
||||||
n.log.Printf("primary port %d unavailable, found port %d and saved in local.conf", origPort, n.localConfig.Settings.PrimaryPort)
|
n.infoLog.Printf("primary port %d unavailable, found port %d and saved in local.conf", origPort, n.localConfig.Settings.PrimaryPort)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -177,11 +207,11 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
portCheckCount++
|
portCheckCount++
|
||||||
if checkPort(n.localConfig.Settings.SecondaryPort) {
|
if checkPort(n.localConfig.Settings.SecondaryPort) {
|
||||||
if n.localConfig.Settings.SecondaryPort != origPort {
|
if n.localConfig.Settings.SecondaryPort != origPort {
|
||||||
n.log.Printf("secondary port %d unavailable, found port %d (port search enabled)", origPort, n.localConfig.Settings.SecondaryPort)
|
n.infoLog.Printf("secondary port %d unavailable, found port %d (port search enabled)", origPort, n.localConfig.Settings.SecondaryPort)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n.log.Printf("secondary port %d unavailable, trying a random port (port search enabled)", n.localConfig.Settings.SecondaryPort)
|
n.infoLog.Printf("secondary port %d unavailable, trying a random port (port search enabled)", n.localConfig.Settings.SecondaryPort)
|
||||||
if portCheckCount <= 64 {
|
if portCheckCount <= 64 {
|
||||||
n.localConfig.Settings.SecondaryPort = unassignedPrivilegedPorts[randomUInt()%uint(len(unassignedPrivilegedPorts))]
|
n.localConfig.Settings.SecondaryPort = unassignedPrivilegedPorts[randomUInt()%uint(len(unassignedPrivilegedPorts))]
|
||||||
} else {
|
} else {
|
||||||
|
@ -200,14 +230,14 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
}
|
}
|
||||||
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
|
if n.localConfig.Settings.SecondaryPort > 0 && n.localConfig.Settings.SecondaryPort < 65536 {
|
||||||
if !checkPort(n.localConfig.Settings.SecondaryPort) {
|
if !checkPort(n.localConfig.Settings.SecondaryPort) {
|
||||||
n.log.Printf("WARNING: unable to bind secondary port %d",n.localConfig.Settings.SecondaryPort)
|
n.infoLog.Printf("WARNING: unable to bind secondary port %d", n.localConfig.Settings.SecondaryPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n.namedSocketApiServer, n.tcpApiServer, err = createAPIServer(basePath, n)
|
n.namedSocketApiServer, n.tcpApiServer, err = createAPIServer(basePath, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.log.Printf("FATAL: unable to start API server: %s", err.Error())
|
n.infoLog.Printf("FATAL: unable to start API server: %s", err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,21 +245,21 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
nodesByUserPtr[uintptr(unsafe.Pointer(n))] = n
|
nodesByUserPtr[uintptr(unsafe.Pointer(n))] = n
|
||||||
nodesByUserPtrLock.Unlock()
|
nodesByUserPtrLock.Unlock()
|
||||||
|
|
||||||
|
// Instantiate GoNode and friends from the land of C/C++
|
||||||
cPath := C.CString(basePath)
|
cPath := C.CString(basePath)
|
||||||
n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(uintptr(unsafe.Pointer(n))))
|
n.gn = C.ZT_GoNode_new(cPath, C.uintptr_t(uintptr(unsafe.Pointer(n))))
|
||||||
C.free(unsafe.Pointer(cPath))
|
C.free(unsafe.Pointer(cPath))
|
||||||
if n.gn == nil {
|
if n.gn == nil {
|
||||||
n.log.Println("FATAL: node initialization failed")
|
n.infoLog.Println("FATAL: node initialization failed")
|
||||||
nodesByUserPtrLock.Lock()
|
nodesByUserPtrLock.Lock()
|
||||||
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
|
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
|
||||||
nodesByUserPtrLock.Unlock()
|
nodesByUserPtrLock.Unlock()
|
||||||
return nil, ErrNodeInitFailed
|
return nil, ErrNodeInitFailed
|
||||||
}
|
}
|
||||||
n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn))
|
n.zn = (*C.ZT_Node)(C.ZT_GoNode_getNode(n.gn))
|
||||||
|
|
||||||
n.id, err = newIdentityFromCIdentity(C.ZT_Node_identity(unsafe.Pointer(n.zn)))
|
n.id, err = newIdentityFromCIdentity(C.ZT_Node_identity(unsafe.Pointer(n.zn)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.log.Printf("FATAL: error obtaining node's identity")
|
n.infoLog.Printf("FATAL: error obtaining node's identity")
|
||||||
nodesByUserPtrLock.Lock()
|
nodesByUserPtrLock.Lock()
|
||||||
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
|
delete(nodesByUserPtr, uintptr(unsafe.Pointer(n)))
|
||||||
nodesByUserPtrLock.Unlock()
|
nodesByUserPtrLock.Unlock()
|
||||||
|
@ -237,6 +267,8 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background maintenance goroutine that handles polling for local network changes, cleaning internal data
|
||||||
|
// structures, syncing local config changes, and numerous other things that must happen from time to time.
|
||||||
n.runWaitGroup.Add(1)
|
n.runWaitGroup.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer n.runWaitGroup.Done()
|
defer n.runWaitGroup.Done()
|
||||||
|
@ -296,7 +328,7 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
interfaceAddressesChanged = true
|
interfaceAddressesChanged = true
|
||||||
ipCstr := C.CString(ipn.String())
|
ipCstr := C.CString(ipn.String())
|
||||||
for pn, p := range ports {
|
for pn, p := range ports {
|
||||||
n.log.Printf("UDP binding to port %d on interface %s", p, astr)
|
n.infoLog.Printf("UDP binding to port %d on interface %s", p, astr)
|
||||||
primary := C.int(0)
|
primary := C.int(0)
|
||||||
if pn == 0 {
|
if pn == 0 {
|
||||||
primary = 1
|
primary = 1
|
||||||
|
@ -311,7 +343,7 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
interfaceAddressesChanged = true
|
interfaceAddressesChanged = true
|
||||||
ipCstr := C.CString(ipn.String())
|
ipCstr := C.CString(ipn.String())
|
||||||
for _, p := range ports {
|
for _, p := range ports {
|
||||||
n.log.Printf("UDP closing socket bound to port %d on interface %s", p, astr)
|
n.infoLog.Printf("UDP closing socket bound to port %d on interface %s", p, astr)
|
||||||
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(p))
|
C.ZT_GoNode_phyStopListen(n.gn, nil, ipCstr, C.int(p))
|
||||||
}
|
}
|
||||||
C.free(unsafe.Pointer(ipCstr))
|
C.free(unsafe.Pointer(ipCstr))
|
||||||
|
@ -360,9 +392,9 @@ func NewNode(basePath string) (n *Node, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim log if it's gone over its size limit
|
// Trim infoLog if it's gone over its size limit
|
||||||
if n.localConfig.Settings.LogSizeMax > 0 && n.logW != nil {
|
if n.localConfig.Settings.LogSizeMax > 0 && n.infoLogW != nil {
|
||||||
_ = n.logW.trim(n.localConfig.Settings.LogSizeMax*1024, 0.5, true)
|
_ = n.infoLogW.trim(n.localConfig.Settings.LogSizeMax*1024, 0.5, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
n.localConfigLock.RUnlock()
|
n.localConfigLock.RUnlock()
|
||||||
|
@ -440,16 +472,16 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error)
|
||||||
restartRequired = true
|
restartRequired = true
|
||||||
}
|
}
|
||||||
if lc.Settings.LogSizeMax < 0 {
|
if lc.Settings.LogSizeMax < 0 {
|
||||||
n.log = nullLogger
|
n.infoLog = nullLogger
|
||||||
_ = n.logW.Close()
|
_ = n.infoLogW.Close()
|
||||||
n.logW = nil
|
n.infoLogW = nil
|
||||||
} else if n.logW != nil {
|
} else if n.infoLogW != nil {
|
||||||
n.logW, err = sizeLimitWriterOpen(path.Join(n.basePath, "service.log"))
|
n.infoLogW, err = sizeLimitWriterOpen(path.Join(n.basePath, "service.infoLog"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
n.log = log.New(n.logW, "", log.LstdFlags)
|
n.infoLog = log.New(n.infoLogW, "", log.LstdFlags)
|
||||||
} else {
|
} else {
|
||||||
n.log = nullLogger
|
n.infoLog = nullLogger
|
||||||
n.logW = nil
|
n.infoLogW = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,12 +490,12 @@ func (n *Node) SetLocalConfig(lc *LocalConfig) (restartRequired bool, err error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join joins a network
|
// Join a network.
|
||||||
// If tap is nil, the default system tap for this OS/platform is used (if available).
|
// If tap is nil, the default system tap for this OS/platform is used (if available).
|
||||||
func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*Network, error) {
|
func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*Network, error) {
|
||||||
n.networksLock.RLock()
|
n.networksLock.RLock()
|
||||||
if nw, have := n.networks[nwid]; have {
|
if nw, have := n.networks[nwid]; have {
|
||||||
n.log.Printf("join network %.16x ignored: already a member", nwid)
|
n.infoLog.Printf("join network %.16x ignored: already a member", nwid)
|
||||||
if settings != nil {
|
if settings != nil {
|
||||||
nw.SetLocalSettings(settings)
|
nw.SetLocalSettings(settings)
|
||||||
}
|
}
|
||||||
|
@ -476,13 +508,13 @@ func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*N
|
||||||
}
|
}
|
||||||
ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid))
|
ntap := C.ZT_GoNode_join(n.gn, C.uint64_t(nwid))
|
||||||
if ntap == nil {
|
if ntap == nil {
|
||||||
n.log.Printf("join network %.16x failed: tap device failed to initialize (check drivers / kernel modules)", uint64(nwid))
|
n.infoLog.Printf("join network %.16x failed: tap device failed to initialize (check drivers / kernel modules)", uint64(nwid))
|
||||||
return nil, ErrTapInitFailed
|
return nil, ErrTapInitFailed
|
||||||
}
|
}
|
||||||
|
|
||||||
nw, err := newNetwork(n, nwid, &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1})
|
nw, err := newNetwork(n, nwid, &nativeTap{tap: unsafe.Pointer(ntap), enabled: 1})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n.log.Printf("join network %.16x failed: network failed to initialize: %s", nwid, err.Error())
|
n.infoLog.Printf("join network %.16x failed: network failed to initialize: %s", nwid, err.Error())
|
||||||
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -496,14 +528,14 @@ func (n *Node) Join(nwid NetworkID, settings *NetworkLocalSettings, tap Tap) (*N
|
||||||
return nw, nil
|
return nw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave leaves a network
|
// Leave a network.
|
||||||
func (n *Node) Leave(nwid NetworkID) error {
|
func (n *Node) Leave(nwid NetworkID) error {
|
||||||
n.log.Printf("leaving network %.16x", nwid)
|
|
||||||
n.networksLock.Lock()
|
n.networksLock.Lock()
|
||||||
nw := n.networks[nwid]
|
nw := n.networks[nwid]
|
||||||
delete(n.networks, nwid)
|
delete(n.networks, nwid)
|
||||||
n.networksLock.Unlock()
|
n.networksLock.Unlock()
|
||||||
if nw != nil {
|
if nw != nil {
|
||||||
|
n.infoLog.Printf("leaving network %.16x", nwid)
|
||||||
nw.leaving()
|
nw.leaving()
|
||||||
}
|
}
|
||||||
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
C.ZT_GoNode_leave(n.gn, C.uint64_t(nwid))
|
||||||
|
@ -668,7 +700,7 @@ func (n *Node) stateObjectGet(objType int, id [2]uint64) ([]byte, bool) {
|
||||||
|
|
||||||
func (n *Node) handleTrace(traceMessage string) {
|
func (n *Node) handleTrace(traceMessage string) {
|
||||||
if len(traceMessage) > 0 {
|
if len(traceMessage) > 0 {
|
||||||
n.log.Print("TRACE: " + traceMessage)
|
n.infoLog.Print("TRACE: " + traceMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,25 @@
|
||||||
#ifndef ZT_ZEROTIER_API_H
|
#ifndef ZT_ZEROTIER_API_H
|
||||||
#define ZT_ZEROTIER_API_H
|
#define ZT_ZEROTIER_API_H
|
||||||
|
|
||||||
|
/* ZT_PACKED_STRUCT encloses structs whose contents should be bit-packed.
|
||||||
|
* Nearly all compilers support this. These macros detect the compiler and
|
||||||
|
* define it correctly for gcc/icc/clang or MSC. */
|
||||||
|
#ifndef ZT_PACKED_STRUCT
|
||||||
|
#if defined(__GCC__) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__INTEL_COMPILER) || defined(__clang__)
|
||||||
|
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
|
||||||
|
#define ZT_PACKED_STRUCT_START
|
||||||
|
#define ZT_PACKED_STRUCT_END __attribute__((packed))
|
||||||
|
#endif
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
|
||||||
|
#define ZT_PACKED_STRUCT_START __pragma(pack(push,1))
|
||||||
|
#define ZT_PACKED_STRUCT_END __pragma(pack(pop))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef ZT_PACKED_STRUCT
|
||||||
|
#error Missing a macro to define ZT_PACKED_STRUCT for your compiler.
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -26,26 +45,21 @@ extern "C" {
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* For struct sockaddr_storage, which is referenced here. */
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
#include <WinSock2.h>
|
#include <WinSock2.h>
|
||||||
#include <WS2tcpip.h>
|
#include <WS2tcpip.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#else /* not Windows */
|
#else
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#endif /* Windows or not */
|
#endif
|
||||||
|
|
||||||
/* This symbol may be defined in a build environment or before including this
|
|
||||||
* header if you need to prepend something to function specifications. */
|
|
||||||
#ifndef ZT_SDK_API
|
#ifndef ZT_SDK_API
|
||||||
#define ZT_SDK_API
|
#define ZT_SDK_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
/* Core constants */
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,13 +188,6 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7
|
#define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum number of multicast group subscriptions on a local virtual network interface
|
|
||||||
*
|
|
||||||
* This coincides with many operating systems' maximum values and is rather huge.
|
|
||||||
*/
|
|
||||||
#define ZT_MAX_MULTICAST_SUBSCRIPTIONS 1024
|
|
||||||
|
|
||||||
/* Rule specification contants **********************************************/
|
/* Rule specification contants **********************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -269,7 +276,310 @@ extern "C" {
|
||||||
#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL
|
#define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* Structures and other types */
|
|
||||||
|
/**
|
||||||
|
* Credential type IDs
|
||||||
|
*
|
||||||
|
* These are mostly used internally but are declared here so they can be used
|
||||||
|
* in trace messages.
|
||||||
|
*/
|
||||||
|
enum ZT_CredentialType
|
||||||
|
{
|
||||||
|
ZT_CREDENTIAL_TYPE_NULL = 0,
|
||||||
|
ZT_CREDENTIAL_TYPE_COM = 1,
|
||||||
|
ZT_CREDENTIAL_TYPE_CAPABILITY = 2,
|
||||||
|
ZT_CREDENTIAL_TYPE_TAG = 3,
|
||||||
|
ZT_CREDENTIAL_TYPE_COO = 4,
|
||||||
|
ZT_CREDENTIAL_TYPE_REVOCATION = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Trace events are sent and received as packed structures of a fixed size.
|
||||||
|
* Normally we don't use this form of brittle encoding but in this case the
|
||||||
|
* performance benefit is non-trivial as events are generated in critical
|
||||||
|
* areas of the code.
|
||||||
|
*
|
||||||
|
* NOTE: all integer fields larger than one byte are stored in big-endian
|
||||||
|
* "network" byte order in these structures. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that VL1 tracing should be generated
|
||||||
|
*/
|
||||||
|
#define ZT_TRACE_FLAG_VL1 0x01
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that VL2 (virtual network) tracing should be generated
|
||||||
|
*/
|
||||||
|
#define ZT_TRACE_FLAG_VL2 0x02
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that VL2 network filter tracing should be generated (separate because this can be very verbose)
|
||||||
|
*/
|
||||||
|
#define ZT_TRACE_FLAG_VL2_FILTER 0x04
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag indicating that VL2 multicast propagation should be reported
|
||||||
|
*/
|
||||||
|
#define ZT_TRACE_FLAG_VL2_MULTICAST 0x08
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace event types
|
||||||
|
*
|
||||||
|
* All trace event structures start with a size and type.
|
||||||
|
*/
|
||||||
|
enum ZT_TraceEventType
|
||||||
|
{
|
||||||
|
/* VL1 events related to the peer-to-peer layer */
|
||||||
|
ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE = 1,
|
||||||
|
ZT_TRACE_VL1_TRYING_NEW_PATH = 2,
|
||||||
|
ZT_TRACE_VL1_LEARNED_NEW_PATH = 3,
|
||||||
|
ZT_TRACE_VL1_INCOMING_PACKET_DROPPED = 4,
|
||||||
|
|
||||||
|
/* VL2 events relate to virtual networks, packet filtering, and authentication */
|
||||||
|
ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED = 100,
|
||||||
|
ZT_TRACE_VL2_INCOMING_FRAME_DROPPED = 101,
|
||||||
|
ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED = 102,
|
||||||
|
ZT_TRACE_VL2_NETWORK_FILTER = 103
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace VL1 packet drop reasons
|
||||||
|
*/
|
||||||
|
enum ZT_TracePacketDropReason
|
||||||
|
{
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED = 0,
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD = 1,
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET = 2,
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED = 3,
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 4,
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 5,
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA = 6,
|
||||||
|
ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace VL2 frame drop reasons
|
||||||
|
*/
|
||||||
|
enum ZT_TraceFrameDropReason
|
||||||
|
{
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_UNSPECIFIED = 0,
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE = 1,
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL = 2,
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED = 3,
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED = 4,
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED = 5,
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION = 6,
|
||||||
|
ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Address types for ZT_TraceEventPathAddress
|
||||||
|
*
|
||||||
|
* These are currently the same as the types in Endpoint.hpp and should remain so
|
||||||
|
* if possible for consistency. Not all of these are used (yet?) but they are defined
|
||||||
|
* for possible future use and the structure is sized to support them.
|
||||||
|
*/
|
||||||
|
enum ZT_TraceEventPathAddressType
|
||||||
|
{
|
||||||
|
ZT_TRACE_EVENT_PATH_TYPE_NIL = 0, /* none/empty */
|
||||||
|
ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V4 = 1, /* 4-byte IPv4 */
|
||||||
|
ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V6 = 2, /* 16-byte IPv6 */
|
||||||
|
ZT_TRACE_EVENT_PATH_TYPE_DNSNAME = 3, /* C string */
|
||||||
|
ZT_TRACE_EVENT_PATH_TYPE_ZEROTIER = 4, /* 5-byte ZeroTier + 48-byte identity hash */
|
||||||
|
ZT_TRACE_EVENT_PATH_TYPE_URL = 5, /* C string */
|
||||||
|
ZT_TRACE_EVENT_PATH_TYPE_ETHERNET = 6 /* 6-byte Ethernet */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reasons for trying new paths
|
||||||
|
*/
|
||||||
|
enum ZT_TraceTryingNewPathReason
|
||||||
|
{
|
||||||
|
ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH = 1,
|
||||||
|
ZT_TRACE_TRYING_NEW_PATH_REASON_RECEIVED_PUSH_DIRECT_PATHS = 2,
|
||||||
|
ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reasons for credential rejection
|
||||||
|
*/
|
||||||
|
enum ZT_TraceCredentialRejectionReason
|
||||||
|
{
|
||||||
|
ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED = 1,
|
||||||
|
ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED = 2,
|
||||||
|
ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST = 3,
|
||||||
|
ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Physical path address from a trace event
|
||||||
|
*
|
||||||
|
* This is a special packed address format that roughly mirrors Endpoint in the core
|
||||||
|
* and is designed to support both present and future address types.
|
||||||
|
*/
|
||||||
|
ZT_PACKED_STRUCT(struct ZT_TraceEventPathAddress
|
||||||
|
{
|
||||||
|
uint8_t type; /* ZT_TraceEventPathAddressType */
|
||||||
|
uint8_t address[63]; /* Type-dependent address: 4-byte IPv4, 16-byte IPV6, etc. */
|
||||||
|
uint16_t port; /* UDP/TCP port for address types for which this is meaningful */
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Header for all trace events
|
||||||
|
*
|
||||||
|
* All packet types begin with these fields in this order.
|
||||||
|
*/
|
||||||
|
ZT_PACKED_STRUCT(struct ZT_TraceEvent
|
||||||
|
{
|
||||||
|
uint16_t evSize; /* sizeof(ZT_TraceEvent_XX structure) (inclusive size in bytes) */
|
||||||
|
uint16_t evType; /* ZT_TraceEventType */
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Temporary macros to make it easier to declare all ZT_TraceEvent's sub-types */
|
||||||
|
#define _ZT_TRACE_EVENT_STRUCT_START(e) ZT_PACKED_STRUCT_START struct ZT_TraceEvent_##e { \
|
||||||
|
uint16_t evSize; \
|
||||||
|
uint16_t evType;
|
||||||
|
#define _ZT_TRACE_EVENT_STRUCT_END() } ZT_PACKED_STRUCT_END;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node is resetting all paths in a given address scope
|
||||||
|
*
|
||||||
|
* This happens when the node detects and external surface IP addressing change
|
||||||
|
* via a trusted (usually root) peer. It's used to renegotiate links when nodes
|
||||||
|
* move around on the network.
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL1_RESETTING_PATHS_IN_SCOPE)
|
||||||
|
uint64_t reporter; /* ZeroTier address that triggered the reset */
|
||||||
|
uint8_t reporterIdentityHash[48]; /* full identity hash of triggering node's identity */
|
||||||
|
struct ZT_TraceEventPathAddress from; /* physical origin of triggering packet */
|
||||||
|
struct ZT_TraceEventPathAddress oldExternal; /* previous detected external address */
|
||||||
|
struct ZT_TraceEventPathAddress newExternal; /* new detected external address */
|
||||||
|
uint8_t scope; /* IP scope being reset */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node is trying a new path
|
||||||
|
*
|
||||||
|
* Paths are tried in response to PUSH_DIRECT_PATHS, RENDEZVOUS, and other places
|
||||||
|
* we might hear of them. A node tries a path by sending a trial message to it.
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL1_TRYING_NEW_PATH)
|
||||||
|
uint64_t address; /* short address of node we're trying to reach */
|
||||||
|
uint8_t identityHash[48]; /* identity hash of node we're trying to reach */
|
||||||
|
struct ZT_TraceEventPathAddress physicalAddress; /* physical address being tried */
|
||||||
|
struct ZT_TraceEventPathAddress triggerAddress; /* physical origin of triggering packet */
|
||||||
|
uint64_t triggeringPacketId; /* packet ID of triggering packet */
|
||||||
|
uint8_t triggeringPacketVerb; /* packet verb of triggering packet */
|
||||||
|
uint64_t triggeredByAddress; /* short address of node triggering attempt */
|
||||||
|
uint8_t triggeredByIdentityHash[48]; /* full identity hash of node triggering attempt */
|
||||||
|
uint8_t reason; /* ZT_TraceTryingNewPathReason */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node has learned a new path to another node
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL1_LEARNED_NEW_PATH)
|
||||||
|
uint64_t packetId; /* packet ID of confirming packet */
|
||||||
|
uint64_t address; /* short address of learned peer */
|
||||||
|
uint8_t identityHash[48]; /* full identity hash of learned peer */
|
||||||
|
struct ZT_TraceEventPathAddress physicalAddress; /* physical address learned */
|
||||||
|
struct ZT_TraceEventPathAddress replaced; /* if non-empty, an older address that was replaced */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An incoming packet was dropped at the VL1 level
|
||||||
|
*
|
||||||
|
* This indicates a packet that passed MAC check but was dropped for some other
|
||||||
|
* reason such as rate limits, being malformed, etc.
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL1_INCOMING_PACKET_DROPPED)
|
||||||
|
uint64_t packetId; /* packet ID of failed packet */
|
||||||
|
uint64_t networkId; /* VL2 network ID or 0 if unrelated to a network or unknown */
|
||||||
|
uint64_t address; /* short address that sent packet */
|
||||||
|
uint8_t identityHash[48]; /* full identity hash of sending node */
|
||||||
|
struct ZT_TraceEventPathAddress physicalAddress; /* physical origin address of packet */
|
||||||
|
uint8_t hops; /* hop count of packet */
|
||||||
|
uint8_t verb; /* packet verb */
|
||||||
|
uint8_t reason; /* ZT_TracePacketDropReason */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node declined to send a packet read from a local network port/tap
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL2_OUTGOING_FRAME_DROPPED)
|
||||||
|
uint64_t networkId; /* network ID */
|
||||||
|
uint64_t sourceMac; /* source MAC address */
|
||||||
|
uint64_t destMac; /* destination MAC address */
|
||||||
|
uint16_t etherType; /* Ethernet type of frame */
|
||||||
|
uint16_t frameLength; /* length of dropped frame */
|
||||||
|
uint8_t frameHead[64]; /* first up to 64 bytes of dropped frame */
|
||||||
|
uint8_t reason; /* ZT_TraceFrameDropReason */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An incoming frame was dropped
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL2_INCOMING_FRAME_DROPPED)
|
||||||
|
uint64_t packetId; /* VL1 packet ID */
|
||||||
|
uint64_t networkId; /* VL2 network ID */
|
||||||
|
uint64_t sourceMac; /* 48-bit source MAC */
|
||||||
|
uint64_t destMac; /* 48-bit destination MAC */
|
||||||
|
uint64_t address; /* short address of sending peer */
|
||||||
|
struct ZT_TraceEventPathAddress physicalAddress; /* physical source address of packet */
|
||||||
|
uint8_t hops; /* hop count of packet */
|
||||||
|
uint16_t frameLength; /* length of frame in bytes */
|
||||||
|
uint8_t frameHead[64]; /* first up to 64 bytes of dropped frame */
|
||||||
|
uint8_t verb; /* packet verb indicating how frame was sent */
|
||||||
|
uint8_t credentialRequestSent; /* if non-zero a request for credentials was sent */
|
||||||
|
uint8_t reason; /* ZT_TraceFrameDropReason */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node is requesting a new network config and certificate from a network controller
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL2_NETWORK_CONFIG_REQUESTED)
|
||||||
|
uint64_t networkId; /* VL2 network ID */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Network filter trace results
|
||||||
|
*
|
||||||
|
* These are generated when filter tracing is enabled to allow filters to be debugged.
|
||||||
|
* Format for rule set logs is documented elsewhere.
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL2_NETWORK_FILTER)
|
||||||
|
uint64_t networkId; /* VL2 network ID */
|
||||||
|
uint8_t primaryRuleSetLog[512]; /* primary rule set log */
|
||||||
|
uint8_t matchingCapabilityRuleSetLog[512]; /* capability rule set log (if any) */
|
||||||
|
uint32_t matchingCapabilityId; /* capability ID or 0 if none */
|
||||||
|
int64_t matchingCapabilityTimestamp; /* capability timestamp or 0 if none */
|
||||||
|
uint64_t source; /* source ZeroTier address */
|
||||||
|
uint64_t dest; /* destination ZeroTier address */
|
||||||
|
uint64_t sourceMac; /* packet source MAC */
|
||||||
|
uint64_t destMac; /* packet destination MAC */
|
||||||
|
uint16_t frameLength; /* length of filtered frame */
|
||||||
|
uint8_t frameHead[64]; /* first up to 64 bytes of filtered frame */
|
||||||
|
uint16_t etherType; /* frame Ethernet type */
|
||||||
|
uint16_t vlanId; /* frame VLAN ID (currently unused, always 0) */
|
||||||
|
uint8_t noTee; /* if true noTee flag was set in filter */
|
||||||
|
uint8_t inbound; /* direction: 1 for inbound, 0 for outbound */
|
||||||
|
int8_t accept; /* 0: drop, 1: accept, 2: "super-accept" */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An incoming credential from a peer was rejected
|
||||||
|
*/
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_START(VL2_CREDENTIAL_REJECTED)
|
||||||
|
uint64_t networkId; /* VL2 network ID */
|
||||||
|
uint64_t address; /* short address of sender */
|
||||||
|
uint32_t credentialId; /* credential ID */
|
||||||
|
int64_t credentialTimestamp; /* credential timestamp */
|
||||||
|
uint8_t credentialType; /* credential type */
|
||||||
|
uint8_t reason; /* ZT_TraceCredentialRejectionReason */
|
||||||
|
_ZT_TRACE_EVENT_STRUCT_END()
|
||||||
|
|
||||||
|
#undef _ZT_TRACE_EVENT_STRUCT_START
|
||||||
|
#undef _ZT_TRACE_EVENT_STRUCT_END
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -390,7 +700,7 @@ enum ZT_Event
|
||||||
* These events are only generated if this is a TRACE-enabled build.
|
* These events are only generated if this is a TRACE-enabled build.
|
||||||
* This is for local debug traces, not remote trace diagnostics.
|
* This is for local debug traces, not remote trace diagnostics.
|
||||||
*
|
*
|
||||||
* Meta-data: C string, TRACE message
|
* Meta-data: struct of type ZT_Trace_*
|
||||||
*/
|
*/
|
||||||
ZT_EVENT_TRACE = 5,
|
ZT_EVENT_TRACE = 5,
|
||||||
|
|
||||||
|
@ -1164,8 +1474,6 @@ enum ZT_StateObjectType
|
||||||
*/
|
*/
|
||||||
typedef void ZT_Node;
|
typedef void ZT_Node;
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
/* Callbacks used by Node API */
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1357,8 +1665,6 @@ typedef int (*ZT_PathLookupFunction)(
|
||||||
struct sockaddr_storage *); /* Result buffer */
|
struct sockaddr_storage *); /* Result buffer */
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* C Node API */
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure for configuring ZeroTier core callback functions
|
* Structure for configuring ZeroTier core callback functions
|
||||||
|
@ -1735,6 +2041,8 @@ ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterIns
|
||||||
*/
|
*/
|
||||||
ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
|
ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a new identity
|
* Generate a new identity
|
||||||
*
|
*
|
||||||
|
@ -1844,6 +2152,8 @@ ZT_SDK_API void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int include
|
||||||
*/
|
*/
|
||||||
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id);
|
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get ZeroTier One version
|
* Get ZeroTier One version
|
||||||
*
|
*
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
static inline uint32_t readuint32_t(const void *in)
|
static inline uint32_t readuint32_t(const void *in)
|
||||||
{
|
{
|
||||||
uint32_t v = ((const uint8_t *)in)[0];
|
uint32_t v = ((const uint8_t *)in)[0];
|
||||||
|
@ -161,7 +161,7 @@ void AES::_ctrSW(const uint8_t iv[16],const void *in,unsigned int len,void *out)
|
||||||
while (len >= 16) {
|
while (len >= 16) {
|
||||||
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
|
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
|
||||||
ctr[1] = Utils::hton(++bctr);
|
ctr[1] = Utils::hton(++bctr);
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
for(unsigned int k=0;k<16;++k)
|
for(unsigned int k=0;k<16;++k)
|
||||||
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
|
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
|
||||||
#else
|
#else
|
||||||
|
@ -339,7 +339,7 @@ void AES::_gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_
|
||||||
uint64_t y0 = 0,y1 = 0;
|
uint64_t y0 = 0,y1 = 0;
|
||||||
|
|
||||||
while (len >= 16) {
|
while (len >= 16) {
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y0)[i] ^= *(in++);
|
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y0)[i] ^= *(in++);
|
||||||
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y1)[i] ^= *(in++);
|
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y1)[i] ^= *(in++);
|
||||||
#else
|
#else
|
||||||
|
@ -369,7 +369,7 @@ void AES::_gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_
|
||||||
((uint8_t *)iv2)[14] = 0;
|
((uint8_t *)iv2)[14] = 0;
|
||||||
((uint8_t *)iv2)[15] = 1;
|
((uint8_t *)iv2)[15] = 1;
|
||||||
_encryptSW((const uint8_t *)iv2,(uint8_t *)iv2);
|
_encryptSW((const uint8_t *)iv2,(uint8_t *)iv2);
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
for(unsigned int i=0;i<8;++i) out[i] = ((const uint8_t *)&y0)[i] ^ ((const uint8_t *)iv2)[i];
|
for(unsigned int i=0;i<8;++i) out[i] = ((const uint8_t *)&y0)[i] ^ ((const uint8_t *)iv2)[i];
|
||||||
for(unsigned int i=8;i<16;++i) out[i] = ((const uint8_t *)&y1)[i-8] ^ ((const uint8_t *)iv2)[i];
|
for(unsigned int i=8;i<16;++i) out[i] = ((const uint8_t *)&y1)[i-8] ^ ((const uint8_t *)iv2)[i];
|
||||||
#else
|
#else
|
||||||
|
|
12
node/Buf.hpp
12
node/Buf.hpp
|
@ -145,7 +145,7 @@ public:
|
||||||
{
|
{
|
||||||
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
||||||
ii += 2;
|
ii += 2;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
return (
|
return (
|
||||||
((uint16_t)data[s] << 8U) |
|
((uint16_t)data[s] << 8U) |
|
||||||
(uint16_t)data[s + 1]);
|
(uint16_t)data[s + 1]);
|
||||||
|
@ -164,7 +164,7 @@ public:
|
||||||
{
|
{
|
||||||
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
||||||
ii += 4;
|
ii += 4;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
return (
|
return (
|
||||||
((uint32_t)data[s] << 24U) |
|
((uint32_t)data[s] << 24U) |
|
||||||
((uint32_t)data[s + 1] << 16U) |
|
((uint32_t)data[s + 1] << 16U) |
|
||||||
|
@ -185,7 +185,7 @@ public:
|
||||||
{
|
{
|
||||||
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
||||||
ii += 8;
|
ii += 8;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
return (
|
return (
|
||||||
((uint64_t)data[s] << 56U) |
|
((uint64_t)data[s] << 56U) |
|
||||||
((uint64_t)data[s + 1] << 48U) |
|
((uint64_t)data[s + 1] << 48U) |
|
||||||
|
@ -340,7 +340,7 @@ public:
|
||||||
{
|
{
|
||||||
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
ii += 2;
|
ii += 2;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
data[s] = (uint8_t)(n >> 8U);
|
data[s] = (uint8_t)(n >> 8U);
|
||||||
data[s + 1] = (uint8_t)n;
|
data[s + 1] = (uint8_t)n;
|
||||||
#else
|
#else
|
||||||
|
@ -358,7 +358,7 @@ public:
|
||||||
{
|
{
|
||||||
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
ii += 4;
|
ii += 4;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
data[s] = (uint8_t)(n >> 24U);
|
data[s] = (uint8_t)(n >> 24U);
|
||||||
data[s + 1] = (uint8_t)(n >> 16U);
|
data[s + 1] = (uint8_t)(n >> 16U);
|
||||||
data[s + 2] = (uint8_t)(n >> 8U);
|
data[s + 2] = (uint8_t)(n >> 8U);
|
||||||
|
@ -378,7 +378,7 @@ public:
|
||||||
{
|
{
|
||||||
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
ii += 8;
|
ii += 8;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
data[s] = (uint8_t)(n >> 56U);
|
data[s] = (uint8_t)(n >> 56U);
|
||||||
data[s + 1] = (uint8_t)(n >> 48U);
|
data[s + 1] = (uint8_t)(n >> 48U);
|
||||||
data[s + 2] = (uint8_t)(n >> 40U);
|
data[s + 2] = (uint8_t)(n >> 40U);
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
#if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING))
|
#if defined(__GNUC__) && (!defined(ZT_NO_UNALIGNED_ACCESS))
|
||||||
#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
|
#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
|
||||||
#else
|
#else
|
||||||
#define ZT_VAR_MAY_ALIAS
|
#define ZT_VAR_MAY_ALIAS
|
||||||
|
@ -171,7 +171,7 @@ public:
|
||||||
{
|
{
|
||||||
if (unlikely((i + sizeof(T)) > _l))
|
if (unlikely((i + sizeof(T)) > _l))
|
||||||
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
|
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
|
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
|
||||||
for(unsigned int x=1;x<=sizeof(T);++x)
|
for(unsigned int x=1;x<=sizeof(T);++x)
|
||||||
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
|
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
|
||||||
|
@ -193,7 +193,7 @@ public:
|
||||||
{
|
{
|
||||||
if (unlikely((i + sizeof(T)) > _l))
|
if (unlikely((i + sizeof(T)) > _l))
|
||||||
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
|
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
T v = 0;
|
T v = 0;
|
||||||
const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
|
const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
|
||||||
for(unsigned int x=0;x<sizeof(T);++x) {
|
for(unsigned int x=0;x<sizeof(T);++x) {
|
||||||
|
@ -219,7 +219,7 @@ public:
|
||||||
{
|
{
|
||||||
if (unlikely((_l + sizeof(T)) > C))
|
if (unlikely((_l + sizeof(T)) > C))
|
||||||
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
|
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
|
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
|
||||||
for(unsigned int x=1;x<=sizeof(T);++x)
|
for(unsigned int x=1;x<=sizeof(T);++x)
|
||||||
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
|
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
|
||||||
|
|
|
@ -73,6 +73,7 @@ set(core_src
|
||||||
SHA512.cpp
|
SHA512.cpp
|
||||||
Switch.cpp
|
Switch.cpp
|
||||||
Topology.cpp
|
Topology.cpp
|
||||||
|
Trace.cpp
|
||||||
Utils.cpp
|
Utils.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Capability : public Credential
|
||||||
friend class Credential;
|
friend class Credential;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; }
|
static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_CAPABILITY; }
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Capability() :
|
ZT_ALWAYS_INLINE Capability() :
|
||||||
_nwid(0),
|
_nwid(0),
|
||||||
|
|
|
@ -69,7 +69,7 @@ class CertificateOfMembership : public Credential
|
||||||
friend class Credential;
|
friend class Credential;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; }
|
static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_COM; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reserved qualifier IDs
|
* Reserved qualifier IDs
|
||||||
|
@ -101,7 +101,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Create an empty certificate of membership
|
* Create an empty certificate of membership
|
||||||
*/
|
*/
|
||||||
inline CertificateOfMembership() :
|
ZT_ALWAYS_INLINE CertificateOfMembership() :
|
||||||
_qualifierCount(0),
|
_qualifierCount(0),
|
||||||
_signatureLength(0) {}
|
_signatureLength(0) {}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ public:
|
||||||
* @param nwid Network ID
|
* @param nwid Network ID
|
||||||
* @param issuedTo Certificate recipient
|
* @param issuedTo Certificate recipient
|
||||||
*/
|
*/
|
||||||
inline CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
|
ZT_ALWAYS_INLINE CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
|
||||||
{
|
{
|
||||||
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
|
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
|
||||||
_qualifiers[0].value = timestamp;
|
_qualifiers[0].value = timestamp;
|
||||||
|
@ -135,22 +135,22 @@ public:
|
||||||
* @param startAt Position to start in buffer
|
* @param startAt Position to start in buffer
|
||||||
*/
|
*/
|
||||||
template<unsigned int C>
|
template<unsigned int C>
|
||||||
inline CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
|
ZT_ALWAYS_INLINE CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if there's something here
|
* @return True if there's something here
|
||||||
*/
|
*/
|
||||||
inline operator bool() const { return (_qualifierCount != 0); }
|
ZT_ALWAYS_INLINE operator bool() const { return (_qualifierCount != 0); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Credential ID, always 0 for COMs
|
* @return Credential ID, always 0 for COMs
|
||||||
*/
|
*/
|
||||||
inline uint32_t id() const { return 0; }
|
ZT_ALWAYS_INLINE uint32_t id() const { return 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Timestamp for this cert and maximum delta for timestamp
|
* @return Timestamp for this cert and maximum delta for timestamp
|
||||||
*/
|
*/
|
||||||
inline int64_t timestamp() const
|
ZT_ALWAYS_INLINE int64_t timestamp() const
|
||||||
{
|
{
|
||||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||||
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)
|
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)
|
||||||
|
@ -162,7 +162,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return Address to which this cert was issued
|
* @return Address to which this cert was issued
|
||||||
*/
|
*/
|
||||||
inline Address issuedTo() const
|
ZT_ALWAYS_INLINE Address issuedTo() const
|
||||||
{
|
{
|
||||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||||
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO)
|
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO)
|
||||||
|
@ -174,7 +174,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return Network ID for which this cert was issued
|
* @return Network ID for which this cert was issued
|
||||||
*/
|
*/
|
||||||
inline uint64_t networkId() const
|
ZT_ALWAYS_INLINE uint64_t networkId() const
|
||||||
{
|
{
|
||||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||||
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID)
|
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID)
|
||||||
|
@ -192,7 +192,7 @@ public:
|
||||||
* @param value Qualifier value
|
* @param value Qualifier value
|
||||||
* @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
|
* @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
|
||||||
*/
|
*/
|
||||||
inline void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
|
ZT_ALWAYS_INLINE void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
|
||||||
{
|
{
|
||||||
_signedBy.zero();
|
_signedBy.zero();
|
||||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||||
|
@ -211,7 +211,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
|
ZT_ALWAYS_INLINE void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two certificates for parameter agreement
|
* Compare two certificates for parameter agreement
|
||||||
|
@ -226,7 +226,7 @@ public:
|
||||||
* @param other Cert to compare with
|
* @param other Cert to compare with
|
||||||
* @return True if certs agree and 'other' may be communicated with
|
* @return True if certs agree and 'other' may be communicated with
|
||||||
*/
|
*/
|
||||||
inline bool agreesWith(const CertificateOfMembership &other) const
|
ZT_ALWAYS_INLINE bool agreesWith(const CertificateOfMembership &other) const
|
||||||
{
|
{
|
||||||
unsigned int myidx = 0;
|
unsigned int myidx = 0;
|
||||||
unsigned int otheridx = 0;
|
unsigned int otheridx = 0;
|
||||||
|
@ -268,7 +268,7 @@ public:
|
||||||
* @param with Identity to sign with, must include private key
|
* @param with Identity to sign with, must include private key
|
||||||
* @return True if signature was successful
|
* @return True if signature was successful
|
||||||
*/
|
*/
|
||||||
inline bool sign(const Identity &with)
|
ZT_ALWAYS_INLINE bool sign(const Identity &with)
|
||||||
{
|
{
|
||||||
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
|
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
|
||||||
unsigned int ptr = 0;
|
unsigned int ptr = 0;
|
||||||
|
@ -294,17 +294,12 @@ public:
|
||||||
* @param RR Runtime environment for looking up peers
|
* @param RR Runtime environment for looking up peers
|
||||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||||
*/
|
*/
|
||||||
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
|
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
|
||||||
|
|
||||||
/**
|
|
||||||
* @return True if signed
|
|
||||||
*/
|
|
||||||
inline bool isSigned() const { return (_signedBy); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Address that signed this certificate or null address if none
|
* @return Address that signed this certificate or null address if none
|
||||||
*/
|
*/
|
||||||
inline const Address &signedBy() const { return _signedBy; }
|
ZT_ALWAYS_INLINE const Address &signedBy() const { return _signedBy; }
|
||||||
|
|
||||||
template<unsigned int C>
|
template<unsigned int C>
|
||||||
inline void serialize(Buffer<C> &b) const
|
inline void serialize(Buffer<C> &b) const
|
||||||
|
@ -369,7 +364,7 @@ public:
|
||||||
return (p - startAt);
|
return (p - startAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const CertificateOfMembership &c) const
|
ZT_ALWAYS_INLINE bool operator==(const CertificateOfMembership &c) const
|
||||||
{
|
{
|
||||||
if (_signedBy != c._signedBy)
|
if (_signedBy != c._signedBy)
|
||||||
return false;
|
return false;
|
||||||
|
@ -385,7 +380,7 @@ public:
|
||||||
}
|
}
|
||||||
return (memcmp(_signature,c._signature,_signatureLength) == 0);
|
return (memcmp(_signature,c._signature,_signatureLength) == 0);
|
||||||
}
|
}
|
||||||
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
|
ZT_ALWAYS_INLINE bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct _Qualifier
|
struct _Qualifier
|
||||||
|
|
|
@ -46,7 +46,7 @@ class CertificateOfOwnership : public Credential
|
||||||
friend class Credential;
|
friend class Credential;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
|
static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_COO; }
|
||||||
|
|
||||||
enum Thing
|
enum Thing
|
||||||
{
|
{
|
||||||
|
@ -56,12 +56,12 @@ public:
|
||||||
THING_IPV6_ADDRESS = 3
|
THING_IPV6_ADDRESS = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
inline CertificateOfOwnership()
|
ZT_ALWAYS_INLINE CertificateOfOwnership()
|
||||||
{
|
{
|
||||||
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
|
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id)
|
ZT_ALWAYS_INLINE CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id)
|
||||||
{
|
{
|
||||||
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
|
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
|
||||||
_networkId = nwid;
|
_networkId = nwid;
|
||||||
|
@ -70,19 +70,19 @@ public:
|
||||||
_issuedTo = issuedTo;
|
_issuedTo = issuedTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t networkId() const { return _networkId; }
|
ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
|
||||||
inline int64_t timestamp() const { return _ts; }
|
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
|
||||||
inline uint32_t id() const { return _id; }
|
ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
|
||||||
inline const Address &issuedTo() const { return _issuedTo; }
|
ZT_ALWAYS_INLINE const Address &issuedTo() const { return _issuedTo; }
|
||||||
inline const Address &signer() const { return _signedBy; }
|
ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
|
||||||
inline const uint8_t *signature() const { return _signature; }
|
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
|
||||||
inline unsigned int signatureLength() const { return _signatureLength; }
|
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
|
||||||
|
|
||||||
inline unsigned int thingCount() const { return (unsigned int)_thingCount; }
|
ZT_ALWAYS_INLINE unsigned int thingCount() const { return (unsigned int)_thingCount; }
|
||||||
inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; }
|
ZT_ALWAYS_INLINE Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; }
|
||||||
inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
|
ZT_ALWAYS_INLINE const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
|
||||||
|
|
||||||
inline bool owns(const InetAddress &ip) const
|
ZT_ALWAYS_INLINE bool owns(const InetAddress &ip) const
|
||||||
{
|
{
|
||||||
if (ip.ss_family == AF_INET)
|
if (ip.ss_family == AF_INET)
|
||||||
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
|
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
|
||||||
|
@ -91,14 +91,14 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool owns(const MAC &mac) const
|
ZT_ALWAYS_INLINE bool owns(const MAC &mac) const
|
||||||
{
|
{
|
||||||
uint8_t tmp[6];
|
uint8_t tmp[6];
|
||||||
mac.copyTo(tmp,6);
|
mac.copyTo(tmp,6);
|
||||||
return this->_owns(THING_MAC_ADDRESS,tmp,6);
|
return this->_owns(THING_MAC_ADDRESS,tmp,6);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void addThing(const InetAddress &ip)
|
ZT_ALWAYS_INLINE void addThing(const InetAddress &ip)
|
||||||
{
|
{
|
||||||
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
|
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
|
||||||
if (ip.ss_family == AF_INET) {
|
if (ip.ss_family == AF_INET) {
|
||||||
|
@ -112,7 +112,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void addThing(const MAC &mac)
|
ZT_ALWAYS_INLINE void addThing(const MAC &mac)
|
||||||
{
|
{
|
||||||
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
|
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
|
||||||
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
|
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
|
||||||
|
@ -124,7 +124,7 @@ public:
|
||||||
* @param signer Signing identity, must have private key
|
* @param signer Signing identity, must have private key
|
||||||
* @return True if signature was successful
|
* @return True if signature was successful
|
||||||
*/
|
*/
|
||||||
inline bool sign(const Identity &signer)
|
ZT_ALWAYS_INLINE bool sign(const Identity &signer)
|
||||||
{
|
{
|
||||||
if (signer.hasPrivate()) {
|
if (signer.hasPrivate()) {
|
||||||
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
|
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
|
||||||
|
@ -136,7 +136,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
|
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
|
||||||
|
|
||||||
template<unsigned int C>
|
template<unsigned int C>
|
||||||
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
||||||
|
@ -206,13 +206,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provides natural sort order by ID
|
// Provides natural sort order by ID
|
||||||
inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
|
ZT_ALWAYS_INLINE bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
|
||||||
|
|
||||||
inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); }
|
ZT_ALWAYS_INLINE bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); }
|
||||||
inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
|
ZT_ALWAYS_INLINE bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline bool _owns(const Thing &t,const void *v,unsigned int l) const
|
ZT_ALWAYS_INLINE bool _owns(const Thing &t,const void *v,unsigned int l) const
|
||||||
{
|
{
|
||||||
for(unsigned int i=0,j=_thingCount;i<j;++i) {
|
for(unsigned int i=0,j=_thingCount;i<j;++i) {
|
||||||
if (_thingTypes[i] == (uint8_t)t) {
|
if (_thingTypes[i] == (uint8_t)t) {
|
||||||
|
|
|
@ -118,18 +118,18 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Period between keepalives sent to paths if no other traffic has been sent
|
* Period between keepalives sent to paths if no other traffic has been sent
|
||||||
*
|
|
||||||
* See https://conferences.sigcomm.org/imc/2010/papers/p260.pdf for
|
|
||||||
* some real world data on NAT UDP timeouts. From the paper: "the
|
|
||||||
* lowest measured timeout when a binding has seen bidirectional
|
|
||||||
* traffic is 54 sec." 30 seconds is faster than really necessary.
|
|
||||||
*/
|
*/
|
||||||
#define ZT_PATH_KEEPALIVE_PERIOD 30000
|
#define ZT_PATH_KEEPALIVE_PERIOD 20000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeout for path aliveness (measured from last receive)
|
* Timeout for path alive-ness (measured from last receive)
|
||||||
*/
|
*/
|
||||||
#define ZT_PATH_ACTIVITY_TIMEOUT ((ZT_PATH_KEEPALIVE_PERIOD * 2) + 5000)
|
#define ZT_PATH_ALIVE_TIMEOUT ((ZT_PATH_KEEPALIVE_PERIOD * 2) + 5000)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timeout for path active-ness (measured from last receive)
|
||||||
|
*/
|
||||||
|
#define ZT_PATH_ACTIVITY_TIMEOUT (ZT_PATH_KEEPALIVE_PERIOD + 5000)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay between full HELLO messages between peers
|
* Delay between full HELLO messages between peers
|
||||||
|
@ -137,12 +137,12 @@
|
||||||
#define ZT_PEER_PING_PERIOD 60000
|
#define ZT_PEER_PING_PERIOD 60000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeout for overall peer activity (measured from last receive)
|
* Timeout for peer alive-ness (measured from last receive)
|
||||||
*/
|
*/
|
||||||
#define ZT_PEER_ALIVE_TIMEOUT ((ZT_PEER_PING_PERIOD * 2) + 5000)
|
#define ZT_PEER_ALIVE_TIMEOUT ((ZT_PEER_PING_PERIOD * 2) + 5000)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeout for overall peer activity (measured from last receive)
|
* Timeout for peer active-ness (measured from last receive)
|
||||||
*/
|
*/
|
||||||
#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_PING_PERIOD + 5000)
|
#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_PING_PERIOD + 5000)
|
||||||
|
|
||||||
|
|
|
@ -40,19 +40,6 @@ class RuntimeEnvironment;
|
||||||
class Credential
|
class Credential
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* Do not change type code IDs -- these are used in Revocation objects and elsewhere
|
|
||||||
*/
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
CREDENTIAL_TYPE_NULL = 0,
|
|
||||||
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
|
|
||||||
CREDENTIAL_TYPE_CAPABILITY = 2,
|
|
||||||
CREDENTIAL_TYPE_TAG = 3,
|
|
||||||
CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership
|
|
||||||
CREDENTIAL_TYPE_REVOCATION = 6
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Result of verify() operations
|
* Result of verify() operations
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -19,12 +19,13 @@ bool Endpoint::operator==(const Endpoint &ep) const
|
||||||
{
|
{
|
||||||
if (_t == ep._t) {
|
if (_t == ep._t) {
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
case INETADDR: return (inetAddr() == ep.inetAddr());
|
default: return true;
|
||||||
case DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0));
|
case INETADDR_V4:
|
||||||
case ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0));
|
case INETADDR_V6: return (inetAddr() == ep.inetAddr());
|
||||||
case URL: return (strcmp(_v.url,ep._v.url) == 0);
|
case DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0));
|
||||||
case ETHERNET: return (_v.eth == ep._v.eth);
|
case ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0));
|
||||||
default: return true;
|
case URL: return (strcmp(_v.url,ep._v.url) == 0);
|
||||||
|
case ETHERNET: return (_v.eth == ep._v.eth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -37,7 +38,9 @@ bool Endpoint::operator<(const Endpoint &ep) const
|
||||||
} else if (_t == ep._t) {
|
} else if (_t == ep._t) {
|
||||||
int ncmp;
|
int ncmp;
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
case INETADDR: return (inetAddr() < ep.inetAddr());
|
case INETADDR_V4:
|
||||||
|
case INETADDR_V6:
|
||||||
|
return (inetAddr() < ep.inetAddr());
|
||||||
case DNSNAME:
|
case DNSNAME:
|
||||||
ncmp = strcmp(_v.dns.name,ep._v.dns.name);
|
ncmp = strcmp(_v.dns.name,ep._v.dns.name);
|
||||||
return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
|
return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
|
||||||
|
@ -58,7 +61,8 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const
|
||||||
Utils::storeBigEndian(data + 3,(int16_t)_l[1]);
|
Utils::storeBigEndian(data + 3,(int16_t)_l[1]);
|
||||||
Utils::storeBigEndian(data + 5,(int16_t)_l[2]);
|
Utils::storeBigEndian(data + 5,(int16_t)_l[2]);
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
case INETADDR:
|
case INETADDR_V4:
|
||||||
|
case INETADDR_V6:
|
||||||
return 7 + reinterpret_cast<const InetAddress *>(&_v.sa)->marshal(data+1);
|
return 7 + reinterpret_cast<const InetAddress *>(&_v.sa)->marshal(data+1);
|
||||||
case DNSNAME:
|
case DNSNAME:
|
||||||
p = 7;
|
p = 7;
|
||||||
|
@ -116,7 +120,8 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len)
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
case NIL:
|
case NIL:
|
||||||
return 7;
|
return 7;
|
||||||
case INETADDR:
|
case INETADDR_V4:
|
||||||
|
case INETADDR_V6:
|
||||||
return 7 + reinterpret_cast<InetAddress *>(&_v.sa)->unmarshal(data+7,len-7);
|
return 7 + reinterpret_cast<InetAddress *>(&_v.sa)->unmarshal(data+7,len-7);
|
||||||
case DNSNAME:
|
case DNSNAME:
|
||||||
if (len < 10)
|
if (len < 10)
|
||||||
|
|
|
@ -40,13 +40,14 @@ class Endpoint
|
||||||
public:
|
public:
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
NIL = 0, // NIL value
|
NIL = 0, // NIL value
|
||||||
INETADDR = 1, // InetAddress (v4 or v6)
|
INETADDR_V4 = 1, // IPv4
|
||||||
DNSNAME = 2, // DNS name and port that resolves to InetAddress
|
INETADDR_V6 = 2, // IPv6
|
||||||
ZEROTIER = 3, // ZeroTier Address (for relaying and meshy behavior)
|
DNSNAME = 3, // DNS name and port that resolves to InetAddress
|
||||||
URL = 4, // URL for http/https/ws/etc. (not implemented yet)
|
ZEROTIER = 4, // ZeroTier Address (for relaying and meshy behavior)
|
||||||
ETHERNET = 5, // 48-bit LAN-local Ethernet address
|
URL = 5, // URL for http/https/ws/etc. (not implemented yet)
|
||||||
UNRECOGNIZED = 255 // Unrecognized endpoint type encountered in stream
|
ETHERNET = 6, // 48-bit LAN-local Ethernet address
|
||||||
|
UNRECOGNIZED = 255 // Unrecognized endpoint type encountered in stream
|
||||||
};
|
};
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint()
|
ZT_ALWAYS_INLINE Endpoint()
|
||||||
|
@ -56,13 +57,12 @@ public:
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint(const Endpoint &ep)
|
ZT_ALWAYS_INLINE Endpoint(const Endpoint &ep)
|
||||||
{
|
{
|
||||||
memcpy(reinterpret_cast<void *>(this),&ep,sizeof(Endpoint));
|
memcpy(reinterpret_cast<void *>(this),reinterpret_cast<const void *>(&ep),sizeof(Endpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) :
|
explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa)
|
||||||
_t(INETADDR)
|
|
||||||
{
|
{
|
||||||
_v.sa = sa;
|
*this = sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) :
|
ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) :
|
||||||
|
@ -93,7 +93,17 @@ public:
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint &operator=(const InetAddress &sa)
|
ZT_ALWAYS_INLINE Endpoint &operator=(const InetAddress &sa)
|
||||||
{
|
{
|
||||||
_t = INETADDR;
|
switch(sa.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
_t = INETADDR_V4;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
_t = INETADDR_V6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_t = NIL;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
_v.sa = sa;
|
_v.sa = sa;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +111,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return InetAddress or NIL if not of this type
|
* @return InetAddress or NIL if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE const InetAddress &inetAddr() const { return (_t == INETADDR) ? *reinterpret_cast<const InetAddress *>(&_v.sa) : InetAddress::NIL; }
|
ZT_ALWAYS_INLINE const InetAddress &inetAddr() const { return ((_t == INETADDR_V4)||(_t == INETADDR_V6)) ? *reinterpret_cast<const InetAddress *>(&_v.sa) : InetAddress::NIL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return DNS name or empty string if not of this type
|
* @return DNS name or empty string if not of this type
|
||||||
|
@ -156,14 +166,14 @@ private:
|
||||||
int _l[3]; // X,Y,Z location in kilometers from the nearest gravitational center of mass
|
int _l[3]; // X,Y,Z location in kilometers from the nearest gravitational center of mass
|
||||||
union {
|
union {
|
||||||
struct sockaddr_storage sa;
|
struct sockaddr_storage sa;
|
||||||
ZT_PACKED_STRUCT(struct {
|
struct {
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
char name[ZT_ENDPOINT_MAX_NAME_SIZE];
|
char name[ZT_ENDPOINT_MAX_NAME_SIZE];
|
||||||
}) dns;
|
} dns;
|
||||||
ZT_PACKED_STRUCT(struct {
|
struct {
|
||||||
uint64_t a;
|
uint64_t a;
|
||||||
uint8_t idh[ZT_IDENTITY_HASH_SIZE];
|
uint8_t idh[ZT_IDENTITY_HASH_SIZE];
|
||||||
}) zt;
|
} zt;
|
||||||
char url[ZT_ENDPOINT_MAX_NAME_SIZE];
|
char url[ZT_ENDPOINT_MAX_NAME_SIZE];
|
||||||
uint64_t eth;
|
uint64_t eth;
|
||||||
} _v;
|
} _v;
|
||||||
|
|
|
@ -89,6 +89,7 @@ void Identity::generate(const Type t)
|
||||||
|
|
||||||
_type = t;
|
_type = t;
|
||||||
_hasPrivate = true;
|
_hasPrivate = true;
|
||||||
|
_hash[0] = 0; // force hash recompute
|
||||||
|
|
||||||
char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
char *const genmem = new char[ZT_IDENTITY_GEN_MEMORY];
|
||||||
do {
|
do {
|
||||||
|
@ -142,24 +143,13 @@ bool Identity::locallyValidate() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Identity::hash(uint8_t h[48],const bool includePrivate) const
|
void Identity::hashWithPrivate(uint8_t h[48]) const
|
||||||
{
|
{
|
||||||
switch(_type) {
|
switch(_type) {
|
||||||
|
case C25519: SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); break;
|
||||||
case C25519:
|
case P384: SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv)); break;
|
||||||
if ((_hasPrivate)&&(includePrivate))
|
default: memset(h,0,48);
|
||||||
SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
|
||||||
else SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case P384:
|
|
||||||
if ((_hasPrivate)&&(includePrivate))
|
|
||||||
SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv));
|
|
||||||
else SHA384(h,&_pub,sizeof(_pub));
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
|
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
|
||||||
|
@ -293,6 +283,7 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
|
||||||
bool Identity::fromString(const char *str)
|
bool Identity::fromString(const char *str)
|
||||||
{
|
{
|
||||||
_hasPrivate = false;
|
_hasPrivate = false;
|
||||||
|
_hash[0] = 0; // force hash recompute
|
||||||
|
|
||||||
if (!str) {
|
if (!str) {
|
||||||
_address.zero();
|
_address.zero();
|
||||||
|
@ -386,6 +377,97 @@ bool Identity::fromString(const char *str)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate) const
|
||||||
|
{
|
||||||
|
_address.copyTo(data,ZT_ADDRESS_LENGTH);
|
||||||
|
switch(_type) {
|
||||||
|
|
||||||
|
case C25519:
|
||||||
|
data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
|
||||||
|
memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||||
|
if ((includePrivate)&&(_hasPrivate)) {
|
||||||
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN;
|
||||||
|
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
||||||
|
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
|
||||||
|
}
|
||||||
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
|
||||||
|
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
|
||||||
|
|
||||||
|
case P384:
|
||||||
|
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
|
||||||
|
memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
||||||
|
if ((includePrivate)&&(_hasPrivate)) {
|
||||||
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE;
|
||||||
|
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
||||||
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE] = 0;
|
||||||
|
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1);
|
||||||
|
}
|
||||||
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
|
||||||
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1] = 0;
|
||||||
|
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
|
||||||
|
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Identity::unmarshal(const uint8_t *data,const int len)
|
||||||
|
{
|
||||||
|
if (len < (ZT_ADDRESS_LENGTH + 1))
|
||||||
|
return -1;
|
||||||
|
_hash[0] = 0; // force hash recompute
|
||||||
|
unsigned int privlen;
|
||||||
|
switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
|
||||||
|
|
||||||
|
case C25519:
|
||||||
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
|
||||||
|
return -1;
|
||||||
|
memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
|
||||||
|
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
|
||||||
|
if (privlen == ZT_C25519_PRIVATE_KEY_LEN) {
|
||||||
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
|
||||||
|
return -1;
|
||||||
|
_hasPrivate = true;
|
||||||
|
memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN);
|
||||||
|
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
|
||||||
|
} else if (privlen == 0) {
|
||||||
|
_hasPrivate = false;
|
||||||
|
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P384:
|
||||||
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2))
|
||||||
|
return -1;
|
||||||
|
memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
||||||
|
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
|
||||||
|
if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
|
||||||
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1))
|
||||||
|
return -1;
|
||||||
|
_hasPrivate = true;
|
||||||
|
memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
||||||
|
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE];
|
||||||
|
if (len < (int)(privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)))
|
||||||
|
return -1;
|
||||||
|
return (int)(privlen + (unsigned int)(ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1));
|
||||||
|
} else if (privlen == 0) {
|
||||||
|
_hasPrivate = false;
|
||||||
|
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Identity::_computeHash()
|
||||||
|
{
|
||||||
|
switch(_type) {
|
||||||
|
case C25519: SHA384(_hash,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN); break;
|
||||||
|
case P384: SHA384(_hash,&_pub,sizeof(_pub)); break;
|
||||||
|
default: memset(_hash,0,48);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -473,7 +555,9 @@ uint64_t ZT_Identity_address(const ZT_Identity *id)
|
||||||
|
|
||||||
void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate)
|
void ZT_Identity_hash(const ZT_Identity *id,uint8_t h[48],int includePrivate)
|
||||||
{
|
{
|
||||||
reinterpret_cast<const ZeroTier::Identity *>(id)->hash(h,includePrivate != 0);
|
if (includePrivate)
|
||||||
|
reinterpret_cast<const ZeroTier::Identity *>(id)->hashWithPrivate(h);
|
||||||
|
else memcpy(h,reinterpret_cast<const ZeroTier::Identity *>(id)->hash(),48);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)
|
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)
|
||||||
|
|
|
@ -101,12 +101,21 @@ public:
|
||||||
ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; }
|
ZT_ALWAYS_INLINE bool hasPrivate() const { return _hasPrivate; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This generates a SHA384 hash of this identity's keys.
|
* @return 384-bit/48-byte hash of this identity's public key(s)
|
||||||
*
|
|
||||||
* @param h Buffer to receive SHA384 of public key(s)
|
|
||||||
* @param includePrivate If true, hash private key(s) as well
|
|
||||||
*/
|
*/
|
||||||
bool hash(uint8_t h[48],bool includePrivate = false) const;
|
ZT_ALWAYS_INLINE const uint8_t *hash() const
|
||||||
|
{
|
||||||
|
if (_hash[0] == 0)
|
||||||
|
const_cast<Identity *>(this)->_computeHash();
|
||||||
|
return reinterpret_cast<const uint8_t *>(_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute a hash of this identity's public and private keys
|
||||||
|
*
|
||||||
|
* @param h Buffer to store SHA384 hash
|
||||||
|
*/
|
||||||
|
void hashWithPrivate(uint8_t h[48]) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a message with this identity (private key required)
|
* Sign a message with this identity (private key required)
|
||||||
|
@ -311,91 +320,15 @@ public:
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE unsigned long hashCode() const { return ((unsigned long)_address.toInt() + (unsigned long)_pub.c25519[0] + (unsigned long)_pub.c25519[1] + (unsigned long)_pub.c25519[2]); }
|
ZT_ALWAYS_INLINE unsigned long hashCode() const { return ((unsigned long)_address.toInt() + (unsigned long)_pub.c25519[0] + (unsigned long)_pub.c25519[1] + (unsigned long)_pub.c25519[2]); }
|
||||||
|
|
||||||
// Marshal interface ///////////////////////////////////////////////////////
|
|
||||||
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
|
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
|
||||||
inline int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const
|
int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],bool includePrivate = false) const;
|
||||||
{
|
int unmarshal(const uint8_t *data,int len);
|
||||||
_address.copyTo(data,ZT_ADDRESS_LENGTH);
|
|
||||||
switch(_type) {
|
|
||||||
|
|
||||||
case C25519:
|
|
||||||
data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
|
|
||||||
memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
|
||||||
if ((includePrivate)&&(_hasPrivate)) {
|
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN;
|
|
||||||
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
|
|
||||||
}
|
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
|
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
|
|
||||||
|
|
||||||
case P384:
|
|
||||||
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
|
|
||||||
memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
|
||||||
if ((includePrivate)&&(_hasPrivate)) {
|
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE;
|
|
||||||
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE] = 0;
|
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1);
|
|
||||||
}
|
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
|
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1] = 0;
|
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
|
|
||||||
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
inline int unmarshal(const uint8_t *restrict data,const int len)
|
|
||||||
{
|
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1))
|
|
||||||
return -1;
|
|
||||||
unsigned int privlen;
|
|
||||||
switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
|
|
||||||
|
|
||||||
case C25519:
|
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
|
|
||||||
return -1;
|
|
||||||
memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
|
|
||||||
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
|
|
||||||
if (privlen == ZT_C25519_PRIVATE_KEY_LEN) {
|
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
|
|
||||||
return -1;
|
|
||||||
_hasPrivate = true;
|
|
||||||
memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN);
|
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
|
|
||||||
} else if (privlen == 0) {
|
|
||||||
_hasPrivate = false;
|
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case P384:
|
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2))
|
|
||||||
return -1;
|
|
||||||
memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
|
||||||
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
|
|
||||||
if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
|
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1))
|
|
||||||
return -1;
|
|
||||||
_hasPrivate = true;
|
|
||||||
memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
|
||||||
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE];
|
|
||||||
if (len < (int)(privlen + (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1)))
|
|
||||||
return -1;
|
|
||||||
return (int)(privlen + (unsigned int)(ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE + 1));
|
|
||||||
} else if (privlen == 0) {
|
|
||||||
_hasPrivate = false;
|
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _computeHash(); // recompute _hash
|
||||||
|
|
||||||
Address _address;
|
Address _address;
|
||||||
|
uint64_t _hash[6]; // hash of public key memo-ized for performance, recalculated when _hash[0] == 0
|
||||||
Type _type; // _type determines which fields in _priv and _pub are used
|
Type _type; // _type determines which fields in _priv and _pub are used
|
||||||
bool _hasPrivate;
|
bool _hasPrivate;
|
||||||
ZT_PACKED_STRUCT(struct { // don't re-order these
|
ZT_PACKED_STRUCT(struct { // don't re-order these
|
||||||
|
|
|
@ -35,9 +35,6 @@
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Implementation of each protocol verb //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid,const SharedPtr<Path> &path)
|
void _sendErrorNeedCredentials(IncomingPacket &pkt,const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid,const SharedPtr<Path> &path)
|
||||||
{
|
{
|
||||||
|
@ -65,11 +62,11 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
|
||||||
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(pkt,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
|
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(pkt,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
|
||||||
|
|
||||||
if (protoVersion < ZT_PROTO_VERSION_MIN) {
|
if (protoVersion < ZT_PROTO_VERSION_MIN) {
|
||||||
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"protocol version too old");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (fromAddress != id.address()) {
|
if (fromAddress != id.address()) {
|
||||||
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"identity/address mismatch");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,18 +84,13 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
|
||||||
uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
|
uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
|
||||||
if (RR->identity.agree(id,key)) {
|
if (RR->identity.agree(id,key)) {
|
||||||
if (pkt.dearmor(key)) { // ensure packet is authentic, otherwise drop
|
if (pkt.dearmor(key)) { // ensure packet is authentic, otherwise drop
|
||||||
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"address collision");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||||
Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR);
|
// TODO: we handle identity collisions differently now
|
||||||
outp.append((uint8_t)Packet::VERB_HELLO);
|
|
||||||
outp.append((uint64_t)pid);
|
|
||||||
outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION);
|
|
||||||
outp.armor(key,true);
|
|
||||||
path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
|
||||||
} else {
|
} else {
|
||||||
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid MAC");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid identity");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -106,7 +98,7 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
|
||||||
// Identity is the same as the one we already have -- check packet integrity
|
// Identity is the same as the one we already have -- check packet integrity
|
||||||
|
|
||||||
if (!pkt.dearmor(peer->key())) {
|
if (!pkt.dearmor(peer->key())) {
|
||||||
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid MAC");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,30 +110,30 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
|
||||||
|
|
||||||
// Sanity check: this basically can't happen
|
// Sanity check: this basically can't happen
|
||||||
if (alreadyAuthenticated) {
|
if (alreadyAuthenticated) {
|
||||||
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"illegal alreadyAuthenticated state");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check rate limits
|
// Check rate limits
|
||||||
if (!RR->node->rateGateIdentityVerification(now,path->address())) {
|
if (!RR->node->rateGateIdentityVerification(now,path->address())) {
|
||||||
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"rate limit exceeded");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap)
|
// Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap)
|
||||||
SharedPtr<Peer> newPeer(new Peer(RR));
|
SharedPtr<Peer> newPeer(new Peer(RR));
|
||||||
if (!newPeer->init(RR->identity,id)) {
|
if (!newPeer->init(RR->identity,id)) {
|
||||||
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"error initializing peer");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!pkt.dearmor(newPeer->key())) {
|
if (!pkt.dearmor(newPeer->key())) {
|
||||||
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,path,pid,fromAddress,pkt.hops(),"invalid MAC");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that identity's address is valid as per the derivation function
|
// Check that identity's address is valid as per the derivation function
|
||||||
if (!id.locallyValidate()) {
|
if (!id.locallyValidate()) {
|
||||||
RR->t->incomingPacketDroppedHELLO(tPtr,path,pid,fromAddress,"invalid identity");
|
RR->t->incomingPacketDropped(tPtr,pid,0,id,path->address(),pkt.hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +150,7 @@ ZT_ALWAYS_INLINE bool _doHELLO(IncomingPacket &pkt,const RuntimeEnvironment *con
|
||||||
if (ptr < pkt.size()) {
|
if (ptr < pkt.size()) {
|
||||||
ptr += externalSurfaceAddress.deserialize(pkt,ptr);
|
ptr += externalSurfaceAddress.deserialize(pkt,ptr);
|
||||||
if ((externalSurfaceAddress)&&(pkt.hops() == 0))
|
if ((externalSurfaceAddress)&&(pkt.hops() == 0))
|
||||||
RR->sa->iam(tPtr,id.address(),path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
|
RR->sa->iam(tPtr,id,path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +262,7 @@ ZT_ALWAYS_INLINE bool _doOK(IncomingPacket &pkt,const RuntimeEnvironment *const
|
||||||
InetAddress externalSurfaceAddress;
|
InetAddress externalSurfaceAddress;
|
||||||
externalSurfaceAddress.deserialize(pkt,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2);
|
externalSurfaceAddress.deserialize(pkt,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2);
|
||||||
if (externalSurfaceAddress)
|
if (externalSurfaceAddress)
|
||||||
RR->sa->iam(tPtr,peer->address(),path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(peer->identity()),RR->node->now());
|
RR->sa->iam(tPtr,peer->identity(),path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(peer->identity()),RR->node->now());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,6 +380,7 @@ ZT_ALWAYS_INLINE bool _doFRAME(IncomingPacket &pkt,const RuntimeEnvironment *con
|
||||||
RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen);
|
RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
RR->t->incomingNetworkFrameDropped(tPtr,nwid,MAC(),MAC(),peer->identity(),path->address(),pkt.hops(),0,nullptr,Packet::VERB_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED);
|
||||||
_sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path);
|
_sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -412,7 +405,7 @@ ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!network->gate(tPtr,peer)) {
|
if (!network->gate(tPtr,peer)) {
|
||||||
RR->t->incomingNetworkAccessDenied(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,true);
|
RR->t->incomingNetworkFrameDropped(tPtr,nwid,MAC(),MAC(),peer->identity(),path->address(),pkt.hops(),0,nullptr,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_PERMISSION_DENIED);
|
||||||
_sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path);
|
_sendErrorNeedCredentials(pkt,RR,tPtr,peer,nwid,path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -435,19 +428,19 @@ ZT_ALWAYS_INLINE bool _doEXT_FRAME(IncomingPacket &pkt,const RuntimeEnvironment
|
||||||
if (network->config().permitsBridging(peer->address())) {
|
if (network->config().permitsBridging(peer->address())) {
|
||||||
network->learnBridgeRoute(from,peer->address());
|
network->learnBridgeRoute(from,peer->address());
|
||||||
} else {
|
} else {
|
||||||
RR->t->incomingNetworkFrameDropped(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (remote)");
|
RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),path->address(),pkt.hops(),(uint16_t)frameLen,frameData,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_REMOTE);
|
||||||
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
|
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (to != network->mac()) {
|
} else if (to != network->mac()) {
|
||||||
if (to.isMulticast()) {
|
if (to.isMulticast()) {
|
||||||
if (network->config().multicastLimit == 0) {
|
if (network->config().multicastLimit == 0) {
|
||||||
RR->t->incomingNetworkFrameDropped(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"multicast disabled");
|
RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),path->address(),pkt.hops(),(uint16_t)frameLen,frameData,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED);
|
||||||
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
|
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!network->config().permitsBridging(RR->identity.address())) {
|
} else if (!network->config().permitsBridging(RR->identity.address())) {
|
||||||
RR->t->incomingNetworkFrameDropped(tPtr,network,path,pkt.packetId(),pkt.size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (local)");
|
RR->t->incomingNetworkFrameDropped(tPtr,nwid,from,to,peer->identity(),path->address(),pkt.hops(),(uint16_t)frameLen,frameData,Packet::VERB_EXT_FRAME,true,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL);
|
||||||
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
|
peer->received(tPtr,path,pkt.hops(),pkt.packetId(),pkt.payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,nwid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -733,6 +726,7 @@ ZT_ALWAYS_INLINE bool _doUSER_MESSAGE(IncomingPacket &pkt,const RuntimeEnvironme
|
||||||
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
||||||
{
|
{
|
||||||
const Address sourceAddress(source());
|
const Address sourceAddress(source());
|
||||||
|
const SharedPtr<Peer> peer(RR->topology->get(tPtr,sourceAddress));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
|
// Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
|
||||||
|
@ -746,7 +740,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
||||||
if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) {
|
if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) {
|
||||||
trusted = true;
|
trusted = true;
|
||||||
} else {
|
} else {
|
||||||
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted");
|
if (peer)
|
||||||
|
RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if ((c == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
|
} else if ((c == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
|
||||||
|
@ -754,54 +749,54 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
||||||
return _doHELLO(*this,RR,tPtr,false,_path);
|
return _doHELLO(*this,RR,tPtr,false,_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SharedPtr<Peer> peer(RR->topology->get(tPtr,sourceAddress));
|
if (!peer) {
|
||||||
if (peer) {
|
|
||||||
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 {
|
|
||||||
RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress);
|
RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress);
|
||||||
return false;
|
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) {
|
} catch (int ztExcCode) {
|
||||||
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()");
|
} catch ( ... ) {}
|
||||||
return true;
|
|
||||||
} catch ( ... ) {
|
if (peer)
|
||||||
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()");
|
RR->t->incomingPacketDropped(tPtr,packetId(),0,peer->identity(),_path->address(),hops(),Packet::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -419,6 +419,37 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill out a ZT_TraceEventPathAddress from this InetAddress
|
||||||
|
*
|
||||||
|
* @param ta ZT_TraceEventPathAddress to fill
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE void forTrace(ZT_TraceEventPathAddress &ta) const
|
||||||
|
{
|
||||||
|
uint32_t tmp;
|
||||||
|
switch(ss_family) {
|
||||||
|
default:
|
||||||
|
memset(&ta,0,sizeof(ZT_TraceEventPathAddress));
|
||||||
|
break;
|
||||||
|
case AF_INET:
|
||||||
|
ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V4;
|
||||||
|
tmp = (uint32_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
|
||||||
|
ta.address[0] = reinterpret_cast<const uint8_t *>(&tmp)[0];
|
||||||
|
ta.address[1] = reinterpret_cast<const uint8_t *>(&tmp)[1];
|
||||||
|
ta.address[2] = reinterpret_cast<const uint8_t *>(&tmp)[2];
|
||||||
|
ta.address[3] = reinterpret_cast<const uint8_t *>(&tmp)[3];
|
||||||
|
memset(ta.address + 4,0,sizeof(ta.address) - 4);
|
||||||
|
ta.port = reinterpret_cast<const struct sockaddr_in *>(this)->sin_port;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
ta.type = ZT_TRACE_EVENT_PATH_TYPE_INETADDR_V6;
|
||||||
|
memcpy(ta.address,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
|
||||||
|
memset(ta.address + 16,0,sizeof(ta.address) - 16);
|
||||||
|
ta.port = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to null/zero
|
* Set to null/zero
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -101,7 +101,7 @@ union LZ4_streamDecode_u {
|
||||||
#define HEAPMODE 0
|
#define HEAPMODE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
#define LZ4_FORCE_MEMORY_ACCESS 0
|
#define LZ4_FORCE_MEMORY_ACCESS 0
|
||||||
#else
|
#else
|
||||||
#define LZ4_FORCE_MEMORY_ACCESS 2
|
#define LZ4_FORCE_MEMORY_ACCESS 2
|
||||||
|
|
|
@ -46,8 +46,8 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud
|
||||||
int p = 8;
|
int p = 8;
|
||||||
|
|
||||||
if (_ts > 0) {
|
if (_ts > 0) {
|
||||||
data[p++] = (uint8_t)(_endpointCount >> 8U);
|
Utils::storeBigEndian(data + p,(uint16_t)_endpointCount);
|
||||||
data[p++] = (uint8_t)_endpointCount;
|
p += 2;
|
||||||
for (unsigned int i = 0; i < _endpointCount; ++i) {
|
for (unsigned int i = 0; i < _endpointCount; ++i) {
|
||||||
int tmp = _at[i].marshal(data + p);
|
int tmp = _at[i].marshal(data + p);
|
||||||
if (tmp < 0)
|
if (tmp < 0)
|
||||||
|
@ -56,11 +56,14 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!excludeSignature) {
|
if (!excludeSignature) {
|
||||||
data[p++] = (uint8_t)(_signatureLength >> 8U);
|
Utils::storeBigEndian(data + p,(uint16_t)_signatureLength);
|
||||||
data[p++] = (uint8_t)_signatureLength;
|
p += 2;
|
||||||
memcpy(data + p,_signature,_signatureLength);
|
memcpy(data + p,_signature,_signatureLength);
|
||||||
p += (int)_signatureLength;
|
p += (int)_signatureLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::storeBigEndian(data + p,_flags);
|
||||||
|
p += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
@ -75,9 +78,8 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len)
|
||||||
int p = 8;
|
int p = 8;
|
||||||
|
|
||||||
if (_ts > 0) {
|
if (_ts > 0) {
|
||||||
unsigned int ec = (int)data[p++];
|
const unsigned int ec = Utils::loadBigEndian<uint16_t>(data + p);
|
||||||
ec <<= 8U;
|
p += 2;
|
||||||
ec |= data[p++];
|
|
||||||
if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
|
if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
|
||||||
return -1;
|
return -1;
|
||||||
_endpointCount = ec;
|
_endpointCount = ec;
|
||||||
|
@ -90,9 +92,8 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len)
|
||||||
|
|
||||||
if ((p + 2) > len)
|
if ((p + 2) > len)
|
||||||
return -1;
|
return -1;
|
||||||
unsigned int sl = data[p++];
|
const unsigned int sl = Utils::loadBigEndian<uint16_t>(data + p);
|
||||||
sl <<= 8U;
|
p += 2;
|
||||||
sl |= data[p++];
|
|
||||||
if (sl > ZT_SIGNATURE_BUFFER_SIZE)
|
if (sl > ZT_SIGNATURE_BUFFER_SIZE)
|
||||||
return -1;
|
return -1;
|
||||||
_signatureLength = sl;
|
_signatureLength = sl;
|
||||||
|
@ -100,6 +101,11 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len)
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(_signature,data + p,sl);
|
memcpy(_signature,data + p,sl);
|
||||||
p += (int)sl;
|
p += (int)sl;
|
||||||
|
|
||||||
|
if ((p + 2) > len)
|
||||||
|
return -1;
|
||||||
|
_flags = Utils::loadBigEndian<uint16_t>(data + p);
|
||||||
|
p += 2;
|
||||||
} else {
|
} else {
|
||||||
_ts = 0;
|
_ts = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "Identity.hpp"
|
#include "Identity.hpp"
|
||||||
|
|
||||||
#define ZT_LOCATOR_MAX_ENDPOINTS 8
|
#define ZT_LOCATOR_MAX_ENDPOINTS 8
|
||||||
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + ZT_SIGNATURE_BUFFER_SIZE)
|
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE)
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -120,6 +120,7 @@ private:
|
||||||
unsigned int _endpointCount;
|
unsigned int _endpointCount;
|
||||||
unsigned int _signatureLength;
|
unsigned int _signatureLength;
|
||||||
Endpoint _at[ZT_LOCATOR_MAX_ENDPOINTS];
|
Endpoint _at[ZT_LOCATOR_MAX_ENDPOINTS];
|
||||||
|
uint16_t _flags;
|
||||||
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "Switch.hpp"
|
#include "Switch.hpp"
|
||||||
#include "Packet.hpp"
|
#include "Packet.hpp"
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
#include "Trace.hpp"
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -102,17 +101,24 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
|
||||||
_lastPushedCredentials = now;
|
_lastPushedCredentials = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com)
|
void Membership::clean(const int64_t now,const NetworkConfig &nconf)
|
||||||
|
{
|
||||||
|
_cleanCredImpl<Tag>(nconf,_remoteTags);
|
||||||
|
_cleanCredImpl<Capability>(nconf,_remoteCaps);
|
||||||
|
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos);
|
||||||
|
}
|
||||||
|
|
||||||
|
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com)
|
||||||
{
|
{
|
||||||
const int64_t newts = com.timestamp();
|
const int64_t newts = com.timestamp();
|
||||||
if (newts <= _comRevocationThreshold) {
|
if (newts <= _comRevocationThreshold) {
|
||||||
RR->t->credentialRejected(tPtr,com,"revoked");
|
RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
|
||||||
return ADD_REJECTED;
|
return ADD_REJECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int64_t oldts = _com.timestamp();
|
const int64_t oldts = _com.timestamp();
|
||||||
if (newts < oldts) {
|
if (newts < oldts) {
|
||||||
RR->t->credentialRejected(tPtr,com,"old");
|
RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
|
||||||
return ADD_REJECTED;
|
return ADD_REJECTED;
|
||||||
}
|
}
|
||||||
if ((newts == oldts)&&(_com == com))
|
if ((newts == oldts)&&(_com == com))
|
||||||
|
@ -120,27 +126,34 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
||||||
|
|
||||||
switch(com.verify(RR,tPtr)) {
|
switch(com.verify(RR,tPtr)) {
|
||||||
default:
|
default:
|
||||||
RR->t->credentialRejected(tPtr,com,"invalid");
|
RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
|
||||||
return Membership::ADD_REJECTED;
|
return Membership::ADD_REJECTED;
|
||||||
case Credential::VERIFY_OK:
|
case Credential::VERIFY_OK:
|
||||||
_com = com;
|
_com = com;
|
||||||
return ADD_ACCEPTED_NEW;
|
return ADD_ACCEPTED_NEW;
|
||||||
case Credential::VERIFY_BAD_SIGNATURE:
|
case Credential::VERIFY_BAD_SIGNATURE:
|
||||||
RR->t->credentialRejected(tPtr,com,"invalid");
|
RR->t->credentialRejected(tPtr,com.networkId(),sourcePeerIdentity.address(),com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED);
|
||||||
return ADD_REJECTED;
|
return ADD_REJECTED;
|
||||||
case Credential::VERIFY_NEED_IDENTITY:
|
case Credential::VERIFY_NEED_IDENTITY:
|
||||||
return ADD_DEFERRED_FOR_WHOIS;
|
return ADD_DEFERRED_FOR_WHOIS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Template out addCredential() for many cred types to avoid copypasta
|
// 3/5 of the credential types have identical addCredential() code
|
||||||
template<typename C>
|
template<typename C>
|
||||||
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remoteCreds,const Hashtable<uint64_t,int64_t> &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred)
|
static ZT_ALWAYS_INLINE Membership::AddCredentialResult _addCredImpl(
|
||||||
|
Hashtable<uint32_t,C> &remoteCreds,
|
||||||
|
const Hashtable<uint64_t,int64_t> &revocations,
|
||||||
|
const RuntimeEnvironment *const RR,
|
||||||
|
void *const tPtr,
|
||||||
|
const Identity &sourcePeerIdentity,
|
||||||
|
const NetworkConfig &nconf,
|
||||||
|
const C &cred)
|
||||||
{
|
{
|
||||||
C *rc = remoteCreds.get(cred.id());
|
C *rc = remoteCreds.get(cred.id());
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if (rc->timestamp() > cred.timestamp()) {
|
if (rc->timestamp() > cred.timestamp()) {
|
||||||
RR->t->credentialRejected(tPtr,cred,"old");
|
RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
|
||||||
return Membership::ADD_REJECTED;
|
return Membership::ADD_REJECTED;
|
||||||
}
|
}
|
||||||
if (*rc == cred)
|
if (*rc == cred)
|
||||||
|
@ -149,13 +162,13 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
|
||||||
|
|
||||||
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
|
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
|
||||||
if ((rt)&&(*rt >= cred.timestamp())) {
|
if ((rt)&&(*rt >= cred.timestamp())) {
|
||||||
RR->t->credentialRejected(tPtr,cred,"revoked");
|
RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
|
||||||
return Membership::ADD_REJECTED;
|
return Membership::ADD_REJECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(cred.verify(RR,tPtr)) {
|
switch(cred.verify(RR,tPtr)) {
|
||||||
default:
|
default:
|
||||||
RR->t->credentialRejected(tPtr,cred,"invalid");
|
RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),cred.id(),cred.timestamp(),C::credentialType(),ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
|
||||||
return Membership::ADD_REJECTED;
|
return Membership::ADD_REJECTED;
|
||||||
case 0:
|
case 0:
|
||||||
if (!rc)
|
if (!rc)
|
||||||
|
@ -166,30 +179,29 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
|
||||||
return Membership::ADD_DEFERRED_FOR_WHOIS;
|
return Membership::ADD_DEFERRED_FOR_WHOIS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,sourcePeerIdentity,nconf,tag); }
|
||||||
|
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,sourcePeerIdentity,nconf,cap); }
|
||||||
|
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,sourcePeerIdentity,nconf,coo); }
|
||||||
|
|
||||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,nconf,tag); }
|
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev)
|
||||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,nconf,cap); }
|
|
||||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,nconf,coo); }
|
|
||||||
|
|
||||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev)
|
|
||||||
{
|
{
|
||||||
int64_t *rt;
|
int64_t *rt;
|
||||||
switch(rev.verify(RR,tPtr)) {
|
switch(rev.verify(RR,tPtr)) {
|
||||||
default:
|
default:
|
||||||
RR->t->credentialRejected(tPtr,rev,"invalid");
|
RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
|
||||||
return ADD_REJECTED;
|
return ADD_REJECTED;
|
||||||
case 0: {
|
case 0: {
|
||||||
const Credential::Type ct = rev.type();
|
const ZT_CredentialType ct = rev.typeBeingRevoked();
|
||||||
switch(ct) {
|
switch(ct) {
|
||||||
case Credential::CREDENTIAL_TYPE_COM:
|
case ZT_CREDENTIAL_TYPE_COM:
|
||||||
if (rev.threshold() > _comRevocationThreshold) {
|
if (rev.threshold() > _comRevocationThreshold) {
|
||||||
_comRevocationThreshold = rev.threshold();
|
_comRevocationThreshold = rev.threshold();
|
||||||
return ADD_ACCEPTED_NEW;
|
return ADD_ACCEPTED_NEW;
|
||||||
}
|
}
|
||||||
return ADD_ACCEPTED_REDUNDANT;
|
return ADD_ACCEPTED_REDUNDANT;
|
||||||
case Credential::CREDENTIAL_TYPE_CAPABILITY:
|
case ZT_CREDENTIAL_TYPE_CAPABILITY:
|
||||||
case Credential::CREDENTIAL_TYPE_TAG:
|
case ZT_CREDENTIAL_TYPE_TAG:
|
||||||
case Credential::CREDENTIAL_TYPE_COO:
|
case ZT_CREDENTIAL_TYPE_COO:
|
||||||
rt = &(_revocations[credentialKey(ct,rev.credentialId())]);
|
rt = &(_revocations[credentialKey(ct,rev.credentialId())]);
|
||||||
if (*rt < rev.threshold()) {
|
if (*rt < rev.threshold()) {
|
||||||
*rt = rev.threshold();
|
*rt = rev.threshold();
|
||||||
|
@ -198,7 +210,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
||||||
}
|
}
|
||||||
return ADD_ACCEPTED_REDUNDANT;
|
return ADD_ACCEPTED_REDUNDANT;
|
||||||
default:
|
default:
|
||||||
RR->t->credentialRejected(tPtr,rev,"invalid");
|
RR->t->credentialRejected(tPtr,nconf.networkId,sourcePeerIdentity.address(),rev.id(),0,ZT_CREDENTIAL_TYPE_REVOCATION,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
|
||||||
return ADD_REJECTED;
|
return ADD_REJECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,11 +219,42 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Membership::clean(const int64_t now,const NetworkConfig &nconf)
|
bool Membership::_isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
|
||||||
{
|
{
|
||||||
_cleanCredImpl<Tag>(nconf,_remoteTags);
|
if ((ip.isV6())&&(nconf.ndpEmulation())) {
|
||||||
_cleanCredImpl<Capability>(nconf,_remoteCaps);
|
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
|
||||||
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos);
|
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
|
||||||
|
if (nconf.staticIps[i].ipsEqual(sixpl)) {
|
||||||
|
bool prefixMatches = true;
|
||||||
|
for(unsigned int j=0;j<5;++j) { // check for match on /40
|
||||||
|
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) {
|
||||||
|
prefixMatches = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prefixMatches)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()));
|
||||||
|
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
|
||||||
|
if (nconf.staticIps[i].ipsEqual(rfc4193)) {
|
||||||
|
bool prefixMatches = true;
|
||||||
|
for(unsigned int j=0;j<11;++j) { // check for match on /88
|
||||||
|
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) {
|
||||||
|
prefixMatches = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prefixMatches)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
#include "Revocation.hpp"
|
#include "Revocation.hpp"
|
||||||
#include "NetworkConfig.hpp"
|
#include "NetworkConfig.hpp"
|
||||||
|
|
||||||
#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
class RuntimeEnvironment;
|
class RuntimeEnvironment;
|
||||||
|
@ -61,7 +59,7 @@ public:
|
||||||
* @param peerAddress Address of member peer (the one that this Membership describes)
|
* @param peerAddress Address of member peer (the one that this Membership describes)
|
||||||
* @param nconf My network config
|
* @param nconf My network config
|
||||||
*/
|
*/
|
||||||
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf);
|
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,int64_t now,const Address &peerAddress,const NetworkConfig &nconf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Time we last pushed credentials to this member
|
* @return Time we last pushed credentials to this member
|
||||||
|
@ -94,8 +92,8 @@ public:
|
||||||
{
|
{
|
||||||
if (_isUnspoofableAddress(nconf,r))
|
if (_isUnspoofableAddress(nconf,r))
|
||||||
return true;
|
return true;
|
||||||
uint32_t *k = (uint32_t *)0;
|
uint32_t *k = nullptr;
|
||||||
CertificateOfOwnership *v = (CertificateOfOwnership *)0;
|
CertificateOfOwnership *v = nullptr;
|
||||||
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
|
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
|
||||||
while (i.next(k,v)) {
|
while (i.next(k,v)) {
|
||||||
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
|
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
|
||||||
|
@ -117,12 +115,6 @@ public:
|
||||||
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
|
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com);
|
|
||||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag);
|
|
||||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap);
|
|
||||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
|
|
||||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean internal databases of stale entries
|
* Clean internal databases of stale entries
|
||||||
*
|
*
|
||||||
|
@ -134,70 +126,20 @@ public:
|
||||||
/**
|
/**
|
||||||
* Generates a key for internal use in indexing credentials by type and credential ID
|
* Generates a key for internal use in indexing credentials by type and credential ID
|
||||||
*/
|
*/
|
||||||
static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); }
|
static ZT_ALWAYS_INLINE uint64_t credentialKey(const ZT_CredentialType &t,const uint32_t i) { return (((uint64_t)t << 32U) | (uint64_t)i); }
|
||||||
|
|
||||||
/**
|
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com);
|
||||||
* @return Bytes received so far
|
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag);
|
||||||
*/
|
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap);
|
||||||
ZT_ALWAYS_INLINE uint64_t receivedBytes() const { return _received; }
|
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
|
||||||
|
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev);
|
||||||
/**
|
|
||||||
* @return Bytes sent so far
|
|
||||||
*/
|
|
||||||
ZT_ALWAYS_INLINE uint64_t sentBytes() const { return _sent; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bytes Bytes received
|
|
||||||
*/
|
|
||||||
ZT_ALWAYS_INLINE void logReceivedBytes(const unsigned int bytes) { _received = (uint64_t)bytes; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bytes Bytes sent
|
|
||||||
*/
|
|
||||||
ZT_ALWAYS_INLINE void logSentBytes(const unsigned int bytes) { _sent = (uint64_t)bytes; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
|
// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
|
||||||
// address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
|
// address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
|
||||||
// always return true for them. A certificate is not required for these.
|
// always return true for them. A certificate is not required for these.
|
||||||
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
|
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
|
||||||
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
|
bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const;
|
||||||
{
|
|
||||||
if ((ip.isV6())&&(nconf.ndpEmulation())) {
|
|
||||||
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
|
|
||||||
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
|
|
||||||
if (nconf.staticIps[i].ipsEqual(sixpl)) {
|
|
||||||
bool prefixMatches = true;
|
|
||||||
for(unsigned int j=0;j<5;++j) { // check for match on /40
|
|
||||||
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) {
|
|
||||||
prefixMatches = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (prefixMatches)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()));
|
|
||||||
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
|
|
||||||
if (nconf.staticIps[i].ipsEqual(rfc4193)) {
|
|
||||||
bool prefixMatches = true;
|
|
||||||
for(unsigned int j=0;j<11;++j) { // check for match on /88
|
|
||||||
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) {
|
|
||||||
prefixMatches = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (prefixMatches)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This compares the remote credential's timestamp to the timestamp in our network config
|
// This compares the remote credential's timestamp to the timestamp in our network config
|
||||||
// plus or minus the permitted maximum timestamp delta.
|
// plus or minus the permitted maximum timestamp delta.
|
||||||
|
@ -213,10 +155,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename C>
|
template<typename C>
|
||||||
inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
|
ZT_ALWAYS_INLINE void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
|
||||||
{
|
{
|
||||||
uint32_t *k = (uint32_t *)0;
|
uint32_t *k = nullptr;
|
||||||
C *v = (C *)0;
|
C *v = nullptr;
|
||||||
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
|
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
|
||||||
while (i.next(k,v)) {
|
while (i.next(k,v)) {
|
||||||
if (!_isCredentialTimestampValid(nconf,*v))
|
if (!_isCredentialTimestampValid(nconf,*v))
|
||||||
|
@ -233,12 +175,6 @@ private:
|
||||||
// Time we last pushed credentials
|
// Time we last pushed credentials
|
||||||
int64_t _lastPushedCredentials;
|
int64_t _lastPushedCredentials;
|
||||||
|
|
||||||
// Number of Ethernet frame bytes received
|
|
||||||
uint64_t _received;
|
|
||||||
|
|
||||||
// Number of Ethernet frame bytes sent
|
|
||||||
uint64_t _sent;
|
|
||||||
|
|
||||||
// Remote member's latest network COM
|
// Remote member's latest network COM
|
||||||
CertificateOfMembership _com;
|
CertificateOfMembership _com;
|
||||||
|
|
||||||
|
@ -256,8 +192,8 @@ public:
|
||||||
public:
|
public:
|
||||||
ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
|
ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
|
||||||
_hti(m._remoteCaps),
|
_hti(m._remoteCaps),
|
||||||
_k((uint32_t *)0),
|
_k(nullptr),
|
||||||
_c((Capability *)0),
|
_c(nullptr),
|
||||||
_m(m),
|
_m(m),
|
||||||
_nconf(nconf)
|
_nconf(nconf)
|
||||||
{
|
{
|
||||||
|
@ -269,7 +205,7 @@ public:
|
||||||
if (_m._isCredentialTimestampValid(_nconf,*_c))
|
if (_m._isCredentialTimestampValid(_nconf,*_c))
|
||||||
return _c;
|
return _c;
|
||||||
}
|
}
|
||||||
return (Capability *)0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
198
node/Network.cpp
198
node/Network.cpp
|
@ -11,12 +11,8 @@
|
||||||
*/
|
*/
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "../include/ZeroTierDebug.h"
|
|
||||||
|
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
#include "Network.hpp"
|
#include "Network.hpp"
|
||||||
|
@ -28,7 +24,6 @@
|
||||||
#include "Buffer.hpp"
|
#include "Buffer.hpp"
|
||||||
#include "Packet.hpp"
|
#include "Packet.hpp"
|
||||||
#include "NetworkController.hpp"
|
#include "NetworkController.hpp"
|
||||||
#include "Node.hpp"
|
|
||||||
#include "Peer.hpp"
|
#include "Peer.hpp"
|
||||||
#include "Trace.hpp"
|
#include "Trace.hpp"
|
||||||
#include "ScopedPtr.hpp"
|
#include "ScopedPtr.hpp"
|
||||||
|
@ -40,7 +35,7 @@ namespace ZeroTier {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Returns true if packet appears valid; pos and proto will be set
|
// Returns true if packet appears valid; pos and proto will be set
|
||||||
static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
|
bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
|
||||||
{
|
{
|
||||||
if (frameLen < 40)
|
if (frameLen < 40)
|
||||||
return false;
|
return false;
|
||||||
|
@ -77,7 +72,7 @@ enum _doZtFilterResult
|
||||||
DOZTFILTER_SUPER_ACCEPT
|
DOZTFILTER_SUPER_ACCEPT
|
||||||
};
|
};
|
||||||
|
|
||||||
static _doZtFilterResult _doZtFilter(
|
_doZtFilterResult _doZtFilter(
|
||||||
const RuntimeEnvironment *RR,
|
const RuntimeEnvironment *RR,
|
||||||
Trace::RuleResultLog &rrl,
|
Trace::RuleResultLog &rrl,
|
||||||
const NetworkConfig &nconf,
|
const NetworkConfig &nconf,
|
||||||
|
@ -108,14 +103,14 @@ static _doZtFilterResult _doZtFilter(
|
||||||
rrl.clear();
|
rrl.clear();
|
||||||
|
|
||||||
for(unsigned int rn=0;rn<ruleCount;++rn) {
|
for(unsigned int rn=0;rn<ruleCount;++rn) {
|
||||||
const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3f);
|
const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3fU);
|
||||||
|
|
||||||
// First check if this is an ACTION
|
// First check if this is an ACTION
|
||||||
if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) {
|
if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) {
|
||||||
if (thisSetMatches) {
|
if (thisSetMatches) {
|
||||||
switch(rt) {
|
switch(rt) {
|
||||||
case ZT_NETWORK_RULE_ACTION_PRIORITY:
|
case ZT_NETWORK_RULE_ACTION_PRIORITY:
|
||||||
qosBucket = (rules[rn].v.qosBucket >= 0 || rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority)
|
qosBucket = (rules[rn].v.qosBucket >= 0 && rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority)
|
||||||
return DOZTFILTER_ACCEPT;
|
return DOZTFILTER_ACCEPT;
|
||||||
|
|
||||||
case ZT_NETWORK_RULE_ACTION_DROP:
|
case ZT_NETWORK_RULE_ACTION_DROP:
|
||||||
|
@ -180,7 +175,7 @@ static _doZtFilterResult _doZtFilter(
|
||||||
|
|
||||||
// Circuit breaker: no need to evaluate an AND if the set's match state
|
// Circuit breaker: no need to evaluate an AND if the set's match state
|
||||||
// is currently false since anything AND false is false.
|
// is currently false since anything AND false is false.
|
||||||
if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) {
|
if ((!thisSetMatches)&&(!(rules[rn].t & 0x40U))) {
|
||||||
rrl.logSkipped(rn,thisSetMatches);
|
rrl.logSkipped(rn,thisSetMatches);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +240,7 @@ static _doZtFilterResult _doZtFilter(
|
||||||
const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask;
|
const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask;
|
||||||
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
|
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
|
||||||
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
|
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
|
||||||
const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask;
|
const uint8_t tosMasked = (((frameData[0] << 4U) & 0xf0U) | ((frameData[1] >> 4U) & 0x0fU)) & rules[rn].v.ipTos.mask;
|
||||||
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
|
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
|
||||||
} else {
|
} else {
|
||||||
thisRuleMatches = 0;
|
thisRuleMatches = 0;
|
||||||
|
@ -271,7 +266,7 @@ static _doZtFilterResult _doZtFilter(
|
||||||
case ZT_NETWORK_RULE_MATCH_ICMP:
|
case ZT_NETWORK_RULE_MATCH_ICMP:
|
||||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||||
if (frameData[9] == 0x01) { // IP protocol == ICMP
|
if (frameData[9] == 0x01) { // IP protocol == ICMP
|
||||||
const unsigned int ihl = (frameData[0] & 0xf) * 4;
|
const unsigned int ihl = (frameData[0] & 0xfU) * 4;
|
||||||
if (frameLen >= (ihl + 2)) {
|
if (frameLen >= (ihl + 2)) {
|
||||||
if (rules[rn].v.icmp.type == frameData[ihl]) {
|
if (rules[rn].v.icmp.type == frameData[ihl]) {
|
||||||
if ((rules[rn].v.icmp.flags & 0x01) != 0) {
|
if ((rules[rn].v.icmp.flags & 0x01) != 0) {
|
||||||
|
@ -314,7 +309,7 @@ static _doZtFilterResult _doZtFilter(
|
||||||
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
|
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
|
||||||
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
|
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
|
||||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||||
const unsigned int headerLen = 4 * (frameData[0] & 0xf);
|
const unsigned int headerLen = 4 * (frameData[0] & 0xfU);
|
||||||
int p = -1;
|
int p = -1;
|
||||||
switch(frameData[9]) { // IP protocol number
|
switch(frameData[9]) { // IP protocol number
|
||||||
// All these start with 16-bit source and destination port in that order
|
// All these start with 16-bit source and destination port in that order
|
||||||
|
@ -324,7 +319,7 @@ static _doZtFilterResult _doZtFilter(
|
||||||
case 0x88: // UDPLite
|
case 0x88: // UDPLite
|
||||||
if (frameLen > (headerLen + 4)) {
|
if (frameLen > (headerLen + 4)) {
|
||||||
unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0);
|
unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0);
|
||||||
p = (int)frameData[pos++] << 8;
|
p = (int)(frameData[pos++] << 8U);
|
||||||
p |= (int)frameData[pos];
|
p |= (int)frameData[pos];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -343,7 +338,7 @@ static _doZtFilterResult _doZtFilter(
|
||||||
case 0x88: // UDPLite
|
case 0x88: // UDPLite
|
||||||
if (frameLen > (pos + 4)) {
|
if (frameLen > (pos + 4)) {
|
||||||
if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2;
|
if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2;
|
||||||
p = (int)frameData[pos++] << 8;
|
p = (int)(frameData[pos++] << 8U);
|
||||||
p |= (int)frameData[pos];
|
p |= (int)frameData[pos];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -402,15 +397,15 @@ static _doZtFilterResult _doZtFilter(
|
||||||
}
|
}
|
||||||
cf |= ownershipVerificationMask;
|
cf |= ownershipVerificationMask;
|
||||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)&&(frameData[9] == 0x06)) {
|
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)&&(frameData[9] == 0x06)) {
|
||||||
const unsigned int headerLen = 4 * (frameData[0] & 0xf);
|
const unsigned int headerLen = 4 * (frameData[0] & 0xfU);
|
||||||
cf |= (uint64_t)frameData[headerLen + 13];
|
cf |= (uint64_t)frameData[headerLen + 13];
|
||||||
cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0f)) << 8);
|
cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0fU)) << 8U);
|
||||||
} else if (etherType == ZT_ETHERTYPE_IPV6) {
|
} else if (etherType == ZT_ETHERTYPE_IPV6) {
|
||||||
unsigned int pos = 0,proto = 0;
|
unsigned int pos = 0,proto = 0;
|
||||||
if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
|
if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
|
||||||
if ((proto == 0x06)&&(frameLen > (pos + 14))) {
|
if ((proto == 0x06)&&(frameLen > (pos + 14))) {
|
||||||
cf |= (uint64_t)frameData[pos + 13];
|
cf |= (uint64_t)frameData[pos + 13];
|
||||||
cf |= (((uint64_t)(frameData[pos + 12] & 0x0f)) << 8);
|
cf |= (((uint64_t)(frameData[pos + 12] & 0x0fU)) << 8U);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,15 +486,15 @@ static _doZtFilterResult _doZtFilter(
|
||||||
} break;
|
} break;
|
||||||
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: {
|
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: {
|
||||||
uint64_t integer = 0;
|
uint64_t integer = 0;
|
||||||
const unsigned int bits = (rules[rn].v.intRange.format & 63) + 1;
|
const unsigned int bits = (rules[rn].v.intRange.format & 63U) + 1;
|
||||||
const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8
|
const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8
|
||||||
if ((rules[rn].v.intRange.format & 0x80) == 0) {
|
if ((rules[rn].v.intRange.format & 0x80U) == 0) {
|
||||||
// Big-endian
|
// Big-endian
|
||||||
unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes);
|
unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes);
|
||||||
const unsigned int eof = idx + bytes;
|
const unsigned int eof = idx + bytes;
|
||||||
if (eof <= frameLen) {
|
if (eof <= frameLen) {
|
||||||
while (idx < eof) {
|
while (idx < eof) {
|
||||||
integer <<= 8;
|
integer <<= 8U;
|
||||||
integer |= frameData[idx++];
|
integer |= frameData[idx++];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,8 +505,8 @@ static _doZtFilterResult _doZtFilter(
|
||||||
const unsigned int eof = idx + bytes;
|
const unsigned int eof = idx + bytes;
|
||||||
if (eof <= frameLen) {
|
if (eof <= frameLen) {
|
||||||
while (idx < eof) {
|
while (idx < eof) {
|
||||||
integer >>= 8;
|
integer >>= 8U;
|
||||||
integer |= ((uint64_t)frameData[idx++]) << 56;
|
integer |= ((uint64_t)frameData[idx++]) << 56U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
integer >>= (64 - bits);
|
integer >>= (64 - bits);
|
||||||
|
@ -528,9 +523,9 @@ static _doZtFilterResult _doZtFilter(
|
||||||
|
|
||||||
rrl.log(rn,thisRuleMatches,thisSetMatches);
|
rrl.log(rn,thisRuleMatches,thisSetMatches);
|
||||||
|
|
||||||
if ((rules[rn].t & 0x40))
|
if ((rules[rn].t & 0x40U))
|
||||||
thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
|
thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U));
|
||||||
else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
|
else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U));
|
||||||
}
|
}
|
||||||
|
|
||||||
return DOZTFILTER_NO_MATCH;
|
return DOZTFILTER_NO_MATCH;
|
||||||
|
@ -622,10 +617,10 @@ bool Network::filterOutgoingPacket(
|
||||||
const unsigned int vlanId,
|
const unsigned int vlanId,
|
||||||
uint8_t &qosBucket)
|
uint8_t &qosBucket)
|
||||||
{
|
{
|
||||||
|
Trace::RuleResultLog rrl,crrl;
|
||||||
Address ztFinalDest(ztDest);
|
Address ztFinalDest(ztDest);
|
||||||
int localCapabilityIndex = -1;
|
int localCapabilityIndex = -1;
|
||||||
int accept = 0;
|
int accept = 0;
|
||||||
Trace::RuleResultLog rrl,crrl;
|
|
||||||
Address cc;
|
Address cc;
|
||||||
unsigned int ccLength = 0;
|
unsigned int ccLength = 0;
|
||||||
bool ccWatch = false;
|
bool ccWatch = false;
|
||||||
|
@ -674,8 +669,7 @@ bool Network::filterOutgoingPacket(
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case DOZTFILTER_DROP:
|
case DOZTFILTER_DROP:
|
||||||
//if (_config.remoteTraceTarget)
|
RR->t->networkFilter(tPtr,_id,rrl.l,nullptr,0,0,ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,0);
|
||||||
// RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
|
case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
|
||||||
|
@ -688,10 +682,7 @@ bool Network::filterOutgoingPacket(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accept) {
|
if (accept != 0) {
|
||||||
if (membership)
|
|
||||||
membership->logSentBytes(frameLen);
|
|
||||||
|
|
||||||
if ((!noTee)&&(cc)) {
|
if ((!noTee)&&(cc)) {
|
||||||
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||||
outp.append(_id);
|
outp.append(_id);
|
||||||
|
@ -715,19 +706,19 @@ bool Network::filterOutgoingPacket(
|
||||||
outp.compress();
|
outp.compress();
|
||||||
RR->sw->send(tPtr,outp,true);
|
RR->sw->send(tPtr,outp,true);
|
||||||
|
|
||||||
//if (_config.remoteTraceTarget)
|
// DROP locally since we redirected
|
||||||
// RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
|
accept = 0;
|
||||||
return false; // DROP locally, since we redirected
|
|
||||||
} else {
|
|
||||||
//if (_config.remoteTraceTarget)
|
|
||||||
// RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
//if (_config.remoteTraceTarget)
|
|
||||||
// RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (localCapabilityIndex >= 0) {
|
||||||
|
const Capability &cap = _config.capabilities[localCapabilityIndex];
|
||||||
|
RR->t->networkFilter(tPtr,_id,rrl.l,crrl.l,cap.id(),cap.timestamp(),ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,accept);
|
||||||
|
} else {
|
||||||
|
RR->t->networkFilter(tPtr,_id,rrl.l,nullptr,0,0,ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (accept != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Network::filterIncomingPacket(
|
int Network::filterIncomingPacket(
|
||||||
|
@ -810,8 +801,6 @@ int Network::filterIncomingPacket(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accept) {
|
if (accept) {
|
||||||
membership.logReceivedBytes(frameLen);
|
|
||||||
|
|
||||||
if (cc) {
|
if (cc) {
|
||||||
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||||
outp.append(_id);
|
outp.append(_id);
|
||||||
|
@ -846,6 +835,24 @@ int Network::filterIncomingPacket(
|
||||||
return accept;
|
return accept;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg)
|
||||||
|
{
|
||||||
|
Mutex::Lock l(_myMulticastGroups_l);
|
||||||
|
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
|
||||||
|
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
|
||||||
|
Mutex::Lock l2(_memberships_l);
|
||||||
|
_announceMulticastGroups(tPtr,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::multicastUnsubscribe(const MulticastGroup &mg)
|
||||||
|
{
|
||||||
|
Mutex::Lock l(_myMulticastGroups_l);
|
||||||
|
std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
|
||||||
|
if ( (i != _myMulticastGroups.end()) && (*i == mg) )
|
||||||
|
_myMulticastGroups.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr)
|
uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr)
|
||||||
{
|
{
|
||||||
if (_destroyed)
|
if (_destroyed)
|
||||||
|
@ -861,11 +868,11 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
|
||||||
{
|
{
|
||||||
Mutex::Lock l1(_config_l);
|
Mutex::Lock l1(_config_l);
|
||||||
|
|
||||||
_IncomingConfigChunk *c = (_IncomingConfigChunk *)0;
|
_IncomingConfigChunk *c = nullptr;
|
||||||
uint64_t chunkId = 0;
|
uint64_t chunkId = 0;
|
||||||
unsigned long totalLength,chunkIndex;
|
unsigned long totalLength,chunkIndex;
|
||||||
if (ptr < chunk.size()) {
|
if (ptr < chunk.size()) {
|
||||||
const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0);
|
const bool fastPropagate = ((chunk[ptr++] & 0x01U) != 0);
|
||||||
configUpdateId = chunk.at<uint64_t>(ptr); ptr += 8;
|
configUpdateId = chunk.at<uint64_t>(ptr); ptr += 8;
|
||||||
totalLength = chunk.at<uint32_t>(ptr); ptr += 4;
|
totalLength = chunk.at<uint32_t>(ptr); ptr += 4;
|
||||||
chunkIndex = chunk.at<uint32_t>(ptr); ptr += 4;
|
chunkIndex = chunk.at<uint32_t>(ptr); ptr += 4;
|
||||||
|
@ -906,8 +913,8 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
|
||||||
// New properly verified chunks can be flooded "virally" through the network
|
// New properly verified chunks can be flooded "virally" through the network
|
||||||
if (fastPropagate) {
|
if (fastPropagate) {
|
||||||
Mutex::Lock l2(_memberships_l);
|
Mutex::Lock l2(_memberships_l);
|
||||||
Address *a = (Address *)0;
|
Address *a = nullptr;
|
||||||
Membership *m = (Membership *)0;
|
Membership *m = nullptr;
|
||||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||||
while (i.next(a,m)) {
|
while (i.next(a,m)) {
|
||||||
if ((*a != source)&&(*a != controller())) {
|
if ((*a != source)&&(*a != controller())) {
|
||||||
|
@ -1102,7 +1109,31 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev)
|
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com)
|
||||||
|
{
|
||||||
|
if (com.networkId() != _id)
|
||||||
|
return Membership::ADD_REJECTED;
|
||||||
|
Mutex::Lock _l(_memberships_l);
|
||||||
|
return _memberships[com.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,com);
|
||||||
|
}
|
||||||
|
|
||||||
|
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap)
|
||||||
|
{
|
||||||
|
if (cap.networkId() != _id)
|
||||||
|
return Membership::ADD_REJECTED;
|
||||||
|
Mutex::Lock _l(_memberships_l);
|
||||||
|
return _memberships[cap.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag)
|
||||||
|
{
|
||||||
|
if (tag.networkId() != _id)
|
||||||
|
return Membership::ADD_REJECTED;
|
||||||
|
Mutex::Lock _l(_memberships_l);
|
||||||
|
return _memberships[tag.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Revocation &rev)
|
||||||
{
|
{
|
||||||
if (rev.networkId() != _id)
|
if (rev.networkId() != _id)
|
||||||
return Membership::ADD_REJECTED;
|
return Membership::ADD_REJECTED;
|
||||||
|
@ -1110,14 +1141,14 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address
|
||||||
Mutex::Lock l1(_memberships_l);
|
Mutex::Lock l1(_memberships_l);
|
||||||
Membership &m = _memberships[rev.target()];
|
Membership &m = _memberships[rev.target()];
|
||||||
|
|
||||||
const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,rev);
|
const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,sourcePeerIdentity,_config,rev);
|
||||||
|
|
||||||
if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) {
|
if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) {
|
||||||
Address *a = (Address *)0;
|
Address *a = nullptr;
|
||||||
Membership *m = (Membership *)0;
|
Membership *m = nullptr;
|
||||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||||
while (i.next(a,m)) {
|
while (i.next(a,m)) {
|
||||||
if ((*a != sentFrom)&&(*a != rev.signer())) {
|
if ((*a != sourcePeerIdentity.address())&&(*a != rev.signer())) {
|
||||||
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
||||||
outp.append((uint8_t)0x00); // no COM
|
outp.append((uint8_t)0x00); // no COM
|
||||||
outp.append((uint16_t)0); // no capabilities
|
outp.append((uint16_t)0); // no capabilities
|
||||||
|
@ -1133,15 +1164,44 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo)
|
||||||
|
{
|
||||||
|
if (coo.networkId() != _id)
|
||||||
|
return Membership::ADD_REJECTED;
|
||||||
|
Mutex::Lock _l(_memberships_l);
|
||||||
|
return _memberships[coo.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,coo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::pushCredentialsNow(void *tPtr,const Address &to,const int64_t now)
|
||||||
|
{
|
||||||
|
Mutex::Lock _l(_memberships_l);
|
||||||
|
_memberships[to].pushCredentials(RR,tPtr,now,to,_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::destroy()
|
||||||
|
{
|
||||||
|
_memberships_l.lock();
|
||||||
|
_config_l.lock();
|
||||||
|
_destroyed = true;
|
||||||
|
_config_l.unlock();
|
||||||
|
_memberships_l.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Network::externalConfig(ZT_VirtualNetworkConfig *ec) const
|
||||||
|
{
|
||||||
|
Mutex::Lock _l(_config_l);
|
||||||
|
_externalConfig(ec);
|
||||||
|
}
|
||||||
|
|
||||||
void Network::_requestConfiguration(void *tPtr)
|
void Network::_requestConfiguration(void *tPtr)
|
||||||
{
|
{
|
||||||
if (_destroyed)
|
if (_destroyed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((_id >> 56) == 0xff) {
|
if ((_id >> 56U) == 0xff) {
|
||||||
if ((_id & 0xffffff) == 0) {
|
if ((_id & 0xffffffU) == 0) {
|
||||||
const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff);
|
const uint16_t startPortRange = (uint16_t)((_id >> 40U) & 0xffff);
|
||||||
const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff);
|
const uint16_t endPortRange = (uint16_t)((_id >> 24U) & 0xffff);
|
||||||
if (endPortRange >= startPortRange) {
|
if (endPortRange >= startPortRange) {
|
||||||
ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
|
ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
|
||||||
|
|
||||||
|
@ -1158,7 +1218,7 @@ void Network::_requestConfiguration(void *tPtr)
|
||||||
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
|
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
|
||||||
|
|
||||||
// Drop everything but IPv6
|
// Drop everything but IPv6
|
||||||
nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80; // NOT
|
nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80U; // NOT
|
||||||
nconf->rules[0].v.etherType = 0x86dd; // IPv6
|
nconf->rules[0].v.etherType = 0x86dd; // IPv6
|
||||||
nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP;
|
nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP;
|
||||||
|
|
||||||
|
@ -1170,7 +1230,7 @@ void Network::_requestConfiguration(void *tPtr)
|
||||||
// Allow destination ports within range
|
// Allow destination ports within range
|
||||||
nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL;
|
nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL;
|
||||||
nconf->rules[4].v.ipProtocol = 0x11; // UDP
|
nconf->rules[4].v.ipProtocol = 0x11; // UDP
|
||||||
nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40; // OR
|
nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40U; // OR
|
||||||
nconf->rules[5].v.ipProtocol = 0x06; // TCP
|
nconf->rules[5].v.ipProtocol = 0x06; // TCP
|
||||||
nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE;
|
nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE;
|
||||||
nconf->rules[6].v.port[0] = startPortRange;
|
nconf->rules[6].v.port[0] = startPortRange;
|
||||||
|
@ -1178,7 +1238,7 @@ void Network::_requestConfiguration(void *tPtr)
|
||||||
nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
|
nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
|
||||||
|
|
||||||
// Allow non-SYN TCP packets to permit non-connection-initiating traffic
|
// Allow non-SYN TCP packets to permit non-connection-initiating traffic
|
||||||
nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80; // NOT
|
nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80U; // NOT
|
||||||
nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN;
|
nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN;
|
||||||
nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
|
nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
|
||||||
|
|
||||||
|
@ -1208,16 +1268,16 @@ void Network::_requestConfiguration(void *tPtr)
|
||||||
} else {
|
} else {
|
||||||
this->setNotFound();
|
this->setNotFound();
|
||||||
}
|
}
|
||||||
} else if ((_id & 0xff) == 0x01) {
|
} else if ((_id & 0xffU) == 0x01) {
|
||||||
// ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication
|
// ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication
|
||||||
const uint64_t myAddress = RR->identity.address().toInt();
|
const uint64_t myAddress = RR->identity.address().toInt();
|
||||||
const uint64_t networkHub = (_id >> 8) & 0xffffffffffULL;
|
const uint64_t networkHub = (_id >> 8U) & 0xffffffffffULL;
|
||||||
|
|
||||||
uint8_t ipv4[4];
|
uint8_t ipv4[4];
|
||||||
ipv4[0] = (uint8_t)((_id >> 48) & 0xff);
|
ipv4[0] = (uint8_t)(_id >> 48U);
|
||||||
ipv4[1] = (uint8_t)((myAddress >> 16) & 0xff);
|
ipv4[1] = (uint8_t)(myAddress >> 16U);
|
||||||
ipv4[2] = (uint8_t)((myAddress >> 8) & 0xff);
|
ipv4[2] = (uint8_t)(myAddress >> 8U);
|
||||||
ipv4[3] = (uint8_t)(myAddress & 0xff);
|
ipv4[3] = (uint8_t)myAddress;
|
||||||
|
|
||||||
char v4ascii[24];
|
char v4ascii[24];
|
||||||
Utils::decimal(ipv4[0],v4ascii);
|
Utils::decimal(ipv4[0],v4ascii);
|
||||||
|
@ -1282,7 +1342,7 @@ void Network::_requestConfiguration(void *tPtr)
|
||||||
rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0);
|
rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0);
|
||||||
rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION);
|
rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION);
|
||||||
|
|
||||||
RR->t->networkConfigRequestSent(tPtr,*this,ctrl);
|
RR->t->networkConfigRequestSent(tPtr,_id);
|
||||||
|
|
||||||
if (ctrl == RR->identity.address()) {
|
if (ctrl == RR->identity.address()) {
|
||||||
if (RR->localNetworkController) {
|
if (RR->localNetworkController) {
|
||||||
|
|
135
node/Network.hpp
135
node/Network.hpp
|
@ -58,7 +58,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Compute primary controller device ID from network ID
|
* Compute primary controller device ID from network ID
|
||||||
*/
|
*/
|
||||||
static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); }
|
static ZT_ALWAYS_INLINE Address controllerFor(uint64_t nwid) { return Address(nwid >> 24U); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new network
|
* Construct a new network
|
||||||
|
@ -76,14 +76,14 @@ public:
|
||||||
|
|
||||||
~Network();
|
~Network();
|
||||||
|
|
||||||
inline uint64_t id() const { return _id; }
|
ZT_ALWAYS_INLINE uint64_t id() const { return _id; }
|
||||||
inline Address controller() const { return Address(_id >> 24); }
|
ZT_ALWAYS_INLINE Address controller() const { return Address(_id >> 24); }
|
||||||
inline bool multicastEnabled() const { return (_config.multicastLimit > 0); }
|
ZT_ALWAYS_INLINE bool multicastEnabled() const { return (_config.multicastLimit > 0); }
|
||||||
inline bool hasConfig() const { return (_config); }
|
ZT_ALWAYS_INLINE bool hasConfig() const { return (_config); }
|
||||||
inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; }
|
ZT_ALWAYS_INLINE uint64_t lastConfigUpdate() const { return _lastConfigUpdate; }
|
||||||
inline ZT_VirtualNetworkStatus status() const { return _status(); }
|
ZT_ALWAYS_INLINE ZT_VirtualNetworkStatus status() const { return _status(); }
|
||||||
inline const NetworkConfig &config() const { return _config; }
|
ZT_ALWAYS_INLINE const NetworkConfig &config() const { return _config; }
|
||||||
inline const MAC &mac() const { return _mac; }
|
ZT_ALWAYS_INLINE const MAC &mac() const { return _mac; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply filters to an outgoing packet
|
* Apply filters to an outgoing packet
|
||||||
|
@ -107,15 +107,15 @@ public:
|
||||||
*/
|
*/
|
||||||
bool filterOutgoingPacket(
|
bool filterOutgoingPacket(
|
||||||
void *tPtr,
|
void *tPtr,
|
||||||
const bool noTee,
|
bool noTee,
|
||||||
const Address &ztSource,
|
const Address &ztSource,
|
||||||
const Address &ztDest,
|
const Address &ztDest,
|
||||||
const MAC &macSource,
|
const MAC &macSource,
|
||||||
const MAC &macDest,
|
const MAC &macDest,
|
||||||
const uint8_t *frameData,
|
const uint8_t *frameData,
|
||||||
const unsigned int frameLen,
|
unsigned int frameLen,
|
||||||
const unsigned int etherType,
|
unsigned int etherType,
|
||||||
const unsigned int vlanId,
|
unsigned int vlanId,
|
||||||
uint8_t &qosBucket);
|
uint8_t &qosBucket);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,9 +144,9 @@ public:
|
||||||
const MAC &macSource,
|
const MAC &macSource,
|
||||||
const MAC &macDest,
|
const MAC &macDest,
|
||||||
const uint8_t *frameData,
|
const uint8_t *frameData,
|
||||||
const unsigned int frameLen,
|
unsigned int frameLen,
|
||||||
const unsigned int etherType,
|
unsigned int etherType,
|
||||||
const unsigned int vlanId);
|
unsigned int vlanId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether we are subscribed to a multicast group
|
* Check whether we are subscribed to a multicast group
|
||||||
|
@ -155,7 +155,7 @@ public:
|
||||||
* @param includeBridgedGroups If true, also check groups we've learned via bridging
|
* @param includeBridgedGroups If true, also check groups we've learned via bridging
|
||||||
* @return True if this network endpoint / peer is a member
|
* @return True if this network endpoint / peer is a member
|
||||||
*/
|
*/
|
||||||
inline bool subscribedToMulticastGroup(const MulticastGroup &mg,const bool includeBridgedGroups) const
|
ZT_ALWAYS_INLINE bool subscribedToMulticastGroup(const MulticastGroup &mg,const bool includeBridgedGroups) const
|
||||||
{
|
{
|
||||||
Mutex::Lock l(_myMulticastGroups_l);
|
Mutex::Lock l(_myMulticastGroups_l);
|
||||||
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
|
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
|
||||||
|
@ -171,28 +171,14 @@ public:
|
||||||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||||
* @param mg New multicast group
|
* @param mg New multicast group
|
||||||
*/
|
*/
|
||||||
inline void multicastSubscribe(void *tPtr,const MulticastGroup &mg)
|
void multicastSubscribe(void *tPtr,const MulticastGroup &mg);
|
||||||
{
|
|
||||||
Mutex::Lock l(_myMulticastGroups_l);
|
|
||||||
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
|
|
||||||
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
|
|
||||||
Mutex::Lock l2(_memberships_l);
|
|
||||||
_announceMulticastGroups(tPtr,true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsubscribe from a multicast group
|
* Unsubscribe from a multicast group
|
||||||
*
|
*
|
||||||
* @param mg Multicast group
|
* @param mg Multicast group
|
||||||
*/
|
*/
|
||||||
inline void multicastUnsubscribe(const MulticastGroup &mg)
|
void multicastUnsubscribe(const MulticastGroup &mg);
|
||||||
{
|
|
||||||
Mutex::Lock l(_myMulticastGroups_l);
|
|
||||||
std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
|
|
||||||
if ( (i != _myMulticastGroups.end()) && (*i == mg) )
|
|
||||||
_myMulticastGroups.erase(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an inbound network config chunk
|
* Handle an inbound network config chunk
|
||||||
|
@ -208,7 +194,7 @@ public:
|
||||||
* @param ptr Index of chunk and related fields in packet
|
* @param ptr Index of chunk and related fields in packet
|
||||||
* @return Update ID if update was fully assembled and accepted or 0 otherwise
|
* @return Update ID if update was fully assembled and accepted or 0 otherwise
|
||||||
*/
|
*/
|
||||||
uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr);
|
uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set network configuration
|
* Set network configuration
|
||||||
|
@ -227,12 +213,12 @@ public:
|
||||||
/**
|
/**
|
||||||
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
|
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
|
||||||
*/
|
*/
|
||||||
inline void setAccessDenied() { _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; }
|
ZT_ALWAYS_INLINE void setAccessDenied() { _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
|
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
|
||||||
*/
|
*/
|
||||||
inline void setNotFound() { _netconfFailure = NETCONF_FAILURE_NOT_FOUND; }
|
ZT_ALWAYS_INLINE void setNotFound() { _netconfFailure = NETCONF_FAILURE_NOT_FOUND; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether this peer is permitted to communicate on this network
|
* Determine whether this peer is permitted to communicate on this network
|
||||||
|
@ -245,7 +231,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Do periodic cleanup and housekeeping tasks
|
* Do periodic cleanup and housekeeping tasks
|
||||||
*/
|
*/
|
||||||
void doPeriodicTasks(void *tPtr,const int64_t now);
|
void doPeriodicTasks(void *tPtr,int64_t now);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the node on this network that has this MAC behind it (if any)
|
* Find the node on this network that has this MAC behind it (if any)
|
||||||
|
@ -253,18 +239,13 @@ public:
|
||||||
* @param mac MAC address
|
* @param mac MAC address
|
||||||
* @return ZeroTier address of bridge to this MAC
|
* @return ZeroTier address of bridge to this MAC
|
||||||
*/
|
*/
|
||||||
inline Address findBridgeTo(const MAC &mac) const
|
ZT_ALWAYS_INLINE Address findBridgeTo(const MAC &mac) const
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_remoteBridgeRoutes_l);
|
Mutex::Lock _l(_remoteBridgeRoutes_l);
|
||||||
const Address *const br = _remoteBridgeRoutes.get(mac);
|
const Address *const br = _remoteBridgeRoutes.get(mac);
|
||||||
return ((br) ? *br : Address());
|
return ((br) ? *br : Address());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return True if QoS is in effect for this network
|
|
||||||
*/
|
|
||||||
inline bool qosEnabled() { return false; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a bridge route
|
* Set a bridge route
|
||||||
*
|
*
|
||||||
|
@ -280,7 +261,7 @@ public:
|
||||||
* @param mg Multicast group
|
* @param mg Multicast group
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
*/
|
*/
|
||||||
inline void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now)
|
ZT_ALWAYS_INLINE void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now)
|
||||||
{
|
{
|
||||||
Mutex::Lock l(_myMulticastGroups_l);
|
Mutex::Lock l(_myMulticastGroups_l);
|
||||||
_multicastGroupsBehindMe.set(mg,now);
|
_multicastGroupsBehindMe.set(mg,now);
|
||||||
|
@ -289,51 +270,27 @@ public:
|
||||||
/**
|
/**
|
||||||
* Validate a credential and learn it if it passes certificate and other checks
|
* Validate a credential and learn it if it passes certificate and other checks
|
||||||
*/
|
*/
|
||||||
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com)
|
Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com);
|
||||||
{
|
|
||||||
if (com.networkId() != _id)
|
|
||||||
return Membership::ADD_REJECTED;
|
|
||||||
Mutex::Lock _l(_memberships_l);
|
|
||||||
return _memberships[com.issuedTo()].addCredential(RR,tPtr,_config,com);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate a credential and learn it if it passes certificate and other checks
|
* Validate a credential and learn it if it passes certificate and other checks
|
||||||
*/
|
*/
|
||||||
inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap)
|
Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap);
|
||||||
{
|
|
||||||
if (cap.networkId() != _id)
|
|
||||||
return Membership::ADD_REJECTED;
|
|
||||||
Mutex::Lock _l(_memberships_l);
|
|
||||||
return _memberships[cap.issuedTo()].addCredential(RR,tPtr,_config,cap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate a credential and learn it if it passes certificate and other checks
|
* Validate a credential and learn it if it passes certificate and other checks
|
||||||
*/
|
*/
|
||||||
inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag)
|
Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag);
|
||||||
{
|
|
||||||
if (tag.networkId() != _id)
|
|
||||||
return Membership::ADD_REJECTED;
|
|
||||||
Mutex::Lock _l(_memberships_l);
|
|
||||||
return _memberships[tag.issuedTo()].addCredential(RR,tPtr,_config,tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate a credential and learn it if it passes certificate and other checks
|
* Validate a credential and learn it if it passes certificate and other checks
|
||||||
*/
|
*/
|
||||||
Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev);
|
Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Revocation &rev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate a credential and learn it if it passes certificate and other checks
|
* Validate a credential and learn it if it passes certificate and other checks
|
||||||
*/
|
*/
|
||||||
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo)
|
Membership::AddCredentialResult addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo);
|
||||||
{
|
|
||||||
if (coo.networkId() != _id)
|
|
||||||
return Membership::ADD_REJECTED;
|
|
||||||
Mutex::Lock _l(_memberships_l);
|
|
||||||
return _memberships[coo.issuedTo()].addCredential(RR,tPtr,_config,coo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force push credentials (COM, etc.) to a peer now
|
* Force push credentials (COM, etc.) to a peer now
|
||||||
|
@ -342,11 +299,7 @@ public:
|
||||||
* @param to Destination peer address
|
* @param to Destination peer address
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
*/
|
*/
|
||||||
inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now)
|
void pushCredentialsNow(void *tPtr,const Address &to,int64_t now);
|
||||||
{
|
|
||||||
Mutex::Lock _l(_memberships_l);
|
|
||||||
_memberships[to].pushCredentials(RR,tPtr,now,to,_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push credentials if we haven't done so in a long time
|
* Push credentials if we haven't done so in a long time
|
||||||
|
@ -355,7 +308,7 @@ public:
|
||||||
* @param to Destination peer address
|
* @param to Destination peer address
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
*/
|
*/
|
||||||
inline void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now)
|
ZT_ALWAYS_INLINE void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now)
|
||||||
{
|
{
|
||||||
const int64_t tout = std::min(_config.credentialTimeMaxDelta,(int64_t)ZT_PEER_ACTIVITY_TIMEOUT);
|
const int64_t tout = std::min(_config.credentialTimeMaxDelta,(int64_t)ZT_PEER_ACTIVITY_TIMEOUT);
|
||||||
Mutex::Lock _l(_memberships_l);
|
Mutex::Lock _l(_memberships_l);
|
||||||
|
@ -370,25 +323,14 @@ public:
|
||||||
* This sets the network to completely remove itself on delete. This also prevents the
|
* This sets the network to completely remove itself on delete. This also prevents the
|
||||||
* call of the normal port shutdown event on delete.
|
* call of the normal port shutdown event on delete.
|
||||||
*/
|
*/
|
||||||
inline void destroy()
|
void destroy();
|
||||||
{
|
|
||||||
_memberships_l.lock();
|
|
||||||
_config_l.lock();
|
|
||||||
_destroyed = true;
|
|
||||||
_config_l.unlock();
|
|
||||||
_memberships_l.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get this network's config for export via the ZT core API
|
* Get this network's config for export via the ZT core API
|
||||||
*
|
*
|
||||||
* @param ec Buffer to fill with externally-visible network configuration
|
* @param ec Buffer to fill with externally-visible network configuration
|
||||||
*/
|
*/
|
||||||
inline void externalConfig(ZT_VirtualNetworkConfig *ec) const
|
void externalConfig(ZT_VirtualNetworkConfig *ec) const;
|
||||||
{
|
|
||||||
Mutex::Lock _l(_config_l);
|
|
||||||
_externalConfig(ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate through memberships
|
* Iterate through memberships
|
||||||
|
@ -396,7 +338,7 @@ public:
|
||||||
* @param f Function of (const Address,const Membership)
|
* @param f Function of (const Address,const Membership)
|
||||||
*/
|
*/
|
||||||
template<typename F>
|
template<typename F>
|
||||||
inline void eachMember(F f)
|
ZT_ALWAYS_INLINE void eachMember(F f)
|
||||||
{
|
{
|
||||||
Mutex::Lock ml(_memberships_l);
|
Mutex::Lock ml(_memberships_l);
|
||||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||||
|
@ -411,13 +353,12 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return Externally usable pointer-to-pointer exported via the core API
|
* @return Externally usable pointer-to-pointer exported via the core API
|
||||||
*/
|
*/
|
||||||
inline void **userPtr() { return &_uPtr; }
|
ZT_ALWAYS_INLINE void **userPtr() { return &_uPtr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _requestConfiguration(void *tPtr);
|
void _requestConfiguration(void *tPtr);
|
||||||
ZT_VirtualNetworkStatus _status() const;
|
ZT_VirtualNetworkStatus _status() const;
|
||||||
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
|
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
|
||||||
bool _gate(const SharedPtr<Peer> &peer);
|
|
||||||
void _announceMulticastGroups(void *tPtr,bool force);
|
void _announceMulticastGroups(void *tPtr,bool force);
|
||||||
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
|
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
|
||||||
std::vector<MulticastGroup> _allMulticastGroups() const;
|
std::vector<MulticastGroup> _allMulticastGroups() const;
|
||||||
|
@ -433,11 +374,11 @@ private:
|
||||||
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
|
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
|
||||||
|
|
||||||
NetworkConfig _config;
|
NetworkConfig _config;
|
||||||
uint64_t _lastConfigUpdate;
|
volatile uint64_t _lastConfigUpdate;
|
||||||
|
|
||||||
struct _IncomingConfigChunk
|
struct _IncomingConfigChunk
|
||||||
{
|
{
|
||||||
inline _IncomingConfigChunk() : ts(0),updateId(0),haveChunks(0),haveBytes(0),data() {}
|
ZT_ALWAYS_INLINE _IncomingConfigChunk() : ts(0),updateId(0),haveChunks(0),haveBytes(0),data() {}
|
||||||
uint64_t ts;
|
uint64_t ts;
|
||||||
uint64_t updateId;
|
uint64_t updateId;
|
||||||
uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];
|
uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];
|
||||||
|
|
|
@ -33,10 +33,6 @@
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
/* Public Node interface (C++, exposed via CAPI bindings) */
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64_t now) :
|
Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64_t now) :
|
||||||
_RR(this),
|
_RR(this),
|
||||||
RR(&_RR),
|
RR(&_RR),
|
||||||
|
@ -437,7 +433,7 @@ ZT_PeerList *Node::peers() const
|
||||||
p->address = (*pi)->address().toInt();
|
p->address = (*pi)->address().toInt();
|
||||||
identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted
|
identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted
|
||||||
p->identity = &identities[pl->peerCount];
|
p->identity = &identities[pl->peerCount];
|
||||||
(*pi)->identity().hash(p->identityHash,false);
|
memcpy(p->identityHash,(*pi)->identity().hash(),sizeof(p->identityHash));
|
||||||
if ((*pi)->remoteVersionKnown()) {
|
if ((*pi)->remoteVersionKnown()) {
|
||||||
p->versionMajor = (int)(*pi)->remoteVersionMajor();
|
p->versionMajor = (int)(*pi)->remoteVersionMajor();
|
||||||
p->versionMinor = (int)(*pi)->remoteVersionMinor();
|
p->versionMinor = (int)(*pi)->remoteVersionMinor();
|
||||||
|
|
|
@ -264,7 +264,7 @@ public:
|
||||||
* @param remoteAddress Remote address
|
* @param remoteAddress Remote address
|
||||||
* @return True if path should be used
|
* @return True if path should be used
|
||||||
*/
|
*/
|
||||||
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,const int64_t localSocket,const InetAddress &remoteAddress);
|
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,int64_t localSocket,const InetAddress &remoteAddress);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query callback for a physical address for a peer
|
* Query callback for a physical address for a peer
|
||||||
|
|
11
node/OS.hpp
11
node/OS.hpp
|
@ -28,18 +28,15 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef __GCC__
|
#ifndef __GCC__
|
||||||
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
|
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__INTEL_COMPILER) || defined(__clang__)
|
||||||
#define __GCC__
|
#define __GCC__
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__GCC__) && !defined (__clang__) && !defined(__INTEL_COMPILER)
|
#ifdef _MSC_VER
|
||||||
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
|
|
||||||
#pragma warning(disable : 4290)
|
#pragma warning(disable : 4290)
|
||||||
#pragma warning(disable : 4996)
|
#pragma warning(disable : 4996)
|
||||||
#pragma warning(disable : 4101)
|
#pragma warning(disable : 4101)
|
||||||
#else
|
|
||||||
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
@ -98,8 +95,8 @@
|
||||||
|
|
||||||
// Avoid unaligned type casts on all but x86/x64 architecture.
|
// Avoid unaligned type casts on all but x86/x64 architecture.
|
||||||
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
|
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
|
||||||
#ifndef ZT_NO_TYPE_PUNNING
|
#ifndef ZT_NO_UNALIGNED_ACCESS
|
||||||
#define ZT_NO_TYPE_PUNNING
|
#define ZT_NO_UNALIGNED_ACCESS
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ bool Packet::dearmor(const void *key)
|
||||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||||
uint64_t mac[2];
|
uint64_t mac[2];
|
||||||
poly1305(mac,payload,payloadLen,macKey);
|
poly1305(mac,payload,payloadLen,macKey);
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
|
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -111,7 +111,14 @@ public:
|
||||||
*
|
*
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE bool alive(const int64_t now) const { return ((now - _lastIn) < ZT_PATH_ACTIVITY_TIMEOUT); }
|
ZT_ALWAYS_INLINE bool alive(const int64_t now) const { return ((now - _lastIn) < ZT_PATH_ALIVE_TIMEOUT); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if path is considered active
|
||||||
|
*
|
||||||
|
* @param now Current time
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE bool active(const int64_t now) const { return ((now - _lastIn) < ZT_PATH_ACTIVITY_TIMEOUT); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Physical address
|
* @return Physical address
|
||||||
|
|
|
@ -92,9 +92,7 @@ void Peer::received(
|
||||||
if ((_paths[i]->address().ss_family == path->address().ss_family) &&
|
if ((_paths[i]->address().ss_family == path->address().ss_family) &&
|
||||||
(_paths[i]->localSocket() == path->localSocket()) && // TODO: should be localInterface when multipath is integrated
|
(_paths[i]->localSocket() == path->localSocket()) && // TODO: should be localInterface when multipath is integrated
|
||||||
(_paths[i]->address().ipsEqual2(path->address()))) {
|
(_paths[i]->address().ipsEqual2(path->address()))) {
|
||||||
// If this is another path to the same place, swap it out as the
|
// Replace older path if everything is the same except the port number.
|
||||||
// one we just received from may replace an old one but don't
|
|
||||||
// learn it as a new path.
|
|
||||||
_paths[i] = path;
|
_paths[i] = path;
|
||||||
goto path_check_done;
|
goto path_check_done;
|
||||||
} else {
|
} else {
|
||||||
|
@ -130,7 +128,7 @@ path_check_done:
|
||||||
_lastAttemptedP2PInit = now;
|
_lastAttemptedP2PInit = now;
|
||||||
|
|
||||||
InetAddress addr;
|
InetAddress addr;
|
||||||
if (_bootstrap.type() == Endpoint::INETADDR)
|
if ((_bootstrap.type() == Endpoint::INETADDR_V4)||(_bootstrap.type() == Endpoint::INETADDR_V6))
|
||||||
sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now);
|
sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now);
|
||||||
if (RR->node->externalPathLookup(tPtr,_id,-1,addr)) {
|
if (RR->node->externalPathLookup(tPtr,_id,-1,addr)) {
|
||||||
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,-1,addr))
|
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,-1,addr))
|
||||||
|
@ -256,7 +254,7 @@ void Peer::ping(void *tPtr,int64_t now,const bool pingAllAddressTypes)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bootstrap.type() == Endpoint::INETADDR)
|
if ((_bootstrap.type() == Endpoint::INETADDR_V4)||(_bootstrap.type() == Endpoint::INETADDR_V6))
|
||||||
sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now);
|
sendHELLO(tPtr,-1,_bootstrap.inetAddr(),now);
|
||||||
|
|
||||||
SharedPtr<Peer> r(RR->topology->root());
|
SharedPtr<Peer> r(RR->topology->root());
|
||||||
|
|
|
@ -70,7 +70,7 @@ typedef struct poly1305_state_internal_t {
|
||||||
unsigned char final;
|
unsigned char final;
|
||||||
} poly1305_state_internal_t;
|
} poly1305_state_internal_t;
|
||||||
|
|
||||||
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
|
#if defined(ZT_NO_UNALIGNED_ACCESS) || (__BYTE_ORDER != __LITTLE_ENDIAN)
|
||||||
static inline unsigned long long U8TO64(const unsigned char *p)
|
static inline unsigned long long U8TO64(const unsigned char *p)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
@ -87,7 +87,7 @@ static inline unsigned long long U8TO64(const unsigned char *p)
|
||||||
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p))
|
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
|
#if defined(ZT_NO_UNALIGNED_ACCESS) || (__BYTE_ORDER != __LITTLE_ENDIAN)
|
||||||
static inline void U64TO8(unsigned char *p, unsigned long long v)
|
static inline void U64TO8(unsigned char *p, unsigned long long v)
|
||||||
{
|
{
|
||||||
p[0] = (v ) & 0xff;
|
p[0] = (v ) & 0xff;
|
||||||
|
|
|
@ -44,7 +44,7 @@ class Revocation : public Credential
|
||||||
friend class Credential;
|
friend class Credential;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
|
static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_REVOCATION; }
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Revocation() :
|
ZT_ALWAYS_INLINE Revocation() :
|
||||||
_id(0),
|
_id(0),
|
||||||
|
@ -54,7 +54,7 @@ public:
|
||||||
_flags(0),
|
_flags(0),
|
||||||
_target(),
|
_target(),
|
||||||
_signedBy(),
|
_signedBy(),
|
||||||
_type(Credential::CREDENTIAL_TYPE_NULL),
|
_type(ZT_CREDENTIAL_TYPE_NULL),
|
||||||
_signatureLength(0)
|
_signatureLength(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ public:
|
||||||
* @param tgt Target node whose credential(s) are being revoked
|
* @param tgt Target node whose credential(s) are being revoked
|
||||||
* @param ct Credential type being revoked
|
* @param ct Credential type being revoked
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
|
ZT_ALWAYS_INLINE Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const ZT_CredentialType ct) :
|
||||||
_id(i),
|
_id(i),
|
||||||
_credentialId(cid),
|
_credentialId(cid),
|
||||||
_networkId(nwid),
|
_networkId(nwid),
|
||||||
|
@ -87,7 +87,7 @@ public:
|
||||||
ZT_ALWAYS_INLINE int64_t threshold() const { return _threshold; }
|
ZT_ALWAYS_INLINE int64_t threshold() const { return _threshold; }
|
||||||
ZT_ALWAYS_INLINE const Address &target() const { return _target; }
|
ZT_ALWAYS_INLINE const Address &target() const { return _target; }
|
||||||
ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
|
ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
|
||||||
ZT_ALWAYS_INLINE Credential::Type type() const { return _type; }
|
ZT_ALWAYS_INLINE ZT_CredentialType typeBeingRevoked() const { return _type; }
|
||||||
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
|
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
|
||||||
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
|
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
|
||||||
ZT_ALWAYS_INLINE bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
|
ZT_ALWAYS_INLINE bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
|
||||||
|
@ -160,7 +160,7 @@ public:
|
||||||
_flags = b.template at<uint64_t>(p); p += 8;
|
_flags = b.template at<uint64_t>(p); p += 8;
|
||||||
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||||
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||||
_type = (Credential::Type)b[p++];
|
_type = (ZT_CredentialType)b[p++];
|
||||||
|
|
||||||
if (b[p++] == 1) {
|
if (b[p++] == 1) {
|
||||||
_signatureLength = b.template at<uint16_t>(p);
|
_signatureLength = b.template at<uint16_t>(p);
|
||||||
|
@ -186,7 +186,7 @@ private:
|
||||||
uint64_t _flags;
|
uint64_t _flags;
|
||||||
Address _target;
|
Address _target;
|
||||||
Address _signedBy;
|
Address _signedBy;
|
||||||
Credential::Type _type;
|
ZT_CredentialType _type;
|
||||||
unsigned int _signatureLength;
|
unsigned int _signatureLength;
|
||||||
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||||
};
|
};
|
||||||
|
|
|
@ -235,64 +235,6 @@ public:
|
||||||
}
|
}
|
||||||
return curr_cnt ? subtotal / (float)curr_cnt : 0;
|
return curr_cnt ? subtotal / (float)curr_cnt : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The sample standard deviation of element values
|
|
||||||
*/
|
|
||||||
inline float stddev() { return sqrt(variance()); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The variance of element values
|
|
||||||
*/
|
|
||||||
inline float variance()
|
|
||||||
{
|
|
||||||
size_t iterator = begin;
|
|
||||||
float cached_mean = mean();
|
|
||||||
size_t curr_cnt = count();
|
|
||||||
T sum_of_squared_deviations = 0;
|
|
||||||
for (size_t i=0; i<curr_cnt; i++) {
|
|
||||||
iterator = (iterator + S - 1) % curr_cnt;
|
|
||||||
float deviation = (buf[i] - cached_mean);
|
|
||||||
sum_of_squared_deviations += (T)(deviation*deviation);
|
|
||||||
}
|
|
||||||
float variance = (float)sum_of_squared_deviations / (float)(S - 1);
|
|
||||||
return variance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The number of elements of zero value
|
|
||||||
*/
|
|
||||||
inline size_t zeroCount()
|
|
||||||
{
|
|
||||||
size_t iterator = begin;
|
|
||||||
size_t zeros = 0;
|
|
||||||
size_t curr_cnt = count();
|
|
||||||
for (size_t i=0; i<curr_cnt; i++) {
|
|
||||||
iterator = (iterator + S - 1) % curr_cnt;
|
|
||||||
if (*(buf + iterator) == 0) {
|
|
||||||
zeros++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return zeros;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param value Value to match against in buffer
|
|
||||||
* @return The number of values held in the ring buffer which match a given value
|
|
||||||
*/
|
|
||||||
inline size_t countValue(T value)
|
|
||||||
{
|
|
||||||
size_t iterator = begin;
|
|
||||||
size_t cnt = 0;
|
|
||||||
size_t curr_cnt = count();
|
|
||||||
for (size_t i=0; i<curr_cnt; i++) {
|
|
||||||
iterator = (iterator + S - 1) % curr_cnt;
|
|
||||||
if (*(buf + iterator) == value) {
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -218,7 +218,7 @@ void HMACSHA384(const uint8_t key[32],const void *msg,const unsigned int msglen,
|
||||||
uint64_t kInPadded[16]; // input padded key
|
uint64_t kInPadded[16]; // input padded key
|
||||||
uint64_t outer[22]; // output padded key | H(input padded key | msg)
|
uint64_t outer[22]; // output padded key | H(input padded key | msg)
|
||||||
|
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
for(int i=0;i<32;++i) ((uint8_t *)kInPadded)[i] = key[i] ^ 0x36;
|
for(int i=0;i<32;++i) ((uint8_t *)kInPadded)[i] = key[i] ^ 0x36;
|
||||||
for(int i=4;i<16;++i) kInPadded[i] = 0x3636363636363636ULL;
|
for(int i=4;i<16;++i) kInPadded[i] = 0x3636363636363636ULL;
|
||||||
for(int i=0;i<32;++i) ((uint8_t *)outer)[i] = key[i] ^ 0x5c;
|
for(int i=0;i<32;++i) ((uint8_t *)outer)[i] = key[i] ^ 0x5c;
|
||||||
|
|
|
@ -32,12 +32,6 @@
|
||||||
|
|
||||||
#define ZT_HMACSHA384_LEN 48
|
#define ZT_HMACSHA384_LEN 48
|
||||||
|
|
||||||
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_HMAC_SHA_384 'H'
|
|
||||||
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K1 '1'
|
|
||||||
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K2 '2'
|
|
||||||
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K3 '3'
|
|
||||||
#define ZT_PROTO_KBKDF_LABEL_KEY_USE_AES_GMAC_SIV_K4 '4'
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
@ -108,7 +102,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u
|
||||||
* @param msglen Length of message
|
* @param msglen Length of message
|
||||||
* @param mac Buffer to fill with result
|
* @param mac Buffer to fill with result
|
||||||
*/
|
*/
|
||||||
void HMACSHA384(const uint8_t key[32],const void *msg,const unsigned int msglen,uint8_t mac[48]);
|
void HMACSHA384(const uint8_t key[32],const void *msg,unsigned int msglen,uint8_t mac[48]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF
|
* Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF
|
||||||
|
@ -119,7 +113,7 @@ void HMACSHA384(const uint8_t key[32],const void *msg,const unsigned int msglen,
|
||||||
* @param iter Key iteration for generation of multiple keys for the same label/context
|
* @param iter Key iteration for generation of multiple keys for the same label/context
|
||||||
* @param out Output to receive derived key
|
* @param out Output to receive derived key
|
||||||
*/
|
*/
|
||||||
void KBKDFHMACSHA384(const uint8_t key[32],const char label,const char context,const uint32_t iter,uint8_t out[32]);
|
void KBKDFHMACSHA384(const uint8_t key[32],char label,char context,uint32_t iter,uint8_t out[32]);
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
// Slower version that does not use type punning
|
// Slower version that does not use type punning
|
||||||
#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) )
|
#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) )
|
||||||
static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); }
|
static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); }
|
||||||
|
@ -27,7 +27,7 @@ static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (ui
|
||||||
// Fast version that just does 32-bit load/store
|
// Fast version that just does 32-bit load/store
|
||||||
#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p))))
|
#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p))))
|
||||||
#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v)
|
#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v)
|
||||||
#endif // ZT_NO_TYPE_PUNNING
|
#endif // ZT_NO_UNALIGNED_ACCESS
|
||||||
|
|
||||||
#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?)
|
#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?)
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "Trace.hpp"
|
#include "Trace.hpp"
|
||||||
|
|
||||||
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
|
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
|
||||||
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000
|
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 300000
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -53,11 +53,7 @@ SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SelfAwareness::~SelfAwareness()
|
void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now)
|
|
||||||
{
|
{
|
||||||
const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
|
const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
|
||||||
|
|
||||||
|
@ -65,12 +61,10 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Mutex::Lock l(_phy_l);
|
Mutex::Lock l(_phy_l);
|
||||||
PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)];
|
PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter.address(),receivedOnLocalSocket,reporterPhysicalAddress,scope)];
|
||||||
|
|
||||||
if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
|
if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
|
||||||
// Changes to external surface reported by trusted peers causes path reset in this scope
|
// Changes to external surface reported by trusted peers causes path reset in this scope
|
||||||
RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope);
|
|
||||||
|
|
||||||
entry.mySurface = myPhysicalAddress;
|
entry.mySurface = myPhysicalAddress;
|
||||||
entry.ts = now;
|
entry.ts = now;
|
||||||
entry.trusted = trusted;
|
entry.trusted = trusted;
|
||||||
|
@ -80,10 +74,10 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
|
||||||
// Don't use 'entry' after this since hash table gets modified.
|
// Don't use 'entry' after this since hash table gets modified.
|
||||||
{
|
{
|
||||||
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
|
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
|
||||||
PhySurfaceKey *k = (PhySurfaceKey *)0;
|
PhySurfaceKey *k = nullptr;
|
||||||
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
|
PhySurfaceEntry *e = nullptr;
|
||||||
while (i.next(k,e)) {
|
while (i.next(k,e)) {
|
||||||
if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope))
|
if ((k->scope == scope)&&(k->reporterPhysicalAddress != reporterPhysicalAddress))
|
||||||
_phy.erase(*k);
|
_phy.erase(*k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +85,8 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
|
||||||
// Reset all paths within this scope and address family
|
// Reset all paths within this scope and address family
|
||||||
_ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope);
|
_ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope);
|
||||||
RR->topology->eachPeer<_ResetWithinScope &>(rset);
|
RR->topology->eachPeer<_ResetWithinScope &>(rset);
|
||||||
|
|
||||||
|
RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,entry.mySurface,myPhysicalAddress,scope);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise just update DB to use to determine external surface info
|
// Otherwise just update DB to use to determine external surface info
|
||||||
entry.mySurface = myPhysicalAddress;
|
entry.mySurface = myPhysicalAddress;
|
||||||
|
@ -111,35 +107,6 @@ void SelfAwareness::clean(int64_t now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelfAwareness::symmetricNat(const int64_t now) const
|
|
||||||
{
|
|
||||||
Hashtable< InetAddress,std::pair< std::set<int>,std::set<int64_t> > > ipToPortsAndLocalSockets(16);
|
|
||||||
|
|
||||||
{
|
|
||||||
Mutex::Lock l(_phy_l);
|
|
||||||
Hashtable<PhySurfaceKey,PhySurfaceEntry>::Iterator i(const_cast<SelfAwareness *>(this)->_phy);
|
|
||||||
PhySurfaceKey *k = nullptr;
|
|
||||||
PhySurfaceEntry *e = nullptr;
|
|
||||||
while (i.next(k,e)) {
|
|
||||||
if ((now - e->ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) {
|
|
||||||
std::pair< std::set<int>,std::set<int64_t> > &ii = ipToPortsAndLocalSockets[e->mySurface.ipOnly()];
|
|
||||||
ii.first.insert(e->mySurface.port());
|
|
||||||
if (k->receivedOnLocalSocket != -1)
|
|
||||||
ii.second.insert(k->receivedOnLocalSocket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Hashtable< InetAddress,std::pair< std::set<int>,std::set<int64_t> > >::Iterator i(ipToPortsAndLocalSockets);
|
|
||||||
InetAddress *k = nullptr;
|
|
||||||
std::pair< std::set<int>,std::set<int64_t> > *v = nullptr;
|
|
||||||
while (i.next(k,v)) {
|
|
||||||
if (v->first.size() > v->second.size()) // more external ports than local sockets for a given external IP
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::multimap<unsigned long,InetAddress> SelfAwareness::externalAddresses(const int64_t now) const
|
std::multimap<unsigned long,InetAddress> SelfAwareness::externalAddresses(const int64_t now) const
|
||||||
{
|
{
|
||||||
std::multimap<unsigned long,InetAddress> r;
|
std::multimap<unsigned long,InetAddress> r;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
class Identity;
|
||||||
class RuntimeEnvironment;
|
class RuntimeEnvironment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,19 +36,18 @@ class SelfAwareness
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SelfAwareness(const RuntimeEnvironment *renv);
|
explicit SelfAwareness(const RuntimeEnvironment *renv);
|
||||||
~SelfAwareness();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a remote peer informs us of our external network address
|
* Called when a remote peer informs us of our external network address
|
||||||
*
|
*
|
||||||
* @param reporter ZeroTier address of reporting peer
|
* @param reporter Identity of reporting peer
|
||||||
* @param receivedOnLocalAddress Local address on which report was received
|
* @param receivedOnLocalAddress Local address on which report was received
|
||||||
* @param reporterPhysicalAddress Physical address that reporting peer seems to have
|
* @param reporterPhysicalAddress Physical address that reporting peer seems to have
|
||||||
* @param myPhysicalAddress Physical address that peer says we have
|
* @param myPhysicalAddress Physical address that peer says we have
|
||||||
* @param trusted True if this peer is trusted as an authority to inform us of external address changes
|
* @param trusted True if this peer is trusted as an authority to inform us of external address changes
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
*/
|
*/
|
||||||
void iam(void *tPtr,const Address &reporter,int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now);
|
void iam(void *tPtr,const Identity &reporter,int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up database periodically
|
* Clean up database periodically
|
||||||
|
@ -56,14 +56,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void clean(int64_t now);
|
void clean(int64_t now);
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether this node appears to be behind a symmetric NAT
|
|
||||||
*
|
|
||||||
* @param now Current time
|
|
||||||
* @return True if it looks like we're behind a symmetric NAT
|
|
||||||
*/
|
|
||||||
bool symmetricNat(int64_t now) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get external address consensus, which is the statistical "mode" of external addresses.
|
* Get external address consensus, which is the statistical "mode" of external addresses.
|
||||||
*
|
*
|
||||||
|
|
|
@ -211,7 +211,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
|
||||||
bool fromBridged;
|
bool fromBridged;
|
||||||
if ((fromBridged = (from != network->mac()))) {
|
if ((fromBridged = (from != network->mac()))) {
|
||||||
if (!network->config().permitsBridging(RR->identity.address())) {
|
if (!network->config().permitsBridging(RR->identity.address())) {
|
||||||
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"not a bridge");
|
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_BRIDGING_NOT_ALLOWED_LOCAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
|
||||||
multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0));
|
multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0));
|
||||||
} else if (!network->config().enableBroadcast()) {
|
} else if (!network->config().enableBroadcast()) {
|
||||||
// Don't transmit broadcasts if this network doesn't want them
|
// Don't transmit broadcasts if this network doesn't want them
|
||||||
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"broadcast disabled");
|
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_BROADCAST_DISABLED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) {
|
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) {
|
||||||
|
@ -323,7 +323,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
|
||||||
|
|
||||||
// Check this after NDP emulation, since that has to be allowed in exactly this case
|
// Check this after NDP emulation, since that has to be allowed in exactly this case
|
||||||
if (network->config().multicastLimit == 0) {
|
if (network->config().multicastLimit == 0) {
|
||||||
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"multicast disabled");
|
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_MULTICAST_DISABLED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
|
||||||
|
|
||||||
// First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates.
|
// First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates.
|
||||||
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
||||||
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked");
|
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
|
||||||
SharedPtr<Peer> toPeer(RR->topology->get(tPtr,toZT));
|
SharedPtr<Peer> toPeer(RR->topology->get(tPtr,toZT));
|
||||||
|
|
||||||
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
||||||
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked");
|
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
|
||||||
// for each ZT destination are also done below. This is the same rationale
|
// for each ZT destination are also done below. This is the same rationale
|
||||||
// and design as for multicast.
|
// and design as for multicast.
|
||||||
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
|
||||||
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked");
|
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
|
||||||
outp.append((uint16_t)etherType);
|
outp.append((uint16_t)etherType);
|
||||||
outp.append(data,len);
|
outp.append(data,len);
|
||||||
} else {
|
} else {
|
||||||
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)");
|
RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,ZT_TRACE_FRAME_DROP_REASON_FILTER_BLOCKED_AT_BRIDGE_REPLICATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Tag : public Credential
|
||||||
friend class Credential;
|
friend class Credential;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
|
static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_TAG; }
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Tag() :
|
ZT_ALWAYS_INLINE Tag() :
|
||||||
_id(0),
|
_id(0),
|
||||||
|
|
282
node/Trace.cpp
Normal file
282
node/Trace.cpp
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2024-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#include "Trace.hpp"
|
||||||
|
#include "RuntimeEnvironment.hpp"
|
||||||
|
#include "Node.hpp"
|
||||||
|
#include "Peer.hpp"
|
||||||
|
|
||||||
|
// Macro to avoid calling hton() on values known at compile time.
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
#define CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
|
||||||
|
#else
|
||||||
|
#define CONST_TO_BE_UINT16(x) ((uint16_t)(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
Trace::Trace(const RuntimeEnvironment *renv) :
|
||||||
|
RR(renv),
|
||||||
|
_vl1(false),
|
||||||
|
_vl2(false),
|
||||||
|
_vl2Filter(false),
|
||||||
|
_vl2Multicast(false),
|
||||||
|
_eventBufSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_resettingPathsInScope(
|
||||||
|
void *const tPtr,
|
||||||
|
const Identity &reporter,
|
||||||
|
const InetAddress &from,
|
||||||
|
const InetAddress &oldExternal,
|
||||||
|
const InetAddress &newExternal,
|
||||||
|
const InetAddress::IpScope scope)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL1_RESETTING_PATHS_IN_SCOPE ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE);
|
||||||
|
from.forTrace(ev.from);
|
||||||
|
oldExternal.forTrace(ev.oldExternal);
|
||||||
|
newExternal.forTrace(ev.newExternal);
|
||||||
|
ev.scope = (uint8_t)scope;
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_tryingNewPath(
|
||||||
|
void *const tPtr,
|
||||||
|
const Identity &trying,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
const InetAddress &triggerAddress,
|
||||||
|
uint64_t triggeringPacketId,
|
||||||
|
uint8_t triggeringPacketVerb,
|
||||||
|
uint64_t triggeredByAddress,
|
||||||
|
const uint8_t *triggeredByIdentityHash,
|
||||||
|
ZT_TraceTryingNewPathReason reason)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL1_TRYING_NEW_PATH ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH);
|
||||||
|
ev.address = Utils::hton(trying.address().toInt());
|
||||||
|
memcpy(ev.identityHash,trying.hash(),48);
|
||||||
|
physicalAddress.forTrace(ev.physicalAddress);
|
||||||
|
triggerAddress.forTrace(ev.triggerAddress);
|
||||||
|
ev.triggeringPacketId = Utils::hton(triggeringPacketId);
|
||||||
|
ev.triggeringPacketVerb = triggeringPacketVerb;
|
||||||
|
ev.triggeredByAddress = Utils::hton(triggeredByAddress);
|
||||||
|
if (triggeredByIdentityHash)
|
||||||
|
memcpy(ev.triggeredByIdentityHash,triggeredByIdentityHash,48);
|
||||||
|
else memset(ev.triggeredByIdentityHash,0,48);
|
||||||
|
ev.reason = (uint8_t)reason;
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_learnedNewPath(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t packetId,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
const InetAddress &replaced)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL1_LEARNED_NEW_PATH ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_LEARNED_NEW_PATH);
|
||||||
|
ev.packetId = Utils::hton(packetId);
|
||||||
|
ev.address = Utils::hton(peerIdentity.address().toInt());
|
||||||
|
memcpy(ev.identityHash,peerIdentity.hash(),48);
|
||||||
|
physicalAddress.forTrace(ev.physicalAddress);
|
||||||
|
replaced.forTrace(ev.replaced);
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_incomingPacketDropped(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t packetId,
|
||||||
|
uint64_t networkId,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
uint8_t hops,
|
||||||
|
uint8_t verb,
|
||||||
|
ZT_TracePacketDropReason reason)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL1_INCOMING_PACKET_DROPPED ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL1_INCOMING_PACKET_DROPPED);
|
||||||
|
ev.packetId = Utils::hton(packetId);
|
||||||
|
ev.networkId = Utils::hton(networkId);
|
||||||
|
ev.address = Utils::hton(peerIdentity.address().toInt());
|
||||||
|
memcpy(ev.identityHash,peerIdentity.hash(),48);
|
||||||
|
physicalAddress.forTrace(ev.physicalAddress);
|
||||||
|
ev.hops = hops;
|
||||||
|
ev.verb = verb;
|
||||||
|
ev.reason = (uint8_t)reason;
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_outgoingNetworkFrameDropped(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
uint16_t etherType,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
ZT_TraceFrameDropReason reason)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL2_OUTGOING_FRAME_DROPPED ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_OUTGOING_FRAME_DROPPED);
|
||||||
|
ev.networkId = Utils::hton(networkId);
|
||||||
|
ev.sourceMac = Utils::hton(sourceMac.toInt());
|
||||||
|
ev.destMac = Utils::hton(destMac.toInt());
|
||||||
|
ev.etherType = Utils::hton(etherType);
|
||||||
|
ev.frameLength = Utils::hton(frameLength);
|
||||||
|
if (frameData) {
|
||||||
|
unsigned int l = frameLength;
|
||||||
|
if (l > sizeof(ev.frameHead))
|
||||||
|
l = sizeof(ev.frameHead);
|
||||||
|
memcpy(ev.frameHead,frameData,l);
|
||||||
|
memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
|
||||||
|
}
|
||||||
|
ev.reason = (uint8_t)reason;
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_incomingNetworkFrameDropped(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
uint8_t hops,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
uint8_t verb,
|
||||||
|
bool credentialRequestSent,
|
||||||
|
ZT_TraceFrameDropReason reason)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL2_INCOMING_FRAME_DROPPED ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_INCOMING_FRAME_DROPPED);
|
||||||
|
ev.networkId = Utils::hton(networkId);
|
||||||
|
ev.sourceMac = Utils::hton(sourceMac.toInt());
|
||||||
|
ev.destMac = Utils::hton(destMac.toInt());
|
||||||
|
ev.address = Utils::hton(peerIdentity.address().toInt());
|
||||||
|
physicalAddress.forTrace(ev.physicalAddress);
|
||||||
|
ev.hops = hops;
|
||||||
|
ev.frameLength = Utils::hton(frameLength);
|
||||||
|
if (frameData) {
|
||||||
|
unsigned int l = frameLength;
|
||||||
|
if (l > sizeof(ev.frameHead))
|
||||||
|
l = sizeof(ev.frameHead);
|
||||||
|
memcpy(ev.frameHead,frameData,l);
|
||||||
|
memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
|
||||||
|
}
|
||||||
|
ev.verb = verb;
|
||||||
|
ev.credentialRequestSent = (uint8_t)credentialRequestSent;
|
||||||
|
ev.reason = (uint8_t)reason;
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_networkConfigRequestSent(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL2_NETWORK_CONFIG_REQUESTED ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED);
|
||||||
|
ev.networkId = Utils::hton(networkId);
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_networkFilter(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const uint8_t primaryRuleSetLog[512],
|
||||||
|
const uint8_t matchingCapabilityRuleSetLog[512],
|
||||||
|
uint32_t matchingCapabilityId,
|
||||||
|
int64_t matchingCapabilityTimestamp,
|
||||||
|
const Address &source,
|
||||||
|
const Address &dest,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
uint16_t etherType,
|
||||||
|
uint16_t vlanId,
|
||||||
|
bool noTee,
|
||||||
|
bool inbound,
|
||||||
|
int accept)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL2_NETWORK_FILTER ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER);
|
||||||
|
ev.networkId = Utils::hton(networkId);
|
||||||
|
memcpy(ev.primaryRuleSetLog,primaryRuleSetLog,sizeof(ev.primaryRuleSetLog));
|
||||||
|
if (matchingCapabilityRuleSetLog)
|
||||||
|
memcpy(ev.matchingCapabilityRuleSetLog,matchingCapabilityRuleSetLog,sizeof(ev.matchingCapabilityRuleSetLog));
|
||||||
|
else memset(ev.matchingCapabilityRuleSetLog,0,sizeof(ev.matchingCapabilityRuleSetLog));
|
||||||
|
ev.matchingCapabilityId = Utils::hton(matchingCapabilityId);
|
||||||
|
ev.matchingCapabilityTimestamp = Utils::hton(matchingCapabilityTimestamp);
|
||||||
|
ev.source = Utils::hton(source.toInt());
|
||||||
|
ev.dest = Utils::hton(dest.toInt());
|
||||||
|
ev.sourceMac = Utils::hton(sourceMac.toInt());
|
||||||
|
ev.destMac = Utils::hton(destMac.toInt());
|
||||||
|
ev.frameLength = Utils::hton(frameLength);
|
||||||
|
if (frameData) {
|
||||||
|
unsigned int l = frameLength;
|
||||||
|
if (l > sizeof(ev.frameHead))
|
||||||
|
l = sizeof(ev.frameHead);
|
||||||
|
memcpy(ev.frameHead,frameData,l);
|
||||||
|
memset(ev.frameHead + l,0,sizeof(ev.frameHead) - l);
|
||||||
|
}
|
||||||
|
ev.etherType = Utils::hton(etherType);
|
||||||
|
ev.vlanId = Utils::hton(vlanId);
|
||||||
|
ev.noTee = (uint8_t)noTee;
|
||||||
|
ev.inbound = (uint8_t)inbound;
|
||||||
|
ev.accept = (int8_t)accept;
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::_credentialRejected(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const Address &address,
|
||||||
|
uint32_t credentialId,
|
||||||
|
int64_t credentialTimestamp,
|
||||||
|
uint8_t credentialType,
|
||||||
|
ZT_TraceCredentialRejectionReason reason)
|
||||||
|
{
|
||||||
|
ZT_TraceEvent_VL2_CREDENTIAL_REJECTED ev;
|
||||||
|
ev.evSize = CONST_TO_BE_UINT16(sizeof(ev));
|
||||||
|
ev.evType = CONST_TO_BE_UINT16(ZT_TRACE_VL2_NETWORK_FILTER);
|
||||||
|
ev.networkId = Utils::hton(networkId);
|
||||||
|
ev.address = Utils::hton(address.toInt());
|
||||||
|
ev.credentialId = Utils::hton(credentialId);
|
||||||
|
ev.credentialTimestamp = Utils::hton(credentialTimestamp);
|
||||||
|
ev.credentialType = credentialType;
|
||||||
|
ev.reason = (uint8_t)reason;
|
||||||
|
|
||||||
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
337
node/Trace.hpp
337
node/Trace.hpp
|
@ -14,29 +14,26 @@
|
||||||
#ifndef ZT_TRACE_HPP
|
#ifndef ZT_TRACE_HPP
|
||||||
#define ZT_TRACE_HPP
|
#define ZT_TRACE_HPP
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
#include "SharedPtr.hpp"
|
#include "SharedPtr.hpp"
|
||||||
#include "Packet.hpp"
|
|
||||||
#include "Credential.hpp"
|
|
||||||
#include "InetAddress.hpp"
|
|
||||||
#include "Dictionary.hpp"
|
|
||||||
#include "Mutex.hpp"
|
#include "Mutex.hpp"
|
||||||
#include "Hashtable.hpp"
|
#include "Packet.hpp"
|
||||||
|
#include "InetAddress.hpp"
|
||||||
|
#include "Address.hpp"
|
||||||
|
#include "MAC.hpp"
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
class RuntimeEnvironment;
|
class RuntimeEnvironment;
|
||||||
class Address;
|
|
||||||
class Identity;
|
class Identity;
|
||||||
class Peer;
|
class Peer;
|
||||||
class Path;
|
class Path;
|
||||||
class Network;
|
class Network;
|
||||||
class MAC;
|
|
||||||
class CertificateOfMembership;
|
class CertificateOfMembership;
|
||||||
class CertificateOfOwnership;
|
class CertificateOfOwnership;
|
||||||
class Revocation;
|
class Revocation;
|
||||||
|
@ -50,117 +47,265 @@ struct NetworkConfig;
|
||||||
class Trace
|
class Trace
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class RuleResultLog
|
struct RuleResultLog
|
||||||
{
|
{
|
||||||
public:
|
uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields
|
||||||
ZT_ALWAYS_INLINE RuleResultLog() { this->clear(); }
|
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches) { _l[rn >> 1U] |= ( ((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U) ) << ((rn & 1U) << 2U); }
|
ZT_ALWAYS_INLINE void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches)
|
||||||
ZT_ALWAYS_INLINE void logSkipped(const unsigned int rn,const uint8_t thisSetMatches) { _l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U); }
|
{
|
||||||
ZT_ALWAYS_INLINE void clear() { memset(_l,0,sizeof(_l)); }
|
l[rn >> 1U] |= ( ((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U) ) << ((rn & 1U) << 2U);
|
||||||
|
}
|
||||||
ZT_ALWAYS_INLINE const uint8_t *data() const { return _l; }
|
ZT_ALWAYS_INLINE void logSkipped(const unsigned int rn,const uint8_t thisSetMatches)
|
||||||
ZT_ALWAYS_INLINE unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); }
|
{
|
||||||
|
l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U);
|
||||||
private:
|
}
|
||||||
uint8_t _l[ZT_MAX_NETWORK_RULES / 2];
|
ZT_ALWAYS_INLINE void clear()
|
||||||
|
{
|
||||||
|
memset(l,0,sizeof(l));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Trace(const RuntimeEnvironment *renv)
|
explicit Trace(const RuntimeEnvironment *renv);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope)
|
ZT_ALWAYS_INLINE void resettingPathsInScope(
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void peerLinkNowRedundant(void *const tPtr,Peer &peer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void peerLinkNoLongerRedundant(void *const tPtr,Peer &peer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void peerLinkAggregateStatistics(void *const tPtr,Peer &peer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath,const uint64_t packetId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &path,const uint64_t packetId,const Address &source,const char *reason)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void networkFilter(
|
|
||||||
void *const tPtr,
|
void *const tPtr,
|
||||||
const Network &network,
|
const Identity &reporter,
|
||||||
const RuleResultLog &primaryRuleSetLog,
|
const InetAddress &from,
|
||||||
const RuleResultLog *const matchingCapabilityRuleSetLog,
|
const InetAddress &oldExternal,
|
||||||
const Capability *const matchingCapability,
|
const InetAddress &newExternal,
|
||||||
const Address &ztSource,
|
const InetAddress::IpScope scope)
|
||||||
const Address &ztDest,
|
|
||||||
const MAC &macSource,
|
|
||||||
const MAC &macDest,
|
|
||||||
const uint8_t *const frameData,
|
|
||||||
const unsigned int frameLen,
|
|
||||||
const unsigned int etherType,
|
|
||||||
const unsigned int vlanId,
|
|
||||||
const bool noTee,
|
|
||||||
const bool inbound,
|
|
||||||
const int accept)
|
|
||||||
{
|
{
|
||||||
|
if (_vl1) _resettingPathsInScope(tPtr,reporter,from,oldExternal,newExternal,scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason)
|
ZT_ALWAYS_INLINE void tryingNewPath(
|
||||||
|
void *const tPtr,
|
||||||
|
const Identity &trying,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
const InetAddress &triggerAddress,
|
||||||
|
uint64_t triggeringPacketId,
|
||||||
|
uint8_t triggeringPacketVerb,
|
||||||
|
uint64_t triggeredByAddress,
|
||||||
|
const uint8_t *triggeredByIdentityHash,
|
||||||
|
ZT_TraceTryingNewPathReason reason)
|
||||||
{
|
{
|
||||||
|
if (_vl1) _tryingNewPath(tPtr,trying,physicalAddress,triggerAddress,triggeringPacketId,triggeringPacketVerb,triggeredByAddress,triggeredByIdentityHash,reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason)
|
ZT_ALWAYS_INLINE void learnedNewPath(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t packetId,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
const InetAddress &replaced)
|
||||||
{
|
{
|
||||||
|
if (_vl1) _learnedNewPath(tPtr,packetId,peerIdentity,physicalAddress,replaced);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void credentialRejected(void *const tPtr,const Capability &c,const char *reason)
|
ZT_ALWAYS_INLINE void incomingPacketDropped(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t packetId,
|
||||||
|
uint64_t networkId,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
uint8_t hops,
|
||||||
|
uint8_t verb,
|
||||||
|
const ZT_TracePacketDropReason reason)
|
||||||
{
|
{
|
||||||
|
if (_vl1) _incomingPacketDropped(tPtr,packetId,networkId,peerIdentity,physicalAddress,hops,verb,reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void credentialRejected(void *const tPtr,const Tag &c,const char *reason)
|
ZT_ALWAYS_INLINE void outgoingNetworkFrameDropped(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
uint16_t etherType,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
ZT_TraceFrameDropReason reason)
|
||||||
{
|
{
|
||||||
|
if (_vl2) _outgoingNetworkFrameDropped(tPtr,networkId,sourceMac,destMac,etherType,frameLength,frameData,reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void credentialRejected(void *const tPtr,const Revocation &c,const char *reason)
|
ZT_ALWAYS_INLINE void incomingNetworkFrameDropped(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
uint8_t hops,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
uint8_t verb,
|
||||||
|
bool credentialRequestSent,
|
||||||
|
ZT_TraceFrameDropReason reason)
|
||||||
{
|
{
|
||||||
|
if (_vl2) _incomingNetworkFrameDropped(tPtr,networkId,sourceMac,destMac,peerIdentity,physicalAddress,hops,frameLength,frameData,verb,credentialRequestSent,reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE void networkConfigRequestSent(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId)
|
||||||
|
{
|
||||||
|
if (_vl2) _networkConfigRequestSent(tPtr,networkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE void networkFilter(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const uint8_t primaryRuleSetLog[512],
|
||||||
|
const uint8_t matchingCapabilityRuleSetLog[512],
|
||||||
|
uint32_t matchingCapabilityId,
|
||||||
|
int64_t matchingCapabilityTimestamp,
|
||||||
|
const Address &source,
|
||||||
|
const Address &dest,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
uint16_t etherType,
|
||||||
|
uint16_t vlanId,
|
||||||
|
bool noTee,
|
||||||
|
bool inbound,
|
||||||
|
int accept)
|
||||||
|
{
|
||||||
|
if (_vl2Filter) {
|
||||||
|
_networkFilter(
|
||||||
|
tPtr,
|
||||||
|
networkId,
|
||||||
|
primaryRuleSetLog,
|
||||||
|
matchingCapabilityRuleSetLog,
|
||||||
|
matchingCapabilityId,
|
||||||
|
matchingCapabilityTimestamp,
|
||||||
|
source,
|
||||||
|
dest,
|
||||||
|
sourceMac,
|
||||||
|
destMac,
|
||||||
|
frameLength,
|
||||||
|
frameData,
|
||||||
|
etherType,
|
||||||
|
vlanId,
|
||||||
|
noTee,
|
||||||
|
inbound,
|
||||||
|
accept);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE void credentialRejected(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const Address &address,
|
||||||
|
uint32_t credentialId,
|
||||||
|
int64_t credentialTimestamp,
|
||||||
|
uint8_t credentialType,
|
||||||
|
ZT_TraceCredentialRejectionReason reason)
|
||||||
|
{
|
||||||
|
if (_vl2) _credentialRejected(tPtr,networkId,address,credentialId,credentialTimestamp,credentialType,reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _resettingPathsInScope(
|
||||||
|
void *tPtr,
|
||||||
|
const Identity &reporter,
|
||||||
|
const InetAddress &from,
|
||||||
|
const InetAddress &oldExternal,
|
||||||
|
const InetAddress &newExternal,
|
||||||
|
InetAddress::IpScope scope);
|
||||||
|
void _tryingNewPath(
|
||||||
|
void *tPtr,
|
||||||
|
const Identity &trying,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
const InetAddress &triggerAddress,
|
||||||
|
uint64_t triggeringPacketId,
|
||||||
|
uint8_t triggeringPacketVerb,
|
||||||
|
uint64_t triggeredByAddress,
|
||||||
|
const uint8_t *triggeredByIdentityHash,
|
||||||
|
ZT_TraceTryingNewPathReason reason);
|
||||||
|
void _learnedNewPath(
|
||||||
|
void *tPtr,
|
||||||
|
uint64_t packetId,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
const InetAddress &replaced);
|
||||||
|
void _incomingPacketDropped(
|
||||||
|
void *tPtr,
|
||||||
|
uint64_t packetId,
|
||||||
|
uint64_t networkId,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
uint8_t hops,
|
||||||
|
uint8_t verb,
|
||||||
|
ZT_TracePacketDropReason reason);
|
||||||
|
void _outgoingNetworkFrameDropped(
|
||||||
|
void *tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
uint16_t etherType,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
ZT_TraceFrameDropReason reason);
|
||||||
|
void _incomingNetworkFrameDropped(
|
||||||
|
void *const tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
const Identity &peerIdentity,
|
||||||
|
const InetAddress &physicalAddress,
|
||||||
|
uint8_t hops,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
uint8_t verb,
|
||||||
|
bool credentialRequestSent,
|
||||||
|
ZT_TraceFrameDropReason reason);
|
||||||
|
void _networkConfigRequestSent(
|
||||||
|
void *tPtr,
|
||||||
|
uint64_t networkId);
|
||||||
|
void _networkFilter(
|
||||||
|
void *tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const uint8_t primaryRuleSetLog[512],
|
||||||
|
const uint8_t matchingCapabilityRuleSetLog[512],
|
||||||
|
uint32_t matchingCapabilityId,
|
||||||
|
int64_t matchingCapabilityTimestamp,
|
||||||
|
const Address &source,
|
||||||
|
const Address &dest,
|
||||||
|
const MAC &sourceMac,
|
||||||
|
const MAC &destMac,
|
||||||
|
uint16_t frameLength,
|
||||||
|
const uint8_t *frameData,
|
||||||
|
uint16_t etherType,
|
||||||
|
uint16_t vlanId,
|
||||||
|
bool noTee,
|
||||||
|
bool inbound,
|
||||||
|
int accept);
|
||||||
|
void _credentialRejected(
|
||||||
|
void *tPtr,
|
||||||
|
uint64_t networkId,
|
||||||
|
const Address &address,
|
||||||
|
uint32_t credentialId,
|
||||||
|
int64_t credentialTimestamp,
|
||||||
|
uint8_t credentialType,
|
||||||
|
ZT_TraceCredentialRejectionReason reason);
|
||||||
|
|
||||||
|
const RuntimeEnvironment *const RR;
|
||||||
|
volatile bool _vl1,_vl2,_vl2Filter,_vl2Multicast;
|
||||||
|
|
||||||
|
struct _MonitoringPeer
|
||||||
|
{
|
||||||
|
int64_t _timeSet;
|
||||||
|
unsigned int _traceTypes;
|
||||||
|
SharedPtr<Peer> peer;
|
||||||
|
Mutex lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t _eventBuf[8192]; // must be less than ZT_PROTO_MAX_PACKET_LENGTH
|
||||||
|
unsigned int _eventBufSize;
|
||||||
|
|
||||||
|
std::vector<_MonitoringPeer> _monitoringPeers;
|
||||||
|
RWMutex _monitoringPeers_l;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -331,7 +331,7 @@ uint64_t random()
|
||||||
|
|
||||||
l.lock();
|
l.lock();
|
||||||
const uint64_t result = ROL64(s1 * 5,7) * 9;
|
const uint64_t result = ROL64(s1 * 5,7) * 9;
|
||||||
const uint64_t t = s1 << 17;
|
const uint64_t t = s1 << 17U;
|
||||||
s2 ^= s0;
|
s2 ^= s0;
|
||||||
s3 ^= s1;
|
s3 ^= s1;
|
||||||
s1 ^= s2;
|
s1 ^= s2;
|
||||||
|
|
|
@ -395,7 +395,7 @@ static ZT_ALWAYS_INLINE T ntoh(T n) { return n; }
|
||||||
template<typename I>
|
template<typename I>
|
||||||
static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p)
|
static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p)
|
||||||
{
|
{
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
I x = (I)0;
|
I x = (I)0;
|
||||||
for(unsigned int k=0;k<sizeof(I);++k) {
|
for(unsigned int k=0;k<sizeof(I);++k) {
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
@ -413,7 +413,7 @@ static ZT_ALWAYS_INLINE I loadBigEndian(const void *const p)
|
||||||
template<typename I>
|
template<typename I>
|
||||||
static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i)
|
static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i)
|
||||||
{
|
{
|
||||||
#ifdef ZT_NO_TYPE_PUNNING
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
for(unsigned int k=0;k<sizeof(I);++k) {
|
for(unsigned int k=0;k<sizeof(I);++k) {
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[(sizeof(I)-1)-k];
|
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[(sizeof(I)-1)-k];
|
||||||
|
@ -422,7 +422,7 @@ static ZT_ALWAYS_INLINE void storeBigEndian(void *const p,const I i)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
*reinterpret_cast<I *>(p) = Utils::hton(i);
|
*reinterpret_cast<I *>(p) = hton(i);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GCC__
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)
|
unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)
|
||||||
|
|
|
@ -203,7 +203,7 @@ public:
|
||||||
* @param quot Zero or more quote characters
|
* @param quot Zero or more quote characters
|
||||||
* @return Vector of tokens
|
* @return Vector of tokens
|
||||||
*/
|
*/
|
||||||
static std::vector<std::string> split(const char *s,const char *const sep,const char *esc,const char *quot);
|
static std::vector<std::string> split(const char *s,const char *sep,const char *esc,const char *quot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a block of data to disk, replacing any current file contents
|
* Write a block of data to disk, replacing any current file contents
|
||||||
|
@ -222,9 +222,9 @@ public:
|
||||||
#ifndef OMIT_JSON_SUPPORT
|
#ifndef OMIT_JSON_SUPPORT
|
||||||
static nlohmann::json jsonParse(const std::string &buf);
|
static nlohmann::json jsonParse(const std::string &buf);
|
||||||
static std::string jsonDump(const nlohmann::json &j,int indentation = 1);
|
static std::string jsonDump(const nlohmann::json &j,int indentation = 1);
|
||||||
static uint64_t jsonInt(const nlohmann::json &jv,const uint64_t dfl);
|
static uint64_t jsonInt(const nlohmann::json &jv,uint64_t dfl);
|
||||||
static uint64_t jsonIntHex(const nlohmann::json &jv,const uint64_t dfl);
|
static uint64_t jsonIntHex(const nlohmann::json &jv,uint64_t dfl);
|
||||||
static bool jsonBool(const nlohmann::json &jv,const bool dfl);
|
static bool jsonBool(const nlohmann::json &jv,bool dfl);
|
||||||
static std::string jsonString(const nlohmann::json &jv,const char *dfl);
|
static std::string jsonString(const nlohmann::json &jv,const char *dfl);
|
||||||
#endif // OMIT_JSON_SUPPORT
|
#endif // OMIT_JSON_SUPPORT
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue