mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +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
|
@ -26,64 +26,67 @@ Licensed under the ZeroTier BSL (see LICENSE.txt)
|
|||
Usage: zerotier [-options] <command> [command args]
|
||||
|
||||
Global Options:
|
||||
-j Output raw JSON where applicable
|
||||
-p <path> Use alternate base path
|
||||
-t <path> Load secret auth token from a file
|
||||
-T <token> Set secret auth token on command line
|
||||
-j Output raw JSON where applicable
|
||||
-p <path> Use alternate base path
|
||||
-t <path> Load secret auth token from a file
|
||||
-T <token> Set secret auth token on command line
|
||||
|
||||
Commands:
|
||||
help Show this help
|
||||
version Print version
|
||||
service Start as service
|
||||
status Show node status, identity, and config
|
||||
peers List all VL1 peers
|
||||
join <network> [fingerprint] Join a virtual network
|
||||
leave <network> Leave a virtual network
|
||||
networks List VL2 virtual networks
|
||||
network <network> Show verbose network info
|
||||
set <network> [option] [value] Get or set a network config option
|
||||
manageips <boolean> Is IP management allowed?
|
||||
manageroutes <boolean> Is route management allowed?
|
||||
globalips <boolean> Allow assignment of global IPs?
|
||||
globalroutes <boolean> Can global IP space routes be set?
|
||||
defaultroute <boolean> Can default route be overridden?
|
||||
set [option] [value] Get or set a service config option
|
||||
port <port> Primary P2P port
|
||||
secondaryport <port/0> Secondary P2P port (0 to disable)
|
||||
blacklist cidr <IP/bits> <boolean> Toggle physical path blacklisting
|
||||
blacklist if <prefix> <boolean> Toggle interface prefix blacklisting
|
||||
portmap <boolean> Toggle use of uPnP or NAT-PMP
|
||||
controller <command> [option] Local controller management commands
|
||||
networks List networks run by local controller
|
||||
new Create a new network
|
||||
set <network> [setting] [value] Show or modify network settings
|
||||
members <network> List members of a network
|
||||
member <network> [setting] [value] Show or modify member level settings
|
||||
auth <address|fingerprint> Authorize a peer
|
||||
deauth <address|fingerprint> Deauthorize a peer
|
||||
identity <command> [args] Identity management commands
|
||||
new [c25519|p384] Create identity pair (default: c25519)
|
||||
getpublic <identity> Extract only public part of identity
|
||||
validate <identity> Locally validate an identity
|
||||
sign <identity> <file> Sign a file with an identity's key
|
||||
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
|
||||
help Show this help
|
||||
version Print version
|
||||
service Start as service
|
||||
status Show node status and configuration
|
||||
join <network> [fingerprint] Join a virtual network
|
||||
leave <network> Leave a virtual network
|
||||
networks List VL2 virtual networks
|
||||
network <network> [command] [option] - Network management commands
|
||||
show Show network details (default)
|
||||
set [option] [value] - Get or set network options
|
||||
manageips <boolean> Is IP management allowed?
|
||||
manageroutes <boolean> Is route management allowed?
|
||||
globalips <boolean> Allow assignment of global IPs?
|
||||
globalroutes <boolean> Can global IP space routes be set?
|
||||
defaultroute <boolean> Can default route be overridden?
|
||||
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
|
||||
secondaryport <port/0> Secondary P2P port (0 to disable)
|
||||
blacklist cidr <IP/bits> <boolean> Toggle physical path blacklisting
|
||||
blacklist if <prefix> <boolean> Toggle interface prefix blacklisting
|
||||
portmap <boolean> Toggle use of uPnP or NAT-PMP
|
||||
controller <command> [option] - Local controller management commands
|
||||
networks List networks run by local controller
|
||||
new Create a new network
|
||||
set <network> [setting] [value] Show or modify network settings
|
||||
members <network> List members of a network
|
||||
member <network> [setting] [value] Show or modify member level settings
|
||||
auth <address> Authorize a peer
|
||||
deauth <address> Deauthorize a peer
|
||||
identity <command> [args] - Identity management commands
|
||||
new [c25519|p384] Create identity (default: c25519)
|
||||
getpublic <identity> Extract only public part of identity
|
||||
fingerprint <identity> Get an identity's fingerprint
|
||||
validate <identity> Locally validate an identity
|
||||
sign <identity> <file> Sign a file with an identity's key
|
||||
verify <identity> <file> <sig> Verify a signature
|
||||
|
||||
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
|
||||
options. Otherwise it will get/set local options that pertain to the entire
|
||||
node.
|
||||
An <address> may be specified as a 10-digit short ZeroTier address, a
|
||||
fingerprint containing both an address and a SHA384 hash, or an identity.
|
||||
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
|
||||
a file. This is detected automatically.
|
||||
An <endpoint> is a place where a peer may be reached. Currently these are
|
||||
just 'IP/port' format addresses but other types may be added in the future.
|
||||
`,zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
|
||||
}
|
||||
|
|
|
@ -35,8 +35,9 @@ func Identity(args []string) {
|
|||
os.Exit(1)
|
||||
}
|
||||
switch args[1] {
|
||||
case "c25519":
|
||||
case "p384":
|
||||
case "c25519", "C25519", "0":
|
||||
idType = zerotier.IdentityTypeC25519
|
||||
case "p384", "P384", "1":
|
||||
idType = zerotier.IdentityTypeP384
|
||||
default:
|
||||
Help()
|
||||
|
@ -57,6 +58,12 @@ func Identity(args []string) {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
case "fingerprint":
|
||||
if len(args) == 2 {
|
||||
fmt.Println(readIdentity(args[1]).Fingerprint().String())
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
case "validate":
|
||||
if len(args) == 2 {
|
||||
if readIdentity(args[1]).LocallyValidate() {
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"zerotier/pkg/zerotier"
|
||||
)
|
||||
|
@ -41,10 +42,19 @@ func Join(basePath, authToken string, args []string) {
|
|||
|
||||
var fp *zerotier.Fingerprint
|
||||
if len(args) == 2 {
|
||||
fp, err = zerotier.NewFingerprintFromString(args[1])
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: invalid network controller fingerprint: %s\n", args[1])
|
||||
os.Exit(1)
|
||||
if strings.ContainsRune(args[1], '-') {
|
||||
fp, err = zerotier.NewFingerprintFromString(args[1])
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR: invalid network controller fingerprint: %s\n", args[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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
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)
|
||||
case "identity":
|
||||
cli.Identity(cmdArgs)
|
||||
case "locator":
|
||||
cli.Locator(cmdArgs)
|
||||
case "root":
|
||||
authTokenRequired(authToken)
|
||||
cli.Root(basePath, authToken, cmdArgs, *jflag)
|
||||
|
|
|
@ -21,7 +21,7 @@ const (
|
|||
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
|
||||
EndpointTypeIpHttp = C.ZT_ENDPOINT_TYPE_IP_HTTP
|
||||
)
|
||||
|
||||
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.
|
||||
func (ep *Endpoint) InetAddress() *InetAddress {
|
||||
switch ep.cep._type {
|
||||
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp2:
|
||||
case EndpointTypeIp, EndpointTypeIpUdp, EndpointTypeIpTcp, EndpointTypeIpHttp:
|
||||
ua := sockaddrStorageToUDPAddr(C._getSS(&ep.cep))
|
||||
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.
|
||||
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.
|
||||
func (id *Identity) PrivateKeyString() string {
|
||||
switch id.idtype {
|
||||
|
|
|
@ -305,14 +305,9 @@ enum ZT_EndpointType
|
|||
ZT_ENDPOINT_TYPE_IP = 5, // Naked IP (protocol 193)
|
||||
ZT_ENDPOINT_TYPE_IP_UDP = 6, // IP/UDP
|
||||
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)
|
||||
*/
|
||||
|
@ -2277,6 +2272,8 @@ ZT_SDK_API void ZT_version(
|
|||
int *revision,
|
||||
int *build);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -139,6 +139,11 @@
|
|||
*/
|
||||
#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
|
||||
*/
|
||||
|
@ -168,6 +173,11 @@
|
|||
*/
|
||||
#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
|
||||
*
|
||||
|
|
|
@ -18,34 +18,34 @@ namespace ZeroTier {
|
|||
|
||||
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_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow");
|
||||
|
||||
switch (this->type) {
|
||||
default:
|
||||
default: // ZT_ENDPOINT_TYPE_NIL
|
||||
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] = '-';
|
||||
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] = '-';
|
||||
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:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||
s[0] = s_endpointTypeChars[this->type];
|
||||
s[1] = '-';
|
||||
s[1] = '=';
|
||||
ip().toString(s + 2);
|
||||
break;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ bool Endpoint::fromString(const char *s) noexcept
|
|||
if ((!s) || (!*s))
|
||||
return true;
|
||||
|
||||
const char *start = strchr(s, '-');
|
||||
const char *start = strchr(s, '=');
|
||||
if (start++ != nullptr) {
|
||||
// Parse a fully qualified type-address format Endpoint.
|
||||
char tmp[16];
|
||||
|
@ -93,7 +93,7 @@ bool Endpoint::fromString(const char *s) noexcept
|
|||
case ZT_ENDPOINT_TYPE_IP:
|
||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||
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))
|
||||
return false;
|
||||
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
|
||||
{
|
||||
switch (this->type) {
|
||||
//case ZT_ENDPOINT_TYPE_NIL:
|
||||
default:
|
||||
default: // ZT_ENDPOINT_TYPE_NIL
|
||||
// NIL endpoints get serialized like NIL InetAddress instances.
|
||||
data[0] = ZT_ENDPOINT_TYPE_NIL;
|
||||
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_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.
|
||||
data[0] = 16 + (uint8_t)this->type;
|
||||
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_UDP:
|
||||
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);
|
||||
|
||||
default:
|
||||
|
@ -227,7 +226,7 @@ bool Endpoint::operator==(const Endpoint &ep) const noexcept
|
|||
case ZT_ENDPOINT_TYPE_IP:
|
||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||
return ip() == ep.ip();
|
||||
default:
|
||||
return true;
|
||||
|
@ -249,7 +248,7 @@ bool Endpoint::operator<(const Endpoint &ep) const noexcept
|
|||
case ZT_ENDPOINT_TYPE_IP:
|
||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||
return ip() < ep.ip();
|
||||
default:
|
||||
return true;
|
||||
|
|
|
@ -138,12 +138,12 @@ public:
|
|||
case ZT_ENDPOINT_TYPE_IP:
|
||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||
switch(ep.type) {
|
||||
case ZT_ENDPOINT_TYPE_IP:
|
||||
case ZT_ENDPOINT_TYPE_IP_UDP:
|
||||
case ZT_ENDPOINT_TYPE_IP_TCP:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP2:
|
||||
case ZT_ENDPOINT_TYPE_IP_HTTP:
|
||||
return ip().ipsEqual(ep.ip());
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -39,7 +39,8 @@ namespace ZeroTier {
|
|||
class Expect
|
||||
{
|
||||
public:
|
||||
ZT_INLINE Expect() {}
|
||||
ZT_INLINE Expect()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Called by other code when something is sending a packet that could potentially receive an OK response
|
||||
|
@ -47,7 +48,7 @@ public:
|
|||
* @param packetId Packet ID of packet being sent (be sure it's post-armor())
|
||||
* @param now Current time
|
||||
*/
|
||||
ZT_INLINE void sending(const uint64_t packetId,const int64_t now) noexcept
|
||||
ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept
|
||||
{
|
||||
m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL));
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ public:
|
|||
* @param now Current time
|
||||
* @return True if we're expecting a reply (and a reset occurred)
|
||||
*/
|
||||
ZT_INLINE bool expecting(const uint64_t inRePacketId,const int64_t now) noexcept
|
||||
ZT_INLINE bool expecting(const uint64_t inRePacketId, const int64_t now) noexcept
|
||||
{
|
||||
return (((now / ZT_EXPECT_TTL) - (int64_t)m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1);
|
||||
}
|
||||
|
|
|
@ -243,25 +243,51 @@ void Peer::pulse(void *const tPtr, const int64_t now, const bool isRoot)
|
|||
if (m_locator) {
|
||||
for (Vector<Endpoint>::const_iterator ep(m_locator->endpoints().begin());ep != m_locator->endpoints().end();++ep) {
|
||||
if (ep->type == ZT_ENDPOINT_TYPE_IP_UDP) {
|
||||
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));
|
||||
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);
|
||||
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;
|
||||
if (RR->node->externalPathLookup(tPtr, m_id, -1, addr)) {
|
||||
if ((addr) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr, m_id, -1, addr))) {
|
||||
RR->t->tryingNewPath(tPtr, 0x84a10000, m_id, addr, InetAddress::NIL, 0, 0, Identity::NIL);
|
||||
sent(now, m_sendProbe(tPtr, -1, addr, nullptr, 0, now));
|
||||
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);
|
||||
sent(now, m_sendProbe(tPtr, -1, addr, nullptr, 0, now));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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;
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
p_TryQueueItem &qi = m_tryQueue.front();
|
||||
|
||||
if (qi.target.isInetAddr()) {
|
||||
|
@ -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_queue_item:
|
||||
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;
|
||||
else continue;
|
||||
|
||||
// If the code skips here the front item is instead moved to the back.
|
||||
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());
|
||||
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;
|
||||
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)
|
||||
|
@ -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
|
||||
// traverse some NAT types. It has no effect otherwise.
|
||||
if (ep.isInetAddr() && ep.ip().isV4()) {
|
||||
|
|
|
@ -153,9 +153,7 @@ public:
|
|||
* @param bytes Number of bytes relayed
|
||||
*/
|
||||
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
|
||||
|
@ -288,25 +286,19 @@ public:
|
|||
* @return The permanent shared key for this peer computed by simple identity agreement
|
||||
*/
|
||||
ZT_INLINE SharedPtr<SymmetricKey> identityKey() noexcept
|
||||
{
|
||||
return m_identityKey;
|
||||
}
|
||||
{ return m_identityKey; }
|
||||
|
||||
/**
|
||||
* @return AES instance for HELLO dictionary / encrypted section encryption/decryption
|
||||
*/
|
||||
ZT_INLINE const AES &identityHelloDictionaryEncryptionCipher() noexcept
|
||||
{
|
||||
return m_helloCipher;
|
||||
}
|
||||
{ return m_helloCipher; }
|
||||
|
||||
/**
|
||||
* @return Key for HMAC on HELLOs
|
||||
*/
|
||||
ZT_INLINE const uint8_t *identityHelloHmacKey() noexcept
|
||||
{
|
||||
return m_helloMacKey;
|
||||
}
|
||||
{ return m_helloMacKey; }
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
|
@ -350,10 +340,10 @@ public:
|
|||
*/
|
||||
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
|
||||
|
@ -369,7 +359,7 @@ public:
|
|||
{ return m_vRevision; }
|
||||
|
||||
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
|
||||
|
@ -445,7 +435,7 @@ 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:
|
||||
|
@ -521,7 +511,22 @@ private:
|
|||
// For SharedPtr<>
|
||||
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
|
||||
{
|
||||
ZT_INLINE p_TryQueueItem() :
|
||||
|
@ -539,6 +544,7 @@ private:
|
|||
};
|
||||
|
||||
List<p_TryQueueItem> m_tryQueue;
|
||||
Map<Endpoint,int64_t> m_lastTried;
|
||||
|
||||
uint16_t m_vProto;
|
||||
uint16_t m_vMajor;
|
||||
|
|
|
@ -28,7 +28,7 @@ Topology::Topology(const RuntimeEnvironment *renv, void *tPtr) :
|
|||
for (;;) {
|
||||
Identity id;
|
||||
int l = id.unmarshal(dptr, drem);
|
||||
if ((l > 0)&&(id)) {
|
||||
if ((l > 0) && (id)) {
|
||||
if ((drem -= l) <= 0)
|
||||
break;
|
||||
Locator *const loc = new Locator();
|
||||
|
@ -87,9 +87,9 @@ bool Topology::addRoot(void *const tPtr, const Identity &id, const SharedPtr<con
|
|||
bool Topology::removeRoot(void *const tPtr, Address address)
|
||||
{
|
||||
RWMutex::Lock l1(m_peers_l);
|
||||
for(Vector< SharedPtr<Peer> >::const_iterator r(m_rootPeers.begin());r!=m_rootPeers.end();++r) {
|
||||
for (Vector<SharedPtr<Peer> >::const_iterator r(m_rootPeers.begin());r != m_rootPeers.end();++r) {
|
||||
if ((*r)->address() == address) {
|
||||
Map< Identity,SharedPtr<const Locator> >::iterator rr(m_roots.find((*r)->identity()));
|
||||
Map<Identity, SharedPtr<const Locator> >::iterator rr(m_roots.find((*r)->identity()));
|
||||
if (rr != m_roots.end()) {
|
||||
m_roots.erase(rr);
|
||||
m_updateRootPeers(tPtr);
|
||||
|
@ -113,6 +113,8 @@ void Topology::doPeriodicTasks(void *tPtr, const int64_t now)
|
|||
{
|
||||
RWMutex::Lock l1(m_peers_l);
|
||||
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)) {
|
||||
i->second->save(tPtr);
|
||||
m_peers.erase(i++);
|
||||
|
@ -147,9 +149,9 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &pee
|
|||
Vector<uint8_t> data(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PEER, id));
|
||||
if (data.size() > 8) {
|
||||
const uint8_t *d = data.data();
|
||||
int dl = (int) data.size();
|
||||
int dl = (int)data.size();
|
||||
|
||||
const int64_t ts = (int64_t) Utils::loadBigEndian<uint64_t>(d);
|
||||
const int64_t ts = (int64_t)Utils::loadBigEndian<uint64_t>(d);
|
||||
Peer *const p = new Peer(RR);
|
||||
int n = p->unmarshal(d + 8, dl - 8);
|
||||
if (n < 0) {
|
||||
|
@ -173,7 +175,7 @@ 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,SharedPtr<const 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;
|
||||
|
@ -193,9 +195,9 @@ void Topology::m_writeRootList(void *tPtr)
|
|||
void Topology::m_updateRootPeers(void *tPtr)
|
||||
{
|
||||
// assumes m_peers_l is locked for write
|
||||
Vector< SharedPtr<Peer> > rp;
|
||||
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()));
|
||||
Vector<SharedPtr<Peer> > rp;
|
||||
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;
|
||||
|
|
Loading…
Add table
Reference in a new issue