mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 21:13:44 +02:00
Simplification of addRoot/removeRoot, and some code reformatting and other cleanup across multiple files.
This commit is contained in:
parent
caad356b93
commit
b9bf6d1242
40 changed files with 1680 additions and 1270 deletions
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
}
|
|
@ -104,7 +104,6 @@ func Identity(args []string) {
|
|||
|
||||
case "makeroot":
|
||||
if len(args) >= 2 {
|
||||
//id := readIdentity(args[1])
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
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"))
|
||||
}
|
||||
data, _ = ioutil.ReadFile(userHome + "/Library/Application Support/ZeroTier/One/authtoken.secret")
|
||||
if len(data) > 0 {
|
||||
return string(data)
|
||||
p = append(p,path.Join(userHome,".zerotierauth"))
|
||||
p = append(p,path.Join(userHome,".zeroTierOneAuthToken"))
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
// 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)
|
||||
|
||||
|
|
93
go/pkg/zerotier/endpoint.go
Normal file
93
go/pkg/zerotier/endpoint.go
Normal 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
|
||||
}
|
|
@ -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"`
|
||||
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
|
||||
}
|
||||
var fp Fingerprint
|
||||
fp.Address, _ = NewAddressFromBytes(fpb[0:5])
|
||||
copy(fp.Hash[:],fpb[5:])
|
||||
return &fp, nil
|
||||
if len(h) != 48 {
|
||||
return nil, ErrInvalidParameter
|
||||
}
|
||||
return &Fingerprint{Address: a, Hash: h}, 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 {
|
||||
|
|
|
@ -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++ {
|
||||
|
|
|
@ -21,6 +21,7 @@ type Peer struct {
|
|||
Version [3]int `json:"version"`
|
||||
Latency int `json:"latency"`
|
||||
Root bool `json:"root"`
|
||||
Bootstrap *InetAddress `json:"bootstrap,omitempty"`
|
||||
Paths []Path `json:"paths,omitempty"`
|
||||
LocatorTimestamp int64 `json:"locatorTimestamp"`
|
||||
LocatorEndpoints []Endpoint `json:"locatorEndpoints,omitempty"`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@ set(core_headers
|
|||
Defragmenter.hpp
|
||||
Dictionary.hpp
|
||||
ECC384.hpp
|
||||
EphemeralKey.hpp
|
||||
Expect.hpp
|
||||
FCV.hpp
|
||||
Fingerprint.hpp
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ð_,const Type et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept
|
||||
ZT_INLINE Endpoint(const MAC ð_, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept
|
||||
{
|
||||
if (eth_) {
|
||||
Utils::copy<sizeof(MAC)>(m_value,ð_);
|
||||
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 ð() 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
|
||||
|
|
105
node/FCV.hpp
105
node/FCV.hpp
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,10 +179,12 @@ 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;
|
||||
|
||||
default:
|
||||
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
202
node/Locator.cpp
202
node/Locator.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int Locator::unmarshal(const uint8_t *restrict data, const int len) noexcept
|
||||
{
|
||||
if (len <= (1 + 8 + 2 + 48))
|
||||
return -1;
|
||||
|
||||
if (data[0] != 0xff)
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
rs.first.zero();
|
||||
return rs;
|
||||
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 *data, const int len) noexcept
|
||||
{
|
||||
if (unlikely(len < 10))
|
||||
return -1;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
104
node/Locator.hpp
104
node/Locator.hpp
|
@ -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
|
||||
|
|
72
node/MAC.hpp
72
node/MAC.hpp
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "Utils.hpp"
|
||||
#include "TriviallyCopyable.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
390
node/Node.cpp
390
node/Node.cpp
|
@ -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));
|
||||
RR->topology->removeRoot(tPtr, Address(address));
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
return ZT_RESULT_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
178
node/Node.hpp
178
node/Node.hpp
|
@ -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().
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (m_locator) {
|
||||
data[p++] = 1;
|
||||
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 (s <= 0)
|
||||
return -1;
|
||||
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 (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;
|
||||
|
||||
if (p >= len)
|
||||
} else {
|
||||
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 (s < 0)
|
||||
return s;
|
||||
p += s;
|
||||
m_bootstrap[tmp.type()] = tmp;
|
||||
}
|
||||
|
||||
if ((p + 10) > len)
|
||||
|
|
143
node/Peer.hpp
143
node/Peer.hpp
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,14 +84,12 @@ 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 ((*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);
|
||||
|
@ -98,7 +98,6 @@ bool Topology::removeRoot(void *const tPtr, const Fingerprint &fp)
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue