1.12.0 merge to main (#2104)

* add note about forceTcpRelay

* Create a sample systemd unit for tcp proxy

* set gitattributes for rust & cargo so hashes dont conflict on Windows

* Revert "set gitattributes for rust & cargo so hashes dont conflict on Windows"

This reverts commit 032dc5c108.

* Turn off autocrlf for rust source

Doesn't appear to play nice well when it comes to git and vendored cargo package hashes

* Fix #1883 (#1886)

Still unknown as to why, but the call to `nc->GetProperties()` can fail
when setting a friendly name on the Windows virtual ethernet adapter.
Ensure that `ncp` is not null before continuing and accessing the device
GUID.

* Don't vendor packages for zeroidc (#1885)

* Added docker environment way to join networks (#1871)

* add StringUtils

* fix headers
use recommended headers and remove unused headers

* move extern "C"
only JNI functions need to be exported

* cleanup

* fix ANDROID-50: RESULT_ERROR_BAD_PARAMETER typo

* fix typo in log message

* fix typos in JNI method signatures

* fix typo

* fix ANDROID-51: fieldName is uninitialized

* fix ANDROID-35: memory leak

* fix missing DeleteLocalRef in loops

* update to use unique error codes

* add GETENV macro

* add LOG_TAG defines

* ANDROID-48: add ZT_jnicache.cpp

* ANDROID-48: use ZT_jnicache.cpp and remove ZT_jnilookup.cpp and ZT_jniarray.cpp

* add Event.fromInt

* add PeerRole.fromInt

* add ResultCode.fromInt

* fix ANDROID-36: issues with ResultCode

* add VirtualNetworkConfigOperation.fromInt

* fix ANDROID-40: VirtualNetworkConfigOperation out-of-sync with ZT_VirtualNetworkConfigOperation enum

* add VirtualNetworkStatus.fromInt

* fix ANDROID-37: VirtualNetworkStatus out-of-sync with ZT_VirtualNetworkStatus enum

* add VirtualNetworkType.fromInt

* make NodeStatus a plain data class

* fix ANDROID-52: synchronization bug with nodeMap

* Node init work: separate Node construction and init

* add Node.toString

* make PeerPhysicalPath a plain data class

* remove unused PeerPhysicalPath.fixed

* add array functions

* make Peer a plain data class

* make Version a plain data class

* fix ANDROID-42: copy/paste error

* fix ANDROID-49: VirtualNetworkConfig.equals is wrong

* reimplement VirtualNetworkConfig.equals

* reimplement VirtualNetworkConfig.compareTo

* add VirtualNetworkConfig.hashCode

* make VirtualNetworkConfig a plain data class

* remove unused VirtualNetworkConfig.enabled

* reimplement VirtualNetworkDNS.equals

* add VirtualNetworkDNS.hashCode

* make VirtualNetworkDNS a plain data class

* reimplement VirtualNetworkRoute.equals

* reimplement VirtualNetworkRoute.compareTo

* reimplement VirtualNetworkRoute.toString

* add VirtualNetworkRoute.hashCode

* make VirtualNetworkRoute a plain data class

* add isSocketAddressEmpty

* add addressPort

* add fromSocketAddressObject

* invert logic in a couple of places and return early

* newInetAddress and newInetSocketAddress work
allow newInetSocketAddress to return NULL if given empty address

* fix ANDROID-38: stack corruption in onSendPacketRequested

* use GETENV macro

* JniRef work
JniRef does not use callbacks struct, so remove
fix NewGlobalRef / DeleteGlobalRef mismatch

* use PRId64 macros

* switch statement work

* comments and logging

* Modifier 'public' is redundant for interface members

* NodeException can be made a checked Exception

* 'NodeException' does not define a 'serialVersionUID' field

* 'finalize()' should not be overridden
this is fine to do because ZeroTierOneService calls close() when it is done

* error handling, error reporting, asserts, logging

* simplify loadLibrary

* rename Node.networks -> Node.networkConfigs

* Windows file permissions fix (#1887)

* Allow macOS interfaces to use multiple IP addresses (#1879)

Co-authored-by: Sean OMeara <someara@users.noreply.github.com>
Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* Fix condition where full HELLOs might not be sent when necessary (#1877)

Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* 1.10.4 version bumps

* Add security policy to repo (#1889)

* [+] add e2k64 arch (#1890)

* temp fix for ANDROID-56: crash inside newNetworkConfig from too many args

* 1.10.4 release notes

* Windows 1.10.4 Advanced Installer bump

* Revert "temp fix for ANDROID-56: crash inside newNetworkConfig from too many args"

This reverts commit dd627cd7f4.

* actual fix for ANDROID-56: crash inside newNetworkConfig
cast all arguments to varargs functions as good style

* Fix addIp being called with applied ips (#1897)

This was getting called outside of the check for existing ips
Because of the added ifdef and a brace getting moved to the
wrong place.

```
if (! n.tap()->addIp(*ip)) {
	fprintf(stderr, "ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString(ipbuf));
}
WinFWHelper::newICMPRule(*ip, n.config().nwid);

```

* 1.10.5 (#1905)

* 1.10.5 bump

* 1.10.5 for Windows

* 1.10.5

* Prevent path-learning loops (#1914)

* Prevent path-learning loops

* Only allow new overwrite if not bonded

* fix binding temporary ipv6 addresses on macos (#1910)

The check code wasn't running.

I don't know why !defined(TARGET_OS_IOS) would exclude code on
desktop macOS. I did a quick search and changed it to defined(TARGET_OS_MAC).
Not 100% sure what the most correct solution there is.

You can verify the old and new versions with

`ifconfig | grep temporary`

plus

`zerotier-cli info -j` -> listeningOn

* 1.10.6 (#1929)

* 1.10.5 bump

* 1.10.6

* 1.10.6 AIP for Windows.

* Release notes for 1.10.6 (#1931)

* Minor tweak to Synology Docker image script (#1936)

* Change if_def again so ios can build (#1937)

All apple's variables are "defined"
but sometimes they are defined as "0"

* move begin/commit into try/catch block (#1932)

Thread was exiting in some cases

* Bump openssl from 0.10.45 to 0.10.48 in /zeroidc (#1938)

Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.45 to 0.10.48.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.45...openssl-v0.10.48)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* new drone bits

* Fix multiple network join from environment entrypoint.sh.release (#1961)

* _bond_m guards _bond, not _paths_m (#1965)

* Fix: warning: mutex '_aqm_m' is not held on every path through here [-Wthread-safety-analysis] (#1964)

* Bump h2 from 0.3.16 to 0.3.17 in /zeroidc (#1963)

Bumps [h2](https://github.com/hyperium/h2) from 0.3.16 to 0.3.17.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.16...v0.3.17)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* Add note that binutils is required on FreeBSD (#1968)

* Add prometheus metrics for Central controllers (#1969)

* add header-only prometheus lib to ext

* rename folder

* Undo rename directory

* prometheus simpleapi included on mac & linux

* wip

* wire up some controller stats

* Get windows building with prometheus

* bsd build flags for prometheus

* Fix multiple network join from environment entrypoint.sh.release (#1961)

* _bond_m guards _bond, not _paths_m (#1965)

* Fix: warning: mutex '_aqm_m' is not held on every path through here [-Wthread-safety-analysis] (#1964)

* Serve prom metrics from /metrics endpoint

* Add prom metrics for Central controller specific things

* reorganize metric initialization

* testing out a labled gauge on Networks

* increment error counter on throw

* Consolidate metrics definitions

Put all metric definitions into node/Metrics.hpp.  Accessed as needed
from there.

* Revert "testing out a labled gauge on Networks"

This reverts commit 499ed6d95e.

* still blows up but adding to the record for completeness right now

* Fix runtime issues with metrics

* Add metrics files to visual studio project

* Missed an "extern"

* add copyright headers to new files

* Add metrics for sent/received bytes (total)

* put /metrics endpoint behind auth

* sendto returns int on Win32

---------

Co-authored-by: Leonardo Amaral <leleobhz@users.noreply.github.com>
Co-authored-by: Brenton Bostick <bostick@gmail.com>

* Central startup update (#1973)

* allow specifying authtoken in central startup

* set allowManagedFrom

* move redis_mem_notification to the correct place

* add node checkins metric

* wire up min/max connection pool size metrics

* x86_64-unknown-linux-gnu on ubuntu runner (#1975)

* adding incoming zt packet type metrics (#1976)

* use cpp-httplib for HTTP control plane (#1979)

refactored the old control plane code to use [cpp-httplib](https://github.com/yhirose/cpp-httplib) instead of a hand rolled HTTP server.  Makes the control plane code much more legible.  Also no longer randomly stops responding.

* Outgoing Packet Metrics (#1980)

add tx/rx labels to packet counters and add metrics for outgoing packets

* Add short-term validation test workflow (#1974)

Add short-term validation test workflow

* Brenton/curly braces (#1971)

* fix formatting

* properly adjust various lines
breakup multiple statements onto multiple lines

* insert {} around if, for, etc.

* Fix rust dependency caching (#1983)

* fun with rust caching

* kick

* comment out invalid yaml keys for now

* Caching should now work

* re-add/rename key directives

* bump

* bump

* bump

* Don't force rebuild on Windows build GH Action (#1985)

Switching `/t:ZeroTierOne:Rebuild` to just `/t:ZeroTierOne` allows the Windows build to use the rust cache.  `/t:ZeroTierOne:Rebuild` cleared the cache before building.

* More packet metrics (#1982)

* found path negotation sends that weren't accounted for

* Fix histogram so it will actually compile

* Found more places for packet metrics

* separate the bind & listen calls on the http backplane (#1988)

* fix memory leak (#1992)

* fix a couple of metrics (#1989)

* More aggressive CLI spamming (#1993)

* fix type signatures (#1991)

* Network-metrics (#1994)

* Add a couple quick functions for converting a uint64_t network ID/node ID into std::string

* Network metrics

* Peer metrics (#1995)

* Adding peer metrics

still need to be wired up for use

* per peer packet metrics

* Fix crash from bad instantiation of histogram

* separate alive & dead path counts

* Add peer metric update block

* add peer latency values in doPingAndKeepalive

* prevent deadlock

* peer latency histogram actually works now

* cleanup

* capture counts of packets to specific peers

---------

Co-authored-by: Joseph Henry <joseph.henry@zerotier.com>

* Metrics consolidation (#1997)

* Rename zt_packet_incoming -> zt_packet

Also consolidate zt_peer_packets into a single metric with tx and rx labels.  Same for ztc_tcp_data and ztc_udp_data

* Further collapse tcp & udp into metric labels for zt_data

* Fix zt_data metric description

* zt_peer_packets description fix

* Consolidate incoming/outgoing network packets to a single metric

* zt_incoming_packet_error -> zt_packet_error

* Disable peer metrics for central controllers

Can change in the future if needed, but given the traffic our controllers serve, that's going to be a *lot* of data

* Disable peer metrics for controllers pt 2

* Update readme files for metrics (#2000)

* Controller Metrics & Network Config Request Fix (#2003)

* add new metrics for network config request queue size and sso expirations
* move sso expiration to its own thread in the controller
* fix potential undefined behavior when modifying a set

* Enable RTTI in Windows build

The new prometheus histogram stuff needs it.

Access violation - no RTTI data!INVALID packet 636ebd9ee8cac6c0 from cafe9efeb9(2605:9880:200:1200:30:571:e34:51/9993) (unexpected exception in tryDecode())

* Don't re-apply routes on BSD

See issue #1986

* Capture setContent by-value instead of by-reference (#2006)

Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* fix typos (#2010)

* central controller metrics & request path updates (#2012)

* internal db metrics

* use shared mutexes for read/write locks

* remove this lock. only used for a metric

* more metrics

* remove exploratory metrics

place controller request benchmarks behind ifdef

* Improve validation test (#2013)

* fix init order for EmbeddedNetworkController (#2014)

* add constant for getifaddrs cache time

* cache getifaddrs - mac

* cache getifaddrs - linux

* cache getifaddrs - bsd

* cache getifaddrs - windows

* Fix oidc client lookup query

join condition referenced the wrong table.  Worked fine unless there were multiple identical client IDs

* Fix udp sent metric

was only incrementing by 1 for each packet sent

* Allow sending all surface addresses to peer in low-bandwidth mode

* allow enabling of low bandwidth mode on controllers

* don't unborrow bad connections

pool will clean them up later

* Multi-arch controller container (#2037)

create arm64 & amd64 images for central controller

* Update README.md

issue #2009

* docker tags change

* fix oidc auth url memory leak (#2031)

getAuthURL() was not calling zeroidc::free_cstr(url);

the only place authAuthURL is called, the url can be retrieved
from the network config instead.

You could alternatively copy the string and call free_cstr in getAuthURL.
If that's better we can change the PR.

Since now there are no callers of getAuthURL I deleted it.

Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* Bump openssl from 0.10.48 to 0.10.55 in /zeroidc (#2034)

Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.48 to 0.10.55.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.55)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* zeroidc cargo warnings (#2029)

* fix unused struct member cargo warning

* fix unused import cargo warning

* fix unused return value cargo warning

---------

Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* fix memory leak in macos ipv6/dns helper (#2030)

Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>

* Consider ZEROTIER_JOIN_NETWORKS in healthcheck (#1978)

* Add a 2nd auth token only for access to /metrics (#2043)

* Add a 2nd auth token for /metrics

Allows administrators to distribute a token that only has access to read
metrics and nothing else.

Also added support for using bearer auth tokens for both types of tokens

Separate endpoint for metrics #2041

* Update readme

* fix a couple of cases of writing the wrong token

* Add warning to cli for allow default on FreeBSD

It doesn't work.
Not possible to fix with deficient network
stack and APIs.

ZeroTierOne-freebsd # zerotier-cli set 9bee8941b5xxxxxx allowDefault=1
400 set Allow Default does not work properly on FreeBSD. See #580
root@freebsd13-a:~/ZeroTierOne-freebsd # zerotier-cli get 9bee8941b5xxxxxx allowDefault
1

* ARM64 Support for TapDriver6 (#1949)

* Release memory previously allocated by UPNP_GetValidIGD

* Fix ifdef that breaks libzt on iOS (#2050)

* less drone (#2060)

* Exit if loading an invalid identity from disk (#2058)

* Exit if loading an invalid identity from disk

Previously, if an invalid identity was loaded from disk, ZeroTier would
generate a new identity & chug along and generate a brand new identity
as if nothing happened.  When running in containers, this introduces the
possibility for key matter loss; especially when running in containers
where the identity files are mounted in the container read only.  In
this case, ZT will continue chugging along with a brand new identity
with no possibility of recovering the private key.

ZeroTier should exit upon loading of invalid identity.public/identity.secret #2056

* add validation test for #2056

* tcp-proxy: fix build

* Adjust tcp-proxy makefile to support metrics

There's no way to get the metrics yet. Someone will
have to add the http service.

* remove ZT_NO_METRIC ifdef

* Implement recvmmsg() for Linux to reduce syscalls. (#2046)

Between 5% and 40% speed improvement on Linux, depending on system configuration and load.

* suppress warnings: comparison of integers of different signs: 'int64_t' (aka 'long') and 'uint64_t' (aka 'unsigned long') [-Wsign-compare] (#2063)

* fix warning: 'OS_STRING' macro redefined [-Wmacro-redefined] (#2064)

Even though this is in ext, these particular chunks of code were added
by us, so are ok to modify.

* Apply default route a different way - macOS

The original way we applied default route, by forking
0.0.0.0/0 into 0/1 and 128/1 works, but if mac os has any networking
hiccups -if you change SSIDs or sleep/wake- macos erases the system default route.
And then all networking on the computer is broken.

to summarize the new way:
allowDefault=1
```
sudo route delete default 192.168.82.1
sudo route add default 10.2.0.2
sudo route add -ifscope en1 default 192.168.82.1
```

gives us this routing table
```
Destination        Gateway            RT_IFA             Flags        Refs      Use    Mtu          Netif Expire    rtt(ms) rttvar(ms)
default            10.2.0.2           10.2.0.18          UGScg          90        1   2800       feth4823
default            192.168.82.1       192.168.82.217     UGScIg
```

allowDefault=0
```
sudo route delete default
sudo route delete -ifscope en1 default
sudo route add default 192.168.82.1
```

Notice the I flag, for -ifscope, on the physical default route.

route change does not seem to work reliably.

* fix docker tag for controllers (#2066)

* Update build.sh (#2068)

fix mkwork compilation errors

* Fix network DNS on macOS

It stopped working for ipv4 only networks in Monterey.
See #1696

We add some config like so to System Configuration

```
scutil
show State:/Network/Service/9bee8941b5xxxxxx/IPv4
<dictionary> {
  Addresses : <array> {
    0 : 10.2.1.36
  }
  InterfaceName : feth4823
  Router : 10.2.1.36
  ServerAddress : 127.0.0.1
}

```

* Add search domain to macos dns configuration

Stumbled upon this while debugging something else.
If we add search domain to our system configuration for
network DNS, then search domains work:

```
ping server1                                                                                                                                                                                    ~
PING server1.my.domain (10.123.3.1): 56 data bytes
64 bytes from 10.123.3.1
```

* Fix reporting of secondaryPort and tertiaryPort See: #2039

* Fix typos (#2075)

* Disable executable stacks on assembly objects (#2071)

Add `--noexecstack` to the assembler flags so the resulting binary
will link with a non-executable stack.

Fixes zerotier/ZeroTierOne#1179

Co-authored-by: Joseph Henry <joseph.henry@zerotier.com>

* Test that starting zerotier before internet works

* Don't skip hellos when there are no paths available

working on #2082

* Update validate-1m-linux.sh

* Save zt node log files on abort

* Separate test and summary step in validator script

* Don't apply default route until zerotier is "online"

I was running into issues with restarting the zerotier service while
"full tunnel" mode is enabled.
When zerotier first boots, it gets network state from the cache
on disk. So it immediately applies all the routes it knew about
before it shutdown.
The network config may have change in this time.
If it has, then your default route is via a route
you are blocked from talking on. So you  can't get the current
network config, so your internet does not work.

Other options include
- don't use cached network state on boot
- find a better criteria than "online"

* Fix node time-to-online counter in validator script

* Export variables so that they are accessible by exit function

* Fix PortMapper issue on ZeroTier startup

See issue #2082

We use a call to libnatpmp::ininatpp to make sure the computer
has working network sockets before we go into the main
nat-pmp/upnp logic.

With basic exponenetial delay up to 30 seconds.

* testing

* Comment out PortMapper debug

this got left turned on in a confusing merge previously

* fix macos default route again

see commit fb6af1971 * Fix network DNS on macOS
adding that stuff to System Config causes this extra route to be added
which breaks ipv4 default route.
We figured out a weird System Coniguration setting
that works.

--- old
couldn't figure out how to fix it in SystemConfiguration
so here we are# Please enter the commit message for your changes. Lines starting

We also moved the dns setter to before the syncIps stuff
to help with a race condition. It didn't always work when
you re-joined a network with default route enabled.

* Catch all conditions in switch statement, remove trailing whitespaces

* Add setmtu command, fix bond lifetime issue

* Basic cleanups

* Check if null is passed to VirtualNetworkConfig.equals and name fixes

* ANDROID-96: Simplify and use return code from node_init directly

* Windows arm64 (#2099)

* ARM64 changes for 1.12

* 1.12 Windows advanced installer updates and updates for ARM64

* 1.12.0

* Linux build fixes for old distros.

* release notes

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: travis laduke <travisladuke@gmail.com>
Co-authored-by: Grant Limberg <grant.limberg@zerotier.com>
Co-authored-by: Grant Limberg <glimberg@users.noreply.github.com>
Co-authored-by: Leonardo Amaral <leleobhz@users.noreply.github.com>
Co-authored-by: Brenton Bostick <bostick@gmail.com>
Co-authored-by: Sean OMeara <someara@users.noreply.github.com>
Co-authored-by: Joseph Henry <joseph-henry@users.noreply.github.com>
Co-authored-by: Roman Peshkichev <roman.peshkichev@gmail.com>
Co-authored-by: Joseph Henry <joseph.henry@zerotier.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stavros Kois <47820033+stavros-k@users.noreply.github.com>
Co-authored-by: Jake Vis <jakevis@outlook.com>
Co-authored-by: Jörg Thalheim <joerg@thalheim.io>
Co-authored-by: lison <imlison@foxmail.com>
Co-authored-by: Kenny MacDermid <kenny@macdermid.ca>
This commit is contained in:
Adam Ierymenko 2023-08-23 14:24:21 -04:00 committed by GitHub
commit 0e5651f353
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
536 changed files with 48293 additions and 6671 deletions

View file

@ -136,8 +136,9 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
if (_rp) {
for (;;) {
if (!len)
if (!len) {
return;
}
--len;
_r[_rp++] = *(in++);
if (_rp == 16) {
@ -160,8 +161,9 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
_y[0] = y0;
_y[1] = y1;
for (unsigned int i = 0; i < len; ++i)
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
}
@ -187,8 +189,9 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
uint64_t y1 = _y[1];
if (_rp) {
while (_rp < 16)
while (_rp < 16) {
_r[_rp++] = 0;
}
y0 ^= Utils::loadMachineEndian< uint64_t >(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8);
s_gfmul(h0, h1, y0, y1);
@ -247,8 +250,9 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
_aes.p_encryptSW(reinterpret_cast<const uint8_t *>(_ctr), reinterpret_cast<uint8_t *>(keyStream));
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(++ctr);
uint8_t *outblk = out + (totalLen - 16);
for (int i = 0; i < 16; ++i)
for (int i = 0; i < 16; ++i) {
outblk[i] ^= reinterpret_cast<uint8_t *>(keyStream)[i];
}
break;
}
}
@ -442,8 +446,9 @@ void AES::CTR::finish() noexcept
const unsigned int rem = _len & 15U;
if (rem) {
_aes.encrypt(_ctr, tmp);
for (unsigned int i = 0, j = _len - rem; i < rem; ++i)
for (unsigned int i = 0, j = _len - rem; i < rem; ++i) {
_out[j + i] ^= tmp[i];
}
}
}
@ -497,8 +502,9 @@ void AES::p_initSW(const uint8_t *key) noexcept
rk[9] = rk[1] ^ rk[8];
rk[10] = rk[2] ^ rk[9];
rk[11] = rk[3] ^ rk[10];
if (++i == 7)
if (++i == 7) {
break;
}
temp = rk[11];
rk[12] = rk[4] ^ (Te2_r(temp >> 24U) & 0xff000000U) ^ (Te3_r((temp >> 16U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp >> 8U) & 0xffU] & 0x0000ff00U) ^ (Te1_r((temp) & 0xffU) & 0x000000ffU);
rk[13] = rk[5] ^ rk[12];
@ -511,8 +517,9 @@ void AES::p_initSW(const uint8_t *key) noexcept
p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]);
p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]);
for (int i = 0; i < 60; ++i)
for (int i = 0; i < 60; ++i) {
p_k.sw.dk[i] = p_k.sw.ek[i];
}
rk = p_k.sw.dk;
for (int i = 0, j = 56; i < j; i += 4, j -= 4) {

View file

@ -197,8 +197,9 @@ public:
*reinterpret_cast<uint32_t *>(_iv + 8) = *reinterpret_cast<const uint64_t *>(iv + 8);
*reinterpret_cast<uint32_t *>(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order
#else
for(int i=0;i<12;++i)
for(int i=0;i<12;++i) {
_iv[i] = iv[i];
}
_iv[12] = 0;
_iv[13] = 0;
_iv[14] = 0;
@ -373,8 +374,9 @@ public:
// End of AAD is padded to a multiple of 16 bytes to ensure unique encoding.
len &= 0xfU;
if (len != 0)
if (len != 0) {
_gmac.update(Utils::ZERO256, 16 - len);
}
}
/**
@ -495,8 +497,9 @@ public:
{
_gmac.update(aad, len);
len &= 0xfU;
if (len != 0)
if (len != 0) {
_gmac.update(Utils::ZERO256, 16 - len);
}
}
/**

View file

@ -228,8 +228,9 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
// Handle anything left over from a previous run that wasn't a multiple of 16 bytes.
if (_rp) {
for (;;) {
if (!len)
if (!len) {
return;
}
--len;
_r[_rp++] = *(in++);
if (_rp == 16) {
@ -281,8 +282,9 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
_mm_storeu_si128(reinterpret_cast<__m128i *>(_y), y);
// Any overflow is cached for a later run or finish().
for (unsigned int i = 0; i < len; ++i)
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
}
@ -295,8 +297,9 @@ void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
// Handle any remaining bytes, padding the last block with zeroes.
if (_rp) {
while (_rp < 16)
while (_rp < 16) {
_r[_rp++] = 0;
}
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r))));
}
@ -438,9 +441,9 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
goto skip_conventional_aesni_64;
}
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
goto skip_conventional_aesni_64;
}
#endif
const uint8_t *const eof64 = in + (len & ~((unsigned int)63));
@ -552,8 +555,9 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
// Any remaining input is placed in _out. This will be picked up and crypted
// on subsequent calls to crypt() or finish() as it'll mean _len will not be
// an even multiple of 16.
for (unsigned int i = 0; i < len; ++i)
for (unsigned int i = 0; i < len; ++i) {
out[i] = in[i];
}
_ctr[1] = Utils::hton(c1);
}

View file

@ -56,8 +56,9 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
if (_rp) {
for(;;) {
if (!len)
if (!len) {
return;
}
--len;
_r[_rp++] = *(in++);
if (_rp == 16) {
@ -75,8 +76,9 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
vst1q_u8(reinterpret_cast<uint8_t *>(_y), y);
for (unsigned int i = 0; i < len; ++i)
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
}
@ -87,8 +89,9 @@ void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) {
while (_rp < 16)
while (_rp < 16) {
_r[_rp++] = 0;
}
y = s_clmul_armneon_crypto(h, y, _r);
}
@ -255,8 +258,9 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
in += 64;
dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, four);
if (unlikely(len < 64))
if (unlikely(len < 64)) {
break;
}
dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, four);
dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, four);
dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd3, four);
@ -290,8 +294,9 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
// Any remaining input is placed in _out. This will be picked up and crypted
// on subsequent calls to crypt() or finish() as it'll mean _len will not be
// an even multiple of 16.
for (unsigned int i = 0; i < len; ++i)
for (unsigned int i = 0; i < len; ++i) {
out[i] = in[i];
}
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd));
}
@ -327,12 +332,14 @@ void AES::p_init_armneon_crypto(const uint8_t *key) noexcept
w[i] = w[i - ZT_INIT_ARMNEON_CRYPTO_NK] ^ t;
}
for (unsigned int i=0;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i)
for (unsigned int i=0;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) {
w[i] = Utils::hton(w[i]);
}
p_k.neon.dk[0] = p_k.neon.ek[14];
for (int i=1;i<14;++i)
for (int i=1;i<14;++i) {
p_k.neon.dk[i] = vaesimcq_u8(p_k.neon.ek[14 - i]);
}
p_k.neon.dk[14] = p_k.neon.ek[0];
p_encrypt_armneon_crypto(Utils::ZERO256, h);

View file

@ -71,8 +71,9 @@ public:
*/
inline void copyTo(void *const bits,const unsigned int len) const
{
if (len < ZT_ADDRESS_LENGTH)
if (len < ZT_ADDRESS_LENGTH) {
return;
}
unsigned char *b = (unsigned char *)bits;
*(b++) = (unsigned char)((_a >> 32) & 0xff);
*(b++) = (unsigned char)((_a >> 24) & 0xff);

View file

@ -20,6 +20,11 @@
#include <string>
#include <cinttypes> // for PRId64, etc. macros
// FIXME: remove this suppression and actually fix warnings
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
namespace ZeroTier {
static unsigned char s_freeRandomByteCounter = 0;
@ -97,6 +102,43 @@ SharedPtr<Bond> Bond::getBondByPeerId(int64_t identity)
return _bonds.count(identity) ? _bonds[identity] : SharedPtr<Bond>();
}
bool Bond::setAllMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr)
{
Mutex::Lock _l(_bonds_m);
std::map<int64_t, SharedPtr<Bond> >::iterator bondItr = _bonds.begin();
bool found = false;
while (bondItr != _bonds.end()) {
if (bondItr->second->setMtuByTuple(mtu,ifStr,ipStr)) {
found = true;
}
++bondItr;
}
return found;
}
bool Bond::setMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr)
{
Mutex::Lock _lp(_paths_m);
bool found = false;
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
SharedPtr<Link> sl = getLink(_paths[i].p);
if (sl) {
if (sl->ifname() == ifStr) {
char ipBuf[64] = { 0 };
_paths[i].p->address().toIpString(ipBuf);
std::string newString = std::string(ipBuf);
if (newString == ipStr) {
_paths[i].p->_mtu = mtu;
found = true;
}
}
}
}
}
return found;
}
SharedPtr<Bond> Bond::createBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer)
{
Mutex::Lock _l(_bonds_m);
@ -112,13 +154,11 @@ SharedPtr<Bond> Bond::createBond(const RuntimeEnvironment* renv, const SharedPtr
bond = new Bond(renv, _bondPolicyTemplates[_defaultPolicyStr].ptr(), peer);
bond->debug("new default custom bond (based on %s)", bond->getPolicyStrByCode(bond->policy()).c_str());
}
}
else {
} else {
if (! _bondPolicyTemplates[_policyTemplateAssignments[identity]]) {
bond = new Bond(renv, _defaultPolicy, peer);
bond->debug("peer-specific bond, was specified as %s but the bond definition was not found, using default %s", _policyTemplateAssignments[identity].c_str(), getPolicyStrByCode(_defaultPolicy).c_str());
}
else {
} else {
bond = new Bond(renv, _bondPolicyTemplates[_policyTemplateAssignments[identity]].ptr(), peer);
bond->debug("new default bond");
}
@ -159,8 +199,8 @@ void Bond::destroyBond(uint64_t peerId)
auto iter = _bonds.find(peerId);
if (iter != _bonds.end()) {
iter->second->stopBond();
_bonds.erase(iter);
}
_bonds.erase(peerId);
}
void Bond::stopBond()
@ -187,12 +227,10 @@ SharedPtr<Link> Bond::getLinkBySocket(const std::string& policyAlias, uint64_t l
SharedPtr<Link> s = new Link(ifnameStr, 0, 0, 0, true, ZT_BOND_SLAVE_MODE_PRIMARY, "");
_interfaceToLinkMap[policyAlias].insert(std::pair<std::string, SharedPtr<Link> >(ifnameStr, s));
return s;
}
else {
} else {
return SharedPtr<Link>();
}
}
else {
} else {
return search->second;
}
}
@ -359,8 +397,7 @@ SharedPtr<Path> Bond::getAppropriatePath(int64_t now, int32_t flowId)
_rrPacketsSentOnCurrLink = 0;
if (_numBondedPaths == 1 || _rrIdx >= (ZT_MAX_PEER_NETWORK_PATHS - 1)) {
_rrIdx = 0;
}
else {
} else {
int _tempIdx = _rrIdx;
for (int searchCount = 0; searchCount < (_numBondedPaths - 1); searchCount++) {
_tempIdx = (_tempIdx == (_numBondedPaths - 1)) ? 0 : _tempIdx + 1;
@ -390,8 +427,7 @@ SharedPtr<Path> Bond::getAppropriatePath(int64_t now, int32_t flowId)
if (likely(it != _flows.end())) {
it->second->lastActivity = now;
return _paths[it->second->assignedPath].p;
}
else {
} else {
unsigned char entropy;
Utils::getSecureRandom(&entropy, 1);
SharedPtr<Flow> flow = createFlow(ZT_MAX_PEER_NETWORK_PATHS, flowId, entropy, now);
@ -469,8 +505,7 @@ void Bond::recordIncomingPacket(const SharedPtr<Path>& path, uint64_t packetId,
_paths[pathIdx].qosStatsIn[packetId] = now;
++(_paths[pathIdx].packetsReceivedSinceLastQoS);
//_paths[pathIdx].packetValiditySamples.push(true);
}
else {
} else {
// debug("QoS buffer full, will not record information");
}
/*
@ -497,8 +532,7 @@ void Bond::recordIncomingPacket(const SharedPtr<Path>& path, uint64_t packetId,
SharedPtr<Flow> flow;
if (! _flows.count(flowId)) {
flow = createFlow(pathIdx, flowId, 0, now);
}
else {
} else {
flow = _flows[flowId];
}
if (flow) {
@ -584,8 +618,7 @@ bool Bond::assignFlowToBondedPath(SharedPtr<Flow>& flow, int64_t now, bool reass
if (reassign) {
log("attempting to re-assign out-flow %04x previously on idx %d (%u / %zu flows)", flow->id, flow->assignedPath, _paths[_realIdxMap[flow->assignedPath]].assignedFlowCount, _flows.size());
}
else {
} else {
debug("attempting to assign flow for the first time");
}
@ -599,8 +632,7 @@ bool Bond::assignFlowToBondedPath(SharedPtr<Flow>& flow, int64_t now, bool reass
if (reassign) {
bondedIdx = (flow->assignedPath + offset) % (_numBondedPaths);
}
else {
} else {
bondedIdx = abs((int)((entropy + offset) % (_numBondedPaths)));
}
// debug("idx=%d, offset=%d, randomCap=%f, actualCap=%f", bondedIdx, offset, randomLinkCapacity, _paths[_realIdxMap[bondedIdx]].relativeLinkCapacity);
@ -623,8 +655,7 @@ bool Bond::assignFlowToBondedPath(SharedPtr<Flow>& flow, int64_t now, bool reass
flow->assignPath(_realIdxMap[bondedIdx], now);
++(_paths[_realIdxMap[bondedIdx]].assignedFlowCount);
// debug(" ABLE to find optimal link %f idx %d", _paths[_realIdxMap[bondedIdx]].relativeQuality, bondedIdx);
}
else {
} else {
// We were (unable) to find a path that didn't violate at least one quality requirement, will choose next best option
flow->assignPath(_realIdxMap[nextBestQualIdx], now);
++(_paths[_realIdxMap[nextBestQualIdx]].assignedFlowCount);
@ -684,13 +715,11 @@ void Bond::forgetFlowsWhenNecessary(uint64_t age, bool oldest, int64_t now)
debug("forget flow %04x (age %" PRId64 ") (%u / %zu)", it->first, it->second->age(now), _paths[it->second->assignedPath].assignedFlowCount, (_flows.size() - 1));
_paths[it->second->assignedPath].assignedFlowCount--;
it = _flows.erase(it);
}
else {
} else {
++it;
}
}
}
else if (oldest) { // Remove single oldest by natural expiration
} else if (oldest) { // Remove single oldest by natural expiration
uint64_t maxAge = 0;
while (it != _flows.end()) {
if (it->second->age(now) > maxAge) {
@ -737,8 +766,7 @@ void Bond::processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>&
if (_peer->_id.address().toInt() > RR->node->identity().address().toInt()) {
debug("agree with peer to use alternate link %s/%s\n", link->ifname().c_str(), pathStr);
_negotiatedPathIdx = pathIdx;
}
else {
} else {
debug("ignore petition from peer to use alternate link %s/%s\n", link->ifname().c_str(), pathStr);
}
}
@ -809,6 +837,7 @@ void Bond::sendPATH_NEGOTIATION_REQUEST(void* tPtr, int pathIdx)
Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_PATH_NEGOTIATION_REQUEST);
outp.append<int16_t>(_localUtility);
if (_paths[pathIdx].p->address()) {
Metrics::pkt_path_negotiation_request_out++;
outp.armor(_peer->key(), false, _peer->aesKeysIfSupported());
RR->node->putPacket(tPtr, _paths[pathIdx].p->localSocket(), _paths[pathIdx].p->address(), outp.data(), outp.size());
_overheadBytes += outp.size();
@ -852,10 +881,10 @@ void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, con
if (atAddress) {
outp.armor(_peer->key(), false, _peer->aesKeysIfSupported());
RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size());
}
else {
} else {
RR->sw->send(tPtr, outp, false);
}
Metrics::pkt_qos_out++;
_paths[pathIdx].packetsReceivedSinceLastQoS = 0;
_paths[pathIdx].lastQoSMeasurement = now;
_overheadBytes += outp.size();
@ -892,6 +921,7 @@ void Bond::processBackgroundBondTasks(void* tPtr, int64_t now)
RR->node->putPacket(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), outp.data(), outp.size());
_paths[i].p->_lastOut = now;
_overheadBytes += outp.size();
Metrics::pkt_echo_out++;
// debug("tx: verb 0x%-2x of len %4d via %s (ECHO)", Packet::VERB_ECHO, outp.size(), pathToStr(_paths[i].p).c_str());
}
}
@ -985,7 +1015,7 @@ void Bond::curateBond(int64_t now, bool rebuildBond)
// Whether we've waited long enough since the link last came online
bool satisfiedUpDelay = (now - _paths[i].lastAliveToggle) >= _upDelay;
// How long since the last QoS was received (Must be less than ZT_PEER_PATH_EXPIRATION since the remote peer's _qosSendInterval isn't known)
bool acceptableQoSAge = _paths[i].lastQoSReceived == 0 || ((now - _paths[i].lastQoSReceived) < ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD);
bool acceptableQoSAge = (_paths[i].lastQoSReceived == 0 && inTrial) || ((now - _paths[i].lastQoSReceived) < ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD);
currEligibility = _paths[i].allowed() && ((acceptableAge && satisfiedUpDelay && acceptableQoSAge) || inTrial);
if (currEligibility) {
@ -1077,7 +1107,7 @@ void Bond::curateBond(int64_t now, bool rebuildBond)
// Bond a spare link if required (no viable primary links left)
if (! foundUsablePrimaryPath) {
debug("no usable primary links remain, will attempt to use spare if available");
// debug("no usable primary links remain, will attempt to use spare if available");
for (int j = 0; j < it->second.size(); j++) {
int idx = it->second.at(j);
if (! _paths[idx].p || ! _paths[idx].eligible || ! _paths[idx].allowed() || ! _paths[idx].isSpare()) {
@ -1192,8 +1222,7 @@ void Bond::estimatePathQuality(int64_t now)
if ((now - it->second) >= qosRecordTimeout) {
it = _paths[i].qosStatsOut.erase(it);
++numDroppedQosOutRecords;
}
else {
} else {
++it;
}
}
@ -1221,8 +1250,7 @@ void Bond::estimatePathQuality(int64_t now)
if ((now - it->second) >= qosRecordTimeout) {
it = _paths[i].qosStatsIn.erase(it);
++numDroppedQosInRecords;
}
else {
} else {
++it;
}
}
@ -1253,7 +1281,8 @@ void Bond::estimatePathQuality(int64_t now)
if (link) {
int linkSpeed = link->capacity();
_paths[i].p->_givenLinkSpeed = linkSpeed;
_paths[i].p->_mtu = link->mtu();
_paths[i].p->_mtu = link->mtu() ? link->mtu() : _paths[i].p->_mtu;
_paths[i].p->_assignedFlowCount = _paths[i].assignedFlowCount;
maxObservedLinkCap = linkSpeed > maxObservedLinkCap ? linkSpeed : maxObservedLinkCap;
}
}
@ -1341,8 +1370,7 @@ void Bond::estimatePathQuality(int64_t now)
shouldAvoid = true;
}
_paths[i].shouldAvoid = shouldAvoid;
}
else {
} else {
if (! shouldAvoid) {
log("no longer avoiding link %s", pathToStr(_paths[i].p).c_str());
_paths[i].shouldAvoid = false;
@ -1454,8 +1482,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
_lastBondStatusLog = now;
if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) {
log("no active link");
}
else if (_paths[_abPathIdx].p) {
} else if (_paths[_abPathIdx].p) {
log("active link is %s, failover queue size is %zu", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size());
}
if (_abFailoverQueue.empty()) {
@ -1563,8 +1590,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
log("link %s is ineligible, removing from failover queue (%zu links remain in queue)", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size());
}
continue;
}
else {
} else {
++it;
}
}
@ -1713,8 +1739,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
if (! _abFailoverQueue.empty()) {
dequeueNextActiveBackupPath(now);
log("active link switched to %s", pathToStr(_paths[_abPathIdx].p).c_str());
}
else {
} else {
log("failover queue is empty, no links to choose from");
}
}
@ -1760,8 +1785,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
dequeueNextActiveBackupPath(now);
_lastPathNegotiationCheck = now;
log("switch negotiated link %s (select mode: optimize)", pathToStr(_paths[_abPathIdx].p).c_str());
}
else {
} else {
// Try to find a better path and automatically switch to it -- not too often, though.
if ((now - _lastActiveBackupPathChange) > ZT_BOND_OPTIMIZE_INTERVAL) {
if (! _abFailoverQueue.empty()) {

View file

@ -456,6 +456,26 @@ class Bond {
*/
static SharedPtr<Bond> getBondByPeerId(int64_t identity);
/**
* Set MTU for link by given interface name and IP address (across all bonds)
*
* @param mtu MTU to be used on this link
* @param ifStr interface name to match
* @param ipStr IP address to match
* @return Whether the MTU was set
*/
static bool setAllMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr);
/**
* Set MTU for link by given interface name and IP address
*
* @param mtu MTU to be used on this link
* @param ifStr interface name to match
* @param ipStr IP address to match
* @return Whether the MTU was set
*/
bool setMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr);
/**
* Add a new bond to the bond controller.
*
@ -889,8 +909,7 @@ class Bond {
_lastAckRateCheck = now;
if (_ackCutoffCount > numToDrain) {
_ackCutoffCount -= numToDrain;
}
else {
} else {
_ackCutoffCount = 0;
}
return (_ackCutoffCount < ZT_ACK_CUTOFF_LIMIT);
@ -909,8 +928,7 @@ class Bond {
uint64_t diff = now - _lastQoSRateCheck;
if ((diff) <= (_qosSendInterval / ZT_MAX_PEER_NETWORK_PATHS)) {
++_qosCutoffCount;
}
else {
} else {
_qosCutoffCount = 0;
}
_lastQoSRateCheck = now;
@ -930,8 +948,7 @@ class Bond {
int diff = now - _lastPathNegotiationReceived;
if ((diff) <= (ZT_PATH_NEGOTIATION_CUTOFF_TIME / ZT_MAX_PEER_NETWORK_PATHS)) {
++_pathNegotiationCutoffCount;
}
else {
} else {
_pathNegotiationCutoffCount = 0;
}
_lastPathNegotiationReceived = now;
@ -1228,20 +1245,17 @@ class Bond {
unsigned int suggestedRefractoryPeriod = refractoryPeriod ? punishment + (refractoryPeriod * 2) : punishment;
refractoryPeriod = std::min(suggestedRefractoryPeriod, (unsigned int)ZT_BOND_MAX_REFRACTORY_PERIOD);
lastRefractoryUpdate = 0;
}
else {
} else {
uint32_t drainRefractory = 0;
if (lastRefractoryUpdate) {
drainRefractory = (now - lastRefractoryUpdate);
}
else {
} else {
drainRefractory = (now - lastAliveToggle);
}
lastRefractoryUpdate = now;
if (refractoryPeriod > drainRefractory) {
refractoryPeriod -= drainRefractory;
}
else {
} else {
refractoryPeriod = 0;
lastRefractoryUpdate = 0;
}

View file

@ -81,8 +81,9 @@ public:
Buffer(unsigned int l)
{
if (l > C)
if (l > C) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
_l = l;
}
@ -100,8 +101,9 @@ public:
template<unsigned int C2>
inline Buffer &operator=(const Buffer<C2> &b)
{
if (unlikely(b._l > C))
if (unlikely(b._l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
if (C2 == C) {
memcpy(this,&b,sizeof(Buffer<C>));
} else {
@ -112,23 +114,26 @@ public:
inline void copyFrom(const void *b,unsigned int l)
{
if (unlikely(l > C))
if (unlikely(l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
memcpy(_b,b,l);
_l = l;
}
unsigned char operator[](const unsigned int i) const
{
if (unlikely(i >= _l))
if (unlikely(i >= _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return (unsigned char)_b[i];
}
unsigned char &operator[](const unsigned int i)
{
if (unlikely(i >= _l))
if (unlikely(i >= _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return ((unsigned char *)_b)[i];
}
@ -147,14 +152,16 @@ public:
*/
unsigned char *field(unsigned int i,unsigned int l)
{
if (unlikely((i + l) > _l))
if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return (unsigned char *)(_b + i);
}
const unsigned char *field(unsigned int i,unsigned int l) const
{
if (unlikely((i + l) > _l))
if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return (const unsigned char *)(_b + i);
}
@ -168,12 +175,14 @@ public:
template<typename T>
inline void setAt(unsigned int i,const T v)
{
if (unlikely((i + sizeof(T)) > _l))
if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
#ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
for(unsigned int x=1;x<=sizeof(T);++x)
for(unsigned int x=1;x<=sizeof(T);++x) {
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
}
#else
T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + i);
*p = Utils::hton(v);
@ -190,8 +199,9 @@ public:
template<typename T>
inline T at(unsigned int i) const
{
if (unlikely((i + sizeof(T)) > _l))
if (unlikely((i + sizeof(T)) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
#ifdef ZT_NO_TYPE_PUNNING
T v = 0;
const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
@ -216,12 +226,14 @@ public:
template<typename T>
inline void append(const T v)
{
if (unlikely((_l + sizeof(T)) > C))
if (unlikely((_l + sizeof(T)) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
#ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
for(unsigned int x=1;x<=sizeof(T);++x)
for(unsigned int x=1;x<=sizeof(T);++x) {
*(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
}
#else
T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + _l);
*p = Utils::hton(v);
@ -238,10 +250,12 @@ public:
*/
inline void append(unsigned char c,unsigned int n)
{
if (unlikely((_l + n) > C))
if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
for(unsigned int i=0;i<n;++i)
}
for(unsigned int i=0;i<n;++i) {
_b[_l++] = (char)c;
}
}
/**
@ -251,8 +265,9 @@ public:
*/
inline void appendRandom(unsigned int n)
{
if (unlikely((_l + n) > C))
if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
Utils::getSecureRandom(_b + _l,n);
_l += n;
}
@ -266,8 +281,9 @@ public:
*/
inline void append(const void *b,unsigned int l)
{
if (unlikely((_l + l) > C))
if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
memcpy(_b + _l,b,l);
_l += l;
}
@ -281,10 +297,12 @@ public:
inline void appendCString(const char *s)
{
for(;;) {
if (unlikely(_l >= C))
if (unlikely(_l >= C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
if (!(_b[_l++] = *(s++)))
}
if (!(_b[_l++] = *(s++))) {
break;
}
}
}
@ -313,8 +331,9 @@ public:
*/
inline char *appendField(unsigned int l)
{
if (unlikely((_l + l) > C))
if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
char *r = _b + _l;
_l += l;
return r;
@ -330,8 +349,9 @@ public:
*/
inline void addSize(unsigned int i)
{
if (unlikely((i + _l) > C))
if (unlikely((i + _l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
_l += i;
}
@ -345,8 +365,9 @@ public:
*/
inline void setSize(const unsigned int i)
{
if (unlikely(i > C))
if (unlikely(i > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
_l = i;
}
@ -358,10 +379,12 @@ public:
*/
inline void behead(const unsigned int at)
{
if (!at)
if (!at) {
return;
if (unlikely(at > _l))
}
if (unlikely(at > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
::memmove(_b,_b + at,_l -= at);
}
@ -375,8 +398,9 @@ public:
inline void erase(const unsigned int at,const unsigned int length)
{
const unsigned int endr = at + length;
if (unlikely(endr > _l))
if (unlikely(endr > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
::memmove(_b + at,_b + endr,_l - endr);
_l -= length;
}

View file

@ -731,7 +731,9 @@ static void crypto_scalarmult(u8 *mypublic, const u8 *secret, const u8 *basepoin
uint8_t e[32];
int i;
for (i = 0; i < 32; ++i) e[i] = secret[i];
for (i = 0; i < 32; ++i) {
e[i] = secret[i];
}
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
@ -837,14 +839,12 @@ static inline void reduce_add_sub(fe25519 *r)
crypto_uint32 t;
int i,rep;
for(rep=0;rep<4;rep++)
{
for(rep=0;rep<4;rep++) {
t = r->v[31] >> 7;
r->v[31] &= 127;
t = times19(t);
r->v[0] += t;
for(i=0;i<31;i++)
{
for(i=0;i<31;i++) {
t = r->v[i] >> 8;
r->v[i+1] += t;
r->v[i] &= 255;
@ -857,14 +857,12 @@ static inline void reduce_mul(fe25519 *r)
crypto_uint32 t;
int i,rep;
for(rep=0;rep<2;rep++)
{
for(rep=0;rep<2;rep++) {
t = r->v[31] >> 7;
r->v[31] &= 127;
t = times19(t);
r->v[0] += t;
for(i=0;i<31;i++)
{
for(i=0;i<31;i++) {
t = r->v[i] >> 8;
r->v[i+1] += t;
r->v[i] &= 255;
@ -877,22 +875,26 @@ static inline void fe25519_freeze(fe25519 *r)
{
int i;
crypto_uint32 m = equal(r->v[31],127);
for(i=30;i>0;i--)
for(i=30;i>0;i--) {
m &= equal(r->v[i],255);
}
m &= ge(r->v[0],237);
m = -m;
r->v[31] -= m&127;
for(i=30;i>0;i--)
for(i=30;i>0;i--) {
r->v[i] -= m&255;
}
r->v[0] -= m&237;
}
static inline void fe25519_unpack(fe25519 *r, const unsigned char x[32])
{
int i;
for(i=0;i<32;i++) r->v[i] = x[i];
for(i=0;i<32;i++) {
r->v[i] = x[i];
}
r->v[31] &= 127;
}
@ -902,8 +904,9 @@ static inline void fe25519_pack(unsigned char r[32], const fe25519 *x)
int i;
fe25519 y = *x;
fe25519_freeze(&y);
for(i=0;i<32;i++)
for(i=0;i<32;i++) {
r[i] = y.v[i];
}
}
static inline int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y)
@ -913,8 +916,11 @@ static inline int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y)
fe25519 t2 = *y;
fe25519_freeze(&t1);
fe25519_freeze(&t2);
for(i=0;i<32;i++)
if(t1.v[i] != t2.v[i]) return 0;
for(i=0;i<32;i++) {
if (t1.v[i] != t2.v[i]) {
return 0;
}
}
return 1;
}
@ -923,7 +929,9 @@ static inline void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b)
int i;
crypto_uint32 mask = b;
mask = -mask;
for(i=0;i<32;i++) r->v[i] ^= mask & (x->v[i] ^ r->v[i]);
for(i=0;i<32;i++) {
r->v[i] ^= mask & (x->v[i] ^ r->v[i]);
}
}
static inline unsigned char fe25519_getparity(const fe25519 *x)
@ -937,20 +945,26 @@ static inline void fe25519_setone(fe25519 *r)
{
int i;
r->v[0] = 1;
for(i=1;i<32;i++) r->v[i]=0;
for(i=1;i<32;i++) {
r->v[i]=0;
}
}
static inline void fe25519_setzero(fe25519 *r)
{
int i;
for(i=0;i<32;i++) r->v[i]=0;
for(i=0;i<32;i++) {
r->v[i]=0;
}
}
static inline void fe25519_neg(fe25519 *r, const fe25519 *x)
{
fe25519 t;
int i;
for(i=0;i<32;i++) t.v[i]=x->v[i];
for(i=0;i<32;i++) {
t.v[i]=x->v[i];
}
fe25519_setzero(r);
fe25519_sub(r, r, &t);
}
@ -958,7 +972,9 @@ static inline void fe25519_neg(fe25519 *r, const fe25519 *x)
static inline void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y)
{
int i;
for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
for(i=0;i<32;i++) {
r->v[i] = x->v[i] + y->v[i];
}
reduce_add_sub(r);
}
@ -968,8 +984,12 @@ static inline void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y)
crypto_uint32 t[32];
t[0] = x->v[0] + 0x1da;
t[31] = x->v[31] + 0xfe;
for(i=1;i<31;i++) t[i] = x->v[i] + 0x1fe;
for(i=0;i<32;i++) r->v[i] = t[i] - y->v[i];
for(i=1;i<31;i++) {
t[i] = x->v[i] + 0x1fe;
}
for(i=0;i<32;i++) {
r->v[i] = t[i] - y->v[i];
}
reduce_add_sub(r);
}
@ -977,14 +997,19 @@ static inline void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y)
{
int i,j;
crypto_uint32 t[63];
for(i=0;i<63;i++)t[i] = 0;
for(i=0;i<63;i++) {
t[i] = 0;
}
for(i=0;i<32;i++)
for(j=0;j<32;j++)
for(i=0;i<32;i++) {
for(j=0;j<32;j++) {
t[i+j] += x->v[i] * y->v[j];
}
}
for(i=32;i<63;i++)
for(i=32;i<63;i++) {
r->v[i-32] = t[i-32] + times38(t[i]);
}
r->v[31] = t[31]; /* result now in r[0]...r[31] */
reduce_mul(r);
@ -1136,16 +1161,16 @@ static inline void reduce_add_sub(sc25519 *r)
int i;
unsigned char t[32];
for(i=0;i<32;i++)
{
for(i=0;i<32;i++) {
pb += m[i];
b = lt(r->v[i],pb);
t[i] = r->v[i]-pb+(b<<8);
pb = b;
}
mask = b - 1;
for(i=0;i<32;i++)
for(i=0;i<32;i++) {
r->v[i] ^= mask & (r->v[i] ^ t[i]);
}
}
/* Reduce coefficients of x before calling barrett_reduce */
@ -1161,31 +1186,43 @@ static inline void barrett_reduce(sc25519 *r, const crypto_uint32 x[64])
crypto_uint32 pb = 0;
crypto_uint32 b;
for (i = 0;i < 66;++i) q2[i] = 0;
for (i = 0;i < 33;++i) r2[i] = 0;
for (i = 0;i < 66;++i) {
q2[i] = 0;
}
for (i = 0;i < 33;++i) {
r2[i] = 0;
}
for(i=0;i<33;i++)
for(j=0;j<33;j++)
if(i+j >= 31) q2[i+j] += mu[i]*x[j+31];
for(i=0;i<33;i++) {
for(j=0;j<33;j++) {
if(i+j >= 31) {
q2[i+j] += mu[i]*x[j+31];
}
}
}
carry = q2[31] >> 8;
q2[32] += carry;
carry = q2[32] >> 8;
q2[33] += carry;
for(i=0;i<33;i++)r1[i] = x[i];
for(i=0;i<32;i++)
for(j=0;j<33;j++)
if(i+j < 33) r2[i+j] += m[i]*q3[j];
for(i=0;i<33;i++) {
r1[i] = x[i];
}
for(i=0;i<32;i++) {
for(j=0;j<33;j++) {
if(i+j < 33) {
r2[i+j] += m[i]*q3[j];
}
}
}
for(i=0;i<32;i++)
{
for(i=0;i<32;i++) {
carry = r2[i] >> 8;
r2[i+1] += carry;
r2[i] &= 0xff;
}
for(i=0;i<32;i++)
{
for(i=0;i<32;i++) {
pb += r2[i];
b = lt(r1[i],pb);
r->v[i] = r1[i]-pb+(b<<8);
@ -1204,8 +1241,12 @@ static inline void sc25519_from32bytes(sc25519 *r, const unsigned char x[32])
{
int i;
crypto_uint32 t[64];
for(i=0;i<32;i++) t[i] = x[i];
for(i=32;i<64;++i) t[i] = 0;
for(i=0;i<32;i++) {
t[i] = x[i];
}
for(i=32;i<64;++i) {
t[i] = 0;
}
barrett_reduce(r, t);
}
@ -1213,22 +1254,27 @@ static inline void sc25519_from64bytes(sc25519 *r, const unsigned char x[64])
{
int i;
crypto_uint32 t[64];
for(i=0;i<64;i++) t[i] = x[i];
for(i=0;i<64;i++) {
t[i] = x[i];
}
barrett_reduce(r, t);
}
static inline void sc25519_to32bytes(unsigned char r[32], const sc25519 *x)
{
int i;
for(i=0;i<32;i++) r[i] = x->v[i];
for(i=0;i<32;i++) {
r[i] = x->v[i];
}
}
static inline void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y)
{
int i, carry;
for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
for(i=0;i<31;i++)
{
for(i=0;i<32;i++) {
r->v[i] = x->v[i] + y->v[i];
}
for(i=0;i<31;i++) {
carry = r->v[i] >> 8;
r->v[i+1] += carry;
r->v[i] &= 0xff;
@ -1240,14 +1286,17 @@ static inline void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y)
{
int i,j,carry;
crypto_uint32 t[64];
for(i=0;i<64;i++)t[i] = 0;
for(i=0;i<64;i++) {
t[i] = 0;
}
for(i=0;i<32;i++)
for(j=0;j<32;j++)
for(i=0;i<32;i++) {
for(j=0;j<32;j++) {
t[i+j] += x->v[i] * y->v[j];
}
}
for(i=0;i<63;i++)
{
for(i=0;i<63;i++) {
carry = t[i] >> 8;
t[i+1] += carry;
t[i] &= 0xff;
@ -1260,8 +1309,7 @@ static inline void sc25519_window3(signed char r[85], const sc25519 *s)
{
char carry;
int i;
for(i=0;i<10;i++)
{
for(i=0;i<10;i++) {
r[8*i+0] = s->v[3*i+0] & 7;
r[8*i+1] = (s->v[3*i+0] >> 3) & 7;
r[8*i+2] = (s->v[3*i+0] >> 6) & 7;
@ -1282,8 +1330,7 @@ static inline void sc25519_window3(signed char r[85], const sc25519 *s)
/* Making it signed */
carry = 0;
for(i=0;i<84;i++)
{
for(i=0;i<84;i++) {
r[i] += carry;
r[i+1] += r[i] >> 3;
r[i] &= 7;
@ -1296,8 +1343,7 @@ static inline void sc25519_window3(signed char r[85], const sc25519 *s)
static inline void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2)
{
int i;
for(i=0;i<31;i++)
{
for(i=0;i<31;i++) {
r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2);
r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2);
r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2);
@ -2341,18 +2387,21 @@ static inline int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p
/* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */
fe25519_square(&chk, &r->x);
fe25519_mul(&chk, &chk, &den);
if (!fe25519_iseq_vartime(&chk, &num))
if (!fe25519_iseq_vartime(&chk, &num)) {
fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1);
}
/* 4. Now we have one of the two square roots, except if input was not a square */
fe25519_square(&chk, &r->x);
fe25519_mul(&chk, &chk, &den);
if (!fe25519_iseq_vartime(&chk, &num))
if (!fe25519_iseq_vartime(&chk, &num)) {
return -1;
}
/* 5. Choose the desired square root according to parity: */
if(fe25519_getparity(&r->x) != (1-par))
if(fe25519_getparity(&r->x) != (1-par)) {
fe25519_neg(&r->x, &r->x);
}
fe25519_mul(&r->t, &r->x, &r->y);
return 0;
@ -2399,18 +2448,19 @@ static inline void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge2551
/* scalar multiplication */
*r = pre[b[126]];
for(i=125;i>=0;i--)
{
for(i=125;i>=0;i--) {
dbl_p1p1(&tp1p1, (ge25519_p2 *)r);
p1p1_to_p2((ge25519_p2 *) r, &tp1p1);
dbl_p1p1(&tp1p1, (ge25519_p2 *)r);
if(b[i]!=0)
{
if(b[i]!=0) {
p1p1_to_p3(r, &tp1p1);
add_p1p1(&tp1p1, r, &pre[b[i]]);
}
if(i != 0) p1p1_to_p2((ge25519_p2 *)r, &tp1p1);
else p1p1_to_p3(r, &tp1p1);
if (i != 0) {
p1p1_to_p2((ge25519_p2 *)r, &tp1p1);
} else {
p1p1_to_p3(r, &tp1p1);
}
}
}
@ -2424,8 +2474,7 @@ static inline void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s)
choose_t((ge25519_aff *)r, 0, b[0]);
fe25519_setone(&r->z);
fe25519_mul(&r->t, &r->x, &r->y);
for(i=1;i<85;i++)
{
for(i=1;i<85;i++) {
choose_t(&t, (unsigned long long) i, b[i]);
ge25519_mixadd2(r, &t);
}
@ -2435,9 +2484,15 @@ static inline void get_hram(unsigned char *hram, const unsigned char *sm, const
{
unsigned long long i;
for (i = 0;i < 32;++i) playground[i] = sm[i];
for (i = 32;i < 64;++i) playground[i] = pk[i-32];
for (i = 64;i < smlen;++i) playground[i] = sm[i];
for (i = 0;i < 32;++i) {
playground[i] = sm[i];
}
for (i = 32;i < 64;++i) {
playground[i] = pk[i-32];
}
for (i = 64;i < smlen;++i) {
playground[i] = sm[i];
}
ZeroTier::SHA512(hram,playground,(unsigned int)smlen);
}
@ -2491,10 +2546,12 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
extsk[31] &= 127;
extsk[31] |= 64;
for(unsigned int i=0;i<32;i++)
for(unsigned int i=0;i<32;i++) {
sig[32 + i] = extsk[32 + i];
for(unsigned int i=0;i<32;i++)
}
for(unsigned int i=0;i<32;i++) {
sig[64 + i] = digest[i];
}
SHA512(hmg,sig + 32,64);
@ -2504,8 +2561,9 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
ge25519_pack(r, &ger);
/* Computation of s */
for(unsigned int i=0;i<32;i++)
for(unsigned int i=0;i<32;i++) {
sig[i] = r[i];
}
get_hram(hram,sig,myPublic.data + 32,sig,96);
@ -2516,8 +2574,9 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
sc25519_add(&scs, &scs, &sck);
sc25519_to32bytes(s,&scs); /* cat s */
for(unsigned int i=0;i<32;i++)
for(unsigned int i=0;i<32;i++) {
sig[32 + i] = s[i];
}
#endif
}
@ -2526,8 +2585,9 @@ bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len
const unsigned char *const sig = (const unsigned char *)signature;
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
SHA512(digest,msg,len);
if (!Utils::secureEq(sig + 64,digest,32))
if (!Utils::secureEq(sig + 64,digest,32)) {
return false;
}
unsigned char t2[32];
ge25519 get1, get2;
@ -2535,8 +2595,9 @@ bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len
unsigned char hram[crypto_hash_sha512_BYTES];
unsigned char m[96];
if (ge25519_unpackneg_vartime(&get1,their.data + 32))
if (ge25519_unpackneg_vartime(&get1,their.data + 32)) {
return false;
}
get_hram(hram,sig,their.data + 32,m,96);

View file

@ -25,27 +25,31 @@ int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
try {
// There must be at least one entry, and sanity check for bad chain max length
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
return -1;
}
// Validate all entries in chain of custody
Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true);
for(unsigned int c=0;c<_maxCustodyChainLength;++c) {
if (c == 0) {
if ((!_custody[c].to)||(!_custody[c].from)||(_custody[c].from != Network::controllerFor(_nwid)))
if ((!_custody[c].to)||(!_custody[c].from)||(_custody[c].from != Network::controllerFor(_nwid))) {
return -1; // the first entry must be present and from the network's controller
}
} else {
if (!_custody[c].to)
if (!_custody[c].to) {
return 0; // all previous entries were valid, so we are valid
else if ((!_custody[c].from)||(_custody[c].from != _custody[c-1].to))
} else if ((!_custody[c].from)||(_custody[c].from != _custody[c-1].to)) {
return -1; // otherwise if we have another entry it must be from the previous holder in the chain
}
}
const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from));
if (id) {
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature))
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) {
return -1;
}
} else {
RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from);
return 1;

View file

@ -85,8 +85,9 @@ public:
_maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1),
_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
{
if (_ruleCount > 0)
if (_ruleCount > 0) {
memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
}
}
/**
@ -121,9 +122,11 @@ public:
{
Address i2;
for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
if (!_custody[i].to)
if (!_custody[i].to) {
return i2;
else i2 = _custody[i].to;
} else {
i2 = _custody[i].to;
}
}
return i2;
}
@ -380,7 +383,9 @@ public:
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
// These are the same between Tag and Capability
b.append(_nwid);
@ -409,7 +414,9 @@ public:
// This is the size of any additional fields, currently 0.
b.append((uint16_t)0);
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
}
template<unsigned int C>
@ -419,40 +426,53 @@ public:
unsigned int p = startAt;
_nwid = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
_id = b.template at<uint32_t>(p); p += 4;
_nwid = b.template at<uint64_t>(p);
p += 8;
_ts = b.template at<uint64_t>(p);
p += 8;
_id = b.template at<uint32_t>(p);
p += 4;
const unsigned int rc = b.template at<uint16_t>(p); p += 2;
if (rc > ZT_MAX_CAPABILITY_RULES)
const unsigned int rc = b.template at<uint16_t>(p);
p += 2;
if (rc > ZT_MAX_CAPABILITY_RULES) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
deserializeRules(b,p,_rules,_ruleCount,rc);
_maxCustodyChainLength = (unsigned int)b[p++];
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
for(unsigned int i=0;;++i) {
const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
if (!to)
const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (!to) {
break;
if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
}
if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
_custody[i].to = to;
_custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
p += 2;
memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
p += 2 + b.template at<uint16_t>(p);
}
}
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
if (p > b.size()) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
return (p - startAt);
}

View file

@ -48,25 +48,30 @@ CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t tim
bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const
{
if ((_qualifierCount == 0)||(other._qualifierCount == 0))
if ((_qualifierCount == 0)||(other._qualifierCount == 0)) {
return false;
}
std::map< uint64_t, uint64_t > otherFields;
for(unsigned int i=0;i<other._qualifierCount;++i)
for(unsigned int i=0;i<other._qualifierCount;++i) {
otherFields[other._qualifiers[i].id] = other._qualifiers[i].value;
}
bool fullIdentityVerification = false;
for(unsigned int i=0;i<_qualifierCount;++i) {
const uint64_t qid = _qualifiers[i].id;
if ((qid >= 3)&&(qid <= 6))
if ((qid >= 3)&&(qid <= 6)) {
fullIdentityVerification = true;
}
std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find(qid));
if (otherQ == otherFields.end())
if (otherQ == otherFields.end()) {
return false;
}
const uint64_t a = _qualifiers[i].value;
const uint64_t b = otherQ->second;
if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[i].maxDelta)
if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[i].maxDelta) {
return false;
}
}
// If this COM has a full hash of its identity, assume the other must have this as well.
@ -76,10 +81,12 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
otherIdentity.publicKeyHash(idHash);
for(unsigned long i=0;i<4;++i) {
std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find((uint64_t)(i + 3)));
if (otherQ == otherFields.end())
if (otherQ == otherFields.end()) {
return false;
if (otherQ->second != Utils::ntoh(idHash[i]))
}
if (otherQ->second != Utils::ntoh(idHash[i])) {
return false;
}
}
}
@ -108,8 +115,9 @@ bool CertificateOfMembership::sign(const Identity &with)
int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS))
if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {

View file

@ -142,8 +142,9 @@ public:
inline int64_t timestamp() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) {
return _qualifiers[i].value;
}
}
return 0;
}
@ -154,8 +155,9 @@ public:
inline Address issuedTo() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO)
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) {
return Address(_qualifiers[i].value);
}
}
return Address();
}
@ -166,8 +168,9 @@ public:
inline uint64_t networkId() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID)
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) {
return _qualifiers[i].value;
}
}
return 0ULL;
}
@ -226,8 +229,9 @@ public:
b.append(_qualifiers[i].maxDelta);
}
_signedBy.appendTo(b);
if (_signedBy)
if (_signedBy) {
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
}
}
template<unsigned int C>
@ -238,16 +242,20 @@ public:
_qualifierCount = 0;
_signedBy.zero();
if (b[p++] != 1)
if (b[p++] != 1) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
unsigned int numq = b.template at<uint16_t>(p); p += sizeof(uint16_t);
unsigned int numq = b.template at<uint16_t>(p);
p += sizeof(uint16_t);
uint64_t lastId = 0;
for(unsigned int i=0;i<numq;++i) {
const uint64_t qid = b.template at<uint64_t>(p);
if (qid < lastId)
if (qid < lastId) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
else lastId = qid;
} else {
lastId = qid;
}
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
_qualifiers[_qualifierCount].id = qid;
_qualifiers[_qualifierCount].value = b.template at<uint64_t>(p + 8);
@ -272,15 +280,18 @@ public:
inline bool operator==(const CertificateOfMembership &c) const
{
if (_signedBy != c._signedBy)
if (_signedBy != c._signedBy) {
return false;
if (_qualifierCount != c._qualifierCount)
}
if (_qualifierCount != c._qualifierCount) {
return false;
}
for(unsigned int i=0;i<_qualifierCount;++i) {
const _Qualifier &a = _qualifiers[i];
const _Qualifier &b = c._qualifiers[i];
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta)) {
return false;
}
}
return (memcmp(_signature.data,c._signature.data,ZT_C25519_SIGNATURE_LEN) == 0);
}

View file

@ -23,8 +23,9 @@ namespace ZeroTier {
int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);
@ -45,12 +46,14 @@ bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const
if (_thingTypes[i] == (uint8_t)t) {
unsigned int k = 0;
while (k < l) {
if (reinterpret_cast<const uint8_t *>(v)[k] != _thingValues[i][k])
if (reinterpret_cast<const uint8_t *>(v)[k] != _thingValues[i][k]) {
break;
}
++k;
}
if (k == l)
if (k == l) {
return true;
}
}
}
return false;

View file

@ -80,10 +80,12 @@ public:
inline bool owns(const InetAddress &ip) const
{
if (ip.ss_family == AF_INET)
if (ip.ss_family == AF_INET) {
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
if (ip.ss_family == AF_INET6)
}
if (ip.ss_family == AF_INET6) {
return this->_owns(THING_IPV6_ADDRESS,reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
}
return false;
}
@ -96,7 +98,9 @@ public:
inline void addThing(const InetAddress &ip)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return;
}
if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
@ -110,7 +114,9 @@ public:
inline void addThing(const MAC &mac)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return;
}
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
mac.copyTo(_thingValues[_thingCount],6);
++_thingCount;
@ -142,7 +148,9 @@ public:
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
b.append(_networkId);
b.append(_ts);
@ -164,7 +172,9 @@ public:
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
}
template<unsigned int C>
@ -174,11 +184,16 @@ public:
*this = CertificateOfOwnership();
_networkId = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
_flags = b.template at<uint64_t>(p); p += 8;
_id = b.template at<uint32_t>(p); p += 4;
_thingCount = b.template at<uint16_t>(p); p += 2;
_networkId = b.template at<uint64_t>(p);
p += 8;
_ts = b.template at<uint64_t>(p);
p += 8;
_flags = b.template at<uint64_t>(p);
p += 8;
_id = b.template at<uint32_t>(p);
p += 4;
_thingCount = b.template at<uint16_t>(p);
p += 2;
for(unsigned int i=0,j=_thingCount;i<j;++i) {
if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
_thingTypes[i] = (uint8_t)b[p++];
@ -187,20 +202,25 @@ public:
}
}
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
p += 2 + b.template at<uint16_t>(p);
}
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
if (p > b.size()) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
return (p - startAt);
}

View file

@ -299,7 +299,7 @@
/**
* Delay between checks of peer pings, etc., and also related housekeeping tasks
*/
#define ZT_PING_CHECK_INVERVAL 5000
#define ZT_PING_CHECK_INTERVAL 5000
/**
* How often the local.conf file is checked for changes (service, should be moved there)
@ -687,6 +687,7 @@
#define ZT_EXCEPTION_OUT_OF_MEMORY 101
#define ZT_EXCEPTION_PRIVATE_KEY_REQUIRED 102
#define ZT_EXCEPTION_INVALID_ARGUMENT 103
#define ZT_EXCEPTION_INVALID_IDENTITY 104
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE 200
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW 201
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN 202

View file

@ -55,10 +55,14 @@ public:
{
for(unsigned int i=0;i<C;++i) {
if ((s)&&(i < len)) {
if (!(_d[i] = *s))
if (!(_d[i] = *s)) {
s = (const char *)0;
else ++s;
} else _d[i] = (char)0;
} else {
++s;
}
} else {
_d[i] = (char)0;
}
}
_d[C - 1] = (char)0;
}
@ -82,10 +86,14 @@ public:
{
for(unsigned int i=0;i<C;++i) {
if (s) {
if (!(_d[i] = *s))
if (!(_d[i] = *s)) {
s = (const char *)0;
else ++s;
} else _d[i] = (char)0;
} else {
++s;
}
} else {
_d[i] = (char)0;
}
}
_d[C - 1] = (char)0;
return (!s);
@ -105,8 +113,9 @@ public:
inline unsigned int sizeBytes() const
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i])
if (!_d[i]) {
return i;
}
}
return C-1;
}
@ -141,14 +150,16 @@ public:
bool esc;
int j;
if (!destlen) // sanity check
if (!destlen) { // sanity check
return -1;
}
while (*p) {
k = key;
while ((*k)&&(*p)) {
if (*p != *k)
if (*p != *k) {
break;
}
++k;
if (++p == eof) {
dest[0] = (char)0;
@ -164,11 +175,21 @@ public:
if (esc) {
esc = false;
switch(*p) {
case 'r': dest[j++] = 13; break;
case 'n': dest[j++] = 10; break;
case '0': dest[j++] = (char)0; break;
case 'e': dest[j++] = '='; break;
default: dest[j++] = *p; break;
case 'r':
dest[j++] = 13;
break;
case 'n':
dest[j++] = 10;
break;
case '0':
dest[j++] = (char)0;
break;
case 'e':
dest[j++] = '=';
break;
default:
dest[j++] = *p;
break;
}
if (j == (int)destlen) {
dest[j-1] = (char)0;
@ -202,8 +223,9 @@ public:
dest[0] = (char)0;
return -1;
}
} else {
break;
}
else break;
}
}
@ -242,8 +264,9 @@ public:
bool getB(const char *key,bool dfl = false) const
{
char tmp[4];
if (this->get(key,tmp,sizeof(tmp)) >= 0)
if (this->get(key,tmp,sizeof(tmp)) >= 0) {
return ((*tmp == '1')||(*tmp == 't')||(*tmp == 'T'));
}
return dfl;
}
@ -257,8 +280,9 @@ public:
inline uint64_t getUI(const char *key,uint64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1)
if (this->get(key,tmp,sizeof(tmp)) >= 1) {
return Utils::hexStrToU64(tmp);
}
return dfl;
}
@ -272,8 +296,9 @@ public:
inline int64_t getI(const char *key,int64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1)
if (this->get(key,tmp,sizeof(tmp)) >= 1) {
return Utils::hexStrTo64(tmp);
}
return dfl;
}
@ -335,11 +360,21 @@ public:
return false;
}
switch(*p) {
case 0: _d[j++] = '0'; break;
case 13: _d[j++] = 'r'; break;
case 10: _d[j++] = 'n'; break;
case '\\': _d[j++] = '\\'; break;
case '=': _d[j++] = 'e'; break;
case 0:
_d[j++] = '0';
break;
case 13:
_d[j++] = 'r';
break;
case 10:
_d[j++] = 'n';
break;
case '\\':
_d[j++] = '\\';
break;
case '=':
_d[j++] = 'e';
break;
}
if (j == C) {
_d[i] = (char)0;

View file

@ -81,8 +81,9 @@ public:
return true;
}
++_idx;
if (_idx >= _ht->_bc)
if (_idx >= _ht->_bc) {
return false;
}
_b = _ht->_t[_idx];
}
}
@ -102,10 +103,12 @@ public:
_bc(bc),
_s(0)
{
if (!_t)
if (!_t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY;
for(unsigned long i=0;i<bc;++i)
}
for(unsigned long i=0;i<bc;++i) {
_t[i] = (_Bucket *)0;
}
}
Hashtable(const Hashtable<K,V> &ht) :
@ -113,10 +116,12 @@ public:
_bc(ht._bc),
_s(ht._s)
{
if (!_t)
if (!_t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY;
for(unsigned long i=0;i<_bc;++i)
}
for(unsigned long i=0;i<_bc;++i) {
_t[i] = (_Bucket *)0;
}
for(unsigned long i=0;i<_bc;++i) {
const _Bucket *b = ht._t[i];
while (b) {
@ -234,8 +239,9 @@ public:
{
_Bucket *b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k)
if (b->k == k) {
return &(b->v);
}
b = b->next;
}
return (V *)0;
@ -268,8 +274,9 @@ public:
{
_Bucket *b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k)
if (b->k == k) {
return true;
}
b = b->next;
}
return false;
@ -286,9 +293,11 @@ public:
_Bucket *b = _t[bidx];
while (b) {
if (b->k == k) {
if (lastb)
if (lastb) {
lastb->next = b->next;
else _t[bidx] = b->next;
} else {
_t[bidx] = b->next;
}
delete b;
--_s;
return true;
@ -341,8 +350,9 @@ public:
_Bucket *b = _t[bidx];
while (b) {
if (b->k == k)
if (b->k == k) {
return b->v;
}
b = b->next;
}
@ -396,8 +406,9 @@ private:
const unsigned long nc = _bc * 2;
_Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc));
if (nt) {
for(unsigned long i=0;i<nc;++i)
for(unsigned long i=0;i<nc;++i) {
nt[i] = (_Bucket *)0;
}
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
while (b) {

View file

@ -93,8 +93,9 @@ void Identity::generate()
} while (_address.isReserved());
_publicKey = kp.pub;
if (!_privateKey)
if (!_privateKey) {
_privateKey = new C25519::Private();
}
*_privateKey = kp.priv;
delete [] genmem;
@ -102,8 +103,9 @@ void Identity::generate()
bool Identity::locallyValidate() const
{
if (_address.isReserved())
if (_address.isReserved()) {
return false;
}
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];

View file

@ -56,8 +56,9 @@ public:
Identity(const char *str) :
_privateKey((C25519::Private *)0)
{
if (!fromString(str))
if (!fromString(str)) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
}
template<unsigned int C>
@ -80,8 +81,9 @@ public:
_address = id._address;
_publicKey = id._publicKey;
if (id._privateKey) {
if (!_privateKey)
if (!_privateKey) {
_privateKey = new C25519::Private();
}
*_privateKey = *(id._privateKey);
} else {
delete _privateKey;
@ -144,8 +146,9 @@ public:
*/
inline C25519::Signature sign(const void *data,unsigned int len) const
{
if (_privateKey)
if (_privateKey) {
return C25519::sign(*_privateKey,_publicKey,data,len);
}
throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED;
}
@ -160,8 +163,9 @@ public:
*/
inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const
{
if (siglen != ZT_C25519_SIGNATURE_LEN)
if (siglen != ZT_C25519_SIGNATURE_LEN) {
return false;
}
return C25519::verify(_publicKey,data,len,signature);
}
@ -217,7 +221,9 @@ public:
if ((_privateKey)&&(includePrivate)) {
b.append((unsigned char)ZT_C25519_PRIVATE_KEY_LEN);
b.append(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
} else b.append((unsigned char)0);
} else {
b.append((unsigned char)0);
}
}
/**
@ -243,16 +249,18 @@ public:
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] != 0)
if (b[p++] != 0) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
memcpy(_publicKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
unsigned int privateKeyLength = (unsigned int)b[p++];
if (privateKeyLength) {
if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN)
if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
_privateKey = new C25519::Private();
memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
@ -293,9 +301,11 @@ public:
{
C25519::Pair pair;
pair.pub = _publicKey;
if (_privateKey)
if (_privateKey) {
pair.priv = *_privateKey;
else memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
} else {
memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN);
}
return pair;
}

View file

@ -37,6 +37,7 @@
#include "Trace.hpp"
#include "Path.hpp"
#include "Bond.hpp"
#include "Metrics.hpp"
namespace ZeroTier {
@ -85,28 +86,69 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f
switch(v) {
//case Packet::VERB_NOP:
default: // ignore unknown verbs, but if they pass auth check they are "received"
Metrics::pkt_nop_in++;
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
break;
case Packet::VERB_HELLO: r = _doHELLO(RR,tPtr,true); break;
case Packet::VERB_ACK : r = _doACK(RR,tPtr,peer); break;
case Packet::VERB_QOS_MEASUREMENT: r = _doQOS_MEASUREMENT(RR,tPtr,peer); break;
case Packet::VERB_ERROR: r = _doERROR(RR,tPtr,peer); break;
case Packet::VERB_OK: r = _doOK(RR,tPtr,peer); break;
case Packet::VERB_WHOIS: r = _doWHOIS(RR,tPtr,peer); break;
case Packet::VERB_RENDEZVOUS: r = _doRENDEZVOUS(RR,tPtr,peer); break;
case Packet::VERB_FRAME: r = _doFRAME(RR,tPtr,peer,flowId); break;
case Packet::VERB_EXT_FRAME: r = _doEXT_FRAME(RR,tPtr,peer,flowId); break;
case Packet::VERB_ECHO: r = _doECHO(RR,tPtr,peer); break;
case Packet::VERB_MULTICAST_LIKE: r = _doMULTICAST_LIKE(RR,tPtr,peer); break;
case Packet::VERB_NETWORK_CREDENTIALS: r = _doNETWORK_CREDENTIALS(RR,tPtr,peer); break;
case Packet::VERB_NETWORK_CONFIG_REQUEST: r = _doNETWORK_CONFIG_REQUEST(RR,tPtr,peer); break;
case Packet::VERB_NETWORK_CONFIG: r = _doNETWORK_CONFIG(RR,tPtr,peer); break;
case Packet::VERB_MULTICAST_GATHER: r = _doMULTICAST_GATHER(RR,tPtr,peer); break;
case Packet::VERB_MULTICAST_FRAME: r = _doMULTICAST_FRAME(RR,tPtr,peer); break;
case Packet::VERB_PUSH_DIRECT_PATHS: r = _doPUSH_DIRECT_PATHS(RR,tPtr,peer); break;
case Packet::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(RR,tPtr,peer); break;
case Packet::VERB_REMOTE_TRACE: r = _doREMOTE_TRACE(RR,tPtr,peer); break;
case Packet::VERB_PATH_NEGOTIATION_REQUEST: r = _doPATH_NEGOTIATION_REQUEST(RR,tPtr,peer); break;
case Packet::VERB_HELLO:
r = _doHELLO(RR, tPtr, true);
break;
case Packet::VERB_ACK:
r = _doACK(RR, tPtr, peer);
break;
case Packet::VERB_QOS_MEASUREMENT:
r = _doQOS_MEASUREMENT(RR, tPtr, peer);
break;
case Packet::VERB_ERROR:
r = _doERROR(RR, tPtr, peer);
break;
case Packet::VERB_OK:
r = _doOK(RR, tPtr, peer);
break;
case Packet::VERB_WHOIS:
r = _doWHOIS(RR, tPtr, peer);
break;
case Packet::VERB_RENDEZVOUS:
r = _doRENDEZVOUS(RR, tPtr, peer);
break;
case Packet::VERB_FRAME:
r = _doFRAME(RR, tPtr, peer, flowId);
break;
case Packet::VERB_EXT_FRAME:
r = _doEXT_FRAME(RR, tPtr, peer, flowId);
break;
case Packet::VERB_ECHO:
r = _doECHO(RR, tPtr, peer);
break;
case Packet::VERB_MULTICAST_LIKE:
r = _doMULTICAST_LIKE(RR, tPtr, peer);
break;
case Packet::VERB_NETWORK_CREDENTIALS:
r = _doNETWORK_CREDENTIALS(RR, tPtr, peer);
break;
case Packet::VERB_NETWORK_CONFIG_REQUEST:
r = _doNETWORK_CONFIG_REQUEST(RR, tPtr, peer);
break;
case Packet::VERB_NETWORK_CONFIG:
r = _doNETWORK_CONFIG(RR, tPtr, peer);
break;
case Packet::VERB_MULTICAST_GATHER:
r = _doMULTICAST_GATHER(RR, tPtr, peer);
break;
case Packet::VERB_MULTICAST_FRAME:
r = _doMULTICAST_FRAME(RR, tPtr, peer);
break;
case Packet::VERB_PUSH_DIRECT_PATHS:
r = _doPUSH_DIRECT_PATHS(RR, tPtr, peer);
break;
case Packet::VERB_USER_MESSAGE:
r = _doUSER_MESSAGE(RR, tPtr, peer);
break;
case Packet::VERB_REMOTE_TRACE:
r = _doREMOTE_TRACE(RR, tPtr, peer);
break;
case Packet::VERB_PATH_NEGOTIATION_REQUEST:
r = _doPATH_NEGOTIATION_REQUEST(RR, tPtr, peer);
break;
}
if (r) {
RR->node->statsLogVerb((unsigned int)v,(unsigned int)size());
@ -130,6 +172,8 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE];
uint64_t networkId = 0;
Metrics::pkt_error_in++;
/* Security note: we do not gate doERROR() with expectingReplyTo() to
* avoid having to log every outgoing packet ID. Instead we put the
* logic to determine whether we should consider an ERROR in each
@ -142,9 +186,11 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
// Object not found, currently only meaningful from network controllers.
if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
if ((network)&&(network->controller() == peer->address()))
if ((network)&&(network->controller() == peer->address())) {
network->setNotFound(tPtr);
}
}
Metrics::pkt_error_obj_not_found_in++;
break;
case Packet::ERROR_UNSUPPORTED_OPERATION:
@ -153,15 +199,19 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
// that the queried node does not support acting as a controller.
if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
if ((network)&&(network->controller() == peer->address()))
if ((network)&&(network->controller() == peer->address())) {
network->setNotFound(tPtr);
}
}
Metrics::pkt_error_unsupported_op_in++;
break;
case Packet::ERROR_IDENTITY_COLLISION:
// FIXME: for federation this will need a payload with a signature or something.
if (RR->topology->isUpstream(peer->identity()))
if (RR->topology->isUpstream(peer->identity())) {
RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
}
Metrics::pkt_error_identity_collision_in++;
break;
case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
@ -169,15 +219,19 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
networkId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
const SharedPtr<Network> network(RR->node->network(networkId));
const int64_t now = RR->node->now();
if ((network)&&(network->config().com))
if ((network)&&(network->config().com)) {
network->peerRequestedCredentials(tPtr,peer->address(),now);
}
Metrics::pkt_error_need_membership_cert_in++;
} break;
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
// Network controller: network access denied.
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
if ((network)&&(network->controller() == peer->address()))
if ((network)&&(network->controller() == peer->address())) {
network->setAccessDenied(tPtr);
}
Metrics::pkt_error_network_access_denied_in++;
} break;
case Packet::ERROR_UNWANTED_MULTICAST: {
@ -189,6 +243,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at<uint32_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14));
RR->mc->remove(network->id(),mg,peer->address());
}
Metrics::pkt_error_unwanted_multicast_in++;
} break;
case Packet::ERROR_NETWORK_AUTHENTICATION_REQUIRED: {
@ -247,9 +302,11 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
network->setAuthenticationRequired(tPtr, "");
}
}
Metrics::pkt_error_authentication_required_in++;
} break;
default: break;
default:
break;
}
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId,ZT_QOS_NO_FLOW);
@ -260,8 +317,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
bool IncomingPacket::_doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer)
{
/*
SharedPtr<Bond> bond = peer->bond();
if (! bond || ! bond->rateGateACK(RR->node->now())) {
if (! peer->rateGateACK(RR->node->now())) {
return true;
}
int32_t ackedBytes;
@ -269,17 +325,17 @@ bool IncomingPacket::_doACK(const RuntimeEnvironment* RR, void* tPtr, const Shar
return true; // ignore
}
memcpy(&ackedBytes, payload(), sizeof(ackedBytes));
if (bond) {
bond->receivedAck(_path, RR->node->now(), Utils::ntoh(ackedBytes));
}
peer->receivedAck(_path, RR->node->now(), Utils::ntoh(ackedBytes));
*/
Metrics::pkt_ack_in++;
return true;
}
bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer)
{
Metrics::pkt_qos_in++;
SharedPtr<Bond> bond = peer->bond();
if (! bond || ! bond->rateGateQoS(RR->node->now(), _path)) {
if (! peer->rateGateQoS(RR->node->now(), _path)) {
return true;
}
if (payloadLength() > ZT_QOS_MAX_PACKET_SIZE || payloadLength() < ZT_QOS_MIN_PACKET_SIZE) {
@ -300,14 +356,13 @@ bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr
ptr += sizeof(uint16_t);
count++;
}
if (bond) {
bond->receivedQoS(_path, now, count, rx_id, rx_ts);
}
peer->receivedQoS(_path, now, count, rx_id, rx_ts);
return true;
}
bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated)
{
Metrics::pkt_hello_in++;
const int64_t now = RR->node->now();
const uint64_t pid = packetId();
@ -337,8 +392,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
// Identity is different from the one we already have -- address collision
// Check rate limits
if (!RR->node->rateGateIdentityVerification(now,_path->address()))
if (!RR->node->rateGateIdentityVerification(now,_path->address())) {
return true;
}
uint8_t key[ZT_SYMMETRIC_KEY_SIZE];
if (RR->identity.agree(id,key)) {
@ -349,6 +405,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
outp.append((uint64_t)pid);
outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION);
outp.armor(key,true,peer->aesKeysIfSupported());
Metrics::pkt_error_out++;
Metrics::pkt_error_identity_collision_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
} else {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC");
@ -408,16 +466,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
InetAddress externalSurfaceAddress;
if (ptr < size()) {
ptr += externalSurfaceAddress.deserialize(*this,ptr);
if ((externalSurfaceAddress)&&(hops() == 0))
if ((externalSurfaceAddress)&&(hops() == 0)) {
RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
}
}
// Get primary planet world ID and world timestamp if present
uint64_t planetWorldId = 0;
uint64_t planetWorldTimestamp = 0;
if ((ptr + 16) <= size()) {
planetWorldId = at<uint64_t>(ptr); ptr += 8;
planetWorldTimestamp = at<uint64_t>(ptr); ptr += 8;
planetWorldId = at<uint64_t>(ptr);
ptr += 8;
planetWorldTimestamp = at<uint64_t>(ptr);
ptr += 8;
}
std::vector< std::pair<uint64_t,uint64_t> > moonIdsAndTimestamps;
@ -427,10 +488,12 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
// Get moon IDs and timestamps if present
if ((ptr + 2) <= size()) {
const unsigned int numMoons = at<uint16_t>(ptr); ptr += 2;
const unsigned int numMoons = at<uint16_t>(ptr);
ptr += 2;
for(unsigned int i=0;i<numMoons;++i) {
if ((World::Type)(*this)[ptr++] == World::TYPE_MOON)
if ((World::Type)(*this)[ptr++] == World::TYPE_MOON) {
moonIdsAndTimestamps.push_back(std::pair<uint64_t,uint64_t>(at<uint64_t>(ptr),at<uint64_t>(ptr + 8)));
}
ptr += 16;
}
}
@ -489,8 +552,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
for(std::vector< std::pair<uint64_t,uint64_t> >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) {
if (i->first == m->id()) {
if (m->timestamp() > i->second)
if (m->timestamp() > i->second) {
m->serialize(outp,false);
}
break;
}
}
@ -500,6 +564,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
Metrics::pkt_ok_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),now);
peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
@ -510,12 +575,14 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_ok_in++;
const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB];
const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID);
uint64_t networkId = 0;
if (!RR->node->expectingReplyTo(inRePacketId))
if (!RR->node->expectingReplyTo(inRePacketId)) {
return true;
}
switch(inReVerb) {
@ -525,19 +592,22 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION];
const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION];
const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION);
if (vProto < ZT_PROTO_VERSION_MIN)
if (vProto < ZT_PROTO_VERSION_MIN) {
return true;
}
InetAddress externalSurfaceAddress;
unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2;
// Get reported external surface address if present
if (ptr < size())
if (ptr < size()) {
ptr += externalSurfaceAddress.deserialize(*this,ptr);
}
// Handle planet or moon updates if present
if ((ptr + 2) <= size()) {
const unsigned int worldsLen = at<uint16_t>(ptr); ptr += 2;
const unsigned int worldsLen = at<uint16_t>(ptr);
ptr += 2;
if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) {
const unsigned int endOfWorlds = ptr + worldsLen;
while (ptr < endOfWorlds) {
@ -551,16 +621,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
}
if (!hops()) {
SharedPtr<Bond> bond = peer->bond();
if (!bond) {
_path->updateLatency((unsigned int)latency,RR->node->now());
}
_path->updateLatency((unsigned int)latency,RR->node->now());
}
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
if ((externalSurfaceAddress)&&(hops() == 0))
if ((externalSurfaceAddress)&&(hops() == 0)) {
RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now());
}
} break;
case Packet::VERB_WHOIS:
@ -573,8 +641,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
case Packet::VERB_NETWORK_CONFIG_REQUEST: {
networkId = at<uint64_t>(ZT_PROTO_VERB_OK_IDX_PAYLOAD);
const SharedPtr<Network> network(RR->node->network(networkId));
if (network)
if (network) {
network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD);
}
} break;
case Packet::VERB_MULTICAST_GATHER: {
@ -599,21 +668,25 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
if ((flags & 0x01) != 0) { // deprecated but still used by older peers
CertificateOfMembership com;
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS);
if (com)
if (com) {
network->addCredential(tPtr,com);
}
}
if ((flags & 0x02) != 0) {
// OK(MULTICAST_FRAME) includes implicit gather results
offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS;
unsigned int totalKnown = at<uint32_t>(offset); offset += 4;
unsigned int count = at<uint16_t>(offset); offset += 2;
unsigned int totalKnown = at<uint32_t>(offset);
offset += 4;
unsigned int count = at<uint16_t>(offset);
offset += 2;
RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(offset,count * 5),count,totalKnown);
}
}
} break;
default: break;
default:
break;
}
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId,ZT_QOS_NO_FLOW);
@ -623,8 +696,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now())))
if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) {
return true;
}
Metrics::pkt_whois_in++;
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_WHOIS);
@ -647,6 +723,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar
}
if (count > 0) {
Metrics::pkt_ok_out++;
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
}
@ -658,6 +735,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar
bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_rendezvous_in++;
if (RR->topology->isUpstream(peer->identity())) {
const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
const SharedPtr<Peer> rendezvousWith(RR->topology->getPeer(tPtr,with));
@ -683,8 +761,9 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const
// Returns true if packet appears valid; pos and proto will be set
static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
{
if (frameLen < 40)
if (frameLen < 40) {
return false;
}
pos = 40;
proto = frameData[6];
while (pos <= frameLen) {
@ -693,8 +772,9 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig
case 43: // routing
case 60: // destination options
case 135: // mobility options
if ((pos + 8) > frameLen)
if ((pos + 8) > frameLen) {
return false; // invalid!
}
proto = frameData[pos];
pos += ((unsigned int)frameData[pos + 1] * 8) + 8;
break;
@ -711,9 +791,9 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig
bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId)
{
Metrics::pkt_frame_in++;
int32_t _flowId = ZT_QOS_NO_FLOW;
SharedPtr<Bond> bond = peer->bond();
if (bond && bond->flowHashingSupported()) {
if (peer->flowHashingSupported()) {
if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
@ -788,8 +868,9 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar
const MAC sourceMac(peer->address(),nwid);
const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
const uint8_t *const frameData = reinterpret_cast<const uint8_t *>(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0)
if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) {
RR->node->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen);
}
}
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
@ -803,6 +884,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar
bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId)
{
Metrics::pkt_ext_frame_in++;
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID);
const SharedPtr<Network> network(RR->node->network(nwid));
if (network) {
@ -812,8 +894,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers
CertificateOfMembership com;
comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM);
if (com)
if (com) {
network->addCredential(tPtr,com);
}
}
if (!network->gate(tPtr,peer)) {
@ -872,6 +955,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
const int64_t now = RR->node->now();
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
Metrics::pkt_ok_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
}
@ -885,6 +969,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_echo_in++;
uint64_t now = RR->node->now();
if (!_path->rateGateEchoRequest(now)) {
return true;
@ -894,10 +979,12 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_ECHO);
outp.append((uint64_t)pid);
if (size() > ZT_PACKET_IDX_PAYLOAD)
if (size() > ZT_PACKET_IDX_PAYLOAD) {
outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
}
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
Metrics::pkt_ok_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
@ -907,6 +994,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share
bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_multicast_like_in++;
const int64_t now = RR->node->now();
bool authorized = false;
uint64_t lastNwid = 0;
@ -917,13 +1005,16 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c
if (nwid != lastNwid) {
lastNwid = nwid;
SharedPtr<Network> network(RR->node->network(nwid));
if (network)
if (network) {
authorized = network->gate(tPtr,peer);
if (!authorized)
}
if (!authorized) {
authorized = ((RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())));
}
}
if (authorized)
if (authorized) {
RR->mc->add(tPtr,now,nwid,MulticastGroup(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14)),peer->address());
}
}
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
@ -932,8 +1023,10 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c
bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
if (!peer->rateGateCredentialsReceived(RR->node->now()))
Metrics::pkt_network_credentials_in++;
if (!peer->rateGateCredentialsReceived(RR->node->now())) {
return true;
}
CertificateOfMembership com;
Capability cap;
@ -965,11 +1058,13 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
++p; // skip trailing 0 after COMs if present
if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations
const unsigned int numCapabilities = at<uint16_t>(p); p += 2;
const unsigned int numCapabilities = at<uint16_t>(p);
p += 2;
for(unsigned int i=0;i<numCapabilities;++i) {
p += cap.deserialize(*this,p);
if ((!network)||(network->id() != cap.networkId()))
if ((!network)||(network->id() != cap.networkId())) {
network = RR->node->network(cap.networkId());
}
if (network) {
switch (network->addCredential(tPtr,cap)) {
case Membership::ADD_REJECTED:
@ -984,13 +1079,17 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
}
}
if (p >= size()) return true;
if (p >= size()) {
return true;
}
const unsigned int numTags = at<uint16_t>(p); p += 2;
const unsigned int numTags = at<uint16_t>(p);
p += 2;
for(unsigned int i=0;i<numTags;++i) {
p += tag.deserialize(*this,p);
if ((!network)||(network->id() != tag.networkId()))
if ((!network)||(network->id() != tag.networkId())) {
network = RR->node->network(tag.networkId());
}
if (network) {
switch (network->addCredential(tPtr,tag)) {
case Membership::ADD_REJECTED:
@ -1005,13 +1104,17 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
}
}
if (p >= size()) return true;
if (p >= size()) {
return true;
}
const unsigned int numRevocations = at<uint16_t>(p); p += 2;
const unsigned int numRevocations = at<uint16_t>(p);
p += 2;
for(unsigned int i=0;i<numRevocations;++i) {
p += revocation.deserialize(*this,p);
if ((!network)||(network->id() != revocation.networkId()))
if ((!network)||(network->id() != revocation.networkId())) {
network = RR->node->network(revocation.networkId());
}
if (network) {
switch(network->addCredential(tPtr,peer->address(),revocation)) {
case Membership::ADD_REJECTED:
@ -1026,13 +1129,17 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
}
}
if (p >= size()) return true;
if (p >= size()) {
return true;
}
const unsigned int numCoos = at<uint16_t>(p); p += 2;
const unsigned int numCoos = at<uint16_t>(p);
p += 2;
for(unsigned int i=0;i<numCoos;++i) {
p += coo.deserialize(*this,p);
if ((!network)||(network->id() != coo.networkId()))
if ((!network)||(network->id() != coo.networkId())) {
network = RR->node->network(coo.networkId());
}
if (network) {
switch(network->addCredential(tPtr,coo)) {
case Membership::ADD_REJECTED:
@ -1055,6 +1162,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_network_config_request_in++;
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
const unsigned int hopCount = hops();
const uint64_t requestPacketId = packetId();
@ -1071,6 +1179,8 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void
outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
outp.append(nwid);
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
Metrics::pkt_error_out++;
Metrics::pkt_error_unsupported_op_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
}
@ -1081,6 +1191,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void
bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_network_config_in++;
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PACKET_IDX_PAYLOAD)));
if (network) {
const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD);
@ -1093,6 +1204,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c
const int64_t now = RR->node->now();
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
Metrics::pkt_ok_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
}
}
@ -1104,6 +1216,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c
bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_multicast_gather_in++;
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID);
const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS];
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI));
@ -1115,8 +1228,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
try {
CertificateOfMembership com;
com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM);
if ((com)&&(network))
if ((com)&&(network)) {
network->addCredential(tPtr,com);
}
} catch ( ... ) {} // discard invalid COMs
}
@ -1133,6 +1247,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
if (gatheredLocally > 0) {
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
Metrics::pkt_ok_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),now);
}
}
@ -1144,6 +1259,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_multicast_frame_in++;
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID);
const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS];
@ -1156,8 +1272,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
// This is deprecated but may still be sent by old peers
CertificateOfMembership com;
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM);
if (com)
if (com) {
network->addCredential(tPtr,com);
}
}
if (!network->gate(tPtr,peer)) {
@ -1203,8 +1320,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen);
if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address())))
if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address()))) {
RR->mc->send(tPtr,RR->node->now(),network,peer->address(),to,from,etherType,frameData,frameLen);
}
if (from != MAC(peer->address(),nwid)) {
if (network->config().permitsBridging(peer->address())) {
@ -1216,8 +1334,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
}
}
if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0)
if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) {
RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen);
}
}
if (gatherLimit) {
@ -1232,6 +1351,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
const int64_t now = RR->node->now();
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
Metrics::pkt_ok_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
}
}
@ -1244,6 +1364,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_push_direct_paths_in++;
const int64_t now = RR->node->now();
if (!peer->rateGatePushDirectPaths(now)) {
@ -1260,7 +1381,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
while (count--) { // if ptr overflows Buffer will throw
unsigned int flags = (*this)[ptr++];
unsigned int extLen = at<uint16_t>(ptr); ptr += 2;
unsigned int extLen = at<uint16_t>(ptr);
ptr += 2;
ptr += extLen; // unused right now
unsigned int addrType = (*this)[ptr++];
unsigned int addrLen = (*this)[ptr++];
@ -1306,6 +1428,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_user_message_in++;
if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) {
ZT_UserMessage um;
um.origin = peer->address().toInt();
@ -1322,6 +1445,7 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con
bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_remote_trace_in++;
ZT_RemoteTrace rt;
const char *ptr = reinterpret_cast<const char *>(data()) + ZT_PACKET_IDX_PAYLOAD;
const char *const eof = reinterpret_cast<const char *>(data()) + size();
@ -1346,9 +1470,9 @@ bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,con
bool IncomingPacket::_doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
Metrics::pkt_path_negotiation_request_in++;
uint64_t now = RR->node->now();
SharedPtr<Bond> bond = peer->bond();
if (!bond || !bond->rateGatePathNegotiation(now, _path)) {
if (!peer->rateGatePathNegotiation(now, _path)) {
return true;
}
if (payloadLength() != sizeof(int16_t)) {
@ -1356,9 +1480,7 @@ bool IncomingPacket::_doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,vo
}
int16_t remoteUtility = 0;
memcpy(&remoteUtility, payload(), sizeof(int16_t));
if (peer->bond()) {
peer->bond()->processIncomingPathNegotiationRequest(now, _path, Utils::ntoh(remoteUtility));
}
peer->processIncomingPathNegotiationRequest(now, _path, Utils::ntoh(remoteUtility));
return true;
}
@ -1370,6 +1492,8 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void
outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
outp.append(nwid);
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
Metrics::pkt_error_out++;
Metrics::pkt_error_need_membership_cert_out++;
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
}

View file

@ -33,46 +33,80 @@ InetAddress::IpScope InetAddress::ipScope() const
case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
switch(ip >> 24) {
case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
case 0x00:
return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
case 0x06:
return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a:
return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b:
return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15:
return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16:
return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19:
return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a:
return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c:
return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d:
return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e:
return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33:
return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37:
return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x38:
return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
case 0x64:
if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE; // 100.64.0.0/10
if ((ip & 0xffc00000) == 0x64400000) {
return IP_SCOPE_PRIVATE; // 100.64.0.0/10
}
break;
case 0x7f: return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
case 0x7f:
return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
case 0xa9:
if ((ip & 0xffff0000) == 0xa9fe0000) return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16
if ((ip & 0xffff0000) == 0xa9fe0000) {
return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16
}
break;
case 0xac:
if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12
if ((ip & 0xfff00000) == 0xac100000) {
return IP_SCOPE_PRIVATE; // 172.16.0.0/12
}
break;
case 0xc0:
if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16
if ((ip & 0xffffff00) == 0xc0000200) return IP_SCOPE_PRIVATE; // 192.0.2.0/24
if ((ip & 0xffff0000) == 0xc0a80000) {
return IP_SCOPE_PRIVATE; // 192.168.0.0/16
}
if ((ip & 0xffffff00) == 0xc0000200) {
return IP_SCOPE_PRIVATE; // 192.0.2.0/24
}
break;
case 0xc6:
if ((ip & 0xfffe0000) == 0xc6120000) return IP_SCOPE_PRIVATE; // 198.18.0.0/15
if ((ip & 0xffffff00) == 0xc6336400) return IP_SCOPE_PRIVATE; // 198.51.100.0/24
if ((ip & 0xfffe0000) == 0xc6120000) {
return IP_SCOPE_PRIVATE; // 198.18.0.0/15
}
if ((ip & 0xffffff00) == 0xc6336400) {
return IP_SCOPE_PRIVATE; // 198.51.100.0/24
}
break;
case 0xcb:
if ((ip & 0xffffff00) == 0xcb007100) return IP_SCOPE_PRIVATE; // 203.0.113.0/24
if ((ip & 0xffffff00) == 0xcb007100) {
return IP_SCOPE_PRIVATE; // 203.0.113.0/24
}
break;
case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
case 0xff:
return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
}
switch(ip >> 28) {
case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4
case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
case 0xe:
return IP_SCOPE_MULTICAST; // 224.0.0.0/4
case 0xf:
return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
}
return IP_SCOPE_GLOBAL;
} break;
@ -80,21 +114,35 @@ InetAddress::IpScope InetAddress::ipScope() const
case AF_INET6: {
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
if ((ip[0] & 0xf0) == 0xf0) {
if (ip[0] == 0xff) return IP_SCOPE_MULTICAST; // ff00::/8
if (ip[0] == 0xff) {
return IP_SCOPE_MULTICAST; // ff00::/8
}
if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) {
unsigned int k = 2;
while ((!ip[k])&&(k < 15)) ++k;
if ((k == 15)&&(ip[15] == 0x01))
return IP_SCOPE_LOOPBACK; // fe80::1/128
else return IP_SCOPE_LINK_LOCAL; // fe80::/10
while ((!ip[k])&&(k < 15)) {
++k;
}
if ((k == 15)&&(ip[15] == 0x01)) {
return IP_SCOPE_LOOPBACK; // fe80::1/128
} else {
return IP_SCOPE_LINK_LOCAL; // fe80::/10
}
}
if ((ip[0] & 0xfe) == 0xfc) {
return IP_SCOPE_PRIVATE; // fc00::/7
}
if ((ip[0] & 0xfe) == 0xfc) return IP_SCOPE_PRIVATE; // fc00::/7
}
unsigned int k = 0;
while ((!ip[k])&&(k < 15)) ++k;
while ((!ip[k])&&(k < 15)) {
++k;
}
if (k == 15) { // all 0's except last byte
if (ip[15] == 0x01) return IP_SCOPE_LOOPBACK; // ::1/128
if (ip[15] == 0x00) return IP_SCOPE_NONE; // ::/128
if (ip[15] == 0x01) {
return IP_SCOPE_LOOPBACK; // ::1/128
}
if (ip[15] == 0x00) {
return IP_SCOPE_NONE; // ::/128
}
}
return IP_SCOPE_GLOBAL;
} break;
@ -124,7 +172,9 @@ char *InetAddress::toString(char buf[64]) const
{
char *p = toIpString(buf);
if (*p) {
while (*p) ++p;
while (*p) {
++p;
}
*(p++) = '/';
Utils::decimal(port(),p);
}
@ -160,14 +210,17 @@ bool InetAddress::fromString(const char *ipSlashPort)
memset(this,0,sizeof(InetAddress));
if (!*ipSlashPort)
if (!*ipSlashPort) {
return true;
if (!Utils::scopy(buf,sizeof(buf),ipSlashPort))
}
if (!Utils::scopy(buf,sizeof(buf),ipSlashPort)) {
return false;
}
char *portAt = buf;
while ((*portAt)&&(*portAt != '/'))
while ((*portAt)&&(*portAt != '/')) {
++portAt;
}
unsigned int port = 0;
if (*portAt) {
*(portAt++) = (char)0;
@ -255,8 +308,9 @@ bool InetAddress::isEqualPrefix(const InetAddress &addr) const
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr);
const uint8_t *b = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
for(unsigned int i=0;i<16;++i) {
if ((a[i] & m[i]) != (b[i] & n[i]))
if ((a[i] & m[i]) != (b[i] & n[i])) {
return false;
}
}
return true;
}
@ -271,8 +325,9 @@ bool InetAddress::containsAddress(const InetAddress &addr) const
switch(ss_family) {
case AF_INET: {
const unsigned int bits = netmaskBits();
if (bits == 0)
if (bits == 0) {
return true;
}
return ( (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) >> (32 - bits)) );
}
case AF_INET6: {
@ -281,8 +336,9 @@ bool InetAddress::containsAddress(const InetAddress &addr) const
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr);
const uint8_t *b = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
for(unsigned int i=0;i<16;++i) {
if ((a[i] & m[i]) != b[i])
if ((a[i] & m[i]) != b[i]) {
return false;
}
}
return true;
}
@ -296,26 +352,32 @@ bool InetAddress::isNetwork() const
switch(ss_family) {
case AF_INET: {
unsigned int bits = netmaskBits();
if (bits <= 0)
if (bits <= 0) {
return false;
if (bits >= 32)
}
if (bits >= 32) {
return false;
}
uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
return ((ip & (0xffffffff >> bits)) == 0);
}
case AF_INET6: {
unsigned int bits = netmaskBits();
if (bits <= 0)
if (bits <= 0) {
return false;
if (bits >= 128)
}
if (bits >= 128) {
return false;
}
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
unsigned int p = bits / 8;
if ((ip[p++] & (0xff >> (bits % 8))) != 0)
if ((ip[p++] & (0xff >> (bits % 8))) != 0) {
return false;
}
while (p < 16) {
if (ip[p++])
if (ip[p++]) {
return false;
}
}
return true;
}
@ -348,30 +410,32 @@ bool InetAddress::operator==(const InetAddress &a) const
bool InetAddress::operator<(const InetAddress &a) const
{
if (ss_family < a.ss_family)
if (ss_family < a.ss_family) {
return true;
else if (ss_family == a.ss_family) {
} else if (ss_family == a.ss_family) {
switch(ss_family) {
case AF_INET:
if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port)
if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port) {
return true;
else if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port) {
if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr)
} else if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port) {
if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr) {
return true;
}
}
break;
case AF_INET6:
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port)
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port) {
return true;
else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port) {
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo)
} else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port) {
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo) {
return true;
else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo) {
if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) < 0)
} else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo) {
if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) < 0) {
return true;
else if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0) {
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_scope_id < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_scope_id)
} else if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0) {
if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_scope_id < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_scope_id) {
return true;
}
}
}
}

View file

@ -94,29 +94,33 @@ struct InetAddress : public sockaddr_storage
inline InetAddress &operator=(const InetAddress &a)
{
if (&a != this)
if (&a != this) {
memcpy(this,&a,sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const InetAddress *a)
{
if (a != this)
if (a != this) {
memcpy(this,a,sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage &ss)
{
if (reinterpret_cast<const InetAddress *>(&ss) != this)
if (reinterpret_cast<const InetAddress *>(&ss) != this) {
memcpy(this,&ss,sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage *ss)
{
if (reinterpret_cast<const InetAddress *>(ss) != this)
if (reinterpret_cast<const InetAddress *>(ss) != this) {
memcpy(this,ss,sizeof(InetAddress));
}
return *this;
}
@ -230,8 +234,9 @@ struct InetAddress : public sockaddr_storage
case AF_INET6:
const uint8_t *ipb = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
for(int i=0;i<16;++i) {
if (ipb[i])
if (ipb[i]) {
return false;
}
}
return (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == 0);
}
@ -260,9 +265,12 @@ struct InetAddress : public sockaddr_storage
inline unsigned int port() const
{
switch(ss_family) {
case AF_INET: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port));
case AF_INET6: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port));
default: return 0;
case AF_INET:
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port));
case AF_INET6:
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port));
default:
return 0;
}
}
@ -284,8 +292,10 @@ struct InetAddress : public sockaddr_storage
{
const unsigned int n = port();
switch(ss_family) {
case AF_INET: return (n <= 32);
case AF_INET6: return (n <= 128);
case AF_INET:
return (n <= 32);
case AF_INET6:
return (n <= 128);
}
return false;
}
@ -356,9 +366,12 @@ struct InetAddress : public sockaddr_storage
inline const void *rawIpData() const
{
switch(ss_family) {
case AF_INET: return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
case AF_INET6: return (const void *)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
default: return 0;
case AF_INET:
return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
case AF_INET6:
return (const void *)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
default:
return 0;
}
}
@ -390,10 +403,12 @@ struct InetAddress : public sockaddr_storage
inline bool ipsEqual(const InetAddress &a) const
{
if (ss_family == a.ss_family) {
if (ss_family == AF_INET)
if (ss_family == AF_INET) {
return (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr);
if (ss_family == AF_INET6)
}
if (ss_family == AF_INET6) {
return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0);
}
return (memcmp(this,&a,sizeof(InetAddress)) == 0);
}
return false;
@ -410,10 +425,12 @@ struct InetAddress : public sockaddr_storage
inline bool ipsEqual2(const InetAddress &a) const
{
if (ss_family == a.ss_family) {
if (ss_family == AF_INET)
if (ss_family == AF_INET) {
return (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr);
if (ss_family == AF_INET6)
return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,8) == 0);
}
if (ss_family == AF_INET6) {
return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr, 8) == 0);
}
return (memcmp(this,&a,sizeof(InetAddress)) == 0);
}
return false;
@ -426,14 +443,16 @@ struct InetAddress : public sockaddr_storage
} else if (ss_family == AF_INET6) {
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
for(long i=0;i<16;++i)
for(long i=0;i<16;++i) {
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i];
}
return tmp;
} else {
unsigned long tmp = reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port;
const uint8_t *a = reinterpret_cast<const uint8_t *>(this);
for(long i=0;i<(long)sizeof(InetAddress);++i)
for(long i=0;i<(long)sizeof(InetAddress);++i) {
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i];
}
return tmp;
}
}
@ -470,8 +489,9 @@ struct InetAddress : public sockaddr_storage
while ((ip0 >> 31) == (ip1 >> 31)) {
ip0 <<= 1;
ip1 <<= 1;
if (++c == 32)
if (++c == 32) {
break;
}
}
} break;
case AF_INET6: {
@ -485,8 +505,9 @@ struct InetAddress : public sockaddr_storage
uint8_t ip1b = ip1[i];
uint8_t bit = 0x80;
while (bit != 0) {
if ((ip0b & bit) != (ip1b & bit))
if ((ip0b & bit) != (ip1b & bit)) {
break;
}
++c;
bit >>= 1;
}
@ -512,11 +533,16 @@ struct InetAddress : public sockaddr_storage
break;
case AF_INET6: {
const uint8_t *ip = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
h = ((unsigned long)ip[0]); h <<= 1;
h += ((unsigned long)ip[1]); h <<= 1;
h += ((unsigned long)ip[2]); h <<= 1;
h += ((unsigned long)ip[3]); h <<= 1;
h += ((unsigned long)ip[4]); h <<= 1;
h = ((unsigned long)ip[0]);
h <<= 1;
h += ((unsigned long)ip[1]);
h <<= 1;
h += ((unsigned long)ip[2]);
h <<= 1;
h += ((unsigned long)ip[3]);
h <<= 1;
h += ((unsigned long)ip[4]);
h <<= 1;
h += ((unsigned long)ip[5]);
} break;
}
@ -570,13 +596,17 @@ struct InetAddress : public sockaddr_storage
return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
case 0x04:
ss_family = AF_INET;
memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); p += 4;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4);
p += 4;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p));
p += 2;
break;
case 0x06:
ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16); p += 16;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16);
p += 16;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p));
p += 2;
break;
default:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;

View file

@ -71,11 +71,16 @@ public:
return;
}
const unsigned char *b = (const unsigned char *)bits;
_m = ((((uint64_t)*b) & 0xff) << 40); ++b;
_m |= ((((uint64_t)*b) & 0xff) << 32); ++b;
_m |= ((((uint64_t)*b) & 0xff) << 24); ++b;
_m |= ((((uint64_t)*b) & 0xff) << 16); ++b;
_m |= ((((uint64_t)*b) & 0xff) << 8); ++b;
_m = ((((uint64_t)*b) & 0xff) << 40);
++b;
_m |= ((((uint64_t)*b) & 0xff) << 32);
++b;
_m |= ((((uint64_t)*b) & 0xff) << 24);
++b;
_m |= ((((uint64_t)*b) & 0xff) << 16);
++b;
_m |= ((((uint64_t)*b) & 0xff) << 8);
++b;
_m |= (((uint64_t)*b) & 0xff);
}
@ -85,8 +90,9 @@ public:
*/
inline void copyTo(void *buf,unsigned int len) const
{
if (len < 6)
if (len < 6) {
return;
}
unsigned char *b = (unsigned char *)buf;
*(b++) = (unsigned char)((_m >> 40) & 0xff);
*(b++) = (unsigned char)((_m >> 32) & 0xff);

View file

@ -39,18 +39,21 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
{
const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES];
unsigned int sendCapCount = 0;
for(unsigned int c=0;c<nconf.capabilityCount;++c)
for(unsigned int c=0;c<nconf.capabilityCount;++c) {
sendCaps[sendCapCount++] = &(nconf.capabilities[c]);
}
const Tag *sendTags[ZT_MAX_NETWORK_TAGS];
unsigned int sendTagCount = 0;
for(unsigned int t=0;t<nconf.tagCount;++t)
for(unsigned int t=0;t<nconf.tagCount;++t) {
sendTags[sendTagCount++] = &(nconf.tags[t]);
}
const CertificateOfOwnership *sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
unsigned int sendCooCount = 0;
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c)
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c) {
sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]);
}
unsigned int capPtr = 0;
unsigned int tagPtr = 0;
@ -97,6 +100,7 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
outp.compress();
RR->sw->send(tPtr,outp,true);
Metrics::pkt_network_credentials_out++;
}
_lastPushedCredentials = now;
@ -115,8 +119,9 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
RR->t->credentialRejected(tPtr,com,"old");
return ADD_REJECTED;
}
if (_com == com)
if (_com == com) {
return ADD_ACCEPTED_REDUNDANT;
}
switch(com.verify(RR,tPtr)) {
default:
@ -141,8 +146,9 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
RR->t->credentialRejected(tPtr,cred,"old");
return Membership::ADD_REJECTED;
}
if (*rc == cred)
if (*rc == cred) {
return Membership::ADD_ACCEPTED_REDUNDANT;
}
}
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
@ -156,8 +162,9 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
RR->t->credentialRejected(tPtr,cred,"invalid");
return Membership::ADD_REJECTED;
case 0:
if (!rc)
if (!rc) {
rc = &(remoteCreds[cred.id()]);
}
*rc = cred;
return Membership::ADD_ACCEPTED_NEW;
case 1:

View file

@ -115,8 +115,9 @@ public:
CertificateOfOwnership *v = (CertificateOfOwnership *)0;
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
while (i.next(k,v)) {
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r))) {
return true;
}
}
return _isV6NDPEmulated(nconf,r);
}
@ -187,8 +188,9 @@ private:
break;
}
}
if (prefixMatches)
if (prefixMatches) {
return true;
}
break;
}
}
@ -203,8 +205,9 @@ private:
break;
}
}
if (prefixMatches)
if (prefixMatches) {
return true;
}
break;
}
}
@ -230,8 +233,9 @@ private:
C *v = (C *)0;
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
while (i.next(k,v)) {
if (!_isCredentialTimestampValid(nconf,*v))
if (!_isCredentialTimestampValid(nconf,*v)) {
remoteCreds.erase(*k);
}
}
}
@ -271,8 +275,9 @@ public:
inline Capability *next()
{
while (_hti.next(_k,_c)) {
if (_m._isCredentialTimestampValid(_nconf,*_c))
if (_m._isCredentialTimestampValid(_nconf,*_c)) {
return _c;
}
}
return (Capability *)0;
}

272
node/Metrics.cpp Normal file
View file

@ -0,0 +1,272 @@
/*
* Copyright (c)2013-2023 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: 2025-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.
*/
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h>
namespace prometheus {
namespace simpleapi {
std::shared_ptr<Registry> registry_ptr = std::make_shared<Registry>();
Registry& registry = *registry_ptr;
SaveToFile saver;
}
}
namespace ZeroTier {
namespace Metrics {
// Packet Type Counts
prometheus::simpleapi::counter_family_t packets
{ "zt_packet", "ZeroTier packet type counts"};
// Incoming packets
prometheus::simpleapi::counter_metric_t pkt_nop_in
{ packets.Add({{"packet_type", "nop"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_in
{ packets.Add({{"packet_type", "error"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ack_in
{ packets.Add({{"packet_type", "ack"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_qos_in
{ packets.Add({{"packet_type", "qos"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_hello_in
{ packets.Add({{"packet_type", "hello"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ok_in
{ packets.Add({{"packet_type", "ok"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_whois_in
{ packets.Add({{"packet_type", "whois"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_in
{ packets.Add({{"packet_type", "rendezvous"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_frame_in
{ packets.Add({{"packet_type", "frame"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_in
{ packets.Add({{"packet_type", "ext_frame"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_echo_in
{ packets.Add({{"packet_type", "echo"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_in
{ packets.Add({{"packet_type", "multicast_like"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_in
{ packets.Add({{"packet_type", "network_credentials"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_in
{ packets.Add({{"packet_type", "network_config_request"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_in
{ packets.Add({{"packet_type", "network_config"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in
{ packets.Add({{"packet_type", "multicast_gather"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in
{ packets.Add({{"packet_type", "multicast_frame"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in
{ packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_user_message_in
{ packets.Add({{"packet_type", "user_message"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_in
{ packets.Add({{"packet_type", "remote_trace"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in
{ packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "rx"}}) };
// Outgoing packets
prometheus::simpleapi::counter_metric_t pkt_nop_out
{ packets.Add({{"packet_type", "nop"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_out
{ packets.Add({{"packet_type", "error"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ack_out
{ packets.Add({{"packet_type", "ack"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_qos_out
{ packets.Add({{"packet_type", "qos"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_hello_out
{ packets.Add({{"packet_type", "hello"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ok_out
{ packets.Add({{"packet_type", "ok"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_whois_out
{ packets.Add({{"packet_type", "whois"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_rendezvous_out
{ packets.Add({{"packet_type", "rendezvous"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_frame_out
{ packets.Add({{"packet_type", "frame"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_ext_frame_out
{ packets.Add({{"packet_type", "ext_frame"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_echo_out
{ packets.Add({{"packet_type", "echo"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_like_out
{ packets.Add({{"packet_type", "multicast_like"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_credentials_out
{ packets.Add({{"packet_type", "network_credentials"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_request_out
{ packets.Add({{"packet_type", "network_config_request"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_network_config_out
{ packets.Add({{"packet_type", "network_config"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out
{ packets.Add({{"packet_type", "multicast_gather"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out
{ packets.Add({{"packet_type", "multicast_frame"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out
{ packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_user_message_out
{ packets.Add({{"packet_type", "user_message"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_remote_trace_out
{ packets.Add({{"packet_type", "remote_trace"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out
{ packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "tx"}}) };
// Packet Error Counts
prometheus::simpleapi::counter_family_t packet_errors
{ "zt_packet_error", "ZeroTier packet errors"};
// Incoming Error Counts
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in
{ packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in
{ packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in
{ packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in
{ packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in
{ packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in
{ packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in
{ packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "rx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in
{ packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "rx"}}) };
// Outgoing Error Counts
prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out
{ packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out
{ packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out
{ packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out
{ packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out
{ packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out
{ packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out
{ packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out
{ packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "tx"}}) };
// Data Sent/Received Metrics
prometheus::simpleapi::counter_family_t data
{ "zt_data", "number of bytes ZeroTier has transmitted or received" };
prometheus::simpleapi::counter_metric_t udp_recv
{ data.Add({{"protocol","udp"},{"direction","rx"}}) };
prometheus::simpleapi::counter_metric_t udp_send
{ data.Add({{"protocol","udp"},{"direction","tx"}}) };
prometheus::simpleapi::counter_metric_t tcp_send
{ data.Add({{"protocol","tcp"},{"direction", "tx"}}) };
prometheus::simpleapi::counter_metric_t tcp_recv
{ data.Add({{"protocol","tcp"},{"direction", "rx"}}) };
// Network Metrics
prometheus::simpleapi::gauge_metric_t network_num_joined
{ "zt_num_networks", "number of networks this instance is joined to" };
prometheus::simpleapi::gauge_family_t network_num_multicast_groups
{ "zt_network_multicast_groups_subscribed", "number of multicast groups networks are subscribed to" };
prometheus::simpleapi::counter_family_t network_packets
{ "zt_network_packets", "number of incoming/outgoing packets per network" };
#ifndef ZT_NO_PEER_METRICS
// PeerMetrics
prometheus::CustomFamily<prometheus::Histogram<uint64_t>> &peer_latency =
prometheus::Builder<prometheus::Histogram<uint64_t>>()
.Name("zt_peer_latency")
.Help("peer latency (ms)")
.Register(prometheus::simpleapi::registry);
prometheus::simpleapi::gauge_family_t peer_path_count
{ "zt_peer_path_count", "number of paths to peer" };
prometheus::simpleapi::counter_family_t peer_packets
{ "zt_peer_packets", "number of packets to/from a peer" };
prometheus::simpleapi::counter_family_t peer_packet_errors
{ "zt_peer_packet_errors" , "number of incoming packet errors from a peer" };
#endif
// General Controller Metrics
prometheus::simpleapi::gauge_metric_t network_count
{"controller_network_count", "number of networks the controller is serving"};
prometheus::simpleapi::gauge_metric_t member_count
{"controller_member_count", "number of network members the controller is serving"};
prometheus::simpleapi::counter_metric_t network_changes
{"controller_network_change_count", "number of times a network configuration is changed"};
prometheus::simpleapi::counter_metric_t member_changes
{"controller_member_change_count", "number of times a network member configuration is changed"};
prometheus::simpleapi::counter_metric_t member_auths
{"controller_member_auth_count", "number of network member auths"};
prometheus::simpleapi::counter_metric_t member_deauths
{"controller_member_deauth_count", "number of network member deauths"};
prometheus::simpleapi::gauge_metric_t network_config_request_queue_size
{ "controller_network_config_request_queue", "number of entries in the request queue for network configurations" };
prometheus::simpleapi::counter_metric_t sso_expiration_checks
{ "controller_sso_expiration_checks", "number of sso expiration checks done" };
prometheus::simpleapi::counter_metric_t sso_member_deauth
{ "controller_sso_timeouts", "number of sso timeouts" };
prometheus::simpleapi::counter_metric_t network_config_request
{ "controller_network_config_request", "count of config requests handled" };
prometheus::simpleapi::gauge_metric_t network_config_request_threads
{ "controller_network_config_request_threads", "number of active network config handling threads" };
prometheus::simpleapi::counter_metric_t db_get_network
{ "controller_db_get_network", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member
{ "controller_db_get_network_and_member", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary
{ "controller_db_get_networK_and_member_summary", "counter" };
prometheus::simpleapi::counter_metric_t db_get_member_list
{ "controller_db_get_member_list", "counter" };
prometheus::simpleapi::counter_metric_t db_get_network_list
{ "controller_db_get_network_list", "counter" };
prometheus::simpleapi::counter_metric_t db_member_change
{ "controller_db_member_change", "counter" };
prometheus::simpleapi::counter_metric_t db_network_change
{ "controller_db_network_change", "counter" };
#ifdef ZT_CONTROLLER_USE_LIBPQ
// Central Controller Metrics
prometheus::simpleapi::counter_metric_t pgsql_mem_notification
{ "controller_pgsql_member_notifications_received", "number of member change notifications received via pgsql NOTIFY" };
prometheus::simpleapi::counter_metric_t pgsql_net_notification
{ "controller_pgsql_network_notifications_received", "number of network change notifications received via pgsql NOTIFY" };
prometheus::simpleapi::counter_metric_t pgsql_node_checkin
{ "controller_pgsql_node_checkin_count", "number of node check-ins (pgsql)" };
prometheus::simpleapi::counter_metric_t pgsql_commit_ticks
{ "controller_pgsql_commit_ticks", "number of commit ticks run (pgsql)" };
prometheus::simpleapi::counter_metric_t db_get_sso_info
{ "controller_db_get_sso_info", "counter" };
prometheus::simpleapi::counter_metric_t redis_mem_notification
{ "controller_redis_member_notifications_received", "number of member change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_net_notification
{ "controller_redis_network_notifications_received", "number of network change notifications received via redis" };
prometheus::simpleapi::counter_metric_t redis_node_checkin
{ "controller_redis_node_checkin_count", "number of node check-ins (redis)" };
// Central DB Pool Metrics
prometheus::simpleapi::counter_metric_t conn_counter
{ "controller_pgsql_connections_created", "number of pgsql connections created"};
prometheus::simpleapi::counter_metric_t max_pool_size
{ "controller_pgsql_max_conn_pool_size", "max connection pool size for postgres"};
prometheus::simpleapi::counter_metric_t min_pool_size
{ "controller_pgsql_min_conn_pool_size", "minimum connection pool size for postgres" };
prometheus::simpleapi::gauge_metric_t pool_avail
{ "controller_pgsql_available_conns", "number of available postgres connections" };
prometheus::simpleapi::gauge_metric_t pool_in_use
{ "controller_pgsql_in_use_conns", "number of postgres database connections in use" };
prometheus::simpleapi::counter_metric_t pool_errors
{ "controller_pgsql_connection_errors", "number of connection errors the connection pool has seen" };
#endif
}
}

166
node/Metrics.hpp Normal file
View file

@ -0,0 +1,166 @@
/*
* Copyright (c)2013-2023 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: 2025-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.
*/
#ifndef METRICS_H_
#define METRICS_H_
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h>
namespace prometheus {
namespace simpleapi {
extern std::shared_ptr<Registry> registry_ptr;
}
}
namespace ZeroTier {
namespace Metrics {
// Packet Type Counts
extern prometheus::simpleapi::counter_family_t packets;
// incoming packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_in;
extern prometheus::simpleapi::counter_metric_t pkt_ack_in;
extern prometheus::simpleapi::counter_metric_t pkt_qos_in;
extern prometheus::simpleapi::counter_metric_t pkt_hello_in;
extern prometheus::simpleapi::counter_metric_t pkt_ok_in;
extern prometheus::simpleapi::counter_metric_t pkt_whois_in;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_in;
extern prometheus::simpleapi::counter_metric_t pkt_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_echo_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_in;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_in;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_in;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in;
// outgoing packets
extern prometheus::simpleapi::counter_metric_t pkt_nop_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_out;
extern prometheus::simpleapi::counter_metric_t pkt_ack_out;
extern prometheus::simpleapi::counter_metric_t pkt_qos_out;
extern prometheus::simpleapi::counter_metric_t pkt_hello_out;
extern prometheus::simpleapi::counter_metric_t pkt_ok_out;
extern prometheus::simpleapi::counter_metric_t pkt_whois_out;
extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_out;
extern prometheus::simpleapi::counter_metric_t pkt_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_echo_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_out;
extern prometheus::simpleapi::counter_metric_t pkt_network_config_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out;
extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out;
extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out;
extern prometheus::simpleapi::counter_metric_t pkt_user_message_out;
extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_out;
extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out;
// Packet Error Counts
extern prometheus::simpleapi::counter_family_t packet_errors;
// incoming errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in;
// outgoing errors
extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out;
extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out;
// Data Sent/Received Metrics
extern prometheus::simpleapi::counter_family_t data;
extern prometheus::simpleapi::counter_metric_t udp_send;
extern prometheus::simpleapi::counter_metric_t udp_recv;
extern prometheus::simpleapi::counter_metric_t tcp_send;
extern prometheus::simpleapi::counter_metric_t tcp_recv;
// Network Metrics
extern prometheus::simpleapi::gauge_metric_t network_num_joined;
extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups;
extern prometheus::simpleapi::counter_family_t network_packets;
#ifndef ZT_NO_PEER_METRICS
// Peer Metrics
extern prometheus::CustomFamily<prometheus::Histogram<uint64_t>> &peer_latency;
extern prometheus::simpleapi::gauge_family_t peer_path_count;
extern prometheus::simpleapi::counter_family_t peer_packets;
extern prometheus::simpleapi::counter_family_t peer_packet_errors;
#endif
// General Controller Metrics
extern prometheus::simpleapi::gauge_metric_t network_count;
extern prometheus::simpleapi::gauge_metric_t member_count;
extern prometheus::simpleapi::counter_metric_t network_changes;
extern prometheus::simpleapi::counter_metric_t member_changes;
extern prometheus::simpleapi::counter_metric_t member_auths;
extern prometheus::simpleapi::counter_metric_t member_deauths;
extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size;
extern prometheus::simpleapi::counter_metric_t sso_expiration_checks;
extern prometheus::simpleapi::counter_metric_t sso_member_deauth;
extern prometheus::simpleapi::counter_metric_t network_config_request;
extern prometheus::simpleapi::gauge_metric_t network_config_request_threads;
extern prometheus::simpleapi::counter_metric_t db_get_network;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member;
extern prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary;
extern prometheus::simpleapi::counter_metric_t db_get_member_list;
extern prometheus::simpleapi::counter_metric_t db_get_network_list;
extern prometheus::simpleapi::counter_metric_t db_member_change;
extern prometheus::simpleapi::counter_metric_t db_network_change;
#ifdef ZT_CONTROLLER_USE_LIBPQ
// Central Controller Metrics
extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_net_notification;
extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin;
extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks;
extern prometheus::simpleapi::counter_metric_t db_get_sso_info;
extern prometheus::simpleapi::counter_metric_t redis_mem_notification;
extern prometheus::simpleapi::counter_metric_t redis_net_notification;
extern prometheus::simpleapi::counter_metric_t redis_node_checkin;
// Central DB Pool Metrics
extern prometheus::simpleapi::counter_metric_t conn_counter;
extern prometheus::simpleapi::counter_metric_t max_pool_size;
extern prometheus::simpleapi::counter_metric_t min_pool_size;
extern prometheus::simpleapi::gauge_metric_t pool_avail;
extern prometheus::simpleapi::gauge_metric_t pool_in_use;
extern prometheus::simpleapi::counter_metric_t pool_errors;
#endif
} // namespace Metrics
}// namespace ZeroTier
#endif // METRICS_H_

View file

@ -92,10 +92,11 @@ public:
inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); }
inline bool operator<(const MulticastGroup &g) const
{
if (_mac < g._mac)
if (_mac < g._mac) {
return true;
else if (_mac == g._mac)
} else if (_mac == g._mac) {
return (_adi < g._adi);
}
return false;
}
inline bool operator>(const MulticastGroup &g) const { return (g < *this); }

View file

@ -69,10 +69,11 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const
unsigned int added = 0,i,k,rptr,totalKnown = 0;
uint64_t a,picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2];
if (!limit)
if (!limit) {
return 0;
else if (limit > 0xffff)
} else if (limit > 0xffff) {
limit = 0xffff;
}
const unsigned int totalAt = appendTo.size();
appendTo.addSize(4); // sizeof(uint32_t)
@ -133,12 +134,14 @@ std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup
std::vector<Address> ls;
Mutex::Lock _l(_groups_m);
const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
if (!s)
if (!s) {
return ls;
}
for(std::vector<MulticastGroupMember>::const_reverse_iterator m(s->members.rbegin());m!=s->members.rend();++m) {
ls.push_back(m->address);
if (ls.size() >= limit)
if (ls.size() >= limit) {
break;
}
}
return ls;
}
@ -193,8 +196,11 @@ void Multicaster::send(
outp.append((uint32_t)mg.adi());
outp.append((uint16_t)etherType);
outp.append(data,len);
if (!network->config().disableCompression()) outp.compress();
if (!network->config().disableCompression()) {
outp.compress();
}
outp.armor(bestMulticastReplicator->key(),true,bestMulticastReplicator->aesKeysIfSupported());
Metrics::pkt_multicast_frame_out++;
bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now);
return;
}
@ -208,12 +214,14 @@ void Multicaster::send(
if (!gs.members.empty()) {
// Allocate a memory buffer if group is monstrous
if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long)))
if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) {
indexes = new unsigned long[gs.members.size()];
}
// Generate a random permutation of member indexes
for(unsigned long i=0;i<gs.members.size();++i)
for(unsigned long i=0;i<gs.members.size();++i) {
indexes[i] = i;
}
for(unsigned long i=(unsigned long)gs.members.size()-1;i>0;--i) {
unsigned long j = (unsigned long)RR->node->prng() % (i + 1);
unsigned long tmp = indexes[j];
@ -248,8 +256,9 @@ void Multicaster::send(
for(unsigned int i=0;i<activeBridgeCount;++i) {
if ((activeBridges[i] != RR->identity.address())&&(activeBridges[i] != origin)) {
out.sendOnly(RR,tPtr,activeBridges[i]); // optimization: don't use dedup log if it's a one-pass send
if (++count >= limit)
if (++count >= limit) {
break;
}
}
}
@ -276,16 +285,18 @@ void Multicaster::send(
unsigned int numExplicitGatherPeers = 0;
SharedPtr<Peer> bestRoot(RR->topology->getUpstreamPeer());
if (bestRoot)
if (bestRoot) {
explicitGatherPeers[numExplicitGatherPeers++] = bestRoot->address();
}
explicitGatherPeers[numExplicitGatherPeers++] = network->controller();
Address ac[ZT_MAX_NETWORK_SPECIALISTS];
const unsigned int accnt = network->config().alwaysContactAddresses(ac);
unsigned int shuffled[ZT_MAX_NETWORK_SPECIALISTS];
for(unsigned int i=0;i<accnt;++i)
for(unsigned int i=0;i<accnt;++i) {
shuffled[i] = i;
}
for(unsigned int i=0,k=accnt>>1;i<k;++i) {
const uint64_t x = RR->node->prng();
const unsigned int x1 = shuffled[(unsigned int)x % accnt];
@ -296,16 +307,18 @@ void Multicaster::send(
}
for(unsigned int i=0;i<accnt;++i) {
explicitGatherPeers[numExplicitGatherPeers++] = ac[shuffled[i]];
if (numExplicitGatherPeers == 16)
if (numExplicitGatherPeers == 16) {
break;
}
}
std::vector<Address> anchors(network->config().anchors());
for(std::vector<Address>::const_iterator a(anchors.begin());a!=anchors.end();++a) {
if (*a != RR->identity.address()) {
explicitGatherPeers[numExplicitGatherPeers++] = *a;
if (numExplicitGatherPeers == 16)
if (numExplicitGatherPeers == 16) {
break;
}
}
}
@ -317,10 +330,12 @@ void Multicaster::send(
mg.mac().appendTo(outp);
outp.append((uint32_t)mg.adi());
outp.append((uint32_t)gatherLimit);
if (com)
if (com) {
com->serialize(outp);
}
RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,true);
Metrics::pkt_multicast_gather_out++;
}
}
@ -340,16 +355,18 @@ void Multicaster::send(
data,
len);
if (origin)
if (origin) {
out.logAsSent(origin);
}
unsigned int count = 0;
for(unsigned int i=0;i<activeBridgeCount;++i) {
if (activeBridges[i] != RR->identity.address()) {
out.sendAndLog(RR,tPtr,activeBridges[i]);
if (++count >= limit)
if (++count >= limit) {
break;
}
}
}
@ -365,8 +382,9 @@ void Multicaster::send(
} catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted
// Free allocated memory buffer if any
if (indexes != idxbuf)
if (indexes != idxbuf) {
delete [] indexes;
}
}
void Multicaster::clean(int64_t now)
@ -377,9 +395,11 @@ void Multicaster::clean(int64_t now)
Hashtable<Multicaster::Key,MulticastGroupStatus>::Iterator mm(_groups);
while (mm.next(k,s)) {
for(std::list<OutboundMulticast>::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) {
if ((tx->expired(now))||(tx->atLimit()))
if ((tx->expired(now))||(tx->atLimit())) {
s->txQueue.erase(tx++);
else ++tx;
} else {
++tx;
}
}
unsigned long count = 0;
@ -411,8 +431,9 @@ void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup
// assumes _groups_m is locked
// Do not add self -- even if someone else returns it
if (member == RR->identity.address())
if (member == RR->identity.address()) {
return;
}
std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(),gs.members.end(),member));
if (m != gs.members.end()) {
@ -426,13 +447,15 @@ void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup
}
for(std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
if (tx->atLimit())
if (tx->atLimit()) {
gs.txQueue.erase(tx++);
else {
} else {
tx->sendIfNew(RR,tPtr,member);
if (tx->atLimit())
if (tx->atLimit()) {
gs.txQueue.erase(tx++);
else ++tx;
} else {
++tx;
}
}
}
}

View file

@ -32,6 +32,7 @@
#include "Node.hpp"
#include "Peer.hpp"
#include "Trace.hpp"
#include "Metrics.hpp"
#include <set>
@ -42,8 +43,9 @@ namespace {
// Returns true if packet appears valid; pos and proto will be set
static inline bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
{
if (frameLen < 40)
if (frameLen < 40) {
return false;
}
pos = 40;
proto = frameData[6];
while (pos <= frameLen) {
@ -52,8 +54,9 @@ static inline bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLe
case 43: // routing
case 60: // destination options
case 135: // mobility options
if ((pos + 8) > frameLen)
if ((pos + 8) > frameLen) {
return false; // invalid!
}
proto = frameData[pos];
pos += ((unsigned int)frameData[pos + 1] * 8) + 8;
break;
@ -165,8 +168,9 @@ static _doZtFilterResult _doZtFilter(
case ZT_NETWORK_RULE_ACTION_TEE:
case ZT_NETWORK_RULE_ACTION_WATCH:
case ZT_NETWORK_RULE_ACTION_REDIRECT:
if (RR->identity.address() == rules[rn].v.fwd.address)
if (RR->identity.address() == rules[rn].v.fwd.address) {
superAccept = true;
}
break;
default:
break;
@ -342,7 +346,9 @@ static _doZtFilterResult _doZtFilter(
case 0x84: // SCTP
case 0x88: // UDPLite
if (frameLen > (pos + 4)) {
if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) pos += 2;
if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) {
pos += 2;
}
p = (int)frameData[pos++] << 8;
p |= (int)frameData[pos];
}
@ -358,8 +364,12 @@ static _doZtFilterResult _doZtFilter(
break;
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: {
uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL;
if (macDest.isMulticast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST;
if (macDest.isBroadcast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST;
if (macDest.isMulticast()) {
cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST;
}
if (macDest.isBroadcast()) {
cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST;
}
if (ownershipVerificationMask == 1) {
ownershipVerificationMask = 0;
InetAddress src;
@ -386,17 +396,21 @@ static _doZtFilterResult _doZtFilter(
}
if (inbound) {
if (membership) {
if ((src)&&(membership->hasCertificateOfOwnershipFor<InetAddress>(nconf,src)))
if ((src)&&(membership->hasCertificateOfOwnershipFor<InetAddress>(nconf,src))) {
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
if (membership->hasCertificateOfOwnershipFor<MAC>(nconf,macSource))
}
if (membership->hasCertificateOfOwnershipFor<MAC>(nconf,macSource)) {
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED;
}
}
} else {
for(unsigned int i=0;i<nconf.certificateOfOwnershipCount;++i) {
if ((src)&&(nconf.certificatesOfOwnership[i].owns(src)))
if ((src)&&(nconf.certificatesOfOwnership[i].owns(src))) {
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
if (nconf.certificatesOfOwnership[i].owns(macSource))
}
if (nconf.certificatesOfOwnership[i].owns(macSource)) {
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED;
}
}
}
}
@ -528,9 +542,11 @@ static _doZtFilterResult _doZtFilter(
rrl.log(rn,thisRuleMatches,thisSetMatches);
if ((rules[rn].t & 0x40))
if ((rules[rn].t & 0x40)) {
thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
else thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
} else {
thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1));
}
}
return DOZTFILTER_NO_MATCH;
@ -544,23 +560,31 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
RR(renv),
_uPtr(uptr),
_id(nwid),
_nwidStr(OSUtils::networkIDStr(nwid)),
_lastAnnouncedMulticastGroupsUpstream(0),
_mac(renv->identity.address(),nwid),
_portInitialized(false),
_lastConfigUpdate(0),
_destroyed(false),
_netconfFailure(NETCONF_FAILURE_NONE),
_portError(0)
_portError(0),
_num_multicast_groups{Metrics::network_num_multicast_groups.Add({{"network_id", _nwidStr}})},
_incoming_packets_accepted{Metrics::network_packets.Add({{"direction","rx"},{"network_id", _nwidStr},{"accepted","yes"}})},
_incoming_packets_dropped{Metrics::network_packets.Add({{"direction","rx"},{"network_id", _nwidStr},{"accepted","no"}})},
_outgoing_packets_accepted{Metrics::network_packets.Add({{"direction","tx"},{"network_id", _nwidStr},{"accepted","yes"}})},
_outgoing_packets_dropped{Metrics::network_packets.Add({{"direction","tx"},{"network_id", _nwidStr},{"accepted","no"}})}
{
for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i)
for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i) {
_incomingConfigChunks[i].ts = 0;
}
if (nconf) {
this->setConfiguration(tPtr,*nconf,false);
_lastConfigUpdate = 0; // still want to re-request since it's likely outdated
} else {
uint64_t tmp[2];
tmp[0] = nwid; tmp[1] = 0;
tmp[0] = nwid;
tmp[1] = 0;
bool got = false;
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dict = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
@ -580,8 +604,9 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
} catch ( ... ) {}
delete dict;
if (!got)
if (!got) {
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,"\n",1);
}
}
if (!_portInitialized) {
@ -591,13 +616,15 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
_portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
_portInitialized = true;
}
Metrics::network_num_joined++;
}
Network::~Network()
{
ZT_VirtualNetworkConfig ctmp;
_externalConfig(&ctmp);
Metrics::network_num_joined--;
if (_destroyed) {
// This is done in Node::leave() so we can pass tPtr properly
//RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
@ -664,14 +691,16 @@ bool Network::filterOutgoingPacket(
break;
}
if (accept)
if (accept) {
break;
}
}
} break;
case DOZTFILTER_DROP:
if (_config.remoteTraceTarget)
if (_config.remoteTraceTarget) {
RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
}
return false;
case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
@ -685,6 +714,7 @@ bool Network::filterOutgoingPacket(
}
if (accept) {
_outgoing_packets_accepted++;
if ((!noTee)&&(cc)) {
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
@ -708,17 +738,21 @@ bool Network::filterOutgoingPacket(
outp.compress();
RR->sw->send(tPtr,outp,true);
if (_config.remoteTraceTarget)
if (_config.remoteTraceTarget) {
RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
}
return false; // DROP locally, since we redirected
} else {
if (_config.remoteTraceTarget)
if (_config.remoteTraceTarget) {
RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1);
}
return true;
}
} else {
if (_config.remoteTraceTarget)
_outgoing_packets_dropped++;
if (_config.remoteTraceTarget) {
RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0);
}
return false;
}
}
@ -788,8 +822,9 @@ int Network::filterIncomingPacket(
} break;
case DOZTFILTER_DROP:
if (_config.remoteTraceTarget)
if (_config.remoteTraceTarget) {
RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0);
}
return 0; // DROP
case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
@ -802,6 +837,7 @@ int Network::filterIncomingPacket(
}
if (accept) {
_incoming_packets_accepted++;
if (cc) {
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
@ -825,24 +861,29 @@ int Network::filterIncomingPacket(
outp.compress();
RR->sw->send(tPtr,outp,true);
if (_config.remoteTraceTarget)
if (_config.remoteTraceTarget) {
RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0);
}
return 0; // DROP locally, since we redirected
}
} else {
_incoming_packets_dropped++;
}
if (_config.remoteTraceTarget)
if (_config.remoteTraceTarget) {
RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept);
}
return accept;
}
bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const
{
Mutex::Lock _l(_lock);
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
return true;
else if (includeBridgedGroups)
} else if (includeBridgedGroups) {
return _multicastGroupsBehindMe.contains(mg);
}
return false;
}
@ -852,6 +893,7 @@ void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg)
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
_sendUpdatesToMembers(tPtr,&mg);
_num_multicast_groups++;
}
}
@ -859,20 +901,25 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg)
{
Mutex::Lock _l(_lock);
std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
if ( (i != _myMulticastGroups.end()) && (*i == mg) )
if ( (i != _myMulticastGroups.end()) && (*i == mg) ) {
_myMulticastGroups.erase(i);
_num_multicast_groups--;
}
}
uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr)
{
if (_destroyed)
if (_destroyed) {
return 0;
}
const unsigned int start = ptr;
ptr += 8; // skip network ID, which is already obviously known
const unsigned int chunkLen = chunk.at<uint16_t>(ptr); ptr += 2;
const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen;
const unsigned int chunkLen = chunk.at<uint16_t>(ptr);
ptr += 2;
const void *chunkData = chunk.field(ptr,chunkLen);
ptr += chunkLen;
NetworkConfig *nc = (NetworkConfig *)0;
uint64_t configUpdateId;
@ -884,19 +931,25 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
unsigned long totalLength,chunkIndex;
if (ptr < chunk.size()) {
const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0);
configUpdateId = chunk.at<uint64_t>(ptr); ptr += 8;
totalLength = chunk.at<uint32_t>(ptr); ptr += 4;
chunkIndex = chunk.at<uint32_t>(ptr); ptr += 4;
configUpdateId = chunk.at<uint64_t>(ptr);
ptr += 8;
totalLength = chunk.at<uint32_t>(ptr);
ptr += 4;
chunkIndex = chunk.at<uint32_t>(ptr);
ptr += 4;
if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) // >= since we need room for a null at the end
if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end
return 0;
if ((chunk[ptr] != 1)||(chunk.at<uint16_t>(ptr + 1) != ZT_C25519_SIGNATURE_LEN))
}
if ((chunk[ptr] != 1)||(chunk.at<uint16_t>(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) {
return 0;
}
const uint8_t *sig = reinterpret_cast<const uint8_t *>(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN));
// We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use
for(unsigned int i=0;i<16;++i)
for(unsigned int i=0;i<16;++i) {
reinterpret_cast<uint8_t *>(&chunkId)[i & 7] ^= sig[i];
}
// Find existing or new slot for this update and check if this is a duplicate chunk
for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i) {
@ -904,8 +957,9 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
c = &(_incomingConfigChunks[i]);
for(unsigned long j=0;j<c->haveChunks;++j) {
if (c->haveChunkIds[j] == chunkId)
if (c->haveChunkIds[j] == chunkId) {
return 0;
}
}
break;
@ -916,10 +970,12 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
// If it's not a duplicate, check chunk signature
const Identity controllerId(RR->topology->getIdentity(tPtr,controller()));
if (!controllerId) // we should always have the controller identity by now, otherwise how would we have queried it the first time?
if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time?
return 0;
if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN))
}
if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) {
return 0;
}
// New properly verified chunks can be flooded "virally" through the network
if (fastPropagate) {
@ -941,12 +997,14 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
totalLength = chunkLen;
chunkIndex = 0;
if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)
if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY) {
return 0;
}
for(int i=0;i<ZT_NETWORK_MAX_INCOMING_UPDATES;++i) {
if ((!c)||(_incomingConfigChunks[i].ts < c->ts))
if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) {
c = &(_incomingConfigChunks[i]);
}
}
} else {
// Single-chunk unsigned legacy configs are only allowed from the controller itself
@ -960,8 +1018,9 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
c->haveChunks = 0;
c->haveBytes = 0;
}
if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS)
if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS) {
return false;
}
c->haveChunkIds[c->haveChunks++] = chunkId;
memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen);
@ -996,15 +1055,18 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk)
{
if (_destroyed)
if (_destroyed) {
return 0;
}
// _lock is NOT locked when this is called
try {
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) {
return 0; // invalid config that is not for us or not for this network
if (_config == nconf)
}
if (_config == nconf) {
return 1; // OK config, but duplicate of what we already have
}
ZT_VirtualNetworkConfig ctmp;
bool oldPortInitialized;
@ -1029,7 +1091,8 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
try {
if (nconf.toDictionary(*d,false)) {
uint64_t tmp[2];
tmp[0] = _id; tmp[1] = 0;
tmp[0] = _id;
tmp[1] = 0;
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,d->data(),d->sizeBytes());
}
} catch ( ... ) {}
@ -1043,8 +1106,9 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
void Network::requestConfiguration(void *tPtr)
{
if (_destroyed)
if (_destroyed) {
return;
}
if ((_id >> 56) == 0xff) {
if ((_id & 0xffffff) == 0) {
@ -1145,8 +1209,9 @@ void Network::requestConfiguration(void *tPtr)
nconf->staticIpCount = 2;
nconf->ruleCount = 1;
if (networkHub != 0)
if (networkHub != 0) {
nconf->specialists[0] = networkHub;
}
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,myAddress);
nconf->staticIps[1].set(ipv4,4,8);
@ -1162,7 +1227,9 @@ void Network::requestConfiguration(void *tPtr)
nconf->name[4] = 'c';
nconf->name[5] = '-';
unsigned long nn = 6;
while ((nconf->name[nn] = v4ascii[nn - 6])) ++nn;
while ((nconf->name[nn] = v4ascii[nn - 6])) {
++nn;
}
nconf->name[nn++] = '.';
nconf->name[nn++] = '0';
nconf->name[nn++] = '.';
@ -1234,8 +1301,9 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
// comRevocationThreshold = m->comRevocationThreshold();
//}
if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config, peer->identity()))) ) {
if (!m)
if (!m) {
m = &(_membership(peer->address()));
}
if (m->multicastLikeGate(now)) {
_announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups());
}
@ -1260,16 +1328,18 @@ void Network::clean()
const int64_t now = RR->node->now();
Mutex::Lock _l(_lock);
if (_destroyed)
if (_destroyed) {
return;
}
{
Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe);
MulticastGroup *mg = (MulticastGroup *)0;
uint64_t *ts = (uint64_t *)0;
while (i.next(mg,ts)) {
if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2))
if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2)) {
_multicastGroupsBehindMe.erase(*mg);
}
}
}
@ -1278,9 +1348,11 @@ void Network::clean()
Membership *m = (Membership *)0;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
if (!RR->topology->getPeerNoCache(*a))
if (!RR->topology->getPeerNoCache(*a)) {
_memberships.erase(*a);
else m->clean(now,_config);
} else {
m->clean(now,_config);
}
}
}
}
@ -1315,8 +1387,9 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
{
Hashtable<MAC,Address>::Iterator i(_remoteBridgeRoutes);
while (i.next(m,a)) {
if (*a == maxAddr)
if (*a == maxAddr) {
_remoteBridgeRoutes.erase(*m);
}
}
}
}
@ -1327,22 +1400,25 @@ void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int
Mutex::Lock _l(_lock);
const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size();
_multicastGroupsBehindMe.set(mg,now);
if (tmp != _multicastGroupsBehindMe.size())
if (tmp != _multicastGroupsBehindMe.size()) {
_sendUpdatesToMembers(tPtr,&mg);
}
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const CertificateOfMembership &com)
{
if (com.networkId() != _id)
if (com.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(com.issuedTo()).addCredential(RR,tPtr,_config,com);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev)
{
if (rev.networkId() != _id)
if (rev.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
Membership &m = _membership(rev.target());
@ -1379,8 +1455,9 @@ void Network::destroy()
ZT_VirtualNetworkStatus Network::_status() const
{
// assumes _lock is locked
if (_portError)
if (_portError) {
return ZT_NETWORK_STATUS_PORT_ERROR;
}
switch(_netconfFailure) {
case NETCONF_FAILURE_ACCESS_DENIED:
return ZT_NETWORK_STATUS_ACCESS_DENIED;
@ -1400,9 +1477,11 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
// assumes _lock is locked
ec->nwid = _id;
ec->mac = _mac.toInt();
if (_config)
if (_config) {
Utils::scopy(ec->name,sizeof(ec->name),_config.name);
else ec->name[0] = (char)0;
} else {
ec->name[0] = (char)0;
}
ec->status = _status();
ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE;
ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU;
@ -1459,23 +1538,28 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
const int64_t now = RR->node->now();
std::vector<MulticastGroup> groups;
if (newMulticastGroup)
if (newMulticastGroup) {
groups.push_back(*newMulticastGroup);
else groups = _allMulticastGroups();
} else {
groups = _allMulticastGroups();
}
std::vector<Address> alwaysAnnounceTo;
if ((newMulticastGroup)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) {
if (!newMulticastGroup)
if (!newMulticastGroup) {
_lastAnnouncedMulticastGroupsUpstream = now;
}
alwaysAnnounceTo = _config.alwaysContactAddresses();
if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),controller()) == alwaysAnnounceTo.end())
if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),controller()) == alwaysAnnounceTo.end()) {
alwaysAnnounceTo.push_back(controller());
}
const std::vector<Address> upstreams(RR->topology->upstreamAddresses());
for(std::vector<Address>::const_iterator a(upstreams.begin());a!=upstreams.end();++a) {
if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a) == alwaysAnnounceTo.end())
if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a) == alwaysAnnounceTo.end()) {
alwaysAnnounceTo.push_back(*a);
}
}
std::sort(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end());
@ -1504,8 +1588,9 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
while (i.next(a,m)) {
const Identity remoteIdentity(RR->topology->getIdentity(tPtr, *a));
if (remoteIdentity) {
if ( ( m->multicastLikeGate(now) || (newMulticastGroup) ) && (m->isAllowedOnNetwork(_config, remoteIdentity)) && (!std::binary_search(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a)) )
if ( ( m->multicastLikeGate(now) || (newMulticastGroup) ) && (m->isAllowedOnNetwork(_config, remoteIdentity)) && (!std::binary_search(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a)) ) {
_announceMulticastGroupsTo(tPtr,*a,groups);
}
}
}
}
@ -1544,8 +1629,9 @@ std::vector<MulticastGroup> Network::_allMulticastGroups() const
mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1);
mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end());
_multicastGroupsBehindMe.appendKeys(mgs);
if ((_config)&&(_config.enableBroadcast()))
if ((_config)&&(_config.enableBroadcast())) {
mgs.push_back(Network::BROADCAST);
}
std::sort(mgs.begin(),mgs.end());
mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end());
return mgs;

View file

@ -37,6 +37,7 @@
#include "Membership.hpp"
#include "NetworkConfig.hpp"
#include "CertificateOfMembership.hpp"
#include "Metrics.hpp"
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3
#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
@ -332,8 +333,9 @@ public:
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap)
{
if (cap.networkId() != _id)
if (cap.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap);
}
@ -343,8 +345,9 @@ public:
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag)
{
if (tag.networkId() != _id)
if (tag.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag);
}
@ -359,8 +362,9 @@ public:
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo)
{
if (coo.networkId() != _id)
if (coo.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo);
}
@ -377,8 +381,9 @@ public:
Mutex::Lock _l(_lock);
Membership &m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT))
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) {
m.pushCredentials(RR,tPtr,now,to,_config);
}
}
/**
@ -393,8 +398,9 @@ public:
Mutex::Lock _l(_lock);
Membership &m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT))
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) {
m.pushCredentials(RR,tPtr,now,to,_config);
}
}
/**
@ -434,6 +440,7 @@ private:
const RuntimeEnvironment *const RR;
void *_uPtr;
const uint64_t _id;
std::string _nwidStr;
uint64_t _lastAnnouncedMulticastGroupsUpstream;
MAC _mac; // local MAC address
bool _portInitialized;
@ -474,6 +481,12 @@ private:
Mutex _lock;
AtomicCounter __refCount;
prometheus::simpleapi::gauge_metric_t _num_multicast_groups;
prometheus::simpleapi::counter_metric_t _incoming_packets_accepted;
prometheus::simpleapi::counter_metric_t _incoming_packets_dropped;
prometheus::simpleapi::counter_metric_t _outgoing_packets_accepted;
prometheus::simpleapi::counter_metric_t _outgoing_packets_dropped;
};
} // namespace ZeroTier

View file

@ -29,48 +29,97 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
// Try to put the more human-readable fields first
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) {
delete tmp;
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) {
delete tmp;
return false;
}
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
if (includeLegacy) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) {
return false;
}
std::string v4s;
for(unsigned int i=0;i<staticIpCount;++i) {
if (this->staticIps[i].ss_family == AF_INET) {
if (v4s.length() > 0)
if (v4s.length() > 0) {
v4s.push_back(',');
}
char buf[64];
v4s.append(this->staticIps[i].toString(buf));
}
}
if (v4s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) {
return false;
}
}
std::string v6s;
for(unsigned int i=0;i<staticIpCount;++i) {
if (this->staticIps[i].ss_family == AF_INET6) {
if (v6s.length() > 0)
if (v6s.length() > 0) {
v6s.push_back(',');
}
char buf[64];
v6s.append(this->staticIps[i].toString(buf));
}
}
if (v6s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) {
return false;
}
}
std::string ets;
@ -82,8 +131,9 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
et = rules[i].v.etherType;
} else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) {
if (((int)lastrt < 32)||(lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) {
if (ets.length() > 0)
if (ets.length() > 0) {
ets.push_back(',');
}
char tmp2[16] = {0};
ets.append(Utils::hex((uint16_t)et,tmp2));
}
@ -92,24 +142,31 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
lastrt = rt;
}
if (ets.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) {
return false;
}
}
if (this->com) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) {
return false;
}
}
std::string ab;
for(unsigned int i=0;i<this->specialistCount;++i) {
if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
if (ab.length() > 0)
if (ab.length() > 0) {
ab.push_back(',');
}
char tmp2[16] = {0};
ab.append(Address(this->specialists[i]).toString(tmp2));
}
}
if (ab.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) {
return false;
}
}
}
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
@ -119,35 +176,49 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
if (this->com) {
tmp->clear();
this->com.serialize(*tmp);
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->capabilityCount;++i)
for(unsigned int i=0;i<this->capabilityCount;++i) {
this->capabilities[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->tagCount;++i)
for(unsigned int i=0;i<this->tagCount;++i) {
this->tags[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i)
for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i) {
this->certificatesOfOwnership[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->specialistCount;++i)
for(unsigned int i=0;i<this->specialistCount;++i) {
tmp->append((uint64_t)this->specialists[i]);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) {
return false;
}
}
tmp->clear();
@ -158,50 +229,83 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
tmp->append((uint16_t)this->routes[i].metric);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->staticIpCount;++i)
for(unsigned int i=0;i<this->staticIpCount;++i) {
this->staticIps[i].serialize(*tmp);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) {
return false;
}
}
if (this->ruleCount) {
tmp->clear();
Capability::serializeRules(*tmp,rules,ruleCount);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) {
return false;
}
}
}
tmp->clear();
DNS::serializeDNS(*tmp, &dns);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) {
return false;
}
}
if (this->ssoVersion == 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
return false;
}
if (this->ssoEnabled) {
if (this->authenticationURL[0]) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) {
return false;
}
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) return false;
}
} else if(this->ssoVersion == 1) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
return false;
}
//if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) {
return false;
}
}
delete tmp;
@ -241,37 +345,45 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name));
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU);
if (this->mtu < 1280)
if (this->mtu < 1280) {
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
else if (this->mtu > ZT_MAX_MTU)
} else if (this->mtu > ZT_MAX_MTU) {
this->mtu = ZT_MAX_MTU;
}
if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) {
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
char tmp2[1024] = {0};
// Decode legacy fields if version is old
if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD))
if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) {
this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
}
this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf
this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) break;
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
break;
}
InetAddress ip(f);
if (!ip.isNetwork())
if (!ip.isNetwork()) {
this->staticIps[this->staticIpCount++] = ip;
}
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) break;
if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
break;
}
InetAddress ip(f);
if (!ip.isNetwork())
if (!ip.isNetwork()) {
this->staticIps[this->staticIpCount++] = ip;
}
}
}
@ -283,7 +395,9 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
unsigned int et = Utils::hexStrToUInt(f) & 0xffff;
if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) break;
if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) {
break;
}
if (et > 0) {
this->rules[this->ruleCount].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE;
this->rules[this->ruleCount].v.etherType = (uint16_t)et;
@ -311,8 +425,9 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0);
this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE);
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp))
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) {
this->com.deserialize(*tmp,0);
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) {
try {
@ -341,9 +456,9 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) {
unsigned int p = 0;
while (p < tmp->size()) {
if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP)
if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) {
p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp,p);
else {
} else {
CertificateOfOwnership foo;
p += foo.deserialize(*tmp,p);
}
@ -353,8 +468,9 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) {
unsigned int p = 0;
while ((p + 8) <= tmp->size()) {
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS)
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
this->specialists[this->specialistCount++] = tmp->at<uint64_t>(p);
}
p += 8;
}
}
@ -364,8 +480,10 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
while ((p < tmp->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) {
p += reinterpret_cast<InetAddress *>(&(this->routes[this->routeCount].target))->deserialize(*tmp,p);
p += reinterpret_cast<InetAddress *>(&(this->routes[this->routeCount].via))->deserialize(*tmp,p);
this->routes[this->routeCount].flags = tmp->at<uint16_t>(p); p += 2;
this->routes[this->routeCount].metric = tmp->at<uint16_t>(p); p += 2;
this->routes[this->routeCount].flags = tmp->at<uint16_t>(p);
p += 2;
this->routes[this->routeCount].metric = tmp->at<uint16_t>(p);
p += 2;
++this->routeCount;
}
}

View file

@ -356,8 +356,9 @@ public:
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
r.push_back(Address(specialists[i]));
}
}
return r;
}
@ -366,8 +367,9 @@ public:
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
ab[c++] = specialists[i];
}
}
return c;
}
@ -375,8 +377,9 @@ public:
inline bool isActiveBridge(const Address &a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)&&(a == specialists[i]))
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)&&(a == specialists[i])) {
return true;
}
}
return false;
}
@ -385,8 +388,9 @@ public:
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0)
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) {
r.push_back(Address(specialists[i]));
}
}
return r;
}
@ -395,8 +399,9 @@ public:
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
r.push_back(Address(specialists[i]));
}
}
return r;
}
@ -405,8 +410,9 @@ public:
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
mr[c++] = specialists[i];
}
}
return c;
}
@ -414,8 +420,9 @@ public:
inline bool isMulticastReplicator(const Address &a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)&&(a == specialists[i]))
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0)&&(a == specialists[i])) {
return true;
}
}
return false;
}
@ -424,8 +431,9 @@ public:
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0)
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
r.push_back(Address(specialists[i]));
}
}
return r;
}
@ -434,8 +442,9 @@ public:
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0)
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
ac[c++] = specialists[i];
}
}
return c;
}
@ -456,8 +465,9 @@ public:
inline bool permitsBridging(const Address &fromPeer) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) {
return true;
}
}
return false;
}
@ -495,8 +505,9 @@ public:
const Capability *capability(const uint32_t id) const
{
for(unsigned int i=0;i<capabilityCount;++i) {
if (capabilities[i].id() == id)
if (capabilities[i].id() == id) {
return &(capabilities[i]);
}
}
return (Capability *)0;
}
@ -504,8 +515,9 @@ public:
const Tag *tag(const uint32_t id) const
{
for(unsigned int i=0;i<tagCount;++i) {
if (tags[i].id() == id)
if (tags[i].id() == id) {
return &(tags[i]);
}
}
return (Tag *)0;
}

View file

@ -34,6 +34,12 @@
#include "SelfAwareness.hpp"
#include "Network.hpp"
#include "Trace.hpp"
#include "Metrics.hpp"
// FIXME: remove this suppression and actually fix warnings
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wsign-compare"
#endif
namespace ZeroTier {
@ -53,8 +59,9 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
_lastMemoizedTraceSettings(0),
_lowBandwidthMode(false)
{
if (callbacks->version != 0)
if (callbacks->version != 0) {
throw ZT_EXCEPTION_INVALID_ARGUMENT;
}
memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks));
// Initialize non-cryptographic PRNG from a good random source
@ -68,7 +75,8 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
memset((void *)(&_stats),0,sizeof(_stats));
uint64_t idtmp[2];
idtmp[0] = 0; idtmp[1] = 0;
idtmp[0] = 0;
idtmp[1] = 0;
char tmp[2048];
int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1);
if (n > 0) {
@ -77,7 +85,11 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
RR->identity.toString(false,RR->publicIdentityStr);
RR->identity.toString(true,RR->secretIdentityStr);
} else {
n = -1;
throw ZT_EXCEPTION_INVALID_IDENTITY;
}
if (!RR->identity.locallyValidate()) {
throw ZT_EXCEPTION_INVALID_IDENTITY;
}
}
@ -85,15 +97,18 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
RR->identity.generate();
RR->identity.toString(false,RR->publicIdentityStr);
RR->identity.toString(true,RR->secretIdentityStr);
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
idtmp[0] = RR->identity.address().toInt();
idtmp[1] = 0;
stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr,(unsigned int)strlen(RR->secretIdentityStr));
stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
} else {
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
idtmp[0] = RR->identity.address().toInt();
idtmp[1] = 0;
n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1);
if ((n > 0)&&(n < (int)sizeof(RR->publicIdentityStr))&&(n < (int)sizeof(tmp))) {
if (memcmp(tmp,RR->publicIdentityStr,n))
if (memcmp(tmp,RR->publicIdentityStr,n)) {
stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
}
}
}
@ -107,10 +122,13 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
const unsigned long bc = sizeof(Bond) + (((sizeof(Bond) & 0xf) != 0) ? (16 - (sizeof(Bond) & 0xf)) : 0);
m = reinterpret_cast<char *>(::malloc(16 + ts + sws + mcs + topologys + sas + bc));
if (!m)
if (!m) {
throw std::bad_alloc();
}
RR->rtmem = m;
while (((uintptr_t)m & 0xf) != 0) ++m;
while (((uintptr_t)m & 0xf) != 0) {
++m;
}
RR->t = new (m) Trace(RR);
m += ts;
@ -124,12 +142,24 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
m += sas;
RR->bc = new (m) Bond(RR);
} catch ( ... ) {
if (RR->sa) RR->sa->~SelfAwareness();
if (RR->topology) RR->topology->~Topology();
if (RR->mc) RR->mc->~Multicaster();
if (RR->sw) RR->sw->~Switch();
if (RR->t) RR->t->~Trace();
if (RR->bc) RR->bc->~Bond();
if (RR->sa) {
RR->sa->~SelfAwareness();
}
if (RR->topology) {
RR->topology->~Topology();
}
if (RR->mc) {
RR->mc->~Multicaster();
}
if (RR->sw) {
RR->sw->~Switch();
}
if (RR->t) {
RR->t->~Trace();
}
if (RR->bc) {
RR->bc->~Bond();
}
::free(m);
throw;
}
@ -143,12 +173,24 @@ Node::~Node()
Mutex::Lock _l(_networks_m);
_networks.clear(); // destroy all networks before shutdown
}
if (RR->sa) RR->sa->~SelfAwareness();
if (RR->topology) RR->topology->~Topology();
if (RR->mc) RR->mc->~Multicaster();
if (RR->sw) RR->sw->~Switch();
if (RR->t) RR->t->~Trace();
if (RR->bc) RR->bc->~Bond();
if (RR->sa) {
RR->sa->~SelfAwareness();
}
if (RR->topology) {
RR->topology->~Topology();
}
if (RR->mc) {
RR->mc->~Multicaster();
}
if (RR->sw) {
RR->sw->~Switch();
}
if (RR->t) {
RR->t->~Trace();
}
if (RR->bc) {
RR->bc->~Bond();
}
::free(RR->rtmem);
}
@ -183,7 +225,9 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
if (nw) {
RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength);
return ZT_RESULT_OK;
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
} else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
}
// Closure used to ping upstream and active/online peers
@ -204,9 +248,15 @@ public:
const std::vector<InetAddress> *const alwaysContactEndpoints = _alwaysContact.get(p->address());
if (alwaysContactEndpoints) {
// Contact upstream peers as infrequently as possible
ZT_PeerRole role = RR->topology->role(p->address());
// Contact upstream peers as infrequently as possible
int roleBasedTimerScale = (role == ZT_PEER_ROLE_LEAF) ? 2 : 16;
// Unless we don't any have paths to the roots, then we shouldn't wait a long time to contact them
bool hasPaths = p->paths(RR->node->now()).size() > 0;
roleBasedTimerScale = (role != ZT_PEER_ROLE_LEAF && !hasPaths) ? 0 : roleBasedTimerScale;
if ((RR->node->now() - p->lastSentFullHello()) <= (ZT_PATH_HEARTBEAT_PERIOD * roleBasedTimerScale)) {
return;
}
@ -238,8 +288,9 @@ public:
if ((!contacted)&&(_bestCurrentUpstream)) {
const SharedPtr<Path> up(_bestCurrentUpstream->getAppropriatePath(_now,true));
if (up)
if (up) {
p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now);
}
}
_alwaysContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain
@ -262,7 +313,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
Mutex::Lock bl(_backgroundTasksLock);
// Process background bond tasks
unsigned long bondCheckInterval = ZT_PING_CHECK_INVERVAL;
unsigned long bondCheckInterval = ZT_PING_CHECK_INTERVAL;
if (RR->bc->inUse()) {
bondCheckInterval = std::max(RR->bc->minReqMonitorInterval(), ZT_CORE_TIMER_TASK_GRANULARITY);
if ((now - _lastGratuitousPingCheck) >= ZT_CORE_TIMER_TASK_GRANULARITY) {
@ -271,7 +322,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
}
}
unsigned long timeUntilNextPingCheck = _lowBandwidthMode ? (ZT_PING_CHECK_INVERVAL * 5) : ZT_PING_CHECK_INVERVAL;
unsigned long timeUntilNextPingCheck = _lowBandwidthMode ? (ZT_PING_CHECK_INTERVAL * 5) : ZT_PING_CHECK_INTERVAL;
const int64_t timeSinceLastPingCheck = now - _lastPingCheck;
if (timeSinceLastPingCheck >= timeUntilNextPingCheck) {
try {
@ -298,8 +349,9 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
std::vector<InetAddress> *upstreamStableEndpoints = (std::vector<InetAddress> *)0;
while (i.next(upstreamAddress,upstreamStableEndpoints)) {
SharedPtr<Peer> p(RR->topology->getPeerNoCache(*upstreamAddress));
if (p)
if (p) {
lastReceivedFromUpstream = std::max(p->lastReceive(),lastReceivedFromUpstream);
}
}
}
@ -310,8 +362,9 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
_LocalControllerAuth *k = (_LocalControllerAuth *)0;
int64_t *v = (int64_t *)0;
while (i.next(k,v)) {
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3))
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) {
_localControllerAuthorizations.erase(*k);
}
}
_localControllerAuthorizations_m.unlock();
}
@ -340,8 +393,9 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
Hashtable< Address,std::vector<InetAddress> >::Iterator i(alwaysContact);
Address *upstreamAddress = (Address *)0;
std::vector<InetAddress> *upstreamStableEndpoints = (std::vector<InetAddress> *)0;
while (i.next(upstreamAddress,upstreamStableEndpoints))
while (i.next(upstreamAddress,upstreamStableEndpoints)) {
RR->sw->requestWhois(tptr,now,*upstreamAddress);
}
}
// Refresh network config or broadcast network updates to members as needed
@ -357,8 +411,9 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
// Update online status, post status change as event
const bool oldOnline = _online;
_online = (((now - lastReceivedFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amUpstream()));
if (oldOnline != _online)
if (oldOnline != _online) {
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
}
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
@ -395,8 +450,9 @@ ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr)
{
Mutex::Lock _l(_networks_m);
SharedPtr<Network> &nw = _networks[nwid];
if (!nw)
if (!nw) {
nw = SharedPtr<Network>(new Network(RR,tptr,nwid,uptr,(const NetworkConfig *)0));
}
return ZT_RESULT_OK;
}
@ -408,17 +464,20 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
Mutex::Lock _l(_networks_m);
SharedPtr<Network> *nw = _networks.get(nwid);
RR->sw->removeNetworkQoSControlBlock(nwid);
if (!nw)
if (!nw) {
return ZT_RESULT_OK;
if (uptr)
}
if (uptr) {
*uptr = (*nw)->userPtr();
}
(*nw)->externalConfig(&ctmp);
(*nw)->destroy();
nUserPtr = (*nw)->userPtr();
}
if (nUserPtr)
if (nUserPtr) {
RR->node->configureVirtualNetworkPort(tptr,nwid,nUserPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
}
{
Mutex::Lock _l(_networks_m);
@ -426,7 +485,8 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
}
uint64_t tmp[2];
tmp[0] = nwid; tmp[1] = 0;
tmp[0] = nwid;
tmp[1] = 0;
RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp);
return ZT_RESULT_OK;
@ -438,7 +498,9 @@ ZT_ResultCode Node::multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multica
if (nw) {
nw->multicastSubscribe(tptr,MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff)));
return ZT_RESULT_OK;
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
} else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
}
ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
@ -447,7 +509,9 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u
if (nw) {
nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff)));
return ZT_RESULT_OK;
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
} else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
}
ZT_ResultCode Node::orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed)
@ -481,8 +545,9 @@ ZT_PeerList *Node::peers() const
std::sort(peers.begin(),peers.end());
char *buf = (char *)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size()));
if (!buf)
if (!buf) {
return (ZT_PeerList *)0;
}
ZT_PeerList *pl = (ZT_PeerList *)buf;
pl->peers = (ZT_Peer *)(buf + sizeof(ZT_PeerList));
@ -501,8 +566,9 @@ ZT_PeerList *Node::peers() const
p->versionRev = -1;
}
p->latency = pi->second->latency(_now);
if (p->latency >= 0xffff)
if (p->latency >= 0xffff) {
p->latency = -1;
}
p->role = RR->topology->role(pi->second->identity().address());
std::vector< SharedPtr<Path> > paths(pi->second->paths(_now));
@ -523,6 +589,7 @@ ZT_PeerList *Node::peers() const
p->paths[p->pathCount].latencyVariance = (*path)->latencyVariance();
p->paths[p->pathCount].packetLossRatio = (*path)->packetLossRatio();
p->paths[p->pathCount].packetErrorRatio = (*path)->packetErrorRatio();
p->paths[p->pathCount].assignedFlowCount = (*path)->assignedFlowCount();
p->paths[p->pathCount].relativeQuality = (*path)->relativeQuality();
p->paths[p->pathCount].linkSpeed = (*path)->givenLinkSpeed();
p->paths[p->pathCount].bonded = (*path)->bonded();
@ -536,9 +603,9 @@ ZT_PeerList *Node::peers() const
}
if (pi->second->bond()) {
p->isBonded = pi->second->bond();
p->bondingPolicy = pi->second->bond()->policy();
p->numAliveLinks = pi->second->bond()->getNumAliveLinks();
p->numTotalLinks = pi->second->bond()->getNumTotalLinks();
p->bondingPolicy = pi->second->bondingPolicy();
p->numAliveLinks = pi->second->getNumAliveLinks();
p->numTotalLinks = pi->second->getNumTotalLinks();
}
}
@ -562,8 +629,9 @@ ZT_VirtualNetworkList *Node::networks() const
Mutex::Lock _l(_networks_m);
char *buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * _networks.size()));
if (!buf)
if (!buf) {
return (ZT_VirtualNetworkList *)0;
}
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf;
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
@ -571,16 +639,18 @@ ZT_VirtualNetworkList *Node::networks() const
Hashtable< uint64_t,SharedPtr<Network> >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr<Network> > *>(&_networks));
uint64_t *k = (uint64_t *)0;
SharedPtr<Network> *v = (SharedPtr<Network> *)0;
while (i.next(k,v))
while (i.next(k,v)) {
(*v)->externalConfig(&(nl->networks[nl->networkCount++]));
}
return nl;
}
void Node::freeQueryResult(void *qr)
{
if (qr)
if (qr) {
::free(qr);
}
}
int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr)
@ -619,8 +689,9 @@ int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *d
void Node::setNetconfMaster(void *networkControllerInstance)
{
RR->localNetworkController = reinterpret_cast<NetworkController *>(networkControllerInstance);
if (networkControllerInstance)
RR->localNetworkController->init(RR->identity,this);
if (networkControllerInstance) {
RR->localNetworkController->init(RR->identity, this);
}
}
/****************************************************************************/
@ -629,11 +700,13 @@ void Node::setNetconfMaster(void *networkControllerInstance)
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress)
{
if (!Path::isAddressValidForPath(remoteAddress))
if (!Path::isAddressValidForPath(remoteAddress)) {
return false;
}
if (RR->topology->isProhibitedEndpoint(ztaddr,remoteAddress))
if (RR->topology->isProhibitedEndpoint(ztaddr,remoteAddress)) {
return false;
}
{
Mutex::Lock _l(_networks_m);
@ -643,8 +716,9 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,cons
while (i.next(k,v)) {
if ((*v)->hasConfig()) {
for(unsigned int k=0;k<(*v)->config().staticIpCount;++k) {
if ((*v)->config().staticIps[k].containsAddress(remoteAddress))
if ((*v)->config().staticIps[k].containsAddress(remoteAddress)) {
return false;
}
}
}
}
@ -689,14 +763,18 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de
if (destination == RR->identity.address()) {
SharedPtr<Network> n(network(nwid));
if (!n) return;
if (!n) {
return;
}
n->setConfiguration((void *)0,nc,true);
} else {
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dconf = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
try {
if (nc.toDictionary(*dconf,sendLegacyFormatConfig)) {
uint64_t configUpdateId = prng();
if (!configUpdateId) ++configUpdateId;
if (!configUpdateId) {
++configUpdateId;
}
const unsigned int totalSize = dconf->sizeBytes();
unsigned int chunkIndex = 0;
@ -740,7 +818,9 @@ void Node::ncSendRevocation(const Address &destination,const Revocation &rev)
{
if (destination == RR->identity.address()) {
SharedPtr<Network> n(network(rev.networkId()));
if (!n) return;
if (!n) {
return;
}
n->addCredential((void *)0,RR->identity.address(),rev);
} else {
Packet outp(destination,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
@ -758,7 +838,9 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
{
if (destination == RR->identity.address()) {
SharedPtr<Network> n(network(nwid));
if (!n) return;
if (!n) {
return;
}
switch(errorCode) {
case NetworkController::NC_ERROR_OBJECT_NOT_FOUND:
case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR:
@ -769,11 +851,11 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
break;
case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: {
//fprintf(stderr, "\n\nGot auth required\n\n");
break;
}
}
default: break;
default:
break;
}
} else if (requestPacketId) {
Packet outp(destination,RR->identity.address(),Packet::VERB_ERROR);
@ -784,12 +866,15 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
//case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR:
default:
outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
Metrics::pkt_error_obj_not_found_out++;
break;
case NetworkController::NC_ERROR_ACCESS_DENIED:
outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
Metrics::pkt_error_network_access_denied_out++;
break;
case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED:
outp.append((unsigned char)Packet::ERROR_NETWORK_AUTHENTICATION_REQUIRED);
Metrics::pkt_error_authentication_required_out++;
break;
}
@ -1037,9 +1122,15 @@ enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const stru
void ZT_version(int *major,int *minor,int *revision)
{
if (major) *major = ZEROTIER_ONE_VERSION_MAJOR;
if (minor) *minor = ZEROTIER_ONE_VERSION_MINOR;
if (revision) *revision = ZEROTIER_ONE_VERSION_REVISION;
if (major) {
*major = ZEROTIER_ONE_VERSION_MAJOR;
}
if (minor) {
*minor = ZEROTIER_ONE_VERSION_MINOR;
}
if (revision) {
*revision = ZEROTIER_ONE_VERSION_REVISION;
}
}
} // extern "C"

View file

@ -138,8 +138,9 @@ public:
{
Mutex::Lock _l(_networks_m);
const SharedPtr<Network> *n = _networks.get(nwid);
if (n)
if (n) {
return *n;
}
return SharedPtr<Network>();
}
@ -156,8 +157,9 @@ public:
Hashtable< uint64_t,SharedPtr<Network> >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr<Network> > * >(&_networks));
uint64_t *k = (uint64_t *)0;
SharedPtr<Network> *v = (SharedPtr<Network> *)0;
while (i.next(k,v))
while (i.next(k,v)) {
nw.push_back(*v);
}
return nw;
}
@ -223,8 +225,9 @@ public:
const uint32_t pid2 = (uint32_t)(packetId >> 32);
const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) {
if (_expectingRepliesTo[bucket][i] == pid2)
if (_expectingRepliesTo[bucket][i] == pid2) {
return true;
}
}
return false;
}
@ -258,8 +261,9 @@ public:
_localControllerAuthorizations_m.lock();
const int64_t *const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid,addr));
_localControllerAuthorizations_m.unlock();
if (at)
if (at) {
return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
}
return false;
}

View file

@ -50,20 +50,27 @@ void OutboundMulticast::init(
_frameLen = (len < ZT_MAX_MTU) ? len : ZT_MAX_MTU;
_etherType = etherType;
if (gatherLimit) flags |= 0x02;
if (gatherLimit) {
flags |= 0x02;
}
_packet.setSource(RR->identity.address());
_packet.setVerb(Packet::VERB_MULTICAST_FRAME);
_packet.append((uint64_t)nwid);
_packet.append(flags);
if (gatherLimit) _packet.append((uint32_t)gatherLimit);
if (src) src.appendTo(_packet);
if (gatherLimit) {
_packet.append((uint32_t)gatherLimit);
}
if (src) {
src.appendTo(_packet);
}
dest.mac().appendTo(_packet);
_packet.append((uint32_t)dest.adi());
_packet.append((uint16_t)etherType);
_packet.append(payload,_frameLen);
if (!disableCompression)
if (!disableCompression) {
_packet.compress();
}
memcpy(_frameData,payload,_frameLen);
}

View file

@ -295,7 +295,11 @@ static inline void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
BYTE* d = (BYTE*)dstPtr;
const BYTE* s = (const BYTE*)srcPtr;
BYTE* const e = (BYTE*)dstEnd;
do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
do {
LZ4_copy8(d,s);
d+=8;
s+=8;
} while (d<e);
}
#define MINMATCH 4
@ -355,8 +359,18 @@ static inline unsigned LZ4_NbCommonBytes (reg_t val)
return (__builtin_clzll((U64)val) >> 3);
# else
unsigned r;
if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
if (!(val>>32)) {
r=4;
} else {
r=0;
val>>=32;
}
if (!(val>>16)) {
r+=2;
val>>=8;
} else {
val>>=24;
}
r += (!val);
return r;
# endif
@ -369,7 +383,13 @@ static inline unsigned LZ4_NbCommonBytes (reg_t val)
return (__builtin_clz((U32)val) >> 3);
# else
unsigned r;
if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
if (!(val>>16)) {
r=2;
val>>=8;
} else {
r=0;
val>>=24;
}
r += (!val);
return r;
# endif
@ -384,14 +404,23 @@ static inline unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE
while (likely(pIn<pInLimit-(STEPSIZE-1))) {
reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
if (!diff) {
pIn+=STEPSIZE;
pMatch+=STEPSIZE; continue;
}
pIn += LZ4_NbCommonBytes(diff);
return (unsigned)(pIn - pStart);
}
if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }
if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }
if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) {
pIn+=4; pMatch+=4;
}
if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) {
pIn+=2; pMatch+=2;
}
if ((pIn<pInLimit) && (*pMatch == *pIn)) {
pIn++;
}
return (unsigned)(pIn - pStart);
}
@ -411,10 +440,11 @@ static inline int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize
static inline U32 LZ4_hash4(U32 sequence, tableType_t const tableType)
{
if (tableType == byU16)
if (tableType == byU16) {
return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
else
} else {
return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
}
}
static inline U32 LZ4_hash5(U64 sequence, tableType_t const tableType)
@ -422,25 +452,36 @@ static inline U32 LZ4_hash5(U64 sequence, tableType_t const tableType)
static const U64 prime5bytes = 889523592379ULL;
static const U64 prime8bytes = 11400714785074694791ULL;
const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
if (LZ4_isLittleEndian())
if (LZ4_isLittleEndian()) {
return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));
else
} else {
return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));
}
}
FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType)
{
if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType);
if ((sizeof(reg_t)==8) && (tableType != byU16)) {
return LZ4_hash5(LZ4_read_ARCH(p), tableType);
}
return LZ4_hash4(LZ4_read32(p), tableType);
}
static inline void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)
{
switch (tableType)
{
case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
switch (tableType) {
case byPtr: {
const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p;
return;
}
case byU32: {
U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase);
return;
}
case byU16: {
U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase);
return;
}
}
}
@ -452,9 +493,18 @@ FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t ta
static inline const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
{
if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
{ const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
if (tableType == byPtr) {
const BYTE** hashTable = (const BYTE**) tableBase;
return hashTable[h];
}
if (tableType == byU32) {
const U32* const hashTable = (U32*) tableBase;
return hashTable[h] + srcBase;
}
{ /* default, to ensure a return */
const U16* const hashTable = (U16*) tableBase;
return hashTable[h] + srcBase;
}
}
FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
@ -493,9 +543,10 @@ FORCE_INLINE int LZ4_compress_generic(
U32 forwardH;
/* Init conditions */
if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */
switch(dict)
{
if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) {
return 0; /* Unsupported inputSize, too large (or negative) */
}
switch(dict) {
case noDict:
default:
base = (const BYTE*)source;
@ -510,12 +561,17 @@ FORCE_INLINE int LZ4_compress_generic(
lowLimit = (const BYTE*)source;
break;
}
if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) {
return 0; /* Size too large (not within 64K limit) */
}
if (inputSize<LZ4_minLength) {
goto _last_literals; /* Input too small, no compression (all literals) */
}
/* First Byte */
LZ4_putPosition(ip, cctx->hashTable, tableType, base);
ip++; forwardH = LZ4_hashPosition(ip, tableType);
ip++;
forwardH = LZ4_hashPosition(ip, tableType);
/* Main Loop */
for ( ; ; ) {
@ -524,7 +580,8 @@ FORCE_INLINE int LZ4_compress_generic(
BYTE* token;
/* Find a match */
{ const BYTE* forwardIp = ip;
{
const BYTE* forwardIp = ip;
unsigned step = 1;
unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
do {
@ -533,7 +590,9 @@ FORCE_INLINE int LZ4_compress_generic(
forwardIp += step;
step = (searchMatchNb++ >> LZ4_skipTrigger);
if (unlikely(forwardIp > mflimit)) goto _last_literals;
if (unlikely(forwardIp > mflimit)) {
goto _last_literals;
}
match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);
if (dict==usingExtDict) {
@ -543,7 +602,8 @@ FORCE_INLINE int LZ4_compress_generic(
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
} }
}
}
forwardH = LZ4_hashPosition(forwardIp, tableType);
LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);
@ -553,21 +613,29 @@ FORCE_INLINE int LZ4_compress_generic(
}
/* Catch up */
while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) {
ip--;
match--;
}
/* Encode Literals */
{ unsigned const litLength = (unsigned)(ip - anchor);
{
unsigned const litLength = (unsigned)(ip - anchor);
token = op++;
if ((outputLimited) && /* Check output buffer overflow */
(unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
(unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) {
return 0;
}
if (litLength >= RUN_MASK) {
int len = (int)litLength-RUN_MASK;
*token = (RUN_MASK<<ML_BITS);
for(; len >= 255 ; len-=255) *op++ = 255;
for(; len >= 255 ; len-=255) {
*op++ = 255;
}
*op++ = (BYTE)len;
} else {
*token = (BYTE)(litLength<<ML_BITS);
}
else *token = (BYTE)(litLength<<ML_BITS);
/* Copy Literals */
LZ4_wildCopy(op, anchor, op+litLength);
@ -576,16 +644,20 @@ FORCE_INLINE int LZ4_compress_generic(
_next_match:
/* Encode Offset */
LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
LZ4_writeLE16(op, (U16)(ip-match));
op+=2;
/* Encode MatchLength */
{ unsigned matchCode;
{
unsigned matchCode;
if ((dict==usingExtDict) && (lowLimit==dictionary)) {
const BYTE* limit;
match += refDelta;
limit = ip + (dictEnd-match);
if (limit > matchlimit) limit = matchlimit;
if (limit > matchlimit) {
limit = matchlimit;
}
matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
ip += MINMATCH + matchCode;
if (ip==limit) {
@ -599,8 +671,9 @@ _next_match:
}
if ( outputLimited && /* Check output buffer overflow */
(unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) )
(unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) {
return 0;
}
if (matchCode >= ML_MASK) {
*token += ML_MASK;
matchCode -= ML_MASK;
@ -612,14 +685,17 @@ _next_match:
}
op += matchCode / 255;
*op++ = (BYTE)(matchCode % 255);
} else
} else {
*token += (BYTE)(matchCode);
}
}
anchor = ip;
/* Test end of chunk */
if (ip > mflimit) break;
if (ip > mflimit) {
break;
}
/* Fill table */
LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);
@ -633,12 +709,16 @@ _next_match:
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
} }
}
}
LZ4_putPosition(ip, cctx->hashTable, tableType, base);
if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
&& (match+MAX_DISTANCE>=ip)
&& (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
{ token=op++; *token=0; goto _next_match; }
&& (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) {
token=op++;
*token=0;
goto _next_match;
}
/* Prepare next loop */
forwardH = LZ4_hashPosition(++ip, tableType);
@ -646,14 +726,18 @@ _next_match:
_last_literals:
/* Encode Last Literals */
{ size_t const lastRun = (size_t)(iend - anchor);
{
size_t const lastRun = (size_t)(iend - anchor);
if ( (outputLimited) && /* Check output buffer overflow */
((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) )
((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) {
return 0;
}
if (lastRun >= RUN_MASK) {
size_t accumulator = lastRun - RUN_MASK;
*op++ = RUN_MASK << ML_BITS;
for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
for(; accumulator >= 255 ; accumulator-=255) {
*op++ = 255;
}
*op++ = (BYTE) accumulator;
} else {
*op++ = (BYTE)(lastRun<<ML_BITS);
@ -673,15 +757,17 @@ static inline int LZ4_compress_fast_extState(void* state, const char* source, ch
//if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
if (maxOutputSize >= LZ4_compressBound(inputSize)) {
if (inputSize < LZ4_64Klimit)
if (inputSize < LZ4_64Klimit) {
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
else
} else {
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
}
} else {
if (inputSize < LZ4_64Klimit)
if (inputSize < LZ4_64Klimit) {
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
else
} else {
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
}
}
}
@ -741,9 +827,15 @@ FORCE_INLINE int LZ4_decompress_generic(
/* Special cases */
if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
if ((partialDecoding) && (oexit > oend-MFLIMIT)) {
oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
}
if ((endOnInput) && (unlikely(outputSize==0))) {
return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
}
if ((!endOnInput) && (unlikely(outputSize==0))) {
return (*ip==0?1:-1);
}
/* Main Loop : decode sequences */
while (1) {
@ -759,21 +851,32 @@ FORCE_INLINE int LZ4_decompress_generic(
s = *ip++;
length += s;
} while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) & (s==255) );
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error; /* overflow detection */
if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error; /* overflow detection */
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) {
goto _output_error; /* overflow detection */
}
if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) {
goto _output_error; /* overflow detection */
}
}
/* copy literals */
cpy = op+length;
if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
|| ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )
{
|| ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) {
if (partialDecoding) {
if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
if (cpy > oend) {
goto _output_error; /* Error : write attempt beyond end of output buffer */
}
if ((endOnInput) && (ip+length > iend)) {
goto _output_error; /* Error : read attempt beyond end of input buffer */
}
} else {
if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
if ((!endOnInput) && (cpy != oend)) {
goto _output_error; /* Error : block decoding must stop exactly there */
}
if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) {
goto _output_error; /* Error : input must be consumed */
}
}
memcpy(op, ip, length);
ip += length;
@ -781,12 +884,16 @@ FORCE_INLINE int LZ4_decompress_generic(
break; /* Necessarily EOF, due to parsing restrictions */
}
LZ4_wildCopy(op, ip, cpy);
ip += length; op = cpy;
ip += length;
op = cpy;
/* get offset */
offset = LZ4_readLE16(ip); ip+=2;
offset = LZ4_readLE16(ip);
ip += 2;
match = op - offset;
if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */
if ((checkOffset) && (unlikely(match < lowLimit))) {
goto _output_error; /* Error : offset outside buffers */
}
LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */
/* get matchlength */
@ -795,16 +902,22 @@ FORCE_INLINE int LZ4_decompress_generic(
unsigned s;
do {
s = *ip++;
if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
if ((endOnInput) && (ip > iend-LASTLITERALS)) {
goto _output_error;
}
length += s;
} while (s==255);
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) {
goto _output_error; /* overflow detection */
}
}
length += MINMATCH;
/* check external dictionary */
if ((dict==usingExtDict) && (match < lowPrefix)) {
if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
if (unlikely(op+length > oend-LASTLITERALS)) {
goto _output_error; /* doesn't respect parsing restriction */
}
if (length <= (size_t)(lowPrefix-match)) {
/* match can be copied as a single segment from external dictionary */
@ -819,11 +932,14 @@ FORCE_INLINE int LZ4_decompress_generic(
if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */
BYTE* const endOfMatch = op + restSize;
const BYTE* copyFrom = lowPrefix;
while (op < endOfMatch) *op++ = *copyFrom++;
while (op < endOfMatch) {
*op++ = *copyFrom++;
}
} else {
memcpy(op, lowPrefix, restSize);
op += restSize;
} }
}
}
continue;
}
@ -838,31 +954,40 @@ FORCE_INLINE int LZ4_decompress_generic(
match += dec32table[offset];
memcpy(op+4, match, 4);
match -= dec64;
} else { LZ4_copy8(op, match); match+=8; }
} else {
LZ4_copy8(op, match);
match+=8;
}
op += 8;
if (unlikely(cpy>oend-12)) {
BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1);
if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
if (cpy > oend-LASTLITERALS) {
goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
}
if (op < oCopyLimit) {
LZ4_wildCopy(op, match, oCopyLimit);
match += oCopyLimit - op;
op = oCopyLimit;
}
while (op<cpy) *op++ = *match++;
while (op<cpy) {
*op++ = *match++;
}
} else {
LZ4_copy8(op, match);
if (length>16) LZ4_wildCopy(op+8, match+8, cpy);
if (length>16) {
LZ4_wildCopy(op+8, match+8, cpy);
}
}
op=cpy; /* correction */
}
/* end of decoding */
if (endOnInput)
if (endOnInput) {
return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
else
} else {
return (int) (((const char*)ip)-source); /* Nb of input bytes read */
}
/* Overflow error detected */
_output_error:
return (int) (-(((const char*)ip)-source))-1;
@ -931,8 +1056,9 @@ void Packet::armor(const void *key,bool encryptPayload,const AES aesKeys[2])
uint8_t *const payload = data + ZT_PACKET_IDX_VERB;
const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
if (encryptPayload)
if (encryptPayload) {
s20.crypt12(payload,payload,payloadLen);
}
uint64_t mac[2];
Poly1305::compute(mac,payload,payloadLen,macKey);
@ -977,14 +1103,17 @@ bool Packet::dearmor(const void *key,const AES aesKeys[2])
uint64_t mac[2];
Poly1305::compute(mac,payload,payloadLen,keyStream);
#ifdef ZT_NO_TYPE_PUNNING
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) {
return false;
}
#else
if ((*reinterpret_cast<const uint64_t *>(data + ZT_PACKET_IDX_MAC)) != mac[0]) // also secure, constant time
if ((*reinterpret_cast<const uint64_t *>(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time
return false;
}
#endif
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) {
Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast<const uint8_t *>(keyStream + 8),payloadLen);
}
} else {
Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV);
uint64_t macKey[4];
@ -992,14 +1121,17 @@ bool Packet::dearmor(const void *key,const AES aesKeys[2])
uint64_t mac[2];
Poly1305::compute(mac,payload,payloadLen,macKey);
#ifdef ZT_NO_TYPE_PUNNING
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) {
return false;
}
#else
if ((*reinterpret_cast<const uint64_t *>(data + ZT_PACKET_IDX_MAC)) != mac[0]) // also secure, constant time
if ((*reinterpret_cast<const uint64_t *>(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time
return false;
}
#endif
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) {
s20.crypt12(payload,payload,payloadLen);
}
}
return true;
}
@ -1011,7 +1143,9 @@ void Packet::cryptField(const void *key,unsigned int start,unsigned int len)
{
uint8_t *const data = reinterpret_cast<uint8_t *>(unsafeData());
uint8_t iv[8];
for(int i=0;i<8;++i) iv[i] = data[i];
for(int i=0;i<8;++i) {
iv[i] = data[i];
}
iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called
Salsa20 s20(key,iv);
s20.crypt12(data + start,data + start,len);

View file

@ -461,8 +461,9 @@ public:
*/
inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal)
{
if ((fragStart + fragLen) > p.size())
if ((fragStart + fragLen) > p.size()) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
// NOTE: this copies both the IV/packet ID and the destination address.
@ -1217,9 +1218,11 @@ public:
*/
inline void setFragmented(bool f)
{
if (f)
if (f) {
(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
else (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
} else {
(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
}
}
/**
@ -1265,9 +1268,11 @@ public:
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
// Set DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers
if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) {
b |= ZT_PROTO_FLAG_ENCRYPTED;
else b &= (~ZT_PROTO_FLAG_ENCRYPTED);
} else {
b &= (~ZT_PROTO_FLAG_ENCRYPTED);
}
}
/**
@ -1405,8 +1410,9 @@ private:
// IV and source/destination addresses. Using the addresses divides the
// key space into two halves-- A->B and B->A (since order will change).
for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
for(unsigned int i=0;i<18;++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
out[i] = in[i] ^ d[i];
}
// Flags, but with hop count masked off. Hop count is altered by forwarding
// nodes. It's one of the only parts of a packet modifiable by people
@ -1419,8 +1425,9 @@ private:
out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian
// Rest of raw key is used unchanged
for(unsigned int i=21;i<32;++i)
for(unsigned int i=21;i<32;++i) {
out[i] = in[i];
}
}
};

View file

@ -89,6 +89,7 @@ public:
_latencyVariance(0.0),
_packetLossRatio(0.0),
_packetErrorRatio(0.0),
_assignedFlowCount(0),
_valid(true),
_eligible(false),
_bonded(false),
@ -110,6 +111,7 @@ public:
_latencyVariance(0.0),
_packetLossRatio(0.0),
_packetErrorRatio(0.0),
_assignedFlowCount(0),
_valid(true),
_eligible(false),
_bonded(false),
@ -165,8 +167,7 @@ public:
unsigned int pl = _latency;
if (pl < 0xffff) {
_latency = (pl + l) / 2;
}
else {
} else {
_latency = l;
}
}
@ -230,8 +231,9 @@ public:
// tunnels due to very spotty performance and low MTU issues over
// these IPv6 tunnel links.
const uint8_t *ipd = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr);
if ((ipd[0] == 0x20)&&(ipd[1] == 0x01)&&(ipd[2] == 0x04)&&(ipd[3] == 0x70))
if ((ipd[0] == 0x20)&&(ipd[1] == 0x01)&&(ipd[2] == 0x04)&&(ipd[3] == 0x70)) {
return false;
}
}
return true;
default:
@ -303,48 +305,53 @@ public:
/**
* @return Mean latency as reported by the bonding layer
*/
inline unsigned int latencyMean() const { return _latencyMean; }
inline float latencyMean() const { return _latencyMean; }
/**
* @return Latency variance as reported by the bonding layer
*/
inline unsigned int latencyVariance() const { return _latencyVariance; }
inline float latencyVariance() const { return _latencyVariance; }
/**
* @return Packet Loss Ratio as reported by the bonding layer
*/
inline unsigned int packetLossRatio() const { return _packetLossRatio; }
inline float packetLossRatio() const { return _packetLossRatio; }
/**
* @return Packet Error Ratio as reported by the bonding layer
*/
inline unsigned int packetErrorRatio() const { return _packetErrorRatio; }
inline float packetErrorRatio() const { return _packetErrorRatio; }
/**
* @return Number of flows assigned to this path
*/
inline unsigned int assignedFlowCount() const { return _assignedFlowCount; }
/**
* @return Whether this path is valid as reported by the bonding layer. The bonding layer
* actually checks with Phy to see if the interface is still up
*/
inline unsigned int valid() const { return _valid; }
inline bool valid() const { return _valid; }
/**
* @return Whether this path is eligible for use in a bond as reported by the bonding layer
*/
inline unsigned int eligible() const { return _eligible; }
inline bool eligible() const { return _eligible; }
/**
* @return Whether this path is bonded as reported by the bonding layer
*/
inline unsigned int bonded() const { return _bonded; }
inline bool bonded() const { return _bonded; }
/**
* @return Whether the user-specified MTU for this path (determined by MTU for parent link)
*/
inline unsigned int mtu() const { return _mtu; }
inline uint16_t mtu() const { return _mtu; }
/**
* @return Given link capacity as reported by the bonding layer
*/
inline unsigned int givenLinkSpeed() const { return _givenLinkSpeed; }
inline uint32_t givenLinkSpeed() const { return _givenLinkSpeed; }
/**
* @return Path's quality as reported by the bonding layer
@ -374,6 +381,7 @@ private:
volatile float _latencyVariance;
volatile float _packetLossRatio;
volatile float _packetErrorRatio;
volatile uint16_t _assignedFlowCount;
volatile bool _valid;
volatile bool _eligible;
volatile bool _bonded;

View file

@ -22,37 +22,47 @@
#include "InetAddress.hpp"
#include "RingBuffer.hpp"
#include "Utils.hpp"
#include "Metrics.hpp"
namespace ZeroTier {
static unsigned char s_freeRandomByteCounter = 0;
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) :
RR(renv),
_lastReceive(0),
_lastNontrivialReceive(0),
_lastTriedMemorizedPath(0),
_lastDirectPathPushSent(0),
_lastDirectPathPushReceive(0),
_lastCredentialRequestSent(0),
_lastWhoisRequestReceived(0),
_lastCredentialsReceived(0),
_lastTrustEstablishedPacketReceived(0),
_lastSentFullHello(0),
_lastEchoCheck(0),
_freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter),
_vProto(0),
_vMajor(0),
_vMinor(0),
_vRevision(0),
_id(peerIdentity),
_directPathPushCutoffCount(0),
_echoRequestCutoffCount(0),
_localMultipathSupported(false),
_lastComputedAggregateMeanLatency(0)
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity)
: RR(renv)
, _lastReceive(0)
, _lastNontrivialReceive(0)
, _lastTriedMemorizedPath(0)
, _lastDirectPathPushSent(0)
, _lastDirectPathPushReceive(0)
, _lastCredentialRequestSent(0)
, _lastWhoisRequestReceived(0)
, _lastCredentialsReceived(0)
, _lastTrustEstablishedPacketReceived(0)
, _lastSentFullHello(0)
, _lastEchoCheck(0)
, _freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter)
, _vProto(0)
, _vMajor(0)
, _vMinor(0)
, _vRevision(0)
, _id(peerIdentity)
, _directPathPushCutoffCount(0)
, _echoRequestCutoffCount(0)
, _localMultipathSupported(false)
, _lastComputedAggregateMeanLatency(0)
#ifndef ZT_NO_PEER_METRICS
, _peer_latency{Metrics::peer_latency.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}}, std::vector<uint64_t>{1,3,6,10,30,60,100,300,600,1000})}
, _alive_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","alive"}})}
, _dead_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","dead"}})}
, _incoming_packet{Metrics::peer_packets.Add({{"direction", "rx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})}
, _outgoing_packet{Metrics::peer_packets.Add({{"direction", "tx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})}
, _packet_errors{Metrics::peer_packet_errors.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})}
#endif
{
if (!myIdentity.agree(peerIdentity,_key))
if (!myIdentity.agree(peerIdentity,_key)) {
throw ZT_EXCEPTION_INVALID_ARGUMENT;
}
uint8_t ktmp[ZT_SYMMETRIC_KEY_SIZE];
KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K0,0,0,ktmp);
@ -89,7 +99,9 @@ void Peer::received(
default:
break;
}
#ifndef ZT_NO_PEER_METRICS
_incoming_packet++;
#endif
recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now);
if (trustEstablished) {
@ -145,8 +157,7 @@ void Peer::received(
}
}
}
}
else {
} else {
replacePath = i;
break;
}
@ -199,10 +210,8 @@ void Peer::received(
if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH * timerScale : ZT_DIRECT_PATH_PUSH_INTERVAL)) {
_lastDirectPathPushSent = now;
std::vector<InetAddress> pathsToPush(RR->node->directPaths());
if (! lowBandwidth) {
std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
}
std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
if (!pathsToPush.empty()) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) {
@ -233,9 +242,11 @@ void Peer::received(
++p;
}
if (count) {
Metrics::pkt_push_direct_paths_out++;
outp->setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
outp->compress();
outp->armor(_key,true,aesKeysIfSupported());
Metrics::pkt_push_direct_paths_out++;
path->send(RR,tPtr,outp->data(),outp->size(),now);
}
delete outp;
@ -267,7 +278,9 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
bestPath = i;
}
}
} else break;
} else {
break;
}
}
if (bestPath != ZT_MAX_PEER_NETWORK_PATHS) {
return _paths[bestPath].p;
@ -316,7 +329,9 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
break;
}
} else break;
} else {
break;
}
}
Mutex::Lock _l2(other->_paths_m);
@ -339,7 +354,9 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
break;
}
} else break;
} else {
break;
}
}
unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS;
@ -375,6 +392,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
outp.append(other->_paths[theirs].p->address().rawIpData(),4);
}
outp.armor(_key,true,aesKeysIfSupported());
Metrics::pkt_rendezvous_out++;
_paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now);
} else {
Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS);
@ -389,6 +407,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
outp.append(_paths[mine].p->address().rawIpData(),4);
}
outp.armor(other->_key,true,other->aesKeysIfSupported());
Metrics::pkt_rendezvous_out++;
other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now);
}
++alt;
@ -429,6 +448,8 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt);
Metrics::pkt_hello_out++;
if (atAddress) {
outp.armor(_key,false,nullptr); // false == don't encrypt full payload, but add MAC
RR->node->expectReplyTo(outp.packetId());
@ -444,6 +465,7 @@ void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAdd
if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
outp.armor(_key,true,aesKeysIfSupported());
Metrics::pkt_echo_out++;
RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size());
} else {
@ -465,20 +487,29 @@ void Peer::tryMemorizedPath(void *tPtr,int64_t now)
void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
{
Mutex::Lock _l(_bond_m);
if (_bond) {
// Once enabled the Bond object persists, no need to update state
return;
}
/**
* Check for conditions required for multipath bonding and create a bond
* if allowed.
*/
int numAlivePaths = 0;
bool atLeastOneNonExpired = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p && _paths[i].p->alive(now)) {
numAlivePaths++;
if (_paths[i].p) {
if(_paths[i].p->alive(now)) {
numAlivePaths++;
}
if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) {
atLeastOneNonExpired = true;
}
}
}
if (_bond) {
if (numAlivePaths == 0 && !atLeastOneNonExpired) {
_bond = SharedPtr<Bond>();
RR->bc->destroyBond(_id.address().toInt());
}
return;
}
_localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9));
if (_localMultipathSupported && !_bond) {
if (RR->bc) {
@ -500,56 +531,74 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
{
unsigned int sent = 0;
Mutex::Lock _l(_paths_m);
{
Mutex::Lock _l(_paths_m);
performMultipathStateCheck(tPtr, now);
performMultipathStateCheck(tPtr, now);
const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD);
if (sendFullHello) {
_lastSentFullHello = now;
}
// Right now we only keep pinging links that have the maximum priority. The
// priority is used to track cluster redirections, meaning that when a cluster
// redirects us its redirect target links override all other links and we
// let those old links expire.
long maxPriority = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
maxPriority = std::max(_paths[i].priority,maxPriority);
const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD);
if (sendFullHello) {
_lastSentFullHello = now;
}
else {
break;
}
}
bool deletionOccurred = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
// Clean expired and reduced priority paths
if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) {
if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello);
_paths[i].p->sent(now);
sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2;
// Right now we only keep pinging links that have the maximum priority. The
// priority is used to track cluster redirections, meaning that when a cluster
// redirects us its redirect target links override all other links and we
// let those old links expire.
long maxPriority = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
maxPriority = std::max(_paths[i].priority,maxPriority);
} else {
break;
}
}
bool deletionOccurred = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
// Clean expired and reduced priority paths
if ( ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].priority == maxPriority) ) {
if ((sendFullHello)||(_paths[i].p->needsHeartbeat(now))) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello);
_paths[i].p->sent(now);
sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2;
}
} else {
_paths[i] = _PeerPath();
deletionOccurred = true;
}
}
else {
_paths[i] = _PeerPath();
deletionOccurred = true;
if (!_paths[i].p || deletionOccurred) {
for(unsigned int j=i;j<ZT_MAX_PEER_NETWORK_PATHS;++j) {
if (_paths[j].p && i != j) {
_paths[i] = _paths[j];
_paths[j] = _PeerPath();
break;
}
}
deletionOccurred = false;
}
}
if (!_paths[i].p || deletionOccurred) {
for(unsigned int j=i;j<ZT_MAX_PEER_NETWORK_PATHS;++j) {
if (_paths[j].p && i != j) {
_paths[i] = _paths[j];
_paths[j] = _PeerPath();
break;
#ifndef ZT_NO_PEER_METRICS
uint16_t alive_path_count_tmp = 0, dead_path_count_tmp = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
if (_paths[i].p->alive(now)) {
alive_path_count_tmp++;
}
else {
dead_path_count_tmp++;
}
}
deletionOccurred = false;
}
_alive_path_count = alive_path_count_tmp;
_dead_path_count = dead_path_count_tmp;
#endif
}
#ifndef ZT_NO_PEER_METRICS
_peer_latency.Observe(latency(now));
#endif
return sent;
}
@ -571,7 +620,9 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
newPriority = _paths[i].priority;
break;
}
} else break;
} else {
break;
}
}
newPriority += 2;
@ -581,8 +632,9 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
if ((_paths[i].priority >= newPriority)&&(!_paths[i].p->address().ipsEqual2(remoteAddress))) {
if (i != j)
if (i != j) {
_paths[j] = _paths[i];
}
++j;
}
}
@ -612,13 +664,18 @@ void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddres
_paths[i].p->sent(now);
_paths[i].lr = 0; // path will not be used unless it speaks again
}
} else break;
} else {
break;
}
}
}
void Peer::recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{
#ifndef ZT_NO_PEER_METRICS
_outgoing_packet++;
#endif
if (_localMultipathSupported && _bond) {
_bond->recordOutgoingPacket(path, packetId, payloadLength, verb, flowId, now);
}
@ -626,6 +683,9 @@ void Peer::recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t pack
void Peer::recordIncomingInvalidPacket(const SharedPtr<Path>& path)
{
#ifndef ZT_NO_PEER_METRICS
_packet_errors++;
#endif
if (_localMultipathSupported && _bond) {
_bond->recordIncomingInvalidPacket(path);
}

View file

@ -34,6 +34,7 @@
#include "Mutex.hpp"
#include "Bond.hpp"
#include "AES.hpp"
#include "Metrics.hpp"
#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2))
@ -50,12 +51,11 @@ class Peer
friend class Bond;
private:
Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized
public:
~Peer() {
Utils::burn(_key,sizeof(_key));
RR->bc->destroyBond(_id.address().toInt());
}
/**
@ -119,9 +119,12 @@ public:
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)&&(_paths[i].p->address() == addr))
if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)&&(_paths[i].p->address() == addr)) {
return true;
} else break;
}
} else {
break;
}
}
return false;
}
@ -139,8 +142,9 @@ public:
inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
{
SharedPtr<Path> bp(getAppropriatePath(now,force));
if (bp)
if (bp) {
return bp->send(RR,tPtr,data,len,now);
}
return false;
}
@ -281,7 +285,9 @@ public:
std::vector< SharedPtr<Path> > pp;
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (!_paths[i].p) break;
if (!_paths[i].p) {
break;
}
pp.push_back(_paths[i].p);
}
return pp;
@ -314,7 +320,7 @@ public:
} else {
SharedPtr<Path> bp(getAppropriatePath(now,false));
if (bp) {
return bp->latency();
return (unsigned int)bp->latency();
}
return 0xffff;
}
@ -334,11 +340,13 @@ public:
inline unsigned int relayQuality(const int64_t now)
{
const uint64_t tsr = now - _lastReceive;
if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) {
return (~(unsigned int)0);
}
unsigned int l = latency(now);
if (!l)
if (!l) {
l = 0xffff;
}
return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1));
}
@ -380,9 +388,11 @@ public:
*/
inline bool rateGatePushDirectPaths(const int64_t now)
{
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME)
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) {
++_directPathPushCutoffCount;
else _directPathPushCutoffCount = 0;
} else {
_directPathPushCutoffCount = 0;
}
_lastDirectPathPushReceive = now;
return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT);
}
@ -423,6 +433,64 @@ public:
return false;
}
/**
* See definition in Bond
*/
inline bool rateGateQoS(int64_t now, SharedPtr<Path>& path)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
return _bond->rateGateQoS(now, path);
}
return false; // Default behavior. If there is no bond, we drop these
}
/**
* See definition in Bond
*/
void receivedQoS(const SharedPtr<Path>& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
_bond->receivedQoS(path, now, count, rx_id, rx_ts);
}
}
/**
* See definition in Bond
*/
void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>& path, int16_t remoteUtility)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
_bond->processIncomingPathNegotiationRequest(now, path, remoteUtility);
}
}
/**
* See definition in Bond
*/
inline bool rateGatePathNegotiation(int64_t now, SharedPtr<Path>& path)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
return _bond->rateGatePathNegotiation(now, path);
}
return false; // Default behavior. If there is no bond, we drop these
}
/**
* See definition in Bond
*/
bool flowHashingSupported()
{
Mutex::Lock _l(_bond_m);
if(_bond) {
return _bond->flowHashingSupported();
}
return false;
}
/**
* Serialize a peer for storage in local cache
*
@ -444,13 +512,16 @@ public:
Mutex::Lock _l(_paths_m);
unsigned int pc = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p)
if (_paths[i].p) {
++pc;
else break;
} else {
break;
}
}
b.append((uint16_t)pc);
for(unsigned int i=0;i<pc;++i)
for(unsigned int i=0;i<pc;++i) {
_paths[i].p->address().serialize(b);
}
}
}
@ -459,31 +530,39 @@ public:
{
try {
unsigned int ptr = 0;
if (b[ptr++] != 2)
if (b[ptr++] != 2) {
return SharedPtr<Peer>();
}
Identity id;
ptr += id.deserialize(b,ptr);
if (!id)
if (!id) {
return SharedPtr<Peer>();
}
SharedPtr<Peer> p(new Peer(renv,renv->identity,id));
p->_vProto = b.template at<uint16_t>(ptr); ptr += 2;
p->_vMajor = b.template at<uint16_t>(ptr); ptr += 2;
p->_vMinor = b.template at<uint16_t>(ptr); ptr += 2;
p->_vRevision = b.template at<uint16_t>(ptr); ptr += 2;
p->_vProto = b.template at<uint16_t>(ptr);
ptr += 2;
p->_vMajor = b.template at<uint16_t>(ptr);
ptr += 2;
p->_vMinor = b.template at<uint16_t>(ptr);
ptr += 2;
p->_vRevision = b.template at<uint16_t>(ptr);
ptr += 2;
// When we deserialize from the cache we don't actually restore paths. We
// just try them and then re-learn them if they happen to still be up.
// Paths are fairly ephemeral in the real world in most cases.
const unsigned int tryPathCount = b.template at<uint16_t>(ptr); ptr += 2;
const unsigned int tryPathCount = b.template at<uint16_t>(ptr);
ptr += 2;
for(unsigned int i=0;i<tryPathCount;++i) {
InetAddress inaddr;
try {
ptr += inaddr.deserialize(b,ptr);
if (inaddr)
if (inaddr) {
p->attemptToContactAt(tPtr,-1,inaddr,now,true);
}
} catch ( ... ) {
break;
}
@ -504,13 +583,35 @@ public:
* @return The bonding policy used to reach this peer
*/
inline int8_t bondingPolicy() {
Mutex::Lock _l(_paths_m);
Mutex::Lock _l(_bond_m);
if (_bond) {
return _bond->policy();
}
return ZT_BOND_POLICY_NONE;
}
/**
* @return the number of links in this bond which are considered alive
*/
inline uint8_t getNumAliveLinks() {
Mutex::Lock _l(_paths_m);
if (_bond) {
return _bond->getNumAliveLinks();
}
return 0;
}
/**
* @return the number of links in this bond
*/
inline uint8_t getNumTotalLinks() {
Mutex::Lock _l(_paths_m);
if (_bond) {
return _bond->getNumTotalLinks();
}
return 0;
}
//inline const AES *aesKeysIfSupported() const
//{ return (const AES *)0; }
@ -576,6 +677,15 @@ private:
int32_t _lastComputedAggregateMeanLatency;
SharedPtr<Bond> _bond;
#ifndef ZT_NO_PEER_METRICS
prometheus::Histogram<uint64_t> &_peer_latency;
prometheus::simpleapi::gauge_metric_t _alive_path_count;
prometheus::simpleapi::gauge_metric_t _dead_path_count;
prometheus::simpleapi::counter_metric_t _incoming_packet;
prometheus::simpleapi::counter_metric_t _outgoing_packet;
prometheus::simpleapi::counter_metric_t _packet_errors;
#endif
};
} // namespace ZeroTier

View file

@ -192,8 +192,9 @@ static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16])
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i] = 1;
for (i = i + 1; i < poly1305_block_size; i++)
for (i = i + 1; i < poly1305_block_size; i++) {
st->buffer[i] = 0;
}
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
@ -391,8 +392,9 @@ poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i++] = 1;
for (; i < poly1305_block_size; i++)
for (; i < poly1305_block_size; i++) {
st->buffer[i] = 0;
}
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
@ -477,15 +479,18 @@ static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m
/* handle leftover */
if (st->leftover) {
size_t want = (poly1305_block_size - st->leftover);
if (want > bytes)
if (want > bytes) {
want = bytes;
for (i = 0; i < want; i++)
}
for (i = 0; i < want; i++) {
st->buffer[st->leftover + i] = m[i];
}
bytes -= want;
m += want;
st->leftover += want;
if (st->leftover < poly1305_block_size)
if (st->leftover < poly1305_block_size) {
return;
}
poly1305_blocks(st, st->buffer, poly1305_block_size);
st->leftover = 0;
}
@ -500,8 +505,9 @@ static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m
/* store leftover */
if (bytes) {
for (i = 0; i < bytes; i++)
for (i = 0; i < bytes; i++) {
st->buffer[st->leftover + i] = m[i];
}
st->leftover += bytes;
}
}

View file

@ -23,8 +23,9 @@ namespace ZeroTier {
int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);

View file

@ -118,7 +118,9 @@ public:
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append(_id);
@ -140,7 +142,9 @@ public:
// This is the size of any additional fields, currently 0.
b.append((uint16_t)0);
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
}
template<unsigned int C>
@ -151,14 +155,21 @@ public:
unsigned int p = startAt;
p += 4; // 4 bytes, currently unused
_id = b.template at<uint32_t>(p); p += 4;
_networkId = b.template at<uint64_t>(p); p += 8;
_id = b.template at<uint32_t>(p);
p += 4;
_networkId = b.template at<uint64_t>(p);
p += 8;
p += 4; // 4 bytes, currently unused
_credentialId = b.template at<uint32_t>(p); p += 4;
_threshold = (int64_t)b.template at<uint64_t>(p); p += 8;
_flags = b.template at<uint64_t>(p); p += 8;
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_credentialId = b.template at<uint32_t>(p);
p += 4;
_threshold = (int64_t)b.template at<uint64_t>(p);
p += 8;
_flags = b.template at<uint64_t>(p);
p += 8;
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_type = (Credential::Type)b[p++];
if (b[p++] == 1) {
@ -166,14 +177,17 @@ public:
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
} else {
p += 2 + b.template at<uint16_t>(p);
}
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
if (p > b.size()) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
return (p - startAt);
}

View file

@ -193,11 +193,9 @@ public:
{
if (end == begin) {
return wrap ? S : 0;
}
else if (end > begin) {
} else if (end > begin) {
return end - begin;
}
else {
} else {
return S + end - begin;
}
}

View file

@ -58,12 +58,15 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
uint64_t S[8], W[80], t0, t1;
int i;
for (i = 0; i < 8; i++)
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
for (i = 0; i < 16; i++)
}
for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8*i));
for (i = 16; i < 80; i++)
}
for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
#define RND(a,b,c,d,e,f,g,h,i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
@ -82,8 +85,9 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
}
for (i = 0; i < 8; i++)
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
}
static ZT_INLINE void sha384_init(sha512_state *const md)

View file

@ -121,8 +121,9 @@ void Salsa20::crypt12(const void *in,void *out,unsigned int bytes)
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
#endif
if (!bytes)
if (!bytes) {
return;
}
#ifndef ZT_SALSA20_SSE
j0 = _state.i[0];
@ -145,8 +146,9 @@ void Salsa20::crypt12(const void *in,void *out,unsigned int bytes)
for (;;) {
if (bytes < 64) {
for (i = 0;i < bytes;++i)
for (i = 0;i < bytes;++i) {
tmp[i] = m[i];
}
m = tmp;
ctarget = c;
c = tmp;
@ -589,8 +591,9 @@ void Salsa20::crypt12(const void *in,void *out,unsigned int bytes)
if (bytes <= 64) {
if (bytes < 64) {
for (i = 0;i < bytes;++i)
for (i = 0;i < bytes;++i) {
ctarget[i] = c[i];
}
}
#ifndef ZT_SALSA20_SSE
@ -620,8 +623,9 @@ void Salsa20::crypt20(const void *in,void *out,unsigned int bytes)
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
#endif
if (!bytes)
if (!bytes) {
return;
}
#ifndef ZT_SALSA20_SSE
j0 = _state.i[0];
@ -644,8 +648,9 @@ void Salsa20::crypt20(const void *in,void *out,unsigned int bytes)
for (;;) {
if (bytes < 64) {
for (i = 0;i < bytes;++i)
for (i = 0;i < bytes;++i) {
tmp[i] = m[i];
}
m = tmp;
ctarget = c;
c = tmp;
@ -1320,8 +1325,9 @@ void Salsa20::crypt20(const void *in,void *out,unsigned int bytes)
if (bytes <= 64) {
if (bytes < 64) {
for (i = 0;i < bytes;++i)
for (i = 0;i < bytes;++i) {
ctarget[i] = c[i];
}
}
#ifndef ZT_SALSA20_SSE

View file

@ -61,8 +61,9 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
{
const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
if ((scope != reporterPhysicalAddress.ipScope())||(scope == InetAddress::IP_SCOPE_NONE)||(scope == InetAddress::IP_SCOPE_LOOPBACK)||(scope == InetAddress::IP_SCOPE_MULTICAST))
if ((scope != reporterPhysicalAddress.ipScope())||(scope == InetAddress::IP_SCOPE_NONE)||(scope == InetAddress::IP_SCOPE_LOOPBACK)||(scope == InetAddress::IP_SCOPE_MULTICAST)) {
return;
}
Mutex::Lock _l(_phy_m);
PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)];
@ -83,8 +84,9 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope))
if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) {
_phy.erase(*k);
}
}
}
@ -121,8 +123,9 @@ void SelfAwareness::clean(int64_t now)
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT)
if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) {
_phy.erase(*k);
}
}
}

View file

@ -37,8 +37,9 @@ public:
~SharedPtr()
{
if (_ptr) {
if (--_ptr->__refCount <= 0)
if (--_ptr->__refCount <= 0) {
delete _ptr;
}
}
}
@ -47,8 +48,9 @@ public:
if (_ptr != sp._ptr) {
T *p = sp._getAndInc();
if (_ptr) {
if (--_ptr->__refCount <= 0)
if (--_ptr->__refCount <= 0) {
delete _ptr;
}
}
_ptr = p;
}
@ -97,8 +99,9 @@ public:
inline void zero()
{
if (_ptr) {
if (--_ptr->__refCount <= 0)
if (--_ptr->__refCount <= 0) {
delete _ptr;
}
_ptr = (T *)0;
}
}
@ -108,8 +111,9 @@ public:
*/
inline int references()
{
if (_ptr)
if (_ptr) {
return _ptr->__refCount.load();
}
return 0;
}
@ -123,8 +127,9 @@ public:
private:
inline T *_getAndInc() const
{
if (_ptr)
if (_ptr) {
++_ptr->__refCount;
}
return _ptr;
}
T *_ptr;

View file

@ -31,6 +31,7 @@
#include "SelfAwareness.hpp"
#include "Packet.hpp"
#include "Trace.hpp"
#include "Metrics.hpp"
namespace ZeroTier {
@ -45,8 +46,9 @@ Switch::Switch(const RuntimeEnvironment *renv) :
// Returns true if packet appears valid; pos and proto will be set
static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
{
if (frameLen < 40)
if (frameLen < 40) {
return false;
}
pos = 40;
proto = frameData[6];
while (pos <= frameLen) {
@ -55,8 +57,9 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig
case 43: // routing
case 60: // destination options
case 135: // mobility options
if ((pos + 8) > frameLen)
if ((pos + 8) > frameLen) {
return false; // invalid!
}
proto = frameData[pos];
pos += ((unsigned int)frameData[pos + 1] * 8) + 8;
break;
@ -87,16 +90,19 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
* locate peers with versions <1.0.4. */
const Address beaconAddr(reinterpret_cast<const char *>(data) + 8,5);
if (beaconAddr == RR->identity.address())
if (beaconAddr == RR->identity.address()) {
return;
if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr))
}
if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr)) {
return;
}
const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,beaconAddr));
if (peer) { // we'll only respond to beacons from known peers
if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses
_lastBeaconResponse = now;
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP);
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
Metrics::pkt_nop_out++;
path->send(RR,tPtr,outp.data(),outp.size(),now);
}
}
@ -109,8 +115,9 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
const Address destination(fragment.destination());
if (destination != RR->identity.address()) {
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) )
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) ) {
return;
}
if (fragment.hops() < ZT_RELAY_MAX_HOPS) {
fragment.incrementHops();
@ -121,8 +128,9 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) {
// Don't know peer or no direct path -- so relay via someone upstream
relayTo = RR->topology->getUpstreamPeer();
if (relayTo)
if (relayTo) {
relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true);
}
}
}
} else {
@ -158,8 +166,9 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) {
// We have all fragments -- assemble and process full Packet
for(unsigned int f=1;f<totalFragments;++f)
for(unsigned int f=1;f<totalFragments;++f) {
rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength());
}
if (rq->frag0.tryDecode(RR,tPtr,flowId)) {
rq->timestamp = 0; // packet decoded, free entry
@ -178,12 +187,14 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
const Address destination(reinterpret_cast<const uint8_t *>(data) + 8,ZT_ADDRESS_LENGTH);
const Address source(reinterpret_cast<const uint8_t *>(data) + 13,ZT_ADDRESS_LENGTH);
if (source == RR->identity.address())
if (source == RR->identity.address()) {
return;
}
if (destination != RR->identity.address()) {
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) )
if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) ) {
return;
}
Packet packet(data,len);
@ -193,16 +204,18 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) {
if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) {
const SharedPtr<Peer> sourcePeer(RR->topology->getPeer(tPtr,source));
if (sourcePeer)
if (sourcePeer) {
relayTo->introduce(tPtr,now,sourcePeer);
}
}
} else {
relayTo = RR->topology->getUpstreamPeer();
if ((relayTo)&&(relayTo->address() != source)) {
if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) {
const SharedPtr<Peer> sourcePeer(RR->topology->getPeer(tPtr,source));
if (sourcePeer)
if (sourcePeer) {
relayTo->introduce(tPtr,now,sourcePeer);
}
}
}
}
@ -240,8 +253,9 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
// We have all fragments -- assemble and process full Packet
rq->frag0.init(data,len,path,now);
for(unsigned int f=1;f<rq->totalFragments;++f)
for(unsigned int f=1;f<rq->totalFragments;++f) {
rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength());
}
if (rq->frag0.tryDecode(RR,tPtr,flowId)) {
rq->timestamp = 0; // packet decoded, free entry
@ -277,8 +291,9 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{
if (!network->hasConfig())
if (!network->hasConfig()) {
return;
}
// Check if this packet is from someone other than the tap -- i.e. bridged in
bool fromBridged;
@ -401,8 +416,9 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
if ((sipNetmaskBits == 88)&&(my6[0] == 0xfd)&&(my6[9] == 0x99)&&(my6[10] == 0x93)) { // ZT-RFC4193 /88 ???
unsigned int ptr = 0;
while (ptr != 11) {
if (pkt6[ptr] != my6[ptr])
if (pkt6[ptr] != my6[ptr]) {
break;
}
++ptr;
}
if (ptr == 11) { // prefix match!
@ -414,8 +430,9 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
if ( (my6[0] == 0xfc) && (my6[1] == (uint8_t)((nwid32 >> 24) & 0xff)) && (my6[2] == (uint8_t)((nwid32 >> 16) & 0xff)) && (my6[3] == (uint8_t)((nwid32 >> 8) & 0xff)) && (my6[4] == (uint8_t)(nwid32 & 0xff))) {
unsigned int ptr = 0;
while (ptr != 5) {
if (pkt6[ptr] != my6[ptr])
if (pkt6[ptr] != my6[ptr]) {
break;
}
++ptr;
}
if (ptr == 5) { // prefix match!
@ -431,27 +448,63 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
const MAC peerMac(v6EmbeddedAddress,network->id());
uint8_t adv[72];
adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00;
adv[4] = 0x00; adv[5] = 0x20;
adv[6] = 0x3a; adv[7] = 0xff;
for(int i=0;i<16;++i) adv[8 + i] = pkt6[i];
for(int i=0;i<16;++i) adv[24 + i] = my6[i];
adv[40] = 0x88; adv[41] = 0x00;
adv[42] = 0x00; adv[43] = 0x00; // future home of checksum
adv[44] = 0x60; adv[45] = 0x00; adv[46] = 0x00; adv[47] = 0x00;
for(int i=0;i<16;++i) adv[48 + i] = pkt6[i];
adv[64] = 0x02; adv[65] = 0x01;
adv[66] = peerMac[0]; adv[67] = peerMac[1]; adv[68] = peerMac[2]; adv[69] = peerMac[3]; adv[70] = peerMac[4]; adv[71] = peerMac[5];
adv[0] = 0x60;
adv[1] = 0x00;
adv[2] = 0x00;
adv[3] = 0x00;
adv[4] = 0x00;
adv[5] = 0x20;
adv[6] = 0x3a;
adv[7] = 0xff;
for(int i=0;i<16;++i) {
adv[8 + i] = pkt6[i];
}
for(int i=0;i<16;++i) {
adv[24 + i] = my6[i];
}
adv[40] = 0x88;
adv[41] = 0x00;
adv[42] = 0x00;
adv[43] = 0x00; // future home of checksum
adv[44] = 0x60;
adv[45] = 0x00;
adv[46] = 0x00;
adv[47] = 0x00;
for(int i=0;i<16;++i) {
adv[48 + i] = pkt6[i];
}
adv[64] = 0x02;
adv[65] = 0x01;
adv[66] = peerMac[0];
adv[67] = peerMac[1];
adv[68] = peerMac[2];
adv[69] = peerMac[3];
adv[70] = peerMac[4];
adv[71] = peerMac[5];
uint16_t pseudo_[36];
uint8_t *const pseudo = reinterpret_cast<uint8_t *>(pseudo_);
for(int i=0;i<32;++i) pseudo[i] = adv[8 + i];
pseudo[32] = 0x00; pseudo[33] = 0x00; pseudo[34] = 0x00; pseudo[35] = 0x20;
pseudo[36] = 0x00; pseudo[37] = 0x00; pseudo[38] = 0x00; pseudo[39] = 0x3a;
for(int i=0;i<32;++i) pseudo[40 + i] = adv[40 + i];
for(int i=0;i<32;++i) {
pseudo[i] = adv[8 + i];
}
pseudo[32] = 0x00;
pseudo[33] = 0x00;
pseudo[34] = 0x00;
pseudo[35] = 0x20;
pseudo[36] = 0x00;
pseudo[37] = 0x00;
pseudo[38] = 0x00;
pseudo[39] = 0x3a;
for(int i=0;i<32;++i) {
pseudo[40 + i] = adv[40 + i];
}
uint32_t checksum = 0;
for(int i=0;i<36;++i) checksum += Utils::hton(pseudo_[i]);
while ((checksum >> 16)) checksum = (checksum & 0xffff) + (checksum >> 16);
for(int i=0;i<36;++i) {
checksum += Utils::hton(pseudo_[i]);
}
while ((checksum >> 16)) {
checksum = (checksum & 0xffff) + (checksum >> 16);
}
checksum = ~checksum;
adv[42] = (checksum >> 8) & 0xff;
adv[43] = checksum & 0xff;
@ -472,8 +525,9 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
* Note that some OSes, most notably Linux, do this for you by learning
* multicast addresses on bridge interfaces and subscribing each slave.
* But in that case this does no harm, as the sets are just merged. */
if (fromBridged)
if (fromBridged) {
network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now());
}
// First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates.
if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) {
@ -562,12 +616,15 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
} else {
// Otherwise pick a random set of them
while (numBridges < ZT_MAX_BRIDGE_SPAM) {
if (ab == activeBridges.end())
if (ab == activeBridges.end()) {
ab = activeBridges.begin();
}
if (((unsigned long)RR->node->prng() % (unsigned long)activeBridges.size()) == 0) {
bridges[numBridges++] = *ab;
++ab;
} else ++ab;
} else {
++ab;
}
}
}
}
@ -626,11 +683,13 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
if (nqcb->oldQueues[i]->id == qosBucket) {
selectedQueue = nqcb->oldQueues[i];
}
} if (i < nqcb->newQueues.size()) { // search new queues (this would imply not often-used queues)
}
if (i < nqcb->newQueues.size()) { // search new queues (this would imply not often-used queues)
if (nqcb->newQueues[i]->id == qosBucket) {
selectedQueue = nqcb->newQueues[i];
}
} if (i < nqcb->inactiveQueues.size()) { // search inactive queues
}
if (i < nqcb->inactiveQueues.size()) { // search inactive queues
if (nqcb->inactiveQueues[i]->id == qosBucket) {
selectedQueue = nqcb->inactiveQueues[i];
// move queue to end of NEW queue list
@ -642,6 +701,7 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
}
}
if (!selectedQueue) {
_aqm_m.unlock();
return;
}
@ -653,8 +713,7 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
// Drop a packet if necessary
ManagedQueue *selectedQueueToDropFrom = nullptr;
if (nqcb->_currEnqueuedPackets > ZT_AQM_MAX_ENQUEUED_PACKETS)
{
if (nqcb->_currEnqueuedPackets > ZT_AQM_MAX_ENQUEUED_PACKETS) {
// DEBUG_INFO("too many enqueued packets (%d), finding packet to drop", nqcb->_currEnqueuedPackets);
int maxQueueLength = 0;
for (size_t i=0; i<ZT_AQM_NUM_BUCKETS; i++) {
@ -663,12 +722,14 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
maxQueueLength = nqcb->oldQueues[i]->byteLength;
selectedQueueToDropFrom = nqcb->oldQueues[i];
}
} if (i < nqcb->newQueues.size()) {
}
if (i < nqcb->newQueues.size()) {
if (nqcb->newQueues[i]->byteLength > maxQueueLength) {
maxQueueLength = nqcb->newQueues[i]->byteLength;
selectedQueueToDropFrom = nqcb->newQueues[i];
}
} if (i < nqcb->inactiveQueues.size()) {
}
if (i < nqcb->inactiveQueues.size()) {
if (nqcb->inactiveQueues[i]->byteLength > maxQueueLength) {
maxQueueLength = nqcb->inactiveQueues[i]->byteLength;
selectedQueueToDropFrom = nqcb->inactiveQueues[i];
@ -783,8 +844,7 @@ void Switch::aqm_dequeue(void *tPtr)
// DEBUG_INFO("moving q=%p from NEW to OLD list", queueAtFrontOfList);
oldQueues->push_back(queueAtFrontOfList);
currQueues->erase(currQueues->begin());
}
else {
} else {
int len = entryToEmit->packet.payloadLength();
queueAtFrontOfList->byteLength -= len;
queueAtFrontOfList->byteCredit -= len;
@ -816,8 +876,7 @@ void Switch::aqm_dequeue(void *tPtr)
// Move to inactive list of queues
inactiveQueues->push_back(queueAtFrontOfList);
currQueues->erase(currQueues->begin());
}
else {
} else {
int len = entryToEmit->packet.payloadLength();
queueAtFrontOfList->byteLength -= len;
queueAtFrontOfList->byteCredit -= len;
@ -849,8 +908,10 @@ void Switch::removeNetworkQoSControlBlock(uint64_t nwid)
void Switch::send(void *tPtr,Packet &packet,bool encrypt,int32_t flowId)
{
const Address dest(packet.destination());
if (dest == RR->identity.address())
if (dest == RR->identity.address()) {
return;
}
_recordOutgoingPacketMetrics(packet);
if (!_trySend(tPtr,packet,encrypt,flowId)) {
{
Mutex::Lock _l(_txQueue_m);
@ -859,22 +920,26 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt,int32_t flowId)
}
_txQueue.push_back(TXQueueEntry(dest,RR->node->now(),packet,encrypt,flowId));
}
if (!RR->topology->getPeer(tPtr,dest))
if (!RR->topology->getPeer(tPtr,dest)) {
requestWhois(tPtr,RR->node->now(),dest);
}
}
}
void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
{
if (addr == RR->identity.address())
if (addr == RR->identity.address()) {
return;
}
{
Mutex::Lock _l(_lastSentWhoisRequest_m);
int64_t &last = _lastSentWhoisRequest[addr];
if ((now - last) < ZT_WHOIS_RETRY_DELAY)
if ((now - last) < ZT_WHOIS_RETRY_DELAY) {
return;
else last = now;
} else {
last = now;
}
}
const SharedPtr<Peer> upstream(RR->topology->getUpstreamPeer());
@ -898,8 +963,9 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer)
RXQueueEntry *const rq = &(_rxQueue[ptr]);
Mutex::Lock rql(rq->lock);
if ((rq->timestamp)&&(rq->complete)) {
if ((rq->frag0.tryDecode(RR,tPtr,rq->flowId))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT))
if ((rq->frag0.tryDecode(RR,tPtr,rq->flowId))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) {
rq->timestamp = 0;
}
}
}
@ -922,8 +988,9 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer)
unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
{
const uint64_t timeSinceLastCheck = now - _lastCheckedQueues;
if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY)
if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) {
return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck);
}
_lastCheckedQueues = now;
std::vector<Address> needWhois;
@ -936,14 +1003,16 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
} else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) {
_txQueue.erase(txi++);
} else {
if (!RR->topology->getPeer(tPtr,txi->dest))
if (!RR->topology->getPeer(tPtr,txi->dest)) {
needWhois.push_back(txi->dest);
}
++txi;
}
}
}
for(std::vector<Address>::const_iterator i(needWhois.begin());i!=needWhois.end();++i)
for(std::vector<Address>::const_iterator i(needWhois.begin());i!=needWhois.end();++i) {
requestWhois(tPtr,now,*i);
}
for(unsigned int ptr=0;ptr<ZT_RX_QUEUE_SIZE;++ptr) {
RXQueueEntry *const rq = &(_rxQueue[ptr]);
@ -953,8 +1022,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
rq->timestamp = 0;
} else {
const Address src(rq->frag0.source());
if (!RR->topology->getPeer(tPtr,src))
if (!RR->topology->getPeer(tPtr,src)) {
requestWhois(tPtr,now,src);
}
}
}
}
@ -965,8 +1035,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
_LastUniteKey *k = (_LastUniteKey *)0;
uint64_t *v = (uint64_t *)0;
while (i.next(k,v)) {
if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8))
if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8)) {
_lastUniteAttempt.erase(*k);
}
}
}
@ -976,8 +1047,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,int64_t now)
Address *a = (Address *)0;
int64_t *ts = (int64_t *)0;
while (i.next(a,ts)) {
if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2))
if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) {
_lastSentWhoisRequest.erase(*a);
}
}
}
@ -1014,15 +1086,15 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId)
}
}
return true;
}
else {
} else {
viaPath = peer->getAppropriatePath(now,false,flowId);
if (!viaPath) {
peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known
const SharedPtr<Peer> relay(RR->topology->getUpstreamPeer());
if ( (!relay) || (!(viaPath = relay->getAppropriatePath(now,false,flowId))) ) {
if (!(viaPath = peer->getAppropriatePath(now,true,flowId)))
if (!(viaPath = peer->getAppropriatePath(now,true,flowId))) {
return false;
}
}
}
if (viaPath) {
@ -1064,8 +1136,9 @@ void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path
unsigned int fragStart = chunkSize;
unsigned int remaining = packet.size() - chunkSize;
unsigned int fragsRemaining = (remaining / (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH));
if ((fragsRemaining * (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining)
if ((fragsRemaining * (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) {
++fragsRemaining;
}
const unsigned int totalFragments = fragsRemaining + 1;
for(unsigned int fno=1;fno<totalFragments;++fno) {
@ -1079,4 +1152,72 @@ void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path
}
}
void Switch::_recordOutgoingPacketMetrics(const Packet &p) {
switch (p.verb()) {
case Packet::VERB_NOP:
Metrics::pkt_nop_out++;
break;
case Packet::VERB_HELLO:
Metrics::pkt_hello_out++;
break;
case Packet::VERB_ERROR:
Metrics::pkt_error_out++;
break;
case Packet::VERB_OK:
Metrics::pkt_ok_out++;
break;
case Packet::VERB_WHOIS:
Metrics::pkt_whois_out++;
break;
case Packet::VERB_RENDEZVOUS:
Metrics::pkt_rendezvous_out++;
break;
case Packet::VERB_FRAME:
Metrics::pkt_frame_out++;
break;
case Packet::VERB_EXT_FRAME:
Metrics::pkt_ext_frame_out++;
break;
case Packet::VERB_ECHO:
Metrics::pkt_echo_out++;
break;
case Packet::VERB_MULTICAST_LIKE:
Metrics::pkt_multicast_like_out++;
break;
case Packet::VERB_NETWORK_CREDENTIALS:
Metrics::pkt_network_credentials_out++;
break;
case Packet::VERB_NETWORK_CONFIG_REQUEST:
Metrics::pkt_network_config_request_out++;
break;
case Packet::VERB_NETWORK_CONFIG:
Metrics::pkt_network_config_out++;
break;
case Packet::VERB_MULTICAST_GATHER:
Metrics::pkt_multicast_gather_out++;
break;
case Packet::VERB_MULTICAST_FRAME:
Metrics::pkt_multicast_frame_out++;
break;
case Packet::VERB_PUSH_DIRECT_PATHS:
Metrics::pkt_push_direct_paths_out++;
break;
case Packet::VERB_ACK:
Metrics::pkt_ack_out++;
break;
case Packet::VERB_QOS_MEASUREMENT:
Metrics::pkt_qos_out++;
break;
case Packet::VERB_USER_MESSAGE:
Metrics::pkt_user_message_out++;
break;
case Packet::VERB_REMOTE_TRACE:
Metrics::pkt_remote_trace_out++;
break;
case Packet::VERB_PATH_NEGOTIATION_REQUEST:
Metrics::pkt_path_negotiation_request_out++;
break;
}
}
} // namespace ZeroTier

View file

@ -208,6 +208,7 @@ private:
bool _shouldUnite(const int64_t now,const Address &source,const Address &destination);
bool _trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId = ZT_QOS_NO_FLOW); // packet is modified if return is true
void _sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path> viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId);
void _recordOutgoingPacketMetrics(const Packet &p);
const RuntimeEnvironment *const RR;
int64_t _lastBeaconResponse;
@ -240,8 +241,9 @@ private:
const unsigned int current = static_cast<unsigned int>(_rxQueuePtr.load());
for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) {
RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]);
if ((rq->packetId == packetId)&&(rq->timestamp))
if ((rq->packetId == packetId)&&(rq->timestamp)) {
return rq;
}
}
++_rxQueuePtr;
return &(_rxQueue[static_cast<unsigned int>(current) % ZT_RX_QUEUE_SIZE]);

View file

@ -23,8 +23,9 @@ namespace ZeroTier {
int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId)))
if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) {
return -1;
}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);

View file

@ -116,7 +116,9 @@ public:
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
b.append(_networkId);
b.append(_ts);
@ -133,7 +135,9 @@ public:
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
}
template<unsigned int C>
@ -143,26 +147,35 @@ public:
*this = Tag();
_networkId = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
_id = b.template at<uint32_t>(p); p += 4;
_networkId = b.template at<uint64_t>(p);
p += 8;
_ts = b.template at<uint64_t>(p);
p += 8;
_id = b.template at<uint32_t>(p);
p += 4;
_value = b.template at<uint32_t>(p); p += 4;
_value = b.template at<uint32_t>(p);
p += 4;
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
p += 2 + b.template at<uint16_t>(p);
}
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
if (p > b.size()) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
return (p - startAt);
}

View file

@ -32,7 +32,8 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
{
uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2];
idtmp[0] = 0; idtmp[1] = 0;
idtmp[0] = 0;
idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp));
if (n > 0) {
try {
@ -55,8 +56,9 @@ Topology::~Topology()
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p))
while (i.next(a,p)) {
_savePeer((void *)0,*p);
}
}
SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
@ -65,8 +67,9 @@ SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
{
Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &hp = _peers[peer->address()];
if (!hp)
if (!hp) {
hp = peer;
}
np = hp;
}
return np;
@ -74,26 +77,31 @@ SharedPtr<Peer> Topology::addPeer(void *tPtr,const SharedPtr<Peer> &peer)
SharedPtr<Peer> Topology::getPeer(void *tPtr,const Address &zta)
{
if (zta == RR->identity.address())
if (zta == RR->identity.address()) {
return SharedPtr<Peer>();
}
{
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
if (ap)
if (ap) {
return *ap;
}
}
try {
Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf;
uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0;
uint64_t idbuf[2];
idbuf[0] = zta.toInt();
idbuf[1] = 0;
int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE);
if (len > 0) {
buf.setSize(len);
Mutex::Lock _l(_peers_m);
SharedPtr<Peer> &ap = _peers[zta];
if (ap)
if (ap) {
return ap;
}
ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR);
if (!ap) {
_peers.erase(zta);
@ -112,8 +120,9 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta)
} else {
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
if (ap)
if (ap) {
return (*ap)->identity();
}
}
return Identity();
}
@ -138,8 +147,9 @@ SharedPtr<Peer> Topology::getUpstreamPeer()
}
}
if (!best)
if (!best) {
return SharedPtr<Peer>();
}
return *best;
}
@ -152,11 +162,13 @@ bool Topology::isUpstream(const Identity &id) const
bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const
{
Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end())
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end()) {
return true;
}
for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
if (s->second == addr)
if (s->second == addr) {
return true;
}
}
return false;
}
@ -166,8 +178,9 @@ ZT_PeerRole Topology::role(const Address &ztaddr) const
Mutex::Lock _l(_upstreams_m);
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) {
if (i->identity.address() == ztaddr)
if (i->identity.address() == ztaddr) {
return ZT_PEER_ROLE_PLANET;
}
}
return ZT_PEER_ROLE_MOON;
}
@ -183,22 +196,26 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa
if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) {
for(std::vector<World::Root>::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) {
if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty())
if (r->stableEndpoints.empty()) {
return false; // no stable endpoints specified, so allow dynamic paths
}
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
if (ipaddr.ipsEqual(*e))
if (ipaddr.ipsEqual(*e)) {
return false;
}
}
}
}
for(std::vector<World>::const_iterator m(_moons.begin());m!=_moons.end();++m) {
for(std::vector<World::Root>::const_iterator r(m->roots().begin());r!=m->roots().end();++r) {
if (r->identity.address() == ztaddr) {
if (r->stableEndpoints.empty())
if (r->stableEndpoints.empty()) {
return false; // no stable endpoints specified, so allow dynamic paths
}
for(std::vector<InetAddress>::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) {
if (ipaddr.ipsEqual(*e))
if (ipaddr.ipsEqual(*e)) {
return false;
}
}
}
}
@ -211,8 +228,9 @@ bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipa
bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
{
if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON))
if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) {
return false;
}
Mutex::Lock _l2(_peers_m);
Mutex::Lock _l1(_upstreams_m);
@ -235,9 +253,11 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
}
if (existing) {
if (existing->shouldBeReplacedBy(newWorld))
if (existing->shouldBeReplacedBy(newWorld)) {
*existing = newWorld;
else return false;
} else {
return false;
}
} else if (newWorld.type() == World::TYPE_MOON) {
if (alwaysAcceptNew) {
_moons.push_back(newWorld);
@ -253,13 +273,15 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
break;
}
}
if (existing)
if (existing) {
break;
}
}
}
}
if (!existing)
if (!existing) {
return false;
}
} else {
return false;
}
@ -268,7 +290,8 @@ bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew)
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> sbuf;
existing->serialize(sbuf,false);
uint64_t idtmp[2];
idtmp[0] = existing->id(); idtmp[1] = 0;
idtmp[0] = existing->id();
idtmp[1] = 0;
RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size());
} catch ( ... ) {}
@ -281,7 +304,8 @@ void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed)
{
char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH];
uint64_t idtmp[2];
idtmp[0] = id; idtmp[1] = 0;
idtmp[0] = id;
idtmp[1] = 0;
int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp));
if (n > 0) {
try {
@ -296,8 +320,9 @@ void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed)
if (seed) {
Mutex::Lock _l(_upstreams_m);
if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair<uint64_t,Address>(id,seed)) == _moonSeeds.end())
if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair<uint64_t,Address>(id,seed)) == _moonSeeds.end()) {
_moonSeeds.push_back(std::pair<uint64_t,Address>(id,seed));
}
}
}
@ -312,7 +337,8 @@ void Topology::removeMoon(void *tPtr,const uint64_t id)
nm.push_back(*m);
} else {
uint64_t idtmp[2];
idtmp[0] = id; idtmp[1] = 0;
idtmp[0] = id;
idtmp[1] = 0;
RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp);
}
}
@ -320,8 +346,9 @@ void Topology::removeMoon(void *tPtr,const uint64_t id)
std::vector< std::pair<uint64_t,Address> > cm;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
if (m->first != id)
if (m->first != id) {
cm.push_back(*m);
}
}
_moonSeeds.swap(cm);
@ -350,8 +377,9 @@ void Topology::doPeriodicTasks(void *tPtr,int64_t now)
Path::HashKey *k = (Path::HashKey *)0;
SharedPtr<Path> *p = (SharedPtr<Path> *)0;
while (i.next(k,p)) {
if (p->references() <= 1)
if (p->references() <= 1) {
_paths.erase(*k);
}
}
}
}
@ -382,8 +410,9 @@ void Topology::_memoizeUpstreams(void *tPtr)
} else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) {
_upstreamAddresses.push_back(i->identity.address());
SharedPtr<Peer> &hp = _peers[i->identity.address()];
if (!hp)
if (!hp) {
hp = new Peer(RR,RR->identity,i->identity);
}
}
}
}
@ -396,7 +425,9 @@ void Topology::_savePeer(void *tPtr,const SharedPtr<Peer> &peer)
try {
Buffer<ZT_PEER_MAX_SERIALIZED_STATE_SIZE> buf;
peer->serializeForCache(buf);
uint64_t tmpid[2]; tmpid[0] = peer->address().toInt(); tmpid[1] = 0;
uint64_t tmpid[2];
tmpid[0] = peer->address().toInt();
tmpid[1] = 0;
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size());
} catch ( ... ) {} // sanity check, discard invalid entries
}

View file

@ -89,8 +89,9 @@ public:
{
Mutex::Lock _l(_peers_m);
const SharedPtr<Peer> *const ap = _peers.get(zta);
if (ap)
if (ap) {
return *ap;
}
return SharedPtr<Peer>();
}
@ -105,8 +106,9 @@ public:
{
Mutex::Lock _l(_paths_m);
SharedPtr<Path> &p = _paths[Path::HashKey(l,r)];
if (!p)
if (!p) {
p.set(new Path(l,r));
}
return p;
}
@ -163,8 +165,9 @@ public:
if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end())
if (std::find(ips.begin(),ips.end(),*j) == ips.end()) {
ips.push_back(*j);
}
}
}
}
@ -173,14 +176,16 @@ public:
if (i->identity != RR->identity) {
std::vector<InetAddress> &ips = eps[i->identity.address()];
for(std::vector<InetAddress>::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) {
if (std::find(ips.begin(),ips.end(),*j) == ips.end())
if (std::find(ips.begin(),ips.end(),*j) == ips.end()) {
ips.push_back(*j);
}
}
}
}
}
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m)
for(std::vector< std::pair<uint64_t,Address> >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) {
eps[m->second];
}
}
/**
@ -209,8 +214,9 @@ public:
Mutex::Lock _l(_upstreams_m);
std::vector<uint64_t> mw;
for(std::vector< std::pair<uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) {
if (std::find(mw.begin(),mw.end(),s->first) == mw.end())
if (std::find(mw.begin(),mw.end(),s->first) == mw.end()) {
mw.push_back(s->first);
}
}
return mw;
}
@ -287,8 +293,9 @@ public:
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p)) {
const SharedPtr<Path> pp((*p)->getAppropriatePath(now,false));
if (pp)
if (pp) {
++cnt;
}
}
return cnt;
}
@ -354,8 +361,9 @@ public:
inline unsigned int getOutboundPathMtu(const InetAddress &physicalAddress)
{
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress))
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
return _physicalPathConfig[i].second.mtu;
}
}
return ZT_DEFAULT_PHYSMTU;
}
@ -369,8 +377,9 @@ public:
inline uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
{
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
if (_physicalPathConfig[i].first.containsAddress(physicalAddress))
if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
return _physicalPathConfig[i].second.trustedPathId;
}
}
return 0;
}
@ -384,8 +393,9 @@ public:
inline bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
{
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId)&&(_physicalPathConfig[i].first.containsAddress(physicalAddress)))
if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId)&&(_physicalPathConfig[i].first.containsAddress(physicalAddress))) {
return true;
}
}
return false;
}
@ -399,18 +409,20 @@ public:
_numConfiguredPhysicalPaths = 0;
} else {
std::map<InetAddress,ZT_PhysicalPathConfiguration> cpaths;
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i)
for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
cpaths[_physicalPathConfig[i].first] = _physicalPathConfig[i].second;
}
if (pathConfig) {
ZT_PhysicalPathConfiguration pc(*pathConfig);
if (pc.mtu <= 0)
if (pc.mtu <= 0) {
pc.mtu = ZT_DEFAULT_PHYSMTU;
else if (pc.mtu < ZT_MIN_PHYSMTU)
} else if (pc.mtu < ZT_MIN_PHYSMTU) {
pc.mtu = ZT_MIN_PHYSMTU;
else if (pc.mtu > ZT_MAX_PHYSMTU)
} else if (pc.mtu > ZT_MAX_PHYSMTU) {
pc.mtu = ZT_MAX_PHYSMTU;
}
cpaths[*(reinterpret_cast<const InetAddress *>(pathNetwork))] = pc;
} else {

View file

@ -59,38 +59,47 @@ void Trace::resettingPathsInScope(void *const tPtr,const Address &reporter,const
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR,myPhysicalAddress.toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE,(uint64_t)scope);
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
}
_spamToAllNetworks(tPtr,d,Trace::LEVEL_NORMAL);
}
void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &path,const uint64_t packetId,const Packet::Verb verb)
{
char tmp[128];
if (!path) return; // sanity check
if (!path) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr,RR,"trying unknown path %s to %.10llx (packet %.16llx verb %d local socket %lld network %.16llx)",path->address().toString(tmp),peer.address().toInt(),packetId,verb,path->localSocket(),networkId);
std::pair<Address,Trace::Level> byn;
if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); }
if (networkId) {
Mutex::Lock l(_byNet_m);
_byNet.get(networkId,byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb);
if (networkId)
if (networkId) {
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId);
}
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address());
if (path) {
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
}
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
@ -102,53 +111,69 @@ void Trace::bondStateMessage(void *const tPtr,char *msg)
void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath,const uint64_t packetId)
{
char tmp[128];
if (!newPath) return; // sanity check
if (!newPath) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr,RR,"learned new path %s to %.10llx (packet %.16llx local socket %lld network %.16llx)",newPath->address().toString(tmp),peer.address().toInt(),packetId,newPath->localSocket(),networkId);
std::pair<Address,Trace::Level> byn;
if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); }
if (networkId) {
Mutex::Lock l(_byNet_m);
_byNet.get(networkId,byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S);
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId);
if (networkId)
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId);
if (networkId) {
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId);
}
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address());
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket());
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr<Path> &newPath)
{
char tmp[128];
if (!newPath) return; // sanity check
if (!newPath) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr,RR,"explicit redirect from %.10llx to path %s",peer.address().toInt(),newPath->address().toString(tmp));
std::pair<Address,Trace::Level> byn;
if (networkId) { Mutex::Lock l(_byNet_m); _byNet.get(networkId,byn); }
if (networkId) {
Mutex::Lock l(_byNet_m);
_byNet.get(networkId,byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S);
if (networkId)
if (networkId) {
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId);
}
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address());
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket());
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
@ -157,7 +182,9 @@ void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network
#ifdef ZT_TRACE
char tmp[128],tmp2[128];
#endif
if (!network) return; // sanity check
if (!network) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROP frame %s -> %s etherType %.4x size %u (%s)",network->id(),sourceMac.toString(tmp),destMac.toString(tmp2),etherType,frameLen,(reason) ? reason : "unknown reason");
@ -173,20 +200,25 @@ void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network
d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType);
d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId);
d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen);
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE))
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,_globalTarget);
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE))
}
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested)
{
char tmp[128];
if (!network) return; // sanity check
if (!network) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DENIED packet from %.10llx(%s) verb %d size %u%s",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength,credentialsRequested ? " (credentials requested)" : " (credentials not requested)");
@ -205,17 +237,21 @@ void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr<Network
}
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id());
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE))
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,_globalTarget);
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE))
}
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network> &network,const SharedPtr<Path> &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason)
{
char tmp[128];
if (!network) return; // sanity check
if (!network) {
return; // sanity check
}
ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROPPED frame from %.10llx(%s) verb %d size %u",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength);
@ -235,13 +271,16 @@ void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr<Network
d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id());
d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt());
d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt());
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE))
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,_globalTarget);
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE))
}
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) {
_send(tPtr,d,byn.first);
}
}
}
@ -261,8 +300,9 @@ void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const Sh
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
}
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
_send(tPtr,d,_globalTarget);
}
@ -285,8 +325,9 @@ void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr<Path> &path,c
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
}
d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops);
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
_send(tPtr,d,_globalTarget);
}
@ -307,8 +348,9 @@ void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr<Path> &p
d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp));
d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket());
}
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
_send(tPtr,d,_globalTarget);
}
@ -361,25 +403,33 @@ void Trace::networkFilter(
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND,inbound ? "1" : "0");
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT,(int64_t)accept);
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG,(const char *)primaryRuleSetLog.data(),(int)primaryRuleSetLog.sizeBytes());
if (matchingCapabilityRuleSetLog)
if (matchingCapabilityRuleSetLog) {
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG,(const char *)matchingCapabilityRuleSetLog->data(),(int)matchingCapabilityRuleSetLog->sizeBytes());
if (matchingCapability)
}
if (matchingCapability) {
d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID,(uint64_t)matchingCapability->id());
}
d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen);
if (frameLen > 0)
if (frameLen > 0) {
d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen);
}
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES))
if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES)) {
_send(tPtr,d,_globalTarget);
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES))
}
if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES)) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
@ -389,20 +439,26 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
@ -412,20 +468,26 @@ void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
@ -435,20 +497,26 @@ void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
@ -459,20 +527,26 @@ void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason)
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value());
if (reason)
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
}
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *reason)
{
std::pair<Address,Trace::Level> byn;
if (c.networkId()) { Mutex::Lock l(_byNet_m); _byNet.get(c.networkId(),byn); }
if (c.networkId()) {
Mutex::Lock l(_byNet_m);
_byNet.get(c.networkId(),byn);
}
if ((_globalTarget)||(byn.first)) {
Dictionary<ZT_MAX_REMOTE_TRACE_SIZE> d;
@ -481,13 +555,16 @@ void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id());
d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target());
if (reason)
d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason);
if (reason) {
d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason);
}
if (_globalTarget)
if (_globalTarget) {
_send(tPtr,d,_globalTarget);
if (byn.first)
}
if (byn.first) {
_send(tPtr,d,byn.first);
}
}
}
@ -525,8 +602,9 @@ void Trace::_spamToAllNetworks(void *const tPtr,const Dictionary<ZT_MAX_REMOTE_T
uint64_t *k = (uint64_t *)0;
std::pair<Address,Trace::Level> *v = (std::pair<Address,Trace::Level> *)0;
while (i.next(k,v)) {
if ((v)&&(v->first)&&((int)v->second >= (int)level))
if ((v)&&(v->first)&&((int)v->second >= (int)level)) {
_send(tPtr,d,v->first);
}
}
}

View file

@ -188,18 +188,22 @@ const Utils::CPUIDRegisters Utils::CPUID;
static void _Utils_doBurn(volatile uint8_t *ptr,unsigned int len)
{
volatile uint8_t *const end = ptr + len;
while (ptr != end) *(ptr++) = (uint8_t)0;
while (ptr != end) {
*(ptr++) = (uint8_t)0;
}
}
static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t *,unsigned int) = _Utils_doBurn;
void Utils::burn(void *ptr,unsigned int len) { (_Utils_doBurn_ptr)((volatile uint8_t *)ptr,len); }
static unsigned long _Utils_itoa(unsigned long n,char *s)
{
if (n == 0)
if (n == 0) {
return 0;
}
unsigned long pos = _Utils_itoa(n / 10,s);
if (pos >= 22) // sanity check, should be impossible
if (pos >= 22) { // sanity check, should be impossible
pos = 22;
}
s[pos] = '0' + (char)(n % 10);
return pos + 1;
}
@ -288,7 +292,9 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
exit(1);
return;
}
} else break;
} else {
break;
}
}
randomPtr = 0;
s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf));

View file

@ -102,10 +102,17 @@ public:
*/
static inline unsigned int log2(uint32_t v)
{
uint32_t r = (v > 0xffff) << 4; v >>= r;
uint32_t shift = (v > 0xff) << 3; v >>= shift; r |= shift;
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
uint32_t r = (v > 0xffff) << 4;
v >>= r;
uint32_t shift = (v > 0xff) << 3;
v >>= shift;
r |= shift;
shift = (v > 0xf) << 2;
v >>= shift;
r |= shift;
shift = (v > 0x3) << 1;
v >>= shift;
r |= shift;
r |= (v >> 1);
return (unsigned int)r;
}
@ -121,8 +128,9 @@ public:
static inline bool secureEq(const void *a,const void *b,unsigned int len)
{
uint8_t diff = 0;
for(unsigned int i=0;i<len;++i)
for(unsigned int i=0;i<len;++i) {
diff |= ( (reinterpret_cast<const uint8_t *>(a))[i] ^ (reinterpret_cast<const uint8_t *>(b))[i] );
}
return (diff == 0);
}
@ -225,26 +233,32 @@ public:
unsigned int l = 0;
while (l < buflen) {
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) break;
if (!hc) {
break;
}
uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57)) // 0..9
if ((hc >= 48)&&(hc <= 57)) { // 0..9
c = hc - 48;
else if ((hc >= 97)&&(hc <= 102)) // a..f
} else if ((hc >= 97)&&(hc <= 102)) { // a..f
c = hc - 87;
else if ((hc >= 65)&&(hc <= 70)) // A..F
} else if ((hc >= 65)&&(hc <= 70)) { // A..F
c = hc - 55;
}
hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) break;
if (!hc) {
break;
}
c <<= 4;
if ((hc >= 48)&&(hc <= 57))
if ((hc >= 48)&&(hc <= 57)) {
c |= hc - 48;
else if ((hc >= 97)&&(hc <= 102))
} else if ((hc >= 97)&&(hc <= 102)) {
c |= hc - 87;
else if ((hc >= 65)&&(hc <= 70))
} else if ((hc >= 65)&&(hc <= 70)) {
c |= hc - 55;
}
reinterpret_cast<uint8_t *>(buf)[l++] = c;
}
@ -256,29 +270,39 @@ public:
unsigned int l = 0;
const char *hend = h + hlen;
while (l < buflen) {
if (h == hend) break;
if (h == hend) {
break;
}
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) break;
if (!hc) {
break;
}
uint8_t c = 0;
if ((hc >= 48)&&(hc <= 57))
if ((hc >= 48)&&(hc <= 57)) {
c = hc - 48;
else if ((hc >= 97)&&(hc <= 102))
} else if ((hc >= 97)&&(hc <= 102)) {
c = hc - 87;
else if ((hc >= 65)&&(hc <= 70))
} else if ((hc >= 65)&&(hc <= 70)) {
c = hc - 55;
}
if (h == hend) break;
if (h == hend) {
break;
}
hc = *(reinterpret_cast<const uint8_t *>(h++));
if (!hc) break;
if (!hc) {
break;
}
c <<= 4;
if ((hc >= 48)&&(hc <= 57))
if ((hc >= 48)&&(hc <= 57)) {
c |= hc - 48;
else if ((hc >= 97)&&(hc <= 102))
} else if ((hc >= 97)&&(hc <= 102)) {
c |= hc - 87;
else if ((hc >= 65)&&(hc <= 70))
} else if ((hc >= 65)&&(hc <= 70)) {
c |= hc - 55;
}
reinterpret_cast<uint8_t *>(buf)[l++] = c;
}
@ -375,8 +399,9 @@ public:
*/
static inline bool scopy(char *dest,unsigned int len,const char *src)
{
if (!len)
if (!len) {
return false; // sanity check
}
if (!src) {
*dest = (char)0;
return true;
@ -428,8 +453,9 @@ public:
static inline bool isZero(const void *p,unsigned int len)
{
for(unsigned int i=0;i<len;++i) {
if (((const unsigned char *)p)[i])
if (((const unsigned char *)p)[i]) {
return false;
}
}
return true;
}
@ -653,8 +679,9 @@ public:
{
#ifdef ZT_NO_UNALIGNED_ACCESS
I tmp;
for(int i=0;i<(int)sizeof(I);++i)
for(int i=0;i<(int)sizeof(I);++i) {
reinterpret_cast<uint8_t *>(&tmp)[i] = reinterpret_cast<const uint8_t *>(p)[i];
}
return tmp;
#else
return *reinterpret_cast<const I *>(p);
@ -672,8 +699,9 @@ public:
static ZT_INLINE void storeMachineEndian(void *const p, const I i) noexcept
{
#ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<sizeof(I);++k)
for(unsigned int k=0;k<sizeof(I);++k) {
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k];
}
#else
*reinterpret_cast<I *>(p) = i;
#endif

View file

@ -148,8 +148,9 @@ public:
*/
inline bool shouldBeReplacedBy(const World &update)
{
if ((_id == 0)||(_type == TYPE_NULL))
if ((_id == 0)||(_type == TYPE_NULL)) {
return true;
}
if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
update.serialize(tmp,true);
@ -166,25 +167,32 @@ public:
template<unsigned int C>
inline void serialize(Buffer<C> &b,bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
b.append((uint8_t)_type);
b.append((uint64_t)_id);
b.append((uint64_t)_ts);
b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN);
if (!forSign)
if (!forSign) {
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
}
b.append((uint8_t)_roots.size());
for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
r->identity.serialize(b);
b.append((uint8_t)r->stableEndpoints.size());
for(std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep)
for(std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) {
ep->serialize(b);
}
}
if (_type == TYPE_MOON)
if (_type == TYPE_MOON) {
b.append((uint16_t)0); // no attached dictionary (for future use)
}
if (forSign) b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL);
if (forSign) {
b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL);
}
}
template<unsigned int C>
@ -195,34 +203,47 @@ public:
_roots.clear();
switch((Type)b[p++]) {
case TYPE_NULL: _type = TYPE_NULL; break; // shouldn't ever really happen in serialized data but it's not invalid
case TYPE_PLANET: _type = TYPE_PLANET; break;
case TYPE_MOON: _type = TYPE_MOON; break;
case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid
_type = TYPE_NULL;
break;
case TYPE_PLANET:
_type = TYPE_PLANET;
break;
case TYPE_MOON:
_type = TYPE_MOON;
break;
default:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
_id = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
_id = b.template at<uint64_t>(p);
p += 8;
_ts = b.template at<uint64_t>(p);
p += 8;
memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
const unsigned int numRoots = (unsigned int)b[p++];
if (numRoots > ZT_WORLD_MAX_ROOTS)
if (numRoots > ZT_WORLD_MAX_ROOTS) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
for(unsigned int k=0;k<numRoots;++k) {
_roots.push_back(Root());
Root &r = _roots.back();
p += r.identity.deserialize(b,p);
unsigned int numStableEndpoints = b[p++];
if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)
if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
for(unsigned int kk=0;kk<numStableEndpoints;++kk) {
r.stableEndpoints.push_back(InetAddress());
p += r.stableEndpoints.back().deserialize(b,p);
}
}
if (_type == TYPE_MOON)
if (_type == TYPE_MOON) {
p += b.template at<uint16_t>(p) + 2;
}
return (p - startAt);
}