A bunch of tweaks around CLI parameters and string formats of things.

This commit is contained in:
Adam Ierymenko 2020-06-02 11:37:04 -07:00
parent 8e29acd664
commit 5dac2e82a7
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
16 changed files with 215 additions and 211 deletions

View file

@ -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)
}

View file

@ -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() {

View file

@ -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()
}
}

View file

@ -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)
}

View file

@ -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":
}
}
}

View file

@ -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)

View file

@ -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}
}

View file

@ -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 {

View file

@ -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

View file

@ -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
*

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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 &lt = 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 &lt = 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 &lt = 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 &lt = 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()) {

View file

@ -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;

View file

@ -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;