Simplification of addRoot/removeRoot, and some code reformatting and other cleanup across multiple files.

This commit is contained in:
Adam Ierymenko 2020-05-29 06:30:02 -07:00
parent caad356b93
commit b9bf6d1242
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
40 changed files with 1680 additions and 1270 deletions

View file

@ -1,145 +0,0 @@
package attic
import (
"encoding/binary"
"errors"
)
// Endpoint types are the same as the enum values in Endpoint.hpp in the core.
const (
EndpointTypeNil = 0
EndpointTypeInetAddr = 1
EndpointTypeDnsName = 2
EndpointTypeZeroTier = 3
EndpointTypeUrl = 4
EndpointTypeEthernet = 5
EndpointTypeUnrecognized = 255
)
// Endpoint wraps a variety of different ways of describing a node's physical network location.
type Endpoint struct {
// Type is this endpoint's type
Type int
// Location is the X, Y, Z coordinate of this endpoint or 0,0,0 if unspecified.
Location [3]int
value, value2 interface{}
}
var (
ErrInvalidEndpoint = errors.New("invalid marshaled endpoint object")
)
func (ep *Endpoint) unmarshalZT(b []byte) (int, error) {
if len(b) < 7 {
return 0, ErrInvalidEndpoint
}
ep.Type = int(b[0])
ep.Location[0] = int(binary.BigEndian.Uint16(b[1:3]))
ep.Location[1] = int(binary.BigEndian.Uint16(b[3:5]))
ep.Location[2] = int(binary.BigEndian.Uint16(b[5:7]))
ep.value = nil
ep.value2 = nil
switch ep.Type {
case EndpointTypeNil:
return 7, nil
case EndpointTypeInetAddr:
ina := new(InetAddress)
inlen, err := ina.unmarshalZT(b[7:])
if err != nil {
return 0, err
}
ep.value = ina
return 7 + inlen, nil
case EndpointTypeDnsName:
stringEnd := 0
for i := 7; i < len(b); i++ {
if b[i] == 0 {
stringEnd = i + 1
break
}
}
if stringEnd == 0 || (stringEnd+2) > len(b) {
return 0, ErrInvalidEndpoint
}
ep.value = string(b[7:stringEnd])
port := binary.BigEndian.Uint16(b[stringEnd : stringEnd+2])
ep.value2 = &port
return stringEnd + 2, nil
case EndpointTypeZeroTier:
if len(b) < 60 {
return 0, ErrInvalidEndpoint
}
a, err := NewAddressFromBytes(b[7:12])
if err != nil {
return 0, err
}
ep.value = a
ep.value2 = append(make([]byte, 0, 48), b[12:60]...)
return 60, nil
case EndpointTypeUrl:
stringEnd := 0
for i := 7; i < len(b); i++ {
if b[i] == 0 {
stringEnd = i + 1
break
}
}
if stringEnd == 0 {
return 0, ErrInvalidEndpoint
}
ep.value = string(b[7:stringEnd])
return stringEnd, nil
case EndpointTypeEthernet:
if len(b) < 13 {
return 0, ErrInvalidEndpoint
}
m, err := NewMACFromBytes(b[7:13])
if err != nil {
return 0, err
}
ep.value = m
return 13, nil
default:
if len(b) < 8 {
return 0, ErrInvalidEndpoint
}
ep.Type = EndpointTypeUnrecognized
return 8 + int(b[1]), nil
}
}
// InetAddress gets the address associated with this endpoint or nil if it is not of this type.
func (ep *Endpoint) InetAddress() *InetAddress {
v, _ := ep.value.(*InetAddress)
return v
}
// Address gets the address associated with this endpoint or nil if it is not of this type.
func (ep *Endpoint) Address() *Address {
v, _ := ep.value.(*Address)
return v
}
// DNSName gets the DNS name and port associated with this endpoint or an empty string and -1 if it is not of this type.
func (ep *Endpoint) DNSName() (string, int) {
if ep.Type == EndpointTypeDnsName {
return ep.value.(string), int(*(ep.value2.(*uint16)))
}
return "", -1
}
// InetAddress gets the URL assocaited with this endpoint or an empty string if it is not of this type.
func (ep *Endpoint) URL() string {
if ep.Type == EndpointTypeUrl {
return ep.value.(string)
}
return ""
}
// Ethernet gets the address associated with this endpoint or nil if it is not of this type.
func (ep *Endpoint) Ethernet() *MAC {
v, _ := ep.value.(*MAC)
return v
}

View file

@ -1,56 +0,0 @@
package attic
import (
"encoding/binary"
"errors"
)
// Locator objects are signed collections of physical or virtual endpoints for a node.
type Locator []byte
var (
ErrInvalidLocator = errors.New("invalid marshaled locator object")
)
// Timestamp returns this locator's timestamp in milliseconds since epoch.
func (l Locator) Timestamp() int64 {
if len(l) >= 8 {
return int64(binary.BigEndian.Uint64(l[0:8]))
}
return 0
}
// Nil returns true if this is a nil/empty locator.
func (l Locator) Nil() bool {
return len(l) < 8 || int64(binary.BigEndian.Uint64(l[0:8])) <= 0
}
// Endpoints obtains the endpoints described by this locator.
func (l Locator) Endpoints() (eps []Endpoint, err error) {
if len(l) < 8 {
err = ErrInvalidLocator
return
}
if int64(binary.BigEndian.Uint64(l[0:8])) > 0 {
if len(l) < 10 {
err = ErrInvalidLocator
return
}
endpointCount := int(binary.BigEndian.Uint16(l[8:10]))
eps = make([]Endpoint, endpointCount)
p := 10
for e := 0; e < endpointCount; e++ {
if p >= len(l) {
err = ErrInvalidLocator
return
}
var elen int
elen, err = eps[e].unmarshalZT(l[p:])
if err != nil {
return
}
p += elen
}
}
return
}

View file

@ -1,4 +0,0 @@
package main
func main() {
}

View file

@ -104,7 +104,6 @@ func Identity(args []string) {
case "makeroot":
if len(args) >= 2 {
//id := readIdentity(args[1])
}
}

View file

@ -27,53 +27,32 @@ import (
"zerotier/pkg/zerotier"
)
func readAuthToken(basePath string) string {
data, _ := ioutil.ReadFile(path.Join(basePath, "authtoken.secret"))
if len(data) > 0 {
return string(data)
}
func getAuthTokenPaths(basePath string) (p []string) {
p = append(p,path.Join(basePath,"authtoken.secret"))
userHome, _ := os.UserHomeDir()
if len(userHome) > 0 {
if runtime.GOOS == "darwin" {
data, _ = ioutil.ReadFile(userHome + "/Library/Application Support/ZeroTier/authtoken.secret")
if len(data) > 0 {
return string(data)
}
data, _ = ioutil.ReadFile(userHome + "/Library/Application Support/ZeroTier/One/authtoken.secret")
if len(data) > 0 {
return string(data)
}
}
data, _ = ioutil.ReadFile(path.Join(userHome, ".zerotierauth"))
if len(data) > 0 {
return string(data)
}
data, _ = ioutil.ReadFile(path.Join(userHome, ".zeroTierOneAuthToken"))
if len(data) > 0 {
return string(data)
p = append(p,path.Join(userHome,"Library","Application Support","ZeroTier","authtoken.secret"))
p = append(p,path.Join(userHome,"Library","Application Support","ZeroTier","One","authtoken.secret"))
}
p = append(p,path.Join(userHome,".zerotierauth"))
p = append(p,path.Join(userHome,".zeroTierOneAuthToken"))
}
return ""
return p
}
func authTokenRequired(authToken string) {
if len(authToken) == 0 {
fmt.Println("FATAL: unable to read API authorization token from service path or user home ('sudo' may be needed)")
fmt.Println("FATAL: unable to read API authorization token from command line or any filesystem location.")
os.Exit(1)
}
}
func main() {
// Reduce Go's threads to 1-2 depending on whether this is single core or
// multi-core. Note that I/O threads are in C++ and are separate and Go
// code only does service control and CLI stuff, so this reduces memory
// use and competition with I/O but shouldn't impact throughput. We also
// crank up the GC to reduce memory usage a little bit.
if runtime.NumCPU() >= 2 {
runtime.GOMAXPROCS(2)
} else {
runtime.GOMAXPROCS(1)
}
// Reduce Go's thread and memory footprint. This would slow things down if the Go code
// were doing a lot, but it's not. It just manages the core and is not directly involved
// in pushing a lot of packets around. If that ever changes this should be adjusted.
runtime.GOMAXPROCS(1)
debug.SetGCPercent(20)
globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
@ -103,19 +82,33 @@ func main() {
if len(*pflag) > 0 {
basePath = *pflag
}
authTokenPaths := getAuthTokenPaths(basePath)
var authToken string
if len(*tflag) > 0 {
at, err := ioutil.ReadFile(*tflag)
if err != nil || len(at) == 0 {
fmt.Println("FATAL: unable to read API authorization token from file '" + *tflag + "'")
fmt.Println("FATAL: unable to read local service API authorization token from " + *tflag)
os.Exit(1)
}
authToken = strings.TrimSpace(string(at))
authToken = string(at)
} else if len(*tTflag) > 0 {
authToken = strings.TrimSpace(*tTflag)
authToken = *tTflag
} else {
authToken = readAuthToken(basePath)
for _, p := range authTokenPaths {
tmp, _ := ioutil.ReadFile(p)
if len(tmp) > 0 {
authToken = string(tmp)
break;
}
}
if len(authToken) == 0 {
fmt.Println("FATAL: unable to read local service API authorization token from any of:")
for _, p := range authTokenPaths {
fmt.Println(" " + p)
}
os.Exit(1)
}
}
authToken = strings.TrimSpace(authToken)

View file

@ -0,0 +1,93 @@
package zerotier
// #include "../../native/GoGlue.h"
import "C"
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"unsafe"
)
const (
EndpointTypeNil = C.ZT_ENDPOINT_TYPE_NIL
EndpointTypeZeroTier = C.ZT_ENDPOINT_TYPE_ZEROTIER
EndpointTypeEthernet = C.ZT_ENDPOINT_TYPE_ETHERNET
EndpointTypeWifiDirect = C.ZT_ENDPOINT_TYPE_WIFI_DIRECT
EndpointTypeBluetooth = C.ZT_ENDPOINT_TYPE_BLUETOOTH
EndpointTypeIp = C.ZT_ENDPOINT_TYPE_IP
EndpointTypeIpUdp = C.ZT_ENDPOINT_TYPE_IP_UDP
EndpointTypeIpTcp = C.ZT_ENDPOINT_TYPE_IP_TCP
EndpointTypeIpHttp2 = C.ZT_ENDPOINT_TYPE_IP_HTTP2
)
type Endpoint struct {
cep C.ZT_Endpoint
}
// Type returns this endpoint's type.
func (ep *Endpoint) Type() int {
return ep.cep._type
}
// InetAddress gets this Endpoint as an InetAddress or nil if its type is not addressed by one.
func (ep *Endpoint) InetAddress() *InetAddress {
switch ep.cep._type {
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2:
ua := sockaddrStorageToUDPAddr(&(ep.cep.a.ss))
return &InetAddress{IP: ua.IP, Port: ua.Port}
}
return nil
}
func (ep *Endpoint) String() string {
switch ep.cep._type {
case EndpointTypeZeroTier:
fp := Fingerprint{Address: Address(ep.cep.a.fp.address), Hash: *((*[48]byte)(unsafe.Pointer(&ep.cep.a.fp.hash[0])))}
return fmt.Sprintf("%d/%s", ep.Type(), fp.String())
case EndpointTypeEthernet, EndpointTypeWifiDirect, EndpointTypeBluetooth:
return fmt.Sprintf("%d/%s", ep.Type(), MAC(ep.cep.a.mac).String())
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2:
return fmt.Sprintf("%d/%s", ep.Type(), ep.InetAddress().String())
}
return fmt.Sprintf("%d", ep.Type())
}
func (ep *Endpoint) MarshalJSON() ([]byte, error) {
s := ep.String()
return json.Marshal(&s)
}
func (ep *Endpoint) UnmarshalJSON(j []byte) error {
var s string
err := json.Unmarshal(j, &s)
if err != nil {
return err
}
slashIdx := strings.IndexRune(s, '/')
if slashIdx < 0 {
ep.cep._type = C.uint(strconv.ParseUint(s, 10, 32))
} else if slashIdx == 0 || slashIdx >= (len(s)-1) {
return ErrInvalidParameter
} else {
ep.cep._type = C.uint(strconv.ParseUint(s[0:slashIdx], 10, 32))
s = s[slashIdx+1:]
}
switch ep.cep._type {
case EndpointTypeNil:
return nil
case EndpointTypeZeroTier:
fp, err := NewFingerprintFromString(s)
if err != nil {
return err
}
ep.cep.a.fp.address = C.uint64_t(fp.Address)
copy(((*[48]byte)(unsafe.Pointer(&ep.cep.a.fp.hash[0])))[:], fp.Hash[:])
return nil
}
return ErrInvalidParameter
}

View file

@ -13,41 +13,51 @@
package zerotier
//#cgo CFLAGS: -O3
//#include "../../native/GoGlue.h"
// #include "../../native/GoGlue.h"
import "C"
import (
"bytes"
"errors"
"fmt"
"strings"
"unsafe"
)
type Fingerprint struct {
Address Address `json:"address"`
Hash [48]byte `json:"hash"`
Address Address `json:"address"`
Hash []byte `json:"hash"`
}
func NewFingerprintFromString(fps string) (*Fingerprint, error) {
fpb, err := Base32StdLowerCase.DecodeString(strings.TrimSpace(strings.ToLower(fps)))
if len(fps) < AddressStringLength {
return nil, ErrInvalidZeroTierAddress
}
ss := strings.Split(fps, "/")
if len(ss) < 1 || len(ss) > 2 {
return nil, ErrInvalidParameter
}
a, err := NewAddressFromString(ss[0])
if err != nil {
return nil, err
}
if len(fpb) != 53 {
return nil, errors.New("invalid fingerprint length")
if len(ss) == 2 {
h, err := Base32StdLowerCase.DecodeString(ss[1])
if err != nil {
return nil, err
}
if len(h) != 48 {
return nil, ErrInvalidParameter
}
return &Fingerprint{Address: a, Hash: h}, nil
}
var fp Fingerprint
fp.Address, _ = NewAddressFromBytes(fpb[0:5])
copy(fp.Hash[:],fpb[5:])
return &fp, nil
return &Fingerprint{Address: a, Hash: nil}, nil
}
func (fp *Fingerprint) String() string {
var tmp [53]byte
fp.Address.CopyTo(tmp[0:5])
copy(tmp[5:],fp.Hash[:])
return Base32StdLowerCase.EncodeToString(tmp[:])
if len(fp.Hash) == 48 {
return fmt.Sprintf("%.10x/%s", uint64(fp.Address), Base32StdLowerCase.EncodeToString(fp.Hash))
}
return fp.Address.String()
}
func (fp *Fingerprint) Equals(fp2 *Fingerprint) bool {

View file

@ -510,7 +510,6 @@ func (n *Node) Peers() []*Peer {
p2.Version = [3]int{int(p.versionMajor), int(p.versionMinor), int(p.versionRev)}
p2.Latency = int(p.latency)
p2.Root = p.root != 0
p2.Bootstrap = NewInetAddressFromSockaddr(unsafe.Pointer(&p.bootstrap))
p2.Paths = make([]Path, 0, int(p.pathCount))
for j := 0; j < len(p2.Paths); j++ {

View file

@ -15,12 +15,13 @@ package zerotier
// Peer is another ZeroTier node
type Peer struct {
Address Address `json:"address"`
Identity *Identity `json:"identity"`
Fingerprint Fingerprint `json:"fingerprint"`
Version [3]int `json:"version"`
Latency int `json:"latency"`
Root bool `json:"root"`
Bootstrap *InetAddress `json:"bootstrap,omitempty"`
Paths []Path `json:"paths,omitempty"`
Address Address `json:"address"`
Identity *Identity `json:"identity"`
Fingerprint Fingerprint `json:"fingerprint"`
Version [3]int `json:"version"`
Latency int `json:"latency"`
Root bool `json:"root"`
Paths []Path `json:"paths,omitempty"`
LocatorTimestamp int64 `json:"locatorTimestamp"`
LocatorEndpoints []Endpoint `json:"locatorEndpoints,omitempty"`
}

View file

@ -153,11 +153,6 @@ extern "C" {
*/
#define ZT_MAX_PEER_NETWORK_PATHS 16
/**
* Maximum number of path configurations that can be set
*/
#define ZT_MAX_CONFIGURABLE_PATHS 32
/**
* Maximum number of rules per capability object
*
@ -175,15 +170,6 @@ extern "C" {
*/
#define ZT_MAX_CERTIFICATES_OF_OWNERSHIP 4
/**
* Maximum size in bytes for a root specification
*
* A root specification is just a serialized identity followed by a serialized
* locator. This provides the maximum size of those plus a lot of extra margin
* for any future expansions, but could change in future versions.
*/
#define ZT_ROOT_SPEC_MAX_SIZE 8192
/**
* Packet characteristics flag: packet direction, 1 if inbound 0 if outbound
*/
@ -274,32 +260,21 @@ extern "C" {
/**
* Identity type codes (must be the same as Identity.hpp).
*/
enum ZT_Identity_Type
enum ZT_IdentityType
{
ZT_IDENTITY_TYPE_C25519 = 0, /* C25519/Ed25519 */
ZT_IDENTITY_TYPE_P384 = 1 /* Combined C25519/NIST-P-384 key */
};
/**
* A ZeroTier identity (opaque)
* ZeroTier identity (address plus keys)
*/
typedef void ZT_Identity;
/**
* Full identity fingerprint with address and 384-bit hash of public key(s)
* Locator is a signed list of endpoints
*/
typedef struct
{
/**
* Short address (only least significant 40 bits are used)
*/
uint64_t address;
/**
* 384-bit hash of identity public key(s)
*/
uint8_t hash[48];
} ZT_Fingerprint;
typedef void ZT_Locator;
/**
* Credential type IDs
@ -333,6 +308,27 @@ enum ZT_EndpointType
ZT_ENDPOINT_TYPE_IP_HTTP2 = 8 // IP/HTTP2 encapsulation
};
/**
* A string that contains endpoint type IDs indexed by endpoint type (can be used as a lookup array)
*/
#define ZT_ENDPOINT_TYPE_CHAR_INDEX "012345678"
/**
* Full identity fingerprint with address and 384-bit hash of public key(s)
*/
typedef struct
{
/**
* Short address (only least significant 40 bits are used)
*/
uint64_t address;
/**
* 384-bit hash of identity public key(s)
*/
uint8_t hash[48];
} ZT_Fingerprint;
/**
* Flag indicating that VL1 tracing should be generated
*/
@ -415,7 +411,7 @@ enum ZT_TraceCredentialRejectionReason
};
#define ZT_TRACE_FIELD_TYPE "t"
#define ZT_TRACE_FIELD_CODE_LOCATION "@"
#define ZT_TRACE_FIELD_CODE_LOCATION "c"
#define ZT_TRACE_FIELD_ENDPOINT "e"
#define ZT_TRACE_FIELD_OLD_ENDPOINT "oe"
#define ZT_TRACE_FIELD_NEW_ENDPOINT "ne"
@ -498,7 +494,12 @@ enum ZT_ResultCode
/**
* The requested operation was given a bad parameter or was called in an invalid state
*/
ZT_RESULT_ERROR_BAD_PARAMETER = 1002
ZT_RESULT_ERROR_BAD_PARAMETER = 1002,
/**
* A credential or other object was supplied that failed cryptographic signature or integrity check
*/
ZT_RESULT_ERROR_INVALID_CREDENTIAL = 1003
};
/**
@ -1119,14 +1120,57 @@ typedef struct
} ZT_InterfaceAddress;
/**
* Physical network path to a peer
* Variant type for storing possible path endpoints or peer contact points.
*/
typedef struct
{
/**
* Address of endpoint
* Endpoint type, which determines what field in the union 'a' applies.
*/
struct sockaddr_storage address;
enum ZT_EndpointType type;
union {
/**
* Socket address generic buffer
*/
struct sockaddr_storage ss;
/**
* Socket address header, for all ZT_ENDPOINT_TYPE_IP types
*/
struct sockaddr sa;
/**
* IPv4 address, for all ZT_ENDPOINT_TYPE_IP types if family is AF_INET
*/
struct sockaddr_in sa_in;
/**
* IPv6 address, for all ZT_ENDPOINT_TYPE_IP types if family is AF_INET6
*/
struct sockaddr_in6 sa_in6;
/**
* MAC address (least significant 48 bites) for ZT_ENDPOINT_TYPE_ETHERNET and other MAC addressed types
*/
uint64_t mac;
/**
* ZeroTier node address and identity fingerprint for ZT_ENDPOINT_TYPE_ZEROTIER
*/
ZT_Fingerprint fp;
} value;
} ZT_Endpoint;
/**
* Network path to a peer
*/
typedef struct
{
/**
* Path endpoint
*/
ZT_Endpoint endpoint;
/**
* Time of last send in milliseconds or 0 for never
@ -1147,10 +1191,10 @@ typedef struct
* Is path preferred?
*/
int preferred;
} ZT_PeerPhysicalPath;
} ZT_Path;
/**
* Peer status result buffer
* Peer information
*/
typedef struct
{
@ -1194,20 +1238,6 @@ typedef struct
*/
int root;
/**
* Number of bootstrap addresses
*/
unsigned int bootstrapAddressCount;
/**
* Bootstrap addresses
*
* This is a memo-ized recently valid address that can be saved and used
* to attempt rapid reconnection with this peer. If the ss_family field
* is 0 this field is considered null/empty.
*/
struct sockaddr_storage bootstrap[ZT_MAX_PEER_NETWORK_PATHS];
/**
* Number of networks in which this peer is authenticated
*/
@ -1224,9 +1254,28 @@ typedef struct
unsigned int pathCount;
/**
* Known network paths to peer (array size: pathCount)
* Known network paths to peer (array size: pathCount).
*
* These are direct paths only. Endpoints can also describe indirect paths,
* but those would not appear here. Right now those can only be relaying via
* a root.
*/
ZT_PeerPhysicalPath *paths;
ZT_Path *paths;
/**
* Timestamp of peer's locator or 0 if none on file
*/
int64_t locatorTimestamp;
/**
* Number of endpoints in locator
*/
unsigned int locatorEndpointCount;
/**
* Endpoints in peer's locator
*/
ZT_Endpoint *locatorEndpoints;
} ZT_Peer;
/**
@ -1567,6 +1616,16 @@ ZT_SDK_API void *ZT_getBuffer();
*/
ZT_SDK_API void ZT_freeBuffer(void *b);
/**
* Free a query result buffer
*
* Use this to free the return values of listNetworks(), listPeers(), and
* other query functions that return allocated structures or buffers.
*
* @param qr Query result buffer
*/
ZT_SDK_API void ZT_freeQueryResult(void *qr);
/* ---------------------------------------------------------------------------------------------------------------- */
/**
@ -1584,7 +1643,12 @@ ZT_SDK_API void ZT_freeBuffer(void *b);
* @param now Current clock in milliseconds
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
ZT_SDK_API enum ZT_ResultCode ZT_Node_new(
ZT_Node **node,
void *uptr,
void *tptr,
const struct ZT_Node_Callbacks *callbacks,
int64_t now);
/**
* Delete a node and free all resources it consumes
@ -1595,7 +1659,9 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,c
* @param node Node to delete
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
*/
ZT_SDK_API void ZT_Node_delete(ZT_Node *node,void *tptr);
ZT_SDK_API void ZT_Node_delete(
ZT_Node *node,
void *tptr);
/**
* Process a packet received from the physical wire
@ -1684,7 +1750,12 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,const ZT_Fingerprint *controllerFingerprint,void *uptr,void *tptr);
ZT_SDK_API enum ZT_ResultCode ZT_Node_join(
ZT_Node *node,
uint64_t nwid,
const ZT_Fingerprint *controllerFingerprint,
void *uptr,
void *tptr);
/**
* Leave a network
@ -1702,7 +1773,11 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,const ZT_
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr);
ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(
ZT_Node *node,
uint64_t nwid,
void **uptr,
void *tptr);
/**
* Subscribe to an Ethernet multicast group
@ -1730,7 +1805,12 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **u
* @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed)
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(
ZT_Node *node,
void *tptr,
uint64_t nwid,
uint64_t multicastGroup,
unsigned long multicastAdi);
/**
* Unsubscribe from an Ethernet multicast group (or all groups)
@ -1746,19 +1826,30 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt
* @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed)
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(
ZT_Node *node,
uint64_t nwid,
uint64_t multicastGroup,
unsigned long multicastAdi);
/**
* Add a root node or update its locator
*
* ZeroTier does not take possession of the id or loc objects. The caller
* must still eventually delete them with ZT_Identity_delete() and
* ZT_Locator_delete().
*
* @param node Node instance
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @param rdef Root definition (serialized identity and locator)
* @param rdeflen Length of root definition in bytes
* @param address If non-NULL will be filled with the ZeroTier address of the root (only defined if return is OK)
* @return OK (0) or error code if a fatal error condition has occurred
* @param id Identity of root to add
* @param loc Root locator
* @return OK (0) or error code if an error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,void *tptr,const void *rdef,unsigned int rdeflen,uint64_t *address);
ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(
ZT_Node *node,
void *tptr,
const ZT_Identity *id,
const ZT_Locator *loc);
/**
* Remove a root
@ -1769,10 +1860,13 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,void *tptr,const voi
*
* @param node Node instance
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @param fp Fingerprint of root (will be looked up by address only if hash is all zeroes)
* @return OK (0) or error code if a fatal error condition has occurred
* @param address ZeroTier address to remove
* @return OK (0) or error code if an error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,void *tptr,const ZT_Fingerprint *fp);
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(
ZT_Node *node,
void *tptr,
const uint64_t address);
/**
* Get this node's 40-bit ZeroTier address
@ -1799,7 +1893,9 @@ ZT_SDK_API const ZT_Identity *ZT_Node_identity(ZT_Node *node);
* @param node Node instance
* @param status Buffer to fill with current node status
*/
ZT_SDK_API void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status);
ZT_SDK_API void ZT_Node_status(
ZT_Node *node,
ZT_NodeStatus *status);
/**
* Get a list of known peer nodes
@ -1822,7 +1918,9 @@ ZT_SDK_API ZT_PeerList *ZT_Node_peers(ZT_Node *node);
* @param nwid 64-bit network ID
* @return Network configuration or NULL if we are not a member of this network
*/
ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid);
ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig(
ZT_Node *node,
uint64_t nwid);
/**
* Enumerate and get status of all networks
@ -1841,17 +1939,10 @@ ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node);
* @param nwid Network ID
* @param ptr New network-associated pointer
*/
ZT_SDK_API void ZT_Node_setNetworkUserPtr(ZT_Node *node,uint64_t nwid,void *ptr);
/**
* Free a query result buffer
*
* Use this to free the return values of listNetworks(), listPeers(), etc.
*
* @param node Node instance
* @param qr Query result buffer
*/
ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr);
ZT_SDK_API void ZT_Node_setNetworkUserPtr(
ZT_Node *node,
uint64_t nwid,
void *ptr);
/**
* Set external interface addresses where this node could be reached
@ -1860,7 +1951,10 @@ ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr);
* @param addrs Addresses
* @param addrCount Number of items in addrs[]
*/
ZT_SDK_API void ZT_Node_setInterfaceAddresses(ZT_Node *node,const ZT_InterfaceAddress *addrs,unsigned int addrCount);
ZT_SDK_API void ZT_Node_setInterfaceAddresses(
ZT_Node *node,
const ZT_InterfaceAddress *addrs,
unsigned int addrCount);
/**
* Send a VERB_USER_MESSAGE to another ZeroTier node
@ -1876,7 +1970,13 @@ ZT_SDK_API void ZT_Node_setInterfaceAddresses(ZT_Node *node,const ZT_InterfaceAd
* @param len Length of data in bytes
* @return Boolean: non-zero on success, zero on failure
*/
ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
ZT_SDK_API int ZT_Node_sendUserMessage(
ZT_Node *node,
void *tptr,
uint64_t dest,
uint64_t typeId,
const void *data,
unsigned int len);
/**
* Set a network controller instance for this node
@ -1893,7 +1993,9 @@ ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,ui
* @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterInstance);
ZT_SDK_API void ZT_Node_setController(
ZT_Node *node,
void *networkConfigMasterInstance);
/* ---------------------------------------------------------------------------------------------------------------- */
@ -1907,7 +2009,7 @@ ZT_SDK_API void ZT_Node_setController(ZT_Node *node,void *networkConfigMasterIns
* @param type Type of identity to generate
* @return New identity or NULL on error
*/
ZT_SDK_API ZT_Identity *ZT_Identity_new(enum ZT_Identity_Type type);
ZT_SDK_API ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type);
/**
* Create a new identity object from a string-serialized identity
@ -1938,7 +2040,12 @@ ZT_SDK_API int ZT_Identity_validate(const ZT_Identity *id);
* @param signatureBufferLength Length of buffer (must be at least 96 bytes)
* @return Length of signature in bytes or 0 on failure.
*/
ZT_SDK_API unsigned int ZT_Identity_sign(const ZT_Identity *id,const void *data,unsigned int len,void *signature,unsigned int signatureBufferLength);
ZT_SDK_API unsigned int ZT_Identity_sign(
const ZT_Identity *id,
const void *data,
unsigned int len,
void *signature,
unsigned int signatureBufferLength);
/**
* Verify a signature
@ -1950,7 +2057,12 @@ ZT_SDK_API unsigned int ZT_Identity_sign(const ZT_Identity *id,const void *data,
* @param sigLen Length of signature in bytes
* @return Non-zero if signature is valid
*/
ZT_SDK_API int ZT_Identity_verify(const ZT_Identity *id,const void *data,unsigned int len,const void *signature,unsigned int sigLen);
ZT_SDK_API int ZT_Identity_verify(
const ZT_Identity *id,
const void *data,
unsigned int len,
const void *signature,
unsigned int sigLen);
/**
* Get identity type
@ -1958,7 +2070,7 @@ ZT_SDK_API int ZT_Identity_verify(const ZT_Identity *id,const void *data,unsigne
* @param id Identity to query
* @return Identity type code
*/
ZT_SDK_API enum ZT_Identity_Type ZT_Identity_type(const ZT_Identity *id);
ZT_SDK_API enum ZT_IdentityType ZT_Identity_type(const ZT_Identity *id);
/**
* Convert an identity to its string representation
@ -1969,7 +2081,11 @@ ZT_SDK_API enum ZT_Identity_Type ZT_Identity_type(const ZT_Identity *id);
* @param includePrivate If true include the private key if present
* @return Pointer to buf or NULL on overflow or other error
*/
ZT_SDK_API char *ZT_Identity_toString(const ZT_Identity *id,char *buf,int capacity,int includePrivate);
ZT_SDK_API char *ZT_Identity_toString(
const ZT_Identity *id,
char *buf,
int capacity,
int includePrivate);
/**
* Check whether this identity object also holds a private key
@ -1995,19 +2111,6 @@ ZT_SDK_API uint64_t ZT_Identity_address(const ZT_Identity *id);
*/
ZT_SDK_API const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id);
/**
* Make a root specification
*
* @param id Identity to sign root with (must have private key)
* @param ts Timestamp for root specification in milliseconds since epoch
* @param addrs Physical addresses for root
* @param addrcnt Number of physical addresses for root
* @param rootSpecBuf Buffer to receive result, should be at least ZT_ROOT_SPEC_MAX_SIZE bytes
* @param rootSpecBufSize Size of rootSpecBuf in bytes
* @return Bytes written to rootSpecBuf or -1 on error
*/
ZT_SDK_API int ZT_Identity_makeRootSpecification(ZT_Identity *id,int64_t ts,struct sockaddr_storage *addrs,unsigned int addrcnt,void *rootSpecBuf,unsigned int rootSpecBufSize);
/**
* Delete an identity and free associated memory
*
@ -2020,6 +2123,53 @@ ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id);
/* ---------------------------------------------------------------------------------------------------------------- */
/**
* Create and sign a new locator
*
* @param ts Locator timestamp
* @param endpoints List of endpoints to store in locator
* @param endpointCount Number of endpoints (maximum: 8)
* @param signer Identity to sign locator (must include private key)
* @return Locator or NULL on error (too many endpoints or identity does not have private key)
*/
ZT_SDK_API ZT_Locator *ZT_Locator_create(int64_t ts,const ZT_Endpoint *endpoints,unsigned int endpointCount,const ZT_Identity *signer);
/**
* Decode a serialized locator
*
* @param data Data to deserialize
* @param len Length of data
* @return Locator or NULL if data is not valid
*/
ZT_SDK_API ZT_Locator *ZT_Locator_unmarshal(const void *data,unsigned int len);
/**
* Get the number of endpoints in this locator
*
* @param loc Locator to query
* @return Number of endpoints
*/
ZT_SDK_API unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc);
/**
* Get a pointer to an endpoint in a locator
*
* The returned pointer remains valid as long as the Locator is not deleted.
*
* @param ep Endpoint number from 0 to 1 - endpointCount()
* @return Endpoint or NULL if out of bounds
*/
ZT_SDK_API const ZT_Endpoint *ZT_Locator_endpoint(const unsigned int ep);
/**
* Delete a locator
*
* @param loc Locator to delete
*/
ZT_SDK_API void ZT_Locator_delete(ZT_Locator *loc);
/* ---------------------------------------------------------------------------------------------------------------- */
/**
* Get ZeroTier One version
*

View file

@ -35,7 +35,6 @@ public:
explicit ZT_INLINE Address(const uint64_t a) noexcept : _a(a) {}
explicit ZT_INLINE Address(const uint8_t b[5]) noexcept : _a(((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) | (uint64_t)b[4]) {}
ZT_INLINE Address &operator=(const Address &a) noexcept { _a = a._a; return *this; }
ZT_INLINE Address &operator=(const uint64_t a) noexcept { _a = a; return *this; }
/**
@ -108,6 +107,7 @@ public:
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)_a; }
ZT_INLINE operator bool() const noexcept { return (_a != 0); }
ZT_INLINE operator uint64_t() const noexcept { return _a; }
ZT_INLINE bool operator==(const Address &a) const noexcept { return _a == a._a; }
ZT_INLINE bool operator!=(const Address &a) const noexcept { return _a != a._a; }
@ -116,6 +116,13 @@ public:
ZT_INLINE bool operator>=(const Address &a) const noexcept { return _a >= a._a; }
ZT_INLINE bool operator<=(const Address &a) const noexcept { return _a <= a._a; }
ZT_INLINE bool operator==(const uint64_t a) const noexcept { return _a == a; }
ZT_INLINE bool operator!=(const uint64_t a) const noexcept { return _a != a; }
ZT_INLINE bool operator>(const uint64_t a) const noexcept { return _a > a; }
ZT_INLINE bool operator<(const uint64_t a) const noexcept { return _a < a; }
ZT_INLINE bool operator>=(const uint64_t a) const noexcept { return _a >= a; }
ZT_INLINE bool operator<=(const uint64_t a) const noexcept { return _a <= a; }
private:
uint64_t _a;
};

View file

@ -15,6 +15,7 @@ set(core_headers
Defragmenter.hpp
Dictionary.hpp
ECC384.hpp
EphemeralKey.hpp
Expect.hpp
FCV.hpp
Fingerprint.hpp

View file

@ -139,6 +139,8 @@ class Vector : public std::vector< V,Utils::Mallocator<V> >
{
public:
ZT_INLINE Vector() {}
template<typename I>
ZT_INLINE Vector(I begin,I end) : std::vector< V,Utils::Mallocator<V> >(begin,end) {}
};
template<typename V>

View file

@ -12,65 +12,71 @@
/****/
#include "Dictionary.hpp"
#include "Identity.hpp"
namespace ZeroTier {
static const FCV<char, 8> s_signatureFingerprint("@Si", 4);
static const FCV<char, 8> s_signatureData("@Ss", 4);
Dictionary::Dictionary()
{
}
Vector<uint8_t> &Dictionary::operator[](const char *k)
{
return m_entries[s_toKey(k)];
FCV<char, 8> key;
return m_entries[s_key(key, k)];
}
const Vector<uint8_t> &Dictionary::operator[](const char *k) const
{
static const Vector<uint8_t> s_emptyEntry;
Map< uint64_t,Vector<uint8_t> >::const_iterator e(m_entries.find(s_toKey(k)));
FCV<char, 8> key;
SortedMap<FCV<char, 8>, Vector<uint8_t> >::const_iterator e(m_entries.find(s_key(key, k)));
return (e == m_entries.end()) ? s_emptyEntry : e->second;
}
void Dictionary::add(const char *k,bool v)
void Dictionary::add(const char *k, bool v)
{
Vector<uint8_t> &e = (*this)[k];
e.resize(2);
e[0] = (uint8_t)(v ? '1' : '0');
e[0] = (uint8_t) (v ? '1' : '0');
e[1] = 0;
}
void Dictionary::add(const char *k,const Address &v)
void Dictionary::add(const char *k, const Address &v)
{
Vector<uint8_t> &e = (*this)[k];
e.resize(ZT_ADDRESS_STRING_SIZE_MAX);
v.toString((char *)e.data());
v.toString((char *) e.data());
}
void Dictionary::add(const char *k,const char *v)
void Dictionary::add(const char *k, const char *v)
{
if ((v)&&(*v)) {
if ((v) && (*v)) {
Vector<uint8_t> &e = (*this)[k];
e.clear();
while (*v)
e.push_back((uint8_t)*(v++));
e.push_back((uint8_t) *(v++));
}
}
void Dictionary::add(const char *k,const void *data,unsigned int len)
void Dictionary::add(const char *k, const void *data, unsigned int len)
{
Vector<uint8_t> &e = (*this)[k];
if (len != 0) {
e.assign((const uint8_t *)data,(const uint8_t *)data + len);
e.assign((const uint8_t *) data, (const uint8_t *) data + len);
} else {
e.clear();
}
}
bool Dictionary::getB(const char *k,bool dfl) const
bool Dictionary::getB(const char *k, bool dfl) const
{
const Vector<uint8_t> &e = (*this)[k];
if (!e.empty()) {
switch ((char)e[0]) {
switch ((char) e[0]) {
case '1':
case 't':
case 'T':
@ -84,7 +90,7 @@ bool Dictionary::getB(const char *k,bool dfl) const
return dfl;
}
uint64_t Dictionary::getUI(const char *k,uint64_t dfl) const
uint64_t Dictionary::getUI(const char *k, uint64_t dfl) const
{
uint8_t tmp[18];
uint64_t v = dfl;
@ -92,29 +98,79 @@ uint64_t Dictionary::getUI(const char *k,uint64_t dfl) const
if (!e.empty()) {
if (e.back() != 0) {
const unsigned long sl = e.size();
Utils::copy(tmp,e.data(),(sl > 17) ? 17 : sl);
Utils::copy(tmp, e.data(), (sl > 17) ? 17 : sl);
tmp[17] = 0;
return Utils::unhex((const char *)tmp);
return Utils::unhex((const char *) tmp);
}
return Utils::unhex((const char *)e.data());
return Utils::unhex((const char *) e.data());
}
return v;
}
void Dictionary::getS(const char *k,char *v,const unsigned int cap) const
char *Dictionary::getS(const char *k, char *v, const unsigned int cap) const
{
if (cap == 0) // sanity check
return;
const Vector<uint8_t> &e = (*this)[k];
unsigned int i = 0;
const unsigned int last = cap - 1;
for(;;) {
if ((i == last)||(i >= (unsigned int)e.size()))
for (;;) {
if ((i == last) || (i >= (unsigned int)e.size()))
break;
v[i] = (char)e[i];
v[i] = (char) e[i];
++i;
}
v[i] = 0;
return v;
}
bool Dictionary::sign(const Identity &signer)
{
Vector<uint8_t> data;
encode(data, true);
uint8_t sig[ZT_SIGNATURE_BUFFER_SIZE];
const unsigned int siglen = signer.sign(data.data(), (unsigned int) data.size(), sig, ZT_SIGNATURE_BUFFER_SIZE);
if (siglen == 0)
return false;
uint8_t fp[ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE];
signer.fingerprint().address().copyTo(fp);
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(fp + ZT_ADDRESS_LENGTH, signer.fingerprint().hash());
m_entries[s_signatureFingerprint].assign(fp, fp + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE);
m_entries[s_signatureData].assign(sig, sig + siglen);
return true;
}
Fingerprint Dictionary::signer() const
{
SortedMap<FCV<char, 8>, Vector<uint8_t> >::const_iterator sigfp(m_entries.find(s_signatureFingerprint));
Fingerprint fp;
if ((sigfp != m_entries.end()) && (sigfp->second.size() == (ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE))) {
fp.apiFingerprint()->address = Address(sigfp->second.data()).toInt();
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(fp.apiFingerprint()->hash, sigfp->second.data() + ZT_ADDRESS_LENGTH);
}
return fp;
}
bool Dictionary::verify(const Identity &signer) const
{
SortedMap< FCV<char, 8>, Vector<uint8_t> >::const_iterator sigfp(m_entries.find(s_signatureFingerprint));
if (
(sigfp == m_entries.end()) ||
(sigfp->second.size() != (ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE)) ||
(Address(sigfp->second.data()) != signer.address()) ||
(memcmp(sigfp->second.data() + ZT_ADDRESS_LENGTH,signer.fingerprint().hash(),ZT_FINGERPRINT_HASH_SIZE) != 0))
return false;
SortedMap< FCV<char, 8>, Vector<uint8_t> >::const_iterator sig(m_entries.find(s_signatureData));
if ((sig == m_entries.end()) || (sig->second.empty()))
return false;
Vector<uint8_t> data;
encode(data, true);
return signer.verify(data.data(),(unsigned int)data.size(),sig->second.data(),(unsigned int)sig->second.size());
}
void Dictionary::clear()
@ -122,34 +178,33 @@ void Dictionary::clear()
m_entries.clear();
}
void Dictionary::encode(Vector<uint8_t> &out) const
void Dictionary::encode(Vector<uint8_t> &out, const bool omitSignatureFields) const
{
uint64_t str[2] = { 0,0 }; // second uint64_t being 0 means all strings always 0-terminated
out.clear();
for(Map< uint64_t,Vector<uint8_t> >::const_iterator ti(m_entries.begin());ti != m_entries.end();++ti) {
str[0] = ti->first;
s_appendKey(out,reinterpret_cast<const char *>(str));
for(Vector<uint8_t>::const_iterator i(ti->second.begin());i!=ti->second.end();++i)
s_appendValueByte(out,*i);
out.push_back((uint8_t)'\n');
for (SortedMap<FCV<char, 8>, Vector<uint8_t> >::const_iterator ti(m_entries.begin());ti != m_entries.end();++ti) {
if ((!omitSignatureFields) || ((ti->first != s_signatureFingerprint) && (ti->first != s_signatureData))) {
s_appendKey(out, ti->first.data());
for (Vector<uint8_t>::const_iterator i(ti->second.begin());i != ti->second.end();++i)
s_appendValueByte(out, *i);
out.push_back((uint8_t) '\n');
}
}
out.push_back(0);
}
bool Dictionary::decode(const void *data,unsigned int len)
bool Dictionary::decode(const void *data, unsigned int len)
{
clear();
uint64_t k = 0;
unsigned int ki = 0;
FCV<char, 8> k;
Vector<uint8_t> *v = nullptr;
bool escape = false;
for(unsigned int di=0;di<len;++di) {
for (unsigned int di = 0;di < len;++di) {
uint8_t c = reinterpret_cast<const uint8_t *>(data)[di];
if (!c) break;
if (v) {
if (escape) {
escape = false;
switch(c) {
switch (c) {
case 48:
v->push_back(0);
break;
@ -167,9 +222,8 @@ bool Dictionary::decode(const void *data,unsigned int len)
break;
}
} else {
if (c == (uint8_t)'\n') {
k = 0;
ki = 0;
if (c == (uint8_t) '\n') {
k.clear();
v = nullptr;
} else if (c == 92) { // backslash
escape = true;
@ -178,16 +232,18 @@ bool Dictionary::decode(const void *data,unsigned int len)
}
}
} else {
if ((c < 33)||(c > 126)||(c == 92)) {
if ((c < 33) || (c > 126) || (c == 92)) {
return false;
} else if (c == (uint8_t)'=') {
} else if (c == (uint8_t) '=') {
k.push_back(0);
v = &m_entries[k];
} else if (k.size() < 7) {
k.push_back(c);
} else {
reinterpret_cast<uint8_t *>(&k)[ki & 7U] ^= c;
return false;
}
}
}
return true;
}

View file

@ -18,16 +18,21 @@
#include "Utils.hpp"
#include "Address.hpp"
#include "Buf.hpp"
#include "FCV.hpp"
#include "SHA512.hpp"
#include "Fingerprint.hpp"
#include "Containers.hpp"
namespace ZeroTier {
class Identity;
/**
* A simple key-value store for short keys
*
* This data structure is used for network configurations, node meta-data,
* and other open-definition protocol objects. It consists of a key-value
* store with short (max: 8 characters) keys that map to strings, blobs,
* store with short (max: 7 characters) keys that map to strings, blobs,
* or integers with the latter being by convention in hex format.
*
* If this seems a little odd, it is. It dates back to the very first alpha
@ -118,7 +123,7 @@ public:
* @param v Buffer to hold string
* @param cap Maximum size of string (including terminating null)
*/
void getS(const char *k,char *v,unsigned int cap) const;
char *getS(const char *k,char *v,unsigned int cap) const;
/**
* Get an object supporting the marshal/unmarshal interface pattern
@ -133,11 +138,36 @@ public:
const Vector<uint8_t> &d = (*this)[k];
if (d.empty())
return false;
if (obj.unmarshal(d.data(),(unsigned int)d.size()) <= 0)
return false;
return true;
return (obj.unmarshal(d.data(),(unsigned int)d.size()) > 0);
}
/**
* Sign this identity
*
* This adds two fields:
* "@Si" contains the fingerprint (address followed by hash) of the signer
* "@Ss" contains the signature
*
* @param signer Signing identity (must contain secret)
* @return True if signature was successful
*/
bool sign(const Identity &signer);
/**
* Get the signer's fingerprint for this dictionary or a NIL fingerprint if not signed.
*
* @return Signer
*/
Fingerprint signer() const;
/**
* Verify this identity's signature
*
* @param signer
* @return
*/
bool verify(const Identity &signer) const;
/**
* Erase all entries in dictionary
*/
@ -156,12 +186,10 @@ public:
/**
* Encode to a string in the supplied vector
*
* This does not add a terminating zero. This must be pushed afterwords
* if the result is to be handled as a C string.
*
* @param out String encoded dictionary
* @param omitSignatureFields If true omit the signature fields from encoding (default: false)
*/
void encode(Vector<uint8_t> &out) const;
void encode(Vector<uint8_t> &out,bool omitSignatureFields = false) const;
/**
* Decode a string encoded dictionary
@ -347,31 +375,35 @@ private:
break;
}
}
template<typename V>
ZT_INLINE static void s_appendKey(V &out,const char *const k)
{
for(unsigned int i=0;i<8;++i) {
for(unsigned int i=0;i<7;++i) {
const char kc = k[i];
if (!kc) break;
if (kc == 0)
break;
if ((kc >= 33)&&(kc <= 126)&&(kc != 61)&&(kc != 92)) // printable ASCII with no spaces, equals, or backslash
out.push_back((uint8_t)kc);
}
out.push_back((uint8_t)'=');
}
// This just packs up to 8 character bytes into a 64-bit word. There is no need
// for this to be portable in terms of endian-ness. It's just for fast key lookup.
static ZT_INLINE uint64_t s_toKey(const char *k)
ZT_INLINE static FCV<char,8> &s_key(FCV<char,8> &buf,const char *k) noexcept
{
uint64_t key = 0;
for(int i=0;i<8;++i) {
if ((reinterpret_cast<uint8_t *>(&key)[i] = *(k++)) == 0)
buf.clear();
for(unsigned int i=0;i<7;++i) {
const char kc = k[i];
if (kc == 0)
break;
if ((kc >= 33)&&(kc <= 126)&&(kc != 61)&&(kc != 92)) // printable ASCII with no spaces, equals, or backslash
buf.push_back(kc);
}
return key;
buf.push_back(0);
return buf;
}
Map< uint64_t,Vector<uint8_t> > m_entries;
SortedMap< FCV<char,8>,Vector<uint8_t> > m_entries;
};
} // namespace ZeroTier

View file

@ -16,39 +16,128 @@
namespace ZeroTier {
void Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
{
static const char *const s_endpointTypeChars = ZT_ENDPOINT_TYPE_CHAR_INDEX;
static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow");
static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow");
switch (this->type) {
default:
s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_NIL];
s[1] = 0;
break;
case ZT_ENDPOINT_TYPE_ZEROTIER:
s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_ZEROTIER];
s[1] = '/';
zt().toString(s + 2);
break;
case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH:
s[0] = s_endpointTypeChars[this->type];
s[1] = '/';
eth().toString(s + 2);
break;
case ZT_ENDPOINT_TYPE_IP:
case ZT_ENDPOINT_TYPE_IP_UDP:
case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_HTTP2:
s[0] = s_endpointTypeChars[this->type];
s[1] = '/';
ip().toString(s + 2);
break;
}
}
bool Endpoint::fromString(const char *s) noexcept
{
memoryZero(this);
if ((!s) || (!*s))
return true;
const char *start = strchr(s, '/');
if (start) {
char tmp[16];
for (unsigned int i = 0;i < 15;++i) {
if ((tmp[i] = s[i]) == 0)
break;
}
tmp[15] = 0;
this->type = (ZT_EndpointType)Utils::strToUInt(tmp);
++start;
Fingerprint tmpfp;
MAC tmpmac;
switch (this->type) {
case ZT_ENDPOINT_TYPE_NIL:
break;
case ZT_ENDPOINT_TYPE_ZEROTIER:
if (!tmpfp.fromString(start))
return false;
this->value.fp = tmpfp;
break;
case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH:
tmpmac.fromString(start);
this->value.mac = tmpmac.toInt();
break;
case ZT_ENDPOINT_TYPE_IP:
case ZT_ENDPOINT_TYPE_IP_UDP:
case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_HTTP2:
if (!asInetAddress(this->value.ss).fromString(start))
return false;
default:
this->type = ZT_ENDPOINT_TYPE_NIL;
return false;
}
} else {
if (Utils::strToUInt(s) != (unsigned int)ZT_ENDPOINT_TYPE_NIL)
return false;
}
return true;
}
int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
{
switch(m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1]) {
default:
switch (this->type) {
//case ZT_ENDPOINT_TYPE_NIL:
data[0] = 0;
default:
// NIL endpoints get serialized like NIL InetAddress instances.
data[0] = ZT_ENDPOINT_TYPE_NIL;
return 1;
case ZT_ENDPOINT_TYPE_ZEROTIER:
data[0] = 16 + ZT_ENDPOINT_TYPE_ZEROTIER;
reinterpret_cast<const Fingerprint *>(m_value)->address().copyTo(data + 1);
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + 1 + ZT_ADDRESS_LENGTH,reinterpret_cast<const Fingerprint *>(m_value)->hash());
Address(this->value.fp.address).copyTo(data + 1);
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + 1 + ZT_ADDRESS_LENGTH, this->value.fp.hash);
return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE;
case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH:
data[0] = 16 + m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1];
reinterpret_cast<const MAC *>(m_value)->copyTo(data + 1);
data[0] = 16 + (uint8_t)this->type;
MAC(this->value.mac).copyTo(data + 1);
return 7;
case ZT_ENDPOINT_TYPE_IP_UDP:
return reinterpret_cast<const InetAddress *>(m_value)->marshal(data);
// Default UDP mode gets serialized to look exactly like an InetAddress.
return asInetAddress(this->value.ss).marshal(data);
case ZT_ENDPOINT_TYPE_IP:
case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_HTTP2:
data[0] = 16 + m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1];
return 1 + reinterpret_cast<const InetAddress *>(m_value)->marshal(data + 1);
// Other IP types get serialized as new version Endpoint instances with type.
data[0] = 16 + (uint8_t)this->type;
return 1 + asInetAddress(this->value.ss).marshal(data + 1);
}
}
int Endpoint::unmarshal(const uint8_t *restrict data,int len) noexcept
int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept
{
memoryZero(this);
if (unlikely(len <= 0))
@ -59,25 +148,25 @@ int Endpoint::unmarshal(const uint8_t *restrict data,int len) noexcept
// This allows backward compatibility with old endpoint fields in the
// protocol that were serialized InetAddress instances.
if (data[0] < 16) {
switch(data[0]) {
switch (data[0]) {
case 0:
return 1;
case 4:
case 6:
m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1] = (uint8_t)ZT_ENDPOINT_TYPE_IP_UDP;
return reinterpret_cast<InetAddress *>(m_value)->unmarshal(data,len);
this->type = ZT_ENDPOINT_TYPE_IP_UDP;
return asInetAddress(this->value.ss).unmarshal(data, len);
}
return -1;
}
switch((m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1] = (data[0] - 16))) {
switch ((this->type = (ZT_EndpointType)(data[0] - 16))) {
case ZT_ENDPOINT_TYPE_NIL:
return 1;
case ZT_ENDPOINT_TYPE_ZEROTIER:
if (len >= (1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE)) {
reinterpret_cast<Fingerprint *>(m_value)->apiFingerprint()->address = Address(data + 1).toInt();
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(reinterpret_cast<Fingerprint *>(m_value)->apiFingerprint()->hash,data + 1 + ZT_ADDRESS_LENGTH);
this->value.fp.address = Address(data + 1).toInt();
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(this->value.fp.hash, data + 1 + ZT_ADDRESS_LENGTH);
return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE;
}
return -1;
@ -86,7 +175,9 @@ int Endpoint::unmarshal(const uint8_t *restrict data,int len) noexcept
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH:
if (len >= 7) {
reinterpret_cast<MAC *>(m_value)->setTo(data + 1);
MAC tmp;
tmp.setTo(data + 1);
this->value.mac = tmp.toInt();
return 7;
}
return -1;
@ -95,7 +186,7 @@ int Endpoint::unmarshal(const uint8_t *restrict data,int len) noexcept
case ZT_ENDPOINT_TYPE_IP_UDP:
case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_HTTP2:
return reinterpret_cast<InetAddress *>(m_value)->unmarshal(data + 1,len - 1);
return asInetAddress(this->value.ss).unmarshal(data + 1, len - 1);
default:
break;
@ -104,11 +195,55 @@ int Endpoint::unmarshal(const uint8_t *restrict data,int len) noexcept
// Unrecognized types can still be passed over in a valid stream if they are
// prefixed by a 16-bit size. This allows forward compatibility with future
// endpoint types.
m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1] = (uint8_t)ZT_ENDPOINT_TYPE_NIL;
this->type = ZT_ENDPOINT_TYPE_NIL;
if (len < 3)
return -1;
const int unrecLen = 1 + (int)Utils::loadBigEndian<uint16_t>(data + 1);
const int unrecLen = 1 + (int) Utils::loadBigEndian<uint16_t>(data + 1);
return (unrecLen > len) ? -1 : unrecLen;
}
bool Endpoint::operator==(const Endpoint &ep) const noexcept
{
if (this->type == ep.type) {
switch(this->type) {
case ZT_ENDPOINT_TYPE_ZEROTIER:
return zt() == ep.zt();
case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH:
return this->value.mac == ep.value.mac;
case ZT_ENDPOINT_TYPE_IP:
case ZT_ENDPOINT_TYPE_IP_UDP:
case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_HTTP2:
return ip() == ep.ip();
default:
return true;
}
}
return false;
}
bool Endpoint::operator<(const Endpoint &ep) const noexcept
{
if (this->type == ep.type) {
switch(this->type) {
case ZT_ENDPOINT_TYPE_ZEROTIER:
return zt() < ep.zt();
case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH:
return this->value.mac < ep.value.mac;
case ZT_ENDPOINT_TYPE_IP:
case ZT_ENDPOINT_TYPE_IP_UDP:
case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_HTTP2:
return ip() < ep.ip();
default:
return true;
}
}
return (int)this->type < (int)ep.type;
}
} // namespace ZeroTier

View file

@ -22,13 +22,17 @@
#include "Fingerprint.hpp"
#include "MAC.hpp"
#define ZT_ENDPOINT_MARSHAL_SIZE_MAX 128
static_assert(ZT_ENDPOINT_MARSHAL_SIZE_MAX > (ZT_INETADDRESS_MARSHAL_SIZE_MAX + 1),"ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert(ZT_ENDPOINT_MARSHAL_SIZE_MAX > (sizeof(ZT_Fingerprint) + 1),"ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
#define ZT_ENDPOINT_STRING_SIZE_MAX 256
#define ZT_ENDPOINT_MARSHAL_SIZE_MAX 192
namespace ZeroTier {
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > ZT_INETADDRESS_MARSHAL_SIZE_MAX, "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(ZT_Fingerprint), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(InetAddress), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(MAC), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(Fingerprint), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
/**
* Endpoint variant specifying some form of network endpoint.
*
@ -38,18 +42,17 @@ namespace ZeroTier {
* where InetAddress was used as long as only the UDP type is exchanged
* with those nodes.
*/
class Endpoint : public TriviallyCopyable
class Endpoint : public ZT_Endpoint, public TriviallyCopyable
{
public:
/**
* Endpoint type (defined in the API)
*/
typedef ZT_EndpointType Type;
/**
* Create a NIL/empty endpoint
*/
ZT_INLINE Endpoint() noexcept { memoryZero(this); }
ZT_INLINE Endpoint() noexcept
{ memoryZero(this); }
ZT_INLINE Endpoint(const ZT_Endpoint &ep) noexcept
{ *this = ep; }
/**
* Create an endpoint for a type that uses an IP
@ -57,11 +60,11 @@ public:
* @param a IP/port
* @param et Endpoint type (default: IP_UDP)
*/
ZT_INLINE Endpoint(const InetAddress &a,const Type et = ZT_ENDPOINT_TYPE_IP_UDP) noexcept
ZT_INLINE Endpoint(const InetAddress &inaddr, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_IP_UDP) noexcept
{
if (a) {
Utils::copy<sizeof(InetAddress)>(m_value,&a);
m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1] = (uint8_t)et;
if (inaddr) {
this->type = et;
Utils::copy<sizeof(struct sockaddr_storage)>(&(this->value.ss), &(inaddr.as.ss));
} else {
memoryZero(this);
}
@ -75,8 +78,8 @@ public:
ZT_INLINE Endpoint(const Fingerprint &zt_) noexcept
{
if (zt_) {
Utils::copy<sizeof(Fingerprint)>(m_value,&zt_);
m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1] = (uint8_t)ZT_ENDPOINT_TYPE_ZEROTIER;
this->type = ZT_ENDPOINT_TYPE_ZEROTIER;
this->value.fp = zt_;
} else {
memoryZero(this);
}
@ -88,32 +91,28 @@ public:
* @param eth_ Ethernet address
* @param et Endpoint type (default: ETHERNET)
*/
ZT_INLINE Endpoint(const MAC &eth_,const Type et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept
ZT_INLINE Endpoint(const MAC &eth_, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept
{
if (eth_) {
Utils::copy<sizeof(MAC)>(m_value,&eth_);
m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1] = (uint8_t)et;
this->type = et;
this->value.mac = eth_.toInt();
} else {
memoryZero(this);
}
}
/**
* @return Endpoint type
*/
ZT_INLINE Type type() const noexcept { return (Type)m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1]; }
/**
* @return True if endpoint type isn't NIL
*/
ZT_INLINE operator bool() const noexcept { return (m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX-1] != (uint8_t)ZT_ENDPOINT_TYPE_NIL); }
ZT_INLINE operator bool() const noexcept
{ return this->type != ZT_ENDPOINT_TYPE_NIL; }
/**
* @return True if this endpoint type has an InetAddress address type and thus ip() is valid
*/
ZT_INLINE bool isInetAddr() const noexcept
{
switch(this->type()) {
switch (this->type) {
case ZT_ENDPOINT_TYPE_IP:
case ZT_ENDPOINT_TYPE_IP_UDP:
case ZT_ENDPOINT_TYPE_IP_TCP:
@ -129,28 +128,58 @@ public:
*
* @return InetAddress instance
*/
ZT_INLINE const InetAddress &ip() const noexcept { return *reinterpret_cast<const InetAddress *>(m_value); }
ZT_INLINE const InetAddress &ip() const noexcept
{ return asInetAddress(this->value.ss); }
/**
* Get MAC if this is an Ethernet, WiFi direct, or Bluetooth type (undefined otherwise)
*
* @return Ethernet MAC
*/
ZT_INLINE const MAC &eth() const noexcept { return *reinterpret_cast<const MAC *>(m_value); }
ZT_INLINE MAC eth() const noexcept
{ return MAC(this->value.mac); }
/**
* Get fingerprint if this is a ZeroTier endpoint type (undefined otherwise)
*
* @return ZeroTier fingerprint
*/
ZT_INLINE const Fingerprint &zt() const noexcept { return *reinterpret_cast<const Fingerprint *>(m_value); }
ZT_INLINE Fingerprint zt() const noexcept
{ return Fingerprint(this->value.fp); }
void toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept;
ZT_INLINE String toString() const
{
char tmp[ZT_ENDPOINT_STRING_SIZE_MAX];
toString(tmp);
return String(tmp);
}
bool fromString(const char *s) noexcept;
static constexpr int marshalSizeMax() noexcept
{ return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
static constexpr int marshalSizeMax() noexcept { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept;
int unmarshal(const uint8_t *restrict data,int len) noexcept;
private:
uint8_t m_value[ZT_ENDPOINT_MARSHAL_SIZE_MAX]; // the last byte in this buffer is the type
int unmarshal(const uint8_t *restrict data, int len) noexcept;
bool operator==(const Endpoint &ep) const noexcept;
ZT_INLINE bool operator!=(const Endpoint &ep) const noexcept
{ return !((*this) == ep); }
bool operator<(const Endpoint &ep) const noexcept;
ZT_INLINE bool operator>(const Endpoint &ep) const noexcept
{ return (ep < *this); }
ZT_INLINE bool operator<=(const Endpoint &ep) const noexcept
{ return !(ep < *this); }
ZT_INLINE bool operator>=(const Endpoint &ep) const noexcept
{ return !(*this < ep); }
};
} // namespace ZeroTier

View file

@ -31,18 +31,28 @@ namespace ZeroTier {
* @tparam T Type to contain
* @tparam C Maximum capacity of vector
*/
template<typename T,unsigned int C>
template<typename T, unsigned int C>
class FCV
{
public:
typedef T * iterator;
typedef const T * const_iterator;
typedef T *iterator;
typedef const T *const_iterator;
ZT_INLINE FCV() noexcept : _s(0) {}
ZT_INLINE FCV(const FCV &v) : _s(0) { *this = v; }
ZT_INLINE FCV() noexcept: _s(0)
{}
ZT_INLINE FCV(const FCV &v) : _s(0)
{ *this = v; }
ZT_INLINE FCV(const T *const contents, const unsigned int len) :
_s(0)
{
for (unsigned int i = 0;i < len;++i)
push_back(contents[i]);
}
template<typename I>
ZT_INLINE FCV(I i,I end) :
ZT_INLINE FCV(I i, I end) :
_s(0)
{
while (i != end) {
@ -51,7 +61,8 @@ public:
}
}
ZT_INLINE ~FCV() { this->clear(); }
ZT_INLINE ~FCV()
{ this->clear(); }
ZT_INLINE FCV &operator=(const FCV &v)
{
@ -59,7 +70,7 @@ public:
this->clear();
const unsigned int s = v._s;
_s = s;
for (unsigned int i=0;i<s;++i)
for (unsigned int i = 0;i < s;++i)
new(reinterpret_cast<T *>(_m) + i) T(*(reinterpret_cast<const T *>(v._m) + i));
}
return *this;
@ -72,7 +83,7 @@ public:
{
const unsigned int s = _s;
_s = 0;
for(unsigned int i=0;i<s;++i)
for (unsigned int i = 0;i < s;++i)
(reinterpret_cast<T *>(_m) + i)->~T();
}
@ -83,14 +94,21 @@ public:
*/
ZT_INLINE void unsafeMoveTo(FCV &v) noexcept
{
Utils::copy(v._m,_m,(v._s = _s) * sizeof(T));
Utils::copy(v._m, _m, (v._s = _s) * sizeof(T));
_s = 0;
}
ZT_INLINE iterator begin() noexcept { return reinterpret_cast<T *>(_m); }
ZT_INLINE iterator end() noexcept { return reinterpret_cast<T *>(_m) + _s; }
ZT_INLINE const_iterator begin() const noexcept { return reinterpret_cast<const T *>(_m); }
ZT_INLINE const_iterator end() const noexcept { return reinterpret_cast<const T *>(_m) + _s; }
ZT_INLINE iterator begin() noexcept
{ return reinterpret_cast<T *>(_m); }
ZT_INLINE iterator end() noexcept
{ return reinterpret_cast<T *>(_m) + _s; }
ZT_INLINE const_iterator begin() const noexcept
{ return reinterpret_cast<const T *>(_m); }
ZT_INLINE const_iterator end() const noexcept
{ return reinterpret_cast<const T *>(_m) + _s; }
ZT_INLINE T &operator[](const unsigned int i)
{
@ -98,6 +116,7 @@ public:
return reinterpret_cast<T *>(_m)[i];
throw std::out_of_range("i > capacity");
}
ZT_INLINE const T &operator[](const unsigned int i) const
{
if (likely(i < _s))
@ -105,12 +124,20 @@ public:
throw std::out_of_range("i > capacity");
}
static constexpr unsigned int capacity() noexcept { return C; }
ZT_INLINE unsigned int size() const noexcept { return _s; }
ZT_INLINE bool empty() const noexcept { return (_s == 0); }
static constexpr unsigned int capacity() noexcept
{ return C; }
ZT_INLINE T *data() noexcept { return reinterpret_cast<T *>(_m); }
ZT_INLINE const T *data() const noexcept { return reinterpret_cast<const T *>(_m); }
ZT_INLINE unsigned int size() const noexcept
{ return _s; }
ZT_INLINE bool empty() const noexcept
{ return (_s == 0); }
ZT_INLINE T *data() noexcept
{ return reinterpret_cast<T *>(_m); }
ZT_INLINE const T *data() const noexcept
{ return reinterpret_cast<const T *>(_m); }
/**
* Push a value onto the back of this vector
@ -122,7 +149,7 @@ public:
ZT_INLINE void push_back(const T &v)
{
if (likely(_s < C))
new (reinterpret_cast<T *>(_m) + _s++) T(v);
new(reinterpret_cast<T *>(_m) + _s++) T(v);
else throw std::out_of_range("capacity exceeded");
}
@ -182,6 +209,14 @@ public:
_s = s;
}
/**
* Set the size of this vector without otherwise changing anything
*
* @param ns New size
*/
ZT_INLINE void unsafeSetSize(unsigned int ns)
{ _s = ns; }
/**
* This is a bounds checked auto-resizing variant of the [] operator
*
@ -213,12 +248,12 @@ public:
* @param end Ending iterator (must be greater than start)
*/
template<typename X>
ZT_INLINE void assign(X start,const X &end)
ZT_INLINE void assign(X start, const X &end)
{
const int l = std::min((int)std::distance(start,end),(int)C);
const int l = std::min((int) std::distance(start, end), (int) C);
if (l > 0) {
this->resize((unsigned int)l);
for(int i=0;i<l;++i)
this->resize((unsigned int) l);
for (int i = 0;i < l;++i)
reinterpret_cast<T *>(_m)[i] = *(start++);
} else {
this->clear();
@ -228,7 +263,7 @@ public:
ZT_INLINE bool operator==(const FCV &v) const noexcept
{
if (_s == v._s) {
for(unsigned int i=0;i<_s;++i) {
for (unsigned int i = 0;i < _s;++i) {
if (!(*(reinterpret_cast<const T *>(_m) + i) == *(reinterpret_cast<const T *>(v._m) + i)))
return false;
}
@ -236,11 +271,21 @@ public:
}
return false;
}
ZT_INLINE bool operator!=(const FCV &v) const noexcept { return (!(*this == v)); }
ZT_INLINE bool operator<(const FCV &v) const noexcept { return std::lexicographical_compare(begin(),end(),v.begin(),v.end()); }
ZT_INLINE bool operator>(const FCV &v) const noexcept { return (v < *this); }
ZT_INLINE bool operator<=(const FCV &v) const noexcept { return !(v < *this); }
ZT_INLINE bool operator>=(const FCV &v) const noexcept { return !(*this < v); }
ZT_INLINE bool operator!=(const FCV &v) const noexcept
{ return (!(*this == v)); }
ZT_INLINE bool operator<(const FCV &v) const noexcept
{ return std::lexicographical_compare(begin(), end(), v.begin(), v.end()); }
ZT_INLINE bool operator>(const FCV &v) const noexcept
{ return (v < *this); }
ZT_INLINE bool operator<=(const FCV &v) const noexcept
{ return !(v < *this); }
ZT_INLINE bool operator>=(const FCV &v) const noexcept
{ return !(*this < v); }
private:
#ifdef _MSC_VER

View file

@ -19,59 +19,43 @@
#include "Address.hpp"
#include "Utils.hpp"
#include <algorithm>
#define ZT_FINGERPRINT_STRING_BUFFER_LENGTH 96
#define ZT_FINGERPRINT_STRING_SIZE_MAX 128
namespace ZeroTier {
class Identity;
/**
* Address and full hash of an identity's public keys.
*
* This is the same size as ZT_Fingerprint and should be cast-able back and forth.
* This is checked in Tests.cpp.
*/
class Fingerprint : public TriviallyCopyable
class Fingerprint : public ZT_Fingerprint, public TriviallyCopyable
{
friend class Identity;
public:
/**
* Create an empty/nil fingerprint
*/
ZT_INLINE Fingerprint() noexcept { memoryZero(this); }
ZT_INLINE Fingerprint() noexcept
{ memoryZero(this); }
/**
* Create a Fingerprint that is a copy of the external API companion structure
*
* @param apifp API fingerprint
*/
ZT_INLINE Fingerprint(const ZT_Fingerprint &apifp) noexcept { Utils::copy<sizeof(ZT_Fingerprint)>(&m_cfp,&apifp); }
ZT_INLINE Address address() const noexcept { return Address(m_cfp.address); }
ZT_INLINE const uint8_t *hash() const noexcept { return m_cfp.hash; }
ZT_INLINE ZT_Fingerprint *apiFingerprint() noexcept { return &m_cfp; }
ZT_INLINE const ZT_Fingerprint *apiFingerprint() const noexcept { return &m_cfp; }
ZT_INLINE Fingerprint(const ZT_Fingerprint &fp) noexcept
{ Utils::copy<sizeof(ZT_Fingerprint)>(this, &fp); }
/**
* @return True if hash is not all zero (missing/unspecified)
*/
ZT_INLINE bool haveHash() const noexcept { return (!Utils::allZero(m_cfp.hash, sizeof(m_cfp.hash))); }
ZT_INLINE bool haveHash() const noexcept
{ return (!Utils::allZero(this->hash, ZT_FINGERPRINT_HASH_SIZE)); }
/**
* Get a base32-encoded representation of this fingerprint
*
* @param s Base32 string
*/
ZT_INLINE void toString(char s[ZT_FINGERPRINT_STRING_BUFFER_LENGTH]) const noexcept
ZT_INLINE void toString(char s[ZT_FINGERPRINT_STRING_SIZE_MAX]) const noexcept
{
uint8_t tmp[48 + 5];
address().copyTo(tmp);
Utils::copy<48>(tmp + 5, m_cfp.hash);
Utils::b32e(tmp,sizeof(tmp),s,ZT_FINGERPRINT_STRING_BUFFER_LENGTH);
s[ZT_FINGERPRINT_STRING_BUFFER_LENGTH-1] = 0; // sanity check, ensure always zero terminated
Address(this->address).toString(s);
if (haveHash()) {
s[ZT_ADDRESS_LENGTH_HEX] = '/';
Utils::b32e(this->hash, ZT_FINGERPRINT_HASH_SIZE, s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_FINGERPRINT_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1));
}
}
/**
@ -80,32 +64,56 @@ public:
* @param s String to decode
* @return True if string appears to be valid and of the proper length (no other checking is done)
*/
ZT_INLINE bool fromString(const char *s) noexcept
ZT_INLINE bool fromString(const char *const s) noexcept
{
uint8_t tmp[48 + 5];
if (Utils::b32d(s,tmp,sizeof(tmp)) != sizeof(tmp))
if (!s)
return false;
m_cfp.address = Address(tmp).toInt();
Utils::copy<48>(m_cfp.hash, tmp + 5);
const int l = (int) strlen(s);
if (l < ZT_ADDRESS_LENGTH_HEX)
return false;
char a[ZT_ADDRESS_LENGTH_HEX + 1];
Utils::copy<ZT_ADDRESS_LENGTH_HEX>(a, s);
a[ZT_ADDRESS_LENGTH_HEX] = 0;
this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK;
if (l > (ZT_ADDRESS_LENGTH_HEX + 1)) {
if (Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), this->hash, ZT_FINGERPRINT_HASH_SIZE) != ZT_FINGERPRINT_HASH_SIZE)
return false;
} else {
Utils::zero<ZT_FINGERPRINT_HASH_SIZE>(this->hash);
}
return true;
}
ZT_INLINE void zero() noexcept { memoryZero(this); }
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)m_cfp.address; }
ZT_INLINE void zero() noexcept
{ memoryZero(this); }
ZT_INLINE operator bool() const noexcept { return (m_cfp.address != 0); }
ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)this->address; }
ZT_INLINE bool operator==(const Fingerprint &h) const noexcept { return ((m_cfp.address == h.m_cfp.address) && (memcmp(m_cfp.hash, h.m_cfp.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); }
ZT_INLINE bool operator!=(const Fingerprint &h) const noexcept { return !(*this == h); }
ZT_INLINE bool operator<(const Fingerprint &h) const noexcept { return ((m_cfp.address < h.m_cfp.address) || ((m_cfp.address == h.m_cfp.address) && (memcmp(m_cfp.hash, h.m_cfp.hash, ZT_FINGERPRINT_HASH_SIZE) < 0))); }
ZT_INLINE bool operator>(const Fingerprint &h) const noexcept { return (h < *this); }
ZT_INLINE bool operator<=(const Fingerprint &h) const noexcept { return !(h < *this); }
ZT_INLINE bool operator>=(const Fingerprint &h) const noexcept { return !(*this < h); }
ZT_INLINE operator bool() const noexcept
{ return this->address != 0; }
private:
ZT_Fingerprint m_cfp;
ZT_INLINE bool operator==(const Fingerprint &h) const noexcept
{ return ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); }
ZT_INLINE bool operator!=(const Fingerprint &h) const noexcept
{ return !(*this == h); }
ZT_INLINE bool operator<(const Fingerprint &h) const noexcept
{ return ((this->address < h.address) || ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) < 0))); }
ZT_INLINE bool operator>(const Fingerprint &h) const noexcept
{ return (h < *this); }
ZT_INLINE bool operator<=(const Fingerprint &h) const noexcept
{ return !(h < *this); }
ZT_INLINE bool operator>=(const Fingerprint &h) const noexcept
{ return !(*this < h); }
};
static_assert(sizeof(Fingerprint) == sizeof(ZT_Fingerprint), "size mismatch");
} // namespace ZeroTier
#endif

View file

@ -157,7 +157,7 @@ bool Identity::generate(const Type t)
address.setTo(digest + 59);
} while (address.isReserved());
delete[] genmem;
m_fp.m_cfp.address = address.toInt(); // address comes from PoW hash for type 0 identities
m_fp.address = address; // address comes from PoW hash for type 0 identities
m_computeHash();
} break;
@ -179,9 +179,11 @@ bool Identity::generate(const Type t)
// If we passed PoW then check that the address is valid, otherwise loop
// back around and run the whole process again.
m_computeHash();
m_fp.m_cfp.address = Address(m_fp.m_cfp.hash).toInt();
if (!m_fp.address().isReserved())
const Address addr(m_fp.hash);
if (!addr.isReserved()) {
m_fp.address = addr;
break;
}
}
} break;
@ -195,7 +197,7 @@ bool Identity::generate(const Type t)
bool Identity::locallyValidate() const noexcept
{
try {
if ((m_fp) && ((!m_fp.address().isReserved()))) {
if ((m_fp) && ((!Address(m_fp.address).isReserved()))) {
switch (m_type) {
case C25519: {
uint8_t digest[64];
@ -204,10 +206,10 @@ bool Identity::locallyValidate() const noexcept
return false;
identityV0ProofOfWorkFrankenhash(m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, digest, genmem);
free(genmem);
return ((m_fp.address() == Address(digest + 59)) && (digest[0] < 17));
return ((Address(digest + 59) == m_fp.address) && (digest[0] < 17));
}
case P384: {
if (m_fp.address() != Address(m_fp.hash()))
if (Address(m_fp.hash) != m_fp.address)
return false;
return identityV1ProofOfWorkCriteria(m_pub, sizeof(m_pub));
}
@ -312,7 +314,7 @@ bool Identity::agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) con
char *Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{
char *p = buf;
m_fp.address().toString(p);
Address(m_fp.address).toString(p);
p += 10;
*(p++) = ':';
@ -363,8 +365,8 @@ bool Identity::fromString(const char *str)
switch (fno++) {
case 0:
m_fp.m_cfp.address = Utils::hexStrToU64(f) & ZT_ADDRESS_MASK;
if (m_fp.address().isReserved())
m_fp.address = Utils::hexStrToU64(f) & ZT_ADDRESS_MASK;
if (Address(m_fp.address).isReserved())
return false;
break;
@ -425,12 +427,12 @@ bool Identity::fromString(const char *str)
return false;
m_computeHash();
return !((m_type == P384) && (m_fp.address() != Address(m_fp.hash())));
return !((m_type == P384) && (Address(m_fp.hash) != m_fp.address));
}
int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], const bool includePrivate) const noexcept
{
m_fp.address().copyTo(data);
Address(m_fp.address).copyTo(data);
switch (m_type) {
case C25519:
@ -467,7 +469,7 @@ int Identity::unmarshal(const uint8_t *data, const int len) noexcept
if (len < (1 + ZT_ADDRESS_LENGTH))
return -1;
m_fp.m_cfp.address = Address(data).toInt();
m_fp.address = Address(data);
unsigned int privlen;
switch ((m_type = (Type) data[ZT_ADDRESS_LENGTH])) {
@ -498,7 +500,7 @@ int Identity::unmarshal(const uint8_t *data, const int len) noexcept
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(m_pub, data + ZT_ADDRESS_LENGTH + 1);
m_computeHash(); // this sets the address for P384
if (m_fp.address() != Address(m_fp.hash())) // this sanity check is possible with V1 identities
if (Address(m_fp.hash) != m_fp.address) // this sanity check is possible with V1 identities
return -1;
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
@ -538,12 +540,12 @@ void Identity::m_computeHash()
extern "C" {
ZT_Identity *ZT_Identity_new(enum ZT_Identity_Type type)
ZT_Identity *ZT_Identity_new(enum ZT_IdentityType type)
{
if ((type != ZT_IDENTITY_TYPE_C25519) && (type != ZT_IDENTITY_TYPE_P384))
return nullptr;
try {
ZeroTier::Identity *const id = new ZeroTier::Identity(); // NOLINT(hicpp-use-auto,modernize-use-auto)
ZeroTier::Identity *const id = new ZeroTier::Identity();
id->generate((ZeroTier::Identity::Type) type);
return reinterpret_cast<ZT_Identity *>(id);
} catch (...) {
@ -556,7 +558,7 @@ ZT_Identity *ZT_Identity_fromString(const char *idStr)
if (!idStr)
return nullptr;
try {
ZeroTier::Identity *const id = new ZeroTier::Identity(); // NOLINT(hicpp-use-auto,modernize-use-auto)
ZeroTier::Identity *const id = new ZeroTier::Identity();
if (!id->fromString(idStr)) {
delete id;
return nullptr;
@ -590,11 +592,11 @@ int ZT_Identity_verify(const ZT_Identity *id, const void *data, unsigned int len
return reinterpret_cast<const ZeroTier::Identity *>(id)->verify(data, len, signature, sigLen) ? 1 : 0;
}
enum ZT_Identity_Type ZT_Identity_type(const ZT_Identity *id)
enum ZT_IdentityType ZT_Identity_type(const ZT_Identity *id)
{
if (!id)
return (ZT_Identity_Type) 0;
return (enum ZT_Identity_Type) reinterpret_cast<const ZeroTier::Identity *>(id)->type();
return (ZT_IdentityType) 0;
return (enum ZT_IdentityType) reinterpret_cast<const ZeroTier::Identity *>(id)->type();
}
char *ZT_Identity_toString(const ZT_Identity *id, char *buf, int capacity, int includePrivate)
@ -616,25 +618,14 @@ uint64_t ZT_Identity_address(const ZT_Identity *id)
{
if (!id)
return 0;
return reinterpret_cast<const ZeroTier::Identity *>(id)->address().toInt();
return reinterpret_cast<const ZeroTier::Identity *>(id)->address();
}
const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id)
{
if (!id)
return nullptr;
return reinterpret_cast<const ZeroTier::Identity *>(id)->fingerprint().apiFingerprint();
}
int ZT_Identity_makeRootSpecification(ZT_Identity *id,int64_t ts,struct sockaddr_storage *addrs,unsigned int addrcnt,void *rootSpecBuf,unsigned int rootSpecBufSize)
{
if ((!id)||(!addrs)||(!addrcnt)||(!rootSpecBuf))
return -1;
ZeroTier::Vector<ZeroTier::Endpoint> endpoints;
endpoints.reserve(addrcnt);
for(unsigned int i=0;i<addrcnt;++i)
endpoints.push_back(ZeroTier::Endpoint(ZeroTier::asInetAddress(addrs[i])));
return ZeroTier::Locator::makeRootSpecification(*reinterpret_cast<const ZeroTier::Identity *>(id),ts,endpoints,rootSpecBuf,rootSpecBufSize);
return &(reinterpret_cast<const ZeroTier::Identity *>(id)->fingerprint());
}
ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)

View file

@ -53,8 +53,8 @@ public:
*/
enum Type
{
C25519 = ZT_CRYPTO_ALG_C25519, // Type 0 -- Curve25519 and Ed25519 (1.x and 2.x, default)
P384 = ZT_CRYPTO_ALG_P384 // Type 1 -- NIST P-384 with linked Curve25519/Ed25519 secondaries (2.x+)
C25519 = ZT_IDENTITY_TYPE_C25519, // Type 0 -- Curve25519 and Ed25519 (1.x and 2.x, default)
P384 = ZT_IDENTITY_TYPE_P384 // Type 1 -- NIST P-384 with linked Curve25519/Ed25519 secondaries (2.x+)
};
/**
@ -62,7 +62,7 @@ public:
*/
static const Identity NIL;
ZT_INLINE Identity() noexcept // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE Identity() noexcept
{
Utils::memoryLock(this,sizeof(Identity));
memoryZero(this);
@ -76,7 +76,7 @@ public:
*
* @param str Identity in canonical string format
*/
explicit ZT_INLINE Identity(const char *str) // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
explicit ZT_INLINE Identity(const char *str)
{
Utils::memoryLock(this,sizeof(Identity));
fromString(str);

View file

@ -13,145 +13,99 @@
#include "Locator.hpp"
#include <algorithm>
namespace ZeroTier {
bool Locator::add(const Endpoint &ep)
{
if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) {
if (std::find(m_endpoints.begin(), m_endpoints.end(), ep) == m_endpoints.end())
m_endpoints.push_back(ep);
return true;
}
return false;
}
bool Locator::sign(const int64_t ts, const Identity &id) noexcept
{
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
if (!id.hasPrivate())
return false;
m_ts = ts;
if (m_endpointCount > 0)
std::sort(m_at, m_at + m_endpointCount);
const unsigned int signLen = marshal(signData, true);
m_signatureLength = id.sign(signData, signLen, m_signature, sizeof(m_signature));
return (m_signatureLength > 0);
std::sort(m_endpoints.begin(), m_endpoints.end());
uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const unsigned int signlen = marshal(signdata, true);
const unsigned int siglen = id.sign(signdata, signlen, m_signature.data(), m_signature.capacity());
if (siglen == 0)
return false;
m_signature.unsafeSetSize(siglen);
return true;
}
bool Locator::verify(const Identity &id) const noexcept
{
if ((m_ts == 0) || (m_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS) || (m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
if (m_ts <= 0)
return false;
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const unsigned int signLen = marshal(signData, true);
return id.verify(signData, signLen, m_signature, m_signatureLength);
uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const unsigned int signlen = marshal(signdata, true);
return id.verify(signdata, signlen, m_signature.data(), m_signature.size());
}
int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool excludeSignature) const noexcept
{
if ((m_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS) || (m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return -1;
data[0] = 0xff; // version byte, currently 0xff to never be the same as byte 0 of an identity for legacy compatibility reasons
Utils::storeBigEndian<int64_t>(data + 1, m_ts);
int p = 9;
if (m_ts > 0) {
Utils::storeBigEndian(data + p, (uint16_t) m_endpointCount);
p += 2;
for (unsigned int i = 0;i < m_endpointCount;++i) {
int tmp = m_at[i].marshal(data + p);
if (tmp < 0)
return -1;
p += tmp;
}
if (!excludeSignature) {
Utils::storeBigEndian(data + p, (uint16_t) m_signatureLength);
p += 2;
Utils::copy(data + p, m_signature, m_signatureLength);
p += (int) m_signatureLength;
}
Utils::storeBigEndian(data + p, m_flags);
p += 2;
Utils::storeBigEndian<uint64_t>(data, (uint64_t) m_ts);
Utils::storeBigEndian<uint16_t>(data + 8, (uint16_t) m_endpoints.size());
int p = 10;
for (Vector<Endpoint>::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) {
int l = e->marshal(data + p);
if (l <= 0)
return -1;
p += l;
}
Utils::storeAsIsEndian<uint16_t>(data + p, 0); // length of meta-data, currently always 0
p += 2;
if (!excludeSignature) {
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signature.size());
p += 2;
Utils::copy(data + p, m_signature.data(), m_signature.size());
p += (int) m_signature.size();
}
return p;
}
int Locator::unmarshal(const uint8_t *restrict data, const int len) noexcept
int Locator::unmarshal(const uint8_t *data, const int len) noexcept
{
if (len <= (1 + 8 + 2 + 48))
if (unlikely(len < 10))
return -1;
if (data[0] != 0xff)
m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data);
unsigned int endpointCount = Utils::loadBigEndian<uint16_t>(data + 8);
if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS))
return -1;
m_ts = Utils::loadBigEndian<int64_t>(data + 1);
int p = 9;
if (m_ts > 0) {
const unsigned int ec = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
int p = 10;
m_endpoints.resize(endpointCount);
m_endpoints.shrink_to_fit();
for (unsigned int i = 0;i < endpointCount;++i) {
int l = m_endpoints[i].unmarshal(data + p, len - p);
if (l <= 0)
return -1;
m_endpointCount = ec;
for (unsigned int i = 0;i < ec;++i) {
int tmp = m_at[i].unmarshal(data + p, len - p);
if (tmp < 0)
return -1;
p += tmp;
}
if ((p + 2) > len)
return -1;
const unsigned int sl = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
if (sl > ZT_SIGNATURE_BUFFER_SIZE)
return -1;
m_signatureLength = sl;
if ((p + (int)sl) > len)
return -1;
Utils::copy(m_signature, data + p, sl);
p += (int)sl;
if ((p + 2) > len)
return -1;
m_flags = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
} else {
m_ts = 0;
p += l;
}
if (unlikely((p + 2) > len))
return -1;
p += 2 + (int) Utils::loadBigEndian<uint16_t>(data + p);
if (unlikely((p + 2) > len))
return -1;
unsigned int siglen = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
if (unlikely((siglen > ZT_SIGNATURE_BUFFER_SIZE) || ((p + (int) siglen) > len)))
return -1;
m_signature.unsafeSetSize(siglen);
Utils::copy(m_signature.data(), data + p, siglen);
p += siglen;
if (unlikely(p > len))
return -1;
return p;
}
int Locator::makeRootSpecification(const Identity &id,int64_t ts,const Vector<Endpoint> &endpoints,void *rootSpecBuf,unsigned int rootSpecBufSize)
{
if (endpoints.size() > ZT_LOCATOR_MAX_ENDPOINTS)
return -1;
if (rootSpecBufSize < (ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX + 1))
return -1;
Locator loc;
for (Vector<Endpoint>::const_iterator e(endpoints.begin());e!=endpoints.end();++e)
loc.add(*e);
if (!loc.sign(ts,id))
return -1;
uint8_t *buf = reinterpret_cast<uint8_t *>(rootSpecBuf);
int idl = id.marshal(buf,false);
if (idl <= 0)
return -1;
buf += idl;
int locl = loc.marshal(buf);
if (locl <= 0)
return -1;
return idl + locl;
}
std::pair<Identity,Locator> Locator::parseRootSpecification(const void *rootSpec,unsigned int rootSpecSize)
{
std::pair<Identity,Locator> rs;
int l = rs.first.unmarshal(reinterpret_cast<const uint8_t *>(rootSpec),(int)rootSpecSize);
if (l <= 0) {
rs.first.zero();
return rs;
}
l = rs.second.unmarshal(reinterpret_cast<const uint8_t *>(rootSpec) + l,(int)rootSpecSize - l);
if (l <= 0)
rs.first.zero();
return rs;
}
} // namespace ZeroTier

View file

@ -14,17 +14,16 @@
#ifndef ZT_LOCATOR_HPP
#define ZT_LOCATOR_HPP
#include <algorithm>
#include <vector>
#include <cstdint>
#include "Constants.hpp"
#include "Endpoint.hpp"
#include "Identity.hpp"
#include "TriviallyCopyable.hpp"
#include "SharedPtr.hpp"
#include "FCV.hpp"
#include "Containers.hpp"
#define ZT_LOCATOR_MAX_ENDPOINTS 8
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (1 + 8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE)
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_LOCATOR_MAX_ENDPOINTS * ZT_ENDPOINT_MARSHAL_SIZE_MAX) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE)
namespace ZeroTier {
@ -34,45 +33,39 @@ namespace ZeroTier {
* A locator contains long-lived endpoints for a node such as IP/port pairs,
* URLs, or other nodes, and is signed by the node it describes.
*/
class Locator : public TriviallyCopyable
class Locator
{
public:
ZT_INLINE Locator() noexcept { memoryZero(this); }
friend class SharedPtr<Locator>;
/**
* Zero the Locator data structure
*/
ZT_INLINE void clear() noexcept { memoryZero(this); }
public:
ZT_INLINE Locator() noexcept :
m_ts(0)
{}
ZT_INLINE Locator(const Locator &loc) noexcept :
m_ts(loc.m_ts),
m_endpoints(loc.m_endpoints),
m_signature(loc.m_signature),
__refCount(0)
{}
/**
* @return Timestamp (a.k.a. revision number) set by Location signer
*/
ZT_INLINE int64_t timestamp() const noexcept { return m_ts; }
ZT_INLINE int64_t timestamp() const noexcept
{ return m_ts; }
/**
* @return True if locator is signed
* @return Endpoints specified in locator
*/
ZT_INLINE bool isSigned() const noexcept { return m_signatureLength > 0; }
ZT_INLINE const Vector<Endpoint> &endpoints() const noexcept
{ return m_endpoints; }
/**
* @return Length of signature in bytes or 0 if none
* @return Signature data
*/
ZT_INLINE unsigned int signatureLength() const noexcept { return m_signatureLength; }
/**
* @return Pointer to signature bytes
*/
ZT_INLINE const uint8_t *signature() const noexcept { return m_signature; }
/**
* @return Number of endpoints in this locator
*/
ZT_INLINE unsigned int endpointCount() const noexcept { return m_endpointCount; }
/**
* @return Pointer to array of endpoints
*/
ZT_INLINE const Endpoint *endpoints() const noexcept { return m_at; }
ZT_INLINE const FCV<uint8_t, ZT_SIGNATURE_BUFFER_SIZE> &signature() const noexcept
{ return m_signature; }
/**
* Add an endpoint to this locator
@ -83,13 +76,7 @@ public:
* @param ep Endpoint to add
* @return True if endpoint was added (or already present), false if locator is full
*/
ZT_INLINE bool add(const Endpoint &ep) noexcept
{
if (m_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS)
return false;
m_at[m_endpointCount++] = ep;
return true;
}
bool add(const Endpoint &ep);
/**
* Sign this locator
@ -100,7 +87,7 @@ public:
* @param id Identity that includes private key
* @return True if signature successful
*/
bool sign(int64_t ts,const Identity &id) noexcept;
bool sign(int64_t ts, const Identity &id) noexcept;
/**
* Verify this Locator's validity and signature
@ -110,40 +97,21 @@ public:
*/
bool verify(const Identity &id) const noexcept;
explicit ZT_INLINE operator bool() const noexcept { return m_ts != 0; }
explicit ZT_INLINE operator bool() const noexcept
{ return m_ts > 0; }
static constexpr int marshalSizeMax() noexcept { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],bool excludeSignature = false) const noexcept;
int unmarshal(const uint8_t *restrict data,int len) noexcept;
static constexpr int marshalSizeMax() noexcept
{ return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
/**
* Create a signed Locator and package it with the root's identity to make a root spec
*
* @param id Identity (must have secret)
* @param ts Timestamp
* @param endpoints Endpoints
* @param rootSpecBuf Buffer to store identity and locator into
* @param rootSpecBufSize Size of buffer
* @return Bytes written to buffer or -1 on error
*/
static int makeRootSpecification(const Identity &id,int64_t ts,const Vector<Endpoint> &endpoints,void *rootSpecBuf,unsigned int rootSpecBufSize);
int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept;
/**
* Parse a root specification and decode the identity and locator
*
* @param rootSpec Root spec bytes
* @param rootSpecSize Size in bytes
* @return Identity and locator, with identity NULL if an error occurs
*/
static std::pair<Identity,Locator> parseRootSpecification(const void *rootSpec,unsigned int rootSpecSize);
int unmarshal(const uint8_t *data, int len) noexcept;
private:
int64_t m_ts;
unsigned int m_endpointCount;
unsigned int m_signatureLength;
Endpoint m_at[ZT_LOCATOR_MAX_ENDPOINTS];
uint16_t m_flags;
uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE];
Vector<Endpoint> m_endpoints;
FCV<uint8_t, ZT_SIGNATURE_BUFFER_SIZE> m_signature;
std::atomic<int> __refCount;
};
} // namespace ZeroTier

View file

@ -14,14 +14,11 @@
#ifndef ZT_MAC_HPP
#define ZT_MAC_HPP
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp"
#include "TriviallyCopyable.hpp"
#include "Containers.hpp"
namespace ZeroTier {
@ -32,10 +29,20 @@ class MAC : public TriviallyCopyable
{
public:
ZT_INLINE MAC() noexcept : m_mac(0ULL) {}
ZT_INLINE MAC(const uint8_t a,const uint8_t b,const uint8_t c,const uint8_t d,const uint8_t e,const uint8_t f) noexcept : m_mac((((uint64_t)a) << 40U) | (((uint64_t)b) << 32U) | (((uint64_t)c) << 24U) | (((uint64_t)d) << 16U) | (((uint64_t)e) << 8U) | ((uint64_t)f) ) {}
explicit ZT_INLINE MAC(const uint64_t m) noexcept : m_mac(m) {}
explicit ZT_INLINE MAC(const uint8_t b[6]) noexcept { setTo(b); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE MAC(const Address &ztaddr,const uint64_t nwid) noexcept { fromAddress(ztaddr,nwid); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE MAC(const uint8_t a,const uint8_t b,const uint8_t c,const uint8_t d,const uint8_t e,const uint8_t f) noexcept :
m_mac((((uint64_t)a) << 40U) | (((uint64_t)b) << 32U) | (((uint64_t)c) << 24U) | (((uint64_t)d) << 16U) | (((uint64_t)e) << 8U) | ((uint64_t)f) )
{}
explicit ZT_INLINE MAC(const uint64_t m) noexcept :
m_mac(m)
{}
explicit ZT_INLINE MAC(const uint8_t b[6]) noexcept
{ setTo(b); }
ZT_INLINE MAC(const Address &ztaddr,const uint64_t nwid) noexcept
{ fromAddress(ztaddr,nwid); }
/**
* @return MAC in 64-bit integer
@ -47,11 +54,6 @@ public:
*/
ZT_INLINE void zero() noexcept { m_mac = 0ULL; }
/**
* @return True if MAC is non-zero
*/
ZT_INLINE operator bool() const noexcept { return (m_mac != 0ULL); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
/**
* @param bits Raw MAC in big-endian byte order
* @param len Length, must be >= 6 or result is zero
@ -135,7 +137,7 @@ public:
* @param i Value from 0 to 5 (inclusive)
* @return Byte at said position (address interpreted in big-endian order)
*/
ZT_INLINE uint8_t operator[](unsigned int i) const noexcept { return (uint8_t)(m_mac >> (40 - (i * 8))); }
ZT_INLINE uint8_t operator[](unsigned int i) const noexcept { return (uint8_t)(m_mac >> (unsigned int)(40 - (i * 8))); }
/**
* @return 6, which is the number of bytes in a MAC, for container compliance
@ -144,6 +146,15 @@ public:
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)Utils::hash64(m_mac); }
ZT_INLINE operator bool() const noexcept { return (m_mac != 0ULL); }
ZT_INLINE operator uint64_t() const noexcept { return m_mac; }
/**
* Convert this MAC to a standard format colon-separated hex string
*
* @param buf Buffer to store string
* @return Pointer to buf
*/
ZT_INLINE char *toString(char buf[18]) const noexcept
{
buf[0] = Utils::HEXCHARS[(m_mac >> 44U) & 0xfU];
@ -166,6 +177,32 @@ public:
buf[17] = (char)0;
return buf;
}
ZT_INLINE String toString() const { char tmp[18]; return String(toString(tmp)); }
/**
* Parse a MAC address in hex format with or without : separators and ignoring non-hex characters.
*
* @param s String to parse
*/
ZT_INLINE void fromString(const char *s) noexcept
{
m_mac = 0;
if (s) {
while (*s) {
uint64_t c;
const char hc = *s++;
if ((hc >= 48)&&(hc <= 57))
c = (uint64_t)hc - 48;
else if ((hc >= 97)&&(hc <= 102))
c = (uint64_t)hc - 87;
else if ((hc >= 65)&&(hc <= 70))
c = (uint64_t)hc - 55;
else continue;
m_mac = (m_mac << 4U) | c;
}
m_mac &= 0xffffffffffffULL;
}
}
ZT_INLINE MAC &operator=(const uint64_t m) noexcept { m_mac = m; return *this; }
@ -176,6 +213,13 @@ public:
ZT_INLINE bool operator>(const MAC &m) const noexcept { return (m_mac > m.m_mac); }
ZT_INLINE bool operator>=(const MAC &m) const noexcept { return (m_mac >= m.m_mac); }
ZT_INLINE bool operator==(const uint64_t m) const noexcept { return (m_mac == m); }
ZT_INLINE bool operator!=(const uint64_t m) const noexcept { return (m_mac != m); }
ZT_INLINE bool operator<(const uint64_t m) const noexcept { return (m_mac < m); }
ZT_INLINE bool operator<=(const uint64_t m) const noexcept { return (m_mac <= m); }
ZT_INLINE bool operator>(const uint64_t m) const noexcept { return (m_mac > m); }
ZT_INLINE bool operator>=(const uint64_t m) const noexcept { return (m_mac >= m); }
private:
uint64_t m_mac;
};

View file

@ -132,7 +132,7 @@ public:
return false;
} else {
// LEGACY: support networks run by old controllers.
if (localCom.issuedTo().address() != m_com.issuedTo().address())
if (localCom.issuedTo().address != m_com.issuedTo().address)
return false;
}

View file

@ -20,8 +20,6 @@
#include "Utils.hpp"
#include "TriviallyCopyable.hpp"
#include <cstdint>
namespace ZeroTier {
/**

View file

@ -1022,7 +1022,7 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
try {
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != m_id))
return 0; // invalid config that is not for us or not for this network
if ((!Utils::allZero(nconf.issuedToFingerprintHash,ZT_FINGERPRINT_HASH_SIZE)) && (memcmp(nconf.issuedToFingerprintHash,RR->identity.fingerprint().hash(),ZT_FINGERPRINT_HASH_SIZE) != 0))
if ((!Utils::allZero(nconf.issuedToFingerprintHash,ZT_FINGERPRINT_HASH_SIZE)) && (memcmp(nconf.issuedToFingerprintHash,RR->identity.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE) != 0))
return 0; // full identity hash is present and does not match
if (m_config == nconf)

View file

@ -70,16 +70,6 @@ namespace ZeroTier {
*/
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE 0x0000020000000000ULL
/**
* Device that replicates multicasts
*/
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR 0x0000040000000000ULL
/**
* Device that is allowed to remotely debug this network and query other peers for e.g. remote trace data
*/
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_DIAGNOSTICIAN 0x0000080000000000ULL
// Fields for meta-data sent with network config requests
// Protocol version (see Packet.hpp)
@ -156,7 +146,8 @@ namespace ZeroTier {
*/
struct NetworkConfig : TriviallyCopyable
{
ZT_INLINE NetworkConfig() noexcept { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE NetworkConfig() noexcept
{ memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
/**
* Write this network config to a dictionary for transport
@ -177,22 +168,26 @@ struct NetworkConfig : TriviallyCopyable
/**
* @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
*/
ZT_INLINE bool enableBroadcast() const noexcept { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
ZT_INLINE bool enableBroadcast() const noexcept
{ return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
/**
* @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
*/
ZT_INLINE bool ndpEmulation() const noexcept { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
ZT_INLINE bool ndpEmulation() const noexcept
{ return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
/**
* @return Network type is public (no access control)
*/
ZT_INLINE bool isPublic() const noexcept { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
ZT_INLINE bool isPublic() const noexcept
{ return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
/**
* @return Network type is private (certificate access control)
*/
ZT_INLINE bool isPrivate() const noexcept { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
ZT_INLINE bool isPrivate() const noexcept
{ return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
/**
* @param fromPeer Peer attempting to bridge other Ethernet peers onto network
@ -200,16 +195,20 @@ struct NetworkConfig : TriviallyCopyable
*/
ZT_INLINE bool permitsBridging(const Address &fromPeer) const noexcept
{
for(unsigned int i=0;i<specialistCount;++i) {
if ((fromPeer.toInt() == (specialists[i] & ZT_ADDRESS_MASK))&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
for (unsigned int i = 0;i < specialistCount;++i) {
if ((fromPeer.toInt() == (specialists[i] & ZT_ADDRESS_MASK)) && ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
return true;
}
return false;
}
ZT_INLINE operator bool() const noexcept { return (networkId != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
ZT_INLINE bool operator==(const NetworkConfig &nc) const noexcept { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
ZT_INLINE bool operator!=(const NetworkConfig &nc) const noexcept { return (!(*this == nc)); }
ZT_INLINE operator bool() const noexcept
{ return (networkId != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
ZT_INLINE bool operator==(const NetworkConfig &nc) const noexcept
{ return (memcmp(this, &nc, sizeof(NetworkConfig)) == 0); }
ZT_INLINE bool operator!=(const NetworkConfig &nc) const noexcept
{ return (!(*this == nc)); }
/**
* Add a specialist or mask flags if already present
@ -221,11 +220,11 @@ struct NetworkConfig : TriviallyCopyable
* @param f Flags (OR of specialist role/type flags)
* @return True if successfully masked or added
*/
bool addSpecialist(const Address &a,uint64_t f) noexcept;
bool addSpecialist(const Address &a, uint64_t f) noexcept;
ZT_INLINE const Capability *capability(const uint32_t id) const
{
for(unsigned int i=0;i<capabilityCount;++i) {
for (unsigned int i = 0;i < capabilityCount;++i) {
if (capabilities[i].id() == id)
return &(capabilities[i]);
}
@ -234,7 +233,7 @@ struct NetworkConfig : TriviallyCopyable
ZT_INLINE const Tag *tag(const uint32_t id) const
{
for(unsigned int i=0;i<tagCount;++i) {
for (unsigned int i = 0;i < tagCount;++i) {
if (tags[i].id() == id)
return &(tags[i]);
}

View file

@ -34,13 +34,13 @@ namespace {
// Structure containing all the core objects for a ZeroTier node to reduce memory allocations.
struct _NodeObjects
{
ZT_INLINE _NodeObjects(RuntimeEnvironment *const RR,void *const tPtr) :
ZT_INLINE _NodeObjects(RuntimeEnvironment *const RR, void *const tPtr) :
t(RR),
expect(),
vl2(RR),
vl1(RR),
sa(RR),
topology(RR,tPtr)
topology(RR, tPtr)
{
RR->t = &t;
RR->expect = &expect;
@ -49,6 +49,7 @@ struct _NodeObjects
RR->sa = &sa;
RR->topology = &topology;
}
Trace t;
Expect expect;
VL2 vl2;
@ -59,12 +60,13 @@ struct _NodeObjects
struct _sortPeerPtrsByAddress
{
ZT_INLINE bool operator()(const SharedPtr<Peer> &a,const SharedPtr<Peer> &b) const { return (a->address() < b->address()); }
ZT_INLINE bool operator()(const SharedPtr<Peer> &a, const SharedPtr<Peer> &b) const
{ return (a->address() < b->address()); }
};
} // anonymous namespace
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) :
m_RR(this),
RR(&m_RR),
m_objects(nullptr),
@ -79,14 +81,16 @@ Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64
m_online(false)
{
// Load this node's identity.
uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
Vector<uint8_t> data(stateObjectGet(tPtr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp));
uint64_t idtmp[2];
idtmp[0] = 0;
idtmp[1] = 0;
Vector<uint8_t> data(stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp));
bool haveIdentity = false;
if (!data.empty()) {
data.push_back(0); // zero-terminate string
if (RR->identity.fromString((const char *)data.data())) {
RR->identity.toString(false,RR->publicIdentityStr);
RR->identity.toString(true,RR->secretIdentityStr);
if (RR->identity.fromString((const char *) data.data())) {
RR->identity.toString(false, RR->publicIdentityStr);
RR->identity.toString(true, RR->secretIdentityStr);
haveIdentity = true;
}
}
@ -94,16 +98,18 @@ Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64
// Generate a new identity if we don't have one.
if (!haveIdentity) {
RR->identity.generate(Identity::C25519);
RR->identity.toString(false,RR->publicIdentityStr);
RR->identity.toString(true,RR->secretIdentityStr);
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
stateObjectPut(tPtr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr,(unsigned int)strlen(RR->secretIdentityStr));
stateObjectPut(tPtr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
RR->identity.toString(false, RR->publicIdentityStr);
RR->identity.toString(true, RR->secretIdentityStr);
idtmp[0] = RR->identity.address();
idtmp[1] = 0;
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, RR->secretIdentityStr, (unsigned int) strlen(RR->secretIdentityStr));
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int) strlen(RR->publicIdentityStr));
} else {
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
data = stateObjectGet(tPtr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp);
if ((data.empty())||(memcmp(data.data(),RR->publicIdentityStr,strlen(RR->publicIdentityStr)) != 0))
stateObjectPut(tPtr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
idtmp[0] = RR->identity.address();
idtmp[1] = 0;
data = stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp);
if ((data.empty()) || (memcmp(data.data(), RR->publicIdentityStr, strlen(RR->publicIdentityStr)) != 0))
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int) strlen(RR->publicIdentityStr));
}
uint8_t tmph[ZT_SHA384_DIGEST_SIZE];
@ -126,7 +132,7 @@ Node::~Node()
m_networks_l.unlock();
if (m_objects)
delete (_NodeObjects *)m_objects;
delete (_NodeObjects *) m_objects;
// Let go of cached Buf objects. If other nodes happen to be running in this
// same process space new Bufs will be allocated as needed, but this is almost
@ -137,6 +143,7 @@ Node::~Node()
void Node::shutdown(void *tPtr)
{
postEvent(tPtr, ZT_EVENT_DOWN);
if (RR->topology)
RR->topology->saveAll(tPtr);
}
@ -151,7 +158,7 @@ ZT_ResultCode Node::processWirePacket(
volatile int64_t *nextBackgroundTaskDeadline)
{
m_now = now;
RR->vl1->onRemotePacket(tPtr,localSocket,(remoteAddress) ? InetAddress::NIL : *asInetAddress(remoteAddress),packetData,packetLength);
RR->vl1->onRemotePacket(tPtr, localSocket, (remoteAddress) ? InetAddress::NIL : *asInetAddress(remoteAddress), packetData, packetLength);
return ZT_RESULT_OK;
}
@ -170,7 +177,7 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
m_now = now;
SharedPtr<Network> nw(this->network(nwid));
if (nw) {
RR->vl2->onLocalEthernet(tPtr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength);
RR->vl2->onLocalEthernet(tPtr, nw, MAC(sourceMac), MAC(destMac), etherType, vlanId, frameData, frameLength);
return ZT_RESULT_OK;
} else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
@ -179,20 +186,22 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
struct _processBackgroundTasks_eachPeer
{
ZT_INLINE _processBackgroundTasks_eachPeer(const int64_t now_,Node *const parent_,void *const tPtr_) noexcept :
ZT_INLINE _processBackgroundTasks_eachPeer(const int64_t now_, Node *const parent_, void *const tPtr_) noexcept:
now(now_),
parent(parent_),
tPtr(tPtr_),
online(false),
rootsNotOnline() {}
rootsNotOnline()
{}
const int64_t now;
Node *const parent;
void *const tPtr;
bool online;
Vector< SharedPtr<Peer> > rootsNotOnline;
ZT_INLINE void operator()(const SharedPtr<Peer> &peer,const bool isRoot) noexcept
Vector<SharedPtr<Peer> > rootsNotOnline;
ZT_INLINE void operator()(const SharedPtr<Peer> &peer, const bool isRoot) noexcept
{
peer->pulse(tPtr,now,isRoot);
peer->pulse(tPtr, now, isRoot);
if (isRoot) {
if (peer->directlyConnected(now)) {
online = true;
@ -202,7 +211,8 @@ struct _processBackgroundTasks_eachPeer
}
}
};
ZT_ResultCode Node::processBackgroundTasks(void *tPtr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
{
m_now = now;
Mutex::Lock bl(m_backgroundTasksLock);
@ -212,7 +222,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr,int64_t now,volatile int64
if ((now - m_lastPeerPulse) >= ZT_PEER_PULSE_INTERVAL) {
m_lastPeerPulse = now;
try {
_processBackgroundTasks_eachPeer pf(now,this,tPtr);
_processBackgroundTasks_eachPeer pf(now, this, tPtr);
RR->topology->eachPeerWithRoot<_processBackgroundTasks_eachPeer &>(pf);
if (pf.online != m_online) {
@ -228,7 +238,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr,int64_t now,volatile int64
//for (Vector<Address>::const_iterator r(pf.rootsNotOnline.begin()); r != pf.rootsNotOnline.end(); ++r)
// RR->sw->requestWhois(tPtr,now,*r);
}
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
@ -238,8 +248,8 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr,int64_t now,volatile int64
m_lastHousekeepingRun = now;
{
RWMutex::RLock l(m_networks_l);
for(Map< uint64_t,SharedPtr<Network> >::const_iterator i(m_networks.begin());i != m_networks.end();++i)
i->second->doPeriodicTasks(tPtr,now);
for (Map<uint64_t, SharedPtr<Network> >::const_iterator i(m_networks.begin());i != m_networks.end();++i)
i->second->doPeriodicTasks(tPtr, now);
}
}
@ -251,7 +261,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr,int64_t now,volatile int64
// optimization for network controllers to know whether to accept
// or trust nodes without doing an extra cert check.
m_localControllerAuthorizations_l.lock();
for(Map<p_LocalControllerAuth,int64_t>::iterator i(m_localControllerAuthorizations.begin());i != m_localControllerAuthorizations.end();) { // NOLINT(hicpp-use-auto,modernize-use-auto)
for (Map<p_LocalControllerAuth, int64_t>::iterator i(m_localControllerAuthorizations.begin());i != m_localControllerAuthorizations.end();) { // NOLINT(hicpp-use-auto,modernize-use-auto)
if ((i->second - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3))
m_localControllerAuthorizations.erase(i++);
else ++i;
@ -260,40 +270,40 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr,int64_t now,volatile int64
RR->topology->doPeriodicTasks(tPtr, now);
RR->sa->clean(now);
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
*nextBackgroundTaskDeadline = now + ZT_TIMER_TASK_INTERVAL;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
return ZT_RESULT_OK;
}
ZT_ResultCode Node::join(uint64_t nwid,const ZT_Fingerprint *controllerFingerprint,void *uptr,void *tptr)
ZT_ResultCode Node::join(uint64_t nwid, const ZT_Fingerprint *controllerFingerprint, void *uptr, void *tptr)
{
Fingerprint fp;
if (controllerFingerprint)
Utils::copy<sizeof(ZT_Fingerprint)>(fp.apiFingerprint(),controllerFingerprint);
Utils::copy<sizeof(ZT_Fingerprint)>(fp.apiFingerprint(), controllerFingerprint);
RWMutex::Lock l(m_networks_l);
SharedPtr<Network> &nw = m_networks[nwid];
if (nw)
return ZT_RESULT_OK;
nw.set(new Network(RR,tptr,nwid,fp,uptr,nullptr));
nw.set(new Network(RR, tptr, nwid, fp, uptr, nullptr));
return ZT_RESULT_OK;
}
ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
ZT_ResultCode Node::leave(uint64_t nwid, void **uptr, void *tptr)
{
ZT_VirtualNetworkConfig ctmp;
m_networks_l.lock();
Map< uint64_t,SharedPtr<Network> >::iterator nwi(m_networks.find(nwid)); // NOLINT(hicpp-use-auto,modernize-use-auto)
Map<uint64_t, SharedPtr<Network> >::iterator nwi(m_networks.find(nwid)); // NOLINT(hicpp-use-auto,modernize-use-auto)
if (nwi == m_networks.end()) {
m_networks_l.unlock();
return ZT_RESULT_OK;
@ -306,53 +316,50 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
*uptr = *nw->userPtr();
nw->externalConfig(&ctmp);
RR->node->configureVirtualNetworkPort(tptr,nwid,uptr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
RR->node->configureVirtualNetworkPort(tptr, nwid, uptr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY, &ctmp);
nw->destroy();
nw.zero();
uint64_t tmp[2];
tmp[0] = nwid; tmp[1] = 0;
RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp);
tmp[0] = nwid;
tmp[1] = 0;
RR->node->stateObjectDelete(tptr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp);
return ZT_RESULT_OK;
}
ZT_ResultCode Node::multicastSubscribe(void *tPtr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
ZT_ResultCode Node::multicastSubscribe(void *tPtr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
{
const SharedPtr<Network> nw(this->network(nwid));
if (nw) {
nw->multicastSubscribe(tPtr,MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff)));
nw->multicastSubscribe(tPtr, MulticastGroup(MAC(multicastGroup), (uint32_t) (multicastAdi & 0xffffffff)));
return ZT_RESULT_OK;
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
{
const SharedPtr<Network> nw(this->network(nwid));
if (nw) {
nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff)));
nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup), (uint32_t) (multicastAdi & 0xffffffff)));
return ZT_RESULT_OK;
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
ZT_ResultCode Node::addRoot(void *tPtr,const void *rdef,unsigned int rdeflen,uint64_t *address)
ZT_ResultCode Node::addRoot(void *tPtr, const ZT_Identity *id, const ZT_Locator *loc)
{
if ((!rdef)||(rdeflen == 0))
if ((!id)||(!loc))
return ZT_RESULT_ERROR_BAD_PARAMETER;
std::pair<Identity,Locator> r(Locator::parseRootSpecification(rdef,rdeflen));
if (address)
*address = r.first.address().toInt();
return ((r.first)&&(RR->topology->addRoot(tPtr,r.first,r.second))) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
const SharedPtr<const Locator> locator(new Locator(*reinterpret_cast<const Locator *>(loc)));
// SECURITY: locator credential validation happens in Topology.cpp in addRoot().
return RR->topology->addRoot(tPtr, *reinterpret_cast<const Identity *>(id), locator) ? ZT_RESULT_OK : ZT_RESULT_ERROR_INVALID_CREDENTIAL;
}
ZT_ResultCode Node::removeRoot(void *tPtr,const ZT_Fingerprint *fp)
ZT_ResultCode Node::removeRoot(void *tPtr, const uint64_t address)
{
if (fp) {
RR->topology->removeRoot(tPtr,Fingerprint(*fp));
return ZT_RESULT_OK;
}
return ZT_RESULT_ERROR_BAD_PARAMETER;
RR->topology->removeRoot(tPtr, Address(address));
return ZT_RESULT_OK;
}
uint64_t Node::address() const
@ -371,31 +378,45 @@ void Node::status(ZT_NodeStatus *status) const
ZT_PeerList *Node::peers() const
{
Vector< SharedPtr<Peer> > peers;
Vector<SharedPtr<Peer> > peers;
RR->topology->getAllPeers(peers);
std::sort(peers.begin(),peers.end(),_sortPeerPtrsByAddress());
std::sort(peers.begin(), peers.end(), _sortPeerPtrsByAddress());
char *buf = (char *)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size()) + (sizeof(Identity) * peers.size()));
const unsigned int bufSize =
sizeof(ZT_PeerList) +
(sizeof(ZT_Peer) * peers.size()) +
((sizeof(ZT_Path) * ZT_MAX_PEER_NETWORK_PATHS) * peers.size()) +
(sizeof(Identity) * peers.size()) +
((sizeof(ZT_Endpoint) * ZT_LOCATOR_MAX_ENDPOINTS) * peers.size());
char *buf = (char *) malloc(bufSize);
if (!buf)
return nullptr;
ZT_PeerList *pl = (ZT_PeerList *)buf; // NOLINT(modernize-use-auto,hicpp-use-auto)
pl->peers = (ZT_Peer *)(buf + sizeof(ZT_PeerList));
Identity *identities = (Identity *)(buf + sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size())); // NOLINT(modernize-use-auto,hicpp-use-auto)
Utils::zero(buf, bufSize);
ZT_PeerList *pl = reinterpret_cast<ZT_PeerList *>(buf);
buf += sizeof(ZT_PeerList);
pl->peers = reinterpret_cast<ZT_Peer *>(buf);
buf += sizeof(ZT_Peer) * peers.size();
ZT_Path *peerPath = reinterpret_cast<ZT_Path *>(buf);
buf += (sizeof(ZT_Path) * ZT_MAX_PEER_NETWORK_PATHS) * peers.size();
Identity *identities = reinterpret_cast<Identity *>(buf);
buf += sizeof(Identity) * peers.size();
ZT_Endpoint *locatorEndpoint = reinterpret_cast<ZT_Endpoint *>(buf);
const int64_t now = m_now;
pl->peerCount = 0;
for(Vector< SharedPtr<Peer> >::iterator pi(peers.begin());pi!=peers.end();++pi) { // NOLINT(modernize-use-auto,modernize-loop-convert,hicpp-use-auto)
ZT_Peer *const p = &(pl->peers[pl->peerCount]);
for (Vector<SharedPtr<Peer> >::iterator pi(peers.begin());pi != peers.end();++pi) {
ZT_Peer *const p = pl->peers + pl->peerCount;
p->address = (*pi)->address().toInt();
identities[pl->peerCount] = (*pi)->identity(); // need to make a copy in case peer gets deleted
p->identity = &identities[pl->peerCount];
p->identity = identities + pl->peerCount;
p->fingerprint.address = p->address;
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(p->fingerprint.hash,(*pi)->identity().fingerprint().hash());
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(p->fingerprint.hash, (*pi)->identity().fingerprint().hash);
if ((*pi)->remoteVersionKnown()) {
p->versionMajor = (int)(*pi)->remoteVersionMajor();
p->versionMinor = (int)(*pi)->remoteVersionMinor();
p->versionRev = (int)(*pi)->remoteVersionRevision();
p->versionMajor = (int) (*pi)->remoteVersionMajor();
p->versionMinor = (int) (*pi)->remoteVersionMinor();
p->versionRev = (int) (*pi)->remoteVersionRevision();
} else {
p->versionMajor = -1;
p->versionMinor = -1;
@ -404,25 +425,30 @@ ZT_PeerList *Node::peers() const
p->latency = (*pi)->latency();
p->root = RR->topology->isRoot((*pi)->identity()) ? 1 : 0;
{
FCV<Endpoint,ZT_MAX_PEER_NETWORK_PATHS> bs((*pi)->bootstrap());
p->bootstrapAddressCount = 0;
for (FCV<Endpoint,ZT_MAX_PEER_NETWORK_PATHS>::const_iterator i(bs.begin());i!=bs.end();++i) // NOLINT(modernize-loop-convert)
Utils::copy<sizeof(sockaddr_storage)>(&(p->bootstrap[p->bootstrapAddressCount++]),&(*i));
p->networkCount = 0;
// TODO: enumerate network memberships
Vector<SharedPtr<Path> > paths;
(*pi)->getAllPaths(paths);
p->pathCount = (unsigned int) paths.size();
p->paths = peerPath;
for (Vector<SharedPtr<Path> >::iterator path(paths.begin());path != paths.end();++path) {
ZT_Path *const pp = peerPath++;
pp->endpoint.type = ZT_ENDPOINT_TYPE_IP_UDP; // only type supported right now
Utils::copy<sizeof(sockaddr_storage)>(&pp->endpoint.value.ss, &((*path)->address().as.ss));
pp->lastSend = (*path)->lastOut();
pp->lastReceive = (*path)->lastIn();
pp->alive = (*path)->alive(now) ? 1 : 0;
pp->preferred = (p->pathCount == 0) ? 1 : 0;
}
Vector< SharedPtr<Path> > paths;
(*pi)->getAllPaths(paths);
p->pathCount = 0;
for(Vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) { // NOLINT(modernize-use-auto,modernize-loop-convert,hicpp-use-auto)
Utils::copy<sizeof(sockaddr_storage)>(&(p->paths[p->pathCount].address),&((*path)->address()));
p->paths[p->pathCount].lastSend = (*path)->lastOut();
p->paths[p->pathCount].lastReceive = (*path)->lastIn();
// TODO
//p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address());
p->paths[p->pathCount].alive = (*path)->alive(now) ? 1 : 0;
p->paths[p->pathCount].preferred = (p->pathCount == 0) ? 1 : 0;
++p->pathCount;
const SharedPtr<const Locator> loc((*pi)->locator());
if (loc) {
p->locatorTimestamp = loc->timestamp();
p->locatorEndpointCount = (unsigned int)loc->endpoints().size();
p->locatorEndpoints = locatorEndpoint;
for(Vector<Endpoint>::const_iterator ep(loc->endpoints().begin());ep!=loc->endpoints().end();++ep)
*(locatorEndpoint++) = *ep;
}
++pl->peerCount;
@ -435,7 +461,7 @@ ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const
{
SharedPtr<Network> nw(network(nwid));
if (nw) {
ZT_VirtualNetworkConfig *const nc = (ZT_VirtualNetworkConfig *)::malloc(sizeof(ZT_VirtualNetworkConfig)); // NOLINT(modernize-use-auto,hicpp-use-auto)
ZT_VirtualNetworkConfig *const nc = (ZT_VirtualNetworkConfig *) ::malloc(sizeof(ZT_VirtualNetworkConfig));
nw->externalConfig(nc);
return nc;
}
@ -446,39 +472,33 @@ ZT_VirtualNetworkList *Node::networks() const
{
RWMutex::RLock l(m_networks_l);
char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_networks.size()));
char *const buf = (char *) ::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_networks.size()));
if (!buf)
return nullptr;
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; // NOLINT(modernize-use-auto,hicpp-use-auto)
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *) buf; // NOLINT(modernize-use-auto,hicpp-use-auto)
nl->networks = (ZT_VirtualNetworkConfig *) (buf + sizeof(ZT_VirtualNetworkList));
nl->networkCount = 0;
for(Map< uint64_t,SharedPtr<Network> >::const_iterator i(m_networks.begin());i != m_networks.end();++i) // NOLINT(modernize-use-auto,modernize-loop-convert,hicpp-use-auto)
for (Map<uint64_t, SharedPtr<Network> >::const_iterator i(m_networks.begin());i != m_networks.end();++i) // NOLINT(modernize-use-auto,modernize-loop-convert,hicpp-use-auto)
i->second->externalConfig(&(nl->networks[nl->networkCount++]));
return nl;
}
void Node::setNetworkUserPtr(uint64_t nwid,void *ptr)
void Node::setNetworkUserPtr(uint64_t nwid, void *ptr)
{
SharedPtr<Network> nw(network(nwid));
if (nw)
*(nw->userPtr()) = ptr;
}
void Node::freeQueryResult(void *qr)
{
if (qr)
::free(qr);
}
void Node::setInterfaceAddresses(const ZT_InterfaceAddress *addrs,unsigned int addrCount)
void Node::setInterfaceAddresses(const ZT_InterfaceAddress *addrs, unsigned int addrCount)
{
Mutex::Lock _l(m_localInterfaceAddresses_m);
m_localInterfaceAddresses.clear();
for(unsigned int i=0;i<addrCount;++i) {
for (unsigned int i = 0;i < addrCount;++i) {
bool dupe = false;
for(unsigned int j=0;j<i;++j) {
for (unsigned int j = 0;j < i;++j) {
if (*(reinterpret_cast<const InetAddress *>(&addrs[j].address)) == *(reinterpret_cast<const InetAddress *>(&addrs[i].address))) {
dupe = true;
break;
@ -489,7 +509,7 @@ void Node::setInterfaceAddresses(const ZT_InterfaceAddress *addrs,unsigned int a
}
}
int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len)
int Node::sendUserMessage(void *tptr, uint64_t dest, uint64_t typeId, const void *data, unsigned int len)
{
try {
if (RR->identity.address().toInt() != dest) {
@ -503,7 +523,7 @@ int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *d
*/
return 1;
}
} catch ( ... ) {}
} catch (...) {}
return 0;
}
@ -511,12 +531,12 @@ void Node::setController(void *networkControllerInstance)
{
RR->localNetworkController = reinterpret_cast<NetworkController *>(networkControllerInstance);
if (networkControllerInstance)
RR->localNetworkController->init(RR->identity,this);
RR->localNetworkController->init(RR->identity, this);
}
// Methods used only within the core ----------------------------------------------------------------------------------
Vector<uint8_t> Node::stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2])
Vector<uint8_t> Node::stateObjectGet(void *const tPtr, ZT_StateObjectType type, const uint64_t id[2])
{
Vector<uint8_t> r;
if (m_cb.stateGetFunction) {
@ -530,20 +550,20 @@ Vector<uint8_t> Node::stateObjectGet(void *const tPtr,ZT_StateObjectType type,co
id,
&data,
&freeFunc);
if ((l > 0)&&(data)&&(freeFunc)) {
r.assign(reinterpret_cast<const uint8_t *>(data),reinterpret_cast<const uint8_t *>(data) + l);
if ((l > 0) && (data) && (freeFunc)) {
r.assign(reinterpret_cast<const uint8_t *>(data), reinterpret_cast<const uint8_t *>(data) + l);
freeFunc(data);
}
}
return r;
}
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,const int64_t localSocket,const InetAddress &remoteAddress)
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr, const Identity &id, const int64_t localSocket, const InetAddress &remoteAddress)
{
{
RWMutex::RLock l(m_networks_l);
for(Map< uint64_t,SharedPtr<Network> >::iterator i(m_networks.begin());i != m_networks.end();++i) { // NOLINT(hicpp-use-auto,modernize-use-auto,modernize-loop-convert)
for (unsigned int k = 0,j = i->second->config().staticIpCount; k < j; ++k) {
for (Map<uint64_t, SharedPtr<Network> >::iterator i(m_networks.begin());i != m_networks.end();++i) { // NOLINT(hicpp-use-auto,modernize-use-auto,modernize-loop-convert)
for (unsigned int k = 0, j = i->second->config().staticIpCount;k < j;++k) {
if (i->second->config().staticIps[k].containsAddress(remoteAddress))
return false;
}
@ -556,7 +576,7 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,const i
m_uPtr,
tPtr,
id.address().toInt(),
(const ZT_Identity *)&id,
(const ZT_Identity *) &id,
localSocket,
reinterpret_cast<const struct sockaddr_storage *>(&remoteAddress)) != 0);
}
@ -564,7 +584,7 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,const i
return true;
}
bool Node::externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr)
bool Node::externalPathLookup(void *tPtr, const Identity &id, int family, InetAddress &addr)
{
if (m_cb.pathLookupFunction) {
return (m_cb.pathLookupFunction(
@ -579,7 +599,7 @@ bool Node::externalPathLookup(void *tPtr,const Identity &id,int family,InetAddre
return false;
}
bool Node::localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const
bool Node::localControllerHasAuthorized(const int64_t now, const uint64_t nwid, const Address &addr) const
{
m_localControllerAuthorizations_l.lock();
const int64_t *const at = m_localControllerAuthorizations.get(p_LocalControllerAuth(nwid, addr));
@ -591,7 +611,7 @@ bool Node::localControllerHasAuthorized(const int64_t now,const uint64_t nwid,co
// Implementation of NetworkController::Sender ------------------------------------------------------------------------
void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig)
void Node::ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig)
{
m_localControllerAuthorizations_l.lock();
m_localControllerAuthorizations[p_LocalControllerAuth(nwid, destination)] = now();
@ -601,7 +621,7 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de
SharedPtr<Network> n(network(nwid));
if (!n)
return;
n->setConfiguration((void *)0,nc,true);
n->setConfiguration((void *) 0, nc, true);
} else {
Dictionary dconf;
if (nc.toDictionary(dconf)) {
@ -647,12 +667,12 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de
}
}
void Node::ncSendRevocation(const Address &destination,const Revocation &rev)
void Node::ncSendRevocation(const Address &destination, const Revocation &rev)
{
if (destination == RR->identity.address()) {
SharedPtr<Network> n(network(rev.networkId()));
if (!n) return;
n->addCredential(nullptr,RR->identity,rev);
n->addCredential(nullptr, RR->identity, rev);
} else {
// TODO
/*
@ -668,12 +688,12 @@ void Node::ncSendRevocation(const Address &destination,const Revocation &rev)
}
}
void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode)
void Node::ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode)
{
if (destination == RR->identity.address()) {
SharedPtr<Network> n(network(nwid));
if (!n) return;
switch(errorCode) {
switch (errorCode) {
case NetworkController::NC_ERROR_OBJECT_NOT_FOUND:
case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR:
n->setNotFound();
@ -682,7 +702,8 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
n->setAccessDenied();
break;
default: break;
default:
break;
}
} else if (requestPacketId) {
// TODO
@ -727,38 +748,44 @@ void *ZT_getBuffer()
// wrapped in a SharedPtr<> to be passed into the core.
try {
return _ZT_BUFTOPTR(new ZeroTier::Buf());
} catch ( ... ) {
} catch (...) {
return nullptr; // can only happen on out of memory condition
}
}
ZT_SDK_API void ZT_freeBuffer(void *b)
void ZT_freeBuffer(void *b)
{
if (b)
delete _ZT_PTRTOBUF(b);
}
enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now)
void ZT_freeQueryResult(void *qr)
{
*node = (ZT_Node *)0;
if (qr)
free(qr);
}
enum ZT_ResultCode ZT_Node_new(ZT_Node **node, void *uptr, void *tptr, const struct ZT_Node_Callbacks *callbacks, int64_t now)
{
*node = (ZT_Node *) 0;
try {
*node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(uptr,tptr,callbacks,now));
*node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(uptr, tptr, callbacks, now));
return ZT_RESULT_OK;
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch (std::runtime_error &exc) {
return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
void ZT_Node_delete(ZT_Node *node,void *tPtr)
void ZT_Node_delete(ZT_Node *node, void *tPtr)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->shutdown(tPtr);
delete (reinterpret_cast<ZeroTier::Node *>(node));
} catch ( ... ) {}
} catch (...) {}
}
enum ZT_ResultCode ZT_Node_processWirePacket(
@ -773,11 +800,11 @@ enum ZT_ResultCode ZT_Node_processWirePacket(
volatile int64_t *nextBackgroundTaskDeadline)
{
try {
ZeroTier::SharedPtr<ZeroTier::Buf> buf((isZtBuffer) ? _ZT_PTRTOBUF(packetData) : new ZeroTier::Buf(packetData,packetLength & ZT_BUF_MEM_MASK));
return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(tptr,now,localSocket,remoteAddress,buf,packetLength,nextBackgroundTaskDeadline);
ZeroTier::SharedPtr<ZeroTier::Buf> buf((isZtBuffer) ? _ZT_PTRTOBUF(packetData) : new ZeroTier::Buf(packetData, packetLength & ZT_BUF_MEM_MASK));
return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(tptr, now, localSocket, remoteAddress, buf, packetLength, nextBackgroundTaskDeadline);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_OK; // "OK" since invalid packets are simply dropped, but the system is still up
}
}
@ -797,88 +824,88 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
volatile int64_t *nextBackgroundTaskDeadline)
{
try {
ZeroTier::SharedPtr<ZeroTier::Buf> buf((isZtBuffer) ? _ZT_PTRTOBUF(frameData) : new ZeroTier::Buf(frameData,frameLength & ZT_BUF_MEM_MASK));
return reinterpret_cast<ZeroTier::Node *>(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,buf,frameLength,nextBackgroundTaskDeadline);
ZeroTier::SharedPtr<ZeroTier::Buf> buf((isZtBuffer) ? _ZT_PTRTOBUF(frameData) : new ZeroTier::Buf(frameData, frameLength & ZT_BUF_MEM_MASK));
return reinterpret_cast<ZeroTier::Node *>(node)->processVirtualNetworkFrame(tptr, now, nwid, sourceMac, destMac, etherType, vlanId, buf, frameLength, nextBackgroundTaskDeadline);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node, void *tptr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline);
return reinterpret_cast<ZeroTier::Node *>(node)->processBackgroundTasks(tptr, now, nextBackgroundTaskDeadline);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,const ZT_Fingerprint *controllerFingerprint,void *uptr,void *tptr)
enum ZT_ResultCode ZT_Node_join(ZT_Node *node, uint64_t nwid, const ZT_Fingerprint *controllerFingerprint, void *uptr, void *tptr)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->join(nwid,controllerFingerprint,uptr,tptr);
return reinterpret_cast<ZeroTier::Node *>(node)->join(nwid, controllerFingerprint, uptr, tptr);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr)
enum ZT_ResultCode ZT_Node_leave(ZT_Node *node, uint64_t nwid, void **uptr, void *tptr)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->leave(nwid,uptr,tptr);
return reinterpret_cast<ZeroTier::Node *>(node)->leave(nwid, uptr, tptr);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node, void *tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->multicastSubscribe(tptr,nwid,multicastGroup,multicastAdi);
return reinterpret_cast<ZeroTier::Node *>(node)->multicastSubscribe(tptr, nwid, multicastGroup, multicastAdi);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->multicastUnsubscribe(nwid,multicastGroup,multicastAdi);
return reinterpret_cast<ZeroTier::Node *>(node)->multicastUnsubscribe(nwid, multicastGroup, multicastAdi);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,void *tptr,const void *rdef,unsigned int rdeflen,uint64_t *address)
enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node, void *tptr, const ZT_Identity *id, const ZT_Locator *loc)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->addRoot(tptr,rdef,rdeflen,address);
return reinterpret_cast<ZeroTier::Node *>(node)->addRoot(tptr, id, loc);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,void *tptr,const ZT_Fingerprint *fp)
enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node, void *tptr, const uint64_t address)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(tptr,fp);
return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(tptr, address);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
} catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
@ -890,31 +917,31 @@ uint64_t ZT_Node_address(ZT_Node *node)
const ZT_Identity *ZT_Node_identity(ZT_Node *node)
{
return (const ZT_Identity *)(&(reinterpret_cast<ZeroTier::Node *>(node)->identity()));
return (const ZT_Identity *) (&(reinterpret_cast<ZeroTier::Node *>(node)->identity()));
}
void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status)
void ZT_Node_status(ZT_Node *node, ZT_NodeStatus *status)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->status(status);
} catch ( ... ) {}
} catch (...) {}
}
ZT_PeerList *ZT_Node_peers(ZT_Node *node)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->peers();
} catch ( ... ) {
return (ZT_PeerList *)0;
} catch (...) {
return (ZT_PeerList *) 0;
}
}
ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid)
ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node, uint64_t nwid)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->networkConfig(nwid);
} catch ( ... ) {
return (ZT_VirtualNetworkConfig *)0;
} catch (...) {
return (ZT_VirtualNetworkConfig *) 0;
}
}
@ -922,49 +949,42 @@ ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->networks();
} catch ( ... ) {
return (ZT_VirtualNetworkList *)0;
} catch (...) {
return (ZT_VirtualNetworkList *) 0;
}
}
void ZT_Node_setNetworkUserPtr(ZT_Node *node,uint64_t nwid,void *ptr)
void ZT_Node_setNetworkUserPtr(ZT_Node *node, uint64_t nwid, void *ptr)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->setNetworkUserPtr(nwid,ptr);
} catch ( ... ) {}
reinterpret_cast<ZeroTier::Node *>(node)->setNetworkUserPtr(nwid, ptr);
} catch (...) {}
}
void ZT_Node_freeQueryResult(ZT_Node *node,void *qr)
void ZT_Node_setInterfaceAddresses(ZT_Node *node, const ZT_InterfaceAddress *addrs, unsigned int addrCount)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->freeQueryResult(qr);
} catch ( ... ) {}
reinterpret_cast<ZeroTier::Node *>(node)->setInterfaceAddresses(addrs, addrCount);
} catch (...) {}
}
void ZT_Node_setInterfaceAddresses(ZT_Node *node,const ZT_InterfaceAddress *addrs,unsigned int addrCount)
int ZT_Node_sendUserMessage(ZT_Node *node, void *tptr, uint64_t dest, uint64_t typeId, const void *data, unsigned int len)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->setInterfaceAddresses(addrs,addrCount);
} catch ( ... ) {}
}
int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->sendUserMessage(tptr,dest,typeId,data,len);
} catch ( ... ) {
return reinterpret_cast<ZeroTier::Node *>(node)->sendUserMessage(tptr, dest, typeId, data, len);
} catch (...) {
return 0;
}
}
void ZT_Node_setController(ZT_Node *node,void *networkControllerInstance)
void ZT_Node_setController(ZT_Node *node, void *networkControllerInstance)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->setController(networkControllerInstance);
} catch ( ... ) {}
} catch (...) {}
}
void ZT_version(int *major,int *minor,int *revision,int *build)
void ZT_version(int *major, int *minor, int *revision, int *build)
{
if (major)
*major = ZEROTIER_VERSION_MAJOR;

View file

@ -26,20 +26,8 @@
#include "Buf.hpp"
#include "Containers.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <map>
// Bit mask for "expecting reply" hash
#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255
#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31
namespace ZeroTier {
class Locator;
/**
* Implementation of Node object as defined in CAPI
*
@ -48,24 +36,18 @@ class Locator;
class Node : public NetworkController::Sender
{
public:
Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
virtual ~Node();
/**
* Perform any operations that should be done prior to deleting a Node
*
* This is technically optional but recommended.
*
* @param tPtr Thread pointer to pass through to callbacks
*/
void shutdown(void *tPtr);
// Get rid of alignment warnings on 32-bit Windows
#ifdef __WINDOWS__
void * operator new(size_t i) { return _mm_malloc(i,16); }
void operator delete(void* p) { _mm_free(p); }
#endif
Node(void *uPtr, void *tPtr, const struct ZT_Node_Callbacks *callbacks, int64_t now);
virtual ~Node();
void shutdown(void *tPtr);
// Public API Functions ---------------------------------------------------------------------------------------------
ZT_ResultCode processWirePacket(
@ -76,6 +58,7 @@ public:
SharedPtr<Buf> &packetData,
unsigned int packetLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processVirtualNetworkFrame(
void *tPtr,
int64_t now,
@ -87,30 +70,80 @@ public:
SharedPtr<Buf> &frameData,
unsigned int frameLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid,const ZT_Fingerprint *controllerFingerprint,void *uptr,void *tptr);
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
ZT_ResultCode multicastSubscribe(void *tPtr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode addRoot(void *tptr,const void *rdef,unsigned int rdeflen,uint64_t *address);
ZT_ResultCode removeRoot(void *tptr,const ZT_Fingerprint *fp);
ZT_ResultCode processBackgroundTasks(
void *tPtr,
int64_t now,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode join(
uint64_t nwid,
const ZT_Fingerprint *controllerFingerprint,
void *uptr,
void *tptr);
ZT_ResultCode leave(
uint64_t nwid,
void **uptr,
void *tptr);
ZT_ResultCode multicastSubscribe(
void *tPtr,
uint64_t nwid,
uint64_t multicastGroup,
unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(
uint64_t nwid,
uint64_t multicastGroup,
unsigned long multicastAdi);
ZT_ResultCode addRoot(
void *tptr,
const ZT_Identity *id,
const ZT_Locator *loc);
ZT_ResultCode removeRoot(
void *tptr,
const uint64_t address);
uint64_t address() const;
void status(ZT_NodeStatus *status) const;
void status(
ZT_NodeStatus *status) const;
ZT_PeerList *peers() const;
ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const;
ZT_VirtualNetworkConfig *networkConfig(
uint64_t nwid) const;
ZT_VirtualNetworkList *networks() const;
void setNetworkUserPtr(uint64_t nwid,void *ptr);
void freeQueryResult(void *qr);
void setInterfaceAddresses(const ZT_InterfaceAddress *addrs,unsigned int addrCount);
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
void setController(void *networkControllerInstance);
void setNetworkUserPtr(
uint64_t nwid,
void *ptr);
void setInterfaceAddresses(
const ZT_InterfaceAddress *addrs,
unsigned int addrCount);
int sendUserMessage(
void *tptr,
uint64_t dest,
uint64_t typeId,
const void *data,
unsigned int len);
void setController(
void *networkControllerInstance);
// Internal functions -----------------------------------------------------------------------------------------------
/**
* @return Most recent time value supplied to core via API
*/
ZT_INLINE int64_t now() const noexcept { return m_now; }
ZT_INLINE int64_t now() const noexcept
{ return m_now; }
/**
* Send packet to to the physical wire via callback
@ -123,7 +156,7 @@ public:
* @param ttl TTL or 0 for default/max
* @return True if send appears successful
*/
ZT_INLINE bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) noexcept
ZT_INLINE bool putPacket(void *tPtr, const int64_t localSocket, const InetAddress &addr, const void *data, unsigned int len, unsigned int ttl = 0) noexcept
{
return (m_cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node *>(this),
@ -149,7 +182,7 @@ public:
* @param data Ethernet frame data
* @param len Ethernet frame length in bytes
*/
ZT_INLINE void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) noexcept
ZT_INLINE void putFrame(void *tPtr, uint64_t nwid, void **nuptr, const MAC &source, const MAC &dest, unsigned int etherType, unsigned int vlanId, const void *data, unsigned int len) noexcept
{
m_cb.virtualNetworkFrameFunction(
reinterpret_cast<ZT_Node *>(this),
@ -194,7 +227,7 @@ public:
* @param ev Event object
* @param md Event data or NULL if none
*/
ZT_INLINE void postEvent(void *tPtr,ZT_Event ev,const void *md = nullptr) noexcept
ZT_INLINE void postEvent(void *tPtr, ZT_Event ev, const void *md = nullptr) noexcept
{
m_cb.eventCallback(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, ev, md);
}
@ -208,7 +241,7 @@ public:
* @param op Config operation or event type
* @param nc Network config info
*/
ZT_INLINE void configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) noexcept
ZT_INLINE void configureVirtualNetworkPort(void *tPtr, uint64_t nwid, void **nuptr, ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig *nc) noexcept
{
m_cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, nwid, nuptr, op, nc);
}
@ -216,7 +249,8 @@ public:
/**
* @return True if node appears online
*/
ZT_INLINE bool online() const noexcept { return m_online; }
ZT_INLINE bool online() const noexcept
{ return m_online; }
/**
* Get a state object
@ -226,7 +260,7 @@ public:
* @param id Object ID
* @return Vector containing data or empty vector if not found or empty
*/
Vector<uint8_t> stateObjectGet(void *tPtr,ZT_StateObjectType type,const uint64_t id[2]);
Vector<uint8_t> stateObjectGet(void *tPtr, ZT_StateObjectType type, const uint64_t id[2]);
/**
* Store a state object
@ -237,10 +271,10 @@ public:
* @param data Data to store
* @param len Length of data
*/
ZT_INLINE void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) noexcept
ZT_INLINE void stateObjectPut(void *const tPtr, ZT_StateObjectType type, const uint64_t id[2], const void *const data, const unsigned int len) noexcept
{
if (m_cb.statePutFunction)
m_cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, type, id, data, (int)len);
m_cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, type, id, data, (int) len);
}
/**
@ -250,7 +284,7 @@ public:
* @param type Object type to delete
* @param id Object ID
*/
ZT_INLINE void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) noexcept
ZT_INLINE void stateObjectDelete(void *const tPtr, ZT_StateObjectType type, const uint64_t id[2]) noexcept
{
if (m_cb.statePutFunction)
m_cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_uPtr, tPtr, type, id, nullptr, -1);
@ -267,7 +301,7 @@ public:
* @param remoteAddress Remote address
* @return True if path should be used
*/
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,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
@ -278,17 +312,19 @@ public:
* @param addr Buffer to store address (result paramter)
* @return True if addr was filled with something
*/
bool externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr);
bool externalPathLookup(void *tPtr, const Identity &id, int family, InetAddress &addr);
/**
* @return This node's identity
*/
ZT_INLINE const Identity &identity() const noexcept { return m_RR.identity; }
ZT_INLINE const Identity &identity() const noexcept
{ return m_RR.identity; }
/**
* @return True if aggressive NAT-traversal mechanisms like scanning of <1024 ports are enabled
*/
ZT_INLINE bool natMustDie() const noexcept { return m_natMustDie; }
ZT_INLINE bool natMustDie() const noexcept
{ return m_natMustDie; }
/**
* Check whether a local controller has authorized a member on a network
@ -303,12 +339,14 @@ public:
* @param addr Member address to check
* @return True if member has been authorized
*/
bool localControllerHasAuthorized(int64_t now,uint64_t nwid,const Address &addr) const;
bool localControllerHasAuthorized(int64_t now, uint64_t nwid, const Address &addr) const;
// Implementation of NetworkController::Sender interface
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode);
virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address &destination, const Revocation &rev);
virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode);
private:
RuntimeEnvironment m_RR;
@ -329,23 +367,33 @@ private:
// weird place to put it.
struct p_LocalControllerAuth
{
uint64_t nwid,address;
ZT_INLINE p_LocalControllerAuth(const uint64_t nwid_, const Address &address_) noexcept: nwid(nwid_), address(address_.toInt()) {}
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)(nwid + address); }
ZT_INLINE bool operator==(const p_LocalControllerAuth &a) const noexcept { return ((a.nwid == nwid) && (a.address == address)); }
ZT_INLINE bool operator!=(const p_LocalControllerAuth &a) const noexcept { return ((a.nwid != nwid) || (a.address != address)); }
ZT_INLINE bool operator<(const p_LocalControllerAuth &a) const noexcept { return ((a.nwid < nwid) || ((a.nwid == nwid) && (a.address < address))); }
uint64_t nwid, address;
ZT_INLINE p_LocalControllerAuth(const uint64_t nwid_, const Address &address_) noexcept: nwid(nwid_), address(address_.toInt())
{}
ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long) (nwid + address); }
ZT_INLINE bool operator==(const p_LocalControllerAuth &a) const noexcept
{ return ((a.nwid == nwid) && (a.address == address)); }
ZT_INLINE bool operator!=(const p_LocalControllerAuth &a) const noexcept
{ return ((a.nwid != nwid) || (a.address != address)); }
ZT_INLINE bool operator<(const p_LocalControllerAuth &a) const noexcept
{ return ((a.nwid < nwid) || ((a.nwid == nwid) && (a.address < address))); }
};
Map<p_LocalControllerAuth,int64_t> m_localControllerAuthorizations;
Map<p_LocalControllerAuth, int64_t> m_localControllerAuthorizations;
Mutex m_localControllerAuthorizations_l;
// Locally joined networks by network ID.
Map< uint64_t,SharedPtr<Network> > m_networks;
Map<uint64_t, SharedPtr<Network> > m_networks;
RWMutex m_networks_l;
// These are local interface addresses that have been configured via the API
// and can be pushed to other nodes.
Vector< ZT_InterfaceAddress > m_localInterfaceAddresses;
Vector<ZT_InterfaceAddress> m_localInterfaceAddresses;
Mutex m_localInterfaceAddresses_m;
// This is locked while running processBackgroundTasks().

View file

@ -17,7 +17,7 @@
namespace ZeroTier {
bool Path::send(const RuntimeEnvironment *const RR,void *const tPtr,const void *const data,const unsigned int len,const int64_t now) noexcept
bool Path::send(const RuntimeEnvironment *const RR, void *const tPtr, const void *const data, const unsigned int len, const int64_t now) noexcept
{
if (RR->node->putPacket(tPtr, m_localSocket, m_addr, data, len)) {
m_lastOut = now;

View file

@ -26,7 +26,7 @@ namespace ZeroTier {
class RuntimeEnvironment;
template<unsigned int MF,unsigned int MFP,unsigned int GCT,unsigned int GCS,typename P>
template<unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P>
class Defragmenter;
/**
@ -37,11 +37,12 @@ class Path
friend class SharedPtr<Path>;
// Allow defragmenter to access fragment-in-flight info stored in Path for performance reasons.
template<unsigned int MF,unsigned int MFP,unsigned int GCT,unsigned int GCS,typename P>
friend class Defragmenter;
template<unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P>
friend
class Defragmenter;
public:
ZT_INLINE Path(const int64_t l,const InetAddress &r) noexcept :
ZT_INLINE Path(const int64_t l, const InetAddress &r) noexcept:
m_localSocket(l),
m_lastIn(0),
m_lastOut(0),
@ -60,7 +61,7 @@ public:
* @param now Current time
* @return True if transport reported success
*/
bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now) noexcept;
bool send(const RuntimeEnvironment *RR, void *tPtr, const void *data, unsigned int len, int64_t now) noexcept;
/**
* Explicitly update last sent time
@ -68,7 +69,7 @@ public:
* @param now Time of send
* @param bytes Bytes sent
*/
ZT_INLINE void sent(const int64_t now,const unsigned int bytes) noexcept
ZT_INLINE void sent(const int64_t now, const unsigned int bytes) noexcept
{
m_lastOut.store(now);
m_outMeter.log(now, bytes);
@ -80,7 +81,7 @@ public:
* @param now Time of receive
* @param bytes Bytes received
*/
ZT_INLINE void received(const int64_t now,const unsigned int bytes) noexcept
ZT_INLINE void received(const int64_t now, const unsigned int bytes) noexcept
{
m_lastIn.store(now);
m_inMeter.log(now, bytes);
@ -104,34 +105,40 @@ public:
/**
* @return Latency in milliseconds or -1 if unknown
*/
ZT_INLINE int latency() const noexcept { return m_latency; }
ZT_INLINE int latency() const noexcept
{ return m_latency; }
/**
* Check path aliveness
*
* @param now Current time
*/
ZT_INLINE bool alive(const int64_t now) const noexcept { return ((now - m_lastIn.load()) < ZT_PATH_ALIVE_TIMEOUT); }
ZT_INLINE bool alive(const int64_t now) const noexcept
{ return ((now - m_lastIn.load()) < ZT_PATH_ALIVE_TIMEOUT); }
/**
* @return Physical address
*/
ZT_INLINE const InetAddress &address() const noexcept { return m_addr; }
ZT_INLINE const InetAddress &address() const noexcept
{ return m_addr; }
/**
* @return Local socket as specified by external code
*/
ZT_INLINE int64_t localSocket() const noexcept { return m_localSocket; }
ZT_INLINE int64_t localSocket() const noexcept
{ return m_localSocket; }
/**
* @return Last time we received anything
*/
ZT_INLINE int64_t lastIn() const noexcept { return m_lastIn.load(); }
ZT_INLINE int64_t lastIn() const noexcept
{ return m_lastIn.load(); }
/**
* @return Last time we sent something
*/
ZT_INLINE int64_t lastOut() const noexcept { return m_lastOut.load(); }
ZT_INLINE int64_t lastOut() const noexcept
{ return m_lastOut.load(); }
private:
const int64_t m_localSocket;

View file

@ -129,10 +129,6 @@ void Peer::received(
// Re-prioritize paths to include the new one.
m_prioritizePaths(now);
// Remember most recently learned paths for future bootstrap attempts on restart.
Endpoint pathEndpoint(path->address());
m_bootstrap[pathEndpoint.type()] = pathEndpoint;
RR->t->learnedNewPath(tPtr, 0x582fabdd, packetId, m_id, path->address(), old);
} else {
path->sent(now,hello(tPtr,path->localSocket(),path->address(),now));
@ -227,8 +223,6 @@ void Peer::pulse(void *const tPtr,const int64_t now,const bool isRoot)
{
RWMutex::Lock l(m_lock);
// Determine if we need to send a full HELLO because we are refreshing ephemeral
// keys or it's simply been too long.
bool needHello = false;
if ( (m_vProto >= 11) && ( ((now - m_ephemeralPairTimestamp) >= (ZT_SYMMETRIC_KEY_TTL / 2)) || ((m_ephemeralKeys[0])&&(m_ephemeralKeys[0]->odometer() >= (ZT_SYMMETRIC_KEY_TTL_MESSAGES / 2))) ) ) {
m_ephemeralPair.generate();
@ -237,9 +231,6 @@ void Peer::pulse(void *const tPtr,const int64_t now,const bool isRoot)
needHello = true;
}
// If we have no active paths and none queued to try, attempt any
// old paths we have cached in m_bootstrap or that external code
// supplies to the core via the optional API callback.
if (m_tryQueue.empty()&&(m_alivePathCount == 0)) {
InetAddress addr;
if (RR->node->externalPathLookup(tPtr, m_id, -1, addr)) {
@ -248,27 +239,10 @@ void Peer::pulse(void *const tPtr,const int64_t now,const bool isRoot)
sent(now,m_sendProbe(tPtr,-1,addr,nullptr,0,now));
}
}
if (!m_bootstrap.empty()) {
unsigned int tryAtIndex = (unsigned int)Utils::random() % (unsigned int)m_bootstrap.size();
for(SortedMap< Endpoint::Type,Endpoint >::const_iterator i(m_bootstrap.begin());i != m_bootstrap.end();++i) {
if (tryAtIndex > 0) {
--tryAtIndex;
} else {
if ((i->second.isInetAddr())&&(!i->second.ip().ipsEqual(addr))) {
RR->t->tryingNewPath(tPtr, 0x0a009444, m_id, i->second.ip(), InetAddress::NIL, 0, 0, Identity::NIL);
sent(now,m_sendProbe(tPtr,-1,i->second.ip(),nullptr,0,now));
break;
}
}
}
}
}
// Sort paths and forget expired ones.
m_prioritizePaths(now);
// Attempt queued endpoints if they don't overlap with paths.
if (!m_tryQueue.empty()) {
for(int k=0;k<ZT_NAT_T_MAX_QUEUED_ATTEMPTS_PER_PULSE;++k) {
// This is a global circular pointer that iterates through the list of
@ -398,7 +372,7 @@ void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddres
}
m_alivePathCount = pc;
while (pc < ZT_MAX_PEER_NETWORK_PATHS)
m_paths[pc].zero();
m_paths[pc++].zero();
}
bool Peer::directlyConnected(int64_t now)
@ -464,17 +438,14 @@ int Peer::marshal(uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept
return -1;
p += s;
s = m_locator.marshal(data + p);
if (s <= 0)
return s;
p += s;
data[p++] = (uint8_t)m_bootstrap.size();
for(std::map< Endpoint::Type,Endpoint >::const_iterator i(m_bootstrap.begin());i != m_bootstrap.end();++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
s = i->second.marshal(data + p);
if (m_locator) {
data[p++] = 1;
s = m_locator->marshal(data + p);
if (s <= 0)
return -1;
return s;
p += s;
} else {
data[p++] = 0;
}
Utils::storeBigEndian(data + p,(uint16_t)m_vProto);
@ -528,24 +499,19 @@ int Peer::unmarshal(const uint8_t *restrict data,const int len) noexcept
Utils::burn(k,sizeof(k));
}
s = m_locator.unmarshal(data + p, len - p);
if (s < 0)
return s;
p += s;
if (p >= len)
return -1;
const unsigned int bootstrapCount = data[p++];
if (bootstrapCount > ZT_MAX_PEER_NETWORK_PATHS)
return -1;
m_bootstrap.clear();
for(unsigned int i=0;i<bootstrapCount;++i) {
Endpoint tmp;
s = tmp.unmarshal(data + p,len - p);
if (data[p] == 0) {
++p;
m_locator.zero();
} else if (data[p] == 1) {
++p;
Locator *const loc = new Locator();
s = loc->unmarshal(data + p, len - p);
m_locator.set(loc);
if (s < 0)
return s;
p += s;
m_bootstrap[tmp.type()] = tmp;
} else {
return -1;
}
if ((p + 10) > len)

View file

@ -32,7 +32,7 @@
#include "SymmetricKey.hpp"
#include "Containers.hpp"
#define ZT_PEER_MARSHAL_SIZE_MAX (1 + ZT_ADDRESS_LENGTH + ZT_SYMMETRIC_KEY_SIZE + ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX + 1 + (ZT_MAX_PEER_NETWORK_PATHS * ZT_ENDPOINT_MARSHAL_SIZE_MAX) + (2*4) + 2)
#define ZT_PEER_MARSHAL_SIZE_MAX (1 + ZT_ADDRESS_LENGTH + ZT_SYMMETRIC_KEY_SIZE + ZT_IDENTITY_MARSHAL_SIZE_MAX + 1 + ZT_LOCATOR_MARSHAL_SIZE_MAX + 1 + (ZT_MAX_PEER_NETWORK_PATHS * ZT_ENDPOINT_MARSHAL_SIZE_MAX) + (2*4) + 2)
#define ZT_PEER_DEDUP_BUFFER_SIZE 1024
#define ZT_PEER_DEDUP_BUFFER_MASK 1023U
@ -47,6 +47,7 @@ class Topology;
class Peer
{
friend class SharedPtr<Peer>;
friend class Topology;
public:
@ -73,22 +74,44 @@ public:
/**
* @return This peer's ZT address (short for identity().address())
*/
ZT_INLINE Address address() const noexcept { return m_id.address(); }
ZT_INLINE Address address() const noexcept
{ return m_id.address(); }
/**
* @return This peer's identity
*/
ZT_INLINE const Identity &identity() const noexcept { return m_id; }
ZT_INLINE const Identity &identity() const noexcept
{ return m_id; }
/**
* @return Copy of current locator
* @return Current locator or NULL if no locator is known
*/
ZT_INLINE Locator locator() const noexcept
ZT_INLINE const SharedPtr<const Locator> &locator() const noexcept
{
RWMutex::RLock l(m_lock);
return m_locator;
}
/**
* Set or update peer locator
*
* This checks the locator's timestamp against the current locator and
* replace it if newer.
*
* SECURITY: note that this does NOT validate the locator's signature
* or structural validity. This MUST be done before calling this.
*
* @param loc Locator update
* @return New locator or previous if it was not replaced.
*/
ZT_INLINE SharedPtr<const Locator> setLocator(const SharedPtr<const Locator> &loc) noexcept
{
RWMutex::Lock l(m_lock);
if ((loc) && ((!m_locator) || (m_locator->timestamp() < loc->timestamp())))
m_locator = loc;
return m_locator;
}
/**
* Log receipt of an authenticated packet
*
@ -117,7 +140,7 @@ public:
* @param now Current time
* @param bytes Number of bytes written
*/
ZT_INLINE void sent(const int64_t now,const unsigned int bytes) noexcept
ZT_INLINE void sent(const int64_t now, const unsigned int bytes) noexcept
{
m_lastSend = now;
m_outMeter.log(now, bytes);
@ -129,7 +152,7 @@ public:
* @param now Current time
* @param bytes Number of bytes relayed
*/
ZT_INLINE void relayed(const int64_t now,const unsigned int bytes) noexcept
ZT_INLINE void relayed(const int64_t now, const unsigned int bytes) noexcept
{
m_relayedMeter.log(now, bytes);
}
@ -163,10 +186,10 @@ public:
* @param len Length in bytes
* @param via Path over which to send data (may or may not be an already-learned path for this peer)
*/
ZT_INLINE void send(void *tPtr,int64_t now,const void *data,unsigned int len,const SharedPtr<Path> &via) noexcept
ZT_INLINE void send(void *tPtr, int64_t now, const void *data, unsigned int len, const SharedPtr<Path> &via) noexcept
{
via->send(RR,tPtr,data,len,now);
sent(now,len);
via->send(RR, tPtr, data, len, now);
sent(now, len);
}
/**
@ -180,7 +203,7 @@ public:
* @param data Data to send
* @param len Length in bytes
*/
void send(void *tPtr,int64_t now,const void *data,unsigned int len) noexcept;
void send(void *tPtr, int64_t now, const void *data, unsigned int len) noexcept;
/**
* Send a HELLO to this peer at a specified physical address.
@ -191,7 +214,7 @@ public:
* @param now Current time
* @return Number of bytes sent
*/
unsigned int hello(void *tPtr,int64_t localSocket,const InetAddress &atAddress,int64_t now);
unsigned int hello(void *tPtr, int64_t localSocket, const InetAddress &atAddress, int64_t now);
/**
* Ping this peer if needed and/or perform other periodic tasks.
@ -200,7 +223,7 @@ public:
* @param now Current time
* @param isRoot True if this peer is a root
*/
void pulse(void *tPtr,int64_t now,bool isRoot);
void pulse(void *tPtr, int64_t now, bool isRoot);
/**
* Attempt to contact this peer at a given endpoint.
@ -210,7 +233,7 @@ public:
* @param ep Endpoint to attempt to contact
* @param bfg1024 Use BFG1024 brute force symmetric NAT busting algorithm if applicable
*/
void contact(void *tPtr,int64_t now,const Endpoint &ep,bool breakSymmetricBFG1024);
void contact(void *tPtr, int64_t now, const Endpoint &ep, bool breakSymmetricBFG1024);
/**
* Reset paths within a given IP scope and address family
@ -225,35 +248,13 @@ public:
* @param inetAddressFamily Family e.g. AF_INET
* @param now Current time
*/
void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now);
/**
* @return All currently memorized bootstrap endpoints
*/
ZT_INLINE FCV<Endpoint,ZT_MAX_PEER_NETWORK_PATHS> bootstrap() const noexcept
{
RWMutex::RLock l(m_lock);
FCV<Endpoint,ZT_MAX_PEER_NETWORK_PATHS> r;
for(SortedMap<Endpoint::Type,Endpoint>::const_iterator i(m_bootstrap.begin());i != m_bootstrap.end();++i) // NOLINT(hicpp-use-auto,modernize-use-auto,modernize-loop-convert)
r.push_back(i->second);
return r;
}
/**
* Set bootstrap endpoint
*
* @param ep Bootstrap endpoint
*/
ZT_INLINE void setBootstrap(const Endpoint &ep) noexcept
{
RWMutex::Lock l(m_lock);
m_bootstrap[ep.type()] = ep;
}
void resetWithinScope(void *tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now);
/**
* @return Time of last receive of anything, whether direct or relayed
*/
ZT_INLINE int64_t lastReceive() const noexcept { return m_lastReceive; }
ZT_INLINE int64_t lastReceive() const noexcept
{ return m_lastReceive; }
/**
* @return Average latency of all direct paths or -1 if no direct paths or unknown
@ -263,7 +264,7 @@ public:
int ltot = 0;
int lcnt = 0;
RWMutex::RLock l(m_lock);
for(unsigned int i=0;i < m_alivePathCount;++i) {
for (unsigned int i = 0;i < m_alivePathCount;++i) {
int lat = m_paths[i]->latency();
if (lat > 0) {
ltot += lat;
@ -347,19 +348,28 @@ public:
* @param vmin Minor version
* @param vrev Revision
*/
ZT_INLINE void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev) noexcept
ZT_INLINE void setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev) noexcept
{
m_vProto = (uint16_t)vproto;
m_vMajor = (uint16_t)vmaj;
m_vMinor = (uint16_t)vmin;
m_vRevision = (uint16_t)vrev;
m_vProto = (uint16_t) vproto;
m_vMajor = (uint16_t) vmaj;
m_vMinor = (uint16_t) vmin;
m_vRevision = (uint16_t) vrev;
}
ZT_INLINE unsigned int remoteVersionProtocol() const noexcept { return m_vProto; }
ZT_INLINE unsigned int remoteVersionMajor() const noexcept { return m_vMajor; }
ZT_INLINE unsigned int remoteVersionMinor() const noexcept { return m_vMinor; }
ZT_INLINE unsigned int remoteVersionRevision() const noexcept { return m_vRevision; }
ZT_INLINE bool remoteVersionKnown() const noexcept { return ((m_vMajor > 0) || (m_vMinor > 0) || (m_vRevision > 0)); }
ZT_INLINE unsigned int remoteVersionProtocol() const noexcept
{ return m_vProto; }
ZT_INLINE unsigned int remoteVersionMajor() const noexcept
{ return m_vMajor; }
ZT_INLINE unsigned int remoteVersionMinor() const noexcept
{ return m_vMinor; }
ZT_INLINE unsigned int remoteVersionRevision() const noexcept
{ return m_vRevision; }
ZT_INLINE bool remoteVersionKnown() const noexcept
{ return ((m_vMajor > 0) || (m_vMinor > 0) || (m_vRevision > 0)); }
/**
* @return True if there is at least one alive direct path
@ -380,9 +390,12 @@ public:
// NOTE: peer marshal/unmarshal only saves/restores the identity, locator, most
// recent bootstrap address, and version information.
static constexpr int marshalSizeMax() noexcept { return ZT_PEER_MARSHAL_SIZE_MAX; }
static constexpr int marshalSizeMax() noexcept
{ return ZT_PEER_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept;
int unmarshal(const uint8_t *restrict data,int len) noexcept;
int unmarshal(const uint8_t *restrict data, int len) noexcept;
/**
* Rate limit gate for inbound WHOIS requests
@ -413,7 +426,7 @@ public:
*/
ZT_INLINE bool rateGateProbeRequest(const int64_t now) noexcept
{
if((now - m_lastProbeReceived) > ZT_PEER_PROBE_RESPONSE_RATE_LIMIT) {
if ((now - m_lastProbeReceived) > ZT_PEER_PROBE_RESPONSE_RATE_LIMIT) {
m_lastProbeReceived = now;
return true;
}
@ -432,12 +445,14 @@ public:
ZT_INLINE bool deduplicateIncomingPacket(const uint64_t packetId) noexcept
{
// TODO: should take instance ID into account too, but this isn't fully wired.
return m_dedup[Utils::hash32((uint32_t)packetId) & ZT_PEER_DEDUP_BUFFER_MASK].exchange(packetId) == packetId;
return m_dedup[Utils::hash32((uint32_t) packetId) & ZT_PEER_DEDUP_BUFFER_MASK].exchange(packetId) == packetId;
}
private:
void m_prioritizePaths(int64_t now);
unsigned int m_sendProbe(void *tPtr,int64_t localSocket,const InetAddress &atAddress,const uint16_t *ports,unsigned int numPorts,int64_t now);
unsigned int m_sendProbe(void *tPtr, int64_t localSocket, const InetAddress &atAddress, const uint16_t *ports, unsigned int numPorts, int64_t now);
void m_deriveSecondaryIdentityKeys() noexcept;
ZT_INLINE SharedPtr<SymmetricKey> m_key() noexcept
@ -468,7 +483,7 @@ private:
SharedPtr<SymmetricKey> m_ephemeralKeys[2];
Identity m_id;
Locator m_locator;
SharedPtr<const Locator> m_locator;
// the last time something was sent or received from this peer (direct or indirect).
std::atomic<int64_t> m_lastReceive;
@ -500,24 +515,26 @@ private:
// Direct paths sorted in descending order of preference.
SharedPtr<Path> m_paths[ZT_MAX_PEER_NETWORK_PATHS];
// For SharedPtr<>
std::atomic<int> __refCount;
// Number of paths current alive (number of non-NULL entries in _paths).
unsigned int m_alivePathCount;
// Remembered addresses by endpoint type (std::map is smaller for only a few keys).
SortedMap<Endpoint::Type,Endpoint> m_bootstrap;
// For SharedPtr<>
std::atomic<int> __refCount;
// Addresses recieved via PUSH_DIRECT_PATHS etc. that we are scheduled to try.
struct p_TryQueueItem
{
ZT_INLINE p_TryQueueItem() : target(), ts(0), breakSymmetricBFG1024(false) {}
ZT_INLINE p_TryQueueItem(const int64_t now, const Endpoint &t, const bool bfg) : target(t), ts(now), breakSymmetricBFG1024(bfg) {}
ZT_INLINE p_TryQueueItem() : target(), ts(0), breakSymmetricBFG1024(false)
{}
ZT_INLINE p_TryQueueItem(const int64_t now, const Endpoint &t, const bool bfg) : target(t), ts(now), breakSymmetricBFG1024(bfg)
{}
Endpoint target;
int64_t ts;
bool breakSymmetricBFG1024;
};
List<p_TryQueueItem> m_tryQueue;
List<p_TryQueueItem>::iterator m_tryQueuePtr; // loops over _tryQueue like a circular buffer

View file

@ -40,9 +40,11 @@ class Revocation : public Credential
friend class Credential;
public:
static constexpr ZT_CredentialType credentialType() noexcept { return ZT_CREDENTIAL_TYPE_REVOCATION; }
static constexpr ZT_CredentialType credentialType() noexcept
{ return ZT_CREDENTIAL_TYPE_REVOCATION; }
ZT_INLINE Revocation() noexcept { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE Revocation() noexcept
{ memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
/**
* @param i ID (arbitrary for revocations, currently random)
@ -53,7 +55,7 @@ public:
* @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked
*/
ZT_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) noexcept : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_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) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
m_id(i),
m_credentialId(cid),
m_networkId(nwid),
@ -66,16 +68,35 @@ public:
{
}
ZT_INLINE uint32_t id() const noexcept { return m_id; }
ZT_INLINE uint32_t credentialId() const noexcept { return m_credentialId; }
ZT_INLINE uint64_t networkId() const noexcept { return m_networkId; }
ZT_INLINE int64_t threshold() const noexcept { return m_threshold; }
ZT_INLINE const Address &target() const noexcept { return m_target; }
ZT_INLINE const Address &signer() const noexcept { return m_signedBy; }
ZT_INLINE ZT_CredentialType typeBeingRevoked() const noexcept { return m_type; }
ZT_INLINE const uint8_t *signature() const noexcept { return m_signature; }
ZT_INLINE unsigned int signatureLength() const noexcept { return m_signatureLength; }
ZT_INLINE bool fastPropagate() const noexcept { return ((m_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
ZT_INLINE uint32_t id() const noexcept
{ return m_id; }
ZT_INLINE uint32_t credentialId() const noexcept
{ return m_credentialId; }
ZT_INLINE uint64_t networkId() const noexcept
{ return m_networkId; }
ZT_INLINE int64_t threshold() const noexcept
{ return m_threshold; }
ZT_INLINE const Address &target() const noexcept
{ return m_target; }
ZT_INLINE const Address &signer() const noexcept
{ return m_signedBy; }
ZT_INLINE ZT_CredentialType typeBeingRevoked() const noexcept
{ return m_type; }
ZT_INLINE const uint8_t *signature() const noexcept
{ return m_signature; }
ZT_INLINE unsigned int signatureLength() const noexcept
{ return m_signatureLength; }
ZT_INLINE bool fastPropagate() const noexcept
{ return ((m_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
/**
* @param signer Signing identity, must have private key
@ -89,11 +110,15 @@ public:
* @param RR Runtime environment to provide for peer lookup, etc.
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
ZT_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const noexcept { return _verify(RR,tPtr,*this); }
ZT_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR, void *tPtr) const noexcept
{ return _verify(RR, tPtr, *this); }
static constexpr int marshalSizeMax() noexcept { return ZT_REVOCATION_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],bool forSign = false) const noexcept;
int unmarshal(const uint8_t *restrict data,int len) noexcept;
static constexpr int marshalSizeMax() noexcept
{ return ZT_REVOCATION_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept;
int unmarshal(const uint8_t *restrict data, int len) noexcept;
private:
uint32_t m_id;

View file

@ -251,19 +251,24 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const u
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
{
uint8_t kbkdfMsg[13];
uint8_t kbuf[48];
Utils::storeBigEndian<uint32_t>(kbkdfMsg,(uint32_t)iter);
kbkdfMsg[4] = (uint8_t)'Z';
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
kbkdfMsg[6] = (uint8_t)label;
kbkdfMsg[7] = 0;
kbkdfMsg[8] = (uint8_t)context;
// Output key length: 384 bits (as 32-bit big-endian value)
kbkdfMsg[9] = 0;
kbkdfMsg[10] = 0;
kbkdfMsg[11] = 1;
kbkdfMsg[12] = 0; // key length: 256 bits as big-endian 32-bit value
HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),kbuf);
Utils::copy<ZT_SYMMETRIC_KEY_SIZE>(out,kbuf);
kbkdfMsg[11] = 0x01;
kbkdfMsg[12] = 0x80;
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out);
}
} // namespace ZeroTier

View file

@ -23,6 +23,7 @@
namespace ZeroTier {
class Identity;
class RuntimeEnvironment;
/**
@ -45,7 +46,7 @@ public:
* @param trusted True if this peer is trusted as an authority to inform us of external address changes
* @param now Current time
*/
void iam(void *tPtr,const Identity &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
@ -60,7 +61,7 @@ public:
* @param now Current time
* @return Map of count to IP/port representing how many endpoints reported each address
*/
MultiMap<unsigned int,InetAddress> externalAddresses(int64_t now) const;
MultiMap<unsigned int, InetAddress> externalAddresses(int64_t now) const;
private:
struct p_PhySurfaceKey
@ -70,13 +71,21 @@ private:
InetAddress reporterPhysicalAddress;
InetAddress::IpScope scope;
ZT_INLINE p_PhySurfaceKey() noexcept {}
ZT_INLINE p_PhySurfaceKey(const Address &r, const int64_t rol, const InetAddress &ra, InetAddress::IpScope s) noexcept : reporter(r), receivedOnLocalSocket(rol), reporterPhysicalAddress(ra), scope(s) {}
ZT_INLINE p_PhySurfaceKey() noexcept
{}
ZT_INLINE unsigned long hashCode() const noexcept { return ((unsigned long)reporter.toInt() + (unsigned long)receivedOnLocalSocket + (unsigned long)scope); }
ZT_INLINE p_PhySurfaceKey(const Address &r, const int64_t rol, const InetAddress &ra, InetAddress::IpScope s) noexcept: reporter(r), receivedOnLocalSocket(rol), reporterPhysicalAddress(ra), scope(s)
{}
ZT_INLINE unsigned long hashCode() const noexcept
{ return ((unsigned long) reporter.toInt() + (unsigned long) receivedOnLocalSocket + (unsigned long) scope); }
ZT_INLINE bool operator==(const p_PhySurfaceKey &k) const noexcept
{ return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); }
ZT_INLINE bool operator!=(const p_PhySurfaceKey &k) const noexcept
{ return (!(*this == k)); }
ZT_INLINE bool operator==(const p_PhySurfaceKey &k) const noexcept { return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); }
ZT_INLINE bool operator!=(const p_PhySurfaceKey &k) const noexcept { return (!(*this == k)); }
ZT_INLINE bool operator<(const p_PhySurfaceKey &k) const noexcept
{
if (reporter < k.reporter) {
@ -102,12 +111,15 @@ private:
uint64_t ts;
bool trusted;
ZT_INLINE p_PhySurfaceEntry() noexcept : mySurface(), ts(0), trusted(false) {}
ZT_INLINE p_PhySurfaceEntry(const InetAddress &a, const uint64_t t) noexcept : mySurface(a), ts(t), trusted(false) {}
ZT_INLINE p_PhySurfaceEntry() noexcept: mySurface(), ts(0), trusted(false)
{}
ZT_INLINE p_PhySurfaceEntry(const InetAddress &a, const uint64_t t) noexcept: mySurface(a), ts(t), trusted(false)
{}
};
const RuntimeEnvironment *RR;
Map< p_PhySurfaceKey,p_PhySurfaceEntry > m_phy;
Map<p_PhySurfaceKey, p_PhySurfaceEntry> m_phy;
Mutex m_phy_l;
};

View file

@ -13,6 +13,7 @@
#include "Tests.h"
//#define ZT_ENABLE_TESTS
#ifdef ZT_ENABLE_TESTS
#include "Constants.hpp"
@ -40,12 +41,6 @@
#include "Fingerprint.hpp"
#include "Containers.hpp"
#include <cstdint>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <set>
#ifdef __UNIX_LIKE__
#include <unistd.h>
#include <sys/time.h>

View file

@ -31,14 +31,16 @@ Topology::Topology(const RuntimeEnvironment *renv, void *tPtr) :
if ((l > 0)&&(id)) {
if ((drem -= l) <= 0)
break;
Locator loc;
l = loc.unmarshal(dptr, drem);
if ((l > 0)&&(loc)) {
m_roots[id] = loc;
Locator *const loc = new Locator();
l = loc->unmarshal(dptr, drem);
if (l > 0) {
m_roots[id].set(loc);
dptr += l;
ZT_SPEW("loaded root %s", id.address().toString().c_str());
if ((drem -= l) <= 0)
break;
} else {
delete loc;
}
}
}
@ -71,9 +73,9 @@ struct p_RootSortComparisonOperator
}
};
bool Topology::addRoot(void *const tPtr, const Identity &id, const Locator &loc)
bool Topology::addRoot(void *const tPtr, const Identity &id, const SharedPtr<const Locator> &loc)
{
if ((id == RR->identity) || (!id) || (!loc) || (!loc.verify(id)) || (!id.locallyValidate()))
if ((id == RR->identity) || (!id) || (!loc) || (!loc->verify(id)) || (!id.locallyValidate()))
return false;
RWMutex::Lock l1(m_peers_l);
m_roots[id] = loc;
@ -82,20 +84,17 @@ bool Topology::addRoot(void *const tPtr, const Identity &id, const Locator &loc)
return true;
}
bool Topology::removeRoot(void *const tPtr, const Fingerprint &fp)
bool Topology::removeRoot(void *const tPtr, Address address)
{
const bool hashIsZero = !fp.haveHash();
RWMutex::Lock l1(m_peers_l);
for(Vector< SharedPtr<Peer> >::const_iterator r(m_rootPeers.begin());r!=m_rootPeers.end();++r) {
if ((*r)->address() == fp.address()) {
if ((hashIsZero)||(fp == (*r)->identity().fingerprint())) {
Map<Identity,Locator>::iterator rr(m_roots.find((*r)->identity()));
if (rr != m_roots.end()) {
m_roots.erase(rr);
m_updateRootPeers(tPtr);
m_writeRootList(tPtr);
return true;
}
if ((*r)->address() == address) {
Map< Identity,SharedPtr<const Locator> >::iterator rr(m_roots.find((*r)->identity()));
if (rr != m_roots.end()) {
m_roots.erase(rr);
m_updateRootPeers(tPtr);
m_writeRootList(tPtr);
return true;
}
}
}
@ -174,11 +173,11 @@ void Topology::m_writeRootList(void *tPtr)
uint8_t *const roots = (uint8_t *)malloc((ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX + 2) * m_roots.size());
if (roots) { // sanity check
int p = 0;
for (Map<Identity,Locator>::const_iterator r(m_roots.begin());r!=m_roots.end();++r) {
for (Map< Identity,SharedPtr<const Locator> >::const_iterator r(m_roots.begin());r!=m_roots.end();++r) {
int pp = r->first.marshal(roots + p, false);
if (pp > 0) {
p += pp;
pp = r->second.marshal(roots + p);
pp = r->second->marshal(roots + p);
if (pp > 0)
p += pp;
}
@ -195,16 +194,23 @@ void Topology::m_updateRootPeers(void *tPtr)
{
// assumes m_peers_l is locked for write
Vector< SharedPtr<Peer> > rp;
for (Map<Identity,Locator>::iterator r(m_roots.begin());r!=m_roots.end();++r) {
Map< Address,SharedPtr<Peer> >::iterator p(m_peers.find(r->first.address()));
if ((p == m_peers.end())||(p->second->identity() != r->first)) {
SharedPtr<Peer> np(new Peer(RR));
np->init(r->first);
m_peers[r->first.address()] = np;
rp.push_back(np);
} else {
rp.push_back(p->second);
for (Map< Identity,SharedPtr<const Locator> >::iterator r(m_roots.begin());r!=m_roots.end();++r) {
Map< Address,SharedPtr<Peer> >::iterator pp(m_peers.find(r->first.address()));
SharedPtr<Peer> p;
if (pp != m_peers.end())
p = pp->second;
if (!p)
m_loadCached(tPtr, r->first.address(), p);
if ((!p) || (p->identity() != r->first)) {
p.set(new Peer(RR));
p->init(r->first);
m_peers[r->first.address()] = p;
}
p->setLocator(r->second);
rp.push_back(p);
}
m_rootPeers.swap(rp);
std::sort(m_rootPeers.begin(), m_rootPeers.end(), p_RootSortComparisonOperator());

View file

@ -193,16 +193,16 @@ public:
* @param loc Root locator
* @return True if identity and locator are valid and root was added / updated
*/
bool addRoot(void *tPtr,const Identity &id,const Locator &loc);
bool addRoot(void *tPtr,const Identity &id,const SharedPtr<const Locator> &loc);
/**
* Remove a root server's identity from the root server set
*
* @param tPtr Thread pointer
* @param fp Root identity
* @param address Root address
* @return True if root found and removed, false if not found
*/
bool removeRoot(void *tPtr,const Fingerprint &fp);
bool removeRoot(void *tPtr, Address address);
/**
* Sort roots in ascending order of apparent latency
@ -250,7 +250,7 @@ private:
RWMutex m_peers_l; // locks m_peers, m_roots, and m_rootPeers
Map< uint64_t,SharedPtr<Path> > m_paths;
Map< Address,SharedPtr<Peer> > m_peers;
Map< Identity,Locator > m_roots;
Map< Identity,SharedPtr<const Locator> > m_roots;
Vector< SharedPtr<Peer> > m_rootPeers;
};