Compare commits

...

86 commits
1.14.2 ... dev

Author SHA1 Message Date
Joseph Henry
226bb1d4ef
Merge pull request #2427 from SwarmboticsAI/fix-active-backup-selection
Some checks failed
/ build_macos (push) Has been cancelled
/ build_windows (push) Has been cancelled
/ build_ubuntu (push) Has been cancelled
Fix active backup link selection
2025-07-03 10:55:38 -07:00
Joseph Henry
8753829c1b
Merge pull request #2477 from zerotier/dev-multicast-bridge-fix
Don't count bridges towards multicast limit. Send to all bridges
2025-07-03 10:14:14 -07:00
Joseph Henry
c4af2d79c5
Don't count bridges towards multicast limit. Send to all bridges 2025-07-03 09:44:45 -07:00
Adam Ierymenko
fd9a23f30f
Merge pull request #2475 from zerotier/clang-format
clang-format
2025-07-03 11:57:35 -04:00
Grant Limberg
d72b98b434
does this make windows happy? 2025-07-03 08:48:39 -07:00
Grant Limberg
813fb7a394
one more clang-format fix 2025-07-03 08:41:19 -07:00
Grant Limberg
6d532944bd
stop clang-format from breaking the build by sorting headers here 2025-07-03 08:38:21 -07:00
Adam Ierymenko
ba2a4a605c
clang-format 2025-07-03 11:26:23 -04:00
Grant Limberg
d45f280cb7
Merge pull request #2452 from zerotier/gl/cv2-ctl
CV2 db schema support
2025-07-03 08:24:36 -07:00
Grant Limberg
7cf0d7a5d8
Merge remote-tracking branch 'origin/dev' into gl/cv2-ctl 2025-07-03 08:21:39 -07:00
Grant Limberg
8636fe3c33
comment debug line
Some checks failed
/ build_macos (push) Has been cancelled
/ build_windows (push) Has been cancelled
/ build_ubuntu (push) Has been cancelled
2025-07-02 11:35:59 -07:00
Grant Limberg
08e0da7921
DBMirrorSet wasn't passing along os/arch infof 2025-07-02 11:26:28 -07:00
Grant Limberg
27021ff425
debug log line 2025-07-02 11:15:21 -07:00
Grant Limberg
ecedddb19b
grab os/arch info from nc request
Some checks are pending
/ build_macos (push) Waiting to run
/ build_windows (push) Waiting to run
/ build_ubuntu (push) Waiting to run
2025-07-02 09:17:50 -07:00
Grant Limberg
ee73ac1a74
update makefile for multi-arch controller-v2 docker build
Some checks failed
/ build_macos (push) Has been cancelled
/ build_windows (push) Has been cancelled
/ build_ubuntu (push) Has been cancelled
2025-06-20 14:49:40 -07:00
Grant Limberg
169250d484
update makefile for multi-arch controller-v2 docker build 2025-06-20 14:48:18 -07:00
Grant Limberg
4fea4fc76f
debug output 2025-06-20 14:39:12 -07:00
Grant Limberg
6fa849c956 dump member save output only on error 2025-05-21 15:52:16 -07:00
Grant Limberg
3cef1b0842
error output on exceptions in commit thread 2025-05-21 08:40:11 -07:00
Grant Limberg
08b1ceb9a1
"relayed" as ip addr for unknown IP in last_seen 2025-05-21 07:24:35 -07:00
Grant Limberg
af0a9118c1 another query update 2025-05-19 11:07:18 -07:00
Grant Limberg
568da750bb another query fix 2025-05-19 10:50:37 -07:00
Grant Limberg
d5f6f6b98e fix sql statement 2025-05-19 10:37:52 -07:00
Grant Limberg
10ac0c2e1a remove last_authorized_credential field.
Think that came from when we were trying to have the controller use the same table as CV2.  It's not used or needed by the controller itself
2025-05-19 09:52:27 -07:00
Grant Limberg
1ffadf31de Get node OS/Arch info into the CV2 db 2025-05-14 15:06:24 -07:00
Grant Limberg
224ee88b91
cleanup some debug statements 2025-05-13 13:36:39 -07:00
Grant Limberg
b42067e654
account for SSL db connection 2025-05-13 13:31:49 -07:00
Grant Limberg
c9e08c951a
add postgres tag to go install migrate 2025-05-13 13:27:25 -07:00
Grant Limberg
42f760d72f
file:// url 2025-05-13 13:21:57 -07:00
Grant Limberg
c68acebe31
Add db migrations to CV2 db 2025-05-13 13:11:27 -07:00
Grant Limberg
4b7c5159a3 "" instead of nullptr 2025-05-08 12:24:57 -07:00
Grant Limberg
4a8daf43e4 more query fixes 2025-05-08 10:33:15 -07:00
Grant Limberg
182148a26c query fix 2025-05-08 10:10:20 -07:00
Grant Limberg
af715ca0ff query & null fix 2025-05-08 09:22:28 -07:00
Grant Limberg
990ecb5eb1 another query fix 2025-05-07 12:12:32 -07:00
Grant Limberg
7c88b3f124 fix a couple of queries 2025-05-07 11:57:28 -07:00
Grant Limberg
f4053c8af3
Merge pull request #2451 from zerotier/dependabot/cargo/rustybits/crossbeam-channel-0.5.15
Bump crossbeam-channel from 0.5.13 to 0.5.15 in /rustybits
2025-05-02 12:38:07 -07:00
Grant Limberg
af3f8b00a4
fix cv2 connection 2025-05-01 15:59:07 -07:00
Grant Limberg
db06c98608 startup script 2025-05-01 14:17:49 -07:00
Grant Limberg
332a7d1488 more fun with the startup script 2025-05-01 14:12:30 -07:00
Grant Limberg
48f9f7de14 Allow setting cv2: for the db url 2025-05-01 13:58:54 -07:00
Grant Limberg
35d37559c8 v2controller docker target on mac 2025-05-01 12:57:54 -07:00
Grant Limberg
1a6c0a5f12 reflect schema changes 2025-05-01 12:26:43 -07:00
Grant Limberg
2c8f032a76 CV2 controller. Should have everything but SSO now 2025-04-10 13:32:52 -07:00
dependabot[bot]
bcc766f70d
Bump crossbeam-channel from 0.5.13 to 0.5.15 in /rustybits
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.13 to 0.5.15.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.13...crossbeam-channel-0.5.15)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-version: 0.5.15
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-10 14:38:32 +00:00
Grant Limberg
dcadc2c4d4
Merge pull request #2449 from zerotier/dependabot/cargo/rustybits/openssl-0.10.72
Bump openssl from 0.10.70 to 0.10.72 in /rustybits
2025-04-08 10:36:25 -07:00
Grant Limberg
55ed5d61e0
Merge branch 'dev' into dependabot/cargo/rustybits/openssl-0.10.72 2025-04-08 08:08:28 -07:00
Grant Limberg
86f424130d
Merge pull request #2450 from zerotier/dependabot/cargo/rustybits/tokio-1.43.1
Bump tokio from 1.42.0 to 1.43.1 in /rustybits
2025-04-08 08:08:08 -07:00
dependabot[bot]
4e9b69f0a7
Bump tokio from 1.42.0 to 1.43.1 in /rustybits
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.42.0 to 1.43.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.42.0...tokio-1.43.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-version: 1.43.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-08 02:02:25 +00:00
dependabot[bot]
0a17738f39
Bump openssl from 0.10.70 to 0.10.72 in /rustybits
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.70 to 0.10.72.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.70...openssl-v0.10.72)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-04 20:53:49 +00:00
Grant Limberg
fb7b07fc42 make sure the pg connstring is correct for cv2:// instances 2025-04-03 14:48:13 -07:00
Grant Limberg
1d2130610c use the CV2 db instance if the path prefix is cv2:// 2025-04-03 14:38:58 -07:00
Grant Limberg
0b04f772ef make things compile 2025-04-03 14:26:09 -07:00
Grant Limberg
5c73fe9304 build fix 2025-04-03 10:45:06 -07:00
Grant Limberg
2af105000f
WIP: refactoring for CV2 db integration 2025-04-03 10:27:42 -07:00
Grant Limberg
cadfa0bc4d
Merge pull request #2445 from zerotier/docker-local-conf
Allow setting local.conf content from Docker environment variable
2025-04-03 09:42:11 -07:00
Grant Limberg
f2521c8536
Allow setting local.conf content from Docker environment variable 2025-03-26 11:23:46 -07:00
Grant Limberg
d353e0c6fa
Merge pull request #2442 from zerotier/dependabot/cargo/rustybits/ring-0.17.13
Bump ring from 0.17.8 to 0.17.13 in /rustybits
2025-03-19 08:30:23 -07:00
Grant Limberg
346731ea5d
Merge branch 'dev' into dependabot/cargo/rustybits/ring-0.17.13 2025-03-11 10:47:33 -07:00
Grant Limberg
2ef38d84d1
Merge pull request #2444 from zerotier:gl/temporal-sdk-fix
temporal sdk fix
2025-03-10 16:39:39 -07:00
Grant Limberg
5630d48a66 temporal sdk fix
missing WorkflowIdConflictPolicy
2025-03-10 16:35:10 -07:00
Grant Limberg
b44a9b8b62
Merge pull request #2443 from zerotier:gl/onelogin-fix
Fix AuthInfo Provider not being set
2025-03-10 16:20:06 -07:00
Grant Limberg
f5b0fc6a8f
Fix AuthInfo Provider not being set 2025-03-10 16:04:06 -07:00
dependabot[bot]
a20bc772f2
Bump ring from 0.17.8 to 0.17.13 in /rustybits
Bumps [ring](https://github.com/briansmith/ring) from 0.17.8 to 0.17.13.
- [Changelog](https://github.com/briansmith/ring/blob/main/RELEASES.md)
- [Commits](https://github.com/briansmith/ring/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-07 17:04:31 +00:00
Travis LaDuke
010c4b0d64
Merge pull request #2441 from zerotier/laduke/update-actions
Run CI on pull requests
2025-03-05 09:18:20 -08:00
travisladuke
5998f1497a
Run CI on pull requests
If the PR is from an external repo,
the action won't run without approval.
right now we can't run the actions on external PRs.
2025-03-03 10:01:33 -08:00
Grant Limberg
a2162c01e3
Merge pull request #2430 from zerotier/dependabot/cargo/rustybits/openssl-0.10.70
Bump openssl from 0.10.68 to 0.10.70 in /rustybits
2025-02-04 15:45:25 -08:00
Grant Limberg
870c221690
Merge branch 'dev' into dependabot/cargo/rustybits/openssl-0.10.70 2025-02-04 15:38:52 -08:00
Grant Limberg
87ad848202
Merge pull request #2432 from zerotier:ci-update
Update upload-artifact action to use v4
2025-02-04 15:38:14 -08:00
Grant Limberg
b736b6835d
Update upload-artifact action to use v4
V3 is no longer supported and throws an error on use
2025-02-04 15:30:25 -08:00
dependabot[bot]
91bec01da8
Bump openssl from 0.10.68 to 0.10.70 in /rustybits
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.68 to 0.10.70.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.68...openssl-v0.10.70)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-03 18:50:34 +00:00
William Yates
a0c3f432c4 Sort active backup paths 2025-01-24 17:52:17 -07:00
Grant Limberg
b5c51796b9
Merge pull request #2417 from zerotier/rust-deps
update rust dependencies
2024-12-04 14:46:54 -08:00
Grant Limberg
724002f142
update rust dependencies 2024-12-04 13:43:34 -08:00
Grant Limberg
377a9d6f41
Merge pull request #2409 from zerotier/dependabot/cargo/rustybits/rustls-0.23.18
Bump rustls from 0.23.15 to 0.23.18 in /rustybits
2024-11-25 11:27:22 -08:00
dependabot[bot]
003b4cf876
Bump rustls from 0.23.15 to 0.23.18 in /rustybits
Bumps [rustls](https://github.com/rustls/rustls) from 0.23.15 to 0.23.18.
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.15...v/0.23.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-25 17:00:23 +00:00
Joseph Henry
b12dd19d44
Merge pull request #2405 from zerotier/jh-fix-openbsd-tap
Build fix for OpenBSD - See ticket #2397
2024-11-13 15:12:18 -08:00
Joseph Henry
82c6454950
Fix broken ifdef on OpenBSD 2024-11-13 09:01:09 -08:00
Joseph Henry
969c0ee6e3
Omit CPU pinning code on OpenBSD 2024-11-12 14:40:24 -08:00
Joseph Henry
c092b63987
Merge pull request #2365 from zerotier/laduke/2361-phy-mtu
Lower ZT_MIN_PHYSMTU
2024-11-12 09:38:11 -08:00
Joseph Henry
47efee1df4
Merge branch 'dev' into laduke/2361-phy-mtu 2024-11-12 06:20:29 -08:00
Joseph Henry
18a5452de8
Merge pull request #2395 from zerotier/core-objs
Move osutils/OSUtils.o into CORE_OBJS
2024-11-12 06:20:04 -08:00
Joseph Henry
c3794ba8d4
Merge branch 'dev' into core-objs 2024-11-12 06:05:51 -08:00
Joseph Henry
75a5b4438b
Build fix for OpenBSD - See ticket #2397 2024-11-12 05:59:49 -08:00
Grant Limberg
f959c2f4ca
Move osutils/OSUtils.o into CORE_OBJS
When building via `make core` to make libzerotiercore.a, you can't link unless OSUtils.cpp is also built & linked.
2024-10-25 09:32:13 -07:00
travisladuke
55bbd2aec6 Lower ZT_MIN_PHYSMTU
regarding #2361
2024-10-18 15:44:34 -07:00
159 changed files with 22298 additions and 18854 deletions

View file

@ -1,4 +1,7 @@
on: [ push ]
on:
pull_request:
push:
workflow_dispatch:
jobs:
build_ubuntu:

View file

@ -1,4 +1,5 @@
on:
pull_request:
push:
workflow_dispatch:
@ -44,7 +45,7 @@ jobs:
sudo ./.github/workflows/validate-linux.sh
- name: Archive test results
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{github.sha}}-test-results
path: "*test-results*"

View file

@ -31,3 +31,6 @@ drone:
@echo "rendering .drone.yaml from .drone.jsonnet"
drone jsonnet --format --stream
drone sign zerotier/ZeroTierOne --save
clang-format:
find node osdep service tcp-proxy controller -iname '*.cpp' -o -iname '*.hpp' | xargs clang-format -i

View file

@ -64,6 +64,7 @@ You can control a few settings including the identity used and the authtoken use
- `ZEROTIER_API_SECRET`: replaces the `authtoken.secret` before booting and allows you to manage the control socket's authentication key.
- `ZEROTIER_IDENTITY_PUBLIC`: the `identity.public` file for zerotier-one. Use `zerotier-idtool` to generate one of these for you.
- `ZEROTIER_IDENTITY_SECRET`: the `identity.secret` file for zerotier-one. Use `zerotier-idtool` to generate one of these for you.
- `ZEROTIER_LOCAL_CONF`: Sets the the `local.conf` file content for zerotier-one
### Tips

1952
controller/CV1.cpp Normal file

File diff suppressed because it is too large Load diff

141
controller/CV1.hpp Normal file
View file

@ -0,0 +1,141 @@
/*
* Copyright (c)2019 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: 2026-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 "DB.hpp"
#ifdef ZT_CONTROLLER_USE_LIBPQ
#ifndef ZT_CONTROLLER_CV1_HPP
#define ZT_CONTROLLER_CV1_HPP
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
#include "../node/Metrics.hpp"
#include "ConnectionPool.hpp"
#include "PostgreSQL.hpp"
#include <memory>
#include <pqxx/pqxx>
#include <redis++/redis++.h>
namespace smeeclient {
struct SmeeClient;
}
namespace ZeroTier {
struct RedisConfig;
/**
* A controller database driver that talks to PostgreSQL
*
* This is for use with ZeroTier Central. Others are free to build and use it
* but be aware that we might change it at any time.
*/
class CV1 : public DB {
public:
CV1(const Identity& myId, const char* path, int listenPort, RedisConfig* rc);
virtual ~CV1();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL);
virtual bool ready()
{
return _ready == 2;
}
protected:
struct _PairHasher {
inline std::size_t operator()(const std::pair<uint64_t, uint64_t>& p) const
{
return (std::size_t)(p.first ^ p.second);
}
};
virtual void _memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners)
{
DB::_memberChanged(old, memberConfig, notifyListeners);
}
virtual void _networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners)
{
DB::_networkChanged(old, networkConfig, notifyListeners);
}
private:
void initializeNetworks();
void initializeMembers();
void heartbeat();
void membersDbWatcher();
void _membersWatcher_Postgres();
void networksDbWatcher();
void _networksWatcher_Postgres();
void _membersWatcher_Redis();
void _networksWatcher_Redis();
void commitThread();
void onlineNotificationThread();
void onlineNotification_Postgres();
void onlineNotification_Redis();
uint64_t _doRedisUpdate(sw::redis::Transaction& tx, std::string& controllerId, std::unordered_map<std::pair<uint64_t, uint64_t>, NodeOnlineRecord, _PairHasher>& lastOnline);
void configureSmee();
void notifyNewMember(const std::string& networkID, const std::string& memberID);
enum OverrideMode { ALLOW_PGBOUNCER_OVERRIDE = 0, NO_OVERRIDE = 1 };
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
const Identity _myId;
const Address _myAddress;
std::string _myAddressStr;
std::string _connString;
BlockingQueue<std::pair<nlohmann::json, bool> > _commitQueue;
std::thread _heartbeatThread;
std::thread _membersDbWatcher;
std::thread _networksDbWatcher;
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
std::thread _onlineNotificationThread;
std::unordered_map<std::pair<uint64_t, uint64_t>, NodeOnlineRecord, _PairHasher> _lastOnline;
mutable std::mutex _lastOnline_l;
mutable std::mutex _readyLock;
std::atomic<int> _ready, _connected, _run;
mutable volatile bool _waitNoticePrinted;
int _listenPort;
uint8_t _ssoPsk[48];
RedisConfig* _rc;
std::shared_ptr<sw::redis::Redis> _redis;
std::shared_ptr<sw::redis::RedisCluster> _cluster;
bool _redisMemberStatus;
smeeclient::SmeeClient* _smee;
};
} // namespace ZeroTier
#endif // ZT_CONTROLLER_CV1_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ

1104
controller/CV2.cpp Normal file

File diff suppressed because it is too large Load diff

112
controller/CV2.hpp Normal file
View file

@ -0,0 +1,112 @@
/*
* Copyright (c)2025 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: 2026-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 "DB.hpp"
#ifdef ZT_CONTROLLER_USE_LIBPQ
#ifndef ZT_CONTROLLER_CV2_HPP
#define ZT_CONTROLLER_CV2_HPP
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
#include "../node/Metrics.hpp"
#include "ConnectionPool.hpp"
#include "PostgreSQL.hpp"
#include <memory>
#include <pqxx/pqxx>
#include <redis++/redis++.h>
namespace ZeroTier {
class CV2 : public DB {
public:
CV2(const Identity& myId, const char* path, int listenPort);
virtual ~CV2();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL);
virtual bool ready()
{
return _ready == 2;
}
protected:
struct _PairHasher {
inline std::size_t operator()(const std::pair<uint64_t, uint64_t>& p) const
{
return (std::size_t)(p.first ^ p.second);
}
};
virtual void _memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners)
{
DB::_memberChanged(old, memberConfig, notifyListeners);
}
virtual void _networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners)
{
DB::_networkChanged(old, networkConfig, notifyListeners);
}
private:
void initializeNetworks();
void initializeMembers();
void heartbeat();
void membersDbWatcher();
void networksDbWatcher();
void commitThread();
void onlineNotificationThread();
// void notifyNewMember(const std::string &networkID, const std::string &memberID);
enum OverrideMode { ALLOW_PGBOUNCER_OVERRIDE = 0, NO_OVERRIDE = 1 };
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
const Identity _myId;
const Address _myAddress;
std::string _myAddressStr;
std::string _connString;
BlockingQueue<std::pair<nlohmann::json, bool> > _commitQueue;
std::thread _heartbeatThread;
std::thread _membersDbWatcher;
std::thread _networksDbWatcher;
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
std::thread _onlineNotificationThread;
std::unordered_map<std::pair<uint64_t, uint64_t>, NodeOnlineRecord, _PairHasher> _lastOnline;
mutable std::mutex _lastOnline_l;
mutable std::mutex _readyLock;
std::atomic<int> _ready, _connected, _run;
mutable volatile bool _waitNoticePrinted;
int _listenPort;
uint8_t _ssoPsk[48];
};
} // namespace ZeroTier
#endif // ZT_CONTROLLER_CV2_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ

View file

@ -14,162 +14,162 @@
#ifndef ZT_CONNECTION_POOL_H_
#define ZT_CONNECTION_POOL_H_
#ifndef _DEBUG
#define _DEBUG(x)
#define _DEBUG(x)
#endif
#include "../node/Metrics.hpp"
#include <deque>
#include <set>
#include <exception>
#include <memory>
#include <mutex>
#include <exception>
#include <set>
#include <string>
namespace ZeroTier {
struct ConnectionUnavailable : std::exception {
char const* what() const throw() {
return "Unable to allocate connection";
};
struct ConnectionUnavailable : std::exception {
char const* what() const throw()
{
return "Unable to allocate connection";
};
};
class Connection {
public:
virtual ~Connection() {};
public:
virtual ~Connection() {};
};
class ConnectionFactory {
public:
virtual ~ConnectionFactory() {};
virtual std::shared_ptr<Connection> create()=0;
public:
virtual ~ConnectionFactory() {};
virtual std::shared_ptr<Connection> create() = 0;
};
struct ConnectionPoolStats {
size_t pool_size;
size_t borrowed_size;
size_t pool_size;
size_t borrowed_size;
};
template<class T>
class ConnectionPool {
public:
ConnectionPool(size_t max_pool_size, size_t min_pool_size, std::shared_ptr<ConnectionFactory> factory)
: m_maxPoolSize(max_pool_size)
, m_minPoolSize(min_pool_size)
, m_factory(factory)
{
Metrics::max_pool_size += max_pool_size;
Metrics::min_pool_size += min_pool_size;
while(m_pool.size() < m_minPoolSize){
m_pool.push_back(m_factory->create());
Metrics::pool_avail++;
}
};
template <class T> class ConnectionPool {
public:
ConnectionPool(size_t max_pool_size, size_t min_pool_size, std::shared_ptr<ConnectionFactory> factory) : m_maxPoolSize(max_pool_size), m_minPoolSize(min_pool_size), m_factory(factory)
{
Metrics::max_pool_size += max_pool_size;
Metrics::min_pool_size += min_pool_size;
while (m_pool.size() < m_minPoolSize) {
m_pool.push_back(m_factory->create());
Metrics::pool_avail++;
}
};
ConnectionPoolStats get_stats() {
std::unique_lock<std::mutex> lock(m_poolMutex);
ConnectionPoolStats get_stats()
{
std::unique_lock<std::mutex> lock(m_poolMutex);
ConnectionPoolStats stats;
stats.pool_size = m_pool.size();
stats.borrowed_size = m_borrowed.size();
ConnectionPoolStats stats;
stats.pool_size = m_pool.size();
stats.borrowed_size = m_borrowed.size();
return stats;
};
return stats;
};
~ConnectionPool() {
};
~ConnectionPool() {};
/**
* Borrow
*
* Borrow a connection for temporary use
*
* When done, either (a) call unborrow() to return it, or (b) (if it's bad) just let it go out of scope. This will cause it to automatically be replaced.
* @retval a shared_ptr to the connection object
*/
std::shared_ptr<T> borrow() {
std::unique_lock<std::mutex> l(m_poolMutex);
while((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
std::shared_ptr<Connection> conn = m_factory->create();
m_pool.push_back(conn);
Metrics::pool_avail++;
}
/**
* Borrow
*
* Borrow a connection for temporary use
*
* When done, either (a) call unborrow() to return it, or (b) (if it's bad) just let it go out of scope. This will cause it to automatically be replaced.
* @retval a shared_ptr to the connection object
*/
std::shared_ptr<T> borrow()
{
std::unique_lock<std::mutex> l(m_poolMutex);
if(m_pool.size()==0){
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
try {
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
} catch (std::exception &e) {
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
} else {
for(auto it = m_borrowed.begin(); it != m_borrowed.end(); ++it){
if((*it).unique()) {
// This connection has been abandoned! Destroy it and create a new connection
try {
// If we are able to create a new connection, return it
_DEBUG("Creating new connection to replace discarded connection");
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.erase(it);
m_borrowed.insert(conn);
return std::static_pointer_cast<T>(conn);
} catch(std::exception& e) {
// Error creating a replacement connection
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
}
// Nothing available
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
while ((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
std::shared_ptr<Connection> conn = m_factory->create();
m_pool.push_back(conn);
Metrics::pool_avail++;
}
// Take one off the front
std::shared_ptr<Connection> conn = m_pool.front();
m_pool.pop_front();
Metrics::pool_avail--;
// Add it to the borrowed list
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
};
if (m_pool.size() == 0) {
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
try {
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
}
catch (std::exception& e) {
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
else {
for (auto it = m_borrowed.begin(); it != m_borrowed.end(); ++it) {
if ((*it).unique()) {
// This connection has been abandoned! Destroy it and create a new connection
try {
// If we are able to create a new connection, return it
_DEBUG("Creating new connection to replace discarded connection");
std::shared_ptr<Connection> conn = m_factory->create();
m_borrowed.erase(it);
m_borrowed.insert(conn);
return std::static_pointer_cast<T>(conn);
}
catch (std::exception& e) {
// Error creating a replacement connection
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
}
// Nothing available
Metrics::pool_errors++;
throw ConnectionUnavailable();
}
}
/**
* Unborrow a connection
*
* Only call this if you are returning a working connection. If the connection was bad, just let it go out of scope (so the connection manager can replace it).
* @param the connection
*/
void unborrow(std::shared_ptr<T> conn) {
// Lock
std::unique_lock<std::mutex> lock(m_poolMutex);
m_borrowed.erase(conn);
Metrics::pool_in_use--;
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
Metrics::pool_avail++;
m_pool.push_back(conn);
}
};
protected:
size_t m_maxPoolSize;
size_t m_minPoolSize;
std::shared_ptr<ConnectionFactory> m_factory;
std::deque<std::shared_ptr<Connection> > m_pool;
std::set<std::shared_ptr<Connection> > m_borrowed;
std::mutex m_poolMutex;
// Take one off the front
std::shared_ptr<Connection> conn = m_pool.front();
m_pool.pop_front();
Metrics::pool_avail--;
// Add it to the borrowed list
m_borrowed.insert(conn);
Metrics::pool_in_use++;
return std::static_pointer_cast<T>(conn);
};
/**
* Unborrow a connection
*
* Only call this if you are returning a working connection. If the connection was bad, just let it go out of scope (so the connection manager can replace it).
* @param the connection
*/
void unborrow(std::shared_ptr<T> conn)
{
// Lock
std::unique_lock<std::mutex> lock(m_poolMutex);
m_borrowed.erase(conn);
Metrics::pool_in_use--;
if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
Metrics::pool_avail++;
m_pool.push_back(conn);
}
};
protected:
size_t m_maxPoolSize;
size_t m_minPoolSize;
std::shared_ptr<ConnectionFactory> m_factory;
std::deque<std::shared_ptr<Connection> > m_pool;
std::set<std::shared_ptr<Connection> > m_borrowed;
std::mutex m_poolMutex;
};
}
} // namespace ZeroTier
#endif

64
controller/CtlUtil.cpp Normal file
View file

@ -0,0 +1,64 @@
#include "CtlUtil.hpp"
#ifdef ZT_CONTROLLER_USE_LIBPQ
#include <iomanip>
#include <sstream>
namespace ZeroTier {
const char* _timestr()
{
time_t t = time(0);
char* ts = ctime(&t);
char* p = ts;
if (! p)
return "";
while (*p) {
if (*p == '\n') {
*p = (char)0;
break;
}
++p;
}
return ts;
}
std::vector<std::string> split(std::string str, char delim)
{
std::istringstream iss(str);
std::vector<std::string> tokens;
std::string item;
while (std::getline(iss, item, delim)) {
tokens.push_back(item);
}
return tokens;
}
std::string url_encode(const std::string& value)
{
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char)c);
escaped << std::nouppercase;
}
return escaped.str();
}
} // namespace ZeroTier
#endif

16
controller/CtlUtil.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef ZT_CTLUTIL_HPP
#define ZT_CTLUTIL_HPP
#include <string>
#include <vector>
namespace ZeroTier {
const char* _timestr();
std::vector<std::string> split(std::string str, char delim);
std::string url_encode(const std::string& value);
} // namespace ZeroTier
#endif // namespace ZeroTier

View file

@ -12,77 +12,114 @@
/****/
#include "DB.hpp"
#include "EmbeddedNetworkController.hpp"
#include "../node/Metrics.hpp"
#include <chrono>
#include "../node/Metrics.hpp"
#include "EmbeddedNetworkController.hpp"
#include <algorithm>
#include <chrono>
#include <stdexcept>
using json = nlohmann::json;
namespace ZeroTier {
void DB::initNetwork(nlohmann::json &network)
void DB::initNetwork(nlohmann::json& network)
{
if (!network.count("private")) network["private"] = true;
if (!network.count("creationTime")) network["creationTime"] = OSUtils::now();
if (!network.count("name")) network["name"] = "";
if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32;
if (!network.count("enableBroadcast")) network["enableBroadcast"] = true;
if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}};
if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}};
if (!network.count("authTokens")) network["authTokens"] = {{}};
if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array();
if (!network.count("tags")) network["tags"] = nlohmann::json::array();
if (!network.count("routes")) network["routes"] = nlohmann::json::array();
if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
if (!network.count("removeTraceLevel")) network["remoteTraceLevel"] = 0;
if (!network.count("rulesSource")) network["rulesSource"] = "";
if (!network.count("rules")) {
if (! network.count("private"))
network["private"] = true;
if (! network.count("creationTime"))
network["creationTime"] = OSUtils::now();
if (! network.count("name"))
network["name"] = "";
if (! network.count("multicastLimit"))
network["multicastLimit"] = (uint64_t)32;
if (! network.count("enableBroadcast"))
network["enableBroadcast"] = true;
if (! network.count("v4AssignMode"))
network["v4AssignMode"] = { { "zt", false } };
if (! network.count("v6AssignMode"))
network["v6AssignMode"] = { { "rfc4193", false }, { "zt", false }, { "6plane", false } };
if (! network.count("authTokens"))
network["authTokens"] = { {} };
if (! network.count("capabilities"))
network["capabilities"] = nlohmann::json::array();
if (! network.count("tags"))
network["tags"] = nlohmann::json::array();
if (! network.count("routes"))
network["routes"] = nlohmann::json::array();
if (! network.count("ipAssignmentPools"))
network["ipAssignmentPools"] = nlohmann::json::array();
if (! network.count("mtu"))
network["mtu"] = ZT_DEFAULT_MTU;
if (! network.count("remoteTraceTarget"))
network["remoteTraceTarget"] = nlohmann::json();
if (! network.count("removeTraceLevel"))
network["remoteTraceLevel"] = 0;
if (! network.count("rulesSource"))
network["rulesSource"] = "";
if (! network.count("rules")) {
// If unspecified, rules are set to allow anything and behave like a flat L2 segment
network["rules"] = {{
{ "not",false },
{ "or", false },
{ "type","ACTION_ACCEPT" }
}};
network["rules"] = { { { "not", false }, { "or", false }, { "type", "ACTION_ACCEPT" } } };
}
if (!network.count("dns")) network["dns"] = nlohmann::json::array();
if (!network.count("ssoEnabled")) network["ssoEnabled"] = false;
if (!network.count("clientId")) network["clientId"] = "";
if (!network.count("authorizationEndpoint")) network["authorizationEndpoint"] = "";
if (! network.count("dns"))
network["dns"] = nlohmann::json::array();
if (! network.count("ssoEnabled"))
network["ssoEnabled"] = false;
if (! network.count("clientId"))
network["clientId"] = "";
if (! network.count("authorizationEndpoint"))
network["authorizationEndpoint"] = "";
network["objtype"] = "network";
}
void DB::initMember(nlohmann::json &member)
void DB::initMember(nlohmann::json& member)
{
if (!member.count("authorized")) member["authorized"] = false;
if (!member.count("ssoExempt")) member["ssoExempt"] = false;
if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
if (!member.count("activeBridge")) member["activeBridge"] = false;
if (!member.count("tags")) member["tags"] = nlohmann::json::array();
if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array();
if (!member.count("creationTime")) member["creationTime"] = OSUtils::now();
if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false;
if (!member.count("revision")) member["revision"] = 0ULL;
if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
if (!member.count("lastAuthorizedCredentialType")) member["lastAuthorizedCredentialType"] = nlohmann::json();
if (!member.count("lastAuthorizedCredential")) member["lastAuthorizedCredential"] = nlohmann::json();
if (!member.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = 0LL;
if (!member.count("vMajor")) member["vMajor"] = -1;
if (!member.count("vMinor")) member["vMinor"] = -1;
if (!member.count("vRev")) member["vRev"] = -1;
if (!member.count("vProto")) member["vProto"] = -1;
if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json();
if (!member.count("removeTraceLevel")) member["remoteTraceLevel"] = 0;
if (! member.count("authorized"))
member["authorized"] = false;
if (! member.count("ssoExempt"))
member["ssoExempt"] = false;
if (! member.count("ipAssignments"))
member["ipAssignments"] = nlohmann::json::array();
if (! member.count("activeBridge"))
member["activeBridge"] = false;
if (! member.count("tags"))
member["tags"] = nlohmann::json::array();
if (! member.count("capabilities"))
member["capabilities"] = nlohmann::json::array();
if (! member.count("creationTime"))
member["creationTime"] = OSUtils::now();
if (! member.count("noAutoAssignIps"))
member["noAutoAssignIps"] = false;
if (! member.count("revision"))
member["revision"] = 0ULL;
if (! member.count("lastDeauthorizedTime"))
member["lastDeauthorizedTime"] = 0ULL;
if (! member.count("lastAuthorizedTime"))
member["lastAuthorizedTime"] = 0ULL;
if (! member.count("lastAuthorizedCredentialType"))
member["lastAuthorizedCredentialType"] = nlohmann::json();
if (! member.count("lastAuthorizedCredential"))
member["lastAuthorizedCredential"] = nlohmann::json();
if (! member.count("authenticationExpiryTime"))
member["authenticationExpiryTime"] = 0LL;
if (! member.count("vMajor"))
member["vMajor"] = -1;
if (! member.count("vMinor"))
member["vMinor"] = -1;
if (! member.count("vRev"))
member["vRev"] = -1;
if (! member.count("vProto"))
member["vProto"] = -1;
if (! member.count("remoteTraceTarget"))
member["remoteTraceTarget"] = nlohmann::json();
if (! member.count("removeTraceLevel"))
member["remoteTraceLevel"] = 0;
member["objtype"] = "member";
}
void DB::cleanNetwork(nlohmann::json &network)
void DB::cleanNetwork(nlohmann::json& network)
{
network.erase("clock");
network.erase("authorizedMemberCount");
@ -91,21 +128,25 @@ void DB::cleanNetwork(nlohmann::json &network)
network.erase("lastModified");
}
void DB::cleanMember(nlohmann::json &member)
void DB::cleanMember(nlohmann::json& member)
{
member.erase("clock");
member.erase("physicalAddr");
member.erase("recentLog");
member.erase("lastModified");
member.erase("lastRequestMetaData");
member.erase("authenticationURL"); // computed
member.erase("authenticationClientID"); // computed
member.erase("authenticationURL"); // computed
member.erase("authenticationClientID"); // computed
}
DB::DB() {}
DB::~DB() {}
DB::DB()
{
}
DB::~DB()
{
}
bool DB::get(const uint64_t networkId,nlohmann::json &network)
bool DB::get(const uint64_t networkId, nlohmann::json& network)
{
waitForReady();
Metrics::db_get_network++;
@ -124,7 +165,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network)
return true;
}
bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
bool DB::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member)
{
waitForReady();
Metrics::db_get_network_and_member++;
@ -147,7 +188,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
return true;
}
bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info)
bool DB::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, NetworkSummaryInfo& info)
{
waitForReady();
Metrics::db_get_network_and_member_and_summary++;
@ -162,7 +203,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
{
std::shared_lock<std::shared_mutex> l2(nw->lock);
network = nw->config;
_fillSummaryInfo(nw,info);
_fillSummaryInfo(nw, info);
auto m = nw->members.find(memberId);
if (m == nw->members.end())
return false;
@ -171,7 +212,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
return true;
}
bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
bool DB::get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members)
{
waitForReady();
Metrics::db_get_member_list++;
@ -186,23 +227,23 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohma
{
std::shared_lock<std::shared_mutex> l2(nw->lock);
network = nw->config;
for(auto m=nw->members.begin();m!=nw->members.end();++m) {
for (auto m = nw->members.begin(); m != nw->members.end(); ++m) {
members.push_back(m->second);
}
}
return true;
}
void DB::networks(std::set<uint64_t> &networks)
void DB::networks(std::set<uint64_t>& networks)
{
waitForReady();
Metrics::db_get_network_list++;
std::shared_lock<std::shared_mutex> l(_networks_l);
for(auto n=_networks.begin();n!=_networks.end();++n)
for (auto n = _networks.begin(); n != _networks.end(); ++n)
networks.insert(n->first);
}
void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners)
void DB::_memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners)
{
Metrics::db_member_change++;
uint64_t memberId = 0;
@ -212,9 +253,9 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
std::shared_ptr<_Network> nw;
if (old.is_object()) {
memberId = OSUtils::jsonIntHex(old["id"],0ULL);
networkId = OSUtils::jsonIntHex(old["nwid"],0ULL);
if ((memberId)&&(networkId)) {
memberId = OSUtils::jsonIntHex(old["id"], 0ULL);
networkId = OSUtils::jsonIntHex(old["nwid"], 0ULL);
if ((memberId) && (networkId)) {
{
std::unique_lock<std::shared_mutex> l(_networks_l);
auto nw2 = _networks.find(networkId);
@ -224,17 +265,17 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
if (nw) {
std::unique_lock<std::shared_mutex> l(nw->lock);
if (OSUtils::jsonBool(old["activeBridge"],false)) {
if (OSUtils::jsonBool(old["activeBridge"], false)) {
nw->activeBridgeMembers.erase(memberId);
}
wasAuth = OSUtils::jsonBool(old["authorized"],false);
wasAuth = OSUtils::jsonBool(old["authorized"], false);
if (wasAuth) {
nw->authorizedMembers.erase(memberId);
}
json &ips = old["ipAssignments"];
json& ips = old["ipAssignments"];
if (ips.is_array()) {
for(unsigned long i=0;i<ips.size();++i) {
json &ipj = ips[i];
for (unsigned long i = 0; i < ips.size(); ++i) {
json& ipj = ips[i];
if (ipj.is_string()) {
const std::string ips = ipj;
InetAddress ipa(ips.c_str());
@ -248,14 +289,14 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
if (memberConfig.is_object()) {
if (!nw) {
memberId = OSUtils::jsonIntHex(memberConfig["id"],0ULL);
networkId = OSUtils::jsonIntHex(memberConfig["nwid"],0ULL);
if ((!memberId)||(!networkId))
if (! nw) {
memberId = OSUtils::jsonIntHex(memberConfig["id"], 0ULL);
networkId = OSUtils::jsonIntHex(memberConfig["nwid"], 0ULL);
if ((! memberId) || (! networkId))
return;
std::unique_lock<std::shared_mutex> l(_networks_l);
std::shared_ptr<_Network> &nw2 = _networks[networkId];
if (!nw2)
std::shared_ptr<_Network>& nw2 = _networks[networkId];
if (! nw2)
nw2.reset(new _Network);
nw = nw2;
}
@ -265,18 +306,18 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
nw->members[memberId] = memberConfig;
if (OSUtils::jsonBool(memberConfig["activeBridge"],false)) {
if (OSUtils::jsonBool(memberConfig["activeBridge"], false)) {
nw->activeBridgeMembers.insert(memberId);
}
isAuth = OSUtils::jsonBool(memberConfig["authorized"],false);
isAuth = OSUtils::jsonBool(memberConfig["authorized"], false);
if (isAuth) {
Metrics::member_auths++;
nw->authorizedMembers.insert(memberId);
}
json &ips = memberConfig["ipAssignments"];
json& ips = memberConfig["ipAssignments"];
if (ips.is_array()) {
for(unsigned long i=0;i<ips.size();++i) {
json &ipj = ips[i];
for (unsigned long i = 0; i < ips.size(); ++i) {
json& ipj = ips[i];
if (ipj.is_string()) {
const std::string ips = ipj;
InetAddress ipa(ips.c_str());
@ -286,8 +327,8 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
}
if (!isAuth) {
const int64_t ldt = (int64_t)OSUtils::jsonInt(memberConfig["lastDeauthorizedTime"],0ULL);
if (! isAuth) {
const int64_t ldt = (int64_t)OSUtils::jsonInt(memberConfig["lastDeauthorizedTime"], 0ULL);
if (ldt > nw->mostRecentDeauthTime)
nw->mostRecentDeauthTime = ldt;
}
@ -295,11 +336,12 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
if (notifyListeners) {
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
(*i)->onNetworkMemberUpdate(this,networkId,memberId,memberConfig);
for (auto i = _changeListeners.begin(); i != _changeListeners.end(); ++i) {
(*i)->onNetworkMemberUpdate(this, networkId, memberId, memberConfig);
}
}
} else if (memberId) {
}
else if (memberId) {
if (nw) {
std::unique_lock<std::shared_mutex> l(nw->lock);
nw->members.erase(memberId);
@ -307,7 +349,7 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
if (networkId) {
std::unique_lock<std::shared_mutex> l(_networks_l);
auto er = _networkByMember.equal_range(memberId);
for(auto i=er.first;i!=er.second;++i) {
for (auto i = er.first; i != er.second; ++i) {
if (i->second == networkId) {
_networkByMember.erase(i);
break;
@ -317,40 +359,45 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
}
if (notifyListeners) {
if(networkId != 0 && memberId != 0 && old.is_object() && !memberConfig.is_object()) {
if (networkId != 0 && memberId != 0 && old.is_object() && ! memberConfig.is_object()) {
// member delete
Metrics::member_count--;
} else if (networkId != 0 && memberId != 0 && !old.is_object() && memberConfig.is_object()) {
}
else if (networkId != 0 && memberId != 0 && ! old.is_object() && memberConfig.is_object()) {
// new member
Metrics::member_count++;
}
if (!wasAuth && isAuth) {
if (! wasAuth && isAuth) {
Metrics::member_auths++;
} else if (wasAuth && !isAuth) {
}
else if (wasAuth && ! isAuth) {
Metrics::member_deauths++;
} else {
}
else {
Metrics::member_changes++;
}
}
if ((notifyListeners)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId))) {
if ((notifyListeners) && ((wasAuth) && (! isAuth) && (networkId) && (memberId))) {
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
(*i)->onNetworkMemberDeauthorize(this,networkId,memberId);
for (auto i = _changeListeners.begin(); i != _changeListeners.end(); ++i) {
(*i)->onNetworkMemberDeauthorize(this, networkId, memberId);
}
}
}
void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners)
void DB::_networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners)
{
Metrics::db_network_change++;
if (notifyListeners) {
if (old.is_object() && old.contains("id") && networkConfig.is_object() && networkConfig.contains("id")) {
Metrics::network_changes++;
} else if (!old.is_object() && networkConfig.is_object() && networkConfig.contains("id")) {
}
else if (! old.is_object() && networkConfig.is_object() && networkConfig.contains("id")) {
Metrics::network_count++;
} else if (old.is_object() && old.contains("id") && !networkConfig.is_object()) {
}
else if (old.is_object() && old.contains("id") && ! networkConfig.is_object()) {
Metrics::network_count--;
}
}
@ -362,8 +409,8 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
std::shared_ptr<_Network> nw;
{
std::unique_lock<std::shared_mutex> l(_networks_l);
std::shared_ptr<_Network> &nw2 = _networks[networkId];
if (!nw2)
std::shared_ptr<_Network>& nw2 = _networks[networkId];
if (! nw2)
nw2.reset(new _Network);
nw = nw2;
}
@ -373,12 +420,13 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
}
if (notifyListeners) {
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
(*i)->onNetworkUpdate(this,networkId,networkConfig);
for (auto i = _changeListeners.begin(); i != _changeListeners.end(); ++i) {
(*i)->onNetworkUpdate(this, networkId, networkConfig);
}
}
}
} else if (old.is_object()) {
}
else if (old.is_object()) {
const std::string ids = old["id"];
const uint64_t networkId = Utils::hexStrToU64(ids.c_str());
if (networkId) {
@ -387,15 +435,16 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
nlohmann::json network;
std::vector<nlohmann::json> members;
this->get(networkId, network, members);
for(auto i=members.begin();i!=members.end();++i) {
for (auto i = members.begin(); i != members.end(); ++i) {
const std::string nodeID = (*i)["id"];
const uint64_t memberId = Utils::hexStrToU64(nodeID.c_str());
std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
for(auto j=_changeListeners.begin();j!=_changeListeners.end();++j) {
(*j)->onNetworkMemberDeauthorize(this,networkId,memberId);
for (auto j = _changeListeners.begin(); j != _changeListeners.end(); ++j) {
(*j)->onNetworkMemberDeauthorize(this, networkId, memberId);
}
}
} catch (std::exception &e) {
}
catch (std::exception& e) {
std::cerr << "Error deauthorizing members on network delete: " << e.what() << std::endl;
}
@ -406,17 +455,17 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
}
}
void DB::_fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info)
void DB::_fillSummaryInfo(const std::shared_ptr<_Network>& nw, NetworkSummaryInfo& info)
{
for(auto ab=nw->activeBridgeMembers.begin();ab!=nw->activeBridgeMembers.end();++ab)
for (auto ab = nw->activeBridgeMembers.begin(); ab != nw->activeBridgeMembers.end(); ++ab)
info.activeBridges.push_back(Address(*ab));
std::sort(info.activeBridges.begin(),info.activeBridges.end());
for(auto ip=nw->allocatedIps.begin();ip!=nw->allocatedIps.end();++ip)
std::sort(info.activeBridges.begin(), info.activeBridges.end());
for (auto ip = nw->allocatedIps.begin(); ip != nw->allocatedIps.end(); ++ip)
info.allocatedIps.push_back(*ip);
std::sort(info.allocatedIps.begin(),info.allocatedIps.end());
std::sort(info.allocatedIps.begin(), info.allocatedIps.end());
info.authorizedMemberCount = (unsigned long)nw->authorizedMembers.size();
info.totalMemberCount = (unsigned long)nw->members.size();
info.mostRecentDeauthTime = nw->mostRecentDeauthTime;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,49 +14,36 @@
#ifndef ZT_CONTROLLER_DB_HPP
#define ZT_CONTROLLER_DB_HPP
//#define ZT_CONTROLLER_USE_LIBPQ
// #define ZT_CONTROLLER_USE_LIBPQ
#include "../node/Constants.hpp"
#include "../node/Identity.hpp"
#include "../node/InetAddress.hpp"
#include "../osdep/OSUtils.hpp"
#include "../osdep/BlockingQueue.hpp"
#include "../osdep/OSUtils.hpp"
#include <atomic>
#include <map>
#include <memory>
#include <nlohmann/json.hpp>
#include <prometheus/simpleapi.h>
#include <set>
#include <shared_mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <atomic>
#include <shared_mutex>
#include <set>
#include <map>
#include <nlohmann/json.hpp>
#include <prometheus/simpleapi.h>
#define ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE 25000
namespace ZeroTier
{
namespace ZeroTier {
struct AuthInfo
{
public:
AuthInfo()
: enabled(false)
, version(0)
, authenticationURL()
, authenticationExpiryTime(0)
, issuerURL()
, centralAuthURL()
, ssoNonce()
, ssoState()
, ssoClientID()
, ssoProvider("default")
{}
struct AuthInfo {
public:
AuthInfo() : enabled(false), version(0), authenticationURL(), authenticationExpiryTime(0), issuerURL(), centralAuthURL(), ssoNonce(), ssoState(), ssoClientID(), ssoProvider("default")
{
}
bool enabled;
uint64_t version;
@ -73,22 +60,35 @@ public:
/**
* Base class with common infrastructure for all controller DB implementations
*/
class DB
{
public:
class ChangeListener
{
public:
ChangeListener() {}
virtual ~ChangeListener() {}
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network) {}
virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member) {}
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId) {}
class DB {
#ifdef ZT_CONTROLLER_USE_LIBPQ
friend class MemberNotificationReceiver;
friend class NetworkNotificationReceiver;
#endif
public:
class ChangeListener {
public:
ChangeListener()
{
}
virtual ~ChangeListener()
{
}
virtual void onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network)
{
}
virtual void onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member)
{
}
virtual void onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId)
{
}
};
struct NetworkSummaryInfo
{
NetworkSummaryInfo() : authorizedMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
struct NetworkSummaryInfo {
NetworkSummaryInfo() : authorizedMemberCount(0), totalMemberCount(0), mostRecentDeauthTime(0)
{
}
std::vector<Address> activeBridges;
std::vector<InetAddress> allocatedIps;
unsigned long authorizedMemberCount;
@ -96,10 +96,10 @@ public:
int64_t mostRecentDeauthTime;
};
static void initNetwork(nlohmann::json &network);
static void initMember(nlohmann::json &member);
static void cleanNetwork(nlohmann::json &network);
static void cleanMember(nlohmann::json &member);
static void initNetwork(nlohmann::json& network);
static void initMember(nlohmann::json& member);
static void cleanNetwork(nlohmann::json& network);
static void cleanMember(nlohmann::json& member);
DB();
virtual ~DB();
@ -113,41 +113,44 @@ public:
return (_networks.find(networkId) != _networks.end());
}
bool get(const uint64_t networkId,nlohmann::json &network);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info);
bool get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members);
bool get(const uint64_t networkId, nlohmann::json& network);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, NetworkSummaryInfo& info);
bool get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members);
void networks(std::set<uint64_t> &networks);
void networks(std::set<uint64_t>& networks);
template<typename F>
inline void each(F f)
template <typename F> inline void each(F f)
{
nlohmann::json nullJson;
std::unique_lock<std::shared_mutex> lck(_networks_l);
for(auto nw=_networks.begin();nw!=_networks.end();++nw) {
f(nw->first,nw->second->config,0,nullJson); // first provide network with 0 for member ID
for(auto m=nw->second->members.begin();m!=nw->second->members.end();++m) {
f(nw->first,nw->second->config,m->first,m->second);
for (auto nw = _networks.begin(); nw != _networks.end(); ++nw) {
f(nw->first, nw->second->config, 0, nullJson); // first provide network with 0 for member ID
for (auto m = nw->second->members.begin(); m != nw->second->members.end(); ++m) {
f(nw->first, nw->second->config, m->first, m->second);
}
}
}
virtual bool save(nlohmann::json &record,bool notifyListeners) = 0;
virtual bool save(nlohmann::json& record, bool notifyListeners) = 0;
virtual void eraseNetwork(const uint64_t networkId) = 0;
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId) = 0;
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0;
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId) = 0;
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress) = 0;
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch) = 0;
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); }
virtual AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL)
{
return AuthInfo();
}
inline void addListener(DB::ChangeListener *const listener)
inline void addListener(DB::ChangeListener* const listener)
{
std::unique_lock<std::shared_mutex> l(_changeListeners_l);
_changeListeners.push_back(listener);
}
protected:
static inline bool _compareRecords(const nlohmann::json &a,const nlohmann::json &b)
protected:
static inline bool _compareRecords(const nlohmann::json& a, const nlohmann::json& b)
{
if (a.is_object() == b.is_object()) {
if (a.is_object()) {
@ -155,10 +158,10 @@ protected:
return false;
auto amap = a.get<nlohmann::json::object_t>();
auto bmap = b.get<nlohmann::json::object_t>();
for(auto ai=amap.begin();ai!=amap.end();++ai) {
if (ai->first != "revision") { // ignore revision, compare only non-revision-counter fields
for (auto ai = amap.begin(); ai != amap.end(); ++ai) {
if (ai->first != "revision") { // ignore revision, compare only non-revision-counter fields
auto bi = bmap.find(ai->first);
if ((bi == bmap.end())||(bi->second != ai->second))
if ((bi == bmap.end()) || (bi->second != ai->second))
return false;
}
}
@ -169,29 +172,30 @@ protected:
return false;
}
struct _Network
{
_Network() : mostRecentDeauthTime(0) {}
struct _Network {
_Network() : mostRecentDeauthTime(0)
{
}
nlohmann::json config;
std::unordered_map<uint64_t,nlohmann::json> members;
std::unordered_map<uint64_t, nlohmann::json> members;
std::unordered_set<uint64_t> activeBridgeMembers;
std::unordered_set<uint64_t> authorizedMembers;
std::unordered_set<InetAddress,InetAddress::Hasher> allocatedIps;
std::unordered_set<InetAddress, InetAddress::Hasher> allocatedIps;
int64_t mostRecentDeauthTime;
std::shared_mutex lock;
};
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners);
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners);
void _fillSummaryInfo(const std::shared_ptr<_Network> &nw,NetworkSummaryInfo &info);
virtual void _memberChanged(nlohmann::json& old, nlohmann::json& memberConfig, bool notifyListeners);
virtual void _networkChanged(nlohmann::json& old, nlohmann::json& networkConfig, bool notifyListeners);
void _fillSummaryInfo(const std::shared_ptr<_Network>& nw, NetworkSummaryInfo& info);
std::vector<DB::ChangeListener *> _changeListeners;
std::unordered_map< uint64_t,std::shared_ptr<_Network> > _networks;
std::unordered_multimap< uint64_t,uint64_t > _networkByMember;
std::vector<DB::ChangeListener*> _changeListeners;
std::unordered_map<uint64_t, std::shared_ptr<_Network> > _networks;
std::unordered_multimap<uint64_t, uint64_t> _networkByMember;
mutable std::shared_mutex _changeListeners_l;
mutable std::shared_mutex _networks_l;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -15,56 +15,54 @@
namespace ZeroTier {
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener)
: _listener(listener)
, _running(true)
, _syncCheckerThread()
, _dbs()
, _dbs_l()
DBMirrorSet::DBMirrorSet(DB::ChangeListener* listener) : _listener(listener), _running(true), _syncCheckerThread(), _dbs(), _dbs_l()
{
_syncCheckerThread = std::thread([this]() {
for(;;) {
for(int i=0;i<120;++i) { // 1 minute delay between checks
if (!_running)
for (;;) {
for (int i = 0; i < 120; ++i) { // 1 minute delay between checks
if (! _running)
return;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::vector< std::shared_ptr<DB> > dbs;
std::vector<std::shared_ptr<DB> > dbs;
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
if (_dbs.size() <= 1)
continue; // no need to do this if there's only one DB, so skip the iteration
continue; // no need to do this if there's only one DB, so skip the iteration
dbs = _dbs;
}
for(auto db=dbs.begin();db!=dbs.end();++db) {
(*db)->each([&dbs,&db](uint64_t networkId,const nlohmann::json &network,uint64_t memberId,const nlohmann::json &member) {
for (auto db = dbs.begin(); db != dbs.end(); ++db) {
(*db)->each([&dbs, &db](uint64_t networkId, const nlohmann::json& network, uint64_t memberId, const nlohmann::json& member) {
try {
if (network.is_object()) {
if (memberId == 0) {
for(auto db2=dbs.begin();db2!=dbs.end();++db2) {
for (auto db2 = dbs.begin(); db2 != dbs.end(); ++db2) {
if (db->get() != db2->get()) {
nlohmann::json nw2;
if ((!(*db2)->get(networkId,nw2))||((nw2.is_object())&&(OSUtils::jsonInt(nw2["revision"],0) < OSUtils::jsonInt(network["revision"],0)))) {
if ((! (*db2)->get(networkId, nw2)) || ((nw2.is_object()) && (OSUtils::jsonInt(nw2["revision"], 0) < OSUtils::jsonInt(network["revision"], 0)))) {
nw2 = network;
(*db2)->save(nw2,false);
(*db2)->save(nw2, false);
}
}
}
} else if (member.is_object()) {
for(auto db2=dbs.begin();db2!=dbs.end();++db2) {
}
else if (member.is_object()) {
for (auto db2 = dbs.begin(); db2 != dbs.end(); ++db2) {
if (db->get() != db2->get()) {
nlohmann::json nw2,m2;
if ((!(*db2)->get(networkId,nw2,memberId,m2))||((m2.is_object())&&(OSUtils::jsonInt(m2["revision"],0) < OSUtils::jsonInt(member["revision"],0)))) {
nlohmann::json nw2, m2;
if ((! (*db2)->get(networkId, nw2, memberId, m2)) || ((m2.is_object()) && (OSUtils::jsonInt(m2["revision"], 0) < OSUtils::jsonInt(member["revision"], 0)))) {
m2 = member;
(*db2)->save(m2,false);
(*db2)->save(m2, false);
}
}
}
}
}
} catch ( ... ) {} // skip entries that generate JSON errors
}
catch (...) {
} // skip entries that generate JSON errors
});
}
}
@ -80,58 +78,58 @@ DBMirrorSet::~DBMirrorSet()
bool DBMirrorSet::hasNetwork(const uint64_t networkId) const
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->hasNetwork(networkId))
return true;
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network)) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network)) {
return true;
}
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network,memberId,member))
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network, memberId, member))
return true;
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, DB::NetworkSummaryInfo& info)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network,memberId,member,info))
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network, memberId, member, info))
return true;
}
return false;
}
bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
bool DBMirrorSet::get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if ((*d)->get(networkId,network,members))
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if ((*d)->get(networkId, network, members))
return true;
}
return false;
}
AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL)
AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
AuthInfo info = (*d)->getSSOAuthInfo(member, redirectURL);
if (info.enabled) {
return info;
@ -140,10 +138,10 @@ AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::st
return AuthInfo();
}
void DBMirrorSet::networks(std::set<uint64_t> &networks)
void DBMirrorSet::networks(std::set<uint64_t>& networks)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->networks(networks);
}
}
@ -152,7 +150,7 @@ bool DBMirrorSet::waitForReady()
{
bool r = false;
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
r |= (*d)->waitForReady();
}
return r;
@ -161,30 +159,31 @@ bool DBMirrorSet::waitForReady()
bool DBMirrorSet::isReady()
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
if (!(*d)->isReady())
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if (! (*d)->isReady())
return false;
}
return true;
}
bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners)
bool DBMirrorSet::save(nlohmann::json& record, bool notifyListeners)
{
std::vector< std::shared_ptr<DB> > dbs;
std::vector<std::shared_ptr<DB> > dbs;
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
dbs = _dbs;
}
if (notifyListeners) {
for(auto d=dbs.begin();d!=dbs.end();++d) {
if ((*d)->save(record,true))
for (auto d = dbs.begin(); d != dbs.end(); ++d) {
if ((*d)->save(record, true))
return true;
}
return false;
} else {
}
else {
bool modified = false;
for(auto d=dbs.begin();d!=dbs.end();++d) {
modified |= (*d)->save(record,false);
for (auto d = dbs.begin(); d != dbs.end(); ++d) {
modified |= (*d)->save(record, false);
}
return modified;
}
@ -193,54 +192,59 @@ bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners)
void DBMirrorSet::eraseNetwork(const uint64_t networkId)
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->eraseNetwork(networkId);
}
}
void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId)
void DBMirrorSet::eraseMember(const uint64_t networkId, const uint64_t memberId)
{
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
(*d)->eraseMember(networkId,memberId);
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->eraseMember(networkId, memberId);
}
}
void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
void DBMirrorSet::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch)
{
std::shared_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
(*d)->nodeIsOnline(networkId,memberId,physicalAddress);
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
(*d)->nodeIsOnline(networkId, memberId, physicalAddress, osArch);
}
}
void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network)
void DBMirrorSet::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress)
{
this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown");
}
void DBMirrorSet::onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network)
{
nlohmann::json record(network);
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if (d->get() != db) {
(*d)->save(record,false);
(*d)->save(record, false);
}
}
_listener->onNetworkUpdate(this,networkId,network);
_listener->onNetworkUpdate(this, networkId, network);
}
void DBMirrorSet::onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member)
void DBMirrorSet::onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member)
{
nlohmann::json record(member);
std::unique_lock<std::shared_mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
for (auto d = _dbs.begin(); d != _dbs.end(); ++d) {
if (d->get() != db) {
(*d)->save(record,false);
(*d)->save(record, false);
}
}
_listener->onNetworkMemberUpdate(this,networkId,memberId,member);
_listener->onNetworkMemberUpdate(this, networkId, memberId, member);
}
void DBMirrorSet::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId)
void DBMirrorSet::onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId)
{
_listener->onNetworkMemberDeauthorize(this,networkId,memberId);
_listener->onNetworkMemberDeauthorize(this, networkId, memberId);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -16,58 +16,58 @@
#include "DB.hpp"
#include <vector>
#include <memory>
#include <shared_mutex>
#include <set>
#include <shared_mutex>
#include <thread>
#include <vector>
namespace ZeroTier {
class DBMirrorSet : public DB::ChangeListener
{
public:
DBMirrorSet(DB::ChangeListener *listener);
class DBMirrorSet : public DB::ChangeListener {
public:
DBMirrorSet(DB::ChangeListener* listener);
virtual ~DBMirrorSet();
bool hasNetwork(const uint64_t networkId) const;
bool get(const uint64_t networkId,nlohmann::json &network);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member);
bool get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info);
bool get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members);
bool get(const uint64_t networkId, nlohmann::json& network);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member);
bool get(const uint64_t networkId, nlohmann::json& network, const uint64_t memberId, nlohmann::json& member, DB::NetworkSummaryInfo& info);
bool get(const uint64_t networkId, nlohmann::json& network, std::vector<nlohmann::json>& members);
void networks(std::set<uint64_t> &networks);
void networks(std::set<uint64_t>& networks);
bool waitForReady();
bool isReady();
bool save(nlohmann::json &record,bool notifyListeners);
bool save(nlohmann::json& record, bool notifyListeners);
void eraseNetwork(const uint64_t networkId);
void eraseMember(const uint64_t networkId,const uint64_t memberId);
void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
// These are called by various DB instances when changes occur.
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network);
virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member);
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
virtual void onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network);
virtual void onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member);
virtual void onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId);
AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
AuthInfo getSSOAuthInfo(const nlohmann::json& member, const std::string& redirectURL);
inline void addDB(const std::shared_ptr<DB> &db)
inline void addDB(const std::shared_ptr<DB>& db)
{
db->addListener(this);
std::unique_lock<std::shared_mutex> l(_dbs_l);
_dbs.push_back(db);
}
private:
DB::ChangeListener *const _listener;
private:
DB::ChangeListener* const _listener;
std::atomic_bool _running;
std::thread _syncCheckerThread;
std::vector< std::shared_ptr< DB > > _dbs;
std::vector<std::shared_ptr<DB> > _dbs;
mutable std::shared_mutex _dbs_l;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,112 +14,109 @@
#ifndef ZT_SQLITENETWORKCONTROLLER_HPP
#define ZT_SQLITENETWORKCONTROLLER_HPP
#include <stdint.h>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <list>
#include <thread>
#include <unordered_map>
#include <atomic>
#include "../node/Address.hpp"
#include "../node/Constants.hpp"
#include "../node/InetAddress.hpp"
#include "../node/NetworkController.hpp"
#include "../node/Utils.hpp"
#include "../node/Address.hpp"
#include "../node/InetAddress.hpp"
#include "../osdep/BlockingQueue.hpp"
#include "../osdep/OSUtils.hpp"
#include "../osdep/Thread.hpp"
#include "../osdep/BlockingQueue.hpp"
#include <nlohmann/json.hpp>
#include <cpp-httplib/httplib.h>
#include "DB.hpp"
#include "DBMirrorSet.hpp"
#include <atomic>
#include <cpp-httplib/httplib.h>
#include <list>
#include <map>
#include <nlohmann/json.hpp>
#include <set>
#include <stdint.h>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
namespace ZeroTier {
class Node;
struct RedisConfig;
class EmbeddedNetworkController : public NetworkController,public DB::ChangeListener
{
public:
class EmbeddedNetworkController
: public NetworkController
, public DB::ChangeListener {
public:
/**
* @param node Parent node
* @param dbPath Database path (file path or database credentials)
*/
EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, RedisConfig *rc);
EmbeddedNetworkController(Node* node, const char* ztPath, const char* dbPath, int listenPort, RedisConfig* rc);
virtual ~EmbeddedNetworkController();
virtual void init(const Identity &signingId,Sender *sender);
virtual void init(const Identity& signingId, Sender* sender);
void setSSORedirectURL(const std::string &url);
void setSSORedirectURL(const std::string& url);
virtual void request(
uint64_t nwid,
const InetAddress &fromAddr,
uint64_t requestPacketId,
const Identity &identity,
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
virtual void request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData);
void configureHTTPControlPlane(
httplib::Server &s,
httplib::Server &sV6,
const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
void configureHTTPControlPlane(httplib::Server& s, httplib::Server& sV6, const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
void handleRemoteTrace(const ZT_RemoteTrace &rt);
void handleRemoteTrace(const ZT_RemoteTrace& rt);
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network);
virtual void onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member);
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
virtual void onNetworkUpdate(const void* db, uint64_t networkId, const nlohmann::json& network);
virtual void onNetworkMemberUpdate(const void* db, uint64_t networkId, uint64_t memberId, const nlohmann::json& member);
virtual void onNetworkMemberDeauthorize(const void* db, uint64_t networkId, uint64_t memberId);
private:
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
private:
void _request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData);
void _startThreads();
void _ssoExpiryThread();
std::string networkUpdateFromPostData(uint64_t networkID, const std::string &body);
std::string networkUpdateFromPostData(uint64_t networkID, const std::string& body);
struct _RQEntry
{
struct _RQEntry {
uint64_t nwid;
uint64_t requestPacketId;
InetAddress fromAddr;
Identity identity;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData;
enum {
RQENTRY_TYPE_REQUEST = 0
} type;
enum { RQENTRY_TYPE_REQUEST = 0 } type;
};
struct _MemberStatusKey
{
_MemberStatusKey() : networkId(0),nodeId(0) {}
_MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {}
struct _MemberStatusKey {
_MemberStatusKey() : networkId(0), nodeId(0)
{
}
_MemberStatusKey(const uint64_t nwid, const uint64_t nid) : networkId(nwid), nodeId(nid)
{
}
uint64_t networkId;
uint64_t nodeId;
inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); }
inline bool operator<(const _MemberStatusKey &k) const { return (k.networkId < networkId) || ((k.networkId == networkId)&&(k.nodeId < nodeId)); }
inline bool operator==(const _MemberStatusKey& k) const
{
return ((k.networkId == networkId) && (k.nodeId == nodeId));
}
inline bool operator<(const _MemberStatusKey& k) const
{
return (k.networkId < networkId) || ((k.networkId == networkId) && (k.nodeId < nodeId));
}
};
struct _MemberStatus
{
_MemberStatus() : lastRequestTime(0),authenticationExpiryTime(-1),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {}
struct _MemberStatus {
_MemberStatus() : lastRequestTime(0), authenticationExpiryTime(-1), vMajor(-1), vMinor(-1), vRev(-1), vProto(-1)
{
}
int64_t lastRequestTime;
int64_t authenticationExpiryTime;
int vMajor,vMinor,vRev,vProto;
int vMajor, vMinor, vRev, vProto;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData;
Identity identity;
inline bool online(const int64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); }
inline bool online(const int64_t now) const
{
return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2));
}
};
struct _MemberStatusHash
{
inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const
struct _MemberStatusHash {
inline std::size_t operator()(const _MemberStatusKey& networkIdNodeId) const
{
return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId);
}
@ -127,26 +124,26 @@ private:
const int64_t _startTime;
int _listenPort;
Node *const _node;
Node* const _node;
std::string _ztPath;
std::string _path;
Identity _signingId;
std::string _signingIdAddressString;
NetworkController::Sender *_sender;
NetworkController::Sender* _sender;
DBMirrorSet _db;
BlockingQueue< _RQEntry * > _queue;
BlockingQueue<_RQEntry*> _queue;
std::vector<std::thread> _threads;
std::mutex _threads_l;
std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus;
std::unordered_map<_MemberStatusKey, _MemberStatus, _MemberStatusHash> _memberStatus;
std::mutex _memberStatus_l;
std::set< std::pair<int64_t, _MemberStatusKey> > _expiringSoon;
std::set<std::pair<int64_t, _MemberStatusKey> > _expiringSoon;
std::mutex _expiringSoon_l;
RedisConfig *_rc;
RedisConfig* _rc;
std::string _ssoRedirectURL;
bool _ssoExpiryRunning;
@ -154,30 +151,30 @@ private:
#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK
prometheus::simpleapi::benchmark_family_t _member_status_lookup;
prometheus::simpleapi::counter_family_t _member_status_lookup_count;
prometheus::simpleapi::counter_family_t _member_status_lookup_count;
prometheus::simpleapi::benchmark_family_t _node_is_online;
prometheus::simpleapi::counter_family_t _node_is_online_count;
prometheus::simpleapi::counter_family_t _node_is_online_count;
prometheus::simpleapi::benchmark_family_t _get_and_init_member;
prometheus::simpleapi::counter_family_t _get_and_init_member_count;
prometheus::simpleapi::counter_family_t _get_and_init_member_count;
prometheus::simpleapi::benchmark_family_t _have_identity;
prometheus::simpleapi::counter_family_t _have_identity_count;
prometheus::simpleapi::counter_family_t _have_identity_count;
prometheus::simpleapi::benchmark_family_t _determine_auth;
prometheus::simpleapi::counter_family_t _determine_auth_count;
prometheus::simpleapi::counter_family_t _determine_auth_count;
prometheus::simpleapi::benchmark_family_t _sso_check;
prometheus::simpleapi::counter_family_t _sso_check_count;
prometheus::simpleapi::counter_family_t _sso_check_count;
prometheus::simpleapi::benchmark_family_t _auth_check;
prometheus::simpleapi::counter_family_t _auth_check_count;
prometheus::simpleapi::counter_family_t _auth_check_count;
prometheus::simpleapi::benchmark_family_t _json_schlep;
prometheus::simpleapi::counter_family_t _json_schlep_count;
prometheus::simpleapi::counter_family_t _json_schlep_count;
prometheus::simpleapi::benchmark_family_t _issue_certificate;
prometheus::simpleapi::counter_family_t _issue_certificate_count;
prometheus::simpleapi::counter_family_t _issue_certificate_count;
prometheus::simpleapi::benchmark_family_t _save_member;
prometheus::simpleapi::counter_family_t _save_member_count;
prometheus::simpleapi::counter_family_t _save_member_count;
prometheus::simpleapi::benchmark_family_t _send_netconf;
prometheus::simpleapi::counter_family_t _send_netconf_count;
prometheus::simpleapi::counter_family_t _send_netconf_count;
#endif
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -15,51 +15,49 @@
#include "../node/Metrics.hpp"
namespace ZeroTier
{
namespace ZeroTier {
FileDB::FileDB(const char *path) :
DB(),
_path(path),
_networksPath(_path + ZT_PATH_SEPARATOR_S + "network"),
_tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"),
_running(true)
FileDB::FileDB(const char* path) : DB(), _path(path), _networksPath(_path + ZT_PATH_SEPARATOR_S + "network"), _tracePath(_path + ZT_PATH_SEPARATOR_S + "trace"), _running(true)
{
OSUtils::mkdir(_path.c_str());
OSUtils::lockDownFile(_path.c_str(),true);
OSUtils::lockDownFile(_path.c_str(), true);
OSUtils::mkdir(_networksPath.c_str());
OSUtils::mkdir(_tracePath.c_str());
std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(),false));
std::vector<std::string> networks(OSUtils::listDirectory(_networksPath.c_str(), false));
std::string buf;
for(auto n=networks.begin();n!=networks.end();++n) {
for (auto n = networks.begin(); n != networks.end(); ++n) {
buf.clear();
if ((n->length() == 21)&&(OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(),buf))) {
if ((n->length() == 21) && (OSUtils::readFile((_networksPath + ZT_PATH_SEPARATOR_S + *n).c_str(), buf))) {
try {
nlohmann::json network(OSUtils::jsonParse(buf));
const std::string nwids = network["id"];
if (nwids.length() == 16) {
nlohmann::json nullJson;
_networkChanged(nullJson,network,false);
_networkChanged(nullJson, network, false);
Metrics::network_count++;
std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member");
std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(),false));
for(auto m=members.begin();m!=members.end();++m) {
std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(), false));
for (auto m = members.begin(); m != members.end(); ++m) {
buf.clear();
if ((m->length() == 15)&&(OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(),buf))) {
if ((m->length() == 15) && (OSUtils::readFile((membersPath + ZT_PATH_SEPARATOR_S + *m).c_str(), buf))) {
try {
nlohmann::json member(OSUtils::jsonParse(buf));
const std::string addrs = member["id"];
if (addrs.length() == 10) {
nlohmann::json nullJson2;
_memberChanged(nullJson2,member,false);
_memberChanged(nullJson2, member, false);
Metrics::member_count++;
}
} catch ( ... ) {}
}
catch (...) {
}
}
}
}
} catch ( ... ) {}
}
catch (...) {
}
}
}
}
@ -71,97 +69,109 @@ FileDB::~FileDB()
_running = false;
_online_l.unlock();
_onlineUpdateThread.join();
} catch ( ... ) {}
}
catch (...) {
}
}
bool FileDB::waitForReady() { return true; }
bool FileDB::isReady() { return true; }
bool FileDB::save(nlohmann::json &record,bool notifyListeners)
bool FileDB::waitForReady()
{
char p1[4096],p2[4096],pb[4096];
return true;
}
bool FileDB::isReady()
{
return true;
}
bool FileDB::save(nlohmann::json& record, bool notifyListeners)
{
char p1[4096], p2[4096], pb[4096];
bool modified = false;
try {
const std::string objtype = record["objtype"];
if (objtype == "network") {
const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["id"], 0ULL);
if (nwid) {
nlohmann::json old;
get(nwid,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),nwid);
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
get(nwid, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
OSUtils::ztsnprintf(p1, sizeof(p1), "%s" ZT_PATH_SEPARATOR_S "%.16llx.json", _networksPath.c_str(), nwid);
if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
fprintf(stderr, "WARNING: controller unable to write to path: %s" ZT_EOL_S, p1);
}
_networkChanged(old,record,notifyListeners);
_networkChanged(old, record, notifyListeners);
modified = true;
}
}
} else if (objtype == "member") {
const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL);
if ((id)&&(nwid)) {
nlohmann::json network,old;
get(nwid,network,id,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
OSUtils::ztsnprintf(pb,sizeof(pb),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member",_networksPath.c_str(),(unsigned long long)nwid);
OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.10llx.json",pb,(unsigned long long)id);
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
OSUtils::ztsnprintf(p2,sizeof(p2),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)nwid);
}
else if (objtype == "member") {
const uint64_t id = OSUtils::jsonIntHex(record["id"], 0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"], 0ULL);
if ((id) && (nwid)) {
nlohmann::json network, old;
get(nwid, network, id, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
OSUtils::ztsnprintf(pb, sizeof(pb), "%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member", _networksPath.c_str(), (unsigned long long)nwid);
OSUtils::ztsnprintf(p1, sizeof(p1), "%s" ZT_PATH_SEPARATOR_S "%.10llx.json", pb, (unsigned long long)id);
if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
OSUtils::ztsnprintf(p2, sizeof(p2), "%s" ZT_PATH_SEPARATOR_S "%.16llx", _networksPath.c_str(), (unsigned long long)nwid);
OSUtils::mkdir(p2);
OSUtils::mkdir(pb);
if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
if (! OSUtils::writeFile(p1, OSUtils::jsonDump(record, -1))) {
fprintf(stderr, "WARNING: controller unable to write to path: %s" ZT_EOL_S, p1);
}
}
_memberChanged(old,record,notifyListeners);
_memberChanged(old, record, notifyListeners);
modified = true;
}
}
}
} catch ( ... ) {} // drop invalid records missing fields
}
catch (...) {
} // drop invalid records missing fields
return modified;
}
void FileDB::eraseNetwork(const uint64_t networkId)
{
nlohmann::json network,nullJson;
get(networkId,network);
nlohmann::json network, nullJson;
get(networkId, network);
char p[16384];
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),networkId);
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx.json", _networksPath.c_str(), networkId);
OSUtils::rm(p);
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)networkId);
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx", _networksPath.c_str(), (unsigned long long)networkId);
OSUtils::rmDashRf(p);
_networkChanged(network,nullJson,true);
_networkChanged(network, nullJson, true);
std::lock_guard<std::mutex> l(this->_online_l);
this->_online.erase(networkId);
}
void FileDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
void FileDB::eraseMember(const uint64_t networkId, const uint64_t memberId)
{
nlohmann::json network,member,nullJson;
get(networkId,network,memberId,member);
nlohmann::json network, member, nullJson;
get(networkId, network, memberId, member);
char p[4096];
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json",_networksPath.c_str(),networkId,memberId);
OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx" ZT_PATH_SEPARATOR_S "member" ZT_PATH_SEPARATOR_S "%.10llx.json", _networksPath.c_str(), networkId, memberId);
OSUtils::rm(p);
_memberChanged(member,nullJson,true);
_memberChanged(member, nullJson, true);
std::lock_guard<std::mutex> l(this->_online_l);
this->_online[networkId].erase(memberId);
}
void FileDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
void FileDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch)
{
char mid[32],atmp[64];
OSUtils::ztsnprintf(mid,sizeof(mid),"%.10llx",(unsigned long long)memberId);
char mid[32], atmp[64];
OSUtils::ztsnprintf(mid, sizeof(mid), "%.10llx", (unsigned long long)memberId);
physicalAddress.toString(atmp);
std::lock_guard<std::mutex> l(this->_online_l);
this->_online[networkId][memberId][OSUtils::now()] = physicalAddress;
}
} // namespace ZeroTier
void FileDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress)
{
this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown");
}
} // namespace ZeroTier

View file

@ -16,32 +16,31 @@
#include "DB.hpp"
namespace ZeroTier
{
namespace ZeroTier {
class FileDB : public DB
{
public:
FileDB(const char *path);
class FileDB : public DB {
public:
FileDB(const char* path);
virtual ~FileDB();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json &record,bool notifyListeners);
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
protected:
protected:
std::string _path;
std::string _networksPath;
std::string _tracePath;
std::thread _onlineUpdateThread;
std::map< uint64_t,std::map<uint64_t,std::map<int64_t,InetAddress> > > _online;
std::map<uint64_t, std::map<uint64_t, std::map<int64_t, InetAddress> > > _online;
std::mutex _online_l;
bool _running;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -13,51 +13,52 @@
#include "LFDB.hpp"
#include <thread>
#include "../ext/cpp-httplib/httplib.h"
#include "../osdep/OSUtils.hpp"
#include <chrono>
#include <iostream>
#include <sstream>
#include <thread>
#include "../osdep/OSUtils.hpp"
#include "../ext/cpp-httplib/httplib.h"
namespace ZeroTier {
namespace ZeroTier
{
LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState) :
DB(),
_myId(myId),
_lfOwnerPrivate((lfOwnerPrivate) ? lfOwnerPrivate : ""),
_lfOwnerPublic((lfOwnerPublic) ? lfOwnerPublic : ""),
_lfNodeHost((lfNodeHost) ? lfNodeHost : "127.0.0.1"),
_lfNodePort(((lfNodePort > 0)&&(lfNodePort < 65536)) ? lfNodePort : 9980),
_running(true),
_ready(false),
_storeOnlineState(storeOnlineState)
LFDB::LFDB(const Identity& myId, const char* path, const char* lfOwnerPrivate, const char* lfOwnerPublic, const char* lfNodeHost, int lfNodePort, bool storeOnlineState)
: DB()
, _myId(myId)
, _lfOwnerPrivate((lfOwnerPrivate) ? lfOwnerPrivate : "")
, _lfOwnerPublic((lfOwnerPublic) ? lfOwnerPublic : "")
, _lfNodeHost((lfNodeHost) ? lfNodeHost : "127.0.0.1")
, _lfNodePort(((lfNodePort > 0) && (lfNodePort < 65536)) ? lfNodePort : 9980)
, _running(true)
, _ready(false)
, _storeOnlineState(storeOnlineState)
{
_syncThread = std::thread([this]() {
char controllerAddress[24];
const uint64_t controllerAddressInt = _myId.address().toInt();
_myId.address().toString(controllerAddress);
std::string networksSelectorName("com.zerotier.controller.lfdb:"); networksSelectorName.append(controllerAddress); networksSelectorName.append("/network");
std::string networksSelectorName("com.zerotier.controller.lfdb:");
networksSelectorName.append(controllerAddress);
networksSelectorName.append("/network");
// LF record masking key is the first 32 bytes of SHA512(controller private key) in hex,
// hiding record values from anything but the controller or someone who has its key.
uint8_t sha512pk[64];
_myId.sha512PrivateKey(sha512pk);
char maskingKey [128];
Utils::hex(sha512pk,32,maskingKey);
char maskingKey[128];
Utils::hex(sha512pk, 32, maskingKey);
httplib::Client htcli(_lfNodeHost.c_str(),_lfNodePort);
httplib::Client htcli(_lfNodeHost.c_str(), _lfNodePort);
int64_t timeRangeStart = 0;
while (_running.load()) {
{
std::lock_guard<std::mutex> sl(_state_l);
for(auto ns=_state.begin();ns!=_state.end();++ns) {
for (auto ns = _state.begin(); ns != _state.end(); ++ns) {
if (ns->second.dirty) {
nlohmann::json network;
if (get(ns->first,network)) {
nlohmann::json newrec,selector0;
if (get(ns->first, network)) {
nlohmann::json newrec, selector0;
selector0["Name"] = networksSelectorName;
selector0["Ordinal"] = ns->first;
newrec["Selectors"].push_back(selector0);
@ -66,30 +67,34 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
newrec["MaskingKey"] = maskingKey;
newrec["PulseIfUnchanged"] = true;
try {
auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json");
auto resp = htcli.Post("/makerecord", newrec.dump(), "application/json");
if (resp) {
if (resp->status == 200) {
ns->second.dirty = false;
//printf("SET network %.16llx %s\n",ns->first,resp->body.c_str());
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (create/update network): %s" ZT_EOL_S,resp->status,resp->body.c_str());
// printf("SET network %.16llx %s\n",ns->first,resp->body.c_str());
}
else {
fprintf(stderr, "ERROR: LFDB: %d from node (create/update network): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update network): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update network): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update network): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update network): unknown exception" ZT_EOL_S);
}
}
}
for(auto ms=ns->second.members.begin();ms!=ns->second.members.end();++ms) {
if ((_storeOnlineState)&&(ms->second.lastOnlineDirty)&&(ms->second.lastOnlineAddress)) {
nlohmann::json newrec,selector0,selector1,selectors,ip;
char tmp[1024],tmp2[128];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"com.zerotier.controller.lfdb:%s/network/%.16llx/online",controllerAddress,(unsigned long long)ns->first);
for (auto ms = ns->second.members.begin(); ms != ns->second.members.end(); ++ms) {
if ((_storeOnlineState) && (ms->second.lastOnlineDirty) && (ms->second.lastOnlineAddress)) {
nlohmann::json newrec, selector0, selector1, selectors, ip;
char tmp[1024], tmp2[128];
OSUtils::ztsnprintf(tmp, sizeof(tmp), "com.zerotier.controller.lfdb:%s/network/%.16llx/online", controllerAddress, (unsigned long long)ns->first);
ms->second.lastOnlineAddress.toIpString(tmp2);
selector0["Name"] = tmp;
selector0["Ordinal"] = ms->first;
@ -98,18 +103,18 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
selectors.push_back(selector0);
selectors.push_back(selector1);
newrec["Selectors"] = selectors;
const uint8_t *const rawip = (const uint8_t *)ms->second.lastOnlineAddress.rawIpData();
switch(ms->second.lastOnlineAddress.ss_family) {
const uint8_t* const rawip = (const uint8_t*)ms->second.lastOnlineAddress.rawIpData();
switch (ms->second.lastOnlineAddress.ss_family) {
case AF_INET:
for(int j=0;j<4;++j)
for (int j = 0; j < 4; ++j)
ip.push_back((unsigned int)rawip[j]);
break;
case AF_INET6:
for(int j=0;j<16;++j)
for (int j = 0; j < 16; ++j)
ip.push_back((unsigned int)rawip[j]);
break;
default:
ip = tmp2; // should never happen since only IP transport is currently supported
ip = tmp2; // should never happen since only IP transport is currently supported
break;
}
newrec["Value"] = ip;
@ -118,28 +123,32 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
newrec["Timestamp"] = ms->second.lastOnlineTime;
newrec["PulseIfUnchanged"] = true;
try {
auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json");
auto resp = htcli.Post("/makerecord", newrec.dump(), "application/json");
if (resp) {
if (resp->status == 200) {
ms->second.lastOnlineDirty = false;
//printf("SET member online %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (create/update member online status): %s" ZT_EOL_S,resp->status,resp->body.c_str());
// printf("SET member online %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
}
else {
fprintf(stderr, "ERROR: LFDB: %d from node (create/update member online status): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member online status): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member online status): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member online status): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member online status): unknown exception" ZT_EOL_S);
}
}
if (ms->second.dirty) {
nlohmann::json network,member;
if (get(ns->first,network,ms->first,member)) {
nlohmann::json newrec,selector0,selector1,selectors;
nlohmann::json network, member;
if (get(ns->first, network, ms->first, member)) {
nlohmann::json newrec, selector0, selector1, selectors;
selector0["Name"] = networksSelectorName;
selector0["Ordinal"] = ns->first;
selector1["Name"] = "member";
@ -152,21 +161,25 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
newrec["MaskingKey"] = maskingKey;
newrec["PulseIfUnchanged"] = true;
try {
auto resp = htcli.Post("/makerecord",newrec.dump(),"application/json");
auto resp = htcli.Post("/makerecord", newrec.dump(), "application/json");
if (resp) {
if (resp->status == 200) {
ms->second.dirty = false;
//printf("SET member %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (create/update member): %s" ZT_EOL_S,resp->status,resp->body.c_str());
// printf("SET member %.16llx %.10llx %s\n",ns->first,ms->first,resp->body.c_str());
}
else {
fprintf(stderr, "ERROR: LFDB: %d from node (create/update member): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (create/update member): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (create/update member): unknown exception" ZT_EOL_S);
}
}
}
@ -176,143 +189,161 @@ LFDB::LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,cons
try {
std::ostringstream query;
query <<
"{"
"\"Ranges\":[{"
"\"Name\":\"" << networksSelectorName << "\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":[" << timeRangeStart << ",9223372036854775807],"
"\"MaskingKey\":\"" << maskingKey << "\","
"\"Owners\":[\"" << _lfOwnerPublic << "\"]"
"}";
auto resp = htcli.Post("/query",query.str(),"application/json");
query << "{"
"\"Ranges\":[{"
"\"Name\":\""
<< networksSelectorName
<< "\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":["
<< timeRangeStart
<< ",9223372036854775807],"
"\"MaskingKey\":\""
<< maskingKey
<< "\","
"\"Owners\":[\""
<< _lfOwnerPublic
<< "\"]"
"}";
auto resp = htcli.Post("/query", query.str(), "application/json");
if (resp) {
if (resp->status == 200) {
nlohmann::json results(OSUtils::jsonParse(resp->body));
if ((results.is_array())&&(!results.empty())) {
for(std::size_t ri=0;ri<results.size();++ri) {
nlohmann::json &rset = results[ri];
if ((rset.is_array())&&(!rset.empty())) {
nlohmann::json &result = rset[0];
if ((results.is_array()) && (! results.empty())) {
for (std::size_t ri = 0; ri < results.size(); ++ri) {
nlohmann::json& rset = results[ri];
if ((rset.is_array()) && (! rset.empty())) {
nlohmann::json& result = rset[0];
if (result.is_object()) {
nlohmann::json &record = result["Record"];
nlohmann::json& record = result["Record"];
if (record.is_object()) {
const std::string recordValue = result["Value"];
//printf("GET network %s\n",recordValue.c_str());
// printf("GET network %s\n",recordValue.c_str());
nlohmann::json network(OSUtils::jsonParse(recordValue));
if (network.is_object()) {
const std::string idstr = network["id"];
const uint64_t id = Utils::hexStrToU64(idstr.c_str());
if ((id >> 24) == controllerAddressInt) { // sanity check
if ((id >> 24) == controllerAddressInt) { // sanity check
nlohmann::json oldNetwork;
if ((timeRangeStart > 0)&&(get(id,oldNetwork))) {
if ((timeRangeStart > 0) && (get(id, oldNetwork))) {
const uint64_t revision = network["revision"];
const uint64_t prevRevision = oldNetwork["revision"];
if (prevRevision < revision) {
_networkChanged(oldNetwork,network,timeRangeStart > 0);
_networkChanged(oldNetwork, network, timeRangeStart > 0);
}
} else {
nlohmann::json nullJson;
_networkChanged(nullJson,network,timeRangeStart > 0);
}
else {
nlohmann::json nullJson;
_networkChanged(nullJson, network, timeRangeStart > 0);
}
}
}
}
}
}
}
}
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (check for network updates): %s" ZT_EOL_S,resp->status,resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: %d from node (check for network updates): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for network updates): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for network updates): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for network updates): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for network updates): unknown exception" ZT_EOL_S);
}
try {
std::ostringstream query;
query <<
"{"
"\"Ranges\":[{"
"\"Name\":\"" << networksSelectorName << "\","
"\"Range\":[0,18446744073709551615]"
"},{"
"\"Name\":\"member\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":[" << timeRangeStart << ",9223372036854775807],"
"\"MaskingKey\":\"" << maskingKey << "\","
"\"Owners\":[\"" << _lfOwnerPublic << "\"]"
"}";
auto resp = htcli.Post("/query",query.str(),"application/json");
query << "{"
"\"Ranges\":[{"
"\"Name\":\""
<< networksSelectorName
<< "\","
"\"Range\":[0,18446744073709551615]"
"},{"
"\"Name\":\"member\","
"\"Range\":[0,18446744073709551615]"
"}],"
"\"TimeRange\":["
<< timeRangeStart
<< ",9223372036854775807],"
"\"MaskingKey\":\""
<< maskingKey
<< "\","
"\"Owners\":[\""
<< _lfOwnerPublic
<< "\"]"
"}";
auto resp = htcli.Post("/query", query.str(), "application/json");
if (resp) {
if (resp->status == 200) {
nlohmann::json results(OSUtils::jsonParse(resp->body));
if ((results.is_array())&&(!results.empty())) {
for(std::size_t ri=0;ri<results.size();++ri) {
nlohmann::json &rset = results[ri];
if ((rset.is_array())&&(!rset.empty())) {
nlohmann::json &result = rset[0];
if ((results.is_array()) && (! results.empty())) {
for (std::size_t ri = 0; ri < results.size(); ++ri) {
nlohmann::json& rset = results[ri];
if ((rset.is_array()) && (! rset.empty())) {
nlohmann::json& result = rset[0];
if (result.is_object()) {
nlohmann::json &record = result["Record"];
nlohmann::json& record = result["Record"];
if (record.is_object()) {
const std::string recordValue = result["Value"];
//printf("GET member %s\n",recordValue.c_str());
// printf("GET member %s\n",recordValue.c_str());
nlohmann::json member(OSUtils::jsonParse(recordValue));
if (member.is_object()) {
const std::string nwidstr = member["nwid"];
const std::string idstr = member["id"];
const uint64_t nwid = Utils::hexStrToU64(nwidstr.c_str());
const uint64_t id = Utils::hexStrToU64(idstr.c_str());
if ((id)&&((nwid >> 24) == controllerAddressInt)) { // sanity check
if ((id) && ((nwid >> 24) == controllerAddressInt)) { // sanity check
nlohmann::json network,oldMember;
if ((timeRangeStart > 0)&&(get(nwid,network,id,oldMember))) {
nlohmann::json network, oldMember;
if ((timeRangeStart > 0) && (get(nwid, network, id, oldMember))) {
const uint64_t revision = member["revision"];
const uint64_t prevRevision = oldMember["revision"];
if (prevRevision < revision)
_memberChanged(oldMember,member,timeRangeStart > 0);
} else if (hasNetwork(nwid)) {
nlohmann::json nullJson;
_memberChanged(nullJson,member,timeRangeStart > 0);
_memberChanged(oldMember, member, timeRangeStart > 0);
}
else if (hasNetwork(nwid)) {
nlohmann::json nullJson;
_memberChanged(nullJson, member, timeRangeStart > 0);
}
}
}
}
}
}
}
}
} else {
fprintf(stderr,"ERROR: LFDB: %d from node (check for member updates): %s" ZT_EOL_S,resp->status,resp->body.c_str());
}
} else {
fprintf(stderr,"ERROR: LFDB: node is offline" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: %d from node (check for member updates): %s" ZT_EOL_S, resp->status, resp->body.c_str());
}
}
} catch (std::exception &e) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for member updates): %s" ZT_EOL_S,e.what());
} catch ( ... ) {
fprintf(stderr,"ERROR: LFDB: unexpected exception querying node (check for member updates): unknown exception" ZT_EOL_S);
else {
fprintf(stderr, "ERROR: LFDB: node is offline" ZT_EOL_S);
}
}
catch (std::exception& e) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for member updates): %s" ZT_EOL_S, e.what());
}
catch (...) {
fprintf(stderr, "ERROR: LFDB: unexpected exception querying node (check for member updates): unknown exception" ZT_EOL_S);
}
timeRangeStart = time(nullptr) - 120; // start next query 2m before now to avoid losing updates
timeRangeStart = time(nullptr) - 120; // start next query 2m before now to avoid losing updates
_ready.store(true);
for(int k=0;k<4;++k) { // 2s delay between queries for remotely modified networks or members
if (!_running.load())
for (int k = 0; k < 4; ++k) { // 2s delay between queries for remotely modified networks or members
if (! _running.load())
return;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
@ -328,7 +359,7 @@ LFDB::~LFDB()
bool LFDB::waitForReady()
{
while (!_ready.load()) {
while (! _ready.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return true;
@ -339,18 +370,18 @@ bool LFDB::isReady()
return (_ready.load());
}
bool LFDB::save(nlohmann::json &record,bool notifyListeners)
bool LFDB::save(nlohmann::json& record, bool notifyListeners)
{
bool modified = false;
const std::string objtype = record["objtype"];
if (objtype == "network") {
const uint64_t nwid = OSUtils::jsonIntHex(record["id"],0ULL);
const uint64_t nwid = OSUtils::jsonIntHex(record["id"], 0ULL);
if (nwid) {
nlohmann::json old;
get(nwid,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
_networkChanged(old,record,notifyListeners);
get(nwid, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
_networkChanged(old, record, notifyListeners);
{
std::lock_guard<std::mutex> l(_state_l);
_state[nwid].dirty = true;
@ -358,15 +389,16 @@ bool LFDB::save(nlohmann::json &record,bool notifyListeners)
modified = true;
}
}
} else if (objtype == "member") {
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"],0ULL);
const uint64_t id = OSUtils::jsonIntHex(record["id"],0ULL);
if ((id)&&(nwid)) {
nlohmann::json network,old;
get(nwid,network,id,old);
if ((!old.is_object())||(!_compareRecords(old,record))) {
record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
_memberChanged(old,record,notifyListeners);
}
else if (objtype == "member") {
const uint64_t nwid = OSUtils::jsonIntHex(record["nwid"], 0ULL);
const uint64_t id = OSUtils::jsonIntHex(record["id"], 0ULL);
if ((id) && (nwid)) {
nlohmann::json network, old;
get(nwid, network, id, old);
if ((! old.is_object()) || (! _compareRecords(old, record))) {
record["revision"] = OSUtils::jsonInt(record["revision"], 0ULL) + 1ULL;
_memberChanged(old, record, notifyListeners);
{
std::lock_guard<std::mutex> l(_state_l);
_state[nwid].members[id].dirty = true;
@ -383,12 +415,12 @@ void LFDB::eraseNetwork(const uint64_t networkId)
// TODO
}
void LFDB::eraseMember(const uint64_t networkId,const uint64_t memberId)
void LFDB::eraseMember(const uint64_t networkId, const uint64_t memberId)
{
// TODO
}
void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
void LFDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch)
{
std::lock_guard<std::mutex> l(_state_l);
auto nw = _state.find(networkId);
@ -403,4 +435,9 @@ void LFDB::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const I
}
}
} // namespace ZeroTier
void LFDB::nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress)
{
this->nodeIsOnline(networkId, memberId, physicalAddress, "unknown/unknown");
}
} // namespace ZeroTier

View file

@ -16,19 +16,18 @@
#include "DB.hpp"
#include <atomic>
#include <mutex>
#include <string>
#include <unordered_map>
#include <atomic>
namespace ZeroTier {
/**
* DB implementation for controller that stores data in LF
*/
class LFDB : public DB
{
public:
class LFDB : public DB {
public:
/**
* @param myId This controller's identity
* @param path Base path for ZeroTier node itself
@ -38,44 +37,41 @@ public:
* @param lfNodePort LF node http (not https) port
* @param storeOnlineState If true, store online/offline state and IP info in LF (a lot of data, only for private networks!)
*/
LFDB(const Identity &myId,const char *path,const char *lfOwnerPrivate,const char *lfOwnerPublic,const char *lfNodeHost,int lfNodePort,bool storeOnlineState);
LFDB(const Identity& myId, const char* path, const char* lfOwnerPrivate, const char* lfOwnerPublic, const char* lfNodeHost, int lfNodePort, bool storeOnlineState);
virtual ~LFDB();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json &record,bool notifyListeners);
virtual bool save(nlohmann::json& record, bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId,const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress& physicalAddress, const char* osArch);
protected:
protected:
const Identity _myId;
std::string _lfOwnerPrivate,_lfOwnerPublic;
std::string _lfOwnerPrivate, _lfOwnerPublic;
std::string _lfNodeHost;
int _lfNodePort;
struct _MemberState
{
_MemberState() :
lastOnlineAddress(),
lastOnlineTime(0),
dirty(false),
lastOnlineDirty(false) {}
struct _MemberState {
_MemberState() : lastOnlineAddress(), lastOnlineTime(0), dirty(false), lastOnlineDirty(false)
{
}
InetAddress lastOnlineAddress;
int64_t lastOnlineTime;
bool dirty;
bool lastOnlineDirty;
};
struct _NetworkState
{
_NetworkState() :
members(),
dirty(false) {}
std::unordered_map<uint64_t,_MemberState> members;
struct _NetworkState {
_NetworkState() : members(), dirty(false)
{
}
std::unordered_map<uint64_t, _MemberState> members;
bool dirty;
};
std::unordered_map<uint64_t,_NetworkState> _state;
std::unordered_map<uint64_t, _NetworkState> _state;
std::mutex _state_l;
std::atomic_bool _running;
@ -84,6 +80,6 @@ protected:
bool _storeOnlineState;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*
* Copyright (c)2019 ZeroTier, Inc.
* Copyright (c)2025 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.
@ -11,186 +11,87 @@
*/
/****/
#include "DB.hpp"
#ifdef ZT_CONTROLLER_USE_LIBPQ
#ifndef ZT_CONTROLLER_LIBPQ_HPP
#define ZT_CONTROLLER_LIBPQ_HPP
#define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4
#ifndef ZT_CONTROLLER_POSTGRESQL_HPP
#define ZT_CONTROLLER_POSTGRESQL_HPP
#include "ConnectionPool.hpp"
#include <pqxx/pqxx>
#include "DB.hpp"
#include <memory>
#include <redis++/redis++.h>
#include <pqxx/pqxx>
#include "../node/Metrics.hpp"
namespace ZeroTier {
extern "C" {
typedef struct pg_conn PGconn;
}
namespace smeeclient {
struct SmeeClient;
}
namespace ZeroTier {
struct RedisConfig;
class PostgresConnection : public Connection {
public:
virtual ~PostgresConnection() {
public:
virtual ~PostgresConnection()
{
}
std::shared_ptr<pqxx::connection> c;
int a;
};
class PostgresConnFactory : public ConnectionFactory {
public:
PostgresConnFactory(std::string &connString)
: m_connString(connString)
public:
PostgresConnFactory(std::string& connString) : m_connString(connString)
{
}
virtual std::shared_ptr<Connection> create() {
virtual std::shared_ptr<Connection> create()
{
Metrics::conn_counter++;
auto c = std::shared_ptr<PostgresConnection>(new PostgresConnection());
c->c = std::make_shared<pqxx::connection>(m_connString);
return std::static_pointer_cast<Connection>(c);
}
private:
private:
std::string m_connString;
};
class PostgreSQL;
class MemberNotificationReceiver : public pqxx::notification_receiver {
public:
MemberNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel);
virtual ~MemberNotificationReceiver() {
public:
MemberNotificationReceiver(DB* p, pqxx::connection& c, const std::string& channel);
virtual ~MemberNotificationReceiver()
{
fprintf(stderr, "MemberNotificationReceiver destroyed\n");
}
virtual void operator() (const std::string &payload, int backendPid);
private:
PostgreSQL *_psql;
virtual void operator()(const std::string& payload, int backendPid);
private:
DB* _psql;
};
class NetworkNotificationReceiver : public pqxx::notification_receiver {
public:
NetworkNotificationReceiver(PostgreSQL *p, pqxx::connection &c, const std::string &channel);
virtual ~NetworkNotificationReceiver() {
public:
NetworkNotificationReceiver(DB* p, pqxx::connection& c, const std::string& channel);
virtual ~NetworkNotificationReceiver()
{
fprintf(stderr, "NetworkNotificationReceiver destroyed\n");
};
virtual void operator() (const std::string &payload, int packend_pid);
private:
PostgreSQL *_psql;
virtual void operator()(const std::string& payload, int packend_pid);
private:
DB* _psql;
};
/**
* A controller database driver that talks to PostgreSQL
*
* This is for use with ZeroTier Central. Others are free to build and use it
* but be aware that we might change it at any time.
*/
class PostgreSQL : public DB
{
friend class MemberNotificationReceiver;
friend class NetworkNotificationReceiver;
public:
PostgreSQL(const Identity &myId, const char *path, int listenPort, RedisConfig *rc);
virtual ~PostgreSQL();
virtual bool waitForReady();
virtual bool isReady();
virtual bool save(nlohmann::json &record,bool notifyListeners);
virtual void eraseNetwork(const uint64_t networkId);
virtual void eraseMember(const uint64_t networkId, const uint64_t memberId);
virtual void nodeIsOnline(const uint64_t networkId, const uint64_t memberId, const InetAddress &physicalAddress);
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
protected:
struct _PairHasher
{
inline std::size_t operator()(const std::pair<uint64_t,uint64_t> &p) const { return (std::size_t)(p.first ^ p.second); }
};
virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) {
DB::_memberChanged(old, memberConfig, notifyListeners);
}
virtual void _networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners) {
DB::_networkChanged(old, networkConfig, notifyListeners);
}
private:
void initializeNetworks();
void initializeMembers();
void heartbeat();
void membersDbWatcher();
void _membersWatcher_Postgres();
void networksDbWatcher();
void _networksWatcher_Postgres();
void _membersWatcher_Redis();
void _networksWatcher_Redis();
void commitThread();
void onlineNotificationThread();
void onlineNotification_Postgres();
void onlineNotification_Redis();
uint64_t _doRedisUpdate(sw::redis::Transaction &tx, std::string &controllerId,
std::unordered_map< std::pair<uint64_t,uint64_t>,std::pair<int64_t,InetAddress>,_PairHasher > &lastOnline);
void configureSmee();
void notifyNewMember(const std::string &networkID, const std::string &memberID);
enum OverrideMode {
ALLOW_PGBOUNCER_OVERRIDE = 0,
NO_OVERRIDE = 1
};
std::shared_ptr<ConnectionPool<PostgresConnection> > _pool;
const Identity _myId;
const Address _myAddress;
std::string _myAddressStr;
std::string _connString;
BlockingQueue< std::pair<nlohmann::json,bool> > _commitQueue;
std::thread _heartbeatThread;
std::thread _membersDbWatcher;
std::thread _networksDbWatcher;
std::thread _commitThread[ZT_CENTRAL_CONTROLLER_COMMIT_THREADS];
std::thread _onlineNotificationThread;
std::unordered_map< std::pair<uint64_t,uint64_t>,std::pair<int64_t,InetAddress>,_PairHasher > _lastOnline;
mutable std::mutex _lastOnline_l;
mutable std::mutex _readyLock;
std::atomic<int> _ready, _connected, _run;
mutable volatile bool _waitNoticePrinted;
int _listenPort;
uint8_t _ssoPsk[48];
RedisConfig *_rc;
std::shared_ptr<sw::redis::Redis> _redis;
std::shared_ptr<sw::redis::RedisCluster> _cluster;
bool _redisMemberStatus;
smeeclient::SmeeClient *_smee;
struct NodeOnlineRecord {
uint64_t lastSeen;
InetAddress physicalAddress;
std::string osArch;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_CONTROLLER_LIBPQ_HPP
#endif // ZT_CONTROLLER_POSTGRESQL_HPP
#endif // ZT_CONTROLLER_USE_LIBPQ
#endif // ZT_CONTROLLER_USE_LIBPQ

View file

@ -5,11 +5,11 @@
namespace ZeroTier {
struct RedisConfig {
std::string hostname;
int port;
std::string password;
bool clusterMode;
std::string hostname;
int port;
std::string password;
bool clusterMode;
};
}
} // namespace ZeroTier
#endif

View file

@ -9,15 +9,16 @@ mkztfile() {
file=$1
mode=$2
content=$3
echo "creating $file"
mkdir -p /var/lib/zerotier-one
echo "$content" > "/var/lib/zerotier-one/$file"
echo -n "$content" > "/var/lib/zerotier-one/$file"
chmod "$mode" "/var/lib/zerotier-one/$file"
}
if [ "x$ZEROTIER_API_SECRET" != "x" ]
then
mkztfile authtoken.secret 0600 "$ZEROTIER_API_SECRET"
mkztfile metricstoken.secret 0600 "$ZEROTIER_API_SECRET"
fi
if [ "x$ZEROTIER_IDENTITY_PUBLIC" != "x" ]
@ -30,6 +31,11 @@ then
mkztfile identity.secret 0600 "$ZEROTIER_IDENTITY_SECRET"
fi
if [ "x$ZEROTIER_LOCAL_CONF" != "x" ]
then
mkztfile local.conf 0644 "$ZEROTIER_LOCAL_CONF"
fi
mkztfile zerotier-one.port 0600 "9993"
killzerotier() {

View file

@ -1,11 +1,16 @@
# Dockerfile for ZeroTier Central Controllers
FROM registry.zerotier.com/zerotier/ctlbuild:latest as builder
MAINTAINER Adam Ierymekno <adam.ierymenko@zerotier.com>, Grant Limberg <grant.limberg@zerotier.com>
FROM registry.zerotier.com/zerotier/ctlbuild:2025-05-13-01 AS builder
ADD . /ZeroTierOne
RUN export PATH=$PATH:~/.cargo/bin && cd ZeroTierOne && make clean && make central-controller -j8
FROM registry.zerotier.com/zerotier/ctlrun:latest
FROM golang:bookworm AS go_base
RUN go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
FROM registry.zerotier.com/zerotier/ctlrun:2025-05-13-01
COPY --from=builder /ZeroTierOne/zerotier-one /usr/local/bin/zerotier-one
COPY --from=go_base /go/bin/migrate /usr/local/bin/migrate
COPY ext/central-controller-docker/migrations /migrations
RUN chmod a+x /usr/local/bin/zerotier-one
RUN echo "/usr/local/lib64" > /etc/ld.so.conf.d/usr-local-lib64.conf && ldconfig

View file

@ -1,8 +1,5 @@
# Dockerfile for building ZeroTier Central Controllers
FROM ubuntu:jammy as builder
MAINTAINER Adam Ierymekno <adam.ierymenko@zerotier.com>, Grant Limberg <grant.limberg@zerotier.com>
ARG git_branch=master
FROM debian:bookworm
RUN apt update && apt upgrade -y
RUN apt -y install \

View file

@ -1,15 +1,17 @@
FROM ubuntu:jammy
FROM debian:bookworm
RUN apt update && apt upgrade -y
RUN apt -y install \
netcat \
netcat-traditional \
postgresql-client \
postgresql-client-common \
libjemalloc2 \
libpq5 \
curl \
binutils \
linux-tools-gke \
perf-tools-unstable \
google-perftools
google-perftools \
gnupg

View file

@ -1,9 +1,5 @@
#!/bin/bash
if [ -z "$ZT_IDENTITY_PATH" ]; then
echo '*** FAILED: ZT_IDENTITY_PATH environment variable is not defined'
exit 1
fi
if [ -z "$ZT_DB_HOST" ]; then
echo '*** FAILED: ZT_DB_HOST environment variable not defined'
exit 1
@ -24,6 +20,9 @@ if [ -z "$ZT_DB_PASSWORD" ]; then
echo '*** FAILED: ZT_DB_PASSWORD environment variable not defined'
exit 1
fi
if [ -z "$ZT_DB_TYPE" ]; then
ZT_DB_TYPE="postgres"
fi
REDIS=""
if [ "$ZT_USE_REDIS" == "true" ]; then
@ -56,10 +55,14 @@ fi
mkdir -p /var/lib/zerotier-one
pushd /var/lib/zerotier-one
ln -s $ZT_IDENTITY_PATH/identity.public identity.public
ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret
if [ -f "$ZT_IDENTITY_PATH/authtoken.secret" ]; then
ln -s $ZT_IDENTITY_PATH/authtoken.secret authtoken.secret
if [ -d "$ZT_IDENTITY_PATH" ]; then
echo '*** Using existing ZT identity from path $ZT_IDENTITY_PATH'
ln -s $ZT_IDENTITY_PATH/identity.public identity.public
ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret
if [ -f "$ZT_IDENTITY_PATH/authtoken.secret" ]; then
ln -s $ZT_IDENTITY_PATH/authtoken.secret authtoken.secret
fi
fi
popd
@ -70,7 +73,7 @@ APP_NAME="controller-$(cat /var/lib/zerotier-one/identity.public | cut -d ':' -f
echo "{
\"settings\": {
\"controllerDbPath\": \"postgres:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} application_name=${APP_NAME} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\",
\"controllerDbPath\": \"${ZT_DB_TYPE}:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} application_name=${APP_NAME} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\",
\"portMappingEnabled\": true,
\"softwareUpdate\": \"disable\",
\"interfacePrefixBlacklist\": [
@ -100,6 +103,15 @@ else
done
fi
if [ "$ZT_DB_TYPE" == "cv2" ]; then
echo "Migrating database (if needed)..."
if [ -n "$DB_SERVER_CA" ]; then
/usr/local/bin/migrate -source file:///migrations -database "postgres://$ZT_DB_USER:$ZT_DB_PASSWORD@$ZT_DB_HOST:$ZT_DB_PORT/$ZT_DB_NAME?x-migrations-table=controller_migrations&sslmode=verify-full&sslrootcert=$DB_SERVER_CA&sslcert=$DB_CLIENT_CERT&sslkey=$DB_CLIENT_KEY" up
else
/usr/local/bin/migrate -source file:///migrations -database "postgres://$ZT_DB_USER:$ZT_DB_PASSWORD@$ZT_DB_HOST:$ZT_DB_PORT/$ZT_DB_NAME?x-migrations-table=controller_migrations&sslmode=disable" up
fi
fi
if [ -n "$ZT_TEMPORAL_HOST" ] && [ -n "$ZT_TEMPORAL_PORT" ]; then
echo "waiting for temporal..."
while ! nc -z ${ZT_TEMPORAL_HOST} ${ZT_TEMPORAL_PORT}; do

View file

@ -0,0 +1,3 @@
DROP TABLE IF EXISTS network_memberships_ctl;
DROP TABLE IF EXISTS networks_ctl;
DROP TABLE IF EXISTS controllers_ctl;

View file

@ -0,0 +1,47 @@
-- inits controller db schema
CREATE TABLE IF NOT EXISTS controllers_ctl (
id text NOT NULL PRIMARY KEY,
hostname text,
last_heartbeat timestamp with time zone,
public_identity text NOT NULL,
version text
);
CREATE TABLE IF NOT EXISTS networks_ctl (
id character varying(22) NOT NULL PRIMARY KEY,
name text NOT NULL,
configuration jsonb DEFAULT '{}'::jsonb NOT NULL,
controller_id text REFERENCES controllers_ctl(id),
revision integer DEFAULT 0 NOT NULL,
last_modified timestamp with time zone DEFAULT now(),
creation_time timestamp with time zone DEFAULT now()
);
CREATE TABLE IF NOT EXISTS network_memberships_ctl (
device_id character varying(22) NOT NULL,
network_id character varying(22) NOT NULL REFERENCES networks_ctl(id),
authorized boolean,
active_bridge boolean,
ip_assignments text[],
no_auto_assign_ips boolean,
sso_exempt boolean,
authentication_expiry_time timestamp with time zone,
capabilities jsonb,
creation_time timestamp with time zone DEFAULT now(),
last_modified timestamp with time zone DEFAULT now(),
identity text DEFAULT ''::text,
last_authorized_credential text,
last_authorized_time timestamp with time zone,
last_deauthorized_time timestamp with time zone,
last_seen jsonb DEFAULT '{}'::jsonb NOT NULL, -- in the context of the network
remote_trace_level integer DEFAULT 0 NOT NULL,
remote_trace_target text DEFAULT ''::text NOT NULL,
revision integer DEFAULT 0 NOT NULL,
tags jsonb,
version_major integer DEFAULT 0 NOT NULL,
version_minor integer DEFAULT 0 NOT NULL,
version_revision integer DEFAULT 0 NOT NULL,
version_protocol integer DEFAULT 0 NOT NULL,
PRIMARY KEY (device_id, network_id)
);

View file

@ -0,0 +1,3 @@
ALTER TABLE network_memberships_ctl
DROP COLUMN os,
DROP COLUMN arch;

View file

@ -0,0 +1,3 @@
ALTER TABLE network_memberships_ctl
ADD COLUMN os TEXT NOT NULL DEFAULT 'unknown',
ADD COLUMN arch TEXT NOT NULL DEFAULT 'unknown';

View file

@ -84,7 +84,7 @@ extern "C" {
/**
* Minimum UDP payload size allowed
*/
#define ZT_MIN_PHYSMTU 1400
#define ZT_MIN_PHYSMTU 510
/**
* Maximum physical interface name length. This number is gigantic because of Windows.

View file

@ -431,6 +431,10 @@ central-controller-docker: _buildx FORCE
docker buildx build --platform linux/amd64,linux/arm64 --no-cache -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . --push
@echo Image: registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP}
centralv2-controller-docker: _buildx FORCE
docker buildx build --platform linux/amd64,linux/arm64 --no-cache -t us-central1-docker.pkg.dev/zerotier-421eb9/docker-images/ztcentral-controller:$(shell git rev-parse --short HEAD) -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . --push
@echo Image: us-central1-docker.pkg.dev/zerotier-421eb9/docker-images/ztcentral-controller:$(shell git rev-parse --short HEAD)
debug: FORCE
make ZT_DEBUG=1 one
make ZT_DEBUG=1 selftest

View file

@ -57,9 +57,9 @@ ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connec
ifeq ($(ZT_CONTROLLER),1)
MACOS_VERSION_MIN=10.15
override CXXFLAGS=$(CFLAGS) -std=c++17 -stdlib=libc++
LIBS+=-L/usr/local/opt/libpqxx/lib -L/usr/local/opt/libpq/lib -L/usr/local/opt/openssl/lib/ -lpqxx -lpq -lssl -lcrypto -lgssapi_krb5 ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a
LIBS+=-L/opt/homebrew/lib -L/usr/local/opt/libpqxx/lib -L/usr/local/opt/libpq/lib -L/usr/local/opt/openssl/lib/ -lpqxx -lpq -lssl -lcrypto -lgssapi_krb5 ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a rustybits/target/libsmeeclient.a
DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER_USE_REDIS -DZT_CONTROLLER
INCLUDES+=-I/usr/local/opt/libpq/include -I/usr/local/opt/libpqxx/include -Iext/hiredis-0.14.1/include/ -Iext/redis-plus-plus-1.1.1/install/macos/include/sw/
INCLUDES+=-I/opt/homebrew/include -I/opt/homebrew/opt/libpq/include -I/usr/local/opt/libpq/include -I/usr/local/opt/libpqxx/include -Iext/hiredis-0.14.1/include/ -Iext/redis-plus-plus-1.1.1/install/macos/include/sw/ -Irustybits/target/
else
MACOS_VERSION_MIN=10.13
endif
@ -115,7 +115,11 @@ mac-agent: FORCE
osdep/MacDNSHelper.o: osdep/MacDNSHelper.mm
$(CXX) $(CXXFLAGS) -c osdep/MacDNSHelper.mm -o osdep/MacDNSHelper.o
ifeq ($(ZT_CONTROLLER),1)
one: zeroidc smeeclient $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent
else
one: zeroidc $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent
endif
$(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) rustybits/target/libzeroidc.a
# $(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool
@ -126,6 +130,15 @@ zerotier-one: one
zeroidc: rustybits/target/libzeroidc.a
ifeq ($(ZT_CONTROLLER),1)
smeeclient: rustybits/target/libsmeeclient.a
rustybits/target/libsmeeclient.a: FORCE
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p smeeclient --target=x86_64-apple-darwin $(EXTRA_CARGO_FLAGS)
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p smeeclient --target=aarch64-apple-darwin $(EXTRA_CARGO_FLAGS)
cd rustybits && lipo -create target/x86_64-apple-darwin/$(RUST_VARIANT)/libsmeeclient.a target/aarch64-apple-darwin/$(RUST_VARIANT)/libsmeeclient.a -output target/libsmeeclient.a
endif
rustybits/target/libzeroidc.a: FORCE
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p zeroidc --target=x86_64-apple-darwin $(EXTRA_CARGO_FLAGS)
cd rustybits && MACOSX_DEPLOYMENT_TARGET=$(MACOS_VERSION_MIN) cargo build -p zeroidc --target=aarch64-apple-darwin $(EXTRA_CARGO_FLAGS)
@ -195,6 +208,10 @@ central-controller-docker: _buildx FORCE
docker buildx build --platform linux/arm64,linux/amd64 --no-cache -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=$(shell git name-rev --name-only HEAD) . --push
@echo Image: registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP}
centralv2-controller-docker: _buildx FORCE
docker buildx build --platform linux/amd64,linux/arm64 --no-cache -t us-central1-docker.pkg.dev/zerotier-d648c7/central-v2/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . --push
@echo Image: us-central1-docker.pkg.dev/zerotier-d648c7/central-v2/ztcentral-controller:${TIMESTAMP}
docker-release: _buildx
docker buildx build --platform linux/386,linux/amd64,linux/arm/v7,linux/arm64,linux/mips64le,linux/ppc64le,linux/s390x -t zerotier/zerotier:${RELEASE_DOCKER_TAG} -t zerotier/zerotier:latest --build-arg VERSION=${RELEASE_VERSION} -f Dockerfile.release . --push

View file

@ -11,9 +11,10 @@
*/
/****/
#include "Constants.hpp"
#include "AES.hpp"
#include "Constants.hpp"
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
@ -31,40 +32,40 @@ namespace ZeroTier {
namespace {
#define s_bmul32(N, x, y, rh, rl) \
uint32_t x0t_##N = (x) & 0x11111111U; \
uint32_t x1t_##N = (x) & 0x22222222U; \
uint32_t x2t_##N = (x) & 0x44444444U; \
uint32_t x3t_##N = (x) & 0x88888888U; \
uint32_t y0t_##N = (y) & 0x11111111U; \
uint32_t y1t_##N = (y) & 0x22222222U; \
uint32_t y2t_##N = (y) & 0x44444444U; \
uint32_t y3t_##N = (y) & 0x88888888U; \
uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \
uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \
uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \
z0t_##N |= z1t_##N; \
z2t_##N |= z0t_##N; \
uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \
(rh) = (uint32_t)(zt_##N >> 32U); \
#define s_bmul32(N, x, y, rh, rl) \
uint32_t x0t_##N = (x) & 0x11111111U; \
uint32_t x1t_##N = (x) & 0x22222222U; \
uint32_t x2t_##N = (x) & 0x44444444U; \
uint32_t x3t_##N = (x) & 0x88888888U; \
uint32_t y0t_##N = (y) & 0x11111111U; \
uint32_t y1t_##N = (y) & 0x22222222U; \
uint32_t y2t_##N = (y) & 0x44444444U; \
uint32_t y3t_##N = (y) & 0x88888888U; \
uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \
uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \
uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \
z0t_##N |= z1t_##N; \
z2t_##N |= z0t_##N; \
uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \
(rh) = (uint32_t)(zt_##N >> 32U); \
(rl) = (uint32_t)zt_##N;
void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) noexcept
void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t& y0, uint64_t& y1) noexcept
{
uint32_t hhh = (uint32_t)(hh >> 32U);
uint32_t hhl = (uint32_t)hh;
uint32_t hlh = (uint32_t)(hl >> 32U);
uint32_t hll = (uint32_t)hl;
uint32_t hhXlh = hhh ^hlh;
uint32_t hhXll = hhl ^hll;
uint32_t hhXlh = hhh ^ hlh;
uint32_t hhXll = hhl ^ hll;
uint64_t yl = Utils::ntoh(y0);
uint64_t yh = Utils::ntoh(y1);
uint32_t cilh = (uint32_t)(yh >> 32U);
uint32_t cill = (uint32_t)yh;
uint32_t cihh = (uint32_t)(yl >> 32U);
uint32_t cihl = (uint32_t)yl;
uint32_t cihXlh = cihh ^cilh;
uint32_t cihXll = cihl ^cill;
uint32_t cihXlh = cihh ^ cilh;
uint32_t cihXll = cihl ^ cill;
uint32_t aah, aal, abh, abl, ach, acl;
s_bmul32(M0, cihh, hhh, aah, aal);
s_bmul32(M1, cihl, hhl, abh, abl);
@ -94,8 +95,8 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
cbh ^= bbh ^ abh;
cbl ^= bbl ^ abl;
uint64_t zhh = ((uint64_t)aah << 32U) | aal;
uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^(((uint64_t)cah << 32U) | cal);
uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^(((uint64_t)cbh << 32U) | cbl);
uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^ (((uint64_t)cah << 32U) | cal);
uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^ (((uint64_t)cbh << 32U) | cbl);
uint64_t zll = ((uint64_t)bbh << 32U) | bbl;
zhh = zhh << 1U | zhl >> 63U;
zhl = zhl << 1U | zlh >> 63U;
@ -108,11 +109,11 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
y1 = Utils::hton(zhl);
}
} // anonymous namespace
} // anonymous namespace
void AES::GMAC::update(const void *const data, unsigned int len) noexcept
void AES::GMAC::update(const void* const data, unsigned int len) noexcept
{
const uint8_t *in = reinterpret_cast<const uint8_t *>(data);
const uint8_t* in = reinterpret_cast<const uint8_t*>(data);
_len += len;
#ifdef ZT_AES_AESNI
@ -120,14 +121,14 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
p_aesNIUpdate(in, len);
return;
}
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.pmull) {
p_armUpdate(in, len);
return;
}
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON
const uint64_t h0 = _aes.p_k.sw.h[0];
const uint64_t h1 = _aes.p_k.sw.h[1];
@ -136,14 +137,14 @@ 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) {
y0 ^= Utils::loadMachineEndian< uint64_t >(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8);
y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1);
break;
}
@ -151,8 +152,8 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
}
while (len >= 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(in);
y1 ^= Utils::loadMachineEndian< uint64_t >(in + 8);
y0 ^= Utils::loadMachineEndian<uint64_t>(in);
y1 ^= Utils::loadMachineEndian<uint64_t>(in + 8);
in += 16;
s_gfmul(h0, h1, y0, y1);
len -= 16;
@ -164,7 +165,7 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
_rp = len; // len is always less than 16 here
}
void AES::GMAC::finish(uint8_t tag[16]) noexcept
@ -174,14 +175,14 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
p_aesNIFinish(tag);
return;
}
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.pmull) {
p_armFinish(tag);
return;
}
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON
const uint64_t h0 = _aes.p_k.sw.h[0];
const uint64_t h1 = _aes.p_k.sw.h[1];
@ -192,8 +193,8 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
while (_rp < 16) {
_r[_rp++] = 0;
}
y0 ^= Utils::loadMachineEndian< uint64_t >(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8);
y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1);
}
@ -201,57 +202,57 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
s_gfmul(h0, h1, y0, y1);
uint64_t iv2[2];
Utils::copy< 12 >(iv2, _iv);
Utils::copy<12>(iv2, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(iv2)[3] = 0x00000001;
reinterpret_cast<uint32_t*>(iv2)[3] = 0x00000001;
#else
reinterpret_cast<uint32_t *>(iv2)[3] = 0x01000000;
reinterpret_cast<uint32_t*>(iv2)[3] = 0x01000000;
#endif
_aes.encrypt(iv2, iv2);
Utils::storeMachineEndian< uint64_t >(tag, iv2[0] ^ y0);
Utils::storeMachineEndian< uint64_t >(tag + 8, iv2[1] ^ y1);
Utils::storeMachineEndian<uint64_t>(tag, iv2[0] ^ y0);
Utils::storeMachineEndian<uint64_t>(tag + 8, iv2[1] ^ y1);
}
// AES-CTR ------------------------------------------------------------------------------------------------------------
void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
void AES::CTR::crypt(const void* const input, unsigned int len) noexcept
{
const uint8_t *in = reinterpret_cast<const uint8_t *>(input);
uint8_t *out = _out;
const uint8_t* in = reinterpret_cast<const uint8_t*>(input);
uint8_t* out = _out;
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
p_aesNICrypt(in, out, len);
return;
}
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.aes) {
p_armCrypt(in, out, len);
return;
}
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON
uint64_t keyStream[2];
uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t *>(_ctr)[3]);
uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t*>(_ctr)[3]);
unsigned int totalLen = _len;
if ((totalLen & 15U)) {
for (;;) {
if (!len) {
if (! len) {
_len = (totalLen + len);
return;
}
--len;
out[totalLen++] = *(in++);
if (!(totalLen & 15U)) {
_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);
if (! (totalLen & 15U)) {
_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) {
outblk[i] ^= reinterpret_cast<uint8_t *>(keyStream)[i];
outblk[i] ^= reinterpret_cast<uint8_t*>(keyStream)[i];
}
break;
}
@ -262,10 +263,10 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
_len = (totalLen + len);
if (likely(len >= 16)) {
const uint32_t *const restrict rk = _aes.p_k.sw.ek;
const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[0]) ^rk[0];
const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[1]) ^rk[1];
const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[2]) ^rk[2];
const uint32_t* const restrict rk = _aes.p_k.sw.ek;
const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[0]) ^ rk[0];
const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[1]) ^ rk[1];
const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[2]) ^ rk[2];
const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000;
@ -278,8 +279,8 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = ctr2rk2;
s3 = ctr++ ^ rk[3];
const uint64_t in0 = *reinterpret_cast<const uint64_t *>(in);
const uint64_t in1 = *reinterpret_cast<const uint64_t *>(in + 8);
const uint64_t in0 = *reinterpret_cast<const uint64_t*>(in);
const uint64_t in1 = *reinterpret_cast<const uint64_t*>(in + 8);
in += 16;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -339,11 +340,12 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59];
*reinterpret_cast<uint64_t *>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1);
*reinterpret_cast<uint64_t *>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3);
*reinterpret_cast<uint64_t*>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1);
*reinterpret_cast<uint64_t*>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3);
out += 16;
} while ((len -= 16) >= 16);
} else {
}
else {
do {
uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
s0 = ctr0rk0;
@ -428,7 +430,7 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
in += 16;
} while ((len -= 16) >= 16);
}
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(ctr);
reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(ctr);
}
// Any remaining input is placed in _out. This will be picked up and crypted
@ -454,48 +456,76 @@ void AES::CTR::finish() noexcept
// Software AES and AES key expansion ---------------------------------------------------------------------------------
const uint32_t AES::Te0[256] = {0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153,
0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba,
0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437,
0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878,
0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a};
const uint32_t AES::Te4[256] = {0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131,
0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575,
0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f,
0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2,
0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4,
0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808,
0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828,
0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616};
const uint32_t AES::Td0[256] = {0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c,
0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1,
0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e,
0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14,
0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742};
const uint8_t AES::Td4[256] = {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d,
0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c,
0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};
const uint32_t AES::rcon[15] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000};
const uint32_t AES::Te0[256] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a,
0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b,
0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f,
0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497,
0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3,
0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d,
0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76,
0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b,
0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85,
0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9,
0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a };
const uint32_t AES::Te4[256] = { 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676,
0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0,
0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515,
0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575,
0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484,
0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf,
0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8,
0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2,
0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373,
0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb,
0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979,
0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808,
0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a,
0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e,
0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf,
0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616 };
const uint32_t AES::Td0[256] = { 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f,
0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844,
0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94,
0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051,
0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb,
0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a,
0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef,
0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5,
0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f,
0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713,
0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86,
0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 };
const uint8_t AES::Td4[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
const uint32_t AES::rcon[15] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000 };
void AES::p_initSW(const uint8_t *key) noexcept
void AES::p_initSW(const uint8_t* key) noexcept
{
uint32_t *rk = p_k.sw.ek;
uint32_t* rk = p_k.sw.ek;
rk[0] = Utils::loadBigEndian< uint32_t >(key);
rk[1] = Utils::loadBigEndian< uint32_t >(key + 4);
rk[2] = Utils::loadBigEndian< uint32_t >(key + 8);
rk[3] = Utils::loadBigEndian< uint32_t >(key + 12);
rk[4] = Utils::loadBigEndian< uint32_t >(key + 16);
rk[5] = Utils::loadBigEndian< uint32_t >(key + 20);
rk[6] = Utils::loadBigEndian< uint32_t >(key + 24);
rk[7] = Utils::loadBigEndian< uint32_t >(key + 28);
rk[0] = Utils::loadBigEndian<uint32_t>(key);
rk[1] = Utils::loadBigEndian<uint32_t>(key + 4);
rk[2] = Utils::loadBigEndian<uint32_t>(key + 8);
rk[3] = Utils::loadBigEndian<uint32_t>(key + 12);
rk[4] = Utils::loadBigEndian<uint32_t>(key + 16);
rk[5] = Utils::loadBigEndian<uint32_t>(key + 20);
rk[6] = Utils::loadBigEndian<uint32_t>(key + 24);
rk[7] = Utils::loadBigEndian<uint32_t>(key + 28);
for (int i = 0;;) {
uint32_t temp = rk[7];
rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i];
@ -513,7 +543,7 @@ void AES::p_initSW(const uint8_t *key) noexcept
rk += 8;
}
p_encryptSW((const uint8_t *)Utils::ZERO256, (uint8_t *)p_k.sw.h);
p_encryptSW((const uint8_t*)Utils::ZERO256, (uint8_t*)p_k.sw.h);
p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]);
p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]);
@ -545,17 +575,17 @@ void AES::p_initSW(const uint8_t *key) noexcept
}
}
void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept
void AES::p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept
{
const uint32_t *const restrict rk = p_k.sw.ek;
const uint32_t* const restrict rk = p_k.sw.ek;
const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000;
const uint32_t m8_24 = 0xff000000;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3];
uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -615,20 +645,20 @@ void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3);
Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian<uint32_t>(out + 12, s3);
}
void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept
void AES::p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept
{
const uint32_t *restrict rk = p_k.sw.dk;
const uint32_t* restrict rk = p_k.sw.dk;
const uint32_t m8 = 0x000000ff;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3];
uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3;
t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4];
@ -683,15 +713,15 @@ void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept
t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53];
t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54];
t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55];
s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1) & m8]) ^ rk[56];
s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2) & m8]) ^ rk[57];
s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3) & m8]) ^ rk[58];
s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0) & m8]) ^ rk[59];
s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1)&m8]) ^ rk[56];
s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2)&m8]) ^ rk[57];
s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3)&m8]) ^ rk[58];
s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0)&m8]) ^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3);
Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian<uint32_t>(out + 12, s3);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -15,16 +15,16 @@
#define ZT_AES_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "SHA512.hpp"
#include "Utils.hpp"
// Uncomment to disable all hardware acceleration (usually for testing)
//#define ZT_AES_NO_ACCEL
// #define ZT_AES_NO_ACCEL
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64)
#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64)
#define ZT_AES_AESNI 1
#endif
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO)
#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO)
#define ZT_AES_NEON 1
#endif
@ -40,9 +40,8 @@ namespace ZeroTier {
* This includes hardware acceleration for certain processors. The software
* mode is fallback and is significantly slower.
*/
class AES
{
public:
class AES {
public:
/**
* @return True if this system has hardware AES acceleration
*/
@ -63,39 +62,44 @@ public:
* Create an un-initialized AES instance (must call init() before use)
*/
ZT_INLINE AES() noexcept
{}
{
}
/**
* Create an AES instance with the given key
*
* @param key 256-bit key
*/
explicit ZT_INLINE AES(const void *const key) noexcept
{ this->init(key); }
explicit ZT_INLINE AES(const void* const key) noexcept
{
this->init(key);
}
ZT_INLINE ~AES()
{ Utils::burn(&p_k, sizeof(p_k)); }
{
Utils::burn(&p_k, sizeof(p_k));
}
/**
* Set (or re-set) this AES256 cipher's key
*
* @param key 256-bit / 32-byte key
*/
ZT_INLINE void init(const void *const key) noexcept
ZT_INLINE void init(const void* const key) noexcept
{
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
p_init_aesni(reinterpret_cast<const uint8_t *>(key));
p_init_aesni(reinterpret_cast<const uint8_t*>(key));
return;
}
#endif
#ifdef ZT_AES_NEON
if (Utils::ARMCAP.aes) {
p_init_armneon_crypto(reinterpret_cast<const uint8_t *>(key));
p_init_armneon_crypto(reinterpret_cast<const uint8_t*>(key));
return;
}
#endif
p_initSW(reinterpret_cast<const uint8_t *>(key));
p_initSW(reinterpret_cast<const uint8_t*>(key));
}
/**
@ -104,7 +108,7 @@ public:
* @param in Input block
* @param out Output block (can be same as input)
*/
ZT_INLINE void encrypt(const void *const in, void *const out) const noexcept
ZT_INLINE void encrypt(const void* const in, void* const out) const noexcept
{
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
@ -118,7 +122,7 @@ public:
return;
}
#endif
p_encryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out));
p_encryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
}
/**
@ -127,7 +131,7 @@ public:
* @param in Input block
* @param out Output block (can be same as input)
*/
ZT_INLINE void decrypt(const void *const in, void *const out) const noexcept
ZT_INLINE void decrypt(const void* const in, void* const out) const noexcept
{
#ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) {
@ -141,7 +145,7 @@ public:
return;
}
#endif
p_decryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out));
p_decryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
}
class GMACSIVEncryptor;
@ -150,12 +154,11 @@ public:
/**
* Streaming GMAC calculator
*/
class GMAC
{
class GMAC {
friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor;
public:
public:
/**
* @return True if this system has hardware GMAC acceleration
*/
@ -177,8 +180,9 @@ public:
*
* @param aes Keyed AES instance to use
*/
ZT_INLINE GMAC(const AES &aes) : _aes(aes)
{}
ZT_INLINE GMAC(const AES& aes) : _aes(aes)
{
}
/**
* Reset and initialize for a new GMAC calculation
@ -192,12 +196,12 @@ public:
// We fill the least significant 32 bits in the _iv field with 1 since in GCM mode
// this would hold the counter, but we're not doing GCM. The counter is therefore
// always 1.
#ifdef ZT_AES_AESNI // also implies an x64 processor
*reinterpret_cast<uint64_t *>(_iv) = *reinterpret_cast<const uint64_t *>(iv);
*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
#ifdef ZT_AES_AESNI // also implies an x64 processor
*reinterpret_cast<uint64_t*>(_iv) = *reinterpret_cast<const uint64_t*>(iv);
*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;
@ -215,7 +219,7 @@ public:
* @param data Bytes to process
* @param len Length of input
*/
void update(const void *data, unsigned int len) noexcept;
void update(const void* data, unsigned int len) noexcept;
/**
* Process any remaining cached bytes and generate tag
@ -226,19 +230,19 @@ public:
*/
void finish(uint8_t tag[16]) noexcept;
private:
private:
#ifdef ZT_AES_AESNI
void p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept;
void p_aesNIUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_aesNIFinish(uint8_t tag[16]) noexcept;
#endif
#ifdef ZT_AES_NEON
void p_armUpdate(const uint8_t *in, unsigned int len) noexcept;
void p_armUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_armFinish(uint8_t tag[16]) noexcept;
#endif
const AES &_aes;
const AES& _aes;
unsigned int _rp;
unsigned int _len;
uint8_t _r[16]; // remainder
uint8_t _r[16]; // remainder
uint8_t _iv[16];
uint64_t _y[2];
};
@ -249,14 +253,14 @@ public:
* NOTE: this doesn't support overflow of the counter in the least significant 32 bits.
* AES-GMAC-CTR doesn't need this, so we don't support it as an optimization.
*/
class CTR
{
class CTR {
friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor;
public:
ZT_INLINE CTR(const AES &aes) noexcept: _aes(aes)
{}
public:
ZT_INLINE CTR(const AES& aes) noexcept : _aes(aes)
{
}
/**
* Initialize this CTR instance to encrypt a new stream
@ -264,10 +268,10 @@ public:
* @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/
ZT_INLINE void init(const uint8_t iv[16], void *const output) noexcept
ZT_INLINE void init(const uint8_t iv[16], void* const output) noexcept
{
Utils::copy< 16 >(_ctr, iv);
_out = reinterpret_cast<uint8_t *>(output);
Utils::copy<16>(_ctr, iv);
_out = reinterpret_cast<uint8_t*>(output);
_len = 0;
}
@ -278,11 +282,11 @@ public:
* @param ic Initial counter (must be in big-endian byte order!)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/
ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void *const output) noexcept
ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void* const output) noexcept
{
Utils::copy< 12 >(_ctr, iv);
reinterpret_cast<uint32_t *>(_ctr)[3] = ic;
_out = reinterpret_cast<uint8_t *>(output);
Utils::copy<12>(_ctr, iv);
reinterpret_cast<uint32_t*>(_ctr)[3] = ic;
_out = reinterpret_cast<uint8_t*>(output);
_len = 0;
}
@ -292,7 +296,7 @@ public:
* @param input Input data
* @param len Length of input
*/
void crypt(const void *input, unsigned int len) noexcept;
void crypt(const void* input, unsigned int len) noexcept;
/**
* Finish any remaining bytes if total bytes processed wasn't a multiple of 16
@ -301,16 +305,16 @@ public:
*/
void finish() noexcept;
private:
private:
#ifdef ZT_AES_AESNI
void p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept;
void p_aesNICrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif
#ifdef ZT_AES_NEON
void p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept;
void p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif
const AES &_aes;
const AES& _aes;
uint64_t _ctr[2];
uint8_t *_out;
uint8_t* _out;
unsigned int _len;
};
@ -325,19 +329,19 @@ public:
* This supports encryption of a maximum of 2^31 bytes of data per
* call to init().
*/
class GMACSIVEncryptor
{
public:
class GMACSIVEncryptor {
public:
/**
* Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances
*
* @param k0 First of two AES instances keyed with K0
* @param k1 Second of two AES instances keyed with K1
*/
ZT_INLINE GMACSIVEncryptor(const AES &k0, const AES &k1) noexcept :
_gmac(k0),
_ctr(k1)
{}
ZT_INLINE GMACSIVEncryptor(const AES& k0, const AES& k1) noexcept
: _gmac(k0)
, _ctr(k1)
{
}
/**
* Initialize AES-GMAC-SIV
@ -345,7 +349,7 @@ public:
* @param iv IV in network byte order (byte order in which it will appear on the wire)
* @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data!
*/
ZT_INLINE void init(const uint64_t iv, void *const output) noexcept
ZT_INLINE void init(const uint64_t iv, void* const output) noexcept
{
// Output buffer to receive the result of AES-CTR encryption.
_output = output;
@ -353,7 +357,7 @@ public:
// Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero).
_tag[0] = iv;
_tag[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(_tag));
_gmac.init(reinterpret_cast<const uint8_t*>(_tag));
}
/**
@ -367,7 +371,7 @@ public:
* @param aad Additional authenticated data
* @param len Length of AAD in bytes
*/
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept
ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{
// Feed ADD into GMAC first
_gmac.update(aad, len);
@ -385,8 +389,10 @@ public:
* @param input Plaintext chunk
* @param len Length of plaintext chunk
*/
ZT_INLINE void update1(const void *const input, const unsigned int len) noexcept
{ _gmac.update(input, len); }
ZT_INLINE void update1(const void* const input, const unsigned int len) noexcept
{
_gmac.update(input, len);
}
/**
* Finish first pass, compute CTR IV, initialize second pass.
@ -395,7 +401,7 @@ public:
{
// Compute 128-bit GMAC tag.
uint64_t tmp[2];
_gmac.finish(reinterpret_cast<uint8_t *>(tmp));
_gmac.finish(reinterpret_cast<uint8_t*>(tmp));
// Shorten to 64 bits, concatenate with message IV, and encrypt with AES to
// yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV
@ -415,7 +421,7 @@ public:
// and so 2^31 should be considered the input limit.
tmp[0] = _tag[0];
tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), _output);
_ctr.init(reinterpret_cast<const uint8_t*>(tmp), _output);
}
/**
@ -427,8 +433,10 @@ public:
* @param input Plaintext chunk
* @param len Length of plaintext chunk
*/
ZT_INLINE void update2(const void *const input, const unsigned int len) noexcept
{ _ctr.crypt(input, len); }
ZT_INLINE void update2(const void* const input, const unsigned int len) noexcept
{
_ctr.crypt(input, len);
}
/**
* Finish second pass and return a pointer to the opaque 128-bit IV+MAC block
@ -438,14 +446,14 @@ public:
*
* @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers)
*/
ZT_INLINE const uint64_t *finish2()
ZT_INLINE const uint64_t* finish2()
{
_ctr.finish();
return _tag;
}
private:
void *_output;
private:
void* _output;
uint64_t _tag[2];
AES::GMAC _gmac;
AES::CTR _ctr;
@ -456,13 +464,13 @@ public:
*
* GMAC-SIV decryption is single-pass. AAD (if any) must be processed first.
*/
class GMACSIVDecryptor
{
public:
ZT_INLINE GMACSIVDecryptor(const AES &k0, const AES &k1) noexcept:
_ctr(k1),
_gmac(k0)
{}
class GMACSIVDecryptor {
public:
ZT_INLINE GMACSIVDecryptor(const AES& k0, const AES& k1) noexcept
: _ctr(k1)
, _gmac(k0)
{
}
/**
* Initialize decryptor for a new message
@ -470,18 +478,18 @@ public:
* @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption
* @param output Buffer in which to write output plaintext (must be large enough!)
*/
ZT_INLINE void init(const uint64_t tag[2], void *const output) noexcept
ZT_INLINE void init(const uint64_t tag[2], void* const output) noexcept
{
uint64_t tmp[2];
tmp[0] = tag[0];
tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), output);
_ctr.init(reinterpret_cast<const uint8_t*>(tmp), output);
_ctr._aes.decrypt(tag, _ivMac);
tmp[0] = _ivMac[0];
tmp[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(tmp));
_gmac.init(reinterpret_cast<const uint8_t*>(tmp));
_output = output;
_decryptedLen = 0;
@ -493,7 +501,7 @@ public:
* @param aad Additional authenticated data
* @param len Length of AAD in bytes
*/
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept
ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{
_gmac.update(aad, len);
len &= 0xfU;
@ -510,7 +518,7 @@ public:
* @param input Input ciphertext
* @param len Length of ciphertext
*/
ZT_INLINE void update(const void *const input, const unsigned int len) noexcept
ZT_INLINE void update(const void* const input, const unsigned int len) noexcept
{
_ctr.crypt(input, len);
_decryptedLen += len;
@ -527,52 +535,48 @@ public:
uint64_t gmacTag[2];
_gmac.update(_output, _decryptedLen);
_gmac.finish(reinterpret_cast<uint8_t *>(gmacTag));
_gmac.finish(reinterpret_cast<uint8_t*>(gmacTag));
return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1];
}
private:
private:
uint64_t _ivMac[2];
AES::CTR _ctr;
AES::GMAC _gmac;
void *_output;
void* _output;
unsigned int _decryptedLen;
};
private:
private:
static const uint32_t Te0[256];
static const uint32_t Te4[256];
static const uint32_t Td0[256];
static const uint8_t Td4[256];
static const uint32_t rcon[15];
void p_initSW(const uint8_t *key) noexcept;
void p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept;
void p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept;
void p_initSW(const uint8_t* key) noexcept;
void p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept;
void p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept;
union
{
union {
#ifdef ZT_AES_AESNI
struct
{
struct {
__m128i k[28];
__m128i h[4]; // h, hh, hhh, hhhh
__m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc.
__m128i h[4]; // h, hh, hhh, hhhh
__m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc.
} ni;
#endif
#ifdef ZT_AES_NEON
struct
{
uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens
struct {
uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens
uint8x16_t ek[15];
uint8x16_t dk[15];
uint8x16_t h;
} neon;
#endif
struct
{
struct {
uint64_t h[2];
uint32_t ek[60];
uint32_t dk[60];
@ -580,18 +584,18 @@ private:
} p_k;
#ifdef ZT_AES_AESNI
void p_init_aesni(const uint8_t *key) noexcept;
void p_encrypt_aesni(const void *in, void *out) const noexcept;
void p_decrypt_aesni(const void *in, void *out) const noexcept;
void p_init_aesni(const uint8_t* key) noexcept;
void p_encrypt_aesni(const void* in, void* out) const noexcept;
void p_decrypt_aesni(const void* in, void* out) const noexcept;
#endif
#ifdef ZT_AES_NEON
void p_init_armneon_crypto(const uint8_t *key) noexcept;
void p_encrypt_armneon_crypto(const void *in, void *out) const noexcept;
void p_decrypt_armneon_crypto(const void *in, void *out) const noexcept;
void p_init_armneon_crypto(const uint8_t* key) noexcept;
void p_encrypt_armneon_crypto(const void* in, void* out) const noexcept;
void p_decrypt_armneon_crypto(const void* in, void* out) const noexcept;
#endif
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,8 +11,8 @@
*/
/****/
#include "Constants.hpp"
#include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_AESNI
@ -29,7 +29,8 @@ const __m128i s_sseSwapBytes = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif
__m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
__m128i
p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
{
y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
@ -55,7 +56,7 @@ __m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
* The performance gain can be significant but regular SSE is already so
* fast it's highly unlikely to be a rate limiting factor except on massive
* servers and network infrastructure stuff. */
#if !defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7))
#if ! defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7))
#define ZT_AES_VAES512 1
@ -80,12 +81,8 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m512i kk13 = _mm512_broadcast_i32x4(k[13]);
const __m512i kk14 = _mm512_broadcast_i32x4(k[14]);
do {
__m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i *>(in));
__m512i d0 = _mm512_set_epi64(
(long long)Utils::hton(c1 + 3ULL), (long long)c0,
(long long)Utils::hton(c1 + 2ULL), (long long)c0,
(long long)Utils::hton(c1 + 1ULL), (long long)c0,
(long long)Utils::hton(c1), (long long)c0);
__m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i*>(in));
__m512i d0 = _mm512_set_epi64((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0, (long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0);
c1 += 4;
in += 64;
len -= 64;
@ -104,7 +101,7 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d0 = _mm512_aesenc_epi128(d0, kk12);
d0 = _mm512_aesenc_epi128(d0, kk13);
d0 = _mm512_aesenclast_epi128(d0, kk14);
_mm512_storeu_si512(reinterpret_cast<__m512i *>(out), _mm512_xor_si512(p0, d0));
_mm512_storeu_si512(reinterpret_cast<__m512i*>(out), _mm512_xor_si512(p0, d0));
out += 64;
} while (likely(len >= 64));
}
@ -132,14 +129,10 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]);
const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]);
do {
__m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in));
__m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in + 32));
__m256i d0 = _mm256_set_epi64x(
(long long)Utils::hton(c1 + 1ULL), (long long)c0,
(long long)Utils::hton(c1), (long long)c0);
__m256i d1 = _mm256_set_epi64x(
(long long)Utils::hton(c1 + 3ULL), (long long)c0,
(long long)Utils::hton(c1 + 2ULL), (long long)c0);
__m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in));
__m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in + 32));
__m256i d0 = _mm256_set_epi64x((long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0);
__m256i d1 = _mm256_set_epi64x((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0);
c1 += 4;
in += 64;
len -= 64;
@ -173,18 +166,19 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d1 = _mm256_aesenc_epi128(d1, kk13);
d0 = _mm256_aesenclast_epi128(d0, kk14);
d1 = _mm256_aesenclast_epi128(d1, kk14);
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out), _mm256_xor_si256(d0, p0));
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out + 32), _mm256_xor_si256(d1, p1));
_mm256_storeu_si256(reinterpret_cast<__m256i*>(out), _mm256_xor_si256(d0, p0));
_mm256_storeu_si256(reinterpret_cast<__m256i*>(out + 32), _mm256_xor_si256(d1, p1));
out += 64;
} while (likely(len >= 64));
}
#endif // does compiler support AVX2 and AVX512 AES intrinsics?
#endif // does compiler support AVX2 and AVX512 AES intrinsics?
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
__m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept
__m128i
p_init256_1_aesni(__m128i a, __m128i b) noexcept
{
__m128i x, y;
b = _mm_shuffle_epi32(b, 0xff);
@ -201,7 +195,8 @@ __m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
__m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept
__m128i
p_init256_2_aesni(__m128i a, __m128i b) noexcept
{
__m128i x, y, z;
y = _mm_aeskeygenassist_si128(a, 0x00);
@ -216,25 +211,25 @@ __m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept
return x;
}
} // anonymous namespace
} // anonymous namespace
#ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif
void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
{
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y));
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// 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) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r))));
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
break;
}
}
@ -250,17 +245,21 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
const __m128i hh2 = _aes.p_k.ni.h2[1];
const __m128i hhh2 = _aes.p_k.ni.h2[2];
const __m128i hhhh2 = _aes.p_k.ni.h2[3];
const uint8_t *const end64 = in + (len & ~((unsigned int)63));
const uint8_t* const end64 = in + (len & ~((unsigned int)63));
len &= 63U;
do {
__m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))), sb);
__m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16)), sb);
__m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32)), sb);
__m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48)), sb);
__m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))), sb);
__m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)), sb);
__m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)), sb);
__m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)), sb);
in += 64;
__m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00)));
__m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11)));
__m128i c = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), _mm_xor_si128(a, b));
__m128i c = _mm_xor_si128(
_mm_xor_si128(
_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)),
_mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))),
_mm_xor_si128(a, b));
a = _mm_xor_si128(_mm_slli_si128(c, 8), a);
b = _mm_xor_si128(_mm_srli_si128(c, 8), b);
c = _mm_srli_epi32(a, 31);
@ -274,18 +273,18 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
}
while (len >= 16) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))));
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16;
len -= 16;
}
_mm_storeu_si128(reinterpret_cast<__m128i *>(_y), y);
_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) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
_rp = len; // len is always less than 16 here
}
#ifdef __GNUC__
@ -293,23 +292,23 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul,aes")))
#endif
void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
{
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y));
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// Handle any remaining bytes, padding the last block with zeroes.
if (_rp) {
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))));
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
}
// Interleave encryption of IV with the final GHASH of y XOR (length * 8).
// Then XOR these together to get the final tag.
const __m128i *const k = _aes.p_k.ni.k;
const __m128i* const k = _aes.p_k.ni.k;
const __m128i h = _aes.p_k.ni.h[0];
y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U)));
y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i *>(_iv)), k[0]);
__m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(_iv)), k[0]);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
__m128i t2 = _mm_clmulepi64_si128(h, y, 0x01);
__m128i t3 = _mm_clmulepi64_si128(h, y, 0x10);
@ -359,7 +358,7 @@ void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
t4 = _mm_xor_si128(t4, t3);
encIV = _mm_aesenclast_si128(encIV, k[14]);
t4 = _mm_xor_si128(t4, t5);
_mm_storeu_si128(reinterpret_cast<__m128i *>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV));
_mm_storeu_si128(reinterpret_cast<__m128i*>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV));
}
#ifdef __GNUC__
@ -370,7 +369,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]);
uint64_t c1 = Utils::ntoh(_ctr[1]);
const __m128i *const k = _aes.p_k.ni.k;
const __m128i* const k = _aes.p_k.ni.k;
const __m128i k0 = k[0];
const __m128i k1 = k[1];
const __m128i k2 = k[2];
@ -391,14 +390,14 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
unsigned int totalLen = _len;
if ((totalLen & 15U)) {
for (;;) {
if (unlikely(!len)) {
if (unlikely(! len)) {
_ctr[1] = Utils::hton(c1);
_len = totalLen;
return;
}
--len;
out[totalLen++] = *(in++);
if (!(totalLen & 15U)) {
if (! (totalLen & 15U)) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0);
d0 = _mm_aesenc_si128(d0, k1);
@ -411,7 +410,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k8);
d0 = _mm_aesenc_si128(d0, k9);
d0 = _mm_aesenc_si128(d0, k10);
__m128i *const outblk = reinterpret_cast<__m128i *>(out + (totalLen - 16));
__m128i* const outblk = reinterpret_cast<__m128i*>(out + (totalLen - 16));
d0 = _mm_aesenc_si128(d0, k11);
const __m128i p0 = _mm_loadu_si128(outblk);
d0 = _mm_aesenc_si128(d0, k12);
@ -427,26 +426,26 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
_len = totalLen + len;
if (likely(len >= 64)) {
#if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) {
if (Utils::CPUID.avx512f) {
p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k);
} else {
}
else {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
}
goto skip_conventional_aesni_64;
}
#endif
#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
#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;
}
#endif
const uint8_t *const eof64 = in + (len & ~((unsigned int)63));
const uint8_t* const eof64 = in + (len & ~((unsigned int)63));
len &= 63;
__m128i d0, d1, d2, d3;
do {
@ -515,21 +514,20 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d1 = _mm_aesenc_si128(d1, k13);
d2 = _mm_aesenc_si128(d2, k13);
d3 = _mm_aesenc_si128(d3, k13);
d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)));
d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16)));
d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32)));
d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48)));
d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)));
d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)));
d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)));
in += 64;
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out), d0);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i*>(out + 48), d3);
out += 64;
} while (likely(in != eof64));
}
skip_conventional_aesni_64:
skip_conventional_aesni_64:
while (len >= 16) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0);
@ -546,7 +544,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k11);
d0 = _mm_aesenc_si128(d0, k12);
d0 = _mm_aesenc_si128(d0, k13);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))));
_mm_storeu_si128(reinterpret_cast<__m128i*>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16;
len -= 16;
out += 16;
@ -568,8 +566,8 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
void AES::p_init_aesni(const uint8_t *key) noexcept
{
__m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13;
p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i *)key);
p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i *)(key + 16));
p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i*)key);
p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i*)(key + 16));
p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01));
p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2);
p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02));
@ -597,7 +595,7 @@ void AES::p_init_aesni(const uint8_t *key) noexcept
p_k.ni.k[26] = _mm_aesimc_si128(k2);
p_k.ni.k[27] = _mm_aesimc_si128(k1);
__m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]);
__m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]);
h = _mm_aesenc_si128(h, k1);
h = _mm_aesenc_si128(h, k2);
h = _mm_aesenc_si128(h, k3);
@ -631,7 +629,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
{
__m128i tmp = _mm_loadu_si128((const __m128i *)in);
__m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[0]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]);
@ -646,7 +644,7 @@ void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]);
_mm_storeu_si128((__m128i *)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14]));
_mm_storeu_si128((__m128i*)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14]));
}
#ifdef __GNUC__
@ -654,7 +652,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif
void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
{
__m128i tmp = _mm_loadu_si128((const __m128i *)in);
__m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[14]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]);
@ -669,9 +667,9 @@ void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]);
_mm_storeu_si128((__m128i *)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0]));
_mm_storeu_si128((__m128i*)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0]));
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_AES_AESNI
#endif // ZT_AES_AESNI

View file

@ -11,8 +11,8 @@
*/
/****/
#include "Constants.hpp"
#include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_NEON
@ -29,34 +29,34 @@ ZT_INLINE uint8x16_t s_clmul_armneon_crypto(uint8x16_t h, uint8x16_t y, const ui
y = vrbitq_u8(y);
const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087));
t0 = vextq_u8(y, y, 8);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (r0) : "w" (h), "w" (y));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (r1) : "w" (h), "w" (y));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t1) : "w" (h), "w" (t0));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (h), "w" (t0));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(r0) : "w"(h), "w"(y));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(r1) : "w"(h), "w"(y));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t1) : "w"(h), "w"(t0));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(h), "w"(t0));
t0 = veorq_u8(t0, t1);
t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1);
t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1);
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (r1), "w" (p));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1);
t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t0) : "w" (r1), "w" (p));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
return vrbitq_u8(veorq_u8(r0, t0));
}
} // anonymous namespace
} // anonymous namespace
void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
void AES::GMAC::p_armUpdate(const uint8_t* in, unsigned int len) noexcept
{
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y));
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) {
for(;;) {
if (!len) {
for (;;) {
if (! len) {
return;
}
--len;
@ -74,18 +74,18 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
len -= 16;
}
vst1q_u8(reinterpret_cast<uint8_t *>(_y), y);
vst1q_u8(reinterpret_cast<uint8_t*>(_y), y);
for (unsigned int i = 0; i < len; ++i) {
_r[i] = in[i];
}
_rp = len; // len is always less than 16 here
_rp = len; // len is always less than 16 here
}
void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
{
uint64_t tmp[2];
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y));
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) {
@ -97,25 +97,25 @@ void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
tmp[0] = Utils::hton((uint64_t)_len << 3U);
tmp[1] = 0;
y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t *>(tmp));
y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t*>(tmp));
Utils::copy< 12 >(tmp, _iv);
Utils::copy<12>(tmp, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(tmp)[3] = 0x00000001;
reinterpret_cast<uint32_t*>(tmp)[3] = 0x00000001;
#else
reinterpret_cast<uint32_t *>(tmp)[3] = 0x01000000;
reinterpret_cast<uint32_t*>(tmp)[3] = 0x01000000;
#endif
_aes.encrypt(tmp, tmp);
uint8x16_t yy = y;
Utils::storeMachineEndian< uint64_t >(tag, tmp[0] ^ reinterpret_cast<const uint64_t *>(&yy)[0]);
Utils::storeMachineEndian< uint64_t >(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t *>(&yy)[1]);
Utils::storeMachineEndian<uint64_t>(tag, tmp[0] ^ reinterpret_cast<const uint64_t*>(&yy)[0]);
Utils::storeMachineEndian<uint64_t>(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t*>(&yy)[1]);
}
void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept
void AES::CTR::p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept
{
uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t *>(_ctr)));
const uint32x4_t one = {0,0,0,1};
uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t*>(_ctr)));
const uint32x4_t one = { 0, 0, 0, 1 };
uint8x16_t k0 = _aes.p_k.neon.ek[0];
uint8x16_t k1 = _aes.p_k.neon.ek[1];
@ -136,15 +136,15 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
unsigned int totalLen = _len;
if ((totalLen & 15U) != 0) {
for (;;) {
if (unlikely(!len)) {
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd));
if (unlikely(! len)) {
vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
_len = totalLen;
return;
}
--len;
out[totalLen++] = *(in++);
if ((totalLen & 15U) == 0) {
uint8_t *const otmp = out + (totalLen - 16);
uint8_t* const otmp = out + (totalLen - 16);
uint8x16_t d0 = vrev32q_u8(dd);
uint8x16_t pt = vld1q_u8(otmp);
d0 = vaesmcq_u8(vaeseq_u8(d0, k0));
@ -298,46 +298,52 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
out[i] = in[i];
}
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd));
vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
}
#define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U))
#define ZT_INIT_ARMNEON_CRYPTO_ROTWORD(w) (((w) << 8U) | ((w) >> 24U))
#define ZT_INIT_ARMNEON_CRYPTO_NK 8
#define ZT_INIT_ARMNEON_CRYPTO_NB 4
#define ZT_INIT_ARMNEON_CRYPTO_NR 14
#define ZT_INIT_ARMNEON_CRYPTO_NK 8
#define ZT_INIT_ARMNEON_CRYPTO_NB 4
#define ZT_INIT_ARMNEON_CRYPTO_NR 14
void AES::p_init_armneon_crypto(const uint8_t *key) noexcept
void AES::p_init_armneon_crypto(const uint8_t* key) noexcept
{
static const uint8_t s_sbox[256] = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c,
0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea,
0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
static const uint8_t s_sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
uint64_t h[2];
uint32_t *const w = reinterpret_cast<uint32_t *>(p_k.neon.ek);
uint32_t* const w = reinterpret_cast<uint32_t*>(p_k.neon.ek);
for (unsigned int i=0;i<ZT_INIT_ARMNEON_CRYPTO_NK;++i) {
for (unsigned int i = 0; i < ZT_INIT_ARMNEON_CRYPTO_NK; ++i) {
const unsigned int j = i * 4;
w[i] = ((uint32_t)key[j] << 24U) | ((uint32_t)key[j + 1] << 16U) | ((uint32_t)key[j + 2] << 8U) | (uint32_t)key[j + 3];
}
for (unsigned int i=ZT_INIT_ARMNEON_CRYPTO_NK;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) {
for (unsigned int i = ZT_INIT_ARMNEON_CRYPTO_NK; i < (ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1)); ++i) {
uint32_t t = w[i - 1];
const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1);
if (imod == 0) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(ZT_INIT_ARMNEON_CRYPTO_ROTWORD(t)) ^ rcon[(i - 1) / ZT_INIT_ARMNEON_CRYPTO_NK];
} else if (imod == 4) {
}
else if (imod == 4) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(t);
}
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];
@ -349,9 +355,9 @@ void AES::p_init_armneon_crypto(const uint8_t *key) noexcept
p_k.sw.h[1] = Utils::ntoh(h[1]);
}
void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const noexcept
void AES::p_encrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in));
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2]));
@ -366,12 +372,12 @@ void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12]));
tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp);
vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
}
void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const noexcept
void AES::p_decrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in));
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2]));
@ -386,9 +392,9 @@ void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12]));
tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp);
vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
}
} // namespace ZeroTier
} // namespace ZeroTier
#endif // ZT_AES_NEON
#endif // ZT_AES_NEON

View file

@ -14,49 +14,64 @@
#ifndef ZT_ADDRESS_HPP
#define ZT_ADDRESS_HPP
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
namespace ZeroTier {
/**
* A ZeroTier address
*/
class Address
{
public:
Address() : _a(0) {}
Address(const Address &a) : _a(a._a) {}
Address(uint64_t a) : _a(a & 0xffffffffffULL) {}
class Address {
public:
Address() : _a(0)
{
}
Address(const Address& a) : _a(a._a)
{
}
Address(uint64_t a) : _a(a & 0xffffffffffULL)
{
}
/**
* @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array
*/
Address(const void *bits,unsigned int len) { setTo(bits,len); }
Address(const void* bits, unsigned int len)
{
setTo(bits, len);
}
inline Address &operator=(const Address &a) { _a = a._a; return *this; }
inline Address &operator=(const uint64_t a) { _a = (a & 0xffffffffffULL); return *this; }
inline Address& operator=(const Address& a)
{
_a = a._a;
return *this;
}
inline Address& operator=(const uint64_t a)
{
_a = (a & 0xffffffffffULL);
return *this;
}
/**
* @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array
*/
inline void setTo(const void *bits,const unsigned int len)
inline void setTo(const void* bits, const unsigned int len)
{
if (len < ZT_ADDRESS_LENGTH) {
_a = 0;
return;
}
const unsigned char *b = (const unsigned char *)bits;
const unsigned char* b = (const unsigned char*)bits;
uint64_t a = ((uint64_t)*b++) << 32;
a |= ((uint64_t)*b++) << 24;
a |= ((uint64_t)*b++) << 16;
@ -69,12 +84,12 @@ public:
* @param bits Buffer to hold 5-byte address in big-endian byte order
* @param len Length of array
*/
inline void copyTo(void *const bits,const unsigned int len) const
inline void copyTo(void* const bits, const unsigned int len) const
{
if (len < ZT_ADDRESS_LENGTH) {
return;
}
unsigned char *b = (unsigned char *)bits;
unsigned char* b = (unsigned char*)bits;
*(b++) = (unsigned char)((_a >> 32) & 0xff);
*(b++) = (unsigned char)((_a >> 24) & 0xff);
*(b++) = (unsigned char)((_a >> 16) & 0xff);
@ -87,10 +102,9 @@ public:
*
* @param b Buffer to append to
*/
template<unsigned int C>
inline void appendTo(Buffer<C> &b) const
template <unsigned int C> inline void appendTo(Buffer<C>& b) const
{
unsigned char *p = (unsigned char *)b.appendField(ZT_ADDRESS_LENGTH);
unsigned char* p = (unsigned char*)b.appendField(ZT_ADDRESS_LENGTH);
*(p++) = (unsigned char)((_a >> 32) & 0xff);
*(p++) = (unsigned char)((_a >> 24) & 0xff);
*(p++) = (unsigned char)((_a >> 16) & 0xff);
@ -101,22 +115,34 @@ public:
/**
* @return Integer containing address (0 to 2^40)
*/
inline uint64_t toInt() const { return _a; }
inline uint64_t toInt() const
{
return _a;
}
/**
* @return Hash code for use with Hashtable
*/
inline unsigned long hashCode() const { return (unsigned long)_a; }
inline unsigned long hashCode() const
{
return (unsigned long)_a;
}
/**
* @return Hexadecimal string
*/
inline char *toString(char buf[11]) const { return Utils::hex10(_a,buf); }
inline char* toString(char buf[11]) const
{
return Utils::hex10(_a, buf);
}
/**
* @return True if this address is not zero
*/
inline operator bool() const { return (_a != 0); }
inline operator bool() const
{
return (_a != 0);
}
/**
* Check if this address is reserved
@ -127,34 +153,79 @@ public:
*
* @return True if address is reserved and may not be used
*/
inline bool isReserved() const { return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); }
inline bool isReserved() const
{
return ((! _a) || ((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX));
}
/**
* @param i Value from 0 to 4 (inclusive)
* @return Byte at said position (address interpreted in big-endian order)
*/
inline uint8_t operator[](unsigned int i) const { return (uint8_t)(_a >> (32 - (i * 8))); }
inline uint8_t operator[](unsigned int i) const
{
return (uint8_t)(_a >> (32 - (i * 8)));
}
inline void zero() { _a = 0; }
inline void zero()
{
_a = 0;
}
inline bool operator==(const uint64_t &a) const { return (_a == (a & 0xffffffffffULL)); }
inline bool operator!=(const uint64_t &a) const { return (_a != (a & 0xffffffffffULL)); }
inline bool operator>(const uint64_t &a) const { return (_a > (a & 0xffffffffffULL)); }
inline bool operator<(const uint64_t &a) const { return (_a < (a & 0xffffffffffULL)); }
inline bool operator>=(const uint64_t &a) const { return (_a >= (a & 0xffffffffffULL)); }
inline bool operator<=(const uint64_t &a) const { return (_a <= (a & 0xffffffffffULL)); }
inline bool operator==(const uint64_t& a) const
{
return (_a == (a & 0xffffffffffULL));
}
inline bool operator!=(const uint64_t& a) const
{
return (_a != (a & 0xffffffffffULL));
}
inline bool operator>(const uint64_t& a) const
{
return (_a > (a & 0xffffffffffULL));
}
inline bool operator<(const uint64_t& a) const
{
return (_a < (a & 0xffffffffffULL));
}
inline bool operator>=(const uint64_t& a) const
{
return (_a >= (a & 0xffffffffffULL));
}
inline bool operator<=(const uint64_t& a) const
{
return (_a <= (a & 0xffffffffffULL));
}
inline bool operator==(const Address &a) const { return (_a == a._a); }
inline bool operator!=(const Address &a) const { return (_a != a._a); }
inline bool operator>(const Address &a) const { return (_a > a._a); }
inline bool operator<(const Address &a) const { return (_a < a._a); }
inline bool operator>=(const Address &a) const { return (_a >= a._a); }
inline bool operator<=(const Address &a) const { return (_a <= a._a); }
inline bool operator==(const Address& a) const
{
return (_a == a._a);
}
inline bool operator!=(const Address& a) const
{
return (_a != a._a);
}
inline bool operator>(const Address& a) const
{
return (_a > a._a);
}
inline bool operator<(const Address& a) const
{
return (_a < a._a);
}
inline bool operator>=(const Address& a) const
{
return (_a >= a._a);
}
inline bool operator<=(const Address& a) const
{
return (_a <= a._a);
}
private:
private:
uint64_t _a;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -25,15 +25,17 @@ namespace ZeroTier {
/**
* Simple atomic counter supporting increment and decrement
*/
class AtomicCounter
{
public:
AtomicCounter() { _v = 0; }
class AtomicCounter {
public:
AtomicCounter()
{
_v = 0;
}
inline int load() const
{
#ifdef __GNUC__
return __sync_or_and_fetch(const_cast<int *>(&_v),0);
return __sync_or_and_fetch(const_cast<int*>(&_v), 0);
#else
return _v.load();
#endif
@ -42,7 +44,7 @@ public:
inline int operator++()
{
#ifdef __GNUC__
return __sync_add_and_fetch(&_v,1);
return __sync_add_and_fetch(&_v, 1);
#else
return ++_v;
#endif
@ -51,15 +53,20 @@ public:
inline int operator--()
{
#ifdef __GNUC__
return __sync_sub_and_fetch(&_v,1);
return __sync_sub_and_fetch(&_v, 1);
#else
return --_v;
#endif
}
private:
AtomicCounter(const AtomicCounter &) {}
const AtomicCounter &operator=(const AtomicCounter &) { return *this; }
private:
AtomicCounter(const AtomicCounter&)
{
}
const AtomicCounter& operator=(const AtomicCounter&)
{
return *this;
}
#ifdef __GNUC__
int _v;
@ -68,6 +75,6 @@ private:
#endif
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -373,7 +373,7 @@ SharedPtr<Path> Bond::getAppropriatePath(int64_t now, int32_t flowId)
*/
if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) {
if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && _paths[_abPathIdx].p) {
//fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str());
// fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str());
return _paths[_abPathIdx].p;
}
}
@ -1584,7 +1584,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
}
}
}
if (!foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) {
if (! foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) {
log("found non-preferred primary link (_abPathIdx=%d)", _abPathIdx);
_abPathIdx = nonPreferredPathIdx;
}
@ -1750,19 +1750,12 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
}
}
}
/*
// Sort queue based on performance
if (! _abFailoverQueue.empty()) {
for (int i = 0; i < _abFailoverQueue.size(); i++) {
int value_to_insert = _abFailoverQueue[i];
int hole_position = i;
while (hole_position > 0 && (_abFailoverQueue[hole_position - 1] > value_to_insert)) {
_abFailoverQueue[hole_position] = _abFailoverQueue[hole_position - 1];
hole_position = hole_position - 1;
}
_abFailoverQueue[hole_position] = value_to_insert;
}
}*/
std::sort(_abFailoverQueue.begin(), _abFailoverQueue.end(),
[this](const int a, const int b) {
// Sort by failover score in descending order (highest score first)
return _paths[a].failoverScore > _paths[b].failoverScore;
});
/**
* Short-circuit if we have no queued paths

View file

@ -1144,7 +1144,7 @@ class Bond {
__attribute__((format(printf, 2, 3)))
#endif
{
//if (_peerId != 0x0 && _peerId != 0x0) { return; }
// if (_peerId != 0x0 && _peerId != 0x0) { return; }
#ifdef ZT_TRACE
time_t rawtime;
struct tm* timeinfo;
@ -1176,7 +1176,7 @@ class Bond {
__attribute__((format(printf, 2, 3)))
#endif
{
//if (_peerId != 0x0 && _peerId != 0x0) { return; }
// if (_peerId != 0x0 && _peerId != 0x0) { return; }
#ifdef ZT_DEBUG
time_t rawtime;
struct tm* timeinfo;

View file

@ -14,18 +14,17 @@
#ifndef ZT_BUFFER_HPP
#define ZT_BUFFER_HPP
#include <string.h>
#include <stdint.h>
#include <stdexcept>
#include <string>
#include <algorithm>
#include <utility>
#include "Constants.hpp"
#include "Utils.hpp"
#if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING))
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <string.h>
#include <string>
#include <utility>
#if defined(__GNUC__) && (! defined(ZT_NO_TYPE_PUNNING))
#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
#else
#define ZT_VAR_MAY_ALIAS
@ -46,36 +45,57 @@ namespace ZeroTier {
*
* @tparam C Total capacity
*/
template<unsigned int C>
class Buffer
{
template <unsigned int C> class Buffer {
// I love me!
template <unsigned int C2> friend class Buffer;
public:
public:
// STL container idioms
typedef unsigned char value_type;
typedef unsigned char * pointer;
typedef const char * const_pointer;
typedef char & reference;
typedef const char & const_reference;
typedef char * iterator;
typedef const char * const_iterator;
typedef unsigned char* pointer;
typedef const char* const_pointer;
typedef char& reference;
typedef const char& const_reference;
typedef char* iterator;
typedef const char* const_iterator;
typedef unsigned int size_type;
typedef int difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
inline iterator begin() { return _b; }
inline iterator end() { return (_b + _l); }
inline const_iterator begin() const { return _b; }
inline const_iterator end() const { return (_b + _l); }
inline reverse_iterator rbegin() { return reverse_iterator(begin()); }
inline reverse_iterator rend() { return reverse_iterator(end()); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
inline iterator begin()
{
return _b;
}
inline iterator end()
{
return (_b + _l);
}
inline const_iterator begin() const
{
return _b;
}
inline const_iterator end() const
{
return (_b + _l);
}
inline reverse_iterator rbegin()
{
return reverse_iterator(begin());
}
inline reverse_iterator rend()
{
return reverse_iterator(end());
}
inline const_reverse_iterator rbegin() const
{
return const_reverse_iterator(begin());
}
inline const_reverse_iterator rend() const
{
return const_reverse_iterator(end());
}
Buffer() :
_l(0)
Buffer() : _l(0)
{
}
@ -87,37 +107,36 @@ public:
_l = l;
}
template<unsigned int C2>
Buffer(const Buffer<C2> &b)
template <unsigned int C2> Buffer(const Buffer<C2>& b)
{
*this = b;
}
Buffer(const void *b,unsigned int l)
Buffer(const void* b, unsigned int l)
{
copyFrom(b,l);
copyFrom(b, l);
}
template<unsigned int C2>
inline Buffer &operator=(const Buffer<C2> &b)
template <unsigned int C2> inline Buffer& operator=(const Buffer<C2>& b)
{
if (unlikely(b._l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
if (C2 == C) {
memcpy(this,&b,sizeof(Buffer<C>));
} else {
memcpy(_b,b._b,_l = b._l);
memcpy(this, &b, sizeof(Buffer<C>));
}
else {
memcpy(_b, b._b, _l = b._l);
}
return *this;
}
inline void copyFrom(const void *b,unsigned int l)
inline void copyFrom(const void* b, unsigned int l)
{
if (unlikely(l > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
memcpy(_b,b,l);
memcpy(_b, b, l);
_l = l;
}
@ -129,12 +148,12 @@ public:
return (unsigned char)_b[i];
}
unsigned char &operator[](const unsigned int i)
unsigned char& operator[](const unsigned int i)
{
if (unlikely(i >= _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return ((unsigned char *)_b)[i];
return ((unsigned char*)_b)[i];
}
/**
@ -150,19 +169,19 @@ public:
* @return Pointer to field data
* @throws std::out_of_range Field extends beyond data size
*/
unsigned char *field(unsigned int i,unsigned int l)
unsigned char* field(unsigned int i, unsigned int l)
{
if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return (unsigned char *)(_b + i);
return (unsigned char*)(_b + i);
}
const unsigned char *field(unsigned int i,unsigned int l) const
const unsigned char* field(unsigned int i, unsigned int l) const
{
if (unlikely((i + l) > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
return (const unsigned char *)(_b + i);
return (const unsigned char*)(_b + i);
}
/**
@ -172,19 +191,18 @@ public:
* @param v Value
* @tparam T Integer type (e.g. uint16_t, int64_t)
*/
template<typename T>
inline void setAt(unsigned int i,const T v)
template <typename T> inline void setAt(unsigned int i, const T v)
{
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) {
uint8_t* p = reinterpret_cast<uint8_t*>(_b + i);
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);
T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + i);
*p = Utils::hton(v);
#endif
}
@ -196,22 +214,21 @@ public:
* @tparam T Integer type (e.g. uint16_t, int64_t)
* @return Integer value
*/
template<typename T>
inline T at(unsigned int i) const
template <typename T> inline T at(unsigned int i) const
{
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);
for(unsigned int x=0;x<sizeof(T);++x) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(_b + i);
for (unsigned int x = 0; x < sizeof(T); ++x) {
v <<= 8;
v |= (T)*(p++);
v |= (T) * (p++);
}
return v;
#else
const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i);
const T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T*>(_b + i);
return Utils::ntoh(*p);
#endif
}
@ -223,19 +240,18 @@ public:
* @tparam T Integer type (e.g. uint16_t, int64_t)
* @throws std::out_of_range Attempt to append beyond capacity
*/
template<typename T>
inline void append(const T v)
template <typename T> inline void append(const T v)
{
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) {
uint8_t* p = reinterpret_cast<uint8_t*>(_b + _l);
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);
T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + _l);
*p = Utils::hton(v);
#endif
_l += sizeof(T);
@ -248,12 +264,12 @@ public:
* @param n Number of times to append
* @throws std::out_of_range Attempt to append beyond capacity
*/
inline void append(unsigned char c,unsigned int n)
inline void append(unsigned char c, unsigned int n)
{
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;
}
}
@ -268,7 +284,7 @@ public:
if (unlikely((_l + n) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
Utils::getSecureRandom(_b + _l,n);
Utils::getSecureRandom(_b + _l, n);
_l += n;
}
@ -279,12 +295,12 @@ public:
* @param l Length
* @throws std::out_of_range Attempt to append beyond capacity
*/
inline void append(const void *b,unsigned int l)
inline void append(const void* b, unsigned int l)
{
if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
memcpy(_b + _l,b,l);
memcpy(_b + _l, b, l);
_l += l;
}
@ -294,13 +310,13 @@ public:
* @param s C string
* @throws std::out_of_range Attempt to append beyond capacity
*/
inline void appendCString(const char *s)
inline void appendCString(const char* s)
{
for(;;) {
for (;;) {
if (unlikely(_l >= C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
if (!(_b[_l++] = *(s++))) {
if (! (_b[_l++] = *(s++))) {
break;
}
}
@ -313,10 +329,9 @@ public:
* @tparam C2 Capacity of second buffer (typically inferred)
* @throws std::out_of_range Attempt to append beyond capacity
*/
template<unsigned int C2>
inline void append(const Buffer<C2> &b)
template <unsigned int C2> inline void append(const Buffer<C2>& b)
{
append(b._b,b._l);
append(b._b, b._l);
}
/**
@ -329,12 +344,12 @@ public:
* @param l Length of field to append
* @return Pointer to beginning of appended field of length 'l'
*/
inline char *appendField(unsigned int l)
inline char* appendField(unsigned int l)
{
if (unlikely((_l + l) > C)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
char *r = _b + _l;
char* r = _b + _l;
_l += l;
return r;
}
@ -379,13 +394,13 @@ public:
*/
inline void behead(const unsigned int at)
{
if (!at) {
if (! at) {
return;
}
if (unlikely(at > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
::memmove(_b,_b + at,_l -= at);
::memmove(_b, _b + at, _l -= at);
}
/**
@ -395,92 +410,110 @@ public:
* @param length Length of block to erase
* @throws std::out_of_range Position plus length is beyond size of buffer
*/
inline void erase(const unsigned int at,const unsigned int length)
inline void erase(const unsigned int at, const unsigned int length)
{
const unsigned int endr = at + length;
if (unlikely(endr > _l)) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
}
::memmove(_b + at,_b + endr,_l - endr);
::memmove(_b + at, _b + endr, _l - endr);
_l -= length;
}
/**
* Set buffer data length to zero
*/
inline void clear() { _l = 0; }
inline void clear()
{
_l = 0;
}
/**
* Zero buffer up to size()
*/
inline void zero() { memset(_b,0,_l); }
inline void zero()
{
memset(_b, 0, _l);
}
/**
* Zero unused capacity area
*/
inline void zeroUnused() { memset(_b + _l,0,C - _l); }
inline void zeroUnused()
{
memset(_b + _l, 0, C - _l);
}
/**
* Unconditionally and securely zero buffer's underlying memory
*/
inline void burn() { Utils::burn(_b,sizeof(_b)); }
inline void burn()
{
Utils::burn(_b, sizeof(_b));
}
/**
* @return Constant pointer to data in buffer
*/
inline const void *data() const { return _b; }
inline const void* data() const
{
return _b;
}
/**
* @return Non-constant pointer to data in buffer
*/
inline void *unsafeData() { return _b; }
inline void* unsafeData()
{
return _b;
}
/**
* @return Size of data in buffer
*/
inline unsigned int size() const { return _l; }
inline unsigned int size() const
{
return _l;
}
/**
* @return Capacity of buffer
*/
inline unsigned int capacity() const { return C; }
inline unsigned int capacity() const
{
return C;
}
template<unsigned int C2>
inline bool operator==(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator==(const Buffer<C2>& b) const
{
return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
return ((_l == b._l) && (! memcmp(_b, b._b, _l)));
}
template<unsigned int C2>
inline bool operator!=(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator!=(const Buffer<C2>& b) const
{
return ((_l != b._l)||(memcmp(_b,b._b,_l)));
return ((_l != b._l) || (memcmp(_b, b._b, _l)));
}
template<unsigned int C2>
inline bool operator<(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator<(const Buffer<C2>& b) const
{
return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
return (memcmp(_b, b._b, std::min(_l, b._l)) < 0);
}
template<unsigned int C2>
inline bool operator>(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator>(const Buffer<C2>& b) const
{
return (b < *this);
}
template<unsigned int C2>
inline bool operator<=(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator<=(const Buffer<C2>& b) const
{
return !(b < *this);
return ! (b < *this);
}
template<unsigned int C2>
inline bool operator>=(const Buffer<C2> &b) const
template <unsigned int C2> inline bool operator>=(const Buffer<C2>& b) const
{
return !(*this < b);
return ! (*this < b);
}
private:
private:
char ZT_VAR_MAY_ALIAS _b[C];
unsigned int _l;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -18,20 +18,28 @@
namespace ZeroTier {
#define ZT_C25519_PUBLIC_KEY_LEN 64
#define ZT_C25519_PUBLIC_KEY_LEN 64
#define ZT_C25519_PRIVATE_KEY_LEN 64
#define ZT_C25519_SIGNATURE_LEN 96
#define ZT_C25519_SIGNATURE_LEN 96
/**
* A combined Curve25519 ECDH and Ed25519 signature engine
*/
class C25519
{
public:
struct Public { uint8_t data[ZT_C25519_PUBLIC_KEY_LEN]; };
struct Private { uint8_t data[ZT_C25519_PRIVATE_KEY_LEN]; };
struct Signature { uint8_t data[ZT_C25519_SIGNATURE_LEN]; };
struct Pair { Public pub; Private priv; };
class C25519 {
public:
struct Public {
uint8_t data[ZT_C25519_PUBLIC_KEY_LEN];
};
struct Private {
uint8_t data[ZT_C25519_PRIVATE_KEY_LEN];
};
struct Signature {
uint8_t data[ZT_C25519_SIGNATURE_LEN];
};
struct Pair {
Public pub;
Private priv;
};
/**
* Generate a C25519 elliptic curve key pair
@ -39,7 +47,7 @@ public:
static inline Pair generate()
{
Pair kp;
Utils::getSecureRandom(kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN);
Utils::getSecureRandom(kp.priv.data, ZT_C25519_PRIVATE_KEY_LEN);
_calcPubDH(kp);
_calcPubED(kp);
return kp;
@ -58,18 +66,17 @@ public:
* @return Key pair where cond(kp) returns true
* @tparam F Type of 'cond'
*/
template<typename F>
static inline Pair generateSatisfying(F cond)
template <typename F> static inline Pair generateSatisfying(F cond)
{
Pair kp;
void *const priv = (void *)kp.priv.data;
Utils::getSecureRandom(priv,ZT_C25519_PRIVATE_KEY_LEN);
_calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv
void* const priv = (void*)kp.priv.data;
Utils::getSecureRandom(priv, ZT_C25519_PRIVATE_KEY_LEN);
_calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv
do {
++(((uint64_t *)priv)[1]);
--(((uint64_t *)priv)[2]);
_calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied
} while (!cond(kp));
++(((uint64_t*)priv)[1]);
--(((uint64_t*)priv)[2]);
_calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied
} while (! cond(kp));
return kp;
}
@ -84,8 +91,11 @@ public:
* @param keybuf Buffer to fill
* @param keylen Number of key bytes to generate
*/
static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen);
static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) { agree(mine.priv,their,keybuf,keylen); }
static void agree(const Private& mine, const Public& their, void* keybuf, unsigned int keylen);
static inline void agree(const Pair& mine, const Public& their, void* keybuf, unsigned int keylen)
{
agree(mine.priv, their, keybuf, keylen);
}
/**
* Sign a message with a sender's key pair
@ -106,8 +116,11 @@ public:
* @param len Length of message in bytes
* @param signature Buffer to fill with signature -- MUST be 96 bytes in length
*/
static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature);
static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) { sign(mine.priv,mine.pub,msg,len,signature); }
static void sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len, void* signature);
static inline void sign(const Pair& mine, const void* msg, unsigned int len, void* signature)
{
sign(mine.priv, mine.pub, msg, len, signature);
}
/**
* Sign a message with a sender's key pair
@ -118,16 +131,16 @@ public:
* @param len Length of message in bytes
* @return Signature
*/
static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len)
static inline Signature sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len)
{
Signature sig;
sign(myPrivate,myPublic,msg,len,sig.data);
sign(myPrivate, myPublic, msg, len, sig.data);
return sig;
}
static inline Signature sign(const Pair &mine,const void *msg,unsigned int len)
static inline Signature sign(const Pair& mine, const void* msg, unsigned int len)
{
Signature sig;
sign(mine.priv,mine.pub,msg,len,sig.data);
sign(mine.priv, mine.pub, msg, len, sig.data);
return sig;
}
@ -140,7 +153,7 @@ public:
* @param signature 96-byte signature
* @return True if signature is valid and the message is authentic and unmodified
*/
static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature);
static bool verify(const Public& their, const void* msg, unsigned int len, const void* signature);
/**
* Verify a message's signature
@ -151,21 +164,21 @@ public:
* @param signature 96-byte signature
* @return True if signature is valid and the message is authentic and unmodified
*/
static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature)
static inline bool verify(const Public& their, const void* msg, unsigned int len, const Signature& signature)
{
return verify(their,msg,len,signature.data);
return verify(their, msg, len, signature.data);
}
private:
private:
// derive first 32 bytes of kp.pub from first 32 bytes of kp.priv
// this is the ECDH key
static void _calcPubDH(Pair &kp);
static void _calcPubDH(Pair& kp);
// derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv
// this is the Ed25519 sign/verify key
static void _calcPubED(Pair &kp);
static void _calcPubED(Pair& kp);
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,54 +12,60 @@
/****/
#include "Capability.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const
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) {
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))) {
return -1; // the first entry must be present and from the network's controller
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) {
return 0; // all previous entries were valid, so we are valid
} 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
}
else {
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)) {
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));
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);
}
else {
RR->sw->requestWhois(tPtr, RR->node->now(), _custody[c].from);
return 1;
}
}
// We reached max custody chain length and everything was valid
return 0;
} catch ( ... ) {}
}
catch (...) {
}
return -1;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,19 +14,19 @@
#ifndef ZT_CAPABILITY_HPP
#define ZT_CAPABILITY_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp"
#include "../include/ZeroTierOne.h"
namespace ZeroTier {
class RuntimeEnvironment;
@ -54,20 +54,17 @@ class RuntimeEnvironment;
* handed off between nodes. Limited transferability of capabilities is
* a feature of true capability based security.
*/
class Capability : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; }
Capability() :
_nwid(0),
_ts(0),
_id(0),
_maxCustodyChainLength(0),
_ruleCount(0)
class Capability : public Credential {
public:
static inline Credential::Type credentialType()
{
memset(_rules,0,sizeof(_rules));
memset(_custody,0,sizeof(_custody));
return Credential::CREDENTIAL_TYPE_CAPABILITY;
}
Capability() : _nwid(0), _ts(0), _id(0), _maxCustodyChainLength(0), _ruleCount(0)
{
memset(_rules, 0, sizeof(_rules));
memset(_custody, 0, sizeof(_custody));
}
/**
@ -78,42 +75,57 @@ public:
* @param rules Network flow rules for this capability
* @param ruleCount Number of flow rules
*/
Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) :
_nwid(nwid),
_ts(ts),
_id(id),
_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)
Capability(uint32_t id, uint64_t nwid, int64_t ts, unsigned int mccl, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount)
: _nwid(nwid)
, _ts(ts)
, _id(id)
, _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) {
memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
memcpy(_rules, rules, sizeof(ZT_VirtualNetworkRule) * _ruleCount);
}
}
/**
* @return Rules -- see ruleCount() for size of array
*/
inline const ZT_VirtualNetworkRule *rules() const { return _rules; }
inline const ZT_VirtualNetworkRule* rules() const
{
return _rules;
}
/**
* @return Number of rules in rules()
*/
inline unsigned int ruleCount() const { return _ruleCount; }
inline unsigned int ruleCount() const
{
return _ruleCount;
}
/**
* @return ID and evaluation order of this capability in network
*/
inline uint32_t id() const { return _id; }
inline uint32_t id() const
{
return _id;
}
/**
* @return Network ID for which this capability was issued
*/
inline uint64_t networkId() const { return _nwid; }
inline uint64_t networkId() const
{
return _nwid;
}
/**
* @return Timestamp
*/
inline int64_t timestamp() const { return _ts; }
inline int64_t timestamp() const
{
return _ts;
}
/**
* @return Last 'to' address in chain of custody
@ -121,10 +133,11 @@ public:
inline Address issuedTo() const
{
Address i2;
for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
if (!_custody[i].to) {
for (unsigned int i = 0; i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH; ++i) {
if (! _custody[i].to) {
return i2;
} else {
}
else {
i2 = _custody[i].to;
}
}
@ -144,20 +157,22 @@ public:
* @param to Recipient of this signature
* @return True if signature successful and chain of custody appended
*/
inline bool sign(const Identity &from,const Address &to)
inline bool sign(const Identity& from, const Address& to)
{
try {
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) {
if (!(_custody[i].to)) {
for (unsigned int i = 0; ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)); ++i) {
if (! (_custody[i].to)) {
Buffer<(sizeof(Capability) * 2)> tmp;
this->serialize(tmp,true);
this->serialize(tmp, true);
_custody[i].to = to;
_custody[i].from = from.address();
_custody[i].signature = from.sign(tmp.data(),tmp.size());
_custody[i].signature = from.sign(tmp.data(), tmp.size());
return true;
}
}
} catch ( ... ) {}
}
catch (...) {
}
return false;
}
@ -167,17 +182,16 @@ public:
* @param RR Runtime environment to provide for peer lookup, etc.
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C>
static inline void serializeRules(Buffer<C> &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
template <unsigned int C> static inline void serializeRules(Buffer<C>& b, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount)
{
for(unsigned int i=0;i<ruleCount;++i) {
for (unsigned int i = 0; i < ruleCount; ++i) {
// Each rule consists of its 8-bit type followed by the size of that type's
// field followed by field data. The inclusion of the size will allow non-supported
// rules to be ignored but still parsed.
b.append((uint8_t)rules[i].t);
switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) {
switch ((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) {
default:
b.append((uint8_t)0);
break;
@ -187,7 +201,7 @@ public:
b.append((uint8_t)14);
b.append((uint64_t)rules[i].v.fwd.address);
b.append((uint32_t)rules[i].v.fwd.flags);
b.append((uint16_t)rules[i].v.fwd.length); // unused for redirect
b.append((uint16_t)rules[i].v.fwd.length); // unused for redirect
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
@ -209,18 +223,18 @@ public:
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
case ZT_NETWORK_RULE_MATCH_MAC_DEST:
b.append((uint8_t)6);
b.append(rules[i].v.mac,6);
b.append(rules[i].v.mac, 6);
break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
b.append((uint8_t)5);
b.append(&(rules[i].v.ipv4.ip),4);
b.append(&(rules[i].v.ipv4.ip), 4);
b.append((uint8_t)rules[i].v.ipv4.mask);
break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
b.append((uint8_t)17);
b.append(rules[i].v.ipv6.ip,16);
b.append(rules[i].v.ipv6.ip, 16);
b.append((uint8_t)rules[i].v.ipv6.mask);
break;
case ZT_NETWORK_RULE_MATCH_IP_TOS:
@ -276,7 +290,7 @@ public:
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE:
b.append((uint8_t)19);
b.append((uint64_t)rules[i].v.intRange.start);
b.append((uint64_t)(rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end)); // more future-proof
b.append((uint64_t)(rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end)); // more future-proof
b.append((uint16_t)rules[i].v.intRange.idx);
b.append((uint8_t)rules[i].v.intRange.format);
break;
@ -284,13 +298,12 @@ public:
}
}
template<unsigned int C>
static inline void deserializeRules(const Buffer<C> &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount)
template <unsigned int C> static inline void deserializeRules(const Buffer<C>& b, unsigned int& p, ZT_VirtualNetworkRule* rules, unsigned int& ruleCount, const unsigned int maxRuleCount)
{
while ((ruleCount < maxRuleCount)&&(p < b.size())) {
while ((ruleCount < maxRuleCount) && (p < b.size())) {
rules[ruleCount].t = (uint8_t)b[p++];
const unsigned int fieldLen = (unsigned int)b[p++];
switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) {
switch ((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) {
default:
break;
case ZT_NETWORK_RULE_ACTION_TEE:
@ -302,7 +315,7 @@ public:
break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
rules[ruleCount].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
rules[ruleCount].v.zt = Address(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH).toInt();
break;
case ZT_NETWORK_RULE_MATCH_VLAN_ID:
rules[ruleCount].v.vlanId = b.template at<uint16_t>(p);
@ -315,22 +328,22 @@ public:
break;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
case ZT_NETWORK_RULE_MATCH_MAC_DEST:
memcpy(rules[ruleCount].v.mac,b.field(p,6),6);
memcpy(rules[ruleCount].v.mac, b.field(p, 6), 6);
break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4);
memcpy(&(rules[ruleCount].v.ipv4.ip), b.field(p, 4), 4);
rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4];
break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
memcpy(rules[ruleCount].v.ipv6.ip,b.field(p,16),16);
memcpy(rules[ruleCount].v.ipv6.ip, b.field(p, 16), 16);
rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16];
break;
case ZT_NETWORK_RULE_MATCH_IP_TOS:
rules[ruleCount].v.ipTos.mask = (uint8_t)b[p];
rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p+1];
rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p+2];
rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p + 1];
rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p + 2];
break;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
rules[ruleCount].v.ipProtocol = (uint8_t)b[p];
@ -340,8 +353,8 @@ public:
break;
case ZT_NETWORK_RULE_MATCH_ICMP:
rules[ruleCount].v.icmp.type = (uint8_t)b[p];
rules[ruleCount].v.icmp.code = (uint8_t)b[p+1];
rules[ruleCount].v.icmp.flags = (uint8_t)b[p+2];
rules[ruleCount].v.icmp.code = (uint8_t)b[p + 1];
rules[ruleCount].v.icmp.flags = (uint8_t)b[p + 2];
break;
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
@ -380,8 +393,7 @@ public:
}
}
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -393,19 +405,20 @@ public:
b.append(_id);
b.append((uint16_t)_ruleCount);
serializeRules(b,_rules,_ruleCount);
serializeRules(b, _rules, _ruleCount);
b.append((uint8_t)_maxCustodyChainLength);
if (!forSign) {
for(unsigned int i=0;;++i) {
if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) {
if (! forSign) {
for (unsigned int i = 0;; ++i) {
if ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) && (_custody[i].to)) {
_custody[i].to.appendTo(b);
_custody[i].from.appendTo(b);
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN);
} else {
b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_custody[i].signature.data, ZT_C25519_SIGNATURE_LEN);
}
else {
b.append((unsigned char)0, ZT_ADDRESS_LENGTH); // zero 'to' terminates chain
break;
}
}
@ -419,8 +432,7 @@ public:
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
*this = Capability();
@ -438,33 +450,34 @@ public:
if (rc > ZT_MAX_CAPABILITY_RULES) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
deserializeRules(b,p,_rules,_ruleCount,rc);
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);
for (unsigned int i = 0;; ++i) {
const Address to(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (!to) {
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);
_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) {
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);
memcpy(_custody[i].signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
}
else {
p += 2 + b.template at<uint16_t>(p);
}
}
@ -478,12 +491,21 @@ public:
}
// Provides natural sort order by ID
inline bool operator<(const Capability &c) const { return (_id < c._id); }
inline bool operator<(const Capability& c) const
{
return (_id < c._id);
}
inline bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); }
inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); }
inline bool operator==(const Capability& c) const
{
return (memcmp(this, &c, sizeof(Capability)) == 0);
}
inline bool operator!=(const Capability& c) const
{
return (memcmp(this, &c, sizeof(Capability)) != 0);
}
private:
private:
uint64_t _nwid;
int64_t _ts;
uint32_t _id;
@ -500,6 +522,6 @@ private:
} _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,15 +12,16 @@
/****/
#include "CertificateOfMembership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo)
CertificateOfMembership::CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo)
{
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = timestamp;
@ -36,34 +37,34 @@ CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t tim
// using the original COM format. Format may be revised in the future to make this cleaner.
uint64_t idHash[6];
issuedTo.publicKeyHash(idHash);
for(unsigned long i=0;i<4;++i) {
for (unsigned long i = 0; i < 4; ++i) {
_qualifiers[i + 3].id = (uint64_t)(i + 3);
_qualifiers[i + 3].value = Utils::ntoh(idHash[i]);
_qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL;
}
_qualifierCount = 7;
memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
memset(_signature.data, 0, ZT_C25519_SIGNATURE_LEN);
}
bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const
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) {
std::map<uint64_t, uint64_t> otherFields;
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) {
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));
std::map<uint64_t, uint64_t>::iterator otherQ(otherFields.find(qid));
if (otherQ == otherFields.end()) {
return false;
}
@ -79,8 +80,8 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
if (fullIdentityVerification) {
uint64_t idHash[6];
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)));
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()) {
return false;
}
@ -93,46 +94,47 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, c
return true;
}
bool CertificateOfMembership::sign(const Identity &with)
bool CertificateOfMembership::sign(const Identity& with)
{
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
buf[ptr++] = Utils::hton(_qualifiers[i].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
}
try {
_signature = with.sign(buf,ptr * sizeof(uint64_t));
_signature = with.sign(buf, ptr * sizeof(uint64_t));
_signedBy = with.address();
return true;
} catch ( ... ) {
}
catch (...) {
_signedBy.zero();
return false;
}
}
int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const
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) {
RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);
const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (! id) {
RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1;
}
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
buf[ptr++] = Utils::hton(_qualifiers[i].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
}
return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
return (id.verify(buf, ptr * sizeof(uint64_t), _signature) ? 0 : -1);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,21 +14,20 @@
#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
#define ZT_CERTIFICATEOFMEMBERSHIP_HPP
#include <stdint.h>
#include <string.h>
#include <string>
#include <stdexcept>
#include <algorithm>
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <string.h>
#include <string>
/**
* Maximum number of qualifiers allowed in a COM (absolute max: 65535)
*/
@ -64,10 +63,12 @@ class RuntimeEnvironment;
* This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks.
*/
class CertificateOfMembership : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; }
class CertificateOfMembership : public Credential {
public:
static inline Credential::Type credentialType()
{
return Credential::CREDENTIAL_TYPE_COM;
}
/**
* Reserved qualifier IDs
@ -78,8 +79,7 @@ public:
* Addition of new required fields requires that code in hasRequiredFields
* be updated as well.
*/
enum ReservedId
{
enum ReservedId {
/**
* Timestamp of certificate
*/
@ -101,8 +101,9 @@ public:
/**
* Create an empty certificate of membership
*/
CertificateOfMembership() :
_qualifierCount(0) {}
CertificateOfMembership() : _qualifierCount(0)
{
}
/**
* Create from required fields common to all networks
@ -112,7 +113,7 @@ public:
* @param nwid Network ID
* @param issuedTo Certificate recipient
*/
CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo);
CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo);
/**
* Create from binary-serialized COM in buffer
@ -120,28 +121,33 @@ public:
* @param b Buffer to deserialize from
* @param startAt Position to start in buffer
*/
template<unsigned int C>
CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> CertificateOfMembership(const Buffer<C>& b, unsigned int startAt = 0)
{
deserialize(b,startAt);
deserialize(b, startAt);
}
/**
* @return True if there's something here
*/
inline operator bool() const { return (_qualifierCount != 0); }
inline operator bool() const
{
return (_qualifierCount != 0);
}
/**
* @return Credential ID, always 0 for COMs
*/
inline uint32_t id() const { return 0; }
inline uint32_t id() const
{
return 0;
}
/**
* @return Timestamp for this cert and maximum delta for timestamp
*/
inline int64_t timestamp() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) {
return _qualifiers[i].value;
}
@ -154,7 +160,7 @@ public:
*/
inline Address issuedTo() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) {
return Address(_qualifiers[i].value);
}
@ -167,7 +173,7 @@ public:
*/
inline uint64_t networkId() const
{
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) {
return _qualifiers[i].value;
}
@ -189,7 +195,7 @@ public:
* @param otherIdentity Identity of other node
* @return True if certs agree and 'other' may be communicated with
*/
bool agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const;
bool agreesWith(const CertificateOfMembership& other, const Identity& otherIdentity) const;
/**
* Sign this certificate
@ -197,7 +203,7 @@ public:
* @param with Identity to sign with, must include private key
* @return True if signature was successful
*/
bool sign(const Identity &with);
bool sign(const Identity& with);
/**
* Verify this COM and its signature
@ -206,36 +212,40 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
/**
* @return True if signed
*/
inline bool isSigned() const { return (_signedBy); }
inline bool isSigned() const
{
return (_signedBy);
}
/**
* @return Address that signed this certificate or null address if none
*/
inline const Address &signedBy() const { return _signedBy; }
inline const Address& signedBy() const
{
return _signedBy;
}
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
template <unsigned int C> inline void serialize(Buffer<C>& b) const
{
b.append((uint8_t)1);
b.append((uint16_t)_qualifierCount);
for(unsigned int i=0;i<_qualifierCount;++i) {
for (unsigned int i = 0; i < _qualifierCount; ++i) {
b.append(_qualifiers[i].id);
b.append(_qualifiers[i].value);
b.append(_qualifiers[i].maxDelta);
}
_signedBy.appendTo(b);
if (_signedBy) {
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
unsigned int p = startAt;
@ -249,11 +259,12 @@ public:
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) {
for (unsigned int i = 0; i < numq; ++i) {
const uint64_t qid = b.template at<uint64_t>(p);
if (qid < lastId) {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
} else {
}
else {
lastId = qid;
}
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
@ -262,23 +273,24 @@ public:
_qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16);
p += 24;
++_qualifierCount;
} else {
}
else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
}
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (_signedBy) {
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
}
return (p - startAt);
}
inline bool operator==(const CertificateOfMembership &c) const
inline bool operator==(const CertificateOfMembership& c) const
{
if (_signedBy != c._signedBy) {
return false;
@ -286,25 +298,32 @@ public:
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)) {
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)) {
return false;
}
}
return (memcmp(_signature.data,c._signature.data,ZT_C25519_SIGNATURE_LEN) == 0);
return (memcmp(_signature.data, c._signature.data, ZT_C25519_SIGNATURE_LEN) == 0);
}
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
private:
struct _Qualifier
inline bool operator!=(const CertificateOfMembership& c) const
{
_Qualifier() : id(0),value(0),maxDelta(0) {}
return (! (*this == c));
}
private:
struct _Qualifier {
_Qualifier() : id(0), value(0), maxDelta(0)
{
}
uint64_t id;
uint64_t value;
uint64_t maxDelta;
inline bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order
inline bool operator<(const _Qualifier& q) const
{
return (id < q.id);
} // sort order
};
Address _signedBy;
@ -313,6 +332,6 @@ private:
C25519::Signature _signature;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,41 +12,43 @@
/****/
#include "CertificateOfOwnership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const
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);
const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (! id) {
RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1;
}
try {
Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
} catch ( ... ) {
this->serialize(tmp, true);
return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
}
catch (...) {
return -1;
}
}
bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const
bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing& t, const void* v, unsigned int l) const
{
for(unsigned int i=0,j=_thingCount;i<j;++i) {
for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
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;
@ -59,4 +61,4 @@ bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const
return false;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,20 +14,20 @@
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
#define ZT_CERTIFICATEOFOWNERSHIP_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp"
#include "Credential.hpp"
#include "C25519.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
// Max things per CertificateOfOwnership
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16
@ -41,84 +41,102 @@ class RuntimeEnvironment;
/**
* Certificate indicating ownership of a network identifier
*/
class CertificateOfOwnership : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
enum Thing
class CertificateOfOwnership : public Credential {
public:
static inline Credential::Type credentialType()
{
THING_NULL = 0,
THING_MAC_ADDRESS = 1,
THING_IPV4_ADDRESS = 2,
THING_IPV6_ADDRESS = 3
};
return Credential::CREDENTIAL_TYPE_COO;
}
enum Thing { THING_NULL = 0, THING_MAC_ADDRESS = 1, THING_IPV4_ADDRESS = 2, THING_IPV6_ADDRESS = 3 };
CertificateOfOwnership()
{
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
memset(reinterpret_cast<void*>(this), 0, sizeof(CertificateOfOwnership));
}
CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id)
CertificateOfOwnership(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id)
{
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
memset(reinterpret_cast<void*>(this), 0, sizeof(CertificateOfOwnership));
_networkId = nwid;
_ts = ts;
_id = id;
_issuedTo = issuedTo;
}
inline uint64_t networkId() const { return _networkId; }
inline int64_t timestamp() const { return _ts; }
inline uint32_t id() const { return _id; }
inline unsigned int thingCount() const { return (unsigned int)_thingCount; }
inline uint64_t networkId() const
{
return _networkId;
}
inline int64_t timestamp() const
{
return _ts;
}
inline uint32_t id() const
{
return _id;
}
inline unsigned int thingCount() const
{
return (unsigned int)_thingCount;
}
inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; }
inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; }
inline Thing thingType(const unsigned int i) const
{
return (Thing)_thingTypes[i];
}
inline const uint8_t* thingValue(const unsigned int i) const
{
return _thingValues[i];
}
inline const Address &issuedTo() const { return _issuedTo; }
inline const Address& issuedTo() const
{
return _issuedTo;
}
inline bool owns(const InetAddress &ip) const
inline bool owns(const InetAddress& ip) const
{
if (ip.ss_family == AF_INET) {
return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
return this->_owns(THING_IPV4_ADDRESS, &(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr), 4);
}
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 this->_owns(THING_IPV6_ADDRESS, reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr, 16);
}
return false;
}
inline bool owns(const MAC &mac) const
inline bool owns(const MAC& mac) const
{
uint8_t tmp[6];
mac.copyTo(tmp,6);
return this->_owns(THING_MAC_ADDRESS,tmp,6);
mac.copyTo(tmp, 6);
return this->_owns(THING_MAC_ADDRESS, tmp, 6);
}
inline void addThing(const InetAddress &ip)
inline void addThing(const InetAddress& ip)
{
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);
memcpy(_thingValues[_thingCount], &(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr), 4);
++_thingCount;
} else if (ip.ss_family == AF_INET6) {
}
else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
memcpy(_thingValues[_thingCount], reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr, 16);
++_thingCount;
}
}
inline void addThing(const MAC &mac)
inline void addThing(const MAC& mac)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
return;
}
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
mac.copyTo(_thingValues[_thingCount],6);
mac.copyTo(_thingValues[_thingCount], 6);
++_thingCount;
}
@ -126,13 +144,13 @@ public:
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
inline bool sign(const Identity& signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
this->serialize(tmp, true);
_signature = signer.sign(tmp.data(), tmp.size());
return true;
}
return false;
@ -143,10 +161,9 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
@ -157,28 +174,27 @@ public:
b.append(_flags);
b.append(_id);
b.append((uint16_t)_thingCount);
for(unsigned int i=0,j=_thingCount;i<j;++i) {
for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
b.append((uint8_t)_thingTypes[i]);
b.append(_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
b.append(_thingValues[i], ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
}
_issuedTo.appendTo(b);
_signedBy.appendTo(b);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature
b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
}
b.append((uint16_t)0); // length of additional fields, currently 0
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
unsigned int p = startAt;
@ -194,26 +210,27 @@ public:
p += 4;
_thingCount = b.template at<uint16_t>(p);
p += 2;
for(unsigned int i=0,j=_thingCount;i<j;++i) {
for (unsigned int i = 0, j = _thingCount; i < j; ++i) {
if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
_thingTypes[i] = (uint8_t)b[p++];
memcpy(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
memcpy(_thingValues[i], b.field(p, ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE), ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
}
}
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),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);
_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) {
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);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
}
else {
p += 2 + b.template at<uint16_t>(p);
}
@ -226,13 +243,22 @@ public:
}
// Provides natural sort order by ID
inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
inline bool operator<(const CertificateOfOwnership& coo) const
{
return (_id < coo._id);
}
inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); }
inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); }
inline bool operator==(const CertificateOfOwnership& coo) const
{
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) == 0);
}
inline bool operator!=(const CertificateOfOwnership& coo) const
{
return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) != 0);
}
private:
bool _owns(const Thing &t,const void *v,unsigned int l) const;
private:
bool _owns(const Thing& t, const void* v, unsigned int l) const;
uint64_t _networkId;
int64_t _ts;
@ -246,6 +272,6 @@ private:
C25519::Signature _signature;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -61,8 +61,8 @@
#ifdef ZT_SSO_SUPPORTED
#define ZT_SSO_ENABLED 1
#endif
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#include <TargetConditionals.h>
#ifndef __UNIX_LIKE__
#define __UNIX_LIKE__
@ -85,9 +85,9 @@
#endif
#include <machine/endian.h>
#ifndef __BYTE_ORDER
#define __BYTE_ORDER _BYTE_ORDER
#define __BYTE_ORDER _BYTE_ORDER
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
#define __BIG_ENDIAN _BIG_ENDIAN
#define __BIG_ENDIAN _BIG_ENDIAN
#endif
#endif
@ -106,25 +106,25 @@
#pragma warning(disable : 4101)
#undef __UNIX_LIKE__
#undef __BSD__
#include <winsock2.h>
#include <windows.h>
#include <winsock2.h>
#endif
#ifdef __NetBSD__
#ifndef RTF_MULTICAST
#define RTF_MULTICAST 0x20000000
#define RTF_MULTICAST 0x20000000
#endif
#endif
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#define ZT_ARCH_X64 1
#include <xmmintrin.h>
#include <emmintrin.h>
#include <immintrin.h>
#include <xmmintrin.h>
#endif
#if (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON))
#if (defined(__APPLE__) && !defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__))
#if (defined(__APPLE__) && ! defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__))
#ifdef ZT_ARCH_ARM_HAS_NEON
#undef ZT_ARCH_ARM_HAS_NEON
#endif
@ -145,7 +145,8 @@
#endif
// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64.
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#if (! (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) \
|| defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
#ifndef ZT_NO_TYPE_PUNNING
#define ZT_NO_TYPE_PUNNING 1
#endif
@ -157,23 +158,23 @@
#endif
// Assume little endian if not defined
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (! defined(__BYTE_ORDER))
#undef __BYTE_ORDER
#undef __LITTLE_ENDIAN
#undef __BIG_ENDIAN
#define __BIG_ENDIAN 4321
#define __BIG_ENDIAN 4321
#define __LITTLE_ENDIAN 1234
#define __BYTE_ORDER 1234
#define __BYTE_ORDER 1234
#endif
#ifdef __WINDOWS__
#define ZT_PATH_SEPARATOR '\\'
#define ZT_PATH_SEPARATOR '\\'
#define ZT_PATH_SEPARATOR_S "\\"
#define ZT_EOL_S "\r\n"
#define ZT_EOL_S "\r\n"
#else
#define ZT_PATH_SEPARATOR '/'
#define ZT_PATH_SEPARATOR '/'
#define ZT_PATH_SEPARATOR_S "/"
#define ZT_EOL_S "\n"
#define ZT_EOL_S "\n"
#endif
#ifndef __BYTE_ORDER
@ -182,10 +183,10 @@
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
#ifndef likely
#define likely(x) __builtin_expect((x),1)
#define likely(x) __builtin_expect((x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect((x),0)
#define unlikely(x) __builtin_expect((x), 0)
#endif
#else
#ifndef likely
@ -197,43 +198,43 @@
#endif
#ifdef __WINDOWS__
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
#define ZT_PACKED_STRUCT(D) __pragma(pack(push, 1)) D __pragma(pack(pop))
#else
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
#endif
#if defined(_WIN32)
#define ZT_PLATFORM_NAME "windows" // Windows
#define ZT_PLATFORM_NAME "windows" // Windows
#elif defined(_WIN64)
#define ZT_PLATFORM_NAME "windows" // Windows
#define ZT_PLATFORM_NAME "windows" // Windows
#elif defined(__CYGWIN__)
#define ZT_PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#define ZT_PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#elif defined(__ANDROID__)
#define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#elif defined(__linux__)
#define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
#define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || ! defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h>
#if defined(BSD)
#define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#endif
#elif defined(__hpux)
#define ZT_PLATFORM_NAME "hp-ux" // HP-UX
#define ZT_PLATFORM_NAME "hp-ux" // HP-UX
#elif defined(_AIX)
#define ZT_PLATFORM_NAME "aix" // IBM AIX
#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#define ZT_PLATFORM_NAME "aix" // IBM AIX
#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#include <TargetConditionals.h>
#if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR == 1
#define ZT_PLATFORM_NAME "ios_sim" // Apple iOS
#define ZT_PLATFORM_NAME "ios_sim" // Apple iOS
#elif defined(TARGET_OS_IPAD) && TARGET_OS_IPAD == 1
#define ZT_PLATFORM_NAME "ios_ipad"
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1
#define ZT_PLATFORM_NAME "ios_iphone" // Apple iOS
#define ZT_PLATFORM_NAME "ios_iphone" // Apple iOS
#elif defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1
#define ZT_PLATFORM_NAME "macos" // Apple OSX
#define ZT_PLATFORM_NAME "macos" // Apple OSX
#endif
#elif defined(__sun) && defined(__SVR4)
#define ZT_PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#define ZT_PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#else
#define ZT_PLATFORM_NAME "unknown"
#endif
@ -255,7 +256,7 @@
#define ZT_ARCH_NAME "mips"
#elif defined(__riscv) || defined(__riscv_xlen)
#define ZT_ARCH_NAME "riscv"
#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined (_M_PPC)
#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC)
#define ZT_ARCH_NAME "powerpc"
#elif defined(__s390__) || defined(__s390x__) || defined(__zarch__)
#define ZT_ARCH_NAME "s390"
@ -580,23 +581,23 @@
/**
* Drainage constants for VERB_ECHO rate-limiters
*/
#define ZT_ECHO_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_ECHO_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_ECHO_DRAINAGE_DIVISOR (1000 / ZT_ECHO_CUTOFF_LIMIT)
/**
* Drainage constants for VERB_QOS rate-limiters
*/
#define ZT_QOS_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_QOS_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS)
#define ZT_QOS_DRAINAGE_DIVISOR (1000 / ZT_QOS_CUTOFF_LIMIT)
/**
* Drainage constants for VERB_ACK rate-limiters
*/
#define ZT_ACK_CUTOFF_LIMIT 128
#define ZT_ACK_CUTOFF_LIMIT 128
#define ZT_ACK_DRAINAGE_DIVISOR (1000 / ZT_ACK_CUTOFF_LIMIT)
#define ZT_BOND_DEFAULT_REFRACTORY_PERIOD 8000
#define ZT_BOND_MAX_REFRACTORY_PERIOD 600000
#define ZT_BOND_MAX_REFRACTORY_PERIOD 600000
/**
* Maximum number of direct path pushes within cutoff time
@ -632,7 +633,6 @@
*/
#define ZT_PEER_GENERAL_RATE_LIMIT 1000
/**
* Minimum allowed amount of time between flow/path optimizations (anti-flapping)
*/
@ -709,8 +709,8 @@
* Artificially inflates the failover score for paths which meet
* certain non-performance-related policy ranking criteria.
*/
#define ZT_BOND_FAILOVER_HANDICAP_PREFERRED 500
#define ZT_BOND_FAILOVER_HANDICAP_PRIMARY 1000
#define ZT_BOND_FAILOVER_HANDICAP_PREFERRED 500
#define ZT_BOND_FAILOVER_HANDICAP_PRIMARY 1000
#define ZT_BOND_FAILOVER_HANDICAP_NEGOTIATED 5000
/**
@ -754,14 +754,14 @@
#define ZT_THREAD_MIN_STACK_SIZE 1048576
// Exceptions thrown in core ZT code
#define ZT_EXCEPTION_OUT_OF_BOUNDS 100
#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_OUT_OF_BOUNDS 100
#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
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203
#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203
#endif

View file

@ -14,39 +14,36 @@
#ifndef ZT_CREDENTIAL_HPP
#define ZT_CREDENTIAL_HPP
#include <string>
#include "Constants.hpp"
#include <memory>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "Constants.hpp"
#include <string>
namespace ZeroTier {
/**
* Base class for credentials
*/
class Credential
{
public:
class Credential {
public:
/**
* Do not change type code IDs -- these are used in Revocation objects and elsewhere
*/
enum Type
{
enum Type {
CREDENTIAL_TYPE_NULL = 0,
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
CREDENTIAL_TYPE_CAPABILITY = 2,
CREDENTIAL_TYPE_TAG = 3,
CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership
CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership
CREDENTIAL_TYPE_REVOCATION = 6
};
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -13,45 +13,43 @@
#ifndef ZT_DNS_HPP
#define ZT_DNS_HPP
#include "../include/ZeroTierOne.h"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "../include/ZeroTierOne.h"
namespace ZeroTier {
/**
* DNS data serialization methods
*/
class DNS {
public:
template<unsigned int C>
static inline void serializeDNS(Buffer<C> &b, const ZT_VirtualNetworkDNS *dns)
{
b.append(dns->domain, 128);
for(unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
InetAddress tmp(dns->server_addr[j]);
tmp.serialize(b);
}
}
public:
template <unsigned int C> static inline void serializeDNS(Buffer<C>& b, const ZT_VirtualNetworkDNS* dns)
{
b.append(dns->domain, 128);
for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
InetAddress tmp(dns->server_addr[j]);
tmp.serialize(b);
}
}
template<unsigned int C>
static inline void deserializeDNS(const Buffer<C> &b, unsigned int &p, ZT_VirtualNetworkDNS *dns)
{
char *d = (char*)b.data()+p;
memset(dns, 0, sizeof(ZT_VirtualNetworkDNS));
memcpy(dns->domain, d, 128);
dns->domain[127] = 0;
p += 128;
for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
p += reinterpret_cast<InetAddress *>(&(dns->server_addr[j]))->deserialize(b, p);
}
}
template <unsigned int C> static inline void deserializeDNS(const Buffer<C>& b, unsigned int& p, ZT_VirtualNetworkDNS* dns)
{
char* d = (char*)b.data() + p;
memset(dns, 0, sizeof(ZT_VirtualNetworkDNS));
memcpy(dns->domain, d, 128);
dns->domain[127] = 0;
p += 128;
for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
p += reinterpret_cast<InetAddress*>(&(dns->server_addr[j]))->deserialize(b, p);
}
}
};
}
} // namespace ZeroTier
#endif // ZT_DNS_HPP
#endif // ZT_DNS_HPP

View file

@ -14,10 +14,10 @@
#ifndef ZT_DICTIONARY_HPP
#define ZT_DICTIONARY_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include <stdint.h>
@ -45,36 +45,48 @@ namespace ZeroTier {
*
* @tparam C Dictionary max capacity in bytes
*/
template<unsigned int C>
class Dictionary
{
public:
Dictionary() { memset(_d,0,sizeof(_d)); }
Dictionary(const char *s) { this->load(s); }
Dictionary(const char *s,unsigned int len)
template <unsigned int C> class Dictionary {
public:
Dictionary()
{
for(unsigned int i=0;i<C;++i) {
if ((s)&&(i < len)) {
if (!(_d[i] = *s)) {
s = (const char *)0;
} else {
memset(_d, 0, sizeof(_d));
}
Dictionary(const char* s)
{
this->load(s);
}
Dictionary(const char* s, unsigned int len)
{
for (unsigned int i = 0; i < C; ++i) {
if ((s) && (i < len)) {
if (! (_d[i] = *s)) {
s = (const char*)0;
}
else {
++s;
}
} else {
}
else {
_d[i] = (char)0;
}
}
_d[C - 1] = (char)0;
}
Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); }
inline Dictionary &operator=(const Dictionary &d)
Dictionary(const Dictionary& d)
{
memcpy(_d,d._d,C);
memcpy(_d, d._d, C);
}
inline Dictionary& operator=(const Dictionary& d)
{
memcpy(_d, d._d, C);
return *this;
}
inline operator bool() const { return (_d[0] != 0); }
inline operator bool() const
{
return (_d[0] != 0);
}
/**
* Load a dictionary from a C-string
@ -82,21 +94,23 @@ public:
* @param s Dictionary in string form
* @return False if 's' was longer than our capacity
*/
inline bool load(const char *s)
inline bool load(const char* s)
{
for(unsigned int i=0;i<C;++i) {
for (unsigned int i = 0; i < C; ++i) {
if (s) {
if (!(_d[i] = *s)) {
s = (const char *)0;
} else {
if (! (_d[i] = *s)) {
s = (const char*)0;
}
else {
++s;
}
} else {
}
else {
_d[i] = (char)0;
}
}
_d[C - 1] = (char)0;
return (!s);
return (! s);
}
/**
@ -104,7 +118,7 @@ public:
*/
inline void clear()
{
memset(_d,0,sizeof(_d));
memset(_d, 0, sizeof(_d));
}
/**
@ -112,12 +126,12 @@ public:
*/
inline unsigned int sizeBytes() const
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i]) {
for (unsigned int i = 0; i < C; ++i) {
if (! _d[i]) {
return i;
}
}
return C-1;
return C - 1;
}
/**
@ -142,21 +156,21 @@ public:
* @param destlen Size of destination buffer
* @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
*/
inline int get(const char *key,char *dest,unsigned int destlen) const
inline int get(const char* key, char* dest, unsigned int destlen) const
{
const char *p = _d;
const char *const eof = p + C;
const char *k;
const char* p = _d;
const char* const eof = p + C;
const char* k;
bool esc;
int j;
if (!destlen) { // sanity check
if (! destlen) { // sanity check
return -1;
}
while (*p) {
k = key;
while ((*k)&&(*p)) {
while ((*k) && (*p)) {
if (*p != *k) {
break;
}
@ -167,14 +181,14 @@ public:
}
}
if ((!*k)&&(*p == '=')) {
if ((! *k) && (*p == '=')) {
j = 0;
esc = false;
++p;
while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
while ((*p != 0) && (*p != 13) && (*p != 10)) {
if (esc) {
esc = false;
switch(*p) {
switch (*p) {
case 'r':
dest[j++] = 13;
break;
@ -192,16 +206,18 @@ public:
break;
}
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
dest[j - 1] = (char)0;
return j - 1;
}
} else if (*p == '\\') {
}
else if (*p == '\\') {
esc = true;
} else {
}
else {
dest[j++] = *p;
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
dest[j - 1] = (char)0;
return j - 1;
}
}
if (++p == eof) {
@ -211,8 +227,9 @@ public:
}
dest[j] = (char)0;
return j;
} else {
while ((*p)&&(*p != 13)&&(*p != 10)) {
}
else {
while ((*p) && (*p != 13) && (*p != 10)) {
if (++p == eof) {
dest[0] = (char)0;
return -1;
@ -223,7 +240,8 @@ public:
dest[0] = (char)0;
return -1;
}
} else {
}
else {
break;
}
}
@ -241,14 +259,14 @@ public:
* @return True if key was found (if false, dest will be empty)
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
inline bool get(const char *key,Buffer<BC> &dest) const
template <unsigned int BC> inline bool get(const char* key, Buffer<BC>& dest) const
{
const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),BC);
const int r = this->get(key, const_cast<char*>(reinterpret_cast<const char*>(dest.data())), BC);
if (r >= 0) {
dest.setSize((unsigned int)r);
return true;
} else {
}
else {
dest.clear();
return false;
}
@ -261,11 +279,11 @@ public:
* @param dfl Default value if not found in dictionary
* @return Boolean value of key or 'dfl' if not found
*/
bool getB(const char *key,bool dfl = false) const
bool getB(const char* key, bool dfl = false) const
{
char tmp[4];
if (this->get(key,tmp,sizeof(tmp)) >= 0) {
return ((*tmp == '1')||(*tmp == 't')||(*tmp == 'T'));
if (this->get(key, tmp, sizeof(tmp)) >= 0) {
return ((*tmp == '1') || (*tmp == 't') || (*tmp == 'T'));
}
return dfl;
}
@ -277,10 +295,10 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
inline uint64_t getUI(const char *key,uint64_t dfl = 0) const
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;
@ -293,10 +311,10 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
inline int64_t getI(const char *key,int64_t dfl = 0) const
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;
@ -316,10 +334,10 @@ public:
* @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
* @return True if there was enough room to add this key=value pair
*/
inline bool add(const char *key,const char *value,int vlen = -1)
inline bool add(const char* key, const char* value, int vlen = -1)
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i]) {
for (unsigned int i = 0; i < C; ++i) {
if (! _d[i]) {
unsigned int j = i;
if (j > 0) {
@ -330,7 +348,7 @@ public:
}
}
const char *p = key;
const char* p = key;
while (*p) {
_d[j++] = *(p++);
if (j == C) {
@ -347,8 +365,8 @@ public:
p = value;
int k = 0;
while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
switch(*p) {
while (((vlen < 0) && (*p)) || (k < vlen)) {
switch (*p) {
case 0:
case 13:
case 10:
@ -359,7 +377,7 @@ public:
_d[i] = (char)0;
return false;
}
switch(*p) {
switch (*p) {
case 0:
_d[j++] = '0';
break;
@ -404,41 +422,42 @@ public:
/**
* Add a boolean as a '1' or a '0'
*/
inline bool add(const char *key,bool value)
inline bool add(const char* key, bool value)
{
return this->add(key,(value) ? "1" : "0",1);
return this->add(key, (value) ? "1" : "0", 1);
}
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,uint64_t value)
inline bool add(const char* key, uint64_t value)
{
char tmp[32];
return this->add(key,Utils::hex(value,tmp),-1);
return this->add(key, Utils::hex(value, tmp), -1);
}
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,int64_t value)
inline bool add(const char* key, int64_t value)
{
char tmp[32];
if (value >= 0) {
return this->add(key,Utils::hex((uint64_t)value,tmp),-1);
} else {
return this->add(key, Utils::hex((uint64_t)value, tmp), -1);
}
else {
tmp[0] = '-';
return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1);
return this->add(key, Utils::hex((uint64_t)(value * -1), tmp + 1), -1);
}
}
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,const Address &a)
inline bool add(const char* key, const Address& a)
{
char tmp[32];
return this->add(key,Utils::hex(a.toInt(),tmp),-1);
return this->add(key, Utils::hex(a.toInt(), tmp), -1);
}
/**
@ -446,34 +465,42 @@ public:
*
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
inline bool add(const char *key,const Buffer<BC> &value)
template <unsigned int BC> inline bool add(const char* key, const Buffer<BC>& value)
{
return this->add(key,(const char *)value.data(),(int)value.size());
return this->add(key, (const char*)value.data(), (int)value.size());
}
/**
* @param key Key to check
* @return True if key is present
*/
inline bool contains(const char *key) const
inline bool contains(const char* key) const
{
char tmp[2];
return (this->get(key,tmp,2) >= 0);
return (this->get(key, tmp, 2) >= 0);
}
/**
* @return Value of C template parameter
*/
inline unsigned int capacity() const { return C; }
inline unsigned int capacity() const
{
return C;
}
inline const char *data() const { return _d; }
inline char *unsafeData() { return _d; }
inline const char* data() const
{
return _d;
}
inline char* unsafeData()
{
return _d;
}
private:
private:
char _d[C];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -16,36 +16,43 @@
#include "Constants.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdexcept>
#include <vector>
#include <utility>
#include <algorithm>
#include <vector>
namespace ZeroTier {
/**
* A minimal hash table implementation for the ZeroTier core
*/
template<typename K,typename V>
class Hashtable
{
private:
struct _Bucket
{
_Bucket(const K &k,const V &v) : k(k),v(v) {}
_Bucket(const K &k) : k(k),v() {}
_Bucket(const _Bucket &b) : k(b.k),v(b.v) {}
inline _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; }
template <typename K, typename V> class Hashtable {
private:
struct _Bucket {
_Bucket(const K& k, const V& v) : k(k), v(v)
{
}
_Bucket(const K& k) : k(k), v()
{
}
_Bucket(const _Bucket& b) : k(b.k), v(b.v)
{
}
inline _Bucket& operator=(const _Bucket& b)
{
k = b.k;
v = b.v;
return *this;
}
K k;
V v;
_Bucket *next; // must be set manually for each _Bucket
_Bucket* next; // must be set manually for each _Bucket
};
public:
public:
/**
* A simple forward iterator (different from STL)
*
@ -53,16 +60,12 @@ public:
* may rehash and invalidate the iterator. Note the erasing the key will destroy
* the targets of the pointers returned by next().
*/
class Iterator
{
public:
class Iterator {
public:
/**
* @param ht Hash table to iterate over
*/
Iterator(Hashtable &ht) :
_idx(0),
_ht(&ht),
_b(ht._t[0])
Iterator(Hashtable& ht) : _idx(0), _ht(&ht), _b(ht._t[0])
{
}
@ -71,9 +74,9 @@ public:
* @param vptr Pointer to set to point to next value
* @return True if kptr and vptr are set, false if no more entries
*/
inline bool next(K *&kptr,V *&vptr)
inline bool next(K*& kptr, V*& vptr)
{
for(;;) {
for (;;) {
if (_b) {
kptr = &(_b->k);
vptr = &(_b->v);
@ -88,44 +91,38 @@ public:
}
}
private:
private:
unsigned long _idx;
Hashtable *_ht;
_Bucket *_b;
Hashtable* _ht;
_Bucket* _b;
};
//friend class Hashtable<K,V>::Iterator;
// friend class Hashtable<K,V>::Iterator;
/**
* @param bc Initial capacity in buckets (default: 64, must be nonzero)
*/
Hashtable(unsigned long bc = 64) :
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
_bc(bc),
_s(0)
Hashtable(unsigned long bc = 64) : _t(reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * bc))), _bc(bc), _s(0)
{
if (!_t) {
if (! _t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY;
}
for(unsigned long i=0;i<bc;++i) {
_t[i] = (_Bucket *)0;
for (unsigned long i = 0; i < bc; ++i) {
_t[i] = (_Bucket*)0;
}
}
Hashtable(const Hashtable<K,V> &ht) :
_t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * ht._bc))),
_bc(ht._bc),
_s(ht._s)
Hashtable(const Hashtable<K, V>& ht) : _t(reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * ht._bc))), _bc(ht._bc), _s(ht._s)
{
if (!_t) {
if (! _t) {
throw ZT_EXCEPTION_OUT_OF_MEMORY;
}
for(unsigned long i=0;i<_bc;++i) {
_t[i] = (_Bucket *)0;
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];
for (unsigned long i = 0; i < _bc; ++i) {
const _Bucket* b = ht._t[i];
while (b) {
_Bucket *nb = new _Bucket(*b);
_Bucket* nb = new _Bucket(*b);
nb->next = _t[i];
_t[i] = nb;
b = b->next;
@ -139,14 +136,14 @@ public:
::free(_t);
}
inline Hashtable &operator=(const Hashtable<K,V> &ht)
inline Hashtable& operator=(const Hashtable<K, V>& ht)
{
this->clear();
if (ht._s) {
for(unsigned long i=0;i<ht._bc;++i) {
const _Bucket *b = ht._t[i];
for (unsigned long i = 0; i < ht._bc; ++i) {
const _Bucket* b = ht._t[i];
while (b) {
this->set(b->k,b->v);
this->set(b->k, b->v);
b = b->next;
}
}
@ -160,14 +157,14 @@ public:
inline void clear()
{
if (_s) {
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
_Bucket *const nb = b->next;
_Bucket* const nb = b->next;
delete b;
b = nb;
}
_t[i] = (_Bucket *)0;
_t[i] = (_Bucket*)0;
}
_s = 0;
}
@ -181,8 +178,8 @@ public:
typename std::vector<K> k;
if (_s) {
k.reserve(_s);
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
k.push_back(b->k);
b = b->next;
@ -198,12 +195,11 @@ public:
* @param v Vector, list, or other compliant container
* @tparam Type of V (generally inferred)
*/
template<typename C>
inline void appendKeys(C &v) const
template <typename C> inline void appendKeys(C& v) const
{
if (_s) {
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
v.push_back(b->k);
b = b->next;
@ -215,15 +211,15 @@ public:
/**
* @return Vector of all entries (pairs of K,V)
*/
inline typename std::vector< std::pair<K,V> > entries() const
inline typename std::vector<std::pair<K, V> > entries() const
{
typename std::vector< std::pair<K,V> > k;
typename std::vector<std::pair<K, V> > k;
if (_s) {
k.reserve(_s);
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
k.push_back(std::pair<K,V>(b->k,b->v));
k.push_back(std::pair<K, V>(b->k, b->v));
b = b->next;
}
}
@ -235,27 +231,30 @@ public:
* @param k Key
* @return Pointer to value or NULL if not found
*/
inline V *get(const K &k)
inline V* get(const K& k)
{
_Bucket *b = _t[_hc(k) % _bc];
_Bucket* b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k) {
return &(b->v);
}
b = b->next;
}
return (V *)0;
return (V*)0;
}
inline const V* get(const K& k) const
{
return const_cast<Hashtable*>(this)->get(k);
}
inline const V *get(const K &k) const { return const_cast<Hashtable *>(this)->get(k); }
/**
* @param k Key
* @param v Value to fill with result
* @return True if value was found and set (if false, v is not modified)
*/
inline bool get(const K &k,V &v) const
inline bool get(const K& k, V& v) const
{
_Bucket *b = _t[_hc(k) % _bc];
_Bucket* b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k) {
v = b->v;
@ -270,9 +269,9 @@ public:
* @param k Key to check
* @return True if key is present
*/
inline bool contains(const K &k) const
inline bool contains(const K& k) const
{
_Bucket *b = _t[_hc(k) % _bc];
_Bucket* b = _t[_hc(k) % _bc];
while (b) {
if (b->k == k) {
return true;
@ -286,16 +285,17 @@ public:
* @param k Key
* @return True if value was present
*/
inline bool erase(const K &k)
inline bool erase(const K& k)
{
const unsigned long bidx = _hc(k) % _bc;
_Bucket *lastb = (_Bucket *)0;
_Bucket *b = _t[bidx];
_Bucket* lastb = (_Bucket*)0;
_Bucket* b = _t[bidx];
while (b) {
if (b->k == k) {
if (lastb) {
lastb->next = b->next;
} else {
}
else {
_t[bidx] = b->next;
}
delete b;
@ -313,12 +313,12 @@ public:
* @param v Value
* @return Reference to value in table
*/
inline V &set(const K &k,const V &v)
inline V& set(const K& k, const V& v)
{
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx];
_Bucket* b = _t[bidx];
while (b) {
if (b->k == k) {
b->v = v;
@ -332,7 +332,7 @@ public:
bidx = h % _bc;
}
b = new _Bucket(k,v);
b = new _Bucket(k, v);
b->next = _t[bidx];
_t[bidx] = b;
++_s;
@ -343,12 +343,12 @@ public:
* @param k Key
* @return Value, possibly newly created
*/
inline V &operator[](const K &k)
inline V& operator[](const K& k)
{
const unsigned long h = _hc(k);
unsigned long bidx = h % _bc;
_Bucket *b = _t[bidx];
_Bucket* b = _t[bidx];
while (b) {
if (b->k == k) {
return b->v;
@ -371,22 +371,27 @@ public:
/**
* @return Number of entries
*/
inline unsigned long size() const { return _s; }
inline unsigned long size() const
{
return _s;
}
/**
* @return True if table is empty
*/
inline bool empty() const { return (_s == 0); }
inline bool empty() const
{
return (_s == 0);
}
private:
template<typename O>
static inline unsigned long _hc(const O &obj)
private:
template <typename O> static inline unsigned long _hc(const O& obj)
{
return (unsigned long)obj.hashCode();
}
static inline unsigned long _hc(const uint64_t i)
{
return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses
return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses
}
static inline unsigned long _hc(const uint32_t i)
{
@ -404,15 +409,15 @@ private:
inline void _grow()
{
const unsigned long nc = _bc * 2;
_Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc));
_Bucket** nt = reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * nc));
if (nt) {
for(unsigned long i=0;i<nc;++i) {
nt[i] = (_Bucket *)0;
for (unsigned long i = 0; i < nc; ++i) {
nt[i] = (_Bucket*)0;
}
for(unsigned long i=0;i<_bc;++i) {
_Bucket *b = _t[i];
for (unsigned long i = 0; i < _bc; ++i) {
_Bucket* b = _t[i];
while (b) {
_Bucket *const nb = b->next;
_Bucket* const nb = b->next;
const unsigned long nidx = _hc(b->k) % nc;
b->next = nt[nidx];
nt[nidx] = b;
@ -425,11 +430,11 @@ private:
}
}
_Bucket **_t;
_Bucket** _t;
unsigned long _bc;
unsigned long _s;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,94 +11,98 @@
*/
/****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Identity.hpp"
#include "Constants.hpp"
#include "Identity.hpp"
#include "SHA512.hpp"
#include "Salsa20.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// These can't be changed without a new identity type. They define the
// parameters of the hashcash hashing/searching algorithm.
#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17
#define ZT_IDENTITY_GEN_MEMORY 2097152
#define ZT_IDENTITY_GEN_MEMORY 2097152
namespace ZeroTier {
// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing
static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem)
static inline void _computeMemoryHardHash(const void* publicKey, unsigned int publicKeyBytes, void* digest, void* genmem)
{
// Digest publicKey[] to obtain initial digest
SHA512(digest,publicKey,publicKeyBytes);
SHA512(digest, publicKey, publicKeyBytes);
// Initialize genmem[] using Salsa20 in a CBC-like configuration since
// ordinary Salsa20 is randomly seek-able. This is good for a cipher
// but is not what we want for sequential memory-hardness.
memset(genmem,0,ZT_IDENTITY_GEN_MEMORY);
Salsa20 s20(digest,(char *)digest + 32);
s20.crypt20((char *)genmem,(char *)genmem,64);
for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) {
memset(genmem, 0, ZT_IDENTITY_GEN_MEMORY);
Salsa20 s20(digest, (char*)digest + 32);
s20.crypt20((char*)genmem, (char*)genmem, 64);
for (unsigned long i = 64; i < ZT_IDENTITY_GEN_MEMORY; i += 64) {
unsigned long k = i - 64;
*((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k));
*((uint64_t *)((char *)genmem + i + 8)) = *((uint64_t *)((char *)genmem + k + 8));
*((uint64_t *)((char *)genmem + i + 16)) = *((uint64_t *)((char *)genmem + k + 16));
*((uint64_t *)((char *)genmem + i + 24)) = *((uint64_t *)((char *)genmem + k + 24));
*((uint64_t *)((char *)genmem + i + 32)) = *((uint64_t *)((char *)genmem + k + 32));
*((uint64_t *)((char *)genmem + i + 40)) = *((uint64_t *)((char *)genmem + k + 40));
*((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48));
*((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56));
s20.crypt20((char *)genmem + i,(char *)genmem + i,64);
*((uint64_t*)((char*)genmem + i)) = *((uint64_t*)((char*)genmem + k));
*((uint64_t*)((char*)genmem + i + 8)) = *((uint64_t*)((char*)genmem + k + 8));
*((uint64_t*)((char*)genmem + i + 16)) = *((uint64_t*)((char*)genmem + k + 16));
*((uint64_t*)((char*)genmem + i + 24)) = *((uint64_t*)((char*)genmem + k + 24));
*((uint64_t*)((char*)genmem + i + 32)) = *((uint64_t*)((char*)genmem + k + 32));
*((uint64_t*)((char*)genmem + i + 40)) = *((uint64_t*)((char*)genmem + k + 40));
*((uint64_t*)((char*)genmem + i + 48)) = *((uint64_t*)((char*)genmem + k + 48));
*((uint64_t*)((char*)genmem + i + 56)) = *((uint64_t*)((char*)genmem + k + 56));
s20.crypt20((char*)genmem + i, (char*)genmem + i, 64);
}
// Render final digest using genmem as a lookup table
for(unsigned long i=0;i<(ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) {
unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (64 / sizeof(uint64_t)));
unsigned long idx2 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t)));
uint64_t tmp = ((uint64_t *)genmem)[idx2];
((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1];
((uint64_t *)digest)[idx1] = tmp;
s20.crypt20(digest,digest,64);
for (unsigned long i = 0; i < (ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) {
unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (64 / sizeof(uint64_t)));
unsigned long idx2 = (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t)));
uint64_t tmp = ((uint64_t*)genmem)[idx2];
((uint64_t*)genmem)[idx2] = ((uint64_t*)digest)[idx1];
((uint64_t*)digest)[idx1] = tmp;
s20.crypt20(digest, digest, 64);
}
}
// Hashcash generation halting condition -- halt when first byte is less than
// threshold value.
struct _Identity_generate_cond
{
_Identity_generate_cond() {}
_Identity_generate_cond(unsigned char *sb,char *gm) : digest(sb),genmem(gm) {}
inline bool operator()(const C25519::Pair &kp) const
struct _Identity_generate_cond {
_Identity_generate_cond()
{
_computeMemoryHardHash(kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
}
_Identity_generate_cond(unsigned char* sb, char* gm) : digest(sb), genmem(gm)
{
}
inline bool operator()(const C25519::Pair& kp) const
{
_computeMemoryHardHash(kp.pub.data, ZT_C25519_PUBLIC_KEY_LEN, digest, genmem);
return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN);
}
unsigned char *digest;
char *genmem;
unsigned char* digest;
char* genmem;
};
void Identity::generate()
{
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
char* genmem = new char[ZT_IDENTITY_GEN_MEMORY];
C25519::Pair kp;
do {
kp = C25519::generateSatisfying(_Identity_generate_cond(digest,genmem));
_address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
kp = C25519::generateSatisfying(_Identity_generate_cond(digest, genmem));
_address.setTo(digest + 59, ZT_ADDRESS_LENGTH); // last 5 bytes are address
} while (_address.isReserved());
_publicKey = kp.pub;
if (!_privateKey) {
if (! _privateKey) {
_privateKey = new C25519::Private();
}
*_privateKey = kp.priv;
delete [] genmem;
delete[] genmem;
}
bool Identity::locallyValidate() const
@ -108,60 +112,54 @@ bool Identity::locallyValidate() const
}
unsigned char digest[64];
char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,digest,genmem);
delete [] genmem;
char* genmem = new char[ZT_IDENTITY_GEN_MEMORY];
_computeMemoryHardHash(_publicKey.data, ZT_C25519_PUBLIC_KEY_LEN, digest, genmem);
delete[] genmem;
unsigned char addrb[5];
_address.copyTo(addrb,5);
_address.copyTo(addrb, 5);
return (
(digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
(digest[59] == addrb[0])&&
(digest[60] == addrb[1])&&
(digest[61] == addrb[2])&&
(digest[62] == addrb[3])&&
(digest[63] == addrb[4]));
return ((digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN) && (digest[59] == addrb[0]) && (digest[60] == addrb[1]) && (digest[61] == addrb[2]) && (digest[62] == addrb[3]) && (digest[63] == addrb[4]));
}
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
char* Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{
char *p = buf;
Utils::hex10(_address.toInt(),p);
char* p = buf;
Utils::hex10(_address.toInt(), p);
p += 10;
*(p++) = ':';
*(p++) = '0';
*(p++) = ':';
Utils::hex(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN,p);
Utils::hex(_publicKey.data, ZT_C25519_PUBLIC_KEY_LEN, p);
p += ZT_C25519_PUBLIC_KEY_LEN * 2;
if ((_privateKey)&&(includePrivate)) {
if ((_privateKey) && (includePrivate)) {
*(p++) = ':';
Utils::hex(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN,p);
Utils::hex(_privateKey->data, ZT_C25519_PRIVATE_KEY_LEN, p);
p += ZT_C25519_PRIVATE_KEY_LEN * 2;
}
*p = (char)0;
return buf;
}
bool Identity::fromString(const char *str)
bool Identity::fromString(const char* str)
{
if (!str) {
if (! str) {
_address.zero();
return false;
}
char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH];
if (!Utils::scopy(tmp,sizeof(tmp),str)) {
if (! Utils::scopy(tmp, sizeof(tmp), str)) {
_address.zero();
return false;
}
delete _privateKey;
_privateKey = (C25519::Private *)0;
_privateKey = (C25519::Private*)0;
int fno = 0;
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) {
switch(fno++) {
char* saveptr = (char*)0;
for (char* f = Utils::stok(tmp, ":", &saveptr); (f); f = Utils::stok((char*)0, ":", &saveptr)) {
switch (fno++) {
case 0:
_address = Address(Utils::hexStrToU64(f));
if (_address.isReserved()) {
@ -170,20 +168,20 @@ bool Identity::fromString(const char *str)
}
break;
case 1:
if ((f[0] != '0')||(f[1])) {
if ((f[0] != '0') || (f[1])) {
_address.zero();
return false;
}
break;
case 2:
if (Utils::unhex(f,_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
if (Utils::unhex(f, _publicKey.data, ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) {
_address.zero();
return false;
}
break;
case 3:
_privateKey = new C25519::Private();
if (Utils::unhex(f,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
if (Utils::unhex(f, _privateKey->data, ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) {
_address.zero();
return false;
}
@ -201,4 +199,4 @@ bool Identity::fromString(const char *str)
return true;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,16 +14,16 @@
#ifndef ZT_IDENTITY_HPP
#define ZT_IDENTITY_HPP
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "SHA512.hpp"
#include "Utils.hpp"
#include <stdio.h>
#include <stdlib.h>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Buffer.hpp"
#include "SHA512.hpp"
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 384
namespace ZeroTier {
@ -38,56 +38,49 @@ namespace ZeroTier {
* search for a different public key that duplicates an existing address. (See
* code for deriveAddress() for this algorithm.)
*/
class Identity
{
public:
Identity() :
_privateKey((C25519::Private *)0)
class Identity {
public:
Identity() : _privateKey((C25519::Private*)0)
{
}
Identity(const Identity &id) :
_address(id._address),
_publicKey(id._publicKey),
_privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private *)0)
Identity(const Identity& id) : _address(id._address), _publicKey(id._publicKey), _privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private*)0)
{
}
Identity(const char *str) :
_privateKey((C25519::Private *)0)
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>
Identity(const Buffer<C> &b,unsigned int startAt = 0) :
_privateKey((C25519::Private *)0)
template <unsigned int C> Identity(const Buffer<C>& b, unsigned int startAt = 0) : _privateKey((C25519::Private*)0)
{
deserialize(b,startAt);
deserialize(b, startAt);
}
~Identity()
{
if (_privateKey) {
Utils::burn(_privateKey,sizeof(C25519::Private));
Utils::burn(_privateKey, sizeof(C25519::Private));
delete _privateKey;
}
}
inline Identity &operator=(const Identity &id)
inline Identity& operator=(const Identity& id)
{
_address = id._address;
_publicKey = id._publicKey;
if (id._privateKey) {
if (!_privateKey) {
if (! _privateKey) {
_privateKey = new C25519::Private();
}
*_privateKey = *(id._privateKey);
} else {
}
else {
delete _privateKey;
_privateKey = (C25519::Private *)0;
_privateKey = (C25519::Private*)0;
}
return *this;
}
@ -109,14 +102,17 @@ public:
/**
* @return True if this identity contains a private key
*/
inline bool hasPrivate() const { return (_privateKey != (C25519::Private *)0); }
inline bool hasPrivate() const
{
return (_privateKey != (C25519::Private*)0);
}
/**
* Compute a SHA384 hash of this identity's address and public key(s).
*
*
* @param sha384buf Buffer with 48 bytes of space to receive hash
*/
inline void publicKeyHash(void *sha384buf) const
inline void publicKeyHash(void* sha384buf) const
{
uint8_t address[ZT_ADDRESS_LENGTH];
_address.copyTo(address, ZT_ADDRESS_LENGTH);
@ -129,10 +125,10 @@ public:
* @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length)
* @return True on success, false if no private key
*/
inline bool sha512PrivateKey(void *sha) const
inline bool sha512PrivateKey(void* sha) const
{
if (_privateKey) {
SHA512(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
SHA512(sha, _privateKey->data, ZT_C25519_PRIVATE_KEY_LEN);
return true;
}
return false;
@ -144,10 +140,10 @@ public:
* @param data Data to sign
* @param len Length of data
*/
inline C25519::Signature sign(const void *data,unsigned int len) const
inline C25519::Signature sign(const void* data, unsigned int len) const
{
if (_privateKey) {
return C25519::sign(*_privateKey,_publicKey,data,len);
return C25519::sign(*_privateKey, _publicKey, data, len);
}
throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED;
}
@ -161,12 +157,12 @@ public:
* @param siglen Length of signature in bytes
* @return True if signature validates and data integrity checks
*/
inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const
inline bool verify(const void* data, unsigned int len, const void* signature, unsigned int siglen) const
{
if (siglen != ZT_C25519_SIGNATURE_LEN) {
return false;
}
return C25519::verify(_publicKey,data,len,signature);
return C25519::verify(_publicKey, data, len, signature);
}
/**
@ -177,9 +173,9 @@ public:
* @param signature Signature
* @return True if signature validates and data integrity checks
*/
inline bool verify(const void *data,unsigned int len,const C25519::Signature &signature) const
inline bool verify(const void* data, unsigned int len, const C25519::Signature& signature) const
{
return C25519::verify(_publicKey,data,len,signature);
return C25519::verify(_publicKey, data, len, signature);
}
/**
@ -191,10 +187,10 @@ public:
* @param key Result parameter to fill with key bytes
* @return Was agreement successful?
*/
inline bool agree(const Identity &id,void *const key) const
inline bool agree(const Identity& id, void* const key) const
{
if (_privateKey) {
C25519::agree(*_privateKey,id._publicKey,key,ZT_SYMMETRIC_KEY_SIZE);
C25519::agree(*_privateKey, id._publicKey, key, ZT_SYMMETRIC_KEY_SIZE);
return true;
}
return false;
@ -203,7 +199,10 @@ public:
/**
* @return This identity's address
*/
inline const Address &address() const { return _address; }
inline const Address& address() const
{
return _address;
}
/**
* Serialize this identity (binary)
@ -212,16 +211,16 @@ public:
* @param includePrivate If true, include private key component (if present) (default: false)
* @throws std::out_of_range Buffer too small
*/
template<unsigned int C>
inline void serialize(Buffer<C> &b,bool includePrivate = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, bool includePrivate = false) const
{
_address.appendTo(b);
b.append((uint8_t)0); // C25519/Ed25519 identity type
b.append(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN);
if ((_privateKey)&&(includePrivate)) {
b.append((uint8_t)0); // C25519/Ed25519 identity type
b.append(_publicKey.data, ZT_C25519_PUBLIC_KEY_LEN);
if ((_privateKey) && (includePrivate)) {
b.append((unsigned char)ZT_C25519_PRIVATE_KEY_LEN);
b.append(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
} else {
b.append(_privateKey->data, ZT_C25519_PRIVATE_KEY_LEN);
}
else {
b.append((unsigned char)0);
}
}
@ -238,22 +237,21 @@ public:
* @throws std::out_of_range Serialized data invalid
* @throws std::invalid_argument Serialized data invalid
*/
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
delete _privateKey;
_privateKey = (C25519::Private *)0;
_privateKey = (C25519::Private*)0;
unsigned int p = startAt;
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
_address.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
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);
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++];
@ -262,7 +260,7 @@ public:
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);
memcpy(_privateKey->data, b.field(p, ZT_C25519_PRIVATE_KEY_LEN), ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
}
@ -276,7 +274,7 @@ public:
* @param buf Buffer to store string
* @return ASCII string representation of identity
*/
char *toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
char* toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
/**
* Deserialize a human-friendly string
@ -287,12 +285,15 @@ public:
* @param str String to deserialize
* @return True if deserialization appears successful
*/
bool fromString(const char *str);
bool fromString(const char* str);
/**
* @return C25519 public key
*/
inline const C25519::Public &publicKey() const { return _publicKey; }
inline const C25519::Public& publicKey() const
{
return _publicKey;
}
/**
* @return C25519 key pair (only returns valid pair if private key is present in this Identity object)
@ -303,8 +304,9 @@ public:
pair.pub = _publicKey;
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;
}
@ -312,21 +314,42 @@ public:
/**
* @return True if this identity contains something
*/
inline operator bool() const { return (_address); }
inline operator bool() const
{
return (_address);
}
inline bool operator==(const Identity &id) const { return ((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)); }
inline bool operator<(const Identity &id) const { return ((_address < id._address)||((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) < 0))); }
inline bool operator!=(const Identity &id) const { return !(*this == id); }
inline bool operator>(const Identity &id) const { return (id < *this); }
inline bool operator<=(const Identity &id) const { return !(id < *this); }
inline bool operator>=(const Identity &id) const { return !(*this < id); }
inline bool operator==(const Identity& id) const
{
return ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_C25519_PUBLIC_KEY_LEN) == 0));
}
inline bool operator<(const Identity& id) const
{
return ((_address < id._address) || ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_C25519_PUBLIC_KEY_LEN) < 0)));
}
inline bool operator!=(const Identity& id) const
{
return ! (*this == id);
}
inline bool operator>(const Identity& id) const
{
return (id < *this);
}
inline bool operator<=(const Identity& id) const
{
return ! (id < *this);
}
inline bool operator>=(const Identity& id) const
{
return ! (*this < id);
}
private:
private:
Address _address;
C25519::Public _publicKey;
C25519::Private *_privateKey;
C25519::Private* _privateKey;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,13 +14,13 @@
#ifndef ZT_INCOMINGPACKET_HPP
#define ZT_INCOMINGPACKET_HPP
#include <stdexcept>
#include "MulticastGroup.hpp"
#include "Packet.hpp"
#include "Path.hpp"
#include "Utils.hpp"
#include "MulticastGroup.hpp"
#include "Peer.hpp"
#include "Utils.hpp"
#include <stdexcept>
/*
* The big picture:
@ -46,14 +46,9 @@ class Network;
/**
* Subclass of packet that handles the decoding of it
*/
class IncomingPacket : public Packet
{
public:
IncomingPacket() :
Packet(),
_receiveTime(0),
_path(),
_authenticated(false)
class IncomingPacket : public Packet {
public:
IncomingPacket() : Packet(), _receiveTime(0), _path(), _authenticated(false)
{
}
@ -66,11 +61,7 @@ public:
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) :
Packet(data,len),
_receiveTime(now),
_path(path),
_authenticated(false)
IncomingPacket(const void* data, unsigned int len, const SharedPtr<Path>& path, int64_t now) : Packet(data, len), _receiveTime(now), _path(path), _authenticated(false)
{
}
@ -83,9 +74,9 @@ public:
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
inline void init(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now)
inline void init(const void* data, unsigned int len, const SharedPtr<Path>& path, int64_t now)
{
copyFrom(data,len);
copyFrom(data, len);
_receiveTime = now;
_path = path;
_authenticated = false;
@ -104,44 +95,47 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return True if decoding and processing is complete, false if caller should try again
*/
bool tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t flowId);
bool tryDecode(const RuntimeEnvironment* RR, void* tPtr, int32_t flowId);
/**
* @return Time of packet receipt / start of decode
*/
inline uint64_t receiveTime() const { return _receiveTime; }
inline uint64_t receiveTime() const
{
return _receiveTime;
}
private:
private:
// These are called internally to handle packet contents once it has
// been authenticated, decrypted, decompressed, and classified.
bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId);
bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId);
bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doERROR(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doHELLO(const RuntimeEnvironment* RR, void* tPtr, const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doOK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doWHOIS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doRENDEZVOUS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doFRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, int32_t flowId);
bool _doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, int32_t flowId);
bool _doECHO(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doNETWORK_CONFIG(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_GATHER(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doUSER_MESSAGE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doREMOTE_TRACE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer);
void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid);
void _sendErrorNeedCredentials(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, const uint64_t nwid);
uint64_t _receiveTime;
SharedPtr<Path> _path;
bool _authenticated;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,132 +11,132 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <string>
#include "InetAddress.hpp"
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
namespace ZeroTier {
const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,0);
const InetAddress InetAddress::LO6((const void *)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"),16,0);
const InetAddress InetAddress::LO4((const void*)("\x7f\x00\x00\x01"), 4, 0);
const InetAddress InetAddress::LO6((const void*)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0);
InetAddress::IpScope InetAddress::ipScope() const
{
switch(ss_family) {
switch (ss_family) {
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) {
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)
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)
return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a:
return IP_SCOPE_PRIVATE; // 10.0.0.0/8
return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b:
return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
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)
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)
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)
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)
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)
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)
return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e:
return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
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)
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)
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)
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
return IP_SCOPE_PRIVATE; // 100.64.0.0/10
}
break;
case 0x7f:
return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
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
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
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
return IP_SCOPE_PRIVATE; // 192.168.0.0/16
}
if ((ip & 0xffffff00) == 0xc0000200) {
return IP_SCOPE_PRIVATE; // 192.0.2.0/24
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
return IP_SCOPE_PRIVATE; // 198.18.0.0/15
}
if ((ip & 0xffffff00) == 0xc6336400) {
return IP_SCOPE_PRIVATE; // 198.51.100.0/24
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
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)
return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
}
switch(ip >> 28) {
switch (ip >> 28) {
case 0xe:
return IP_SCOPE_MULTICAST; // 224.0.0.0/4
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_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
}
return IP_SCOPE_GLOBAL;
} break;
} break;
case AF_INET6: {
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
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
return IP_SCOPE_MULTICAST; // ff00::/8
}
if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) {
if ((ip[0] == 0xfe) && ((ip[1] & 0xc0) == 0x80)) {
unsigned int k = 2;
while ((!ip[k])&&(k < 15)) {
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 ((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
return IP_SCOPE_PRIVATE; // fc00::/7
}
}
// :::ffff:127.0.0.1
// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1
unsigned int k = 0;
while ((!ip[k])&&(k < 9)) {
while ((! ip[k]) && (k < 9)) {
++k;
}
if (k == 9) {
@ -146,92 +146,92 @@ InetAddress::IpScope InetAddress::ipScope() const
}
k = 0;
while ((!ip[k])&&(k < 15)) {
while ((! ip[k]) && (k < 15)) {
++k;
}
if (k == 15) { // all 0's except last byte
if (k == 15) { // all 0's except last byte
if (ip[15] == 0x01) {
return IP_SCOPE_LOOPBACK; // ::1/128
return IP_SCOPE_LOOPBACK; // ::1/128
}
if (ip[15] == 0x00) {
return IP_SCOPE_NONE; // ::/128
return IP_SCOPE_NONE; // ::/128
}
}
return IP_SCOPE_GLOBAL;
} break;
} break;
}
return IP_SCOPE_NONE;
}
void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
void InetAddress::set(const void* ipBytes, unsigned int ipLen, unsigned int port)
{
memset(this,0,sizeof(InetAddress));
memset(this, 0, sizeof(InetAddress));
if (ipLen == 4) {
uint32_t ipb[1];
memcpy(ipb,ipBytes,4);
memcpy(ipb, ipBytes, 4);
ss_family = AF_INET;
reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr = ipb[0];
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
} else if (ipLen == 16) {
reinterpret_cast<struct sockaddr_in*>(this)->sin_addr.s_addr = ipb[0];
reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton((uint16_t)port);
}
else if (ipLen == 16) {
ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes,16);
reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
memcpy(reinterpret_cast<struct sockaddr_in6*>(this)->sin6_addr.s6_addr, ipBytes, 16);
reinterpret_cast<struct sockaddr_in6*>(this)->sin6_port = Utils::hton((uint16_t)port);
}
}
char *InetAddress::toString(char buf[64]) const
char* InetAddress::toString(char buf[64]) const
{
char *p = toIpString(buf);
char* p = toIpString(buf);
if (*p) {
while (*p) {
++p;
}
*(p++) = '/';
Utils::decimal(port(),p);
Utils::decimal(port(), p);
}
return buf;
}
char *InetAddress::toIpString(char buf[64]) const
char* InetAddress::toIpString(char buf[64]) const
{
buf[0] = (char)0;
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
#ifdef _WIN32
inet_ntop(AF_INET, (void*)&reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
inet_ntop(AF_INET, (void*)&reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#else
inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#endif
} break;
} break;
case AF_INET6: {
#ifdef _WIN32
inet_ntop(AF_INET6, (void*)reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, (void*)reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#else
inet_ntop(AF_INET6, reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#endif
} break;
} break;
}
return buf;
}
bool InetAddress::fromString(const char *ipSlashPort)
bool InetAddress::fromString(const char* ipSlashPort)
{
char buf[64];
memset(this,0,sizeof(InetAddress));
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 != '/')) {
char* portAt = buf;
while ((*portAt) && (*portAt != '/')) {
++portAt;
}
unsigned int port = 0;
@ -240,19 +240,21 @@ bool InetAddress::fromString(const char *ipSlashPort)
port = Utils::strToUInt(portAt) & 0xffff;
}
if (strchr(buf,':')) {
struct sockaddr_in6 *const in6 = reinterpret_cast<struct sockaddr_in6 *>(this);
if (strchr(buf, ':')) {
struct sockaddr_in6* const in6 = reinterpret_cast<struct sockaddr_in6*>(this);
inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr);
in6->sin6_family = AF_INET6;
in6->sin6_port = Utils::hton((uint16_t)port);
return true;
} else if (strchr(buf,'.')) {
struct sockaddr_in *const in = reinterpret_cast<struct sockaddr_in *>(this);
}
else if (strchr(buf, '.')) {
struct sockaddr_in* const in = reinterpret_cast<struct sockaddr_in*>(this);
inet_pton(AF_INET, buf, &in->sin_addr.s_addr);
in->sin_family = AF_INET;
in->sin_port = Utils::hton((uint16_t)port);
return true;
} else {
}
else {
return false;
}
}
@ -260,22 +262,23 @@ bool InetAddress::fromString(const char *ipSlashPort)
InetAddress InetAddress::netmask() const
{
InetAddress r(*this);
switch(r.ss_family) {
switch (r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
break;
case AF_INET6: {
uint64_t nm[2];
const unsigned int bits = netmaskBits();
if(bits) {
if (bits) {
nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
} else {
}
else {
nm[0] = 0;
nm[1] = 0;
}
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break;
}
return r;
}
@ -284,7 +287,7 @@ InetAddress InetAddress::broadcast() const
{
if (ss_family == AF_INET) {
InetAddress r(*this);
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
return r;
}
return InetAddress();
@ -293,34 +296,34 @@ InetAddress InetAddress::broadcast() const
InetAddress InetAddress::network() const
{
InetAddress r(*this);
switch(r.ss_family) {
switch (r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
break;
case AF_INET6: {
uint64_t nm[2];
const unsigned int bits = netmaskBits();
memcpy(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
memcpy(nm, reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, 16);
nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, nm, 16);
} break;
}
return r;
}
bool InetAddress::isEqualPrefix(const InetAddress &addr) const
bool InetAddress::isEqualPrefix(const InetAddress& addr) const
{
if (addr.ss_family == ss_family) {
switch(ss_family) {
switch (ss_family) {
case AF_INET6: {
const InetAddress mask(netmask());
InetAddress addr_mask(addr.netmask());
const uint8_t *n = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr_mask)->sin6_addr.s6_addr);
const uint8_t *m = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&mask)->sin6_addr.s6_addr);
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) {
const uint8_t* n = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&addr_mask)->sin6_addr.s6_addr);
const uint8_t* m = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&mask)->sin6_addr.s6_addr);
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])) {
return false;
}
@ -332,23 +335,24 @@ bool InetAddress::isEqualPrefix(const InetAddress &addr) const
return false;
}
bool InetAddress::containsAddress(const InetAddress &addr) const
bool InetAddress::containsAddress(const InetAddress& addr) const
{
if (addr.ss_family == ss_family) {
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
const unsigned int bits = netmaskBits();
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)) );
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: {
const InetAddress mask(netmask());
const uint8_t *m = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&mask)->sin6_addr.s6_addr);
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) {
const uint8_t* m = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&mask)->sin6_addr.s6_addr);
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]) {
return false;
}
@ -362,7 +366,7 @@ bool InetAddress::containsAddress(const InetAddress &addr) const
bool InetAddress::isNetwork() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
unsigned int bits = netmaskBits();
if (bits <= 0) {
@ -371,7 +375,7 @@ bool InetAddress::isNetwork() const
if (bits >= 32) {
return false;
}
uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
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: {
@ -382,7 +386,7 @@ bool InetAddress::isNetwork() const
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);
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) {
return false;
@ -398,55 +402,60 @@ bool InetAddress::isNetwork() const
return false;
}
bool InetAddress::operator==(const InetAddress &a) const
bool InetAddress::operator==(const InetAddress& a) const
{
if (ss_family == a.ss_family) {
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return (
(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port)&&
(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr));
(reinterpret_cast<const struct sockaddr_in*>(this)->sin_port == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_port)
&& (reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in*>(&a)->sin_addr.s_addr));
break;
case AF_INET6:
return (
(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port)&&
(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo)&&
(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)&&
(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_scope_id == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_scope_id));
(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_port)
&& (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_flowinfo)
&& (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)
&& (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_scope_id == reinterpret_cast<const struct sockaddr_in6*>(&a)->sin6_scope_id));
break;
default:
return (memcmp(this,&a,sizeof(InetAddress)) == 0);
return (memcmp(this, &a, sizeof(InetAddress)) == 0);
}
}
return false;
}
bool InetAddress::operator<(const InetAddress &a) const
bool InetAddress::operator<(const InetAddress& a) const
{
if (ss_family < a.ss_family) {
return true;
} else if (ss_family == a.ss_family) {
switch(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;
}
}
@ -454,13 +463,13 @@ bool InetAddress::operator<(const InetAddress &a) const
}
break;
default:
return (memcmp(this,&a,sizeof(InetAddress)) < 0);
return (memcmp(this, &a, sizeof(InetAddress)) < 0);
}
}
return false;
}
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
InetAddress InetAddress::makeIpv6LinkLocal(const MAC& mac)
{
struct sockaddr_in6 sin6;
sin6.sin6_family = AF_INET6;
@ -484,10 +493,10 @@ InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
return InetAddress(sin6);
}
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress)
{
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
struct sockaddr_in6* const sin6 = reinterpret_cast<struct sockaddr_in6*>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfd;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56);
@ -505,15 +514,15 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16);
sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8);
sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress;
sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that
sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that
return r;
}
InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress)
{
nwid ^= (nwid >> 32);
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
struct sockaddr_in6* const sin6 = reinterpret_cast<struct sockaddr_in6*>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfc;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24);
@ -530,4 +539,4 @@ InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
return r;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,15 +14,15 @@
#ifndef ZT_INETADDRESS_HPP
#define ZT_INETADDRESS_HPP
#include "../include/ZeroTierOne.h"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "MAC.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Utils.hpp"
#include "MAC.hpp"
#include "Buffer.hpp"
namespace ZeroTier {
@ -39,8 +39,7 @@ namespace ZeroTier {
* sockaddr_storage and used interchangeably. DO NOT change this by e.g.
* adding non-static fields, since much code depends on this identity.
*/
struct InetAddress : public sockaddr_storage
{
struct InetAddress : public sockaddr_storage {
/**
* Loopback IPv4 address (no port)
*/
@ -58,134 +57,177 @@ struct InetAddress : public sockaddr_storage
* MUST remain that way or Path must be changed to reflect. Also be sure
* to change ZT_INETADDRESS_MAX_SCOPE if the max changes.
*/
enum IpScope
{
IP_SCOPE_NONE = 0, // NULL or not an IP address
IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs
IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc.
IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted"
IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others)
IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL
IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges
IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
enum IpScope {
IP_SCOPE_NONE = 0, // NULL or not an IP address
IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs
IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc.
IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted"
IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others)
IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL
IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges
IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
};
// Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core
// but this is safe to put here.
struct Hasher
{
inline std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); }
struct Hasher {
inline std::size_t operator()(const InetAddress& a) const
{
return (std::size_t)a.hashCode();
}
};
InetAddress() { memset(this,0,sizeof(InetAddress)); }
InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); }
InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); }
InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
InetAddress(const struct sockaddr &sa) { *this = sa; }
InetAddress(const struct sockaddr *sa) { *this = sa; }
InetAddress(const struct sockaddr_in &sa) { *this = sa; }
InetAddress(const struct sockaddr_in *sa) { *this = sa; }
InetAddress(const struct sockaddr_in6 &sa) { *this = sa; }
InetAddress(const struct sockaddr_in6 *sa) { *this = sa; }
InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); }
InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); }
InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); }
InetAddress()
{
memset(this, 0, sizeof(InetAddress));
}
InetAddress(const InetAddress& a)
{
memcpy(this, &a, sizeof(InetAddress));
}
InetAddress(const InetAddress* a)
{
memcpy(this, a, sizeof(InetAddress));
}
InetAddress(const struct sockaddr_storage& ss)
{
*this = ss;
}
InetAddress(const struct sockaddr_storage* ss)
{
*this = ss;
}
InetAddress(const struct sockaddr& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr* sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in* sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in6& sa)
{
*this = sa;
}
InetAddress(const struct sockaddr_in6* sa)
{
*this = sa;
}
InetAddress(const void* ipBytes, unsigned int ipLen, unsigned int port)
{
this->set(ipBytes, ipLen, port);
}
InetAddress(const uint32_t ipv4, unsigned int port)
{
this->set(&ipv4, 4, port);
}
InetAddress(const char* ipSlashPort)
{
this->fromString(ipSlashPort);
}
inline InetAddress &operator=(const InetAddress &a)
inline InetAddress& operator=(const InetAddress& a)
{
if (&a != this) {
memcpy(this,&a,sizeof(InetAddress));
memcpy(this, &a, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const InetAddress *a)
inline InetAddress& operator=(const InetAddress* a)
{
if (a != this) {
memcpy(this,a,sizeof(InetAddress));
memcpy(this, a, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage &ss)
inline InetAddress& operator=(const struct sockaddr_storage& ss)
{
if (reinterpret_cast<const InetAddress *>(&ss) != this) {
memcpy(this,&ss,sizeof(InetAddress));
if (reinterpret_cast<const InetAddress*>(&ss) != this) {
memcpy(this, &ss, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage *ss)
inline InetAddress& operator=(const struct sockaddr_storage* ss)
{
if (reinterpret_cast<const InetAddress *>(ss) != this) {
memcpy(this,ss,sizeof(InetAddress));
if (reinterpret_cast<const InetAddress*>(ss) != this) {
memcpy(this, ss, sizeof(InetAddress));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in &sa)
inline InetAddress& operator=(const struct sockaddr_in& sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in));
if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this, 0, sizeof(InetAddress));
memcpy(this, &sa, sizeof(struct sockaddr_in));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in *sa)
inline InetAddress& operator=(const struct sockaddr_in* sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in));
if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this, 0, sizeof(InetAddress));
memcpy(this, sa, sizeof(struct sockaddr_in));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in6 &sa)
inline InetAddress& operator=(const struct sockaddr_in6& sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,&sa,sizeof(struct sockaddr_in6));
if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this, 0, sizeof(InetAddress));
memcpy(this, &sa, sizeof(struct sockaddr_in6));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr_in6 *sa)
inline InetAddress& operator=(const struct sockaddr_in6* sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
memcpy(this,sa,sizeof(struct sockaddr_in6));
if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this, 0, sizeof(InetAddress));
memcpy(this, sa, sizeof(struct sockaddr_in6));
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr &sa)
inline InetAddress& operator=(const struct sockaddr& sa)
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
switch(sa.sa_family) {
if (reinterpret_cast<const InetAddress*>(&sa) != this) {
memset(this, 0, sizeof(InetAddress));
switch (sa.sa_family) {
case AF_INET:
memcpy(this,&sa,sizeof(struct sockaddr_in));
memcpy(this, &sa, sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(this,&sa,sizeof(struct sockaddr_in6));
memcpy(this, &sa, sizeof(struct sockaddr_in6));
break;
}
}
return *this;
}
inline InetAddress &operator=(const struct sockaddr *sa)
inline InetAddress& operator=(const struct sockaddr* sa)
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
switch(sa->sa_family) {
if (reinterpret_cast<const InetAddress*>(sa) != this) {
memset(this, 0, sizeof(InetAddress));
switch (sa->sa_family) {
case AF_INET:
memcpy(this,sa,sizeof(struct sockaddr_in));
memcpy(this, sa, sizeof(struct sockaddr_in));
break;
case AF_INET6:
memcpy(this,sa,sizeof(struct sockaddr_in6));
memcpy(this, sa, sizeof(struct sockaddr_in6));
break;
}
}
@ -204,7 +246,7 @@ struct InetAddress : public sockaddr_storage
* @param ipLen Length of IP address: 4 or 16
* @param port Port number or 0 for none
*/
void set(const void *ipBytes,unsigned int ipLen,unsigned int port);
void set(const void* ipBytes, unsigned int ipLen, unsigned int port);
/**
* Set the port component
@ -213,12 +255,12 @@ struct InetAddress : public sockaddr_storage
*/
inline void setPort(unsigned int port)
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton((uint16_t)port);
break;
case AF_INET6:
reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
reinterpret_cast<struct sockaddr_in6*>(this)->sin6_port = Utils::hton((uint16_t)port);
break;
}
}
@ -228,17 +270,17 @@ struct InetAddress : public sockaddr_storage
*/
inline bool isDefaultRoute() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return ( (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == 0) );
return ((reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<const struct sockaddr_in*>(this)->sin_port == 0));
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) {
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]) {
return false;
}
}
return (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == 0);
return (reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port == 0);
}
return false;
}
@ -246,29 +288,29 @@ struct InetAddress : public sockaddr_storage
/**
* @return ASCII IP/port format representation
*/
char *toString(char buf[64]) const;
char* toString(char buf[64]) const;
/**
* @return IP portion only, in ASCII string format
*/
char *toIpString(char buf[64]) const;
char* toIpString(char buf[64]) const;
/**
* @param ipSlashPort IP/port (port is optional, will be 0 if not included)
* @return True if address appeared to be valid
*/
bool fromString(const char *ipSlashPort);
bool fromString(const char* ipSlashPort);
/**
* @return Port or 0 if no port component defined
*/
inline unsigned int port() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port));
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));
return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_port));
default:
return 0;
}
@ -283,7 +325,10 @@ struct InetAddress : public sockaddr_storage
*
* @return Netmask bits
*/
inline unsigned int netmaskBits() const { return port(); }
inline unsigned int netmaskBits() const
{
return port();
}
/**
* @return True if netmask bits is valid for the address type
@ -291,7 +336,7 @@ struct InetAddress : public sockaddr_storage
inline bool netmaskBitsValid() const
{
const unsigned int n = port();
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return (n <= 32);
case AF_INET6:
@ -308,7 +353,10 @@ struct InetAddress : public sockaddr_storage
*
* @return Gateway metric
*/
inline unsigned int metric() const { return port(); }
inline unsigned int metric() const
{
return port();
}
/**
* Construct a full netmask as an InetAddress
@ -340,7 +388,7 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check
* @return True if this IPv6 prefix matches the prefix of a given IPv6 address
*/
bool isEqualPrefix(const InetAddress &addr) const;
bool isEqualPrefix(const InetAddress& addr) const;
/**
* Test whether this IP/netmask contains this address
@ -348,28 +396,34 @@ struct InetAddress : public sockaddr_storage
* @param addr Address to check
* @return True if this IP/netmask (route) contains this address
*/
bool containsAddress(const InetAddress &addr) const;
bool containsAddress(const InetAddress& addr) const;
/**
* @return True if this is an IPv4 address
*/
inline bool isV4() const { return (ss_family == AF_INET); }
inline bool isV4() const
{
return (ss_family == AF_INET);
}
/**
* @return True if this is an IPv6 address
*/
inline bool isV6() const { return (ss_family == AF_INET6); }
inline bool isV6() const
{
return (ss_family == AF_INET6);
}
/**
* @return pointer to raw address bytes or NULL if not available
*/
inline const void *rawIpData() const
inline const void* rawIpData() const
{
switch(ss_family) {
switch (ss_family) {
case AF_INET:
return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
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);
return (const void*)(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
default:
return 0;
}
@ -381,14 +435,14 @@ struct InetAddress : public sockaddr_storage
inline InetAddress ipOnly() const
{
InetAddress r;
switch(ss_family) {
switch (ss_family) {
case AF_INET:
r.ss_family = AF_INET;
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr;
reinterpret_cast<struct sockaddr_in*>(&r)->sin_addr.s_addr = reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr;
break;
case AF_INET6:
r.ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
memcpy(reinterpret_cast<struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, 16);
break;
}
return r;
@ -400,16 +454,16 @@ struct InetAddress : public sockaddr_storage
* @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses)
*/
inline bool ipsEqual(const InetAddress &a) const
inline bool ipsEqual(const InetAddress& a) const
{
if (ss_family == a.ss_family) {
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);
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,16) == 0);
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 (memcmp(this, &a, sizeof(InetAddress)) == 0);
}
return false;
}
@ -422,16 +476,16 @@ struct InetAddress : public sockaddr_storage
* @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses)
*/
inline bool ipsEqual2(const InetAddress &a) const
inline bool ipsEqual2(const InetAddress& a) const
{
if (ss_family == a.ss_family) {
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);
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);
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 (memcmp(this, &a, sizeof(InetAddress)) == 0);
}
return false;
}
@ -439,19 +493,21 @@ struct InetAddress : public sockaddr_storage
inline unsigned long hashCode() const
{
if (ss_family == AF_INET) {
return ((unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast<const struct sockaddr_in *>(this)->sin_port);
} 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) {
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i];
return ((unsigned long)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast<const struct sockaddr_in*>(this)->sin_port);
}
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) {
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) {
reinterpret_cast<uint8_t *>(&tmp)[i % sizeof(tmp)] ^= a[i];
}
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) {
reinterpret_cast<uint8_t*>(&tmp)[i % sizeof(tmp)] ^= a[i];
}
return tmp;
}
@ -460,7 +516,10 @@ struct InetAddress : public sockaddr_storage
/**
* Set to null/zero
*/
inline void zero() { memset(this,0,sizeof(InetAddress)); }
inline void zero()
{
memset(this, 0, sizeof(InetAddress));
}
/**
* Check whether this is a network/route rather than an IP assignment
@ -474,18 +533,18 @@ struct InetAddress : public sockaddr_storage
/**
* Find the total number of prefix bits that match between this IP and another
*
*
* @param b Second IP to compare with
* @return Number of matching prefix bits or 0 if none match or IPs are of different families (e.g. v4 and v6)
*/
inline unsigned int matchingPrefixBits(const InetAddress &b) const
inline unsigned int matchingPrefixBits(const InetAddress& b) const
{
unsigned int c = 0;
if (ss_family == b.ss_family) {
switch(ss_family) {
switch (ss_family) {
case AF_INET: {
uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(&b)->sin_addr.s_addr);
uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr);
uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(&b)->sin_addr.s_addr);
while ((ip0 >> 31) == (ip1 >> 31)) {
ip0 <<= 1;
ip1 <<= 1;
@ -493,14 +552,15 @@ struct InetAddress : public sockaddr_storage
break;
}
}
} break;
} break;
case AF_INET6: {
const uint8_t *ip0 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
const uint8_t *ip1 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&b)->sin6_addr.s6_addr);
for(unsigned int i=0;i<16;++i) {
const uint8_t* ip0 = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr);
const uint8_t* ip1 = reinterpret_cast<const uint8_t*>(reinterpret_cast<const struct sockaddr_in6*>(&b)->sin6_addr.s6_addr);
for (unsigned int i = 0; i < 16; ++i) {
if (ip0[i] == ip1[i]) {
c += 8;
} else {
}
else {
uint8_t ip0b = ip0[i];
uint8_t ip1b = ip1[i];
uint8_t bit = 0x80;
@ -514,7 +574,7 @@ struct InetAddress : public sockaddr_storage
break;
}
}
} break;
} break;
}
}
return c;
@ -526,13 +586,13 @@ struct InetAddress : public sockaddr_storage
inline unsigned long rateGateHash() const
{
unsigned long h = 0;
switch(ss_family) {
switch (ss_family) {
case AF_INET:
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
h ^= (h >> 14);
break;
case AF_INET6: {
const uint8_t *ip = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
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]);
@ -544,7 +604,7 @@ struct InetAddress : public sockaddr_storage
h += ((unsigned long)ip[4]);
h <<= 1;
h += ((unsigned long)ip[5]);
} break;
} break;
}
return (h & 0x3fff);
}
@ -552,23 +612,25 @@ struct InetAddress : public sockaddr_storage
/**
* @return True if address family is non-zero
*/
inline operator bool() const { return (ss_family != 0); }
inline operator bool() const
{
return (ss_family != 0);
}
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
template <unsigned int C> inline void serialize(Buffer<C>& b) const
{
// This is used in the protocol and must be the same as describe in places
// like VERB_HELLO in Packet.hpp.
switch(ss_family) {
switch (ss_family) {
case AF_INET:
b.append((uint8_t)0x04);
b.append(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr),4);
b.append((uint16_t)port()); // just in case sin_port != uint16_t
b.append(&(reinterpret_cast<const struct sockaddr_in*>(this)->sin_addr.s_addr), 4);
b.append((uint16_t)port()); // just in case sin_port != uint16_t
return;
case AF_INET6:
b.append((uint8_t)0x06);
b.append(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
b.append((uint16_t)port()); // just in case sin_port != uint16_t
b.append(reinterpret_cast<const struct sockaddr_in6*>(this)->sin6_addr.s6_addr, 16);
b.append((uint16_t)port()); // just in case sin_port != uint16_t
return;
default:
b.append((uint8_t)0);
@ -576,12 +638,11 @@ struct InetAddress : public sockaddr_storage
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
memset(this,0,sizeof(InetAddress));
memset(this, 0, sizeof(InetAddress));
unsigned int p = startAt;
switch(b[p++]) {
switch (b[p++]) {
case 0:
return 1;
case 0x01:
@ -593,19 +654,19 @@ struct InetAddress : public sockaddr_storage
case 0x03:
// TODO: Other address types (but accept for forward compatibility)
// These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc.
return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
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);
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));
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);
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));
reinterpret_cast<struct sockaddr_in*>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p));
p += 2;
break;
default:
@ -614,18 +675,30 @@ struct InetAddress : public sockaddr_storage
return (p - startAt);
}
bool operator==(const InetAddress &a) const;
bool operator<(const InetAddress &a) const;
inline bool operator!=(const InetAddress &a) const { return !(*this == a); }
inline bool operator>(const InetAddress &a) const { return (a < *this); }
inline bool operator<=(const InetAddress &a) const { return !(a < *this); }
inline bool operator>=(const InetAddress &a) const { return !(*this < a); }
bool operator==(const InetAddress& a) const;
bool operator<(const InetAddress& a) const;
inline bool operator!=(const InetAddress& a) const
{
return ! (*this == a);
}
inline bool operator>(const InetAddress& a) const
{
return (a < *this);
}
inline bool operator<=(const InetAddress& a) const
{
return ! (a < *this);
}
inline bool operator>=(const InetAddress& a) const
{
return ! (*this < a);
}
/**
* @param mac MAC address seed
* @return IPv6 link-local address
*/
static InetAddress makeIpv6LinkLocal(const MAC &mac);
static InetAddress makeIpv6LinkLocal(const MAC& mac);
/**
* Compute private IPv6 unicast address from network ID and ZeroTier address
@ -668,14 +741,14 @@ struct InetAddress : public sockaddr_storage
* @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored)
* @return IPv6 private unicast address with /88 netmask
*/
static InetAddress makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress);
static InetAddress makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress);
/**
* Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address
*/
static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress);
static InetAddress makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress);
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,64 +14,81 @@
#ifndef ZT_MAC_HPP
#define ZT_MAC_HPP
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
namespace ZeroTier {
/**
* 48-byte Ethernet MAC address
*/
class MAC
{
public:
MAC() : _m(0ULL) {}
MAC(const MAC &m) : _m(m._m) {}
class MAC {
public:
MAC() : _m(0ULL)
{
}
MAC(const MAC& m) : _m(m._m)
{
}
MAC(const unsigned char a,const unsigned char b,const unsigned char c,const unsigned char d,const unsigned char e,const unsigned char f) :
_m( ((((uint64_t)a) & 0xffULL) << 40) |
((((uint64_t)b) & 0xffULL) << 32) |
((((uint64_t)c) & 0xffULL) << 24) |
((((uint64_t)d) & 0xffULL) << 16) |
((((uint64_t)e) & 0xffULL) << 8) |
(((uint64_t)f) & 0xffULL) ) {}
MAC(const void *bits,unsigned int len) { setTo(bits,len); }
MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); }
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {}
MAC(const unsigned char a, const unsigned char b, const unsigned char c, const unsigned char d, const unsigned char e, const unsigned char f)
: _m(((((uint64_t)a) & 0xffULL) << 40) | ((((uint64_t)b) & 0xffULL) << 32) | ((((uint64_t)c) & 0xffULL) << 24) | ((((uint64_t)d) & 0xffULL) << 16) | ((((uint64_t)e) & 0xffULL) << 8) | (((uint64_t)f) & 0xffULL))
{
}
MAC(const void* bits, unsigned int len)
{
setTo(bits, len);
}
MAC(const Address& ztaddr, uint64_t nwid)
{
fromAddress(ztaddr, nwid);
}
MAC(const uint64_t m) : _m(m & 0xffffffffffffULL)
{
}
/**
* @return MAC in 64-bit integer
*/
inline uint64_t toInt() const { return _m; }
inline uint64_t toInt() const
{
return _m;
}
/**
* Set MAC to zero
*/
inline void zero() { _m = 0ULL; }
inline void zero()
{
_m = 0ULL;
}
/**
* @return True if MAC is non-zero
*/
inline operator bool() const { return (_m != 0ULL); }
inline operator bool() const
{
return (_m != 0ULL);
}
/**
* @param bits Raw MAC in big-endian byte order
* @param len Length, must be >= 6 or result is zero
*/
inline void setTo(const void *bits,unsigned int len)
inline void setTo(const void* bits, unsigned int len)
{
if (len < 6) {
_m = 0ULL;
return;
}
const unsigned char *b = (const unsigned char *)bits;
_m = ((((uint64_t)*b) & 0xff) << 40);
const unsigned char* b = (const unsigned char*)bits;
_m = ((((uint64_t)*b) & 0xff) << 40);
++b;
_m |= ((((uint64_t)*b) & 0xff) << 32);
++b;
@ -88,12 +105,12 @@ public:
* @param buf Destination buffer for MAC in big-endian byte order
* @param len Length of buffer, must be >= 6 or nothing is copied
*/
inline void copyTo(void *buf,unsigned int len) const
inline void copyTo(void* buf, unsigned int len) const
{
if (len < 6) {
return;
}
unsigned char *b = (unsigned char *)buf;
unsigned char* b = (unsigned char*)buf;
*(b++) = (unsigned char)((_m >> 40) & 0xff);
*(b++) = (unsigned char)((_m >> 32) & 0xff);
*(b++) = (unsigned char)((_m >> 24) & 0xff);
@ -107,10 +124,9 @@ public:
*
* @param b Buffer to append to
*/
template<unsigned int C>
inline void appendTo(Buffer<C> &b) const
template <unsigned int C> inline void appendTo(Buffer<C>& b) const
{
unsigned char *p = (unsigned char *)b.appendField(6);
unsigned char* p = (unsigned char*)b.appendField(6);
*(p++) = (unsigned char)((_m >> 40) & 0xff);
*(p++) = (unsigned char)((_m >> 32) & 0xff);
*(p++) = (unsigned char)((_m >> 24) & 0xff);
@ -122,17 +138,26 @@ public:
/**
* @return True if this is broadcast (all 0xff)
*/
inline bool isBroadcast() const { return (_m == 0xffffffffffffULL); }
inline bool isBroadcast() const
{
return (_m == 0xffffffffffffULL);
}
/**
* @return True if this is a multicast MAC
*/
inline bool isMulticast() const { return ((_m & 0x010000000000ULL) != 0ULL); }
inline bool isMulticast() const
{
return ((_m & 0x010000000000ULL) != 0ULL);
}
/**
* @param True if this is a locally-administered MAC
*/
inline bool isLocallyAdministered() const { return ((_m & 0x020000000000ULL) != 0ULL); }
inline bool isLocallyAdministered() const
{
return ((_m & 0x020000000000ULL) != 0ULL);
}
/**
* Set this MAC to a MAC derived from an address and a network ID
@ -140,10 +165,10 @@ public:
* @param ztaddr ZeroTier address
* @param nwid 64-bit network ID
*/
inline void fromAddress(const Address &ztaddr,uint64_t nwid)
inline void fromAddress(const Address& ztaddr, uint64_t nwid)
{
uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40;
m |= ztaddr.toInt(); // a is 40 bits
m |= ztaddr.toInt(); // a is 40 bits
m ^= ((nwid >> 8) & 0xff) << 32;
m ^= ((nwid >> 16) & 0xff) << 24;
m ^= ((nwid >> 24) & 0xff) << 16;
@ -161,8 +186,8 @@ public:
*/
inline Address toAddress(uint64_t nwid) const
{
uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address
a ^= ((nwid >> 8) & 0xff) << 32; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it
uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address
a ^= ((nwid >> 8) & 0xff) << 32; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it
a ^= ((nwid >> 16) & 0xff) << 24;
a ^= ((nwid >> 24) & 0xff) << 16;
a ^= ((nwid >> 32) & 0xff) << 8;
@ -176,24 +201,33 @@ public:
*/
static inline unsigned char firstOctetForNetwork(uint64_t nwid)
{
unsigned char a = ((unsigned char)(nwid & 0xfe) | 0x02); // locally administered, not multicast, from LSB of network ID
return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux
unsigned char a = ((unsigned char)(nwid & 0xfe) | 0x02); // locally administered, not multicast, from LSB of network ID
return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux
}
/**
* @param i Value from 0 to 5 (inclusive)
* @return Byte at said position (address interpreted in big-endian order)
*/
inline unsigned char operator[](unsigned int i) const { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); }
inline unsigned char operator[](unsigned int i) const
{
return (unsigned char)((_m >> (40 - (i * 8))) & 0xff);
}
/**
* @return 6, which is the number of bytes in a MAC, for container compliance
*/
inline unsigned int size() const { return 6; }
inline unsigned int size() const
{
return 6;
}
inline unsigned long hashCode() const { return (unsigned long)_m; }
inline unsigned long hashCode() const
{
return (unsigned long)_m;
}
inline char *toString(char buf[18]) const
inline char* toString(char buf[18]) const
{
buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf];
buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf];
@ -216,28 +250,46 @@ public:
return buf;
}
inline MAC &operator=(const MAC &m)
inline MAC& operator=(const MAC& m)
{
_m = m._m;
return *this;
}
inline MAC &operator=(const uint64_t m)
inline MAC& operator=(const uint64_t m)
{
_m = m;
return *this;
}
inline bool operator==(const MAC &m) const { return (_m == m._m); }
inline bool operator!=(const MAC &m) const { return (_m != m._m); }
inline bool operator<(const MAC &m) const { return (_m < m._m); }
inline bool operator<=(const MAC &m) const { return (_m <= m._m); }
inline bool operator>(const MAC &m) const { return (_m > m._m); }
inline bool operator>=(const MAC &m) const { return (_m >= m._m); }
inline bool operator==(const MAC& m) const
{
return (_m == m._m);
}
inline bool operator!=(const MAC& m) const
{
return (_m != m._m);
}
inline bool operator<(const MAC& m) const
{
return (_m < m._m);
}
inline bool operator<=(const MAC& m) const
{
return (_m <= m._m);
}
inline bool operator>(const MAC& m) const
{
return (_m > m._m);
}
inline bool operator>=(const MAC& m) const
{
return (_m >= m._m);
}
private:
private:
uint64_t _m;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,47 +11,41 @@
*/
/****/
#include <algorithm>
#include "Membership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Peer.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Packet.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
#include <algorithm>
namespace ZeroTier {
Membership::Membership() :
_lastUpdatedMulticast(0),
_comRevocationThreshold(0),
_lastPushedCredentials(0),
_revocations(4),
_remoteTags(4),
_remoteCaps(4),
_remoteCoos(4)
Membership::Membership() : _lastUpdatedMulticast(0), _comRevocationThreshold(0), _lastPushedCredentials(0), _revocations(4), _remoteTags(4), _remoteCaps(4), _remoteCoos(4)
{
}
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf)
void Membership::pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf)
{
const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES];
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];
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];
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]);
}
@ -59,8 +53,8 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
unsigned int tagPtr = 0;
unsigned int cooPtr = 0;
bool sendCom = (bool)(nconf.com);
while ((capPtr < sendCapCount)||(tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)) {
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
while ((capPtr < sendCapCount) || (tagPtr < sendTagCount) || (cooPtr < sendCooCount) || (sendCom)) {
Packet outp(peerAddress, RR->identity.address(), Packet::VERB_NETWORK_CREDENTIALS);
if (sendCom) {
sendCom = false;
@ -71,20 +65,20 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
const unsigned int capCountAt = outp.size();
outp.addSize(2);
unsigned int thisPacketCapCount = 0;
while ((capPtr < sendCapCount)&&((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
while ((capPtr < sendCapCount) && ((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendCaps[capPtr++]->serialize(outp);
++thisPacketCapCount;
}
outp.setAt(capCountAt,(uint16_t)thisPacketCapCount);
outp.setAt(capCountAt, (uint16_t)thisPacketCapCount);
const unsigned int tagCountAt = outp.size();
outp.addSize(2);
unsigned int thisPacketTagCount = 0;
while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
while ((tagPtr < sendTagCount) && ((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendTags[tagPtr++]->serialize(outp);
++thisPacketTagCount;
}
outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount);
outp.setAt(tagCountAt, (uint16_t)thisPacketTagCount);
// No revocations, these propagate differently
outp.append((uint16_t)0);
@ -92,43 +86,43 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
const unsigned int cooCountAt = outp.size();
outp.addSize(2);
unsigned int thisPacketCooCount = 0;
while ((cooPtr < sendCooCount)&&((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
while ((cooPtr < sendCooCount) && ((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) {
sendCoos[cooPtr++]->serialize(outp);
++thisPacketCooCount;
}
outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount);
outp.setAt(cooCountAt, (uint16_t)thisPacketCooCount);
outp.compress();
RR->sw->send(tPtr,outp,true);
RR->sw->send(tPtr, outp, true);
Metrics::pkt_network_credentials_out++;
}
_lastPushedCredentials = now;
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com)
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com)
{
const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) {
RR->t->credentialRejected(tPtr,com,"revoked");
RR->t->credentialRejected(tPtr, com, "revoked");
return ADD_REJECTED;
}
const int64_t oldts = _com.timestamp();
if (newts < oldts) {
RR->t->credentialRejected(tPtr,com,"old");
RR->t->credentialRejected(tPtr, com, "old");
return ADD_REJECTED;
}
if (_com == com) {
return ADD_ACCEPTED_REDUNDANT;
}
switch(com.verify(RR,tPtr)) {
switch (com.verify(RR, tPtr)) {
default:
RR->t->credentialRejected(tPtr,com,"invalid");
RR->t->credentialRejected(tPtr, com, "invalid");
return ADD_REJECTED;
case 0:
//printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout);
// printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout);
_com = com;
return ADD_ACCEPTED_NEW;
case 1:
@ -137,13 +131,13 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
// Template out addCredential() for many cred types to avoid copypasta
template<typename C>
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remoteCreds,const Hashtable<uint64_t,int64_t> &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred)
template <typename C>
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t, C>& remoteCreds, const Hashtable<uint64_t, int64_t>& revocations, const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const C& cred)
{
C *rc = remoteCreds.get(cred.id());
C* rc = remoteCreds.get(cred.id());
if (rc) {
if (rc->timestamp() > cred.timestamp()) {
RR->t->credentialRejected(tPtr,cred,"old");
RR->t->credentialRejected(tPtr, cred, "old");
return Membership::ADD_REJECTED;
}
if (*rc == cred) {
@ -151,18 +145,18 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
}
}
const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
if ((rt)&&(*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr,cred,"revoked");
const int64_t* const rt = revocations.get(Membership::credentialKey(C::credentialType(), cred.id()));
if ((rt) && (*rt >= cred.timestamp())) {
RR->t->credentialRejected(tPtr, cred, "revoked");
return Membership::ADD_REJECTED;
}
switch(cred.verify(RR,tPtr)) {
switch (cred.verify(RR, tPtr)) {
default:
RR->t->credentialRejected(tPtr,cred,"invalid");
RR->t->credentialRejected(tPtr, cred, "invalid");
return Membership::ADD_REJECTED;
case 0:
if (!rc) {
if (! rc) {
rc = &(remoteCreds[cred.id()]);
}
*rc = cred;
@ -172,20 +166,29 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remot
}
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,nconf,tag); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,nconf,cap); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,nconf,coo); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev)
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag)
{
int64_t *rt;
switch(rev.verify(RR,tPtr)) {
return _addCredImpl<Tag>(_remoteTags, _revocations, RR, tPtr, nconf, tag);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap)
{
return _addCredImpl<Capability>(_remoteCaps, _revocations, RR, tPtr, nconf, cap);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo)
{
return _addCredImpl<CertificateOfOwnership>(_remoteCoos, _revocations, RR, tPtr, nconf, coo);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev)
{
int64_t* rt;
switch (rev.verify(RR, tPtr)) {
default:
RR->t->credentialRejected(tPtr,rev,"invalid");
RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED;
case 0: {
const Credential::Type ct = rev.type();
switch(ct) {
switch (ct) {
case Credential::CREDENTIAL_TYPE_COM:
if (rev.threshold() > _comRevocationThreshold) {
_comRevocationThreshold = rev.threshold();
@ -195,7 +198,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
case Credential::CREDENTIAL_TYPE_CAPABILITY:
case Credential::CREDENTIAL_TYPE_TAG:
case Credential::CREDENTIAL_TYPE_COO:
rt = &(_revocations[credentialKey(ct,rev.credentialId())]);
rt = &(_revocations[credentialKey(ct, rev.credentialId())]);
if (*rt < rev.threshold()) {
*rt = rev.threshold();
_comRevocationThreshold = rev.threshold();
@ -203,7 +206,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
return ADD_ACCEPTED_REDUNDANT;
default:
RR->t->credentialRejected(tPtr,rev,"invalid");
RR->t->credentialRejected(tPtr, rev, "invalid");
return ADD_REJECTED;
}
}
@ -212,11 +215,11 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
}
void Membership::clean(const int64_t now,const NetworkConfig &nconf)
void Membership::clean(const int64_t now, const NetworkConfig& nconf)
{
_cleanCredImpl<Tag>(nconf,_remoteTags);
_cleanCredImpl<Capability>(nconf,_remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos);
_cleanCredImpl<Tag>(nconf, _remoteTags);
_cleanCredImpl<Capability>(nconf, _remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf, _remoteCoos);
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,17 +14,17 @@
#ifndef ZT_MEMBERSHIP_HPP
#define ZT_MEMBERSHIP_HPP
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Capability.hpp"
#include "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Hashtable.hpp"
#include "CertificateOfMembership.hpp"
#include "Capability.hpp"
#include "Tag.hpp"
#include "Revocation.hpp"
#include "NetworkConfig.hpp"
#include "Revocation.hpp"
#include "Tag.hpp"
#include <stdint.h>
#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL
@ -40,16 +40,9 @@ class Network;
*
* This class is not thread safe. It must be locked externally.
*/
class Membership
{
public:
enum AddCredentialResult
{
ADD_REJECTED,
ADD_ACCEPTED_NEW,
ADD_ACCEPTED_REDUNDANT,
ADD_DEFERRED_FOR_WHOIS
};
class Membership {
public:
enum AddCredentialResult { ADD_REJECTED, ADD_ACCEPTED_NEW, ADD_ACCEPTED_REDUNDANT, ADD_DEFERRED_FOR_WHOIS };
Membership();
@ -62,11 +55,20 @@ public:
* @param peerAddress Address of member peer (the one that this Membership describes)
* @param nconf My network config
*/
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf);
void pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf);
inline int64_t lastPushedCredentials() { return _lastPushedCredentials; }
inline int64_t comTimestamp() { return _com.timestamp(); }
inline int64_t comRevocationThreshold() { return _comRevocationThreshold; }
inline int64_t lastPushedCredentials()
{
return _lastPushedCredentials;
}
inline int64_t comTimestamp()
{
return _com.timestamp();
}
inline int64_t comRevocationThreshold()
{
return _comRevocationThreshold;
}
/**
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@ -90,14 +92,14 @@ public:
* @param otherNodeIdentity Identity of remote node
* @return True if this peer is allowed on this network at all
*/
inline bool isAllowedOnNetwork(const NetworkConfig &thisNodeNetworkConfig, const Identity &otherNodeIdentity) const
inline bool isAllowedOnNetwork(const NetworkConfig& thisNodeNetworkConfig, const Identity& otherNodeIdentity) const
{
return thisNodeNetworkConfig.isPublic() || (((_com.timestamp() > _comRevocationThreshold) && (thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity))));
}
inline bool recentlyAssociated(const int64_t now) const
{
return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT));
return ((_com) && ((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT));
}
/**
@ -108,18 +110,17 @@ public:
* @param r Resource to check
* @return True if this peer has a certificate of ownership for the given resource
*/
template<typename T>
inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const
template <typename T> inline bool hasCertificateOfOwnershipFor(const NetworkConfig& nconf, const T& r) const
{
uint32_t *k = (uint32_t *)0;
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))) {
uint32_t* k = (uint32_t*)0;
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))) {
return true;
}
}
return _isV6NDPEmulated(nconf,r);
return _isV6NDPEmulated(nconf, r);
}
/**
@ -129,36 +130,36 @@ public:
* @param id Tag ID
* @return Pointer to tag or NULL if not found
*/
inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
inline const Tag* getTag(const NetworkConfig& nconf, const uint32_t id) const
{
const Tag *const t = _remoteTags.get(id);
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
const Tag* const t = _remoteTags.get(id);
return (((t) && (_isCredentialTimestampValid(nconf, *t))) ? t : (Tag*)0);
}
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo);
/**
* Validate and add a credential if signature is okay and it's otherwise good
*/
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev);
/**
* Clean internal databases of stale entries
@ -166,24 +167,30 @@ public:
* @param now Current time
* @param nconf Current network configuration
*/
void clean(const int64_t now,const NetworkConfig &nconf);
void clean(const int64_t now, const NetworkConfig& nconf);
/**
* Generates a key for the internal use in indexing credentials by type and credential ID
*/
static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); }
private:
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const MAC &m) const { return false; }
inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const InetAddress &ip) const
static uint64_t credentialKey(const Credential::Type& t, const uint32_t i)
{
if ((ip.isV6())&&(nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
return (((uint64_t)t << 32) | (uint64_t)i);
}
private:
inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const MAC& m) const
{
return false;
}
inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const InetAddress& ip) const
{
if ((ip.isV6()) && (nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId, nconf.issuedTo.toInt()));
for (unsigned int i = 0; i < nconf.staticIpCount; ++i) {
if (nconf.staticIps[i].ipsEqual(sixpl)) {
bool prefixMatches = true;
for(unsigned int j=0;j<5;++j) { // check for match on /40
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) {
for (unsigned int j = 0; j < 5; ++j) { // check for match on /40
if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&sixpl)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
@ -195,12 +202,12 @@ private:
}
}
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()));
for(unsigned int i=0;i<nconf.staticIpCount;++i) {
const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId, nconf.issuedTo.toInt()));
for (unsigned int i = 0; i < nconf.staticIpCount; ++i) {
if (nconf.staticIps[i].ipsEqual(rfc4193)) {
bool prefixMatches = true;
for(unsigned int j=0;j<11;++j) { // check for match on /88
if ((((const struct sockaddr_in6 *)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) {
for (unsigned int j = 0; j < 11; ++j) { // check for match on /88
if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&rfc4193)->sin6_addr.s6_addr)[j]) {
prefixMatches = false;
break;
}
@ -215,25 +222,23 @@ private:
return false;
}
template<typename C>
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
template <typename C> inline bool _isCredentialTimestampValid(const NetworkConfig& nconf, const C& remoteCredential) const
{
const int64_t ts = remoteCredential.timestamp();
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
const int64_t *threshold = _revocations.get(credentialKey(C::credentialType(),remoteCredential.id()));
return ((!threshold)||(ts > *threshold));
const int64_t* threshold = _revocations.get(credentialKey(C::credentialType(), remoteCredential.id()));
return ((! threshold) || (ts > *threshold));
}
return false;
}
template<typename C>
inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
template <typename C> inline void _cleanCredImpl(const NetworkConfig& nconf, Hashtable<uint32_t, C>& remoteCreds)
{
uint32_t *k = (uint32_t *)0;
C *v = (C *)0;
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
while (i.next(k,v)) {
if (!_isCredentialTimestampValid(nconf,*v)) {
uint32_t* k = (uint32_t*)0;
C* v = (C*)0;
typename Hashtable<uint32_t, C>::Iterator i(remoteCreds);
while (i.next(k, v)) {
if (! _isCredentialTimestampValid(nconf, *v)) {
remoteCreds.erase(*k);
}
}
@ -252,45 +257,39 @@ private:
CertificateOfMembership _com;
// Revocations by credentialKey()
Hashtable< uint64_t,int64_t > _revocations;
Hashtable<uint64_t, int64_t> _revocations;
// Remote credentials that we have received from this member (and that are valid)
Hashtable< uint32_t,Tag > _remoteTags;
Hashtable< uint32_t,Capability > _remoteCaps;
Hashtable< uint32_t,CertificateOfOwnership > _remoteCoos;
Hashtable<uint32_t, Tag> _remoteTags;
Hashtable<uint32_t, Capability> _remoteCaps;
Hashtable<uint32_t, CertificateOfOwnership> _remoteCoos;
public:
class CapabilityIterator
{
public:
CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
_hti(m._remoteCaps),
_k((uint32_t *)0),
_c((Capability *)0),
_m(m),
_nconf(nconf)
public:
class CapabilityIterator {
public:
CapabilityIterator(Membership& m, const NetworkConfig& nconf) : _hti(m._remoteCaps), _k((uint32_t*)0), _c((Capability*)0), _m(m), _nconf(nconf)
{
}
inline Capability *next()
inline Capability* next()
{
while (_hti.next(_k,_c)) {
if (_m._isCredentialTimestampValid(_nconf,*_c)) {
while (_hti.next(_k, _c)) {
if (_m._isCredentialTimestampValid(_nconf, *_c)) {
return _c;
}
}
return (Capability *)0;
return (Capability*)0;
}
private:
Hashtable< uint32_t,Capability >::Iterator _hti;
uint32_t *_k;
Capability *_c;
Membership &_m;
const NetworkConfig &_nconf;
private:
Hashtable<uint32_t, Capability>::Iterator _hti;
uint32_t* _k;
Capability* _c;
Membership& _m;
const NetworkConfig& _nconf;
};
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -10,263 +10,157 @@
* of this software will be governed by version 2.0 of the Apache License.
*/
// clang-format off
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h>
// clang-format on
namespace prometheus {
namespace simpleapi {
std::shared_ptr<Registry> registry_ptr = std::make_shared<Registry>();
Registry& registry = *registry_ptr;
SaveToFile saver;
}
}
namespace simpleapi {
std::shared_ptr<Registry> registry_ptr = std::make_shared<Registry>();
Registry& registry = *registry_ptr;
SaveToFile saver;
} // namespace simpleapi
} // namespace prometheus
namespace ZeroTier {
namespace Metrics {
// Packet Type Counts
prometheus::simpleapi::counter_family_t packets
{ "zt_packet", "ZeroTier packet type counts"};
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"}}) };
// 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"}}) };
// 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" };
// 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" } }) };
// 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" } }) };
// 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" } }) };
// 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" };
// 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" };
// 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"};
// 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::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_member_deauth
{ "controller_sso_timeouts", "number of sso timeouts" };
prometheus::simpleapi::counter_metric_t sso_expiration_checks { "controller_sso_expiration_checks", "number of sso expiration checks done" };
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" };
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" };
// 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)" };
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" };
// 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
}
}
} // namespace Metrics
} // namespace ZeroTier

View file

@ -12,155 +12,154 @@
#ifndef METRICS_H_
#define METRICS_H_
// clang-format off
#include <prometheus/simpleapi.h>
#include <prometheus/histogram.h>
// clang-format on
namespace prometheus {
namespace simpleapi {
extern std::shared_ptr<Registry> registry_ptr;
}
namespace simpleapi {
extern std::shared_ptr<Registry> registry_ptr;
}
} // namespace prometheus
namespace ZeroTier {
namespace Metrics {
// Packet Type Counts
extern prometheus::simpleapi::counter_family_t packets;
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;
// 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;
// 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;
// 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;
// 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;
// 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;
// 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;
// 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;
// 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;
// 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;
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 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;
// 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
} // namespace Metrics
} // namespace ZeroTier
#endif // METRICS_H_
#endif // METRICS_H_

View file

@ -14,10 +14,10 @@
#ifndef ZT_MULTICASTGROUP_HPP
#define ZT_MULTICASTGROUP_HPP
#include <stdint.h>
#include "MAC.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include <stdint.h>
namespace ZeroTier {
@ -36,18 +36,13 @@ namespace ZeroTier {
*
* MulticastGroup behaves as an immutable value object.
*/
class MulticastGroup
{
public:
MulticastGroup() :
_mac(),
_adi(0)
class MulticastGroup {
public:
MulticastGroup() : _mac(), _adi(0)
{
}
MulticastGroup(const MAC &m,uint32_t a) :
_mac(m),
_adi(a)
MulticastGroup(const MAC& m, uint32_t a) : _mac(m), _adi(a)
{
}
@ -57,21 +52,22 @@ public:
* @param ip IP address (port field is ignored)
* @return Multicast group for ARP/NDP
*/
static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip)
{
if (ip.isV4()) {
// IPv4 wants broadcast MACs, so we shove the V4 address itself into
// the Multicast Group ADI field. Making V4 ARP work is basically why
// ADI was added, as well as handling other things that want mindless
// Ethernet broadcast to all.
return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData())));
} else if (ip.isV6()) {
return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t*)ip.rawIpData())));
}
else if (ip.isV6()) {
// IPv6 is better designed in this respect. We can compute the IPv6
// multicast address directly from the IP address, and it gives us
// 24 bits of uniqueness. Collisions aren't likely to be common enough
// to care about.
const unsigned char *a = (const unsigned char *)ip.rawIpData();
return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
const unsigned char* a = (const unsigned char*)ip.rawIpData();
return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0);
}
return MulticastGroup();
}
@ -79,35 +75,60 @@ public:
/**
* @return Multicast address
*/
inline const MAC &mac() const { return _mac; }
inline const MAC& mac() const
{
return _mac;
}
/**
* @return Additional distinguishing information
*/
inline uint32_t adi() const { return _adi; }
inline uint32_t adi() const
{
return _adi;
}
inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); }
inline unsigned long hashCode() const
{
return (_mac.hashCode() ^ (unsigned long)_adi);
}
inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); }
inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); }
inline bool operator<(const MulticastGroup &g) const
inline bool operator==(const MulticastGroup& g) const
{
return ((_mac == g._mac) && (_adi == g._adi));
}
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) {
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); }
inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); }
inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); }
inline bool operator>(const MulticastGroup& g) const
{
return (g < *this);
}
inline bool operator<=(const MulticastGroup& g) const
{
return ! (g < *this);
}
inline bool operator>=(const MulticastGroup& g) const
{
return ! (*this < g);
}
private:
private:
MAC _mac;
uint32_t _adi;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,25 +11,24 @@
*/
/****/
#include <algorithm>
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "Multicaster.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "C25519.hpp"
#include "CertificateOfMembership.hpp"
#include "Node.hpp"
#include "Constants.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include <algorithm>
namespace ZeroTier {
Multicaster::Multicaster(const RuntimeEnvironment *renv) :
RR(renv),
_groups(32)
Multicaster::Multicaster(const RuntimeEnvironment* renv) : RR(renv), _groups(32)
{
}
@ -37,24 +36,24 @@ Multicaster::~Multicaster()
{
}
void Multicaster::addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown)
void Multicaster::addMultiple(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const void* addresses, unsigned int count, unsigned int totalKnown)
{
const unsigned char *p = (const unsigned char *)addresses;
const unsigned char *e = p + (5 * count);
const unsigned char* p = (const unsigned char*)addresses;
const unsigned char* e = p + (5 * count);
Mutex::Lock _l(_groups_m);
MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)];
MulticastGroupStatus& gs = _groups[Multicaster::Key(nwid, mg)];
while (p != e) {
_add(tPtr,now,nwid,mg,gs,Address(p,5));
_add(tPtr, now, nwid, mg, gs, Address(p, 5));
p += 5;
}
}
void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &member)
void Multicaster::remove(uint64_t nwid, const MulticastGroup& mg, const Address& member)
{
Mutex::Lock _l(_groups_m);
MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg));
if (s) {
for(std::vector<MulticastGroupMember>::iterator m(s->members.begin());m!=s->members.end();++m) {
for (std::vector<MulticastGroupMember>::iterator m(s->members.begin()); m != s->members.end(); ++m) {
if (m->address == member) {
s->members.erase(m);
break;
@ -63,26 +62,27 @@ void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &m
}
}
unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const
unsigned int Multicaster::gather(const Address& queryingPeer, uint64_t nwid, const MulticastGroup& mg, Buffer<ZT_PROTO_MAX_PACKET_LENGTH>& appendTo, unsigned int limit) const
{
unsigned char *p;
unsigned int added = 0,i,k,rptr,totalKnown = 0;
uint64_t a,picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2];
unsigned char* p;
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)
appendTo.addSize(4); // sizeof(uint32_t)
const unsigned int addedAt = appendTo.size();
appendTo.addSize(2); // sizeof(uint16_t)
appendTo.addSize(2); // sizeof(uint16_t)
{ // Return myself if I am a member of this group
{ // Return myself if I am a member of this group
SharedPtr<Network> network(RR->node->network(nwid));
if ((network)&&(network->subscribedToMulticastGroup(mg,true))) {
if ((network) && (network->subscribedToMulticastGroup(mg, true))) {
RR->identity.address().appendTo(appendTo);
++totalKnown;
++added;
@ -91,19 +91,19 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const
Mutex::Lock _l(_groups_m);
const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
if ((s)&&(!s->members.empty())) {
const MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg));
if ((s) && (! s->members.empty())) {
totalKnown += (unsigned int)s->members.size();
// Members are returned in random order so that repeated gather queries
// will return different subsets of a large multicast group.
k = 0;
while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) {
while ((added < limit) && (k < s->members.size()) && ((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) {
rptr = (unsigned int)RR->node->prng();
restart_member_scan:
restart_member_scan:
a = s->members[rptr % (unsigned int)s->members.size()].address.toInt();
for(i=0;i<k;++i) {
for (i = 0; i < k; ++i) {
if (picked[i] == a) {
++rptr;
goto restart_member_scan;
@ -111,8 +111,8 @@ restart_member_scan:
}
picked[k++] = a;
if (queryingPeer.toInt() != a) { // do not return the peer that is making the request as a result
p = (unsigned char *)appendTo.appendField(ZT_ADDRESS_LENGTH);
if (queryingPeer.toInt() != a) { // do not return the peer that is making the request as a result
p = (unsigned char*)appendTo.appendField(ZT_ADDRESS_LENGTH);
*(p++) = (unsigned char)((a >> 32) & 0xff);
*(p++) = (unsigned char)((a >> 24) & 0xff);
*(p++) = (unsigned char)((a >> 16) & 0xff);
@ -123,21 +123,21 @@ restart_member_scan:
}
}
appendTo.setAt(totalAt,(uint32_t)totalKnown);
appendTo.setAt(addedAt,(uint16_t)added);
appendTo.setAt(totalAt, (uint32_t)totalKnown);
appendTo.setAt(addedAt, (uint16_t)added);
return added;
}
std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const
std::vector<Address> Multicaster::getMembers(uint64_t nwid, const MulticastGroup& mg, unsigned int limit) const
{
std::vector<Address> ls;
Mutex::Lock _l(_groups_m);
const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
if (!s) {
const MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg));
if (! s) {
return ls;
}
for(std::vector<MulticastGroupMember>::const_reverse_iterator m(s->members.rbegin());m!=s->members.rend();++m) {
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) {
break;
@ -146,19 +146,10 @@ std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup
return ls;
}
void Multicaster::send(
void *tPtr,
int64_t now,
const SharedPtr<Network> &network,
const Address &origin,
const MulticastGroup &mg,
const MAC &src,
unsigned int etherType,
const void *data,
unsigned int len)
void Multicaster::send(void* tPtr, int64_t now, const SharedPtr<Network>& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len)
{
unsigned long idxbuf[4096];
unsigned long *indexes = idxbuf;
unsigned long* indexes = idxbuf;
// If we're in hub-and-spoke designated multicast replication mode, see if we
// have a multicast replicator active. If so, pick the best and send it
@ -168,19 +159,19 @@ void Multicaster::send(
// the current protocol and could be fixed, but fixing it would add more
// complexity than the fix is probably worth. Bridges are generally high
// bandwidth nodes.
if (!network->config().isActiveBridge(RR->identity.address())) {
if (! network->config().isActiveBridge(RR->identity.address())) {
Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS];
const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators);
if (multicastReplicatorCount) {
if (std::find(multicastReplicators,multicastReplicators + multicastReplicatorCount,RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) {
if (std::find(multicastReplicators, multicastReplicators + multicastReplicatorCount, RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) {
SharedPtr<Peer> bestMulticastReplicator;
SharedPtr<Path> bestMulticastReplicatorPath;
unsigned int bestMulticastReplicatorLatency = 0xffff;
for(unsigned int i=0;i<multicastReplicatorCount;++i) {
for (unsigned int i = 0; i < multicastReplicatorCount; ++i) {
const SharedPtr<Peer> p(RR->topology->getPeerNoCache(multicastReplicators[i]));
if ((p)&&(p->isAlive(now))) {
const SharedPtr<Path> pp(p->getAppropriatePath(now,false));
if ((pp)&&(pp->latency() < bestMulticastReplicatorLatency)) {
if ((p) && (p->isAlive(now))) {
const SharedPtr<Path> pp(p->getAppropriatePath(now, false));
if ((pp) && (pp->latency() < bestMulticastReplicatorLatency)) {
bestMulticastReplicatorLatency = pp->latency();
bestMulticastReplicatorPath = pp;
bestMulticastReplicator = p;
@ -188,20 +179,20 @@ void Multicaster::send(
}
}
if (bestMulticastReplicator) {
Packet outp(bestMulticastReplicator->address(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
Packet outp(bestMulticastReplicator->address(), RR->identity.address(), Packet::VERB_MULTICAST_FRAME);
outp.append((uint64_t)network->id());
outp.append((uint8_t)0x0c); // includes source MAC | please replicate
((src) ? src : MAC(RR->identity.address(),network->id())).appendTo(outp);
outp.append((uint8_t)0x0c); // includes source MAC | please replicate
((src) ? src : MAC(RR->identity.address(), network->id())).appendTo(outp);
mg.mac().appendTo(outp);
outp.append((uint32_t)mg.adi());
outp.append((uint16_t)etherType);
outp.append(data,len);
if (!network->config().disableCompression()) {
outp.append(data, len);
if (! network->config().disableCompression()) {
outp.compress();
}
outp.armor(bestMulticastReplicator->key(),true,bestMulticastReplicator->aesKeysIfSupported());
outp.armor(bestMulticastReplicator->key(), true, bestMulticastReplicator->aesKeysIfSupported());
Metrics::pkt_multicast_frame_out++;
bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now);
bestMulticastReplicatorPath->send(RR, tPtr, outp.data(), outp.size(), now);
return;
}
}
@ -210,19 +201,19 @@ void Multicaster::send(
try {
Mutex::Lock _l(_groups_m);
MulticastGroupStatus &gs = _groups[Multicaster::Key(network->id(),mg)];
MulticastGroupStatus& gs = _groups[Multicaster::Key(network->id(), mg)];
if (!gs.members.empty()) {
if (! gs.members.empty()) {
// Allocate a memory buffer if group is monstrous
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) {
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];
indexes[j] = indexes[i];
@ -244,7 +235,7 @@ void Multicaster::send(
network->id(),
network->config().disableCompression(),
limit,
1, // we'll still gather a little from peers to keep multicast list fresh
1, // we'll still gather a little from peers to keep multicast list fresh
src,
mg,
etherType,
@ -253,24 +244,22 @@ void Multicaster::send(
unsigned int count = 0;
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) {
break;
}
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
}
}
unsigned long idx = 0;
while ((count < limit)&&(idx < gs.members.size())) {
while ((count < limit) && (idx < gs.members.size())) {
const Address ma(gs.members[indexes[idx++]].address);
if ((std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount))&&(ma != origin)) {
out.sendOnly(RR,tPtr,ma); // optimization: don't use dedup log if it's a one-pass send
if ((std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) && (ma != origin)) {
out.sendOnly(RR, tPtr, ma); // optimization: don't use dedup log if it's a one-pass send
++count;
}
}
} else {
}
else {
while (gs.txQueue.size() >= ZT_TX_QUEUE_SIZE) {
gs.txQueue.pop_front();
}
@ -278,7 +267,7 @@ void Multicaster::send(
const unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
int timerScale = RR->node->lowBandwidthModeEnabled() ? 3 : 1;
if ((gs.members.empty())||((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) {
if ((gs.members.empty()) || ((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) {
gs.lastExplicitGather = now;
Address explicitGatherPeers[16];
@ -294,10 +283,10 @@ void Multicaster::send(
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) {
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];
const unsigned int x2 = shuffled[(unsigned int)(x >> 32) % accnt];
@ -305,7 +294,7 @@ void Multicaster::send(
shuffled[x1] = shuffled[x2];
shuffled[x2] = tmp;
}
for(unsigned int i=0;i<accnt;++i) {
for (unsigned int i = 0; i < accnt; ++i) {
explicitGatherPeers[numExplicitGatherPeers++] = ac[shuffled[i]];
if (numExplicitGatherPeers == 16) {
break;
@ -313,7 +302,7 @@ void Multicaster::send(
}
std::vector<Address> anchors(network->config().anchors());
for(std::vector<Address>::const_iterator a(anchors.begin());a!=anchors.end();++a) {
for (std::vector<Address>::const_iterator a(anchors.begin()); a != anchors.end(); ++a) {
if (*a != RR->identity.address()) {
explicitGatherPeers[numExplicitGatherPeers++] = *a;
if (numExplicitGatherPeers == 16) {
@ -322,9 +311,9 @@ void Multicaster::send(
}
}
for(unsigned int k=0;k<numExplicitGatherPeers;++k) {
const CertificateOfMembership *com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0;
Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
for (unsigned int k = 0; k < numExplicitGatherPeers; ++k) {
const CertificateOfMembership* com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership*)0) : (const CertificateOfMembership*)0;
Packet outp(explicitGatherPeers[k], RR->identity.address(), Packet::VERB_MULTICAST_GATHER);
outp.append(network->id());
outp.append((uint8_t)((com) ? 0x01 : 0x00));
mg.mac().appendTo(outp);
@ -334,26 +323,15 @@ void Multicaster::send(
com->serialize(outp);
}
RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,true);
RR->sw->send(tPtr, outp, true);
Metrics::pkt_multicast_gather_out++;
}
}
gs.txQueue.push_back(OutboundMulticast());
OutboundMulticast &out = gs.txQueue.back();
OutboundMulticast& out = gs.txQueue.back();
out.init(
RR,
now,
network->id(),
network->config().disableCompression(),
limit,
gatherLimit,
src,
mg,
etherType,
data,
len);
out.init(RR, now, network->id(), network->config().disableCompression(), limit, gatherLimit, src, mg, etherType, data, len);
if (origin) {
out.logAsSent(origin);
@ -361,9 +339,9 @@ void Multicaster::send(
unsigned int count = 0;
for(unsigned int i=0;i<activeBridgeCount;++i) {
for (unsigned int i = 0; i < activeBridgeCount; ++i) {
if (activeBridges[i] != RR->identity.address()) {
out.sendAndLog(RR,tPtr,activeBridges[i]);
out.sendAndLog(RR, tPtr, activeBridges[i]);
if (++count >= limit) {
break;
}
@ -371,33 +349,36 @@ void Multicaster::send(
}
unsigned long idx = 0;
while ((count < limit)&&(idx < gs.members.size())) {
while ((count < limit) && (idx < gs.members.size())) {
Address ma(gs.members[indexes[idx++]].address);
if (std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount)) {
out.sendAndLog(RR,tPtr,ma);
if (std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) {
out.sendAndLog(RR, tPtr, ma);
++count;
}
}
}
} catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted
}
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) {
delete [] indexes;
delete[] indexes;
}
}
void Multicaster::clean(int64_t now)
{
Mutex::Lock _l(_groups_m);
Multicaster::Key *k = (Multicaster::Key *)0;
MulticastGroupStatus *s = (MulticastGroupStatus *)0;
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())) {
Multicaster::Key* k = (Multicaster::Key*)0;
MulticastGroupStatus* s = (MulticastGroupStatus*)0;
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())) {
s->txQueue.erase(tx++);
} else {
}
else {
++tx;
}
}
@ -418,15 +399,17 @@ void Multicaster::clean(int64_t now)
if (count) {
s->members.resize(count);
} else if (s->txQueue.empty()) {
}
else if (s->txQueue.empty()) {
_groups.erase(*k);
} else {
}
else {
s->members.clear();
}
}
}
void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
void Multicaster::_add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member)
{
// assumes _groups_m is locked
@ -435,29 +418,32 @@ void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup
return;
}
std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(),gs.members.end(),member));
std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(), gs.members.end(), member));
if (m != gs.members.end()) {
if (m->address == member) {
m->timestamp = now;
return;
}
gs.members.insert(m,MulticastGroupMember(member,now));
} else {
gs.members.push_back(MulticastGroupMember(member,now));
gs.members.insert(m, MulticastGroupMember(member, now));
}
else {
gs.members.push_back(MulticastGroupMember(member, now));
}
for(std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
for (std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin()); tx != gs.txQueue.end();) {
if (tx->atLimit()) {
gs.txQueue.erase(tx++);
} else {
tx->sendIfNew(RR,tPtr,member);
}
else {
tx->sendIfNew(RR, tPtr, member);
if (tx->atLimit()) {
gs.txQueue.erase(tx++);
} else {
}
else {
++tx;
}
}
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,22 +14,21 @@
#ifndef ZT_MULTICASTER_HPP
#define ZT_MULTICASTER_HPP
#include <stdint.h>
#include <string.h>
#include <map>
#include <vector>
#include <list>
#include "Address.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Address.hpp"
#include "MAC.hpp"
#include "MulticastGroup.hpp"
#include "OutboundMulticast.hpp"
#include "Utils.hpp"
#include "Mutex.hpp"
#include "OutboundMulticast.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <list>
#include <map>
#include <stdint.h>
#include <string.h>
#include <vector>
namespace ZeroTier {
@ -41,10 +40,9 @@ class Network;
/**
* Database of known multicast peers within a network
*/
class Multicaster
{
public:
Multicaster(const RuntimeEnvironment *renv);
class Multicaster {
public:
Multicaster(const RuntimeEnvironment* renv);
~Multicaster();
/**
@ -55,10 +53,10 @@ public:
* @param mg Multicast group
* @param member New member address
*/
inline void add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member)
inline void add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const Address& member)
{
Mutex::Lock _l(_groups_m);
_add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member);
_add(tPtr, now, nwid, mg, _groups[Multicaster::Key(nwid, mg)], member);
}
/**
@ -74,7 +72,7 @@ public:
* @param count Number of addresses
* @param totalKnown Total number of known addresses as reported by peer
*/
void addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown);
void addMultiple(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const void* addresses, unsigned int count, unsigned int totalKnown);
/**
* Remove a multicast group member (if present)
@ -83,7 +81,7 @@ public:
* @param mg Multicast group
* @param member Member to unsubscribe
*/
void remove(uint64_t nwid,const MulticastGroup &mg,const Address &member);
void remove(uint64_t nwid, const MulticastGroup& mg, const Address& member);
/**
* Append gather results to a packet by choosing registered multicast recipients at random
@ -103,7 +101,7 @@ public:
* @return Number of addresses appended
* @throws std::out_of_range Buffer overflow writing to packet
*/
unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const;
unsigned int gather(const Address& queryingPeer, uint64_t nwid, const MulticastGroup& mg, Buffer<ZT_PROTO_MAX_PACKET_LENGTH>& appendTo, unsigned int limit) const;
/**
* Get subscribers to a multicast group
@ -111,7 +109,7 @@ public:
* @param nwid Network ID
* @param mg Multicast group
*/
std::vector<Address> getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const;
std::vector<Address> getMembers(uint64_t nwid, const MulticastGroup& mg, unsigned int limit) const;
/**
* Send a multicast
@ -126,16 +124,7 @@ public:
* @param data Packet data
* @param len Length of packet data
*/
void send(
void *tPtr,
int64_t now,
const SharedPtr<Network> &network,
const Address &origin,
const MulticastGroup &mg,
const MAC &src,
unsigned int etherType,
const void *data,
unsigned int len);
void send(void* tPtr, int64_t now, const SharedPtr<Network>& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len);
/**
* Clean database
@ -145,53 +134,87 @@ public:
*/
void clean(int64_t now);
private:
struct Key
{
Key() : nwid(0),mg() {}
Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {}
private:
struct Key {
Key() : nwid(0), mg()
{
}
Key(uint64_t n, const MulticastGroup& g) : nwid(n), mg(g)
{
}
uint64_t nwid;
MulticastGroup mg;
inline bool operator==(const Key &k) const { return ((nwid == k.nwid)&&(mg == k.mg)); }
inline bool operator!=(const Key &k) const { return ((nwid != k.nwid)||(mg != k.mg)); }
inline unsigned long hashCode() const { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); }
inline bool operator==(const Key& k) const
{
return ((nwid == k.nwid) && (mg == k.mg));
}
inline bool operator!=(const Key& k) const
{
return ((nwid != k.nwid) || (mg != k.mg));
}
inline unsigned long hashCode() const
{
return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32)));
}
};
struct MulticastGroupMember
{
MulticastGroupMember() {}
MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {}
struct MulticastGroupMember {
MulticastGroupMember()
{
}
MulticastGroupMember(const Address& a, uint64_t ts) : address(a), timestamp(ts)
{
}
inline bool operator<(const MulticastGroupMember &a) const { return (address < a.address); }
inline bool operator==(const MulticastGroupMember &a) const { return (address == a.address); }
inline bool operator!=(const MulticastGroupMember &a) const { return (address != a.address); }
inline bool operator<(const Address &a) const { return (address < a); }
inline bool operator==(const Address &a) const { return (address == a); }
inline bool operator!=(const Address &a) const { return (address != a); }
inline bool operator<(const MulticastGroupMember& a) const
{
return (address < a.address);
}
inline bool operator==(const MulticastGroupMember& a) const
{
return (address == a.address);
}
inline bool operator!=(const MulticastGroupMember& a) const
{
return (address != a.address);
}
inline bool operator<(const Address& a) const
{
return (address < a);
}
inline bool operator==(const Address& a) const
{
return (address == a);
}
inline bool operator!=(const Address& a) const
{
return (address != a);
}
Address address;
int64_t timestamp; // time of last notification
int64_t timestamp; // time of last notification
};
struct MulticastGroupStatus
{
MulticastGroupStatus() : lastExplicitGather(0) {}
struct MulticastGroupStatus {
MulticastGroupStatus() : lastExplicitGather(0)
{
}
int64_t lastExplicitGather;
std::list<OutboundMulticast> txQueue; // pending outbound multicasts
std::vector<MulticastGroupMember> members; // members of this group
std::list<OutboundMulticast> txQueue; // pending outbound multicasts
std::vector<MulticastGroupMember> members; // members of this group
};
void _add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member);
void _add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member);
const RuntimeEnvironment *const RR;
const RuntimeEnvironment* const RR;
Hashtable<Multicaster::Key,MulticastGroupStatus> _groups;
Hashtable<Multicaster::Key, MulticastGroupStatus> _groups;
Mutex _groups_m;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -18,19 +18,18 @@
#ifdef __UNIX_LIKE__
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
namespace ZeroTier {
// libpthread based mutex lock
class Mutex
{
public:
class Mutex {
public:
Mutex()
{
pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0);
pthread_mutex_init(&_mh, (const pthread_mutexattr_t*)0);
}
~Mutex()
@ -40,25 +39,22 @@ public:
inline void lock() const
{
pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh));
pthread_mutex_lock(&((const_cast<Mutex*>(this))->_mh));
}
inline void unlock() const
{
pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh));
pthread_mutex_unlock(&((const_cast<Mutex*>(this))->_mh));
}
class Lock
{
public:
Lock(Mutex &m) :
_m(&m)
class Lock {
public:
Lock(Mutex& m) : _m(&m)
{
m.lock();
}
Lock(const Mutex &m) :
_m(const_cast<Mutex *>(&m))
Lock(const Mutex& m) : _m(const_cast<Mutex*>(&m))
{
_m->lock();
}
@ -68,18 +64,23 @@ public:
_m->unlock();
}
private:
Mutex *const _m;
private:
Mutex* const _m;
};
private:
Mutex(const Mutex &) {}
const Mutex &operator=(const Mutex &) { return *this; }
private:
Mutex(const Mutex&)
{
}
const Mutex& operator=(const Mutex&)
{
return *this;
}
pthread_mutex_t _mh;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif
@ -91,9 +92,8 @@ private:
namespace ZeroTier {
// Windows critical section based lock
class Mutex
{
public:
class Mutex {
public:
Mutex()
{
InitializeCriticalSection(&_cs);
@ -116,25 +116,22 @@ public:
inline void lock() const
{
(const_cast <Mutex *> (this))->lock();
(const_cast<Mutex*>(this))->lock();
}
inline void unlock() const
{
(const_cast <Mutex *> (this))->unlock();
(const_cast<Mutex*>(this))->unlock();
}
class Lock
{
public:
Lock(Mutex &m) :
_m(&m)
class Lock {
public:
Lock(Mutex& m) : _m(&m)
{
m.lock();
}
Lock(const Mutex &m) :
_m(const_cast<Mutex *>(&m))
Lock(const Mutex& m) : _m(const_cast<Mutex*>(&m))
{
_m->lock();
}
@ -144,19 +141,24 @@ public:
_m->unlock();
}
private:
Mutex *const _m;
private:
Mutex* const _m;
};
private:
Mutex(const Mutex &) {}
const Mutex &operator=(const Mutex &) { return *this; }
private:
Mutex(const Mutex&)
{
}
const Mutex& operator=(const Mutex&)
{
return *this;
}
CRITICAL_SECTION _cs;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif // _WIN32
#endif // _WIN32
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,33 +14,31 @@
#ifndef ZT_NETWORK_HPP
#define ZT_NETWORK_HPP
#include <stdint.h>
#include "../include/ZeroTierOne.h"
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Address.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "MulticastGroup.hpp"
#include "MAC.hpp"
#include "Dictionary.hpp"
#include "Multicaster.hpp"
#include "Membership.hpp"
#include "NetworkConfig.hpp"
#include "CertificateOfMembership.hpp"
#include "Constants.hpp"
#include "Dictionary.hpp"
#include "Hashtable.hpp"
#include "MAC.hpp"
#include "Membership.hpp"
#include "Metrics.hpp"
#include "MulticastGroup.hpp"
#include "Multicaster.hpp"
#include "Mutex.hpp"
#include "NetworkConfig.hpp"
#include "SharedPtr.hpp"
#include <algorithm>
#include <map>
#include <stdexcept>
#include <stdint.h>
#include <string>
#include <vector>
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3
#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1)
namespace ZeroTier {
@ -50,11 +48,10 @@ class Peer;
/**
* A virtual LAN
*/
class Network
{
class Network {
friend class SharedPtr<Network>;
public:
public:
/**
* Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0
*/
@ -63,7 +60,10 @@ public:
/**
* Compute primary controller device ID from network ID
*/
static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); }
static inline Address controllerFor(uint64_t nwid)
{
return Address(nwid >> 24);
}
/**
* Construct a new network
@ -77,18 +77,43 @@ public:
* @param uptr Arbitrary pointer used by externally-facing API (for user use)
* @param nconf Network config, if known
*/
Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr,const NetworkConfig *nconf);
Network(const RuntimeEnvironment* renv, void* tPtr, uint64_t nwid, void* uptr, const NetworkConfig* nconf);
~Network();
inline uint64_t id() const { return _id; }
inline Address controller() const { return Address(_id >> 24); }
inline bool multicastEnabled() const { return (_config.multicastLimit > 0); }
inline bool hasConfig() const { return (_config); }
inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; }
inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); }
inline const NetworkConfig &config() const { return _config; }
inline const MAC &mac() const { return _mac; }
inline uint64_t id() const
{
return _id;
}
inline Address controller() const
{
return Address(_id >> 24);
}
inline bool multicastEnabled() const
{
return (_config.multicastLimit > 0);
}
inline bool hasConfig() const
{
return (_config);
}
inline uint64_t lastConfigUpdate() const
{
return _lastConfigUpdate;
}
inline ZT_VirtualNetworkStatus status() const
{
Mutex::Lock _l(_lock);
return _status();
}
inline const NetworkConfig& config() const
{
return _config;
}
inline const MAC& mac() const
{
return _mac;
}
/**
* Apply filters to an outgoing packet
@ -111,17 +136,17 @@ public:
* @return True if packet should be sent, false if dropped or redirected
*/
bool filterOutgoingPacket(
void *tPtr,
void* tPtr,
const bool noTee,
const Address &ztSource,
const Address &ztDest,
const MAC &macSource,
const MAC &macDest,
const uint8_t *frameData,
const Address& ztSource,
const Address& ztDest,
const MAC& macSource,
const MAC& macDest,
const uint8_t* frameData,
const unsigned int frameLen,
const unsigned int etherType,
const unsigned int vlanId,
uint8_t &qosBucket);
uint8_t& qosBucket);
/**
* Apply filters to an incoming packet
@ -143,12 +168,12 @@ public:
* @return 0 == drop, 1 == accept, 2 == accept even if bridged
*/
int filterIncomingPacket(
void *tPtr,
const SharedPtr<Peer> &sourcePeer,
const Address &ztDest,
const MAC &macSource,
const MAC &macDest,
const uint8_t *frameData,
void* tPtr,
const SharedPtr<Peer>& sourcePeer,
const Address& ztDest,
const MAC& macSource,
const MAC& macDest,
const uint8_t* frameData,
const unsigned int frameLen,
const unsigned int etherType,
const unsigned int vlanId);
@ -160,7 +185,7 @@ public:
* @param includeBridgedGroups If true, also check groups we've learned via bridging
* @return True if this network endpoint / peer is a member
*/
bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const;
bool subscribedToMulticastGroup(const MulticastGroup& mg, bool includeBridgedGroups) const;
/**
* Subscribe to a multicast group
@ -168,14 +193,14 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param mg New multicast group
*/
void multicastSubscribe(void *tPtr,const MulticastGroup &mg);
void multicastSubscribe(void* tPtr, const MulticastGroup& mg);
/**
* Unsubscribe from a multicast group
*
* @param mg Multicast group
*/
void multicastUnsubscribe(const MulticastGroup &mg);
void multicastUnsubscribe(const MulticastGroup& mg);
/**
* Handle an inbound network config chunk
@ -191,7 +216,7 @@ public:
* @param ptr Index of chunk and related fields in packet
* @return Update ID if update was fully assembled and accepted or 0 otherwise
*/
uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr);
uint64_t handleConfigChunk(void* tPtr, const uint64_t packetId, const Address& source, const Buffer<ZT_PROTO_MAX_PACKET_LENGTH>& chunk, unsigned int ptr);
/**
* Set network configuration
@ -201,12 +226,12 @@ public:
* @param saveToDisk Save to disk? Used during loading, should usually be true otherwise.
* @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new
*/
int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk);
int setConfiguration(void* tPtr, const NetworkConfig& nconf, bool saveToDisk);
/**
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
*/
inline void setAccessDenied(void *tPtr)
inline void setAccessDenied(void* tPtr)
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_ACCESS_DENIED;
@ -217,7 +242,7 @@ public:
/**
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
*/
inline void setNotFound(void *tPtr)
inline void setNotFound(void* tPtr)
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_NOT_FOUND;
@ -228,7 +253,7 @@ public:
/**
* Set netconf failure to 'authentication required' possibly with an authorization URL
*/
inline void setAuthenticationRequired(void *tPtr, const char *url)
inline void setAuthenticationRequired(void* tPtr, const char* url)
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED;
@ -242,14 +267,14 @@ public:
* set netconf failure to 'authentication required' along with info needed
* for sso full flow authentication.
*/
void setAuthenticationRequired(void *tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char *ssoProvider, const char* nonce, const char* state);
void setAuthenticationRequired(void* tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char* ssoProvider, const char* nonce, const char* state);
/**
* Causes this network to request an updated configuration from its master node now
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
void requestConfiguration(void *tPtr);
void requestConfiguration(void* tPtr);
/**
* Determine whether this peer is permitted to communicate on this network
@ -257,7 +282,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer Peer to check
*/
bool gate(void *tPtr,const SharedPtr<Peer> &peer);
bool gate(void* tPtr, const SharedPtr<Peer>& peer);
/**
* Check whether a given peer has recently had an association with this network
@ -270,7 +295,7 @@ public:
* @param addr Peer address
* @return True if peer has recently associated
*/
bool recentlyAssociatedWith(const Address &addr);
bool recentlyAssociatedWith(const Address& addr);
/**
* Do periodic cleanup and housekeeping tasks
@ -282,10 +307,10 @@ public:
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
inline void sendUpdatesToMembers(void *tPtr)
inline void sendUpdatesToMembers(void* tPtr)
{
Mutex::Lock _l(_lock);
_sendUpdatesToMembers(tPtr,(const MulticastGroup *)0);
_sendUpdatesToMembers(tPtr, (const MulticastGroup*)0);
}
/**
@ -294,17 +319,20 @@ public:
* @param mac MAC address
* @return ZeroTier address of bridge to this MAC
*/
inline Address findBridgeTo(const MAC &mac) const
inline Address findBridgeTo(const MAC& mac) const
{
Mutex::Lock _l(_lock);
const Address *const br = _remoteBridgeRoutes.get(mac);
const Address* const br = _remoteBridgeRoutes.get(mac);
return ((br) ? *br : Address());
}
/**
* @return True if QoS is in effect for this network
*/
inline bool qosEnabled() { return false; }
inline bool qosEnabled()
{
return false;
}
/**
* Set a bridge route
@ -312,7 +340,7 @@ public:
* @param mac MAC address of destination
* @param addr Bridge this MAC is reachable behind
*/
void learnBridgeRoute(const MAC &mac,const Address &addr);
void learnBridgeRoute(const MAC& mac, const Address& addr);
/**
* Learn a multicast group that is bridged to our tap device
@ -321,52 +349,52 @@ public:
* @param mg Multicast group
* @param now Current time
*/
void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now);
void learnBridgedMulticastGroup(void* tPtr, const MulticastGroup& mg, int64_t now);
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com);
Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfMembership& com);
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap)
inline Membership::AddCredentialResult addCredential(void* tPtr, const Capability& cap)
{
if (cap.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap);
return _membership(cap.issuedTo()).addCredential(RR, tPtr, _config, cap);
}
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag)
inline Membership::AddCredentialResult addCredential(void* tPtr, const Tag& tag)
{
if (tag.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag);
return _membership(tag.issuedTo()).addCredential(RR, tPtr, _config, tag);
}
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev);
Membership::AddCredentialResult addCredential(void* tPtr, const Address& sentFrom, const Revocation& rev);
/**
* Validate a credential and learn it if it passes certificate and other checks
*/
inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo)
inline Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfOwnership& coo)
{
if (coo.networkId() != _id) {
return Membership::ADD_REJECTED;
}
Mutex::Lock _l(_lock);
return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo);
return _membership(coo.issuedTo()).addCredential(RR, tPtr, _config, coo);
}
/**
@ -376,13 +404,13 @@ public:
* @param to Destination peer address
* @param now Current time
*/
inline void peerRequestedCredentials(void *tPtr,const Address &to,const int64_t now)
inline void peerRequestedCredentials(void* tPtr, const Address& to, const int64_t now)
{
Mutex::Lock _l(_lock);
Membership &m = _membership(to);
Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) {
m.pushCredentials(RR,tPtr,now,to,_config);
if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) {
m.pushCredentials(RR, tPtr, now, to, _config);
}
}
@ -393,13 +421,13 @@ public:
* @param to Destination peer address
* @param now Current time
*/
inline void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now)
inline void pushCredentialsIfNeeded(void* tPtr, const Address& to, const int64_t now)
{
Mutex::Lock _l(_lock);
Membership &m = _membership(to);
Membership& m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) {
m.pushCredentials(RR,tPtr,now,to,_config);
if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) {
m.pushCredentials(RR, tPtr, now, to, _config);
}
}
@ -416,7 +444,7 @@ public:
*
* @param ec Buffer to fill with externally-visible network configuration
*/
inline void externalConfig(ZT_VirtualNetworkConfig *ec) const
inline void externalConfig(ZT_VirtualNetworkConfig* ec) const
{
Mutex::Lock _l(_lock);
_externalConfig(ec);
@ -425,36 +453,41 @@ public:
/**
* @return Externally usable pointer-to-pointer exported via the core API
*/
inline void **userPtr() { return &_uPtr; }
inline void** userPtr()
{
return &_uPtr;
}
private:
private:
ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer> &peer);
void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
void _externalConfig(ZT_VirtualNetworkConfig* ec) const; // assumes _lock is locked
bool _gate(const SharedPtr<Peer>& peer);
void _sendUpdatesToMembers(void* tPtr, const MulticastGroup* const newMulticastGroup);
void _announceMulticastGroupsTo(void* tPtr, const Address& peer, const std::vector<MulticastGroup>& allMulticastGroups);
std::vector<MulticastGroup> _allMulticastGroups() const;
Membership &_membership(const Address &a);
void _sendUpdateEvent(void *tPtr);
Membership& _membership(const Address& a);
void _sendUpdateEvent(void* tPtr);
const RuntimeEnvironment *const RR;
void *_uPtr;
const RuntimeEnvironment* const RR;
void* _uPtr;
const uint64_t _id;
std::string _nwidStr;
uint64_t _lastAnnouncedMulticastGroupsUpstream;
MAC _mac; // local MAC address
MAC _mac; // local MAC address
bool _portInitialized;
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap)
Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
std::vector<MulticastGroup> _myMulticastGroups; // multicast groups that we belong to (according to tap)
Hashtable<MulticastGroup, uint64_t> _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
Hashtable<MAC, Address> _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
NetworkConfig _config;
int64_t _lastConfigUpdate;
struct _IncomingConfigChunk
{
_IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); }
struct _IncomingConfigChunk {
_IncomingConfigChunk()
{
memset(this, 0, sizeof(_IncomingConfigChunk));
}
uint64_t ts;
uint64_t updateId;
uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS];
@ -466,17 +499,11 @@ private:
bool _destroyed;
enum {
NETCONF_FAILURE_NONE,
NETCONF_FAILURE_ACCESS_DENIED,
NETCONF_FAILURE_NOT_FOUND,
NETCONF_FAILURE_INIT_FAILED,
NETCONF_FAILURE_AUTHENTICATION_REQUIRED
} _netconfFailure;
int _portError; // return value from port config callback
enum { NETCONF_FAILURE_NONE, NETCONF_FAILURE_ACCESS_DENIED, NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED, NETCONF_FAILURE_AUTHENTICATION_REQUIRED } _netconfFailure;
int _portError; // return value from port config callback
std::string _authenticationURL;
Hashtable<Address,Membership> _memberships;
Hashtable<Address, Membership> _memberships;
Mutex _lock;

View file

@ -11,88 +11,87 @@
*/
/****/
#include <stdint.h>
#include "NetworkConfig.hpp"
#include <algorithm>
#include "NetworkConfig.hpp"
#include <stdint.h>
namespace ZeroTier {
bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const
bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d, bool includeLegacy) const
{
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
char tmp2[128] = {0};
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>* tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
char tmp2[128] = { 0 };
try {
d.clear();
// Try to put the more human-readable fields first
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) {
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)) {
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)) {
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)) {
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)) {
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))) {
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))) {
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)) {
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)) {
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)) {
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)) {
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)) {
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)) {
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())) {
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())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD, this->isPrivate())) {
return false;
}
std::string v4s;
for(unsigned int i=0;i<staticIpCount;++i) {
for (unsigned int i = 0; i < staticIpCount; ++i) {
if (this->staticIps[i].ss_family == AF_INET) {
if (v4s.length() > 0) {
v4s.push_back(',');
@ -102,12 +101,12 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
}
}
if (v4s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) {
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) {
for (unsigned int i = 0; i < staticIpCount; ++i) {
if (this->staticIps[i].ss_family == AF_INET6) {
if (v6s.length() > 0) {
v6s.push_back(',');
@ -117,7 +116,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
}
}
if (v6s.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD, v6s.c_str())) {
return false;
}
}
@ -125,130 +124,131 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
std::string ets;
unsigned int et = 0;
ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT;
for(unsigned int i=0;i<ruleCount;++i) {
for (unsigned int i = 0; i < ruleCount; ++i) {
ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f);
if (rt == ZT_NETWORK_RULE_MATCH_ETHERTYPE) {
et = rules[i].v.etherType;
} else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) {
if (((int)lastrt < 32)||(lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) {
}
else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) {
if (((int)lastrt < 32) || (lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) {
if (ets.length() > 0) {
ets.push_back(',');
}
char tmp2[16] = {0};
ets.append(Utils::hex((uint16_t)et,tmp2));
char tmp2[16] = { 0 };
ets.append(Utils::hex((uint16_t)et, tmp2));
}
et = 0;
}
lastrt = rt;
}
if (ets.length() > 0) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) {
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())) {
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) {
for (unsigned int i = 0; i < this->specialistCount; ++i) {
if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
if (ab.length() > 0) {
ab.push_back(',');
}
char tmp2[16] = {0};
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())) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, ab.c_str())) {
return false;
}
}
}
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
// Then add binary blobs
if (this->com) {
tmp->clear();
this->com.serialize(*tmp);
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) {
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)) {
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)) {
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)) {
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)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) {
return false;
}
}
tmp->clear();
for(unsigned int i=0;i<this->routeCount;++i) {
reinterpret_cast<const InetAddress *>(&(this->routes[i].target))->serialize(*tmp);
reinterpret_cast<const InetAddress *>(&(this->routes[i].via))->serialize(*tmp);
for (unsigned int i = 0; i < this->routeCount; ++i) {
reinterpret_cast<const InetAddress*>(&(this->routes[i].target))->serialize(*tmp);
reinterpret_cast<const InetAddress*>(&(this->routes[i].via))->serialize(*tmp);
tmp->append((uint16_t)this->routes[i].flags);
tmp->append((uint16_t)this->routes[i].metric);
}
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) {
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)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) {
return false;
}
}
if (this->ruleCount) {
tmp->clear();
Capability::serializeRules(*tmp,rules,ruleCount);
Capability::serializeRules(*tmp, rules, ruleCount);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) {
return false;
}
}
@ -257,59 +257,61 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
tmp->clear();
DNS::serializeDNS(*tmp, &dns);
if (tmp->size()) {
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) {
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)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) {
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)) {
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)) {
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)) {
}
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)) {
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)) {
// 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)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) {
return false;
}
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) {
if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) {
return false;
}
}
delete tmp;
} catch ( ... ) {
}
catch (...) {
delete tmp;
throw;
}
@ -317,83 +319,84 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
return true;
}
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d)
{
static const NetworkConfig NIL_NC;
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>* tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
try {
*this = NIL_NC;
// Fields that are always present, new or old
this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0);
if (!this->networkId) {
this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, 0);
if (! this->networkId) {
delete tmp;
return false;
}
this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0);
this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0);
this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0);
this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
if (!this->issuedTo) {
this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, 0);
this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, 0);
this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION, 0);
this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, 0);
if (! this->issuedTo) {
delete tmp;
return false;
}
this->remoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET);
this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL);
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0);
d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name));
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, 0);
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);
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU, ZT_DEFAULT_MTU);
if (this->mtu < 1280) {
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
} else if (this->mtu > ZT_MAX_MTU) {
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
}
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};
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)) {
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;
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 (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;
}
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 (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;
}
InetAddress ip(f);
if (!ip.isNetwork()) {
if (! ip.isNetwork()) {
this->staticIps[this->staticIpCount++] = ip;
}
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,tmp2,sizeof(tmp2)) > 0) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD, tmp2, sizeof(tmp2)) > 0) {
this->com.fromString(tmp2);
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD, tmp2, sizeof(tmp2)) > 0) {
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;
@ -405,67 +408,74 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
this->rules[this->ruleCount++].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
}
} else {
}
else {
this->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
this->ruleCount = 1;
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,tmp2,sizeof(tmp2)) > 0) {
char *saveptr = (char *)0;
for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
this->addSpecialist(Address(Utils::hexStrToU64(f)),ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, tmp2, sizeof(tmp2)) > 0) {
char* saveptr = (char*)0;
for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) {
this->addSpecialist(Address(Utils::hexStrToU64(f)), ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
}
}
#else
#else
delete tmp;
return false;
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
} else {
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
}
else {
// Otherwise we can use the new fields
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);
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)) {
this->com.deserialize(*tmp,0);
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM, *tmp)) {
this->com.deserialize(*tmp, 0);
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES, *tmp)) {
try {
unsigned int p = 0;
while (p < tmp->size()) {
Capability cap;
p += cap.deserialize(*tmp,p);
p += cap.deserialize(*tmp, p);
this->capabilities[this->capabilityCount++] = cap;
}
} catch ( ... ) {}
std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount]));
}
catch (...) {
}
std::sort(&(this->capabilities[0]), &(this->capabilities[this->capabilityCount]));
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS, *tmp)) {
try {
unsigned int p = 0;
while (p < tmp->size()) {
Tag tag;
p += tag.deserialize(*tmp,p);
p += tag.deserialize(*tmp, p);
this->tags[this->tagCount++] = tag;
}
} catch ( ... ) {}
std::sort(&(this->tags[0]),&(this->tags[this->tagCount]));
}
catch (...) {
}
std::sort(&(this->tags[0]), &(this->tags[this->tagCount]));
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) {
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) {
p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp,p);
} else {
p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp, p);
}
else {
CertificateOfOwnership foo;
p += foo.deserialize(*tmp,p);
p += foo.deserialize(*tmp, p);
}
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) {
unsigned int p = 0;
while ((p + 8) <= tmp->size()) {
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
@ -475,11 +485,11 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES, *tmp)) {
unsigned int p = 0;
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);
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);
@ -488,17 +498,17 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) {
unsigned int p = 0;
while ((p < tmp->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
p += this->staticIps[this->staticIpCount++].deserialize(*tmp,p);
while ((p < tmp->size()) && (staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
p += this->staticIps[this->staticIpCount++].deserialize(*tmp, p);
}
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) {
this->ruleCount = 0;
unsigned int p = 0;
Capability::deserializeRules(*tmp,p,this->rules,this->ruleCount,ZT_MAX_NETWORK_RULES);
Capability::deserializeRules(*tmp, p, this->rules, this->ruleCount, ZT_MAX_NETWORK_RULES);
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) {
@ -513,16 +523,19 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
// implicit flow
if (this->ssoEnabled) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated
} else {
this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated
}
else {
this->authenticationURL[0] = 0;
}
this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0);
} else {
}
else {
this->authenticationURL[0] = 0;
this->authenticationExpiryTime = 0;
}
} else if (this->ssoVersion == 1) {
}
else if (this->ssoVersion == 1) {
// full flow
if (this->ssoEnabled) {
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) {
@ -545,11 +558,13 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider, (unsigned int)(sizeof(this->ssoProvider))) > 0) {
this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0;
} else {
}
else {
strncpy(this->ssoProvider, "default", sizeof(this->ssoProvider));
this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0;
}
} else {
}
else {
this->authenticationURL[0] = 0;
this->authenticationExpiryTime = 0;
this->centralAuthURL[0] = 0;
@ -562,16 +577,17 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
}
//printf("~~~\n%s\n~~~\n",d.data());
//dump();
//printf("~~~\n");
// printf("~~~\n%s\n~~~\n",d.data());
// dump();
// printf("~~~\n");
delete tmp;
return true;
} catch ( ... ) {
}
catch (...) {
delete tmp;
return false;
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,31 +14,29 @@
#ifndef ZT_NETWORKCONFIG_HPP
#define ZT_NETWORKCONFIG_HPP
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "Buffer.hpp"
#include "DNS.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp"
#include "Buffer.hpp"
#include "Capability.hpp"
#include "CertificateOfMembership.hpp"
#include "CertificateOfOwnership.hpp"
#include "Capability.hpp"
#include "Tag.hpp"
#include "Constants.hpp"
#include "DNS.hpp"
#include "Dictionary.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Tag.hpp"
#include "Trace.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
/**
* Default time delta for COMs, tags, and capabilities
@ -93,7 +91,9 @@
namespace ZeroTier {
// Dictionary capacity needed for max size network config
#define ZT_NETWORKCONFIG_DICT_CAPACITY (4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
#define ZT_NETWORKCONFIG_DICT_CAPACITY \
(4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) \
+ (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
// Dictionary capacity needed for max size network meta-data
#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024
@ -248,46 +248,45 @@ namespace ZeroTier {
* This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks.
*/
class NetworkConfig
{
public:
NetworkConfig() :
networkId(0),
timestamp(0),
credentialTimeMaxDelta(0),
revision(0),
issuedTo(),
remoteTraceTarget(),
flags(0),
remoteTraceLevel(Trace::LEVEL_NORMAL),
mtu(0),
multicastLimit(0),
specialistCount(0),
routeCount(0),
staticIpCount(0),
ruleCount(0),
capabilityCount(0),
tagCount(0),
certificateOfOwnershipCount(0),
capabilities(),
tags(),
certificatesOfOwnership(),
type(ZT_NETWORK_TYPE_PRIVATE),
dnsCount(0),
ssoEnabled(false),
authenticationURL(),
authenticationExpiryTime(0),
issuerURL(),
centralAuthURL(),
ssoNonce(),
ssoState(),
ssoClientID()
class NetworkConfig {
public:
NetworkConfig()
: networkId(0)
, timestamp(0)
, credentialTimeMaxDelta(0)
, revision(0)
, issuedTo()
, remoteTraceTarget()
, flags(0)
, remoteTraceLevel(Trace::LEVEL_NORMAL)
, mtu(0)
, multicastLimit(0)
, specialistCount(0)
, routeCount(0)
, staticIpCount(0)
, ruleCount(0)
, capabilityCount(0)
, tagCount(0)
, certificateOfOwnershipCount(0)
, capabilities()
, tags()
, certificatesOfOwnership()
, type(ZT_NETWORK_TYPE_PRIVATE)
, dnsCount(0)
, ssoEnabled(false)
, authenticationURL()
, authenticationExpiryTime(0)
, issuerURL()
, centralAuthURL()
, ssoNonce()
, ssoState()
, ssoClientID()
{
name[0] = 0;
memset(specialists, 0, sizeof(uint64_t)*ZT_MAX_NETWORK_SPECIALISTS);
memset(routes, 0, sizeof(ZT_VirtualNetworkRoute)*ZT_MAX_NETWORK_ROUTES);
memset(staticIps, 0, sizeof(InetAddress)*ZT_MAX_ZT_ASSIGNED_ADDRESSES);
memset(rules, 0, sizeof(ZT_VirtualNetworkRule)*ZT_MAX_NETWORK_RULES);
memset(specialists, 0, sizeof(uint64_t) * ZT_MAX_NETWORK_SPECIALISTS);
memset(routes, 0, sizeof(ZT_VirtualNetworkRoute) * ZT_MAX_NETWORK_ROUTES);
memset(staticIps, 0, sizeof(InetAddress) * ZT_MAX_ZT_ASSIGNED_ADDRESSES);
memset(rules, 0, sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES);
memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS));
memset(authenticationURL, 0, sizeof(authenticationURL));
memset(issuerURL, 0, sizeof(issuerURL));
@ -305,7 +304,7 @@ public:
* @param includeLegacy If true, include legacy fields for old node versions
* @return True if dictionary was successfully created, false if e.g. overflow
*/
bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const;
bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d, bool includeLegacy) const;
/**
* Read this network config from a dictionary
@ -313,17 +312,23 @@ public:
* @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
* @return True if dictionary was valid and network config successfully initialized
*/
bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d);
bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>& d);
/**
* @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
*/
inline bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
inline bool enableBroadcast() const
{
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0);
}
/**
* @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
*/
inline bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
inline bool ndpEmulation() const
{
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0);
}
/**
* @return True if frames should not be compressed
@ -344,12 +349,18 @@ public:
/**
* @return Network type is public (no access control)
*/
inline bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
inline bool isPublic() const
{
return (this->type == ZT_NETWORK_TYPE_PUBLIC);
}
/**
* @return Network type is private (certificate access control)
*/
inline bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
inline bool isPrivate() const
{
return (this->type == ZT_NETWORK_TYPE_PRIVATE);
}
/**
* @return ZeroTier addresses of devices on this network designated as active bridges
@ -357,7 +368,7 @@ public:
inline std::vector<Address> activeBridges() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
r.push_back(Address(specialists[i]));
}
@ -368,7 +379,7 @@ public:
inline unsigned int activeBridges(Address ab[ZT_MAX_NETWORK_SPECIALISTS]) const
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) {
ab[c++] = specialists[i];
}
@ -376,10 +387,10 @@ public:
return c;
}
inline bool isActiveBridge(const Address &a) const
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])) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) && (a == specialists[i])) {
return true;
}
}
@ -389,7 +400,7 @@ public:
inline std::vector<Address> anchors() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) {
r.push_back(Address(specialists[i]));
}
@ -400,7 +411,7 @@ public:
inline std::vector<Address> multicastReplicators() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
r.push_back(Address(specialists[i]));
}
@ -411,7 +422,7 @@ public:
inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) {
mr[c++] = specialists[i];
}
@ -419,10 +430,10 @@ public:
return c;
}
inline bool isMulticastReplicator(const Address &a) const
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])) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if (((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) && (a == specialists[i])) {
return true;
}
}
@ -432,7 +443,7 @@ public:
inline std::vector<Address> alwaysContactAddresses() const
{
std::vector<Address> r;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
r.push_back(Address(specialists[i]));
}
@ -443,7 +454,7 @@ public:
inline unsigned int alwaysContactAddresses(Address ac[ZT_MAX_NETWORK_SPECIALISTS]) const
{
unsigned int c = 0;
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
ac[c++] = specialists[i];
}
@ -451,9 +462,9 @@ public:
return c;
}
inline void alwaysContactAddresses(Hashtable< Address,std::vector<InetAddress> > &a) const
inline void alwaysContactAddresses(Hashtable<Address, std::vector<InetAddress> >& a) const
{
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) {
a[Address(specialists[i])];
}
@ -464,19 +475,28 @@ public:
* @param fromPeer Peer attempting to bridge other Ethernet peers onto network
* @return True if this network allows bridging
*/
inline bool permitsBridging(const Address &fromPeer) const
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)) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((fromPeer == specialists[i]) && ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) {
return true;
}
}
return false;
}
inline operator bool() const { return (networkId != 0); }
inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
inline operator bool() const
{
return (networkId != 0);
}
inline bool operator==(const NetworkConfig& nc) const
{
return (memcmp(this, &nc, sizeof(NetworkConfig)) == 0);
}
inline bool operator!=(const NetworkConfig& nc) const
{
return (! (*this == nc));
}
/**
* Add a specialist or mask flags if already present
@ -488,10 +508,10 @@ public:
* @param f Flags (OR of specialist role/type flags)
* @return True if successfully masked or added
*/
inline bool addSpecialist(const Address &a,const uint64_t f)
inline bool addSpecialist(const Address& a, const uint64_t f)
{
const uint64_t aint = a.toInt();
for(unsigned int i=0;i<specialistCount;++i) {
for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & 0xffffffffffULL) == aint) {
specialists[i] |= f;
return true;
@ -504,24 +524,24 @@ public:
return false;
}
const Capability *capability(const uint32_t id) const
const Capability* capability(const uint32_t id) const
{
for(unsigned int i=0;i<capabilityCount;++i) {
for (unsigned int i = 0; i < capabilityCount; ++i) {
if (capabilities[i].id() == id) {
return &(capabilities[i]);
}
}
return (Capability *)0;
return (Capability*)0;
}
const Tag *tag(const uint32_t id) const
const Tag* tag(const uint32_t id) const
{
for(unsigned int i=0;i<tagCount;++i) {
for (unsigned int i = 0; i < tagCount; ++i) {
if (tags[i].id() == id) {
return &(tags[i]);
}
}
return (Tag *)0;
return (Tag*)0;
}
/**
@ -729,6 +749,6 @@ public:
char ssoProvider[64];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,13 +14,13 @@
#ifndef ZT_NETWORKCONFIGMASTER_HPP
#define ZT_NETWORKCONFIGMASTER_HPP
#include <stdint.h>
#include "Address.hpp"
#include "Constants.hpp"
#include "Dictionary.hpp"
#include "NetworkConfig.hpp"
#include "Revocation.hpp"
#include "Address.hpp"
#include <stdint.h>
namespace ZeroTier {
@ -30,24 +30,15 @@ struct InetAddress;
/**
* Interface for network controller implementations
*/
class NetworkController
{
public:
enum ErrorCode
{
NC_ERROR_NONE = 0,
NC_ERROR_OBJECT_NOT_FOUND = 1,
NC_ERROR_ACCESS_DENIED = 2,
NC_ERROR_INTERNAL_SERVER_ERROR = 3,
NC_ERROR_AUTHENTICATION_REQUIRED = 4
};
class NetworkController {
public:
enum ErrorCode { NC_ERROR_NONE = 0, NC_ERROR_OBJECT_NOT_FOUND = 1, NC_ERROR_ACCESS_DENIED = 2, NC_ERROR_INTERNAL_SERVER_ERROR = 3, NC_ERROR_AUTHENTICATION_REQUIRED = 4 };
/**
* Interface for sender used to send pushes and replies
*/
class Sender
{
public:
class Sender {
public:
/**
* Send a configuration to a remote peer
*
@ -57,7 +48,7 @@ public:
* @param nc Network configuration to send
* @param sendLegacyFormatConfig If true, send an old-format network config
*/
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) = 0;
virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig) = 0;
/**
* Send revocation to a node
@ -65,14 +56,14 @@ public:
* @param destination Destination node address
* @param rev Revocation to send
*/
virtual void ncSendRevocation(const Address &destination,const Revocation &rev) = 0;
virtual void ncSendRevocation(const Address& destination, const Revocation& rev) = 0;
/**
* Send a network configuration request error
*
* If errorData/errorDataSize are provided they must point to a valid serialized
* Dictionary containing error data. They can be null/zero if not specified.
*
*
* @param nwid Network ID
* @param requestPacketId Request packet ID or 0 if none
* @param destination Destination peer Address
@ -80,11 +71,15 @@ public:
* @param errorData Data associated with error or NULL if none
* @param errorDataSize Size of errorData in bytes
*/
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize) = 0;
virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize) = 0;
};
NetworkController() {}
virtual ~NetworkController() {}
NetworkController()
{
}
virtual ~NetworkController()
{
}
/**
* Called when this is added to a Node to initialize and supply info
@ -92,7 +87,7 @@ public:
* @param signingId Identity for signing of network configurations, certs, etc.
* @param sender Sender implementation for sending replies or config pushes
*/
virtual void init(const Identity &signingId,Sender *sender) = 0;
virtual void init(const Identity& signingId, Sender* sender) = 0;
/**
* Handle a network configuration request
@ -104,14 +99,9 @@ public:
* @param metaData Meta-data bundled with request (if any)
* @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error
*/
virtual void request(
uint64_t nwid,
const InetAddress &fromAddr,
uint64_t requestPacketId,
const Identity &identity,
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData) = 0;
virtual void request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>& metaData) = 0;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,29 +14,26 @@
#ifndef ZT_NODE_HPP
#define ZT_NODE_HPP
#include "../include/ZeroTierOne.h"
#include "Bond.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include "Mutex.hpp"
#include "Network.hpp"
#include "NetworkController.hpp"
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "Salsa20.hpp"
#include "SelfAwareness.hpp"
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <map>
#include <vector>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "RuntimeEnvironment.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "MAC.hpp"
#include "Network.hpp"
#include "Path.hpp"
#include "Salsa20.hpp"
#include "NetworkController.hpp"
#include "Hashtable.hpp"
#include "Bond.hpp"
#include "SelfAwareness.hpp"
// Bit mask for "expecting reply" hash
#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255
#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31
@ -50,94 +47,76 @@ class World;
*
* The pointer returned by ZT_Node_new() is an instance of this class.
*/
class Node : public NetworkController::Sender
{
public:
Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
class Node : public NetworkController::Sender {
public:
Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
virtual ~Node();
// Get rid of alignment warnings on 32-bit Windows and possibly improve performance
#ifdef __WINDOWS__
void * operator new(size_t i) { return _mm_malloc(i,16); }
void operator delete(void* p) { _mm_free(p); }
void* operator new(size_t i)
{
return _mm_malloc(i, 16);
}
void operator delete(void* p)
{
_mm_free(p);
}
#endif
// Public API Functions ----------------------------------------------------
ZT_ResultCode processWirePacket(
void *tptr,
int64_t now,
int64_t localSocket,
const struct sockaddr_storage *remoteAddress,
const void *packetData,
unsigned int packetLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processWirePacket(void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode processVirtualNetworkFrame(
void *tptr,
void* tptr,
int64_t now,
uint64_t nwid,
uint64_t sourceMac,
uint64_t destMac,
unsigned int etherType,
unsigned int vlanId,
const void *frameData,
const void* frameData,
unsigned int frameLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr);
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed);
ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId);
volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid, void* uptr, void* tptr);
ZT_ResultCode leave(uint64_t nwid, void** uptr, void* tptr);
ZT_ResultCode multicastSubscribe(void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
ZT_ResultCode orbit(void* tptr, uint64_t moonWorldId, uint64_t moonSeed);
ZT_ResultCode deorbit(void* tptr, uint64_t moonWorldId);
uint64_t address() const;
void status(ZT_NodeStatus *status) const;
ZT_PeerList *peers() const;
ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const;
ZT_VirtualNetworkList *networks() const;
void freeQueryResult(void *qr);
int addLocalInterfaceAddress(const struct sockaddr_storage *addr);
void status(ZT_NodeStatus* status) const;
ZT_PeerList* peers() const;
ZT_VirtualNetworkConfig* networkConfig(uint64_t nwid) const;
ZT_VirtualNetworkList* networks() const;
void freeQueryResult(void* qr);
int addLocalInterfaceAddress(const struct sockaddr_storage* addr);
void clearLocalInterfaceAddresses();
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
void setNetconfMaster(void *networkControllerInstance);
int sendUserMessage(void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len);
void setNetconfMaster(void* networkControllerInstance);
// Internal functions ------------------------------------------------------
inline int64_t now() const { return _now; }
inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
inline int64_t now() const
{
return (_cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node *>(this),
_uPtr,
tPtr,
localSocket,
reinterpret_cast<const struct sockaddr_storage *>(&addr),
data,
len,
ttl) == 0);
return _now;
}
inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
inline bool putPacket(void* tPtr, const int64_t localSocket, const InetAddress& addr, const void* data, unsigned int len, unsigned int ttl = 0)
{
_cb.virtualNetworkFrameFunction(
reinterpret_cast<ZT_Node *>(this),
_uPtr,
tPtr,
nwid,
nuptr,
source.toInt(),
dest.toInt(),
etherType,
vlanId,
data,
len);
return (_cb.wirePacketSendFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, localSocket, reinterpret_cast<const struct sockaddr_storage*>(&addr), data, len, ttl) == 0);
}
inline void putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len)
{
_cb.virtualNetworkFrameFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, nwid, nuptr, source.toInt(), dest.toInt(), etherType, vlanId, data, len);
}
inline SharedPtr<Network> network(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
const SharedPtr<Network> *n = _networks.get(nwid);
const SharedPtr<Network>* n = _networks.get(nwid);
if (n) {
return *n;
}
@ -150,14 +129,14 @@ public:
return _networks.contains(nwid);
}
inline std::vector< SharedPtr<Network> > allNetworks() const
inline std::vector<SharedPtr<Network> > allNetworks() const
{
std::vector< SharedPtr<Network> > nw;
std::vector<SharedPtr<Network> > nw;
Mutex::Lock _l(_networks_m);
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)) {
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)) {
nw.push_back(*v);
}
return nw;
@ -169,30 +148,60 @@ public:
return _directPaths;
}
inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); }
inline void postEvent(void* tPtr, ZT_Event ev, const void* md = (const void*)0)
{
_cb.eventCallback(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, ev, md);
}
inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,nwid,nuptr,op,nc); }
inline int configureVirtualNetworkPort(void* tPtr, uint64_t nwid, void** nuptr, ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig* nc)
{
return _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, nwid, nuptr, op, nc);
}
inline bool online() const { return _online; }
inline bool online() const
{
return _online;
}
inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,maxlen); }
inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,(int)len); }
inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,(const void *)0,-1); }
inline int stateObjectGet(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], void* const data, const unsigned int maxlen)
{
return _cb.stateGetFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, data, maxlen);
}
inline void stateObjectPut(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], const void* const data, const unsigned int len)
{
_cb.statePutFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, data, (int)len);
}
inline void stateObjectDelete(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2])
{
_cb.statePutFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, type, id, (const void*)0, -1);
}
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress);
inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); }
bool shouldUsePathForZeroTierTraffic(void* tPtr, const Address& ztaddr, const int64_t localSocket, const InetAddress& remoteAddress);
inline bool externalPathLookup(void* tPtr, const Address& ztaddr, int family, InetAddress& addr)
{
return ((_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node*>(this), _uPtr, tPtr, ztaddr.toInt(), family, reinterpret_cast<struct sockaddr_storage*>(&addr)) != 0) : false);
}
uint64_t prng();
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig);
World planet() const;
std::vector<World> moons() const;
inline const Identity &identity() const { return _RR.identity; }
inline const Identity& identity() const
{
return _RR.identity;
}
inline const std::vector<InetAddress> SurfaceAddresses() const { return _RR.sa->whoami(); }
inline const std::vector<InetAddress> SurfaceAddresses() const
{
return _RR.sa->whoami();
}
inline Bond *bondController() const { return _RR.bc; }
inline Bond* bondController() const
{
return _RR.bc;
}
/**
* Register that we are expecting a reply to a packet ID
@ -224,7 +233,7 @@ 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) {
for (unsigned long i = 0; i <= ZT_EXPECTING_REPLIES_BUCKET_MASK2; ++i) {
if (_expectingRepliesTo[bucket][i] == pid2) {
return true;
}
@ -239,7 +248,7 @@ public:
* @param from Source address of packet
* @return True if within rate limits
*/
inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from)
inline bool rateGateIdentityVerification(const int64_t now, const InetAddress& from)
{
unsigned long iph = from.rateGateHash();
if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) {
@ -249,17 +258,23 @@ public:
return false;
}
virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize);
virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig);
virtual void ncSendRevocation(const Address& destination, const Revocation& rev);
virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize);
inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; }
inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; }
inline const Address& remoteTraceTarget() const
{
return _remoteTraceTarget;
}
inline Trace::Level remoteTraceLevel() const
{
return _remoteTraceLevel;
}
inline bool localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const
inline bool localControllerHasAuthorized(const int64_t now, const uint64_t nwid, const Address& addr) const
{
_localControllerAuthorizations_m.lock();
const int64_t *const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid,addr));
const int64_t* const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid, addr));
_localControllerAuthorizations_m.unlock();
if (at) {
return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
@ -267,7 +282,7 @@ public:
return false;
}
inline void statsLogVerb(const unsigned int v,const unsigned int bytes)
inline void statsLogVerb(const unsigned int v, const unsigned int bytes)
{
++_stats.inVerbCounts[v];
_stats.inVerbBytes[v] += (uint64_t)bytes;
@ -285,11 +300,10 @@ public:
void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled);
public:
public:
RuntimeEnvironment _RR;
RuntimeEnvironment *RR;
void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P
RuntimeEnvironment* RR;
void* _uPtr; // _uptr (lower case) is reserved in Visual Studio :P
ZT_Node_Callbacks _cb;
// For tracking packet IDs to filter out OK/ERROR replies to packets we did not send
@ -304,18 +318,28 @@ public:
// Map that remembers if we have recently sent a network config to someone
// querying us as a controller.
struct _LocalControllerAuth
{
uint64_t nwid,address;
_LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {}
inline unsigned long hashCode() const { return (unsigned long)(nwid ^ address); }
inline bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); }
inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); }
struct _LocalControllerAuth {
uint64_t nwid, address;
_LocalControllerAuth(const uint64_t nwid_, const Address& address_) : nwid(nwid_), address(address_.toInt())
{
}
inline unsigned long hashCode() const
{
return (unsigned long)(nwid ^ address);
}
inline bool operator==(const _LocalControllerAuth& a) const
{
return ((a.nwid == nwid) && (a.address == address));
}
inline bool operator!=(const _LocalControllerAuth& a) const
{
return ((a.nwid != nwid) || (a.address != address));
}
};
Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations;
Hashtable<_LocalControllerAuth, int64_t> _localControllerAuthorizations;
Mutex _localControllerAuthorizations_m;
Hashtable< uint64_t,SharedPtr<Network> > _networks;
Hashtable<uint64_t, SharedPtr<Network> > _networks;
Mutex _networks_m;
std::vector<InetAddress> _directPaths;
@ -336,6 +360,6 @@ public:
bool _lowBandwidthMode;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,28 +11,29 @@
*/
/****/
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "OutboundMulticast.hpp"
#include "Switch.hpp"
#include "Constants.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
void OutboundMulticast::init(
const RuntimeEnvironment *RR,
const RuntimeEnvironment* RR,
uint64_t timestamp,
uint64_t nwid,
bool disableCompression,
unsigned int limit,
unsigned int gatherLimit,
const MAC &src,
const MulticastGroup &dest,
const MAC& src,
const MulticastGroup& dest,
unsigned int etherType,
const void *payload,
const void* payload,
unsigned int len)
{
uint8_t flags = 0;
@ -42,8 +43,9 @@ void OutboundMulticast::init(
if (src) {
_macSrc = src;
flags |= 0x04;
} else {
_macSrc.fromAddress(RR->identity.address(),nwid);
}
else {
_macSrc.fromAddress(RR->identity.address(), nwid);
}
_macDest = dest.mac();
_limit = limit;
@ -67,26 +69,26 @@ void OutboundMulticast::init(
dest.mac().appendTo(_packet);
_packet.append((uint32_t)dest.adi());
_packet.append((uint16_t)etherType);
_packet.append(payload,_frameLen);
if (!disableCompression) {
_packet.append(payload, _frameLen);
if (! disableCompression) {
_packet.compress();
}
memcpy(_frameData,payload,_frameLen);
memcpy(_frameData, payload, _frameLen);
}
void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr)
void OutboundMulticast::sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{
const SharedPtr<Network> nw(RR->node->network(_nwid));
uint8_t QoSBucket = 255; // Dummy value
if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr,_macSrc,_macDest,_frameData,_frameLen,_etherType,0,QoSBucket))) {
nw->pushCredentialsIfNeeded(tPtr,toAddr,RR->node->now());
uint8_t QoSBucket = 255; // Dummy value
if ((nw) && (nw->filterOutgoingPacket(tPtr, true, RR->identity.address(), toAddr, _macSrc, _macDest, _frameData, _frameLen, _etherType, 0, QoSBucket))) {
nw->pushCredentialsIfNeeded(tPtr, toAddr, RR->node->now());
_packet.newInitializationVector();
_packet.setDestination(toAddr);
RR->node->expectReplyTo(_packet.packetId());
_tmp = _packet;
RR->sw->send(tPtr,_tmp,true);
RR->sw->send(tPtr, _tmp, true);
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,17 +14,16 @@
#ifndef ZT_OUTBOUNDMULTICAST_HPP
#define ZT_OUTBOUNDMULTICAST_HPP
#include <stdint.h>
#include <vector>
#include <algorithm>
#include "Address.hpp"
#include "Constants.hpp"
#include "MAC.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp"
#include "Packet.hpp"
#include <algorithm>
#include <stdint.h>
#include <vector>
namespace ZeroTier {
class CertificateOfMembership;
@ -35,15 +34,16 @@ class RuntimeEnvironment;
*
* This object isn't guarded by a mutex; caller must synchronize access.
*/
class OutboundMulticast
{
public:
class OutboundMulticast {
public:
/**
* Create an uninitialized outbound multicast
*
* It must be initialized with init().
*/
OutboundMulticast() {}
OutboundMulticast()
{
}
/**
* Initialize outbound multicast
@ -62,33 +62,42 @@ public:
* @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME
*/
void init(
const RuntimeEnvironment *RR,
const RuntimeEnvironment* RR,
uint64_t timestamp,
uint64_t nwid,
bool disableCompression,
unsigned int limit,
unsigned int gatherLimit,
const MAC &src,
const MulticastGroup &dest,
const MAC& src,
const MulticastGroup& dest,
unsigned int etherType,
const void *payload,
const void* payload,
unsigned int len);
/**
* @return Multicast creation time
*/
inline uint64_t timestamp() const { return _timestamp; }
inline uint64_t timestamp() const
{
return _timestamp;
}
/**
* @param now Current time
* @return True if this multicast is expired (has exceeded transmit timeout)
*/
inline bool expired(int64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); }
inline bool expired(int64_t now) const
{
return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT);
}
/**
* @return True if this outbound multicast has been sent to enough peers
*/
inline bool atLimit() const { return (_alreadySentTo.size() >= _limit); }
inline bool atLimit() const
{
return (_alreadySentTo.size() >= _limit);
}
/**
* Just send without checking log
@ -97,7 +106,7 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address
*/
void sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr);
void sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr);
/**
* Just send and log but do not check sent log
@ -106,10 +115,10 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param toAddr Destination address
*/
inline void sendAndLog(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr)
inline void sendAndLog(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{
_alreadySentTo.push_back(toAddr);
sendOnly(RR,tPtr,toAddr);
sendOnly(RR, tPtr, toAddr);
}
/**
@ -117,7 +126,7 @@ public:
*
* @param toAddr Address to log as sent
*/
inline void logAsSent(const Address &toAddr)
inline void logAsSent(const Address& toAddr)
{
_alreadySentTo.push_back(toAddr);
}
@ -130,17 +139,18 @@ public:
* @param toAddr Destination address
* @return True if address is new and packet was sent to switch, false if duplicate
*/
inline bool sendIfNew(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr)
inline bool sendIfNew(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr)
{
if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) {
sendAndLog(RR,tPtr,toAddr);
if (std::find(_alreadySentTo.begin(), _alreadySentTo.end(), toAddr) == _alreadySentTo.end()) {
sendAndLog(RR, tPtr, toAddr);
return true;
} else {
}
else {
return false;
}
}
private:
private:
uint64_t _timestamp;
uint64_t _nwid;
MAC _macSrc;
@ -148,11 +158,11 @@ private:
unsigned int _limit;
unsigned int _frameLen;
unsigned int _etherType;
Packet _packet,_tmp;
Packet _packet, _tmp;
std::vector<Address> _alreadySentTo;
uint8_t _frameData[ZT_MAX_MTU];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -14,21 +14,19 @@
#ifndef ZT_N_PACKET_HPP
#define ZT_N_PACKET_HPP
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include "Constants.hpp"
#include "AES.hpp"
#include "Address.hpp"
#include "Buffer.hpp"
#include "Constants.hpp"
#include "Poly1305.hpp"
#include "Salsa20.hpp"
#include "AES.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include <iostream>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
/**
* Protocol version -- incremented only for major changes
@ -221,12 +219,12 @@
#define ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT 0x02
// Field indexes in packet header
#define ZT_PACKET_IDX_IV 0
#define ZT_PACKET_IDX_DEST 8
#define ZT_PACKET_IDX_SOURCE 13
#define ZT_PACKET_IDX_FLAGS 18
#define ZT_PACKET_IDX_MAC 19
#define ZT_PACKET_IDX_VERB 27
#define ZT_PACKET_IDX_IV 0
#define ZT_PACKET_IDX_DEST 8
#define ZT_PACKET_IDX_SOURCE 13
#define ZT_PACKET_IDX_FLAGS 18
#define ZT_PACKET_IDX_MAC 19
#define ZT_PACKET_IDX_VERB 27
#define ZT_PACKET_IDX_PAYLOAD 28
/**
@ -240,12 +238,12 @@
#define ZT_PROTO_MIN_PACKET_LENGTH ZT_PACKET_IDX_PAYLOAD
// Indexes of fields in fragment header
#define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0
#define ZT_PACKET_FRAGMENT_IDX_DEST 8
#define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0
#define ZT_PACKET_FRAGMENT_IDX_DEST 8
#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR 13
#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14
#define ZT_PACKET_FRAGMENT_IDX_HOPS 15
#define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16
#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14
#define ZT_PACKET_FRAGMENT_IDX_HOPS 15
#define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16
/**
* Magic number found at ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR
@ -264,89 +262,89 @@
// See their respective handler functions.
#define ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1)
#define ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION + 1)
#define ZT_PROTO_VERB_HELLO_IDX_REVISION (ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION + 1)
#define ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP (ZT_PROTO_VERB_HELLO_IDX_REVISION + 2)
#define ZT_PROTO_VERB_HELLO_IDX_IDENTITY (ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP + 8)
#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1)
#define ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION + 1)
#define ZT_PROTO_VERB_HELLO_IDX_REVISION (ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION + 1)
#define ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP (ZT_PROTO_VERB_HELLO_IDX_REVISION + 2)
#define ZT_PROTO_VERB_HELLO_IDX_IDENTITY (ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP + 8)
#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB + 1)
#define ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE (ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID + 8)
#define ZT_PROTO_VERB_ERROR_IDX_PAYLOAD (ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE + 1)
#define ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE (ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID + 8)
#define ZT_PROTO_VERB_ERROR_IDX_PAYLOAD (ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE + 1)
#define ZT_PROTO_VERB_OK_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_OK_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_OK_IDX_IN_RE_VERB + 1)
#define ZT_PROTO_VERB_OK_IDX_PAYLOAD (ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID + 8)
#define ZT_PROTO_VERB_OK_IDX_PAYLOAD (ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID + 8)
#define ZT_PROTO_VERB_WHOIS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1)
#define ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2)
#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2)
#define ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID 8
#define ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS (ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS 1
#define ZT_PROTO_VERB_EXT_FRAME_IDX_COM (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS)
#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6
#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6
#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2
#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE + ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE)
#define ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS (ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS 1
#define ZT_PROTO_VERB_EXT_FRAME_IDX_COM (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS)
#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6
#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6
#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM)
#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2
#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE + ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 4)
#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 4)
// Note: COM, GATHER_LIMIT, and SOURCE_MAC are optional, and so are specified without size
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2)
#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP + 8)
#define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1)
#define ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION + 1)
#define ZT_PROTO_VERB_HELLO__OK__IDX_REVISION (ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION + 1)
#define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1)
#define ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION + 1)
#define ZT_PROTO_VERB_HELLO__OK__IDX_REVISION (ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION + 1)
#define ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2)
#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC + 6)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI + 4)
#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS + 1)
// ---------------------------------------------------------------------------
@ -388,9 +386,8 @@ namespace ZeroTier {
* For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever
* sent in the clear, as it's the "here is my public key" message.
*/
class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH>
{
public:
class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> {
public:
/**
* A packet fragment
*
@ -417,22 +414,17 @@ public:
* receipt to authenticate and decrypt; there is no per-fragment MAC. (But if
* fragments are corrupt, the MAC will fail for the whole assembled packet.)
*/
class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH>
{
public:
Fragment() :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH> {
public:
Fragment() : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
{
}
template<unsigned int C2>
Fragment(const Buffer<C2> &b) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
template <unsigned int C2> Fragment(const Buffer<C2>& b) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
{
}
Fragment(const void *data,unsigned int len) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
Fragment(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, len)
{
}
@ -445,9 +437,9 @@ public:
* @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0)
*/
Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal)
Fragment(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal)
{
init(p,fragStart,fragLen,fragNo,fragTotal);
init(p, fragStart, fragLen, fragNo, fragTotal);
}
/**
@ -459,7 +451,7 @@ public:
* @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
* @param fragTotal Total number of fragments (including 0)
*/
inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal)
inline void init(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal)
{
if ((fragStart + fragLen) > p.size()) {
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
@ -467,13 +459,13 @@ public:
setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
// NOTE: this copies both the IV/packet ID and the destination address.
memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.field(ZT_PACKET_IDX_IV,13),13);
memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID, 13), p.field(ZT_PACKET_IDX_IV, 13), 13);
(*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
(*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
(*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0;
memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.field(fragStart,fragLen),fragLen);
memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, fragLen), p.field(fragStart, fragLen), fragLen);
}
/**
@ -481,32 +473,50 @@ public:
*
* @return Destination ZT address
*/
inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
inline Address destination() const
{
return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/**
* @return True if fragment is of a valid length
*/
inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
inline bool lengthValid() const
{
return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
}
/**
* @return ID of packet this is a fragment of
*/
inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); }
inline uint64_t packetId() const
{
return at<uint64_t>(ZT_PACKET_FRAGMENT_IDX_PACKET_ID);
}
/**
* @return Total number of fragments in packet
*/
inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); }
inline unsigned int totalFragments() const
{
return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf);
}
/**
* @return Fragment number of this fragment
*/
inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); }
inline unsigned int fragmentNumber() const
{
return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf);
}
/**
* @return Fragment ZT hop count
*/
inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); }
inline unsigned int hops() const
{
return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]);
}
/**
* Increment this packet's hop count
@ -519,14 +529,17 @@ public:
/**
* @return Length of payload in bytes
*/
inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); }
inline unsigned int payloadLength() const
{
return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0);
}
/**
* @return Raw packet payload
*/
inline const unsigned char *payload() const
inline const unsigned char* payload() const
{
return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
}
};
@ -793,12 +806,12 @@ public:
*
* ERROR response payload:
* <[8] 64-bit network ID>
* <[2] 16-bit length of error-related data (optional)>
* <[...] error-related data (optional)>
*
* Error related data is a Dictionary containing things like a URL
* for authentication or a human-readable error message, and is
* optional and may be absent or empty.
* <[2] 16-bit length of error-related data (optional)>
* <[...] error-related data (optional)>
*
* Error related data is a Dictionary containing things like a URL
* for authentication or a human-readable error message, and is
* optional and may be absent or empty.
*/
VERB_NETWORK_CONFIG_REQUEST = 0x0b,
@ -1056,8 +1069,7 @@ public:
/**
* Error codes for VERB_ERROR
*/
enum ErrorCode
{
enum ErrorCode {
/* No error, not actually used in transit */
ERROR_NONE = 0x00,
@ -1085,18 +1097,15 @@ public:
/* Multicasts to this group are not wanted */
ERROR_UNWANTED_MULTICAST = 0x08,
/* Network requires external or 2FA authentication (e.g. SSO). */
ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09
/* Network requires external or 2FA authentication (e.g. SSO). */
ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09
};
template<unsigned int C2>
Packet(const Buffer<C2> &b) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
template <unsigned int C2> Packet(const Buffer<C2>& b) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
{
}
Packet(const void *data,unsigned int len) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
Packet(const void* data, unsigned int len) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data, len)
{
}
@ -1107,11 +1116,10 @@ public:
* Use the header access methods (setDestination() and friends) to fill out
* the header. Payload should be appended; initial size is header size.
*/
Packet() :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
Packet() : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
{
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
}
/**
@ -1123,10 +1131,9 @@ public:
* @param prototype Prototype packet
* @param dest Destination ZeroTier address for new packet
*/
Packet(const Packet &prototype,const Address &dest) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
Packet(const Packet& prototype, const Address& dest) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
{
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest);
}
@ -1137,13 +1144,12 @@ public:
* @param source Source ZT address
* @param v Verb
*/
Packet(const Address &dest,const Address &source,const Verb v) :
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
Packet(const Address& dest, const Address& source, const Verb v) : Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
{
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest);
setSource(source);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
setVerb(v);
}
@ -1154,13 +1160,13 @@ public:
* @param source Source ZT address
* @param v Verb
*/
inline void reset(const Address &dest,const Address &source,const Verb v)
inline void reset(const Address& dest, const Address& source, const Verb v)
{
setSize(ZT_PROTO_MIN_PACKET_LENGTH);
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
setDestination(dest);
setSource(source);
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
(*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
setVerb(v);
}
@ -1171,45 +1177,66 @@ public:
* technically different but otherwise identical copies of the same
* packet.
*/
inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); }
inline void newInitializationVector()
{
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8);
}
/**
* Set this packet's destination
*
* @param dest ZeroTier address of destination
*/
inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
inline void setDestination(const Address& dest)
{
dest.copyTo(field(ZT_PACKET_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/**
* Set this packet's source
*
* @param source ZeroTier address of source
*/
inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
inline void setSource(const Address& source)
{
source.copyTo(field(ZT_PACKET_IDX_SOURCE, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/**
* Get this packet's destination
*
* @return Destination ZT address
*/
inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
inline Address destination() const
{
return Address(field(ZT_PACKET_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/**
* Get this packet's source
*
* @return Source ZT address
*/
inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
inline Address source() const
{
return Address(field(ZT_PACKET_IDX_SOURCE, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
}
/**
* @return True if packet is of valid length
*/
inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); }
inline bool lengthValid() const
{
return (size() >= ZT_PROTO_MIN_PACKET_LENGTH);
}
/**
* @return True if packet is fragmented (expect fragments)
*/
inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); }
inline bool fragmented() const
{
return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0);
}
/**
* Set this packet's fragmented flag
@ -1220,7 +1247,8 @@ public:
{
if (f) {
(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
} else {
}
else {
(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
}
}
@ -1228,19 +1256,25 @@ public:
/**
* @return True if compressed (result only valid if unencrypted)
*/
inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); }
inline bool compressed() const
{
return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0);
}
/**
* @return ZeroTier forwarding hops (0 to 7)
*/
inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); }
inline unsigned int hops() const
{
return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07);
}
/**
* Increment this packet's hop count
*/
inline void incrementHops()
{
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xf8) | ((b + 1) & 0x07);
}
@ -1265,12 +1299,13 @@ public:
*/
inline void setCipher(unsigned int c)
{
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
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) {
b |= ZT_PROTO_FLAG_ENCRYPTED;
} else {
}
else {
b &= (~ZT_PROTO_FLAG_ENCRYPTED);
}
}
@ -1280,7 +1315,10 @@ public:
*
* @return Trusted path ID (from MAC field)
*/
inline uint64_t trustedPathId() const { return at<uint64_t>(ZT_PACKET_IDX_MAC); }
inline uint64_t trustedPathId() const
{
return at<uint64_t>(ZT_PACKET_IDX_MAC);
}
/**
* Set this packet's trusted path ID and set the cipher spec to trusted path
@ -1290,7 +1328,7 @@ public:
inline void setTrusted(const uint64_t tpid)
{
setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH);
setAt(ZT_PACKET_IDX_MAC,tpid);
setAt(ZT_PACKET_IDX_MAC, tpid);
}
/**
@ -1304,7 +1342,10 @@ public:
*
* @return Packet ID
*/
inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_IDX_IV); }
inline uint64_t packetId() const
{
return at<uint64_t>(ZT_PACKET_IDX_IV);
}
/**
* Set packet verb
@ -1314,22 +1355,34 @@ public:
*
* @param v New packet verb
*/
inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; }
inline void setVerb(Verb v)
{
(*this)[ZT_PACKET_IDX_VERB] = (char)v;
}
/**
* @return Packet verb (not including flag bits)
*/
inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); }
inline Verb verb() const
{
return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f);
}
/**
* @return Length of packet payload
*/
inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); }
inline unsigned int payloadLength() const
{
return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH));
}
/**
* @return Raw packet payload
*/
inline const unsigned char *payload() const { return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); }
inline const unsigned char* payload() const
{
return field(ZT_PACKET_IDX_PAYLOAD, size() - ZT_PACKET_IDX_PAYLOAD);
}
/**
* Armor packet for transport
@ -1338,7 +1391,7 @@ public:
* @param encryptPayload If true, encrypt packet payload, else just MAC
* @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV
*/
void armor(const void *key,bool encryptPayload,const AES aesKeys[2]);
void armor(const void* key, bool encryptPayload, const AES aesKeys[2]);
/**
* Verify and (if encrypted) decrypt packet
@ -1351,7 +1404,7 @@ public:
* @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV
* @return False if packet is invalid or failed MAC authenticity check
*/
bool dearmor(const void *key,const AES aesKeys[2]);
bool dearmor(const void* key, const AES aesKeys[2]);
/**
* Encrypt/decrypt a separately armored portion of a packet
@ -1366,7 +1419,7 @@ public:
* @param start Start of encrypted portion
* @param len Length of encrypted portion
*/
void cryptField(const void *key,unsigned int start,unsigned int len);
void cryptField(const void* key, unsigned int start, unsigned int len);
/**
* Attempt to compress payload if not already (must be unencrypted)
@ -1390,7 +1443,7 @@ public:
*/
bool uncompress();
private:
private:
static const unsigned char ZERO_KEY[32];
/**
@ -1404,13 +1457,13 @@ private:
* @param in Input key (32 bytes)
* @param out Output buffer (32 bytes)
*/
inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const
inline void _salsa20MangleKey(const unsigned char* in, unsigned char* out) const
{
const unsigned char *d = (const unsigned char *)data();
const unsigned char* d = (const unsigned char*)data();
// 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];
}
@ -1422,15 +1475,15 @@ private:
// Raw packet size in bytes -- thus each packet size defines a new
// key space.
out[19] = in[19] ^ (unsigned char)(size() & 0xff);
out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian
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];
}
}
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -13,9 +13,9 @@
#include "PacketMultiplexer.hpp"
#include "Constants.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Constants.hpp"
#include <stdio.h>
#include <stdlib.h>
@ -30,12 +30,12 @@ PacketMultiplexer::PacketMultiplexer(const RuntimeEnvironment* renv)
void PacketMultiplexer::putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len, unsigned int flowId)
{
#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__WINDOWS__)
RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len);
RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len);
return;
#endif
if (!_enabled) {
RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len);
if (! _enabled) {
RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len);
return;
}

View file

@ -12,18 +12,19 @@
/****/
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
namespace ZeroTier {
bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now)
bool Path::send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now)
{
if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) {
if (RR->node->putPacket(tPtr, _localSocket, _addr, data, len)) {
_lastOut = now;
return true;
}
return false;
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,20 +14,19 @@
#ifndef ZT_PATH_HPP
#define ZT_PATH_HPP
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdexcept>
#include <algorithm>
#include "AtomicCounter.hpp"
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "Utils.hpp"
#include "Packet.hpp"
#include "RingBuffer.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <algorithm>
#include <stdexcept>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/**
* Maximum return value of preferenceRank()
@ -41,89 +40,102 @@ class RuntimeEnvironment;
/**
* A path across the physical network
*/
class Path
{
class Path {
friend class SharedPtr<Path>;
friend class Bond;
public:
public:
/**
* Efficient unique key for paths in a Hashtable
*/
class HashKey
{
public:
HashKey() {}
class HashKey {
public:
HashKey()
{
}
HashKey(const int64_t l,const InetAddress &r)
HashKey(const int64_t l, const InetAddress& r)
{
if (r.ss_family == AF_INET) {
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr;
_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port;
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in*>(&r)->sin_addr.s_addr;
_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in*>(&r)->sin_port;
_k[2] = (uint64_t)l;
} else if (r.ss_family == AF_INET6) {
memcpy(_k,reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port << 32) ^ (uint64_t)l;
} else {
memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress)));
}
else if (r.ss_family == AF_INET6) {
memcpy(_k, reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_addr.s6_addr, 16);
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6*>(&r)->sin6_port << 32) ^ (uint64_t)l;
}
else {
memcpy(_k, &r, std::min(sizeof(_k), sizeof(InetAddress)));
_k[2] += (uint64_t)l;
}
}
inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
inline unsigned long hashCode() const
{
return (unsigned long)(_k[0] + _k[1] + _k[2]);
}
inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
inline bool operator!=(const HashKey &k) const { return (!(*this == k)); }
inline bool operator==(const HashKey& k) const
{
return ((_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]));
}
inline bool operator!=(const HashKey& k) const
{
return (! (*this == k));
}
private:
private:
uint64_t _k[3];
};
Path() :
_lastOut(0),
_lastIn(0),
_lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localPort(0),
_localSocket(-1),
_latencyMean(0.0),
_latencyVariance(0.0),
_packetLossRatio(0.0),
_packetErrorRatio(0.0),
_assignedFlowCount(0),
_valid(true),
_eligible(false),
_bonded(false),
_mtu(0),
_givenLinkSpeed(0),
_relativeQuality(0),
_latency(0xffff),
_addr(),
_ipScope(InetAddress::IP_SCOPE_NONE)
{}
Path()
: _lastOut(0)
, _lastIn(0)
, _lastTrustEstablishedPacketReceived(0)
, _lastEchoRequestReceived(0)
, _localPort(0)
, _localSocket(-1)
, _latencyMean(0.0)
, _latencyVariance(0.0)
, _packetLossRatio(0.0)
, _packetErrorRatio(0.0)
, _assignedFlowCount(0)
, _valid(true)
, _eligible(false)
, _bonded(false)
, _mtu(0)
, _givenLinkSpeed(0)
, _relativeQuality(0)
, _latency(0xffff)
, _addr()
, _ipScope(InetAddress::IP_SCOPE_NONE)
{
}
Path(const int64_t localSocket,const InetAddress &addr) :
_lastOut(0),
_lastIn(0),
_lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localPort(0),
_localSocket(localSocket),
_latencyMean(0.0),
_latencyVariance(0.0),
_packetLossRatio(0.0),
_packetErrorRatio(0.0),
_assignedFlowCount(0),
_valid(true),
_eligible(false),
_bonded(false),
_mtu(0),
_givenLinkSpeed(0),
_relativeQuality(0),
_latency(0xffff),
_addr(addr),
_ipScope(addr.ipScope())
{}
Path(const int64_t localSocket, const InetAddress& addr)
: _lastOut(0)
, _lastIn(0)
, _lastTrustEstablishedPacketReceived(0)
, _lastEchoRequestReceived(0)
, _localPort(0)
, _localSocket(localSocket)
, _latencyMean(0.0)
, _latencyVariance(0.0)
, _packetLossRatio(0.0)
, _packetErrorRatio(0.0)
, _assignedFlowCount(0)
, _valid(true)
, _eligible(false)
, _bonded(false)
, _mtu(0)
, _givenLinkSpeed(0)
, _relativeQuality(0)
, _latency(0xffff)
, _addr(addr)
, _ipScope(addr.ipScope())
{
}
/**
* Called when a packet is received from this remote path, regardless of content
@ -138,7 +150,10 @@ public:
/**
* Set time last trusted packet was received (done in Peer::received())
*/
inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; }
inline void trustedPacketReceived(const uint64_t t)
{
_lastTrustEstablishedPacketReceived = t;
}
/**
* Send a packet via this path (last out time is also updated)
@ -150,14 +165,17 @@ public:
* @param now Current time
* @return True if transport reported success
*/
bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now);
bool send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now);
/**
* Manually update last sent time
*
* @param t Time of send
*/
inline void sent(const int64_t t) { _lastOut = t; }
inline void sent(const int64_t t)
{
_lastOut = t;
}
/**
* Update path latency with a new measurement
@ -169,7 +187,8 @@ public:
unsigned int pl = _latency;
if (pl < 0xffff) {
_latency = (pl + l) / 2;
} else {
}
else {
_latency = l;
}
}
@ -177,27 +196,42 @@ public:
/**
* @return Local socket as specified by external code
*/
inline int64_t localSocket() const { return _localSocket; }
inline int64_t localSocket() const
{
return _localSocket;
}
/**
* @return Local port corresponding to the localSocket
*/
inline int64_t localPort() const { return _localPort; }
inline int64_t localPort() const
{
return _localPort;
}
/**
* @return Physical address
*/
inline const InetAddress &address() const { return _addr; }
inline const InetAddress& address() const
{
return _addr;
}
/**
* @return IP scope -- faster shortcut for address().ipScope()
*/
inline InetAddress::IpScope ipScope() const { return _ipScope; }
inline InetAddress::IpScope ipScope() const
{
return _ipScope;
}
/**
* @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
inline bool trustEstablished(const int64_t now) const
{
return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION);
}
/**
* @return Preference rank, higher == better
@ -206,7 +240,7 @@ public:
{
// This causes us to rank paths in order of IP scope rank (see InetAddress.hpp) but
// within each IP scope class to prefer IPv6 over IPv4.
return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) );
return (((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6));
}
/**
@ -218,10 +252,10 @@ public:
* @param a Address to check
* @return True if address is good for ZeroTier path use
*/
static inline bool isAddressValidForPath(const InetAddress &a)
static inline bool isAddressValidForPath(const InetAddress& a)
{
if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) {
switch(a.ipScope()) {
if ((a.ss_family == AF_INET) || (a.ss_family == AF_INET6)) {
switch (a.ipScope()) {
/* Note: we don't do link-local at the moment. Unfortunately these
* cause several issues. The first is that they usually require a
* device qualifier, which we don't handle yet and can't portably
@ -237,8 +271,8 @@ public:
// TEMPORARY HACK: for now, we are going to blacklist he.net IPv6
// 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)) {
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)) {
return false;
}
}
@ -253,7 +287,10 @@ public:
/**
* @return Latency or 0xffff if unknown
*/
inline unsigned int latency() const { return _latency; }
inline unsigned int latency() const
{
return _latency;
}
/**
* @return Path quality -- lower is better
@ -261,41 +298,57 @@ public:
inline long quality(const int64_t now) const
{
const int l = (long)_latency;
const int age = (long)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow
const int age = (long)std::min((now - _lastIn), (int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow
return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1));
}
/**
* @return True if this path is alive (receiving heartbeats)
*/
inline bool alive(const int64_t now) const {
inline bool alive(const int64_t now) const
{
return (now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000);
}
/**
* @return True if this path needs a heartbeat
*/
inline bool needsHeartbeat(const int64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); }
inline bool needsHeartbeat(const int64_t now) const
{
return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD);
}
/**
* @return Last time we sent something
*/
inline int64_t lastOut() const { return _lastOut; }
inline int64_t lastOut() const
{
return _lastOut;
}
/**
* @return Last time we received anything
*/
inline int64_t lastIn() const { return _lastIn; }
inline int64_t lastIn() const
{
return _lastIn;
}
/**
* @return the age of the path in terms of receiving packets
*/
inline int64_t age(int64_t now) { return (now - _lastIn); }
inline int64_t age(int64_t now)
{
return (now - _lastIn);
}
/**
* @return Time last trust-established packet was received
*/
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
inline int64_t lastTrustEstablishedPacketReceived() const
{
return _lastTrustEstablishedPacketReceived;
}
/**
* Rate limit gate for inbound ECHO requests
@ -312,69 +365,102 @@ public:
/**
* @return Mean latency as reported by the bonding layer
*/
inline float latencyMean() const { return _latencyMean; }
inline float latencyMean() const
{
return _latencyMean;
}
/**
* @return Latency variance as reported by the bonding layer
*/
inline float latencyVariance() const { return _latencyVariance; }
inline float latencyVariance() const
{
return _latencyVariance;
}
/**
* @return Packet Loss Ratio as reported by the bonding layer
*/
inline float packetLossRatio() const { return _packetLossRatio; }
inline float packetLossRatio() const
{
return _packetLossRatio;
}
/**
* @return Packet Error Ratio as reported by the bonding layer
*/
inline float 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; }
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 bool 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 bool eligible() const { return _eligible; }
inline bool eligible() const
{
return _eligible;
}
/**
* @return Whether this path is bonded as reported by the bonding layer
*/
inline bool 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 uint16_t mtu() const { return _mtu; }
inline uint16_t mtu() const
{
return _mtu;
}
/**
* @return Given link capacity as reported by the bonding layer
*/
inline uint32_t givenLinkSpeed() const { return _givenLinkSpeed; }
inline uint32_t givenLinkSpeed() const
{
return _givenLinkSpeed;
}
/**
* @return Path's quality as reported by the bonding layer
*/
inline float relativeQuality() const { return _relativeQuality; }
inline float relativeQuality() const
{
return _relativeQuality;
}
/**
* @return Physical interface name that this path lives on
*/
char *ifname() {
char* ifname()
{
return _ifname;
}
private:
char _ifname[ZT_MAX_PHYSIFNAME] = { };
private:
char _ifname[ZT_MAX_PHYSIFNAME] = {};
volatile int64_t _lastOut;
volatile int64_t _lastIn;
@ -399,10 +485,10 @@ private:
volatile unsigned int _latency;
InetAddress _addr;
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
AtomicCounter __refCount;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,24 +11,25 @@
*/
/****/
#include "Peer.hpp"
#include "../version.h"
#include "Constants.hpp"
#include "Peer.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "SelfAwareness.hpp"
#include "Packet.hpp"
#include "Trace.hpp"
#include "InetAddress.hpp"
#include "RingBuffer.hpp"
#include "Utils.hpp"
#include "Metrics.hpp"
#include "Network.hpp"
#include "Packet.hpp"
#include "RingBuffer.hpp"
#include "SelfAwareness.hpp"
#include "Switch.hpp"
#include "Trace.hpp"
#include "Utils.hpp"
namespace ZeroTier {
static unsigned char s_freeRandomByteCounter = 0;
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity)
Peer::Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity)
: RR(renv)
, _lastReceive(0)
, _lastNontrivialReceive(0)
@ -52,29 +53,29 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
, _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())}})}
, _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);
KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K0, 0, 0, ktmp);
_aesKeys[0].init(ktmp);
KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K1,0,0,ktmp);
KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K1, 0, 0, ktmp);
_aesKeys[1].init(ktmp);
Utils::burn(ktmp,ZT_SYMMETRIC_KEY_SIZE);
Utils::burn(ktmp, ZT_SYMMETRIC_KEY_SIZE);
}
void Peer::received(
void *tPtr,
const SharedPtr<Path> &path,
void* tPtr,
const SharedPtr<Path>& path,
const unsigned int hops,
const uint64_t packetId,
const unsigned int payloadLength,
@ -114,7 +115,7 @@ void Peer::received(
bool havePath = false;
{
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if (_paths[i].p == path) {
_paths[i].lr = now;
@ -123,25 +124,26 @@ void Peer::received(
}
// If same address on same interface then don't learn unless existing path isn't alive (prevents learning loop)
if (_paths[i].p->address().ipsEqual(path->address()) && _paths[i].p->localSocket() == path->localSocket()) {
if (_paths[i].p->alive(now) && !_bond) {
if (_paths[i].p->alive(now) && ! _bond) {
havePath = true;
break;
}
}
} else {
}
else {
break;
}
}
}
if ( (!havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()) ) {
if ((! havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr, _id.address(), path->localSocket(), path->address())) {
if (verb == Packet::VERB_OK) {
Mutex::Lock _l(_paths_m);
unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int oldestPathAge = 0;
unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
// Keep track of oldest path as a last resort option
unsigned int currAge = _paths[i].p->age(now);
@ -151,13 +153,14 @@ void Peer::received(
}
if (_paths[i].p->address().ipsEqual(path->address())) {
if (_paths[i].p->localSocket() == path->localSocket()) {
if (!_paths[i].p->alive(now)) {
if (! _paths[i].p->alive(now)) {
replacePath = i;
break;
}
}
}
} else {
}
else {
replacePath = i;
break;
}
@ -171,30 +174,33 @@ void Peer::received(
_paths[replacePath].p = path;
_paths[replacePath].priority = 1;
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
_bond->nominatePathToBond(_paths[replacePath].p, now);
}
}
} else {
}
else {
Mutex::Lock ltl(_lastTriedPath_m);
bool triedTooRecently = false;
for(std::list< std::pair< Path *, int64_t > >::iterator i(_lastTriedPath.begin());i!=_lastTriedPath.end();) {
for (std::list<std::pair<Path*, int64_t> >::iterator i(_lastTriedPath.begin()); i != _lastTriedPath.end();) {
if ((now - i->second) > 1000) {
_lastTriedPath.erase(i++);
} else if (i->first == path.ptr()) {
}
else if (i->first == path.ptr()) {
++i;
triedTooRecently = true;
} else {
}
else {
++i;
}
}
if (!triedTooRecently) {
_lastTriedPath.push_back(std::pair< Path *, int64_t >(path.ptr(), now));
attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true);
if (! triedTooRecently) {
_lastTriedPath.push_back(std::pair<Path*, int64_t>(path.ptr(), now));
attemptToContactAt(tPtr, path->localSocket(), path->address(), now, true);
path->sent(now);
RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb);
RR->t->peerConfirmingUnknownPath(tPtr, networkId, *this, path, packetId, verb);
}
}
}
@ -212,30 +218,30 @@ void Peer::received(
std::vector<InetAddress> pathsToPush(RR->node->directPaths());
std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
if (!pathsToPush.empty()) {
if (! pathsToPush.empty()) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) {
Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
outp->addSize(2); // leave room for count
Packet* const outp = new Packet(_id.address(), RR->identity.address(), Packet::VERB_PUSH_DIRECT_PATHS);
outp->addSize(2); // leave room for count
unsigned int count = 0;
while ((p != pathsToPush.end())&&((outp->size() + 24) < 1200)) {
while ((p != pathsToPush.end()) && ((outp->size() + 24) < 1200)) {
uint8_t addressType = 4;
switch(p->ss_family) {
switch (p->ss_family) {
case AF_INET:
break;
case AF_INET6:
addressType = 6;
break;
default: // we currently only push IP addresses
default: // we currently only push IP addresses
++p;
continue;
}
outp->append((uint8_t)0); // no flags
outp->append((uint16_t)0); // no extensions
outp->append((uint8_t)0); // no flags
outp->append((uint16_t)0); // no extensions
outp->append(addressType);
outp->append((uint8_t)((addressType == 4) ? 6 : 18));
outp->append(p->rawIpData(),((addressType == 4) ? 4 : 16));
outp->append(p->rawIpData(), ((addressType == 4) ? 4 : 16));
outp->append((uint16_t)p->port());
++count;
@ -243,11 +249,11 @@ void Peer::received(
}
if (count) {
Metrics::pkt_push_direct_paths_out++;
outp->setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
outp->setAt(ZT_PACKET_IDX_PAYLOAD, (uint16_t)count);
outp->compress();
outp->armor(_key,true,aesKeysIfSupported());
outp->armor(_key, true, aesKeysIfSupported());
Metrics::pkt_push_direct_paths_out++;
path->send(RR,tPtr,outp->data(),outp->size(),now);
path->send(RR, tPtr, outp->data(), outp->size(), now);
}
delete outp;
}
@ -260,7 +266,7 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
{
Mutex::Lock _l(_paths_m);
Mutex::Lock _lb(_bond_m);
if(_bond && _bond->isReady()) {
if (_bond && _bond->isReady()) {
return _bond->getAppropriatePath(now, flowId);
}
unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS;
@ -269,16 +275,17 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
* use the old path quality metric from protocol version 9.
*/
long bestPathQuality = 2147483647;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if ((includeExpired)||((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)) {
if ((includeExpired) || ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)) {
const long q = _paths[i].p->quality(now) / _paths[i].priority;
if (q <= bestPathQuality) {
bestPathQuality = q;
bestPath = i;
}
}
} else {
}
else {
break;
}
}
@ -288,17 +295,17 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired, int32
return SharedPtr<Path>();
}
void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const
void Peer::introduce(void* const tPtr, const int64_t now, const SharedPtr<Peer>& other) const
{
unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1];
for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) {
unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1];
for (int i = 0; i <= ZT_INETADDRESS_MAX_SCOPE; ++i) {
myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS;
myBestV4QualityByScope[i] = 2147483647;
@ -311,11 +318,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
Mutex::Lock _l1(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
const long q = _paths[i].p->quality(now) / _paths[i].priority;
const unsigned int s = (unsigned int)_paths[i].p->ipScope();
switch(_paths[i].p->address().ss_family) {
switch (_paths[i].p->address().ss_family) {
case AF_INET:
if (q <= myBestV4QualityByScope[s]) {
myBestV4QualityByScope[s] = q;
@ -329,18 +336,19 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
break;
}
} else {
}
else {
break;
}
}
Mutex::Lock _l2(other->_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (other->_paths[i].p) {
const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority;
const unsigned int s = (unsigned int)other->_paths[i].p->ipScope();
switch(other->_paths[i].p->address().ss_family) {
switch (other->_paths[i].p->address().ss_family) {
case AF_INET:
if (q <= theirBestV4QualityByScope[s]) {
theirBestV4QualityByScope[s] = q;
@ -354,7 +362,8 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
break;
}
} else {
}
else {
break;
}
}
@ -362,13 +371,13 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS;
unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS;
for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) {
if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
for (int s = ZT_INETADDRESS_MAX_SCOPE; s >= 0; --s) {
if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
mine = myBestV6ByScope[s];
theirs = theirBestV6ByScope[s];
break;
}
if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) {
mine = myBestV4ByScope[s];
theirs = theirBestV4ByScope[s];
break;
@ -376,55 +385,58 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
if (mine != ZT_MAX_PEER_NETWORK_PATHS) {
unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons
unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons
const unsigned int completed = alt + 2;
while (alt != completed) {
if ((alt & 1) == 0) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS);
Packet outp(_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0);
other->_id.address().appendTo(outp);
outp.append((uint16_t)other->_paths[theirs].p->address().port());
if (other->_paths[theirs].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16);
outp.append(other->_paths[theirs].p->address().rawIpData(),16);
} else {
outp.append((uint8_t)4);
outp.append(other->_paths[theirs].p->address().rawIpData(),4);
outp.append(other->_paths[theirs].p->address().rawIpData(), 16);
}
outp.armor(_key,true,aesKeysIfSupported());
else {
outp.append((uint8_t)4);
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);
_paths[mine].p->send(RR, tPtr, outp.data(), outp.size(), now);
}
else {
Packet outp(other->_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS);
outp.append((uint8_t)0);
_id.address().appendTo(outp);
outp.append((uint16_t)_paths[mine].p->address().port());
if (_paths[mine].p->address().ss_family == AF_INET6) {
outp.append((uint8_t)16);
outp.append(_paths[mine].p->address().rawIpData(),16);
} else {
outp.append((uint8_t)4);
outp.append(_paths[mine].p->address().rawIpData(),4);
outp.append(_paths[mine].p->address().rawIpData(), 16);
}
outp.armor(other->_key,true,other->aesKeysIfSupported());
else {
outp.append((uint8_t)4);
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);
other->_paths[theirs].p->send(RR, tPtr, outp.data(), outp.size(), now);
}
++alt;
}
}
}
void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now)
void Peer::sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now)
{
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO);
Packet outp(_id.address(), RR->identity.address(), Packet::VERB_HELLO);
outp.append((unsigned char)ZT_PROTO_VERSION);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
outp.append(now);
RR->identity.serialize(outp,false);
RR->identity.serialize(outp, false);
atAddress.serialize(outp);
outp.append((uint64_t)RR->topology->planetWorldId());
@ -435,56 +447,58 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
std::vector<World> moons(RR->topology->moons());
std::vector<uint64_t> moonsWanted(RR->topology->moonsWanted());
outp.append((uint16_t)(moons.size() + moonsWanted.size()));
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
for (std::vector<World>::const_iterator m(moons.begin()); m != moons.end(); ++m) {
outp.append((uint8_t)m->type());
outp.append((uint64_t)m->id());
outp.append((uint64_t)m->timestamp());
}
for(std::vector<uint64_t>::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) {
for (std::vector<uint64_t>::const_iterator m(moonsWanted.begin()); m != moonsWanted.end(); ++m) {
outp.append((uint8_t)World::TYPE_MOON);
outp.append(*m);
outp.append((uint64_t)0);
}
outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt);
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
outp.armor(_key, false, nullptr); // false == don't encrypt full payload, but add MAC
RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -1,atAddress,outp.data(),outp.size());
} else {
RR->node->putPacket(tPtr, RR->node->lowBandwidthModeEnabled() ? localSocket : -1, atAddress, outp.data(), outp.size());
}
else {
RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC
RR->sw->send(tPtr, outp, false); // false == don't encrypt full payload, but add MAC
}
}
void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello)
void Peer::attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello)
{
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());
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 {
sendHELLO(tPtr,localSocket,atAddress,now);
RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size());
}
else {
sendHELLO(tPtr, localSocket, atAddress, now);
}
}
void Peer::tryMemorizedPath(void *tPtr,int64_t now)
void Peer::tryMemorizedPath(void* tPtr, int64_t now)
{
if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) {
_lastTriedMemorizedPath = now;
InetAddress mp;
if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) {
attemptToContactAt(tPtr,-1,mp,now,true);
if (RR->node->externalPathLookup(tPtr, _id.address(), -1, mp)) {
attemptToContactAt(tPtr, -1, mp, now, true);
}
}
}
void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
void Peer::performMultipathStateCheck(void* tPtr, int64_t now)
{
Mutex::Lock _l(_bond_m);
/**
@ -493,9 +507,9 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
*/
int numAlivePaths = 0;
bool atLeastOneNonExpired = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if(_paths[i].p->alive(now)) {
if (_paths[i].p->alive(now)) {
numAlivePaths++;
}
if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) {
@ -504,21 +518,21 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
}
}
if (_bond) {
if (numAlivePaths == 0 && !atLeastOneNonExpired) {
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 (_localMultipathSupported && ! _bond) {
if (RR->bc) {
_bond = RR->bc->createBond(RR, this);
/**
* Allow new bond to retroactively learn all paths known to this peer
*/
if (_bond) {
for (unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
_bond->nominatePathToBond(_paths[i].p, now);
}
@ -528,7 +542,7 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
}
}
unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
unsigned int Peer::doPingAndKeepalive(void* tPtr, int64_t now)
{
unsigned int sent = 0;
{
@ -546,31 +560,33 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
// 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) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
maxPriority = std::max(_paths[i].priority,maxPriority);
} else {
maxPriority = std::max(_paths[i].priority, maxPriority);
}
else {
break;
}
}
bool deletionOccurred = false;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
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);
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 {
}
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[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();
@ -582,7 +598,7 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
}
#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) {
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++;
@ -602,25 +618,26 @@ unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now)
return sent;
}
void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,const InetAddress &remoteAddress,const int64_t now)
void Peer::clusterRedirect(void* tPtr, const SharedPtr<Path>& originatingPath, const InetAddress& remoteAddress, const int64_t now)
{
SharedPtr<Path> np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress));
RR->t->peerRedirected(tPtr,0,*this,np);
SharedPtr<Path> np(RR->topology->getPath(originatingPath->localSocket(), remoteAddress));
RR->t->peerRedirected(tPtr, 0, *this, np);
attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true);
attemptToContactAt(tPtr, originatingPath->localSocket(), remoteAddress, now, true);
{
Mutex::Lock _l(_paths_m);
// New priority is higher than the priority of the originating path (if known)
long newPriority = 1;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if (_paths[i].p == originatingPath) {
newPriority = _paths[i].priority;
break;
}
} else {
}
else {
break;
}
}
@ -629,9 +646,9 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
// Erase any paths with lower priority than this one or that are duplicate
// IPs and add this path.
unsigned int j = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
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 ((_paths[i].priority >= newPriority) && (! _paths[i].p->address().ipsEqual2(remoteAddress))) {
if (i != j) {
_paths[j] = _paths[i];
}
@ -654,24 +671,24 @@ void Peer::clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,con
}
}
void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now)
void Peer::resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now)
{
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
if ((_paths[i].p->address().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) {
attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false);
if ((_paths[i].p->address().ss_family == inetAddressFamily) && (_paths[i].p->ipScope() == scope)) {
attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, false);
_paths[i].p->sent(now);
_paths[i].lr = 0; // path will not be used unless it speaks again
_paths[i].lr = 0; // path will not be used unless it speaks again
}
} else {
}
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)
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++;
@ -691,12 +708,11 @@ void Peer::recordIncomingInvalidPacket(const SharedPtr<Path>& path)
}
}
void Peer::recordIncomingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
void Peer::recordIncomingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now)
{
if (_localMultipathSupported && _bond) {
_bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now);
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,27 +14,26 @@
#ifndef ZT_PEER_HPP
#define ZT_PEER_HPP
#include <vector>
#include <list>
#include "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "Path.hpp"
#include "AES.hpp"
#include "Address.hpp"
#include "Utils.hpp"
#include "AtomicCounter.hpp"
#include "Bond.hpp"
#include "Constants.hpp"
#include "Hashtable.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "Packet.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#include "Bond.hpp"
#include "AES.hpp"
#include "Metrics.hpp"
#include "Mutex.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Path.hpp"
#include "RuntimeEnvironment.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#include <list>
#include <vector>
#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2))
@ -43,19 +42,19 @@ namespace ZeroTier {
/**
* Peer on P2P Network (virtual layer 1)
*/
class Peer
{
class Peer {
friend class SharedPtr<Peer>;
friend class SharedPtr<Bond>;
friend class Switch;
friend class Bond;
private:
Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized
private:
Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized
public:
~Peer() {
Utils::burn(_key,sizeof(_key));
public:
~Peer()
{
Utils::burn(_key, sizeof(_key));
}
/**
@ -66,17 +65,23 @@ public:
* @param peerIdentity Identity of peer
* @throws std::runtime_error Key agreement with peer's identity failed
*/
Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity);
Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity);
/**
* @return This peer's ZT address (short for identity().address())
*/
inline const Address &address() const { return _id.address(); }
inline const Address& address() const
{
return _id.address();
}
/**
* @return This peer's identity
*/
inline const Identity &identity() const { return _id; }
inline const Identity& identity() const
{
return _id;
}
/**
* Log receipt of an authenticated packet
@ -95,8 +100,8 @@ public:
* @param networkId Network ID if this pertains to a network, or 0 otherwise
*/
void received(
void *tPtr,
const SharedPtr<Path> &path,
void* tPtr,
const SharedPtr<Path>& path,
const unsigned int hops,
const uint64_t packetId,
const unsigned int payloadLength,
@ -114,15 +119,16 @@ public:
* @param addr Remote address
* @return True if we have an active path to this destination
*/
inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const
inline bool hasActivePathTo(int64_t now, const InetAddress& addr) const
{
Mutex::Lock _l(_paths_m);
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
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 {
}
else {
break;
}
}
@ -139,11 +145,11 @@ public:
* @param force If true, send even if path is not alive
* @return True if we actually sent something
*/
inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
inline bool sendDirect(void* tPtr, const void* data, unsigned int len, int64_t now, bool force)
{
SharedPtr<Path> bp(getAppropriatePath(now,force));
SharedPtr<Path> bp(getAppropriatePath(now, force));
if (bp) {
return bp->send(RR,tPtr,data,len,now);
return bp->send(RR, tPtr, data, len, now);
}
return false;
}
@ -159,8 +165,7 @@ public:
* @param flowId Flow ID
* @param now Current time
*/
void recordIncomingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
void recordIncomingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
/**
*
@ -171,8 +176,7 @@ public:
* @param flowId Flow ID
* @param now Current time
*/
void recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
void recordOutgoingPacket(const SharedPtr<Path>& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now);
/**
* Record an invalid incoming packet. This packet failed
@ -195,7 +199,7 @@ public:
/**
* Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path
*/
void introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const;
void introduce(void* const tPtr, const int64_t now, const SharedPtr<Peer>& other) const;
/**
* Send a HELLO to this peer at a specified physical address
@ -207,7 +211,7 @@ public:
* @param atAddress Destination address
* @param now Current time
*/
void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now);
void sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now);
/**
* Send ECHO (or HELLO for older peers) to this peer at the given address
@ -220,7 +224,7 @@ public:
* @param now Current time
* @param sendFullHello If true, always send a full HELLO instead of just an ECHO
*/
void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello);
void attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello);
/**
* Try a memorized or statically defined path if any are known
@ -230,14 +234,14 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param now Current time
*/
void tryMemorizedPath(void *tPtr,int64_t now);
void tryMemorizedPath(void* tPtr, int64_t now);
/**
* A check to be performed periodically which determines whether multipath communication is
* possible with this peer. This check should be performed early in the life-cycle of the peer
* as well as during the process of learning new paths.
*/
void performMultipathStateCheck(void *tPtr, int64_t now);
void performMultipathStateCheck(void* tPtr, int64_t now);
/**
* Send pings or keepalives depending on configured timeouts
@ -249,7 +253,7 @@ public:
* @param inetAddressFamily Keep this address family alive, or -1 for any
* @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent)
*/
unsigned int doPingAndKeepalive(void *tPtr,int64_t now);
unsigned int doPingAndKeepalive(void* tPtr, int64_t now);
/**
* Process a cluster redirect sent by this peer
@ -259,7 +263,7 @@ public:
* @param remoteAddress Remote address
* @param now Current time
*/
void clusterRedirect(void *tPtr,const SharedPtr<Path> &originatingPath,const InetAddress &remoteAddress,const int64_t now);
void clusterRedirect(void* tPtr, const SharedPtr<Path>& originatingPath, const InetAddress& remoteAddress, const int64_t now);
/**
* Reset paths within a given IP scope and address family
@ -274,18 +278,18 @@ public:
* @param inetAddressFamily Family e.g. AF_INET
* @param now Current time
*/
void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now);
void resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now);
/**
* @param now Current time
* @return All known paths to this peer
*/
inline std::vector< SharedPtr<Path> > paths(const int64_t now) const
inline std::vector<SharedPtr<Path> > paths(const int64_t now) const
{
std::vector< SharedPtr<Path> > pp;
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) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (! _paths[i].p) {
break;
}
pp.push_back(_paths[i].p);
@ -296,19 +300,31 @@ public:
/**
* @return Time of last receive of anything, whether direct or relayed
*/
inline int64_t lastReceive() const { return _lastReceive; }
inline int64_t lastReceive() const
{
return _lastReceive;
}
/**
* @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT
*/
inline bool isAlive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
inline bool isAlive(const int64_t now) const
{
return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT);
}
/**
* @return True if this peer has sent us real network traffic recently
*/
inline int64_t isActive(int64_t now) const { return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
inline int64_t isActive(int64_t now) const
{
return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT);
}
inline int64_t lastSentFullHello() { return _lastSentFullHello; }
inline int64_t lastSentFullHello()
{
return _lastSentFullHello;
}
/**
* @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths
@ -317,8 +333,9 @@ public:
{
if (_localMultipathSupported) {
return (int)_lastComputedAggregateMeanLatency;
} else {
SharedPtr<Path> bp(getAppropriatePath(now,false));
}
else {
SharedPtr<Path> bp(getAppropriatePath(now, false));
if (bp) {
return (unsigned int)bp->latency();
}
@ -344,7 +361,7 @@ public:
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));
@ -353,7 +370,10 @@ public:
/**
* @return 256-bit secret symmetric encryption key
*/
inline const unsigned char *key() const { return _key; }
inline const unsigned char* key() const
{
return _key;
}
/**
* Set the currently known remote version of this peer's client
@ -363,7 +383,7 @@ public:
* @param vmin Minor version
* @param vrev Revision
*/
inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
inline void setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev)
{
_vProto = (uint16_t)vproto;
_vMajor = (uint16_t)vmaj;
@ -371,17 +391,35 @@ public:
_vRevision = (uint16_t)vrev;
}
inline unsigned int remoteVersionProtocol() const { return _vProto; }
inline unsigned int remoteVersionMajor() const { return _vMajor; }
inline unsigned int remoteVersionMinor() const { return _vMinor; }
inline unsigned int remoteVersionRevision() const { return _vRevision; }
inline unsigned int remoteVersionProtocol() const
{
return _vProto;
}
inline unsigned int remoteVersionMajor() const
{
return _vMajor;
}
inline unsigned int remoteVersionMinor() const
{
return _vMinor;
}
inline unsigned int remoteVersionRevision() const
{
return _vRevision;
}
inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
inline bool remoteVersionKnown() const
{
return ((_vMajor > 0) || (_vMinor > 0) || (_vRevision > 0));
}
/**
* @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms
*/
inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); }
inline bool trustEstablished(const int64_t now) const
{
return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION);
}
/**
* Rate limit gate for VERB_PUSH_DIRECT_PATHS
@ -390,7 +428,8 @@ public:
{
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) {
++_directPathPushCutoffCount;
} else {
}
else {
_directPathPushCutoffCount = 0;
}
_lastDirectPathPushReceive = now;
@ -439,10 +478,10 @@ public:
inline bool rateGateQoS(int64_t now, SharedPtr<Path>& path)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
return _bond->rateGateQoS(now, path);
}
return false; // Default behavior. If there is no bond, we drop these
return false; // Default behavior. If there is no bond, we drop these
}
/**
@ -451,7 +490,7 @@ public:
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) {
if (_bond) {
_bond->receivedQoS(path, now, count, rx_id, rx_ts);
}
}
@ -462,7 +501,7 @@ public:
void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>& path, int16_t remoteUtility)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
_bond->processIncomingPathNegotiationRequest(now, path, remoteUtility);
}
}
@ -473,10 +512,10 @@ public:
inline bool rateGatePathNegotiation(int64_t now, SharedPtr<Path>& path)
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
return _bond->rateGatePathNegotiation(now, path);
}
return false; // Default behavior. If there is no bond, we drop these
return false; // Default behavior. If there is no bond, we drop these
}
/**
@ -485,7 +524,7 @@ public:
bool flowHashingSupported()
{
Mutex::Lock _l(_bond_m);
if(_bond) {
if (_bond) {
return _bond->flowHashingSupported();
}
return false;
@ -496,8 +535,7 @@ public:
*
* This does not serialize everything, just non-ephemeral information.
*/
template<unsigned int C>
inline void serializeForCache(Buffer<C> &b) const
template <unsigned int C> inline void serializeForCache(Buffer<C>& b) const
{
b.append((uint8_t)2);
@ -511,22 +549,22 @@ public:
{
Mutex::Lock _l(_paths_m);
unsigned int pc = 0;
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) {
++pc;
} else {
}
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);
}
}
}
template<unsigned int C>
inline static SharedPtr<Peer> deserializeFromCache(int64_t now,void *tPtr,Buffer<C> &b,const RuntimeEnvironment *renv)
template <unsigned int C> inline static SharedPtr<Peer> deserializeFromCache(int64_t now, void* tPtr, Buffer<C>& b, const RuntimeEnvironment* renv)
{
try {
unsigned int ptr = 0;
@ -535,12 +573,12 @@ public:
}
Identity id;
ptr += id.deserialize(b,ptr);
if (!id) {
ptr += id.deserialize(b, ptr);
if (! id) {
return SharedPtr<Peer>();
}
SharedPtr<Peer> p(new Peer(renv,renv->identity,id));
SharedPtr<Peer> p(new Peer(renv, renv->identity, id));
p->_vProto = b.template at<uint16_t>(ptr);
ptr += 2;
@ -556,20 +594,22 @@ public:
// Paths are fairly ephemeral in the real world in most cases.
const unsigned int tryPathCount = b.template at<uint16_t>(ptr);
ptr += 2;
for(unsigned int i=0;i<tryPathCount;++i) {
for (unsigned int i = 0; i < tryPathCount; ++i) {
InetAddress inaddr;
try {
ptr += inaddr.deserialize(b,ptr);
ptr += inaddr.deserialize(b, ptr);
if (inaddr) {
p->attemptToContactAt(tPtr,-1,inaddr,now,true);
p->attemptToContactAt(tPtr, -1, inaddr, now, true);
}
} catch ( ... ) {
}
catch (...) {
break;
}
}
return p;
} catch ( ... ) {
}
catch (...) {
return SharedPtr<Peer>();
}
}
@ -577,12 +617,16 @@ public:
/**
* @return The bonding policy used to reach this peer
*/
SharedPtr<Bond> bond() { return _bond; }
SharedPtr<Bond> bond()
{
return _bond;
}
/**
* @return The bonding policy used to reach this peer
*/
inline int8_t bondingPolicy() {
inline int8_t bondingPolicy()
{
Mutex::Lock _l(_bond_m);
if (_bond) {
return _bond->policy();
@ -593,7 +637,8 @@ public:
/**
* @return the number of links in this bond which are considered alive
*/
inline uint8_t getNumAliveLinks() {
inline uint8_t getNumAliveLinks()
{
Mutex::Lock _l(_paths_m);
if (_bond) {
return _bond->getNumAliveLinks();
@ -604,7 +649,8 @@ public:
/**
* @return the number of links in this bond
*/
inline uint8_t getNumTotalLinks() {
inline uint8_t getNumTotalLinks()
{
Mutex::Lock _l(_paths_m);
if (_bond) {
return _bond->getNumTotalLinks();
@ -612,31 +658,36 @@ public:
return 0;
}
//inline const AES *aesKeysIfSupported() const
// inline const AES *aesKeysIfSupported() const
//{ return (const AES *)0; }
inline const AES *aesKeysIfSupported() const
{ return (_vProto >= 12) ? _aesKeys : (const AES *)0; }
inline const AES *aesKeys() const
{ return _aesKeys; }
private:
struct _PeerPath
inline const AES* aesKeysIfSupported() const
{
_PeerPath() : lr(0),p(),priority(1) {}
int64_t lr; // time of last valid ZeroTier packet
return (_vProto >= 12) ? _aesKeys : (const AES*)0;
}
inline const AES* aesKeys() const
{
return _aesKeys;
}
private:
struct _PeerPath {
_PeerPath() : lr(0), p(), priority(1)
{
}
int64_t lr; // time of last valid ZeroTier packet
SharedPtr<Path> p;
long priority; // >= 1, higher is better
long priority; // >= 1, higher is better
};
uint8_t _key[ZT_SYMMETRIC_KEY_SIZE];
AES _aesKeys[2];
const RuntimeEnvironment *RR;
const RuntimeEnvironment* RR;
int64_t _lastReceive; // direct or indirect
int64_t _lastNontrivialReceive; // frames, things like netconf, etc.
int64_t _lastReceive; // direct or indirect
int64_t _lastNontrivialReceive; // frames, things like netconf, etc.
int64_t _lastTriedMemorizedPath;
int64_t _lastDirectPathPushSent;
int64_t _lastDirectPathPushReceive;
@ -654,7 +705,7 @@ private:
uint16_t _vMinor;
uint16_t _vRevision;
std::list< std::pair< Path *, int64_t > > _lastTriedPath;
std::list<std::pair<Path*, int64_t> > _lastTriedPath;
Mutex _lastTriedPath_m;
_PeerPath _paths[ZT_MAX_PEER_NETWORK_PATHS];
@ -679,7 +730,7 @@ private:
SharedPtr<Bond> _bond;
#ifndef ZT_NO_PEER_METRICS
prometheus::Histogram<uint64_t> &_peer_latency;
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;
@ -688,15 +739,14 @@ private:
#endif
};
} // namespace ZeroTier
} // namespace ZeroTier
// Add a swap() for shared ptr's to peers to speed up peer sorts
namespace std {
template<>
inline void swap(ZeroTier::SharedPtr<ZeroTier::Peer> &a,ZeroTier::SharedPtr<ZeroTier::Peer> &b)
{
a.swap(b);
}
template <> inline void swap(ZeroTier::SharedPtr<ZeroTier::Peer>& a, ZeroTier::SharedPtr<ZeroTier::Peer>& b)
{
a.swap(b);
}
} // namespace std
#endif

View file

@ -4,16 +4,17 @@ D. J. Bernstein
Public domain.
*/
#include "Constants.hpp"
#include "Poly1305.hpp"
#include <stdio.h>
#include "Constants.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WINDOWS__
#pragma warning(disable: 4146)
#pragma warning(disable : 4146)
#endif
namespace ZeroTier {
@ -21,8 +22,8 @@ namespace ZeroTier {
namespace {
typedef struct poly1305_context {
size_t aligner;
unsigned char opaque[136];
size_t aligner;
unsigned char opaque[136];
} poly1305_context;
#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
@ -31,32 +32,42 @@ typedef struct poly1305_context {
// 128-bit implementation for MSC and GCC from Poly1305-donna
#if defined(_MSC_VER)
#include <intrin.h>
#include <intrin.h>
typedef struct uint128_t {
unsigned long long lo;
unsigned long long hi;
} uint128_t;
typedef struct uint128_t {
unsigned long long lo;
unsigned long long hi;
} uint128_t;
#define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi)
#define ADD(out, in) { unsigned long long t = out.lo; out.lo += in.lo; out.hi += (out.lo < t) + in.hi; }
#define ADDLO(out, in) { unsigned long long t = out.lo; out.lo += in; out.hi += (out.lo < t); }
#define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift)))
#define LO(in) (in.lo)
#define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi)
#define ADD(out, in) \
{ \
unsigned long long t = out.lo; \
out.lo += in.lo; \
out.hi += (out.lo < t) + in.hi; \
}
#define ADDLO(out, in) \
{ \
unsigned long long t = out.lo; \
out.lo += in; \
out.hi += (out.lo < t); \
}
#define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift)))
#define LO(in) (in.lo)
// #define POLY1305_NOINLINE __declspec(noinline)
#elif defined(__GNUC__)
#if defined(__SIZEOF_INT128__)
typedef unsigned __int128 uint128_t;
#else
typedef unsigned uint128_t __attribute__((mode(TI)));
#endif
#if defined(__SIZEOF_INT128__)
typedef unsigned __int128 uint128_t;
#else
typedef unsigned uint128_t __attribute__((mode(TI)));
#endif
#define MUL(out, x, y) out = ((uint128_t)x * y)
#define ADD(out, in) out += in
#define ADDLO(out, in) out += in
#define SHR(in, shift) (unsigned long long)(in >> (shift))
#define LO(in) (unsigned long long)(in)
#define MUL(out, x, y) out = ((uint128_t)x * y)
#define ADD(out, in) out += in
#define ADDLO(out, in) out += in
#define SHR(in, shift) (unsigned long long)(in >> (shift))
#define LO(in) (unsigned long long)(in)
// #define POLY1305_NOINLINE __attribute__((noinline))
#endif
@ -65,192 +76,228 @@ typedef struct poly1305_context {
/* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */
typedef struct poly1305_state_internal_t {
unsigned long long r[3];
unsigned long long h[3];
unsigned long long pad[2];
size_t leftover;
unsigned char buffer[poly1305_block_size];
unsigned char final;
unsigned long long r[3];
unsigned long long h[3];
unsigned long long pad[2];
size_t leftover;
unsigned char buffer[poly1305_block_size];
unsigned char final;
} poly1305_state_internal_t;
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline unsigned long long U8TO64(const unsigned char *p)
static inline unsigned long long U8TO64(const unsigned char* p)
{
return
(((unsigned long long)(p[0] & 0xff) ) |
((unsigned long long)(p[1] & 0xff) << 8) |
((unsigned long long)(p[2] & 0xff) << 16) |
((unsigned long long)(p[3] & 0xff) << 24) |
((unsigned long long)(p[4] & 0xff) << 32) |
((unsigned long long)(p[5] & 0xff) << 40) |
((unsigned long long)(p[6] & 0xff) << 48) |
((unsigned long long)(p[7] & 0xff) << 56));
return (
((unsigned long long)(p[0] & 0xff)) | ((unsigned long long)(p[1] & 0xff) << 8) | ((unsigned long long)(p[2] & 0xff) << 16) | ((unsigned long long)(p[3] & 0xff) << 24) | ((unsigned long long)(p[4] & 0xff) << 32)
| ((unsigned long long)(p[5] & 0xff) << 40) | ((unsigned long long)(p[6] & 0xff) << 48) | ((unsigned long long)(p[7] & 0xff) << 56));
}
#else
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p))
#define U8TO64(p) (*reinterpret_cast<const unsigned long long*>(p))
#endif
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
static inline void U64TO8(unsigned char *p, unsigned long long v)
static inline void U64TO8(unsigned char* p, unsigned long long v)
{
p[0] = (v ) & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff;
p[4] = (v >> 32) & 0xff;
p[5] = (v >> 40) & 0xff;
p[6] = (v >> 48) & 0xff;
p[7] = (v >> 56) & 0xff;
p[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff;
p[4] = (v >> 32) & 0xff;
p[5] = (v >> 40) & 0xff;
p[6] = (v >> 48) & 0xff;
p[7] = (v >> 56) & 0xff;
}
#else
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v))
#define U64TO8(p, v) ((*reinterpret_cast<unsigned long long*>(p)) = (v))
#endif
static inline void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned long long t0,t1;
static inline void poly1305_init(poly1305_context* ctx, const unsigned char key[32])
{
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long t0, t1;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO64(&key[0]);
t1 = U8TO64(&key[8]);
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO64(&key[0]);
t1 = U8TO64(&key[8]);
st->r[0] = ( t0 ) & 0xffc0fffffff;
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f;
st->r[0] = (t0) & 0xffc0fffffff;
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
/* h = 0 */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
/* h = 0 */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
/* save pad for later */
st->pad[0] = U8TO64(&key[16]);
st->pad[1] = U8TO64(&key[24]);
/* save pad for later */
st->pad[0] = U8TO64(&key[16]);
st->pad[1] = U8TO64(&key[24]);
st->leftover = 0;
st->final = 0;
st->leftover = 0;
st->final = 0;
}
static inline void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
unsigned long long r0,r1,r2;
unsigned long long s1,s2;
unsigned long long h0,h1,h2;
unsigned long long c;
uint128_t d0,d1,d2,d;
static inline void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes)
{
const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
unsigned long long r0, r1, r2;
unsigned long long s1, s2;
unsigned long long h0, h1, h2;
unsigned long long c;
uint128_t d0, d1, d2, d;
r0 = st->r[0];
r1 = st->r[1];
r2 = st->r[2];
r0 = st->r[0];
r1 = st->r[1];
r2 = st->r[2];
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
s1 = r1 * (5 << 2);
s2 = r2 * (5 << 2);
s1 = r1 * (5 << 2);
s2 = r2 * (5 << 2);
while (bytes >= poly1305_block_size) {
unsigned long long t0,t1;
while (bytes >= poly1305_block_size) {
unsigned long long t0, t1;
/* h += m[i] */
t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]);
/* h += m[i] */
t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]);
h0 += (( t0 ) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit;
h0 += ((t0) & 0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
/* h *= r */
MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d);
MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d);
MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d);
/* h *= r */
MUL(d0, h0, r0);
MUL(d, h1, s2);
ADD(d0, d);
MUL(d, h2, s1);
ADD(d0, d);
MUL(d1, h0, r1);
MUL(d, h1, r0);
ADD(d1, d);
MUL(d, h2, s2);
ADD(d1, d);
MUL(d2, h0, r2);
MUL(d, h1, r1);
ADD(d2, d);
MUL(d, h2, r0);
ADD(d2, d);
/* (partial) h %= p */
c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff;
ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff;
ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff;
h1 += c;
/* (partial) h %= p */
c = SHR(d0, 44);
h0 = LO(d0) & 0xfffffffffff;
ADDLO(d1, c);
c = SHR(d1, 44);
h1 = LO(d1) & 0xfffffffffff;
ADDLO(d2, c);
c = SHR(d2, 42);
h2 = LO(d2) & 0x3ffffffffff;
h0 += c * 5;
c = (h0 >> 44);
h0 = h0 & 0xfffffffffff;
h1 += c;
m += poly1305_block_size;
bytes -= poly1305_block_size;
}
m += poly1305_block_size;
bytes -= poly1305_block_size;
}
st->h[0] = h0;
st->h[1] = h1;
st->h[2] = h2;
st->h[0] = h0;
st->h[1] = h1;
st->h[2] = h2;
}
static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned long long h0,h1,h2,c;
unsigned long long g0,g1,g2;
unsigned long long t0,t1;
static inline void poly1305_finish(poly1305_context* ctx, unsigned char mac[16])
{
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long h0, h1, h2, c;
unsigned long long g0, g1, g2;
unsigned long long t0, t1;
/* process the remaining block */
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i] = 1;
for (i = i + 1; i < poly1305_block_size; i++) {
st->buffer[i] = 0;
}
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
/* process the remaining block */
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i] = 1;
for (i = i + 1; i < poly1305_block_size; i++) {
st->buffer[i] = 0;
}
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
/* fully carry h */
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
/* fully carry h */
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
c = (h1 >> 44); h1 &= 0xfffffffffff;
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff;
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
h1 += c;
c = (h1 >> 44);
h1 &= 0xfffffffffff;
h2 += c;
c = (h2 >> 42);
h2 &= 0x3ffffffffff;
h0 += c * 5;
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += c;
c = (h1 >> 44);
h1 &= 0xfffffffffff;
h2 += c;
c = (h2 >> 42);
h2 &= 0x3ffffffffff;
h0 += c * 5;
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += c;
/* compute h + -p */
g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
g2 = h2 + c - ((unsigned long long)1 << 42);
/* compute h + -p */
g0 = h0 + 5;
c = (g0 >> 44);
g0 &= 0xfffffffffff;
g1 = h1 + c;
c = (g1 >> 44);
g1 &= 0xfffffffffff;
g2 = h2 + c - ((unsigned long long)1 << 42);
/* select h if h < p, or h + -p if h >= p */
c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1;
g0 &= c;
g1 &= c;
g2 &= c;
c = ~c;
h0 = (h0 & c) | g0;
h1 = (h1 & c) | g1;
h2 = (h2 & c) | g2;
/* select h if h < p, or h + -p if h >= p */
c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1;
g0 &= c;
g1 &= c;
g2 &= c;
c = ~c;
h0 = (h0 & c) | g0;
h1 = (h1 & c) | g1;
h2 = (h2 & c) | g2;
/* h = (h + pad) */
t0 = st->pad[0];
t1 = st->pad[1];
/* h = (h + pad) */
t0 = st->pad[0];
t1 = st->pad[1];
h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff;
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff;
h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff;
h0 += ((t0) & 0xfffffffffff);
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
c = (h1 >> 44);
h1 &= 0xfffffffffff;
h2 += (((t1 >> 24)) & 0x3ffffffffff) + c;
h2 &= 0x3ffffffffff;
/* mac = h % (2^128) */
h0 = ((h0 ) | (h1 << 44));
h1 = ((h1 >> 20) | (h2 << 24));
/* mac = h % (2^128) */
h0 = ((h0) | (h1 << 44));
h1 = ((h1 >> 20) | (h2 << 24));
U64TO8(&mac[0], h0);
U64TO8(&mac[8], h1);
U64TO8(&mac[0], h0);
U64TO8(&mac[8], h1);
/* zero out the state */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->r[0] = 0;
st->r[1] = 0;
st->r[2] = 0;
st->pad[0] = 0;
st->pad[1] = 0;
/* zero out the state */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->r[0] = 0;
st->r[1] = 0;
st->r[2] = 0;
st->pad[0] = 0;
st->pad[1] = 0;
}
//////////////////////////////////////////////////////////////////////////////
@ -264,262 +311,291 @@ static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16])
/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */
typedef struct poly1305_state_internal_t {
unsigned long r[5];
unsigned long h[5];
unsigned long pad[4];
size_t leftover;
unsigned char buffer[poly1305_block_size];
unsigned char final;
unsigned long r[5];
unsigned long h[5];
unsigned long pad[4];
size_t leftover;
unsigned char buffer[poly1305_block_size];
unsigned char final;
} poly1305_state_internal_t;
/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
static unsigned long
U8TO32(const unsigned char *p) {
return
(((unsigned long)(p[0] & 0xff) ) |
((unsigned long)(p[1] & 0xff) << 8) |
((unsigned long)(p[2] & 0xff) << 16) |
((unsigned long)(p[3] & 0xff) << 24));
static unsigned long U8TO32(const unsigned char* p)
{
return (((unsigned long)(p[0] & 0xff)) | ((unsigned long)(p[1] & 0xff) << 8) | ((unsigned long)(p[2] & 0xff) << 16) | ((unsigned long)(p[3] & 0xff) << 24));
}
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
static void
U32TO8(unsigned char *p, unsigned long v) {
p[0] = (v ) & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff;
static void U32TO8(unsigned char* p, unsigned long v)
{
p[0] = (v) & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff;
}
static inline void
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
static inline void poly1305_init(poly1305_context* ctx, const unsigned char key[32])
{
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff;
st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03;
st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff;
st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff;
st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
st->r[0] = (U8TO32(&key[0])) & 0x3ffffff;
st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03;
st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff;
st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff;
st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
/* h = 0 */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->h[3] = 0;
st->h[4] = 0;
/* h = 0 */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->h[3] = 0;
st->h[4] = 0;
/* save pad for later */
st->pad[0] = U8TO32(&key[16]);
st->pad[1] = U8TO32(&key[20]);
st->pad[2] = U8TO32(&key[24]);
st->pad[3] = U8TO32(&key[28]);
/* save pad for later */
st->pad[0] = U8TO32(&key[16]);
st->pad[1] = U8TO32(&key[20]);
st->pad[2] = U8TO32(&key[24]);
st->pad[3] = U8TO32(&key[28]);
st->leftover = 0;
st->final = 0;
st->leftover = 0;
st->final = 0;
}
static inline void
poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */
unsigned long r0,r1,r2,r3,r4;
unsigned long s1,s2,s3,s4;
unsigned long h0,h1,h2,h3,h4;
unsigned long long d0,d1,d2,d3,d4;
unsigned long c;
static inline void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes)
{
const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */
unsigned long r0, r1, r2, r3, r4;
unsigned long s1, s2, s3, s4;
unsigned long h0, h1, h2, h3, h4;
unsigned long long d0, d1, d2, d3, d4;
unsigned long c;
r0 = st->r[0];
r1 = st->r[1];
r2 = st->r[2];
r3 = st->r[3];
r4 = st->r[4];
r0 = st->r[0];
r1 = st->r[1];
r2 = st->r[2];
r3 = st->r[3];
r4 = st->r[4];
s1 = r1 * 5;
s2 = r2 * 5;
s3 = r3 * 5;
s4 = r4 * 5;
s1 = r1 * 5;
s2 = r2 * 5;
s3 = r3 * 5;
s4 = r4 * 5;
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h3 = st->h[3];
h4 = st->h[4];
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h3 = st->h[3];
h4 = st->h[4];
while (bytes >= poly1305_block_size) {
/* h += m[i] */
h0 += (U8TO32(m+ 0) ) & 0x3ffffff;
h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff;
h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff;
h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff;
h4 += (U8TO32(m+12) >> 8) | hibit;
while (bytes >= poly1305_block_size) {
/* h += m[i] */
h0 += (U8TO32(m + 0)) & 0x3ffffff;
h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff;
h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff;
h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff;
h4 += (U8TO32(m + 12) >> 8) | hibit;
/* h *= r */
d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1);
d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2);
d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3);
d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4);
d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0);
/* h *= r */
d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1);
d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2);
d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3);
d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4);
d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0);
/* (partial) h %= p */
c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff;
d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff;
d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff;
d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff;
d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff;
h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff;
h1 += c;
/* (partial) h %= p */
c = (unsigned long)(d0 >> 26);
h0 = (unsigned long)d0 & 0x3ffffff;
d1 += c;
c = (unsigned long)(d1 >> 26);
h1 = (unsigned long)d1 & 0x3ffffff;
d2 += c;
c = (unsigned long)(d2 >> 26);
h2 = (unsigned long)d2 & 0x3ffffff;
d3 += c;
c = (unsigned long)(d3 >> 26);
h3 = (unsigned long)d3 & 0x3ffffff;
d4 += c;
c = (unsigned long)(d4 >> 26);
h4 = (unsigned long)d4 & 0x3ffffff;
h0 += c * 5;
c = (h0 >> 26);
h0 = h0 & 0x3ffffff;
h1 += c;
m += poly1305_block_size;
bytes -= poly1305_block_size;
}
m += poly1305_block_size;
bytes -= poly1305_block_size;
}
st->h[0] = h0;
st->h[1] = h1;
st->h[2] = h2;
st->h[3] = h3;
st->h[4] = h4;
st->h[0] = h0;
st->h[1] = h1;
st->h[2] = h2;
st->h[3] = h3;
st->h[4] = h4;
}
static inline void
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned long h0,h1,h2,h3,h4,c;
unsigned long g0,g1,g2,g3,g4;
unsigned long long f;
unsigned long mask;
static inline void poly1305_finish(poly1305_context* ctx, unsigned char mac[16])
{
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long h0, h1, h2, h3, h4, c;
unsigned long g0, g1, g2, g3, g4;
unsigned long long f;
unsigned long mask;
/* process the remaining block */
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i++] = 1;
for (; i < poly1305_block_size; i++) {
st->buffer[i] = 0;
}
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
/* process the remaining block */
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i++] = 1;
for (; i < poly1305_block_size; i++) {
st->buffer[i] = 0;
}
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
/* fully carry h */
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h3 = st->h[3];
h4 = st->h[4];
/* fully carry h */
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h3 = st->h[3];
h4 = st->h[4];
c = h1 >> 26; h1 = h1 & 0x3ffffff;
h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
h1 += c;
c = h1 >> 26;
h1 = h1 & 0x3ffffff;
h2 += c;
c = h2 >> 26;
h2 = h2 & 0x3ffffff;
h3 += c;
c = h3 >> 26;
h3 = h3 & 0x3ffffff;
h4 += c;
c = h4 >> 26;
h4 = h4 & 0x3ffffff;
h0 += c * 5;
c = h0 >> 26;
h0 = h0 & 0x3ffffff;
h1 += c;
/* compute h + -p */
g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;
g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;
g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;
g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;
g4 = h4 + c - (1 << 26);
/* compute h + -p */
g0 = h0 + 5;
c = g0 >> 26;
g0 &= 0x3ffffff;
g1 = h1 + c;
c = g1 >> 26;
g1 &= 0x3ffffff;
g2 = h2 + c;
c = g2 >> 26;
g2 &= 0x3ffffff;
g3 = h3 + c;
c = g3 >> 26;
g3 &= 0x3ffffff;
g4 = h4 + c - (1 << 26);
/* select h if h < p, or h + -p if h >= p */
mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
g0 &= mask;
g1 &= mask;
g2 &= mask;
g3 &= mask;
g4 &= mask;
mask = ~mask;
h0 = (h0 & mask) | g0;
h1 = (h1 & mask) | g1;
h2 = (h2 & mask) | g2;
h3 = (h3 & mask) | g3;
h4 = (h4 & mask) | g4;
/* select h if h < p, or h + -p if h >= p */
mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
g0 &= mask;
g1 &= mask;
g2 &= mask;
g3 &= mask;
g4 &= mask;
mask = ~mask;
h0 = (h0 & mask) | g0;
h1 = (h1 & mask) | g1;
h2 = (h2 & mask) | g2;
h3 = (h3 & mask) | g3;
h4 = (h4 & mask) | g4;
/* h = h % (2^128) */
h0 = ((h0 ) | (h1 << 26)) & 0xffffffff;
h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
/* h = h % (2^128) */
h0 = ((h0) | (h1 << 26)) & 0xffffffff;
h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */
f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f;
f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f;
f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f;
/* mac = (h + pad) % (2^128) */
f = (unsigned long long)h0 + st->pad[0];
h0 = (unsigned long)f;
f = (unsigned long long)h1 + st->pad[1] + (f >> 32);
h1 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32);
h2 = (unsigned long)f;
f = (unsigned long long)h3 + st->pad[3] + (f >> 32);
h3 = (unsigned long)f;
U32TO8(mac + 0, h0);
U32TO8(mac + 4, h1);
U32TO8(mac + 8, h2);
U32TO8(mac + 12, h3);
U32TO8(mac + 0, h0);
U32TO8(mac + 4, h1);
U32TO8(mac + 8, h2);
U32TO8(mac + 12, h3);
/* zero out the state */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->h[3] = 0;
st->h[4] = 0;
st->r[0] = 0;
st->r[1] = 0;
st->r[2] = 0;
st->r[3] = 0;
st->r[4] = 0;
st->pad[0] = 0;
st->pad[1] = 0;
st->pad[2] = 0;
st->pad[3] = 0;
/* zero out the state */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->h[3] = 0;
st->h[4] = 0;
st->r[0] = 0;
st->r[1] = 0;
st->r[2] = 0;
st->r[3] = 0;
st->r[4] = 0;
st->pad[0] = 0;
st->pad[1] = 0;
st->pad[2] = 0;
st->pad[3] = 0;
}
//////////////////////////////////////////////////////////////////////////////
#endif // MSC/GCC or not
#endif // MSC/GCC or not
static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
size_t i;
/* handle leftover */
if (st->leftover) {
size_t want = (poly1305_block_size - st->leftover);
if (want > bytes) {
want = bytes;
}
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) {
return;
}
poly1305_blocks(st, st->buffer, poly1305_block_size);
st->leftover = 0;
}
/* process full blocks */
if (bytes >= poly1305_block_size) {
size_t want = (bytes & ~(poly1305_block_size - 1));
poly1305_blocks(st, m, want);
m += want;
bytes -= want;
}
/* store leftover */
if (bytes) {
for (i = 0; i < bytes; i++) {
st->buffer[st->leftover + i] = m[i];
}
st->leftover += bytes;
}
}
} // anonymous namespace
void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key)
static inline void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes)
{
poly1305_context ctx;
poly1305_init(&ctx,reinterpret_cast<const unsigned char *>(key));
poly1305_update(&ctx,reinterpret_cast<const unsigned char *>(data),(size_t)len);
poly1305_finish(&ctx,reinterpret_cast<unsigned char *>(auth));
poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
size_t i;
/* handle leftover */
if (st->leftover) {
size_t want = (poly1305_block_size - st->leftover);
if (want > bytes) {
want = bytes;
}
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) {
return;
}
poly1305_blocks(st, st->buffer, poly1305_block_size);
st->leftover = 0;
}
/* process full blocks */
if (bytes >= poly1305_block_size) {
size_t want = (bytes & ~(poly1305_block_size - 1));
poly1305_blocks(st, m, want);
m += want;
bytes -= want;
}
/* store leftover */
if (bytes) {
for (i = 0; i < bytes; i++) {
st->buffer[st->leftover + i] = m[i];
}
st->leftover += bytes;
}
}
} // namespace ZeroTier
} // anonymous namespace
void Poly1305::compute(void* auth, const void* data, unsigned int len, const void* key)
{
poly1305_context ctx;
poly1305_init(&ctx, reinterpret_cast<const unsigned char*>(key));
poly1305_update(&ctx, reinterpret_cast<const unsigned char*>(data), (size_t)len);
poly1305_finish(&ctx, reinterpret_cast<unsigned char*>(auth));
}
} // namespace ZeroTier

View file

@ -30,9 +30,8 @@ namespace ZeroTier {
* keystream as a one-time-use key. These 32 bytes are then discarded and
* the packet is encrypted with the next N bytes.
*/
class Poly1305
{
public:
class Poly1305 {
public:
/**
* Compute a one-time authentication code
*
@ -41,9 +40,9 @@ public:
* @param len Length of data to authenticate in bytes
* @param key 32-byte one-time use key to authenticate data (must not be reused)
*/
static void compute(void *auth,const void *data,unsigned int len,const void *key);
static void compute(void* auth, const void* data, unsigned int len, const void* key);
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -12,32 +12,34 @@
/****/
#include "Revocation.hpp"
#include "RuntimeEnvironment.hpp"
#include "Identity.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Network.hpp"
#include "Node.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
namespace ZeroTier {
int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const
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);
const Identity id(RR->topology->getIdentity(tPtr, _signedBy));
if (! id) {
RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy);
return 1;
}
try {
Buffer<sizeof(Revocation) + 64> tmp;
this->serialize(tmp,true);
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
} catch ( ... ) {
this->serialize(tmp, true);
return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1);
}
catch (...) {
return -1;
}
}
} // namespace ZeroTier
} // namespace ZeroTier

View file

@ -14,19 +14,19 @@
#ifndef ZT_REVOCATION_HPP
#define ZT_REVOCATION_HPP
#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Buffer.hpp"
#include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Credential.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp"
/**
* Flag: fast propagation via rumor mill algorithm
@ -40,22 +40,16 @@ class RuntimeEnvironment;
/**
* Revocation certificate to instantaneously revoke a COM, capability, or tag
*/
class Revocation : public Credential
{
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
Revocation() :
_id(0),
_credentialId(0),
_networkId(0),
_threshold(0),
_flags(0),
_target(),
_signedBy(),
_type(Credential::CREDENTIAL_TYPE_NULL)
class Revocation : public Credential {
public:
static inline Credential::Type credentialType()
{
memset(_signature.data,0,sizeof(_signature.data));
return Credential::CREDENTIAL_TYPE_REVOCATION;
}
Revocation() : _id(0), _credentialId(0), _networkId(0), _threshold(0), _flags(0), _target(), _signedBy(), _type(Credential::CREDENTIAL_TYPE_NULL)
{
memset(_signature.data, 0, sizeof(_signature.data));
}
/**
@ -67,40 +61,64 @@ public:
* @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked
*/
Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const int64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
_id(i),
_credentialId(cid),
_networkId(nwid),
_threshold(thr),
_flags(fl),
_target(tgt),
_signedBy(),
_type(ct)
Revocation(const uint32_t i, const uint64_t nwid, const uint32_t cid, const int64_t thr, const uint64_t fl, const Address& tgt, const Credential::Type ct)
: _id(i)
, _credentialId(cid)
, _networkId(nwid)
, _threshold(thr)
, _flags(fl)
, _target(tgt)
, _signedBy()
, _type(ct)
{
memset(_signature.data,0,sizeof(_signature.data));
memset(_signature.data, 0, sizeof(_signature.data));
}
inline uint32_t id() const { return _id; }
inline uint32_t credentialId() const { return _credentialId; }
inline uint64_t networkId() const { return _networkId; }
inline int64_t threshold() const { return _threshold; }
inline const Address &target() const { return _target; }
inline const Address &signer() const { return _signedBy; }
inline Credential::Type type() const { return _type; }
inline uint32_t id() const
{
return _id;
}
inline uint32_t credentialId() const
{
return _credentialId;
}
inline uint64_t networkId() const
{
return _networkId;
}
inline int64_t threshold() const
{
return _threshold;
}
inline const Address& target() const
{
return _target;
}
inline const Address& signer() const
{
return _signedBy;
}
inline Credential::Type type() const
{
return _type;
}
inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
inline bool fastPropagate() const
{
return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0);
}
/**
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
inline bool sign(const Identity &signer)
inline bool sign(const Identity& signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(Revocation) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signature = signer.sign(tmp.data(),tmp.size());
this->serialize(tmp, true);
_signature = signer.sign(tmp.data(), tmp.size());
return true;
}
return false;
@ -113,19 +131,18 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
*/
int verify(const RuntimeEnvironment *RR,void *tPtr) const;
int verify(const RuntimeEnvironment* RR, void* tPtr) const;
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
template <unsigned int C> inline void serialize(Buffer<C>& b, const bool forSign = false) const
{
if (forSign) {
b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append(_id);
b.append(_networkId);
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
b.append(_credentialId);
b.append(_threshold);
b.append(_flags);
@ -133,10 +150,10 @@ public:
_signedBy.appendTo(b);
b.append((uint8_t)_type);
if (!forSign) {
b.append((uint8_t)1); // 1 == Ed25519 signature
if (! forSign) {
b.append((uint8_t)1); // 1 == Ed25519 signature
b.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
b.append(_signature.data, ZT_C25519_SIGNATURE_LEN);
}
// This is the size of any additional fields, currently 0.
@ -147,40 +164,41 @@ public:
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
template <unsigned int C> inline unsigned int deserialize(const Buffer<C>& b, unsigned int startAt = 0)
{
*this = Revocation();
unsigned int p = startAt;
p += 4; // 4 bytes, currently unused
p += 4; // 4 bytes, currently unused
_id = b.template at<uint32_t>(p);
p += 4;
_networkId = b.template at<uint64_t>(p);
p += 8;
p += 4; // 4 bytes, currently unused
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);
_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);
_signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
_type = (Credential::Type)b[p++];
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
p += 2;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data, b.field(p, ZT_C25519_SIGNATURE_LEN), ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else {
}
else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
}
} else {
}
else {
p += 2 + b.template at<uint16_t>(p);
}
@ -192,7 +210,7 @@ public:
return (p - startAt);
}
private:
private:
uint32_t _id;
uint32_t _credentialId;
uint64_t _networkId;
@ -204,6 +222,6 @@ private:
C25519::Signature _signature;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,12 +14,12 @@
#ifndef ZT_RINGBUFFER_H
#define ZT_RINGBUFFER_H
#include <typeinfo>
#include <cstdint>
#include <stdlib.h>
#include <memory.h>
#include <algorithm>
#include <cstdint>
#include <math.h>
#include <memory.h>
#include <stdlib.h>
#include <typeinfo>
namespace ZeroTier {
@ -34,28 +34,23 @@ namespace ZeroTier {
* to reduce the complexity of code needed to interact with this type of buffer.
*/
template <class T,size_t S>
class RingBuffer
{
private:
template <class T, size_t S> class RingBuffer {
private:
T buf[S];
size_t begin;
size_t end;
bool wrap;
public:
RingBuffer() :
begin(0),
end(0),
wrap(false)
public:
RingBuffer() : begin(0), end(0), wrap(false)
{
memset(buf,0,sizeof(T)*S);
memset(buf, 0, sizeof(T) * S);
}
/**
* @return A pointer to the underlying buffer
*/
inline T *get_buf()
inline T* get_buf()
{
return buf + begin;
}
@ -87,7 +82,10 @@ public:
* Fast erase, O(1).
* Merely reset the buffer pointer, doesn't erase contents
*/
inline void reset() { consume(count()); }
inline void reset()
{
consume(count());
}
/**
* adjust buffer index pointer as if we copied data out
@ -116,7 +114,7 @@ public:
* @param data Buffer that is to be written to the ring
* @param n Number of elements to write to the buffer
*/
inline size_t write(const T * data, size_t n)
inline size_t write(const T* data, size_t n)
{
n = std::min(n, getFree());
if (n == 0) {
@ -157,14 +155,17 @@ public:
/**
* @return The most recently pushed element on the buffer
*/
inline T get_most_recent() { return *(buf + end); }
inline T get_most_recent()
{
return *(buf + end);
}
/**
* @param dest Destination buffer
* @param n Size (in terms of number of elements) of the destination buffer
* @return Number of elements read from the buffer
*/
inline size_t read(T *dest,size_t n)
inline size_t read(T* dest, size_t n)
{
n = std::min(n, count());
if (n == 0) {
@ -193,9 +194,11 @@ 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;
}
}
@ -203,7 +206,10 @@ public:
/**
* @return The number of slots that are unused in the buffer
*/
inline size_t getFree() { return S - count(); }
inline size_t getFree()
{
return S - count();
}
/**
* @return The arithmetic mean of the contents of the buffer
@ -213,7 +219,7 @@ public:
size_t iterator = begin;
float subtotal = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator);
}
@ -229,7 +235,7 @@ public:
size_t iterator = begin;
float subtotal = 0;
size_t curr_cnt = count();
for (size_t i=0; i<n; i++) {
for (size_t i = 0; i < n; i++) {
iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator);
}
@ -244,7 +250,7 @@ public:
size_t iterator = begin;
float total = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
total += (float)*(buf + iterator);
}
@ -254,7 +260,10 @@ public:
/**
* @return The sample standard deviation of element values
*/
inline float stddev() { return sqrt(variance()); }
inline float stddev()
{
return sqrt(variance());
}
/**
* @return The variance of element values
@ -265,10 +274,10 @@ public:
float cached_mean = mean();
size_t curr_cnt = count();
T sum_of_squared_deviations = 0;
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
float deviation = (buf[i] - cached_mean);
sum_of_squared_deviations += (T)(deviation*deviation);
sum_of_squared_deviations += (T)(deviation * deviation);
}
float variance = (float)sum_of_squared_deviations / (float)(S - 1);
return variance;
@ -282,7 +291,7 @@ public:
size_t iterator = begin;
size_t zeros = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == 0) {
zeros++;
@ -300,7 +309,7 @@ public:
size_t iterator = begin;
size_t cnt = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
for (size_t i = 0; i < curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == value) {
cnt++;
@ -329,6 +338,6 @@ public:
*/
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -14,11 +14,11 @@
#ifndef ZT_RUNTIMEENVIRONMENT_HPP
#define ZT_RUNTIMEENVIRONMENT_HPP
#include <string.h>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
#include "Utils.hpp"
#include <string.h>
namespace ZeroTier {
@ -36,17 +36,9 @@ class PacketMultiplexer;
/**
* Holds global state for an instance of ZeroTier::Node
*/
class RuntimeEnvironment
{
public:
RuntimeEnvironment(Node *n) :
node(n)
,localNetworkController((NetworkController *)0)
,rtmem((void *)0)
,sw((Switch *)0)
,mc((Multicaster *)0)
,topology((Topology *)0)
,sa((SelfAwareness *)0)
class RuntimeEnvironment {
public:
RuntimeEnvironment(Node* n) : node(n), localNetworkController((NetworkController*)0), rtmem((void*)0), sw((Switch*)0), mc((Multicaster*)0), topology((Topology*)0), sa((SelfAwareness*)0)
{
publicIdentityStr[0] = (char)0;
secretIdentityStr[0] = (char)0;
@ -54,17 +46,17 @@ public:
~RuntimeEnvironment()
{
Utils::burn(secretIdentityStr,sizeof(secretIdentityStr));
Utils::burn(secretIdentityStr, sizeof(secretIdentityStr));
}
// Node instance that owns this RuntimeEnvironment
Node *const node;
Node* const node;
// This is set externally to an instance of this base class
NetworkController *localNetworkController;
NetworkController* localNetworkController;
// Memory actually occupied by Trace, Switch, etc.
void *rtmem;
void* rtmem;
/* Order matters a bit here. These are constructed in this order
* and then deleted in the opposite order on Node exit. The order ensures
@ -72,13 +64,13 @@ public:
*
* These are constant and never null after startup unless indicated. */
Trace *t;
Switch *sw;
Multicaster *mc;
Topology *topology;
SelfAwareness *sa;
Bond *bc;
PacketMultiplexer *pm;
Trace* t;
Switch* sw;
Multicaster* mc;
Topology* topology;
SelfAwareness* sa;
Bond* bc;
PacketMultiplexer* pm;
// This node's identity and string representations thereof
Identity identity;
@ -86,6 +78,6 @@ public:
char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -1,10 +1,11 @@
// This code is public domain, taken from a PD crypto source file on GitHub.
#include <algorithm>
#include "SHA512.hpp"
#include "Utils.hpp"
#include <algorithm>
namespace ZeroTier {
#ifndef ZT_HAVE_NATIVE_SHA512
@ -12,48 +13,35 @@ namespace ZeroTier {
namespace {
struct sha512_state {
uint64_t length,state[8];
uint64_t length, state[8];
unsigned long curlen;
uint8_t buf[128];
};
static const uint64_t K[80] = {
0x428a2f98d728ae22ULL,0x7137449123ef65cdULL,0xb5c0fbcfec4d3b2fULL,0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL,0x59f111f1b605d019ULL,0x923f82a4af194f9bULL,0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL,0x12835b0145706fbeULL,0x243185be4ee4b28cULL,0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL,0x80deb1fe3b1696b1ULL,0x9bdc06a725c71235ULL,0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL,0xefbe4786384f25e3ULL,0x0fc19dc68b8cd5b5ULL,0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL,0x4a7484aa6ea6e483ULL,0x5cb0a9dcbd41fbd4ULL,0x76f988da831153b5ULL,
0x983e5152ee66dfabULL,0xa831c66d2db43210ULL,0xb00327c898fb213fULL,0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL,0xd5a79147930aa725ULL,0x06ca6351e003826fULL,0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL,0x2e1b21385c26c926ULL,0x4d2c6dfc5ac42aedULL,0x53380d139d95b3dfULL,
0x650a73548baf63deULL,0x766a0abb3c77b2a8ULL,0x81c2c92e47edaee6ULL,0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL,0xa81a664bbc423001ULL,0xc24b8b70d0f89791ULL,0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL,0xd69906245565a910ULL,0xf40e35855771202aULL,0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL,0x1e376c085141ab53ULL,0x2748774cdf8eeb99ULL,0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL,0x4ed8aa4ae3418acbULL,0x5b9cca4f7763e373ULL,0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL,0x78a5636f43172f60ULL,0x84c87814a1f0ab72ULL,0x8cc702081a6439ecULL,
0x90befffa23631e28ULL,0xa4506cebde82bde9ULL,0xbef9a3f7b2c67915ULL,0xc67178f2e372532bULL,
0xca273eceea26619cULL,0xd186b8c721c0c207ULL,0xeada7dd6cde0eb1eULL,0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL,0x0a637dc5a2c898a6ULL,0x113f9804bef90daeULL,0x1b710b35131c471bULL,
0x28db77f523047d84ULL,0x32caab7b40c72493ULL,0x3c9ebe0a15c9bebcULL,0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL,0x597f299cfc657e2aULL,0x5fcb6fab3ad6faecULL,0x6c44198c4a475817ULL
};
static const uint64_t K[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
#define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y,x)
#define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y)
#define ROL64c(x,y) (((x)<<(y)) | ((x)>>(64-(y))))
#define ROR64c(x,y) (((x)>>(y)) | ((x)<<(64-(y))))
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) ((x)>>(n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
#define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y, x)
#define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y)
#define ROL64c(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#define ROR64c(x, y) (((x) >> (y)) | ((x) << (64 - (y))))
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) ((x) >> (n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
static ZT_INLINE void sha512_compress(sha512_state* const md, uint8_t* const buf)
{
uint64_t S[8], W[80], t0, t1;
int i;
@ -62,27 +50,27 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
S[i] = md->state[i];
}
for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8*i));
LOAD64H(W[i], buf + (8 * 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]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
#define RND(a, b, c, d, e, f, g, h, i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
for (i = 0; i < 80; i += 8) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
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++) {
@ -90,7 +78,7 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
}
}
static ZT_INLINE void sha384_init(sha512_state *const md)
static ZT_INLINE void sha384_init(sha512_state* const md)
{
md->curlen = 0;
md->length = 0;
@ -104,7 +92,7 @@ static ZT_INLINE void sha384_init(sha512_state *const md)
md->state[7] = 0x47b5481dbefa4fa4ULL;
}
static ZT_INLINE void sha512_init(sha512_state *const md)
static ZT_INLINE void sha512_init(sha512_state* const md)
{
md->curlen = 0;
md->length = 0;
@ -118,30 +106,31 @@ static ZT_INLINE void sha512_init(sha512_state *const md)
md->state[7] = 0x5be0cd19137e2179ULL;
}
static void sha512_process(sha512_state *const md,const uint8_t *in,unsigned long inlen)
static void sha512_process(sha512_state* const md, const uint8_t* in, unsigned long inlen)
{
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
sha512_compress(md,(uint8_t *)in);
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
unsigned long n = std::min(inlen,(128 - md->curlen));
Utils::copy(md->buf + md->curlen,in,n);
sha512_compress(md, (uint8_t*)in);
md->length += 128 * 8;
in += 128;
inlen -= 128;
}
else {
unsigned long n = std::min(inlen, (128 - md->curlen));
Utils::copy(md->buf + md->curlen, in, n);
md->curlen += n;
in += n;
inlen -= n;
in += n;
inlen -= n;
if (md->curlen == 128) {
sha512_compress(md,md->buf);
md->length += 8*128;
sha512_compress(md, md->buf);
md->length += 8 * 128;
md->curlen = 0;
}
}
}
}
static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out)
static ZT_INLINE void sha512_done(sha512_state* const md, uint8_t* out)
{
int i;
@ -160,58 +149,58 @@ static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out)
md->buf[md->curlen++] = (uint8_t)0;
}
STORE64H(md->length, md->buf+120);
STORE64H(md->length, md->buf + 120);
sha512_compress(md, md->buf);
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i));
STORE64H(md->state[i], out + (8 * i));
}
}
} // anonymous namespace
} // anonymous namespace
void SHA512(void *digest,const void *data,unsigned int len)
void SHA512(void* digest, const void* data, unsigned int len)
{
sha512_state state;
sha512_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len);
sha512_done(&state,(uint8_t *)digest);
sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state, (uint8_t*)digest);
}
void SHA384(void *digest,const void *data,unsigned int len)
void SHA384(void* digest, const void* data, unsigned int len)
{
uint8_t tmp[64];
sha512_state state;
sha384_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len);
sha512_done(&state,tmp);
Utils::copy<48>(digest,tmp);
sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state, tmp);
Utils::copy<48>(digest, tmp);
}
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1)
void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{
uint8_t tmp[64];
sha512_state state;
sha384_init(&state);
sha512_process(&state,(uint8_t *)data0,(unsigned long)len0);
sha512_process(&state,(uint8_t *)data1,(unsigned long)len1);
sha512_done(&state,tmp);
Utils::copy<48>(digest,tmp);
sha512_process(&state, (uint8_t*)data0, (unsigned long)len0);
sha512_process(&state, (uint8_t*)data1, (unsigned long)len1);
sha512_done(&state, tmp);
Utils::copy<48>(digest, tmp);
}
#endif // !ZT_HAVE_NATIVE_SHA512
#endif // !ZT_HAVE_NATIVE_SHA512
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const unsigned int msglen,uint8_t mac[48])
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, const unsigned int msglen, uint8_t mac[48])
{
uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg)
uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg)
const uint64_t k0 = Utils::loadMachineEndian< uint64_t >(key);
const uint64_t k1 = Utils::loadMachineEndian< uint64_t >(key + 8);
const uint64_t k2 = Utils::loadMachineEndian< uint64_t >(key + 16);
const uint64_t k3 = Utils::loadMachineEndian< uint64_t >(key + 24);
const uint64_t k4 = Utils::loadMachineEndian< uint64_t >(key + 32);
const uint64_t k5 = Utils::loadMachineEndian< uint64_t >(key + 40);
const uint64_t k0 = Utils::loadMachineEndian<uint64_t>(key);
const uint64_t k1 = Utils::loadMachineEndian<uint64_t>(key + 8);
const uint64_t k2 = Utils::loadMachineEndian<uint64_t>(key + 16);
const uint64_t k3 = Utils::loadMachineEndian<uint64_t>(key + 24);
const uint64_t k4 = Utils::loadMachineEndian<uint64_t>(key + 32);
const uint64_t k5 = Utils::loadMachineEndian<uint64_t>(key + 40);
const uint64_t ipad = 0x3636363636363636ULL;
kInPadded[0] = k0 ^ ipad;
@ -250,18 +239,18 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const u
outer[15] = opad;
// H(output padded key | H(input padded key | msg))
SHA384(reinterpret_cast<uint8_t *>(outer) + 128,kInPadded,128,msg,msglen);
SHA384(mac,outer,176);
SHA384(reinterpret_cast<uint8_t*>(outer) + 128, kInPadded, 128, msg, msglen);
SHA384(mac, outer, 176);
}
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const char label, const char context, const uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
{
uint8_t kbkdfMsg[13];
Utils::storeBigEndian<uint32_t>(kbkdfMsg,(uint32_t)iter);
Utils::storeBigEndian<uint32_t>(kbkdfMsg, (uint32_t)iter);
kbkdfMsg[4] = (uint8_t)'Z';
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
kbkdfMsg[6] = (uint8_t)label;
kbkdfMsg[7] = 0;
@ -273,13 +262,15 @@ void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,c
kbkdfMsg[11] = 0x01;
kbkdfMsg[12] = 0x80;
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out);
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE, "sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key, &kbkdfMsg, sizeof(kbkdfMsg), out);
}
} // namespace ZeroTier
} // namespace ZeroTier
// Internally re-export to included C code, which includes some fast crypto code ported in on some platforms.
// This eliminates the need to link against a third party SHA512() from this code
extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len)
{ ZeroTier::SHA512(digest,data,len); }
extern "C" void ZT_sha512internal(void* digest, const void* data, unsigned int len)
{
ZeroTier::SHA512(digest, data, len);
}

View file

@ -22,8 +22,8 @@
#define ZT_SHA512_DIGEST_SIZE 64
#define ZT_SHA384_DIGEST_SIZE 48
#define ZT_SHA512_BLOCK_SIZE 128
#define ZT_SHA384_BLOCK_SIZE 128
#define ZT_SHA512_BLOCK_SIZE 128
#define ZT_SHA384_BLOCK_SIZE 128
#define ZT_HMACSHA384_LEN 48
@ -32,34 +32,34 @@ namespace ZeroTier {
// SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS
#ifdef __APPLE__
#define ZT_HAVE_NATIVE_SHA512 1
static ZT_INLINE void SHA512(void *digest,const void *data,unsigned int len)
static ZT_INLINE void SHA512(void* digest, const void* data, unsigned int len)
{
CC_SHA512_CTX ctx;
CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx,data,len);
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
CC_SHA512_Update(&ctx, data, len);
CC_SHA512_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
}
static ZT_INLINE void SHA384(void *digest,const void *data,unsigned int len)
static ZT_INLINE void SHA384(void* digest, const void* data, unsigned int len)
{
CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data,len);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
CC_SHA384_Update(&ctx, data, len);
CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
}
static ZT_INLINE void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1)
static ZT_INLINE void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{
CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data0,len0);
CC_SHA384_Update(&ctx,data1,len1);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx);
CC_SHA384_Update(&ctx, data0, len0);
CC_SHA384_Update(&ctx, data1, len1);
CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
}
#endif
#ifndef ZT_HAVE_NATIVE_SHA512
void SHA512(void *digest,const void *data,unsigned int len);
void SHA384(void *digest,const void *data,unsigned int len);
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1);
void SHA512(void* digest, const void* data, unsigned int len);
void SHA384(void* digest, const void* data, unsigned int len);
void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1);
#endif
/**
@ -70,7 +70,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u
* @param msglen Length of message
* @param mac Buffer to fill with result
*/
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigned int msglen,uint8_t mac[48]);
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, unsigned int msglen, uint8_t mac[48]);
/**
* Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF
@ -81,8 +81,8 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigne
* @param iter Key iteration for generation of multiple keys for the same label/context
* @param out Output to receive derived key
*/
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],char label,char context,uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]);
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], char label, char context, uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE]);
} // namespace ZeroTier
} // namespace ZeroTier
#endif

File diff suppressed because it is too large Load diff

View file

@ -7,32 +7,36 @@
#ifndef ZT_SALSA20_HPP
#define ZT_SALSA20_HPP
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "Constants.hpp"
#include "Utils.hpp"
#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && !defined(__MINGW32__) && !defined(_M_ARM64)))
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if (! defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && ! defined(__MINGW32__) && ! defined(_M_ARM64)))
#define ZT_SALSA20_SSE 1
#endif
#ifdef ZT_SALSA20_SSE
#include <emmintrin.h>
#endif // ZT_SALSA20_SSE
#endif // ZT_SALSA20_SSE
namespace ZeroTier {
/**
* Salsa20 stream cipher
*/
class Salsa20
{
public:
Salsa20() {}
~Salsa20() { Utils::burn(&_state,sizeof(_state)); }
class Salsa20 {
public:
Salsa20()
{
}
~Salsa20()
{
Utils::burn(&_state, sizeof(_state));
}
/**
* XOR d with s
@ -45,48 +49,48 @@ public:
* @param s Source bytes to XOR with destination
* @param len Length of s and d
*/
static inline void memxor(uint8_t *d,const uint8_t *s,unsigned int len)
static inline void memxor(uint8_t* d, const uint8_t* s, unsigned int len)
{
#ifdef ZT_SALSA20_SSE
while (len >= 128) {
__m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s));
__m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 16));
__m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 32));
__m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 48));
__m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 64));
__m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 80));
__m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 96));
__m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 112));
__m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d));
__m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 16));
__m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 32));
__m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 48));
__m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 64));
__m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 80));
__m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 96));
__m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 112));
d0 = _mm_xor_si128(d0,s0);
d1 = _mm_xor_si128(d1,s1);
d2 = _mm_xor_si128(d2,s2);
d3 = _mm_xor_si128(d3,s3);
d4 = _mm_xor_si128(d4,s4);
d5 = _mm_xor_si128(d5,s5);
d6 = _mm_xor_si128(d6,s6);
d7 = _mm_xor_si128(d7,s7);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 16),d1);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 32),d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 48),d3);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 64),d4);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 80),d5);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 96),d6);
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 112),d7);
__m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s));
__m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 16));
__m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 32));
__m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 48));
__m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 64));
__m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 80));
__m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 96));
__m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(s + 112));
__m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d));
__m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 16));
__m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 32));
__m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 48));
__m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 64));
__m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 80));
__m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 96));
__m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 112));
d0 = _mm_xor_si128(d0, s0);
d1 = _mm_xor_si128(d1, s1);
d2 = _mm_xor_si128(d2, s2);
d3 = _mm_xor_si128(d3, s3);
d4 = _mm_xor_si128(d4, s4);
d5 = _mm_xor_si128(d5, s5);
d6 = _mm_xor_si128(d6, s6);
d7 = _mm_xor_si128(d7, s7);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d), d0);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 48), d3);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 64), d4);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 80), d5);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 96), d6);
_mm_storeu_si128(reinterpret_cast<__m128i*>(d + 112), d7);
s += 128;
d += 128;
len -= 128;
}
while (len >= 16) {
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),_mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i *>(d)),_mm_loadu_si128(reinterpret_cast<const __m128i *>(s))));
_mm_storeu_si128(reinterpret_cast<__m128i*>(d), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i*>(d)), _mm_loadu_si128(reinterpret_cast<const __m128i*>(s))));
s += 16;
d += 16;
len -= 16;
@ -94,10 +98,10 @@ public:
#else
#ifndef ZT_NO_TYPE_PUNNING
while (len >= 16) {
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
(*reinterpret_cast<uint64_t*>(d)) ^= (*reinterpret_cast<const uint64_t*>(s));
s += 8;
d += 8;
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
(*reinterpret_cast<uint64_t*>(d)) ^= (*reinterpret_cast<const uint64_t*>(s));
s += 8;
d += 8;
len -= 16;
@ -114,9 +118,9 @@ public:
* @param key 256-bit (32 byte) key
* @param iv 64-bit initialization vector
*/
Salsa20(const void *key,const void *iv)
Salsa20(const void* key, const void* iv)
{
init(key,iv);
init(key, iv);
}
/**
@ -125,7 +129,7 @@ public:
* @param key Key bits
* @param iv 64-bit initialization vector
*/
void init(const void *key,const void *iv);
void init(const void* key, const void* iv);
/**
* Encrypt/decrypt data using Salsa20/12
@ -134,7 +138,7 @@ public:
* @param out Output buffer
* @param bytes Length of data
*/
void crypt12(const void *in,void *out,unsigned int bytes);
void crypt12(const void* in, void* out, unsigned int bytes);
/**
* Encrypt/decrypt data using Salsa20/20
@ -143,17 +147,17 @@ public:
* @param out Output buffer
* @param bytes Length of data
*/
void crypt20(const void *in,void *out,unsigned int bytes);
void crypt20(const void* in, void* out, unsigned int bytes);
private:
private:
union {
#ifdef ZT_SALSA20_SSE
__m128i v[4];
#endif // ZT_SALSA20_SSE
#endif // ZT_SALSA20_SSE
uint32_t i[16];
} _state;
};
} // namespace ZeroTier
} // namespace ZeroTier
#endif

View file

@ -11,66 +11,64 @@
*/
/****/
#include "SelfAwareness.hpp"
#include "Constants.hpp"
#include "Node.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "RuntimeEnvironment.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
#include <set>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <set>
#include <vector>
#include "Constants.hpp"
#include "SelfAwareness.hpp"
#include "RuntimeEnvironment.hpp"
#include "Node.hpp"
#include "Topology.hpp"
#include "Packet.hpp"
#include "Peer.hpp"
#include "Switch.hpp"
#include "Trace.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000
namespace ZeroTier {
class _ResetWithinScope
{
public:
_ResetWithinScope(void *tPtr,int64_t now,int inetAddressFamily,InetAddress::IpScope scope) :
_now(now),
_tPtr(tPtr),
_family(inetAddressFamily),
_scope(scope) {}
class _ResetWithinScope {
public:
_ResetWithinScope(void* tPtr, int64_t now, int inetAddressFamily, InetAddress::IpScope scope) : _now(now), _tPtr(tPtr), _family(inetAddressFamily), _scope(scope)
{
}
inline void operator()(Topology &t,const SharedPtr<Peer> &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); }
inline void operator()(Topology& t, const SharedPtr<Peer>& p)
{
p->resetWithinScope(_tPtr, _scope, _family, _now);
}
private:
private:
uint64_t _now;
void *_tPtr;
void* _tPtr;
int _family;
InetAddress::IpScope _scope;
};
SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
RR(renv),
_phy(128)
SelfAwareness::SelfAwareness(const RuntimeEnvironment* renv) : RR(renv), _phy(128)
{
}
void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now)
void SelfAwareness::iam(void* tPtr, const Address& reporter, const int64_t receivedOnLocalSocket, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, bool trusted, int64_t now)
{
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)];
PhySurfaceEntry& entry = _phy[PhySurfaceKey(reporter, receivedOnLocalSocket, reporterPhysicalAddress, scope)];
if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
if ((trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (! entry.mySurface.ipsEqual(myPhysicalAddress))) {
// Changes to external surface reported by trusted peers causes path reset in this scope
RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope);
RR->t->resettingPathsInScope(tPtr, reporter, reporterPhysicalAddress, myPhysicalAddress, scope);
entry.mySurface = myPhysicalAddress;
entry.ts = now;
@ -80,20 +78,21 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
// due to multiple reports of endpoint change.
// Don't use 'entry' after this since hash table gets modified.
{
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) {
Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k, e)) {
if ((k->reporterPhysicalAddress != reporterPhysicalAddress) && (k->scope == scope)) {
_phy.erase(*k);
}
}
}
// Reset all paths within this scope and address family
_ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope &>(rset);
} else {
_ResetWithinScope rset(tPtr, now, myPhysicalAddress.ss_family, (InetAddress::IpScope)scope);
RR->topology->eachPeer<_ResetWithinScope&>(rset);
}
else {
// Otherwise just update DB to use to determine external surface info
entry.mySurface = myPhysicalAddress;
entry.ts = now;
@ -105,10 +104,10 @@ std::vector<InetAddress> SelfAwareness::whoami()
{
std::vector<InetAddress> surfaceAddresses;
Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k, e)) {
if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) {
surfaceAddresses.push_back(e->mySurface);
}
@ -119,14 +118,14 @@ std::vector<InetAddress> SelfAwareness::whoami()
void SelfAwareness::clean(int64_t now)
{
Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
Hashtable<PhySurfaceKey, PhySurfaceEntry>::Iterator i(_phy);
PhySurfaceKey* k = (PhySurfaceKey*)0;
PhySurfaceEntry* e = (PhySurfaceEntry*)0;
while (i.next(k, e)) {
if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) {
_phy.erase(*k);
}
}
}
} // namespace ZeroTier
} // namespace ZeroTier

Some files were not shown because too many files have changed in this diff Show more