mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 13:03:45 +02:00
A bunch of tweaks around CLI parameters and string formats of things.
This commit is contained in:
parent
8e29acd664
commit
5dac2e82a7
16 changed files with 215 additions and 211 deletions
|
@ -35,55 +35,58 @@ Commands:
|
||||||
help Show this help
|
help Show this help
|
||||||
version Print version
|
version Print version
|
||||||
service Start as service
|
service Start as service
|
||||||
status Show node status, identity, and config
|
status Show node status and configuration
|
||||||
peers List all VL1 peers
|
|
||||||
join <network> [fingerprint] Join a virtual network
|
join <network> [fingerprint] Join a virtual network
|
||||||
leave <network> Leave a virtual network
|
leave <network> Leave a virtual network
|
||||||
networks List VL2 virtual networks
|
networks List VL2 virtual networks
|
||||||
network <network> Show verbose network info
|
network <network> [command] [option] - Network management commands
|
||||||
set <network> [option] [value] Get or set a network config option
|
show Show network details (default)
|
||||||
|
set [option] [value] - Get or set network options
|
||||||
manageips <boolean> Is IP management allowed?
|
manageips <boolean> Is IP management allowed?
|
||||||
manageroutes <boolean> Is route management allowed?
|
manageroutes <boolean> Is route management allowed?
|
||||||
globalips <boolean> Allow assignment of global IPs?
|
globalips <boolean> Allow assignment of global IPs?
|
||||||
globalroutes <boolean> Can global IP space routes be set?
|
globalroutes <boolean> Can global IP space routes be set?
|
||||||
defaultroute <boolean> Can default route be overridden?
|
defaultroute <boolean> Can default route be overridden?
|
||||||
set [option] [value] Get or set a service config option
|
peers List VL1 peers
|
||||||
|
peer <address> [command] [option] - Peer management commands
|
||||||
|
show Show peer details (default)
|
||||||
|
try <endpoint> [...] Try peer at explicit endpoint
|
||||||
|
roots List root peers
|
||||||
|
root [command] - Root management commands
|
||||||
|
add <identity> [endpoint] Designate a peer as a root
|
||||||
|
remove <address> Un-designate a peer as a root
|
||||||
|
set [option] [value] - Get or set a core config option
|
||||||
port <port> Primary P2P port
|
port <port> Primary P2P port
|
||||||
secondaryport <port/0> Secondary P2P port (0 to disable)
|
secondaryport <port/0> Secondary P2P port (0 to disable)
|
||||||
blacklist cidr <IP/bits> <boolean> Toggle physical path blacklisting
|
blacklist cidr <IP/bits> <boolean> Toggle physical path blacklisting
|
||||||
blacklist if <prefix> <boolean> Toggle interface prefix blacklisting
|
blacklist if <prefix> <boolean> Toggle interface prefix blacklisting
|
||||||
portmap <boolean> Toggle use of uPnP or NAT-PMP
|
portmap <boolean> Toggle use of uPnP or NAT-PMP
|
||||||
controller <command> [option] Local controller management commands
|
controller <command> [option] - Local controller management commands
|
||||||
networks List networks run by local controller
|
networks List networks run by local controller
|
||||||
new Create a new network
|
new Create a new network
|
||||||
set <network> [setting] [value] Show or modify network settings
|
set <network> [setting] [value] Show or modify network settings
|
||||||
members <network> List members of a network
|
members <network> List members of a network
|
||||||
member <network> [setting] [value] Show or modify member level settings
|
member <network> [setting] [value] Show or modify member level settings
|
||||||
auth <address|fingerprint> Authorize a peer
|
auth <address> Authorize a peer
|
||||||
deauth <address|fingerprint> Deauthorize a peer
|
deauth <address> Deauthorize a peer
|
||||||
identity <command> [args] Identity management commands
|
identity <command> [args] - Identity management commands
|
||||||
new [c25519|p384] Create identity pair (default: c25519)
|
new [c25519|p384] Create identity (default: c25519)
|
||||||
getpublic <identity> Extract only public part of identity
|
getpublic <identity> Extract only public part of identity
|
||||||
|
fingerprint <identity> Get an identity's fingerprint
|
||||||
validate <identity> Locally validate an identity
|
validate <identity> Locally validate an identity
|
||||||
sign <identity> <file> Sign a file with an identity's key
|
sign <identity> <file> Sign a file with an identity's key
|
||||||
verify <identity> <file> <sig> Verify a signature
|
verify <identity> <file> <sig> Verify a signature
|
||||||
locator <command> [args] Locator management commands
|
|
||||||
new <identity> <address> [...] Create and sign a new locator
|
|
||||||
show <locator> [identity] Show locator information
|
|
||||||
root [command] Root management commands
|
|
||||||
list List root peers (same as no command)
|
|
||||||
add <identity> <endpoint|locator> Designate a peer as a root
|
|
||||||
remove <address> Un-designate a peer as a root
|
|
||||||
|
|
||||||
The 'service' command does not exit until the service receives a signal.
|
The 'service' command does not exit until the service receives a signal.
|
||||||
This is typically run from launchd (Mac), systemd or init (Linux), a Windows
|
|
||||||
service harness (Windows), etc.
|
|
||||||
|
|
||||||
If 'set' is followed by a 16-digit hex number it will get/set network config
|
An <address> may be specified as a 10-digit short ZeroTier address, a
|
||||||
options. Otherwise it will get/set local options that pertain to the entire
|
fingerprint containing both an address and a SHA384 hash, or an identity.
|
||||||
node.
|
The latter two options are equivalent in terms of specificity and may be
|
||||||
|
used if stronger security guarantees are desired than those provided by
|
||||||
|
the basic ZeroTier addressing system. Fields of type <identity> must be
|
||||||
|
full identities and may be specified either verbatim or as a path to a file.
|
||||||
|
|
||||||
Identities can be specified verbatim on the command line or as a path to
|
An <endpoint> is a place where a peer may be reached. Currently these are
|
||||||
a file. This is detected automatically.
|
just 'IP/port' format addresses but other types may be added in the future.
|
||||||
`,zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
`,zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,9 @@ func Identity(args []string) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
switch args[1] {
|
switch args[1] {
|
||||||
case "c25519":
|
case "c25519", "C25519", "0":
|
||||||
case "p384":
|
idType = zerotier.IdentityTypeC25519
|
||||||
|
case "p384", "P384", "1":
|
||||||
idType = zerotier.IdentityTypeP384
|
idType = zerotier.IdentityTypeP384
|
||||||
default:
|
default:
|
||||||
Help()
|
Help()
|
||||||
|
@ -57,6 +58,12 @@ func Identity(args []string) {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "fingerprint":
|
||||||
|
if len(args) == 2 {
|
||||||
|
fmt.Println(readIdentity(args[1]).Fingerprint().String())
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
case "validate":
|
case "validate":
|
||||||
if len(args) == 2 {
|
if len(args) == 2 {
|
||||||
if readIdentity(args[1]).LocallyValidate() {
|
if readIdentity(args[1]).LocallyValidate() {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"zerotier/pkg/zerotier"
|
"zerotier/pkg/zerotier"
|
||||||
)
|
)
|
||||||
|
@ -41,11 +42,20 @@ func Join(basePath, authToken string, args []string) {
|
||||||
|
|
||||||
var fp *zerotier.Fingerprint
|
var fp *zerotier.Fingerprint
|
||||||
if len(args) == 2 {
|
if len(args) == 2 {
|
||||||
|
if strings.ContainsRune(args[1], '-') {
|
||||||
fp, err = zerotier.NewFingerprintFromString(args[1])
|
fp, err = zerotier.NewFingerprintFromString(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: invalid network controller fingerprint: %s\n", args[1])
|
fmt.Printf("ERROR: invalid network controller fingerprint: %s\n", args[1])
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
id, err := zerotier.NewIdentityFromString(args[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR: invalid network controller identity: %s\n", args[1])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fp = id.Fingerprint()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var network zerotier.APINetwork
|
var network zerotier.APINetwork
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file in the project's root directory.
|
|
||||||
*
|
|
||||||
* Change Date: 2024-01-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2.0 of the Apache License.
|
|
||||||
*/
|
|
||||||
/****/
|
|
||||||
|
|
||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
"zerotier/pkg/zerotier"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Locator(args []string) {
|
|
||||||
if len(args) > 0 {
|
|
||||||
switch args[0] {
|
|
||||||
|
|
||||||
case "new":
|
|
||||||
if len(args) >= 3 {
|
|
||||||
id := readIdentity(args[1])
|
|
||||||
if !id.HasPrivate() {
|
|
||||||
fmt.Println("ERROR: identity is missing private key and can't be used to sign a locator.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
var eps []zerotier.Endpoint
|
|
||||||
for i:=2;i<len(args);i++ {
|
|
||||||
ep, _ := zerotier.NewEndpointFromString(args[i])
|
|
||||||
if ep != nil {
|
|
||||||
eps = append(eps, *ep)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loc, err := zerotier.NewLocator(zerotier.TimeMs(),eps,id)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("ERROR: unable to create or sign locator: %s\n",err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
fmt.Println(loc.String())
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "show":
|
|
||||||
if len(args) > 1 && len(args) < 4 {
|
|
||||||
loc := readLocator(args[1])
|
|
||||||
var id *zerotier.Identity
|
|
||||||
if len(args) == 3 {
|
|
||||||
id = readIdentity(args[2])
|
|
||||||
}
|
|
||||||
ts, fp, eps, valid, _ := loc.GetInfo(id)
|
|
||||||
fmt.Printf("%s\n Timestamp: %s (%d)\n Validity: ",fp.String(),time.Unix(ts / 1000,ts * 1000).String(),ts)
|
|
||||||
if id == nil {
|
|
||||||
fmt.Printf("(no identity provided)\n")
|
|
||||||
} else {
|
|
||||||
if valid {
|
|
||||||
fmt.Printf("SIGNATURE VERIFIED\n")
|
|
||||||
} else {
|
|
||||||
fmt.Printf("! INVALID SIGNATURE\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Print(" Endpoints: ")
|
|
||||||
for i := range eps {
|
|
||||||
if i > 0 {
|
|
||||||
fmt.Print(" ")
|
|
||||||
}
|
|
||||||
fmt.Print(eps[i].String())
|
|
||||||
}
|
|
||||||
fmt.Printf("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Help()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
|
@ -14,4 +14,13 @@
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
func Root(basePath, authToken string, args []string, jsonOutput bool) {
|
func Root(basePath, authToken string, args []string, jsonOutput bool) {
|
||||||
|
if len(args) > 0 {
|
||||||
|
switch args[0] {
|
||||||
|
|
||||||
|
case "add":
|
||||||
|
|
||||||
|
case "remove":
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,8 +144,6 @@ func main() {
|
||||||
cli.Set(basePath, authToken, cmdArgs)
|
cli.Set(basePath, authToken, cmdArgs)
|
||||||
case "identity":
|
case "identity":
|
||||||
cli.Identity(cmdArgs)
|
cli.Identity(cmdArgs)
|
||||||
case "locator":
|
|
||||||
cli.Locator(cmdArgs)
|
|
||||||
case "root":
|
case "root":
|
||||||
authTokenRequired(authToken)
|
authTokenRequired(authToken)
|
||||||
cli.Root(basePath, authToken, cmdArgs, *jflag)
|
cli.Root(basePath, authToken, cmdArgs, *jflag)
|
||||||
|
|
|
@ -21,7 +21,7 @@ const (
|
||||||
EndpointTypeIp = C.ZT_ENDPOINT_TYPE_IP
|
EndpointTypeIp = C.ZT_ENDPOINT_TYPE_IP
|
||||||
EndpointTypeIpUdp = C.ZT_ENDPOINT_TYPE_IP_UDP
|
EndpointTypeIpUdp = C.ZT_ENDPOINT_TYPE_IP_UDP
|
||||||
EndpointTypeIpTcp = C.ZT_ENDPOINT_TYPE_IP_TCP
|
EndpointTypeIpTcp = C.ZT_ENDPOINT_TYPE_IP_TCP
|
||||||
EndpointTypeIpHttp2 = C.ZT_ENDPOINT_TYPE_IP_HTTP2
|
EndpointTypeIpHttp = C.ZT_ENDPOINT_TYPE_IP_HTTP
|
||||||
)
|
)
|
||||||
|
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
|
@ -65,7 +65,7 @@ func (ep *Endpoint) Type() int {
|
||||||
// InetAddress gets this Endpoint as an InetAddress or nil if its type is not addressed by one.
|
// InetAddress gets this Endpoint as an InetAddress or nil if its type is not addressed by one.
|
||||||
func (ep *Endpoint) InetAddress() *InetAddress {
|
func (ep *Endpoint) InetAddress() *InetAddress {
|
||||||
switch ep.cep._type {
|
switch ep.cep._type {
|
||||||
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2:
|
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp:
|
||||||
ua := sockaddrStorageToUDPAddr(C._getSS(&ep.cep))
|
ua := sockaddrStorageToUDPAddr(C._getSS(&ep.cep))
|
||||||
return &InetAddress{IP: ua.IP, Port: ua.Port}
|
return &InetAddress{IP: ua.IP, Port: ua.Port}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,6 +166,12 @@ func (id *Identity) Address() Address { return id.address }
|
||||||
// HasPrivate returns true if this identity has its own private portion.
|
// HasPrivate returns true if this identity has its own private portion.
|
||||||
func (id *Identity) HasPrivate() bool { return len(id.privateKey) > 0 }
|
func (id *Identity) HasPrivate() bool { return len(id.privateKey) > 0 }
|
||||||
|
|
||||||
|
// Fingerprint gets this identity's address plus hash of public key(s).
|
||||||
|
func (id *Identity) Fingerprint() *Fingerprint {
|
||||||
|
id.initCIdentityPtr()
|
||||||
|
return newFingerprintFromCFingerprint(C.ZT_Identity_fingerprint(id.cid))
|
||||||
|
}
|
||||||
|
|
||||||
// PrivateKeyString returns the full identity.secret if the private key is set, or an empty string if no private key is set.
|
// PrivateKeyString returns the full identity.secret if the private key is set, or an empty string if no private key is set.
|
||||||
func (id *Identity) PrivateKeyString() string {
|
func (id *Identity) PrivateKeyString() string {
|
||||||
switch id.idtype {
|
switch id.idtype {
|
||||||
|
|
|
@ -305,14 +305,9 @@ enum ZT_EndpointType
|
||||||
ZT_ENDPOINT_TYPE_IP = 5, // Naked IP (protocol 193)
|
ZT_ENDPOINT_TYPE_IP = 5, // Naked IP (protocol 193)
|
||||||
ZT_ENDPOINT_TYPE_IP_UDP = 6, // IP/UDP
|
ZT_ENDPOINT_TYPE_IP_UDP = 6, // IP/UDP
|
||||||
ZT_ENDPOINT_TYPE_IP_TCP = 7, // IP/TCP
|
ZT_ENDPOINT_TYPE_IP_TCP = 7, // IP/TCP
|
||||||
ZT_ENDPOINT_TYPE_IP_HTTP2 = 8 // IP/HTTP2 encapsulation
|
ZT_ENDPOINT_TYPE_IP_HTTP = 8 // IP/HTTP 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)
|
* Full identity fingerprint with address and 384-bit hash of public key(s)
|
||||||
*/
|
*/
|
||||||
|
@ -2277,6 +2272,8 @@ ZT_SDK_API void ZT_version(
|
||||||
int *revision,
|
int *revision,
|
||||||
int *build);
|
int *build);
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -139,6 +139,11 @@
|
||||||
*/
|
*/
|
||||||
#define ZT_NAT_T_PORT_SCAN_MAX 16
|
#define ZT_NAT_T_PORT_SCAN_MAX 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimum interval between attempts to reach a given physical endpoint
|
||||||
|
*/
|
||||||
|
#define ZT_PATH_MIN_TRY_INTERVAL ZT_PATH_KEEPALIVE_PERIOD
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay between calls to the pulse() method in Peer for each peer
|
* Delay between calls to the pulse() method in Peer for each peer
|
||||||
*/
|
*/
|
||||||
|
@ -168,6 +173,11 @@
|
||||||
*/
|
*/
|
||||||
#define ZT_PEER_PRIORITIZE_PATHS_INTERVAL 5000
|
#define ZT_PEER_PRIORITIZE_PATHS_INTERVAL 5000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of previous endpoints to cache for root-less re-establishment
|
||||||
|
*/
|
||||||
|
#define ZT_PEER_ENDPOINT_CACHE_SIZE 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay between requests for updated network autoconf information
|
* Delay between requests for updated network autoconf information
|
||||||
*
|
*
|
||||||
|
|
|
@ -18,34 +18,34 @@ namespace ZeroTier {
|
||||||
|
|
||||||
char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
|
char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
|
||||||
{
|
{
|
||||||
static const char *const s_endpointTypeChars = ZT_ENDPOINT_TYPE_CHAR_INDEX;
|
static const char *const s_endpointTypeChars = "0123456789";
|
||||||
|
|
||||||
static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow");
|
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");
|
static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow");
|
||||||
|
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
default:
|
default: // ZT_ENDPOINT_TYPE_NIL
|
||||||
s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_NIL];
|
s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_NIL];
|
||||||
s[1] = 0;
|
s[1] = 0;
|
||||||
break;
|
break;
|
||||||
case ZT_ENDPOINT_TYPE_ZEROTIER:
|
case ZT_ENDPOINT_TYPE_ZEROTIER:
|
||||||
s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_ZEROTIER];
|
s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_ZEROTIER];
|
||||||
s[1] = '-';
|
s[1] = '=';
|
||||||
zt().toString(s + 2);
|
zt().toString(s + 2);
|
||||||
break;
|
break;
|
||||||
case ZT_ENDPOINT_TYPE_ETHERNET:
|
case ZT_ENDPOINT_TYPE_ETHERNET:
|
||||||
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
|
case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
|
||||||
case ZT_ENDPOINT_TYPE_BLUETOOTH:
|
case ZT_ENDPOINT_TYPE_BLUETOOTH:
|
||||||
s[0] = s_endpointTypeChars[this->type];
|
s[0] = s_endpointTypeChars[this->type];
|
||||||
s[1] = '-';
|
s[1] = '=';
|
||||||
eth().toString(s + 2);
|
eth().toString(s + 2);
|
||||||
break;
|
break;
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
s[0] = s_endpointTypeChars[this->type];
|
s[0] = s_endpointTypeChars[this->type];
|
||||||
s[1] = '-';
|
s[1] = '=';
|
||||||
ip().toString(s + 2);
|
ip().toString(s + 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ bool Endpoint::fromString(const char *s) noexcept
|
||||||
if ((!s) || (!*s))
|
if ((!s) || (!*s))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const char *start = strchr(s, '-');
|
const char *start = strchr(s, '=');
|
||||||
if (start++ != nullptr) {
|
if (start++ != nullptr) {
|
||||||
// Parse a fully qualified type-address format Endpoint.
|
// Parse a fully qualified type-address format Endpoint.
|
||||||
char tmp[16];
|
char tmp[16];
|
||||||
|
@ -93,7 +93,7 @@ bool Endpoint::fromString(const char *s) noexcept
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
if (!asInetAddress(this->value.ss).fromString(start))
|
if (!asInetAddress(this->value.ss).fromString(start))
|
||||||
return false;
|
return false;
|
||||||
default:
|
default:
|
||||||
|
@ -116,8 +116,7 @@ bool Endpoint::fromString(const char *s) noexcept
|
||||||
int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
|
int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
|
||||||
{
|
{
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
//case ZT_ENDPOINT_TYPE_NIL:
|
default: // ZT_ENDPOINT_TYPE_NIL
|
||||||
default:
|
|
||||||
// NIL endpoints get serialized like NIL InetAddress instances.
|
// NIL endpoints get serialized like NIL InetAddress instances.
|
||||||
data[0] = ZT_ENDPOINT_TYPE_NIL;
|
data[0] = ZT_ENDPOINT_TYPE_NIL;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -141,7 +140,7 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
|
||||||
|
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
// Other IP types get serialized as new version Endpoint instances with type.
|
// Other IP types get serialized as new version Endpoint instances with type.
|
||||||
data[0] = 16 + (uint8_t)this->type;
|
data[0] = 16 + (uint8_t)this->type;
|
||||||
return 1 + asInetAddress(this->value.ss).marshal(data + 1);
|
return 1 + asInetAddress(this->value.ss).marshal(data + 1);
|
||||||
|
@ -197,7 +196,7 @@ int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
return asInetAddress(this->value.ss).unmarshal(data + 1, len - 1);
|
return asInetAddress(this->value.ss).unmarshal(data + 1, len - 1);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -227,7 +226,7 @@ bool Endpoint::operator==(const Endpoint &ep) const noexcept
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
return ip() == ep.ip();
|
return ip() == ep.ip();
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
|
@ -249,7 +248,7 @@ bool Endpoint::operator<(const Endpoint &ep) const noexcept
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
return ip() < ep.ip();
|
return ip() < ep.ip();
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -138,12 +138,12 @@ public:
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
switch(ep.type) {
|
switch(ep.type) {
|
||||||
case ZT_ENDPOINT_TYPE_IP:
|
case ZT_ENDPOINT_TYPE_IP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||||
return ip().ipsEqual(ep.ip());
|
return ip().ipsEqual(ep.ip());
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -39,7 +39,8 @@ namespace ZeroTier {
|
||||||
class Expect
|
class Expect
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ZT_INLINE Expect() {}
|
ZT_INLINE Expect()
|
||||||
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by other code when something is sending a packet that could potentially receive an OK response
|
* Called by other code when something is sending a packet that could potentially receive an OK response
|
||||||
|
|
|
@ -243,23 +243,49 @@ void Peer::pulse(void *const tPtr, const int64_t now, const bool isRoot)
|
||||||
if (m_locator) {
|
if (m_locator) {
|
||||||
for (Vector<Endpoint>::const_iterator ep(m_locator->endpoints().begin());ep != m_locator->endpoints().end();++ep) {
|
for (Vector<Endpoint>::const_iterator ep(m_locator->endpoints().begin());ep != m_locator->endpoints().end();++ep) {
|
||||||
if (ep->type == ZT_ENDPOINT_TYPE_IP_UDP) {
|
if (ep->type == ZT_ENDPOINT_TYPE_IP_UDP) {
|
||||||
|
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr, m_id, -1, ep->ip())) {
|
||||||
|
int64_t < = m_lastTried[*ep];
|
||||||
|
if ((now - lt) > ZT_PATH_MIN_TRY_INTERVAL) {
|
||||||
|
lt = now;
|
||||||
RR->t->tryingNewPath(tPtr, 0x84b22322, m_id, ep->ip(), InetAddress::NIL, 0, 0, Identity::NIL);
|
RR->t->tryingNewPath(tPtr, 0x84b22322, m_id, ep->ip(), InetAddress::NIL, 0, 0, Identity::NIL);
|
||||||
sent(now, m_sendProbe(tPtr, -1, ep->ip(), nullptr, 0, now));
|
sent(now, m_sendProbe(tPtr, -1, ep->ip(), nullptr, 0, now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i=0;i<ZT_PEER_ENDPOINT_CACHE_SIZE;++i) {
|
||||||
|
if ((m_endpointCache[i].firstSeen > 0) && (m_endpointCache[i].target.type == ZT_ENDPOINT_TYPE_IP_UDP)) {
|
||||||
|
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr, m_id, -1, m_endpointCache[i].target.ip())) {
|
||||||
|
int64_t < = m_lastTried[m_endpointCache[i].target];
|
||||||
|
if ((now - lt) > ZT_PATH_MIN_TRY_INTERVAL) {
|
||||||
|
lt = now;
|
||||||
|
RR->t->tryingNewPath(tPtr, 0x84b22343, m_id, m_endpointCache[i].target.ip(), InetAddress::NIL, 0, 0, Identity::NIL);
|
||||||
|
sent(now, m_sendProbe(tPtr, -1, m_endpointCache[i].target.ip(), nullptr, 0, now));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InetAddress addr;
|
InetAddress addr;
|
||||||
if (RR->node->externalPathLookup(tPtr, m_id, -1, addr)) {
|
if (RR->node->externalPathLookup(tPtr, m_id, -1, addr)) {
|
||||||
if ((addr) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr, m_id, -1, addr))) {
|
if ((addr) && RR->node->shouldUsePathForZeroTierTraffic(tPtr, m_id, -1, addr)) {
|
||||||
|
int64_t < = m_lastTried[Endpoint(addr)];
|
||||||
|
if ((now - lt) > ZT_PATH_MIN_TRY_INTERVAL) {
|
||||||
|
lt = now;
|
||||||
RR->t->tryingNewPath(tPtr, 0x84a10000, m_id, addr, InetAddress::NIL, 0, 0, Identity::NIL);
|
RR->t->tryingNewPath(tPtr, 0x84a10000, m_id, addr, InetAddress::NIL, 0, 0, Identity::NIL);
|
||||||
sent(now, m_sendProbe(tPtr, -1, addr, nullptr, 0, now));
|
sent(now, m_sendProbe(tPtr, -1, addr, nullptr, 0, now));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Attempt up to ZT_NAT_T_MAX_QUEUED_ATTEMPTS_PER_PULSE queued addresses.
|
// Attempt up to ZT_NAT_T_MAX_QUEUED_ATTEMPTS_PER_PULSE queued addresses.
|
||||||
|
|
||||||
|
// Note that m_lastTried is checked when contact() is called and something
|
||||||
|
// is added to the try queue, not here.
|
||||||
|
|
||||||
unsigned int attempts = 0;
|
unsigned int attempts = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
p_TryQueueItem &qi = m_tryQueue.front();
|
p_TryQueueItem &qi = m_tryQueue.front();
|
||||||
|
@ -326,15 +352,15 @@ void Peer::pulse(void *const tPtr, const int64_t now, const bool isRoot)
|
||||||
// Discard front item unless the code skips to requeue_item.
|
// Discard front item unless the code skips to requeue_item.
|
||||||
discard_queue_item:
|
discard_queue_item:
|
||||||
m_tryQueue.pop_front();
|
m_tryQueue.pop_front();
|
||||||
if ((m_tryQueue.empty()) || (attempts >= ZT_NAT_T_PORT_SCAN_MAX))
|
if (attempts >= std::min((unsigned int)m_tryQueue.size(),(unsigned int)ZT_NAT_T_PORT_SCAN_MAX))
|
||||||
break;
|
break;
|
||||||
else continue;
|
else continue;
|
||||||
|
|
||||||
// If the code skips here the front item is instead moved to the back.
|
// If the code skips here the front item is instead moved to the back.
|
||||||
requeue_item:
|
requeue_item:
|
||||||
if (m_tryQueue.size() > 1)
|
if (m_tryQueue.size() > 1) // no point in doing this splice if there's only one item
|
||||||
m_tryQueue.splice(m_tryQueue.end(), m_tryQueue, m_tryQueue.begin());
|
m_tryQueue.splice(m_tryQueue.end(), m_tryQueue, m_tryQueue.begin());
|
||||||
if (attempts >= ZT_NAT_T_PORT_SCAN_MAX)
|
if (attempts >= std::min((unsigned int)m_tryQueue.size(),(unsigned int)ZT_NAT_T_PORT_SCAN_MAX))
|
||||||
break;
|
break;
|
||||||
else continue;
|
else continue;
|
||||||
}
|
}
|
||||||
|
@ -370,6 +396,13 @@ void Peer::pulse(void *const tPtr, const int64_t now, const bool isRoot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean m_lastTried
|
||||||
|
for (Map<Endpoint,int64_t>::iterator i(m_lastTried.begin());i!=m_lastTried.end();) {
|
||||||
|
if ((now - i->second) > (ZT_PATH_MIN_TRY_INTERVAL * 4))
|
||||||
|
m_lastTried.erase(i++);
|
||||||
|
else ++i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peer::contact(void *tPtr, const int64_t now, const Endpoint &ep, int tries)
|
void Peer::contact(void *tPtr, const int64_t now, const Endpoint &ep, int tries)
|
||||||
|
@ -387,6 +420,12 @@ void Peer::contact(void *tPtr, const int64_t now, const Endpoint &ep, int tries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check underlying path attempt rate limit.
|
||||||
|
int64_t < = m_lastTried[ep];
|
||||||
|
if ((now - lt) < ZT_PATH_MIN_TRY_INTERVAL)
|
||||||
|
return;
|
||||||
|
lt = now;
|
||||||
|
|
||||||
// For IPv4 addresses we send a tiny packet with a low TTL, which helps to
|
// For IPv4 addresses we send a tiny packet with a low TTL, which helps to
|
||||||
// traverse some NAT types. It has no effect otherwise.
|
// traverse some NAT types. It has no effect otherwise.
|
||||||
if (ep.isInetAddr() && ep.ip().isV4()) {
|
if (ep.isInetAddr() && ep.ip().isV4()) {
|
||||||
|
|
|
@ -153,9 +153,7 @@ public:
|
||||||
* @param bytes Number of bytes relayed
|
* @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); }
|
||||||
m_relayedMeter.log(now, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current best direct path or NULL if none
|
* Get the current best direct path or NULL if none
|
||||||
|
@ -288,25 +286,19 @@ public:
|
||||||
* @return The permanent shared key for this peer computed by simple identity agreement
|
* @return The permanent shared key for this peer computed by simple identity agreement
|
||||||
*/
|
*/
|
||||||
ZT_INLINE SharedPtr<SymmetricKey> identityKey() noexcept
|
ZT_INLINE SharedPtr<SymmetricKey> identityKey() noexcept
|
||||||
{
|
{ return m_identityKey; }
|
||||||
return m_identityKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return AES instance for HELLO dictionary / encrypted section encryption/decryption
|
* @return AES instance for HELLO dictionary / encrypted section encryption/decryption
|
||||||
*/
|
*/
|
||||||
ZT_INLINE const AES &identityHelloDictionaryEncryptionCipher() noexcept
|
ZT_INLINE const AES &identityHelloDictionaryEncryptionCipher() noexcept
|
||||||
{
|
{ return m_helloCipher; }
|
||||||
return m_helloCipher;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Key for HMAC on HELLOs
|
* @return Key for HMAC on HELLOs
|
||||||
*/
|
*/
|
||||||
ZT_INLINE const uint8_t *identityHelloHmacKey() noexcept
|
ZT_INLINE const uint8_t *identityHelloHmacKey() noexcept
|
||||||
{
|
{ return m_helloMacKey; }
|
||||||
return m_helloMacKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Raw identity key bytes
|
* @return Raw identity key bytes
|
||||||
|
@ -336,9 +328,7 @@ public:
|
||||||
* @return True if this key is ephemeral, false if it's the long-lived identity key
|
* @return True if this key is ephemeral, false if it's the long-lived identity key
|
||||||
*/
|
*/
|
||||||
ZT_INLINE bool isEphemeral(const SharedPtr<SymmetricKey> &k) const noexcept
|
ZT_INLINE bool isEphemeral(const SharedPtr<SymmetricKey> &k) const noexcept
|
||||||
{
|
{ return m_identityKey != k; }
|
||||||
return (m_identityKey != k);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the currently known remote version of this peer's client
|
* Set the currently known remote version of this peer's client
|
||||||
|
@ -369,7 +359,7 @@ public:
|
||||||
{ return m_vRevision; }
|
{ return m_vRevision; }
|
||||||
|
|
||||||
ZT_INLINE bool remoteVersionKnown() const noexcept
|
ZT_INLINE bool remoteVersionKnown() const noexcept
|
||||||
{ return ((m_vMajor > 0) || (m_vMinor > 0) || (m_vRevision > 0)); }
|
{ return (m_vMajor > 0) || (m_vMinor > 0) || (m_vRevision > 0); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if there is at least one alive direct path
|
* @return True if there is at least one alive direct path
|
||||||
|
@ -521,7 +511,22 @@ private:
|
||||||
// For SharedPtr<>
|
// For SharedPtr<>
|
||||||
std::atomic<int> __refCount;
|
std::atomic<int> __refCount;
|
||||||
|
|
||||||
// Addresses recieved via PUSH_DIRECT_PATHS etc. that we are scheduled to try.
|
struct p_EndpointCacheItem
|
||||||
|
{
|
||||||
|
Endpoint target;
|
||||||
|
uint64_t timesSeen;
|
||||||
|
int64_t firstSeen;
|
||||||
|
|
||||||
|
ZT_INLINE bool operator<(const p_EndpointCacheItem &ci) const noexcept
|
||||||
|
{ return (ci.timesSeen < timesSeen) || ((ci.timesSeen == timesSeen) && (ci.firstSeen < firstSeen)); }
|
||||||
|
|
||||||
|
ZT_INLINE p_EndpointCacheItem() noexcept : target(), timesSeen(0), firstSeen(0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Endpoint cache sorted in ascending order of times seen followed by first seen time.
|
||||||
|
p_EndpointCacheItem m_endpointCache[ZT_PEER_ENDPOINT_CACHE_SIZE];
|
||||||
|
|
||||||
struct p_TryQueueItem
|
struct p_TryQueueItem
|
||||||
{
|
{
|
||||||
ZT_INLINE p_TryQueueItem() :
|
ZT_INLINE p_TryQueueItem() :
|
||||||
|
@ -539,6 +544,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
List<p_TryQueueItem> m_tryQueue;
|
List<p_TryQueueItem> m_tryQueue;
|
||||||
|
Map<Endpoint,int64_t> m_lastTried;
|
||||||
|
|
||||||
uint16_t m_vProto;
|
uint16_t m_vProto;
|
||||||
uint16_t m_vMajor;
|
uint16_t m_vMajor;
|
||||||
|
|
|
@ -113,6 +113,8 @@ void Topology::doPeriodicTasks(void *tPtr, const int64_t now)
|
||||||
{
|
{
|
||||||
RWMutex::Lock l1(m_peers_l);
|
RWMutex::Lock l1(m_peers_l);
|
||||||
for (Map<Address, SharedPtr<Peer> >::iterator i(m_peers.begin());i != m_peers.end();) {
|
for (Map<Address, SharedPtr<Peer> >::iterator i(m_peers.begin());i != m_peers.end();) {
|
||||||
|
// TODO: also delete if the peer has not exchanged meaningful communication in a while, such as
|
||||||
|
// a network frame or non-trivial control packet.
|
||||||
if (((now - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) && (m_roots.count(i->second->identity()) == 0)) {
|
if (((now - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) && (m_roots.count(i->second->identity()) == 0)) {
|
||||||
i->second->save(tPtr);
|
i->second->save(tPtr);
|
||||||
m_peers.erase(i++);
|
m_peers.erase(i++);
|
||||||
|
|
Loading…
Add table
Reference in a new issue