mirror of
https://github.com/ZeroTier/ZeroTierOne
synced 2025-08-21 13:54:15 -07:00
Merge branch 'dev'
This commit is contained in:
commit
24769219b5
393 changed files with 74602 additions and 12278 deletions
247
service/MULTIPATH.md
Normal file
247
service/MULTIPATH.md
Normal file
|
@ -0,0 +1,247 @@
|
|||
### Bonding (link aggregation)
|
||||
|
||||
Link aggregation allows the simultaneous (or conditional) use of multiple physical links to enable increased throughput, load balancing, redundancy, and fault tolerance. There are a variety of standard policies available that can be used right out of the box with little to no configuration. These policies are directly inspired by [the policies offered by the Linux kernel](https://www.kernel.org/doc/Documentation/networking/bonding.txt) but are now offered in user-space and hence available on all platforms that ZeroTier supports.
|
||||
|
||||
#### Standard policies
|
||||
|
||||
| Policy name | Fault tolerance | Min. failover (sec.) | Default Failover (sec.)| Balancing | Aggregation efficiency | Redundancy | Sequence Reordering |
|
||||
|--------------------|:---------------------:|---------------------:|-----------------------:|----------------------:|-----------------------:|-----------:|--------------------:|
|
||||
| `none` | None | `60+` | `60+` | none | `none` |1 | No
|
||||
| `active-backup` | Brief interruption | `0.25` | `10` | none | `low` |1 | Only during failover
|
||||
| `broadcast` | Fully tolerant | `N/A` | `N/A` | none | `very low` |N | Often
|
||||
| `balance-rr` | Self-healing | `0.25` | `10` | packet-based | `high` |1 | Often
|
||||
| `balance-xor` | Self-healing | `0.25` | `10` | flow-based | `very high` |1 | Only during failover
|
||||
| `balance-aware` | Self-healing | `0.25` | `10` | *adaptive* flow-based | `very high` |1 | Only during failover and re-balance
|
||||
|
||||
A policy can be used easily without specifying any additional parameters:
|
||||
|
||||
```
|
||||
{
|
||||
"settings": {
|
||||
"defaultBondingPolicy": "active-backup"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Custom policies
|
||||
|
||||
To customize a bonding policy for your use-case simply specify a `basePolicy` and override chosen parameters. For example, to create a more aggressive `active-backup` policy with low monitoring overhead that will failover `0.250` seconds after it detects a link failure, one could do the following:
|
||||
|
||||
```
|
||||
{
|
||||
"settings":
|
||||
{
|
||||
"defaultBondingPolicy": "aggressive-active-backup",
|
||||
"policies":
|
||||
{
|
||||
"aggressive-active-backup":
|
||||
{
|
||||
"failoverInterval": 250,
|
||||
"pathMonitorStrategy": "dynamic",
|
||||
"basePolicy": "active-backup"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Specifying links
|
||||
|
||||
Bonds are composed of multiple `links`. Different sets of links can be constructed for different bonding policies and used simultaneously. One can specify the links that ZeroTier should use in any given bonding policy simply by providing an array of links with names corresponding to interface names. If a user doesn't specify a set of interfaces to use, ZeroTier will assume every system interface is available for use. However, if the user **does** specify a set of interfaces, ZeroTier will only use what is specified. The same applies to failover rules, if none are specified, ZeroTier will failover to any operational link. On the other hand, if the user does specify failover rules and there is ever a situation where a link is available for usage but does not fit within the rules specified by the user, it will go unused.
|
||||
|
||||
To specify that ZeroTier should only use `eth0` and `eth1` as primary links, and `eth2` as a backup spare and that it should prefer IPv4 over IPv6 except on `eth2` where only IPv6 is allowed:
|
||||
|
||||
```
|
||||
{
|
||||
"settings": {
|
||||
"defaultBondingPolicy": "aggressive-active-backup",
|
||||
"policies": {
|
||||
"aggressive-active-backup": {
|
||||
"links": {
|
||||
"eth0": {
|
||||
"ipvPref": 46,
|
||||
"failoverTo": "eth2",
|
||||
"mode": "primary"
|
||||
},
|
||||
"eth1": {
|
||||
"ipvPref": 46,
|
||||
"failoverTo": "eth2",
|
||||
"mode": "primary"
|
||||
},
|
||||
"eth2": {
|
||||
"ipvPref": 6,
|
||||
"mode": "spare"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Additional link-specific parameters:
|
||||
|
||||
```
|
||||
"links":
|
||||
{
|
||||
"interfaceName": /* System-name of the network interface. */
|
||||
{
|
||||
"failoverInterval": 0-65535, /* (optional) How quickly a path on this link should failover after a detected failure. */
|
||||
"ipvPref": [0,4,6,46,64], /* (optional) IP version preference for detected paths on a link. */
|
||||
"speed": 0-1000000, /* (optional) How fast this link is (in arbitrary units). This is a useful way to manually allocate a bond. */
|
||||
"alloc": 0-255, /* (optional) A relative value representing a desired allocation. */
|
||||
"upDelay": 0-65535, /* (optional) How long after a path becomes alive before it is added to the bond. */
|
||||
"downDelay": 0-65535, /* (optional) How long after a path fails before it is removed from the bond. */
|
||||
"failoverTo": "spareInterfaceName", /* (optional) Which link should be used next after a failure of this link. */
|
||||
"enabled": true|false, /* (optional) Whether any paths on this link are allowed to be used this bond. */
|
||||
"mode": "primary"|"spare" /* (optional) Whether this link is used by default or only after failover events. */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Peer-specific bonds
|
||||
|
||||
It is possible to direct ZeroTier to form a certain type of bond with specific peers of your choice. For instance, if one were to want `active-backup` by default but for certain peers to be bonded with a custom load-balanced bond such as `my-custom-balance-aware` one could do the following:
|
||||
|
||||
```
|
||||
{
|
||||
"settings":
|
||||
{
|
||||
"defaultBondingPolicy": "active-backup",
|
||||
"policies":
|
||||
{
|
||||
"my-custom-balance-aware":
|
||||
{
|
||||
"failoverInterval": 2000,
|
||||
"monitorStrategy": "dynamic",
|
||||
"basePolicy": "balance-aware"
|
||||
}
|
||||
},
|
||||
"peerSpecificBonds":
|
||||
{
|
||||
"f6203a2db3":"my-custom-balance-aware",
|
||||
"45b0301da2":"my-custom-balance-aware",
|
||||
"a92cb526fa":"my-custom-balance-aware"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Active backup (`active-backup`)
|
||||
|
||||
Traffic is sent only on (one) path at any given time. A different path becomes active if the current path fails. This mode provides fault tolerance with a nearly immediate fail-over. This mode **does not** increase total throughput.
|
||||
|
||||
- `mode`: `primary, spare` Link option which specifies which link is the primary device. The specified device is intended to always be the active link while it is available. There are exceptions to this behavior when using different `linkSelectMethod` modes. There can only be one `primary` link in this bonding policy.
|
||||
|
||||
- `linkSelectMethod`: Specifies the selection policy for the active link during failure and/or recovery events. This is similar to the Linux Kernel's `primary_reselect` option but with a minor extension:
|
||||
- `optimize`: **(default if user provides no failover guidance)** The primary link can change periodically if a superior path is detected.
|
||||
- `always`: **(default when links are explicitly specified)**: Primary link regains status as active link whenever it comes back up.
|
||||
- `better`: Primary link regains status as active link when it comes back up and (if) it is better than the currently-active link.
|
||||
- `failure`: Primary link regains status as active link only if the currently-active link fails.
|
||||
|
||||
```
|
||||
{
|
||||
"settings":
|
||||
{
|
||||
"defaultBondingPolicy": "active-backup",
|
||||
"active-backup":
|
||||
{
|
||||
"linkSelectMethod": "always",
|
||||
"links":
|
||||
{
|
||||
"eth0": { "failoverTo": "eth1", "mode": "primary" },
|
||||
"eth1": { "mode": "spare" },
|
||||
"eth2": { "mode": "spare" },
|
||||
"eth3": { "mode": "spare" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Broadcast (`broadcast`)
|
||||
|
||||
Traffic is sent on (all) available paths simultaneously. This mode provides fault tolerance and effectively immediate failover due to transmission redundancy. This mode is a poor utilization of throughput resources and will **not** increase throughput but can prevent packet loss during a link failure. The only option available is `dedup` which will de-duplicate all packets on the receiving end if set to `true`.
|
||||
|
||||
#### Balance round robin (`balance-rr`)
|
||||
|
||||
Traffic is striped across multiple paths. Offers partial fault tolerance immediately, full fault tolerance eventually. This policy is unaware of protocols and is primarily intended for use with protocols that are not sensitive to reordering delays. The only option available for this policy is `packetsPerLink` which specifies the number of packets to transmit via a path before moving to the next in the RR sequence. When set to `0` a path is chosen at random for each outgoing packet. The default value is `8`, low values can begin to add overhead to packet processing.
|
||||
|
||||
#### Balance XOR (`balance-xor`, similar to the Linux kernel's [balance-xor](https://www.kernel.org/doc/Documentation/networking/bonding.txt) with `xmit_hash_policy=layer3+4`)
|
||||
|
||||
Traffic is categorized into *flows* based on *source port*, *destination port*, and *protocol type* these flows are then hashed onto available links. Each flow will persist on its assigned link interface for its entire life-cycle. Traffic that does not have an assigned port (such as ICMP pings) will be randomly distributed across links. The hash function is simply: `src_port ^ dst_port ^ proto`.
|
||||
|
||||
#### Balance aware (`balance-aware`, similar to Linux kernel's [`balance-*lb`](https://www.kernel.org/doc/Documentation/networking/bonding.txt) modes)
|
||||
|
||||
Traffic is dynamically allocated and balanced across multiple links simultaneously according to the target allocation. Options allow for *packet* or *flow-based* processing, and active-flow reassignment. Flows mediated over a recently failed links will be reassigned in a manner that respects the target allocation of the bond. An optional `balancePolicy` can be specified with the following effects: `flow-dynamic` (default) will hash flows onto links according to target allocation and may perform periodic re-assignments in order to preserve balance. `flow-static`, will hash flows onto links according to target allocation but will not re-assign flows unless a failure occurs or the link is no longer operating within acceptable parameters. And lastly `packet` which simply load balances packets across links according to target allocation but with no concern for sequence reordering.
|
||||
|
||||
```
|
||||
{
|
||||
"settings":
|
||||
{
|
||||
"defaultBondingPolicy": "balance-aware",
|
||||
"balance-aware": {
|
||||
"balancePolicy": "flow-dynamic"|"flow-static"|"packet"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Link quality
|
||||
|
||||
ZeroTier measures various properties of a link (such as latency, throughput, jitter, packet loss ratio, etc) in order to arrive at a quality estimate. This estimate is used by bonding policies to make allocation and failover decisions:
|
||||
|
||||
| Policy name | Role |
|
||||
|:---------------|:-----|
|
||||
|`active-backup` | Determines the order of the failover queue. And if `activeReselect=optimize` whether a new active link is selected. |
|
||||
|`broadcast` | Does not use quality measurements. |
|
||||
|`balance-rr` | May trigger removal of link from bond. |
|
||||
|`balance-xor` | May trigger removal of link from bond. |
|
||||
|`balance-aware` | Informs flow assignments and (re-)assignments. May trigger removal of link from bond. |
|
||||
|
||||
A link's eligibility for being included in a bond is dependent on more than perceived quality. If a path on a link begins to exhibit disruptive behavior such as extremely high packet loss, corruption, or periodic inability to process traffic it will be removed from the bond, its traffic will be appropriately reallocated and it will be punished. Punishments gradually fade and a link can be readmitted to the bond over time. However, punishments increase exponentially if applied more than once within a given window of time.
|
||||
|
||||
#### Asymmetric links
|
||||
|
||||
In cases where it is necessary to bond physical links that vary radically in terms of cost, throughput, latency, and or reliability, there are a couple of ways to automatically (or manually) allocate traffic among them. Traffic distribution and balancing can be either `packet` or `flow` based. Where packet-based is suitable for protocols not susceptible to reordering penalties and flow-based is suitable for protocols such as TCP where it is desirable to keep a conversation on a single link unless we can't avoid having to re-assign it. Additionally, a *target allocation* of traffic used by the bonding policy can be derived/specified in the following ways:
|
||||
|
||||
- **Automatically**: This is the easiest and requires no user configuration. The bonding layer measures and senses the link properties and determines a target allocation based on perceived quality and capacity. Weaker, less reliable links will have less traffic allocated to them and stronger, more reliable links will have more traffic allocated to them. Optionally, the user can specify a set of weights (totaling `1.0`) to inform the bonding layer how important certain link properties are. For instance, one may primarily be concerned with latency and jitter but not total throughput:
|
||||
|
||||
```
|
||||
"balance-aware": {
|
||||
"quality": {
|
||||
"lat": 0.3, /* Moving average of latency in milliseconds */
|
||||
"ltm": 0.2, /* Maximum observed latency in milliseconds */
|
||||
"pdv": 0.3, /* Packet delay variance in milliseconds. Similar to jitter */
|
||||
"plr": 0.1, /* Packet loss ratio */
|
||||
"per": 0.1, /* Packet error ratio */
|
||||
"avl": 0.0, /* Availability */
|
||||
}
|
||||
}
|
||||
```
|
||||
In the absence of user guidance ZeroTier will attempt to form an understanding of each link's speed and capacity but this value can be inaccurate if the links are not routinely saturated. Therefore we provide a way to explicitly signal the capacity of each link in terms of arbitrary but relative values:
|
||||
|
||||
```
|
||||
"links": {
|
||||
"eth0": { "speed": 10000 },
|
||||
"eth1": { "speed": 1000 },
|
||||
"eth2": { "speed": 100 }
|
||||
}
|
||||
```
|
||||
|
||||
The user specifies allocation percentages (totaling `1.0`). In this case quality measurements will only be used to determine a link's eligibility to be a member of a bond, now how much traffic it will carry:
|
||||
|
||||
```
|
||||
"links": {
|
||||
"eth0": { "alloc": 0.50 },
|
||||
"eth1": { "alloc": 0.25 },
|
||||
"eth2": { "alloc": 0.25 }
|
||||
}
|
||||
```
|
||||
|
||||
#### Performance and overhead considerations
|
||||
|
||||
- Only packets with internal IDs divisible by `16` are included in measurements, this amounts to about `6.25%` of all traffic.
|
||||
- `failoverInterval` specifies how quickly failover should occur during a link failure. In order to accomplish this a combination of active and passive measurement techniques are employed which may result in `VERB_HELLO` probes being sent every `failoverInterval / 4` time units. As a mitigation `monitorStrategy` may be set to `dynamic` so that probe frequency directly correlates with native application traffic.
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Copyright (c)2019 ZeroTier, Inc.
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2023-01-01
|
||||
* Change Date: 2025-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
|
@ -39,6 +39,8 @@
|
|||
#include "../node/Salsa20.hpp"
|
||||
#include "../node/Poly1305.hpp"
|
||||
#include "../node/SHA512.hpp"
|
||||
#include "../node/Bond.hpp"
|
||||
#include "../node/Peer.hpp"
|
||||
|
||||
#include "../osdep/Phy.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
|
@ -48,6 +50,7 @@
|
|||
#include "../osdep/Binder.hpp"
|
||||
#include "../osdep/ManagedRoute.hpp"
|
||||
#include "../osdep/BlockingQueue.hpp"
|
||||
#include "../osdep/Link.hpp"
|
||||
|
||||
#include "OneService.hpp"
|
||||
#include "SoftwareUpdater.hpp"
|
||||
|
@ -69,6 +72,12 @@
|
|||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "../osdep/MacDNSHelper.hpp"
|
||||
#elif defined(__WINDOWS__)
|
||||
#include "../osdep/WinDNSHelper.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef ZT_USE_SYSTEM_HTTP_PARSER
|
||||
#include <http_parser.h>
|
||||
#else
|
||||
|
@ -86,7 +95,8 @@ extern "C" {
|
|||
using json = nlohmann::json;
|
||||
|
||||
#include "../controller/EmbeddedNetworkController.hpp"
|
||||
#include "../controller/RabbitMQ.hpp"
|
||||
#include "../controller/PostgreSQL.hpp"
|
||||
#include "../controller/Redis.hpp"
|
||||
#include "../osdep/EthernetTap.hpp"
|
||||
#ifdef __WINDOWS__
|
||||
#include "../osdep/WindowsEthernetTap.hpp"
|
||||
|
@ -199,6 +209,7 @@ static void _networkToJson(nlohmann::json &nj,const ZT_VirtualNetworkConfig *nc,
|
|||
nj["allowManaged"] = localSettings.allowManaged;
|
||||
nj["allowGlobal"] = localSettings.allowGlobal;
|
||||
nj["allowDefault"] = localSettings.allowDefault;
|
||||
nj["allowDNS"] = localSettings.allowDNS;
|
||||
|
||||
nlohmann::json aa = nlohmann::json::array();
|
||||
for(unsigned int i=0;i<nc->assignedAddressCount;++i) {
|
||||
|
@ -227,6 +238,20 @@ static void _networkToJson(nlohmann::json &nj,const ZT_VirtualNetworkConfig *nc,
|
|||
mca.push_back(m);
|
||||
}
|
||||
nj["multicastSubscriptions"] = mca;
|
||||
|
||||
nlohmann::json m;
|
||||
m["domain"] = nc->dns.domain;
|
||||
m["servers"] = nlohmann::json::array();
|
||||
for(int j=0;j<ZT_MAX_DNS_SERVERS;++j) {
|
||||
|
||||
InetAddress a(nc->dns.server_addr[j]);
|
||||
if (a.isV4() || a.isV6()) {
|
||||
char buf[256];
|
||||
m["servers"].push_back(a.toIpString(buf));
|
||||
}
|
||||
}
|
||||
nj["dns"] = m;
|
||||
|
||||
}
|
||||
|
||||
static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer)
|
||||
|
@ -249,6 +274,11 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer)
|
|||
pj["version"] = tmp;
|
||||
pj["latency"] = peer->latency;
|
||||
pj["role"] = prole;
|
||||
pj["isBonded"] = peer->isBonded;
|
||||
pj["bondingPolicy"] = peer->bondingPolicy;
|
||||
pj["isHealthy"] = peer->isHealthy;
|
||||
pj["numAliveLinks"] = peer->numAliveLinks;
|
||||
pj["numTotalLinks"] = peer->numTotalLinks;
|
||||
|
||||
nlohmann::json pa = nlohmann::json::array();
|
||||
for(unsigned int i=0;i<peer->pathCount;++i) {
|
||||
|
@ -267,37 +297,43 @@ static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer)
|
|||
pj["paths"] = pa;
|
||||
}
|
||||
|
||||
static void _peerAggregateLinkToJson(nlohmann::json &pj,const ZT_Peer *peer)
|
||||
static void _peerBondToJson(nlohmann::json &pj,const ZT_Peer *peer)
|
||||
{
|
||||
char tmp[256];
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.10llx",peer->address);
|
||||
pj["aggregateLinkLatency"] = peer->latency;
|
||||
//pj["aggregateLinkLatency"] = peer->latency;
|
||||
std::string policyStr = BondController::getPolicyStrByCode(peer->bondingPolicy);
|
||||
pj["policy"] = policyStr;
|
||||
|
||||
nlohmann::json pa = nlohmann::json::array();
|
||||
for(unsigned int i=0;i<peer->pathCount;++i) {
|
||||
int64_t lastSend = peer->paths[i].lastSend;
|
||||
int64_t lastReceive = peer->paths[i].lastReceive;
|
||||
nlohmann::json j;
|
||||
j["address"] = reinterpret_cast<const InetAddress *>(&(peer->paths[i].address))->toString(tmp);
|
||||
j["lastSend"] = (lastSend < 0) ? 0 : lastSend;
|
||||
j["lastReceive"] = (lastReceive < 0) ? 0 : lastReceive;
|
||||
j["ifname"] = std::string(peer->paths[i].ifname);
|
||||
j["path"] = reinterpret_cast<const InetAddress *>(&(peer->paths[i].address))->toString(tmp);
|
||||
j["lastTX"] = (lastSend < 0) ? 0 : lastSend;
|
||||
j["lastRX"] = (lastReceive < 0) ? 0 : lastReceive;
|
||||
j["lat"] = peer->paths[i].latencyMean;
|
||||
j["pdv"] = peer->paths[i].latencyVariance;
|
||||
|
||||
//j["trustedPathId"] = peer->paths[i].trustedPathId;
|
||||
//j["active"] = (bool)(peer->paths[i].expired == 0);
|
||||
//j["expired"] = (bool)(peer->paths[i].expired != 0);
|
||||
//j["preferred"] = (bool)(peer->paths[i].preferred != 0);
|
||||
j["latency"] = peer->paths[i].latency;
|
||||
j["pdv"] = peer->paths[i].packetDelayVariance;
|
||||
//j["throughputDisturbCoeff"] = peer->paths[i].throughputDisturbCoeff;
|
||||
//j["packetErrorRatio"] = peer->paths[i].packetErrorRatio;
|
||||
//j["packetLossRatio"] = peer->paths[i].packetLossRatio;
|
||||
j["stability"] = peer->paths[i].stability;
|
||||
j["throughput"] = peer->paths[i].throughput;
|
||||
//j["maxThroughput"] = peer->paths[i].maxThroughput;
|
||||
j["allocation"] = peer->paths[i].allocation;
|
||||
j["ifname"] = peer->paths[i].ifname;
|
||||
//j["ltm"] = peer->paths[i].latencyMax;
|
||||
//j["plr"] = peer->paths[i].packetLossRatio;
|
||||
//j["per"] = peer->paths[i].packetErrorRatio;
|
||||
//j["thr"] = peer->paths[i].throughputMean;
|
||||
//j["thm"] = peer->paths[i].throughputMax;
|
||||
//j["thv"] = peer->paths[i].throughputVariance;
|
||||
//j["avl"] = peer->paths[i].availability;
|
||||
//j["age"] = peer->paths[i].age;
|
||||
//j["alloc"] = peer->paths[i].allocation;
|
||||
//j["ifname"] = peer->paths[i].ifname;
|
||||
pa.push_back(j);
|
||||
}
|
||||
pj["paths"] = pa;
|
||||
pj["links"] = pa;
|
||||
}
|
||||
|
||||
static void _moonToJson(nlohmann::json &mj,const World &world)
|
||||
|
@ -430,7 +466,7 @@ public:
|
|||
bool _updateAutoApply;
|
||||
bool _allowTcpFallbackRelay;
|
||||
bool _allowSecondaryPort;
|
||||
unsigned int _multipathMode;
|
||||
|
||||
unsigned int _primaryPort;
|
||||
unsigned int _secondaryPort;
|
||||
unsigned int _tertiaryPort;
|
||||
|
@ -486,6 +522,8 @@ public:
|
|||
settings.allowManaged = true;
|
||||
settings.allowGlobal = false;
|
||||
settings.allowDefault = false;
|
||||
settings.allowDNS = false;
|
||||
memset(&config, 0, sizeof(ZT_VirtualNetworkConfig));
|
||||
}
|
||||
|
||||
std::shared_ptr<EthernetTap> tap;
|
||||
|
@ -525,7 +563,7 @@ public:
|
|||
volatile bool _run;
|
||||
Mutex _run_m;
|
||||
|
||||
MQConfig *_mqc;
|
||||
RedisConfig *_rc;
|
||||
|
||||
// end member variables ----------------------------------------------------
|
||||
|
||||
|
@ -562,7 +600,7 @@ public:
|
|||
,_vaultPath("cubbyhole/zerotier")
|
||||
#endif
|
||||
,_run(true)
|
||||
,_mqc(NULL)
|
||||
,_rc(NULL)
|
||||
{
|
||||
_ports[0] = 0;
|
||||
_ports[1] = 0;
|
||||
|
@ -587,7 +625,7 @@ public:
|
|||
delete _portMapper;
|
||||
#endif
|
||||
delete _controller;
|
||||
delete _mqc;
|
||||
delete _rc;
|
||||
}
|
||||
|
||||
virtual ReasonForTermination run()
|
||||
|
@ -723,11 +761,12 @@ public:
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Delete legacy iddb.d if present (cleanup)
|
||||
OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str());
|
||||
|
||||
// Network controller is now enabled by default for desktop and server
|
||||
_controller = new EmbeddedNetworkController(_node,_homePath.c_str(),_controllerDbPath.c_str(),_ports[0], _mqc);
|
||||
_controller = new EmbeddedNetworkController(_node,_homePath.c_str(),_controllerDbPath.c_str(),_ports[0], _rc);
|
||||
_node->setNetconfMaster((void *)_controller);
|
||||
|
||||
// Join existing networks in networks.d
|
||||
|
@ -757,7 +796,6 @@ public:
|
|||
int64_t lastTapMulticastGroupCheck = 0;
|
||||
int64_t lastBindRefresh = 0;
|
||||
int64_t lastUpdateCheck = clockShouldBe;
|
||||
int64_t lastMultipathModeUpdate = 0;
|
||||
int64_t lastCleanedPeersDb = 0;
|
||||
int64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle
|
||||
int64_t lastLocalConfFileCheck = OSUtils::now();
|
||||
|
@ -803,7 +841,7 @@ public:
|
|||
}
|
||||
|
||||
// Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default)
|
||||
if (((now - lastBindRefresh) >= (_multipathMode ? ZT_BINDER_REFRESH_PERIOD / 8 : ZT_BINDER_REFRESH_PERIOD))||(restarted)) {
|
||||
if (((now - lastBindRefresh) >= (_node->bondController()->inUse() ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD))||(restarted)) {
|
||||
lastBindRefresh = now;
|
||||
unsigned int p[3];
|
||||
unsigned int pc = 0;
|
||||
|
@ -816,15 +854,10 @@ public:
|
|||
Mutex::Lock _l(_nets_m);
|
||||
for(std::map<uint64_t,NetworkState>::iterator n(_nets.begin());n!=_nets.end();++n) {
|
||||
if (n->second.tap)
|
||||
syncManagedStuff(n->second,false,true);
|
||||
syncManagedStuff(n->second,false,true,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update multipath mode (if needed)
|
||||
if (((now - lastMultipathModeUpdate) >= ZT_BINDER_REFRESH_PERIOD / 8)||(restarted)) {
|
||||
lastMultipathModeUpdate = now;
|
||||
_node->setMultipathMode(_multipathMode);
|
||||
}
|
||||
|
||||
// Run background task processor in core if it's time to do so
|
||||
int64_t dl = _nextBackgroundTaskDeadline;
|
||||
|
@ -860,7 +893,7 @@ public:
|
|||
}
|
||||
|
||||
// Sync information about physical network interfaces
|
||||
if ((now - lastLocalInterfaceAddressCheck) >= (_multipathMode ? ZT_LOCAL_INTERFACE_CHECK_INTERVAL / 8 : ZT_LOCAL_INTERFACE_CHECK_INTERVAL)) {
|
||||
if ((now - lastLocalInterfaceAddressCheck) >= (_node->bondController()->inUse() ? ZT_LOCAL_INTERFACE_CHECK_INTERVAL / 8 : ZT_LOCAL_INTERFACE_CHECK_INTERVAL)) {
|
||||
lastLocalInterfaceAddressCheck = now;
|
||||
|
||||
_node->clearLocalInterfaceAddresses();
|
||||
|
@ -874,8 +907,9 @@ public:
|
|||
#endif
|
||||
|
||||
std::vector<InetAddress> boundAddrs(_binder.allBoundLocalInterfaceAddresses());
|
||||
for(std::vector<InetAddress>::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i)
|
||||
for(std::vector<InetAddress>::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i) {
|
||||
_node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&(*i)));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean peers.d periodically
|
||||
|
@ -991,15 +1025,17 @@ public:
|
|||
if (cdbp.length() > 0)
|
||||
_controllerDbPath = cdbp;
|
||||
|
||||
json &rmq = settings["rabbitmq"];
|
||||
if (rmq.is_object() && _mqc == NULL) {
|
||||
fprintf(stderr, "Reading RabbitMQ Config\n");
|
||||
_mqc = new MQConfig;
|
||||
_mqc->port = rmq["port"];
|
||||
_mqc->host = OSUtils::jsonString(rmq["host"], "");
|
||||
_mqc->username = OSUtils::jsonString(rmq["username"], "");
|
||||
_mqc->password = OSUtils::jsonString(rmq["password"], "");
|
||||
#ifdef ZT_CONTROLLER_USE_LIBPQ
|
||||
// TODO: Redis config
|
||||
json &redis = settings["redis"];
|
||||
if (redis.is_object() && _rc == NULL) {
|
||||
_rc = new RedisConfig;
|
||||
_rc->hostname = OSUtils::jsonString(redis["hostname"],"");
|
||||
_rc->port = redis["port"];
|
||||
_rc->password = OSUtils::jsonString(redis["password"],"");
|
||||
_rc->clusterMode = OSUtils::jsonBool(redis["clusterMode"], false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Bind to wildcard instead of to specific interfaces (disables full tunnel capability)
|
||||
json &bind = settings["bind"];
|
||||
|
@ -1100,11 +1136,12 @@ public:
|
|||
fprintf(out,"allowManaged=%d\n",(int)n->second.settings.allowManaged);
|
||||
fprintf(out,"allowGlobal=%d\n",(int)n->second.settings.allowGlobal);
|
||||
fprintf(out,"allowDefault=%d\n",(int)n->second.settings.allowDefault);
|
||||
fprintf(out,"allowDNS=%d\n",(int)n->second.settings.allowDNS);
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
if (n->second.tap)
|
||||
syncManagedStuff(n->second,true,true);
|
||||
syncManagedStuff(n->second,true,true,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1222,15 +1259,15 @@ public:
|
|||
settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff;
|
||||
settings["allowTcpFallbackRelay"] = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],_allowTcpFallbackRelay);
|
||||
|
||||
if (_multipathMode) {
|
||||
json &multipathConfig = res["multipath"];
|
||||
if (_node->bondController()->inUse()) {
|
||||
json &multipathConfig = res["bonds"];
|
||||
ZT_PeerList *pl = _node->peers();
|
||||
char peerAddrStr[256];
|
||||
if (pl) {
|
||||
for(unsigned long i=0;i<pl->peerCount;++i) {
|
||||
if (pl->peers[i].hadAggregateLink) {
|
||||
if (pl->peers[i].isBonded) {
|
||||
nlohmann::json pj;
|
||||
_peerAggregateLinkToJson(pj,&(pl->peers[i]));
|
||||
_peerBondToJson(pj,&(pl->peers[i]));
|
||||
OSUtils::ztsnprintf(peerAddrStr,sizeof(peerAddrStr),"%.10llx",pl->peers[i].address);
|
||||
multipathConfig[peerAddrStr] = (pj);
|
||||
}
|
||||
|
@ -1340,6 +1377,35 @@ public:
|
|||
} else scode = 404;
|
||||
_node->freeQueryResult((void *)pl);
|
||||
} else scode = 500;
|
||||
} else if (ps[0] == "bonds") {
|
||||
ZT_PeerList *pl = _node->peers();
|
||||
if (pl) {
|
||||
if (ps.size() == 1) {
|
||||
// Return [array] of all peers
|
||||
|
||||
res = nlohmann::json::array();
|
||||
for(unsigned long i=0;i<pl->peerCount;++i) {
|
||||
nlohmann::json pj;
|
||||
_peerToJson(pj,&(pl->peers[i]));
|
||||
res.push_back(pj);
|
||||
}
|
||||
|
||||
scode = 200;
|
||||
} else if (ps.size() == 2) {
|
||||
// Return a single peer by ID or 404 if not found
|
||||
|
||||
uint64_t wantp = Utils::hexStrToU64(ps[1].c_str());
|
||||
for(unsigned long i=0;i<pl->peerCount;++i) {
|
||||
if (pl->peers[i].address == wantp) {
|
||||
_peerToJson(res,&(pl->peers[i]));
|
||||
scode = 200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else scode = 404;
|
||||
_node->freeQueryResult((void *)pl);
|
||||
} else scode = 500;
|
||||
} else {
|
||||
if (_controller) {
|
||||
scode = _controller->handleControlPlaneHttpGET(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
|
||||
|
@ -1359,8 +1425,8 @@ public:
|
|||
if (j.is_object()) {
|
||||
seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"],"0").c_str());
|
||||
}
|
||||
} catch (std::exception &exc) {
|
||||
} catch ( ... ) {
|
||||
// discard invalid JSON
|
||||
}
|
||||
|
||||
std::vector<World> moons(_node->moons());
|
||||
|
@ -1408,9 +1474,11 @@ public:
|
|||
if (allowGlobal.is_boolean()) localSettings.allowGlobal = (bool)allowGlobal;
|
||||
json &allowDefault = j["allowDefault"];
|
||||
if (allowDefault.is_boolean()) localSettings.allowDefault = (bool)allowDefault;
|
||||
json &allowDNS = j["allowDNS"];
|
||||
if (allowDNS.is_boolean()) localSettings.allowDNS = (bool)allowDNS;
|
||||
}
|
||||
} catch (std::exception &exc) {
|
||||
} catch ( ... ) {
|
||||
// discard invalid JSON
|
||||
}
|
||||
|
||||
setNetworkSettings(nws->networks[i].nwid,localSettings);
|
||||
|
@ -1564,19 +1632,148 @@ public:
|
|||
|
||||
json &settings = lc["settings"];
|
||||
|
||||
if (!_node->bondController()->inUse()) {
|
||||
// defaultBondingPolicy
|
||||
std::string defaultBondingPolicyStr(OSUtils::jsonString(settings["defaultBondingPolicy"],""));
|
||||
int defaultBondingPolicy = _node->bondController()->getPolicyCodeByStr(defaultBondingPolicyStr);
|
||||
_node->bondController()->setBondingLayerDefaultPolicy(defaultBondingPolicy);
|
||||
_node->bondController()->setBondingLayerDefaultPolicyStr(defaultBondingPolicyStr); // Used if custom policy
|
||||
// Custom Policies
|
||||
json &customBondingPolicies = settings["policies"];
|
||||
for (json::iterator policyItr = customBondingPolicies.begin(); policyItr != customBondingPolicies.end();++policyItr) {
|
||||
// Custom Policy
|
||||
std::string customPolicyStr(policyItr.key());
|
||||
json &customPolicy = policyItr.value();
|
||||
std::string basePolicyStr(OSUtils::jsonString(customPolicy["basePolicy"],""));
|
||||
if (_node->bondController()->getPolicyCodeByStr(basePolicyStr) == ZT_BONDING_POLICY_NONE) {
|
||||
fprintf(stderr, "error: custom policy (%s) is invalid, unknown base policy (%s).\n",
|
||||
customPolicyStr.c_str(), basePolicyStr.c_str());
|
||||
continue;
|
||||
} if (_node->bondController()->getPolicyCodeByStr(customPolicyStr) != ZT_BONDING_POLICY_NONE) {
|
||||
fprintf(stderr, "error: custom policy (%s) will be ignored, cannot use standard policy names for custom policies.\n",
|
||||
customPolicyStr.c_str());
|
||||
continue;
|
||||
}
|
||||
// New bond, used as a copy template for new instances
|
||||
SharedPtr<Bond> newTemplateBond = new Bond(NULL, basePolicyStr, customPolicyStr, SharedPtr<Peer>());
|
||||
// Acceptable ranges
|
||||
newTemplateBond->setMaxAcceptableLatency(OSUtils::jsonInt(customPolicy["maxAcceptableLatency"],-1));
|
||||
newTemplateBond->setMaxAcceptableMeanLatency(OSUtils::jsonInt(customPolicy["maxAcceptableMeanLatency"],-1));
|
||||
newTemplateBond->setMaxAcceptablePacketDelayVariance(OSUtils::jsonInt(customPolicy["maxAcceptablePacketDelayVariance"],-1));
|
||||
newTemplateBond->setMaxAcceptablePacketLossRatio((float)OSUtils::jsonDouble(customPolicy["maxAcceptablePacketLossRatio"],-1));
|
||||
newTemplateBond->setMaxAcceptablePacketErrorRatio((float)OSUtils::jsonDouble(customPolicy["maxAcceptablePacketErrorRatio"],-1));
|
||||
newTemplateBond->setMinAcceptableAllocation((float)OSUtils::jsonDouble(customPolicy["minAcceptableAllocation"],0));
|
||||
// Quality weights
|
||||
json &qualityWeights = customPolicy["qualityWeights"];
|
||||
if (qualityWeights.size() == ZT_QOS_WEIGHT_SIZE) { // TODO: Generalize this
|
||||
float weights[ZT_QOS_WEIGHT_SIZE];
|
||||
weights[ZT_QOS_LAT_IDX] = (float)OSUtils::jsonDouble(qualityWeights["lat"],0.0);
|
||||
weights[ZT_QOS_LTM_IDX] = (float)OSUtils::jsonDouble(qualityWeights["ltm"],0.0);
|
||||
weights[ZT_QOS_PDV_IDX] = (float)OSUtils::jsonDouble(qualityWeights["pdv"],0.0);
|
||||
weights[ZT_QOS_PLR_IDX] = (float)OSUtils::jsonDouble(qualityWeights["plr"],0.0);
|
||||
weights[ZT_QOS_PER_IDX] = (float)OSUtils::jsonDouble(qualityWeights["per"],0.0);
|
||||
weights[ZT_QOS_THR_IDX] = (float)OSUtils::jsonDouble(qualityWeights["thr"],0.0);
|
||||
weights[ZT_QOS_THM_IDX] = (float)OSUtils::jsonDouble(qualityWeights["thm"],0.0);
|
||||
weights[ZT_QOS_THV_IDX] = (float)OSUtils::jsonDouble(qualityWeights["thv"],0.0);
|
||||
newTemplateBond->setUserQualityWeights(weights,ZT_QOS_WEIGHT_SIZE);
|
||||
}
|
||||
// Bond-specific properties
|
||||
newTemplateBond->setUpDelay(OSUtils::jsonInt(customPolicy["upDelay"],-1));
|
||||
newTemplateBond->setDownDelay(OSUtils::jsonInt(customPolicy["downDelay"],-1));
|
||||
newTemplateBond->setFlowRebalanceStrategy(OSUtils::jsonInt(customPolicy["flowRebalanceStrategy"],(uint64_t)0));
|
||||
newTemplateBond->setFailoverInterval(OSUtils::jsonInt(customPolicy["failoverInterval"],(uint64_t)0));
|
||||
newTemplateBond->setPacketsPerLink(OSUtils::jsonInt(customPolicy["packetsPerLink"],-1));
|
||||
|
||||
std::string linkMonitorStrategyStr(OSUtils::jsonString(customPolicy["linkMonitorStrategy"],""));
|
||||
uint8_t linkMonitorStrategy = ZT_MULTIPATH_SLAVE_MONITOR_STRATEGY_DEFAULT;
|
||||
if (linkMonitorStrategyStr == "passive") { linkMonitorStrategy = ZT_MULTIPATH_SLAVE_MONITOR_STRATEGY_PASSIVE; }
|
||||
if (linkMonitorStrategyStr == "active") { linkMonitorStrategy = ZT_MULTIPATH_SLAVE_MONITOR_STRATEGY_ACTIVE; }
|
||||
if (linkMonitorStrategyStr == "dynamic") { linkMonitorStrategy = ZT_MULTIPATH_SLAVE_MONITOR_STRATEGY_DYNAMIC; }
|
||||
newTemplateBond->setLinkMonitorStrategy(linkMonitorStrategy);
|
||||
|
||||
// Policy-Specific link set
|
||||
json &links = customPolicy["links"];
|
||||
for (json::iterator linkItr = links.begin(); linkItr != links.end();++linkItr) {
|
||||
std::string linkNameStr(linkItr.key());
|
||||
json &link = linkItr.value();
|
||||
|
||||
bool enabled = OSUtils::jsonInt(link["enabled"],true);
|
||||
uint32_t speed = OSUtils::jsonInt(link["speed"],0);
|
||||
float alloc = (float)OSUtils::jsonDouble(link["alloc"],0);
|
||||
|
||||
if (speed && alloc) {
|
||||
fprintf(stderr, "error: cannot specify both speed (%d) and alloc (%f) for link (%s), pick one, link disabled.\n",
|
||||
speed, alloc, linkNameStr.c_str());
|
||||
enabled = false;
|
||||
}
|
||||
uint32_t upDelay = OSUtils::jsonInt(link["upDelay"],-1);
|
||||
uint32_t downDelay = OSUtils::jsonInt(link["downDelay"],-1);
|
||||
uint8_t ipvPref = OSUtils::jsonInt(link["ipvPref"],0);
|
||||
uint32_t linkMonitorInterval = OSUtils::jsonInt(link["monitorInterval"],(uint64_t)0);
|
||||
std::string failoverToStr(OSUtils::jsonString(link["failoverTo"],""));
|
||||
// Mode
|
||||
std::string linkModeStr(OSUtils::jsonString(link["mode"],"spare"));
|
||||
uint8_t linkMode = ZT_MULTIPATH_SLAVE_MODE_SPARE;
|
||||
if (linkModeStr == "primary") { linkMode = ZT_MULTIPATH_SLAVE_MODE_PRIMARY; }
|
||||
if (linkModeStr == "spare") { linkMode = ZT_MULTIPATH_SLAVE_MODE_SPARE; }
|
||||
// ipvPref
|
||||
if ((ipvPref != 0) && (ipvPref != 4) && (ipvPref != 6) && (ipvPref != 46) && (ipvPref != 64)) {
|
||||
fprintf(stderr, "error: invalid ipvPref value (%d), link disabled.\n", ipvPref);
|
||||
enabled = false;
|
||||
}
|
||||
if (linkMode == ZT_MULTIPATH_SLAVE_MODE_SPARE && failoverToStr.length()) {
|
||||
fprintf(stderr, "error: cannot specify failover links for spares, link disabled.\n");
|
||||
failoverToStr = "";
|
||||
enabled = false;
|
||||
}
|
||||
_node->bondController()->addCustomLink(customPolicyStr, new Link(linkNameStr,ipvPref,speed,linkMonitorInterval,upDelay,downDelay,enabled,linkMode,failoverToStr,alloc));
|
||||
}
|
||||
std::string linkSelectMethodStr(OSUtils::jsonString(customPolicy["activeReselect"],"optimize"));
|
||||
if (linkSelectMethodStr == "always") {
|
||||
newTemplateBond->setLinkSelectMethod(ZT_MULTIPATH_RESELECTION_POLICY_ALWAYS);
|
||||
}
|
||||
if (linkSelectMethodStr == "better") {
|
||||
newTemplateBond->setLinkSelectMethod(ZT_MULTIPATH_RESELECTION_POLICY_BETTER);
|
||||
}
|
||||
if (linkSelectMethodStr == "failure") {
|
||||
newTemplateBond->setLinkSelectMethod(ZT_MULTIPATH_RESELECTION_POLICY_FAILURE);
|
||||
}
|
||||
if (linkSelectMethodStr == "optimize") {
|
||||
newTemplateBond->setLinkSelectMethod(ZT_MULTIPATH_RESELECTION_POLICY_OPTIMIZE);
|
||||
}
|
||||
if (newTemplateBond->getLinkSelectMethod() < 0 || newTemplateBond->getLinkSelectMethod() > 3) {
|
||||
fprintf(stderr, "warning: invalid value (%s) for linkSelectMethod, assuming mode: always\n", linkSelectMethodStr.c_str());
|
||||
}
|
||||
/*
|
||||
newBond->setPolicy(_node->bondController()->getPolicyCodeByStr(basePolicyStr));
|
||||
newBond->setFlowHashing((bool)OSUtils::jsonInt(userSpecifiedBondingPolicies[i]["allowFlowHashing"],(bool)allowFlowHashing));
|
||||
newBond->setBondMonitorInterval((unsigned int)OSUtils::jsonInt(userSpecifiedBondingPolicies[i]["monitorInterval"],(uint64_t)0));
|
||||
newBond->setAllowPathNegotiation((bool)OSUtils::jsonInt(userSpecifiedBondingPolicies[i]["allowPathNegotiation"],(bool)false));
|
||||
*/
|
||||
if (!_node->bondController()->addCustomPolicy(newTemplateBond)) {
|
||||
fprintf(stderr, "error: a custom policy of this name (%s) already exists.\n", customPolicyStr.c_str());
|
||||
}
|
||||
}
|
||||
// Peer-specific bonding
|
||||
json &peerSpecificBonds = settings["peerSpecificBonds"];
|
||||
for (json::iterator peerItr = peerSpecificBonds.begin(); peerItr != peerSpecificBonds.end();++peerItr) {
|
||||
_node->bondController()->assignBondingPolicyToPeer(std::stoull(peerItr.key(),0,16), peerItr.value());
|
||||
}
|
||||
// Check settings
|
||||
if (defaultBondingPolicyStr.length() && !defaultBondingPolicy && !_node->bondController()->inUse()) {
|
||||
fprintf(stderr, "error: unknown policy (%s) specified by defaultBondingPolicy, link disabled.\n", defaultBondingPolicyStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// bondingPolicy cannot be used with allowTcpFallbackRelay
|
||||
_allowTcpFallbackRelay = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],true) && !(_node->bondController()->inUse());
|
||||
_primaryPort = (unsigned int)OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff;
|
||||
_allowTcpFallbackRelay = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],true);
|
||||
_allowSecondaryPort = OSUtils::jsonBool(settings["allowSecondaryPort"],true);
|
||||
_secondaryPort = (unsigned int)OSUtils::jsonInt(settings["secondaryPort"],0);
|
||||
_tertiaryPort = (unsigned int)OSUtils::jsonInt(settings["tertiaryPort"],0);
|
||||
if (_secondaryPort != 0 || _tertiaryPort != 0) {
|
||||
fprintf(stderr,"WARNING: using manually-specified ports. This can cause NAT issues." ZT_EOL_S);
|
||||
}
|
||||
_multipathMode = (unsigned int)OSUtils::jsonInt(settings["multipathMode"],0);
|
||||
if (_multipathMode != 0 && _allowTcpFallbackRelay) {
|
||||
fprintf(stderr,"WARNING: multipathMode cannot be used with allowTcpFallbackRelay. Disabling allowTcpFallbackRelay" ZT_EOL_S);
|
||||
_allowTcpFallbackRelay = false;
|
||||
}
|
||||
_portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"],true);
|
||||
|
||||
#ifndef ZT_SDK
|
||||
|
@ -1698,7 +1895,7 @@ public:
|
|||
}
|
||||
|
||||
// Apply or update managed IPs for a configured network (be sure n.tap exists)
|
||||
void syncManagedStuff(NetworkState &n,bool syncIps,bool syncRoutes)
|
||||
void syncManagedStuff(NetworkState &n,bool syncIps,bool syncRoutes, bool syncDns)
|
||||
{
|
||||
char ipbuf[64];
|
||||
|
||||
|
@ -1721,9 +1918,8 @@ public:
|
|||
}
|
||||
}
|
||||
#ifdef __SYNOLOGY__
|
||||
if (!n.tap->addIps(newManagedIps)) {
|
||||
if (!n.tap->addIpSyn(newManagedIps))
|
||||
fprintf(stderr,"ERROR: unable to add ip addresses to ifcfg" ZT_EOL_S);
|
||||
}
|
||||
#else
|
||||
for(std::vector<InetAddress>::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) {
|
||||
if (std::find(n.managedIps.begin(),n.managedIps.end(),*ip) == n.managedIps.end()) {
|
||||
|
@ -1819,6 +2015,28 @@ public:
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (syncDns) {
|
||||
if (n.settings.allowDNS) {
|
||||
if (strlen(n.config.dns.domain) != 0) {
|
||||
std::vector<InetAddress> servers;
|
||||
for (int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) {
|
||||
InetAddress a(n.config.dns.server_addr[j]);
|
||||
if (a.isV4() || a.isV6()) {
|
||||
servers.push_back(a);
|
||||
}
|
||||
}
|
||||
n.tap->setDns(n.config.dns.domain, servers);
|
||||
}
|
||||
} else {
|
||||
#ifdef __APPLE__
|
||||
MacDNSHelper::removeDNS(n.config.nwid);
|
||||
#elif defined(__WINDOWS__)
|
||||
WinDNSHelper::removeDNS(n.config.nwid);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
@ -2041,8 +2259,6 @@ public:
|
|||
return;
|
||||
|
||||
}
|
||||
} catch (std::exception &exc) {
|
||||
_phy.close(sock);
|
||||
} catch ( ... ) {
|
||||
_phy.close(sock);
|
||||
}
|
||||
|
@ -2138,6 +2354,7 @@ public:
|
|||
}
|
||||
n.settings.allowGlobal = nc.getB("allowGlobal", false);
|
||||
n.settings.allowDefault = nc.getB("allowDefault", false);
|
||||
n.settings.allowDNS = nc.getB("allowDNS", false);
|
||||
}
|
||||
} catch (std::exception &exc) {
|
||||
#ifdef __WINDOWS__
|
||||
|
@ -2151,8 +2368,6 @@ public:
|
|||
#endif
|
||||
_nets.erase(nwid);
|
||||
return -999;
|
||||
} catch (int exc) {
|
||||
return -999;
|
||||
} catch ( ... ) {
|
||||
return -999; // tap init failed
|
||||
}
|
||||
|
@ -2172,7 +2387,7 @@ public:
|
|||
Sleep(10);
|
||||
}
|
||||
#endif
|
||||
syncManagedStuff(n,true,true);
|
||||
syncManagedStuff(n,true,true,true);
|
||||
n.tap->setMtu(nwc->mtu);
|
||||
} else {
|
||||
_nets.erase(nwid);
|
||||
|
@ -2759,6 +2974,7 @@ public:
|
|||
if (!strncmp(p->c_str(),ifname,p->length()))
|
||||
return false;
|
||||
}
|
||||
return _node->bondController()->allowedToBind(std::string(ifname));
|
||||
}
|
||||
{
|
||||
// Check global blacklists
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 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: 2023-01-01
|
||||
* Change Date: 2025-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
|
@ -86,6 +86,11 @@ public:
|
|||
* Allow overriding of system default routes for "full tunnel" operation?
|
||||
*/
|
||||
bool allowDefault;
|
||||
|
||||
/**
|
||||
* Allow configuration of DNS for the network
|
||||
*/
|
||||
bool allowDNS;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -139,6 +139,7 @@ Most network settings are not writable, as they are defined by the network contr
|
|||
| allowManaged | boolean | Allow IP and route management | yes |
|
||||
| allowGlobal | boolean | Allow IPs and routes that overlap with global IPs | yes |
|
||||
| allowDefault | boolean | Allow overriding of system default route | yes |
|
||||
| allowDNS | boolean | Allow configuration of DNS on network | yes |
|
||||
|
||||
Route objects:
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 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: 2023-01-01
|
||||
* Change Date: 2025-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
|
@ -112,10 +112,10 @@ void SoftwareUpdater::setUpdateDistribution(bool distribute)
|
|||
// If update meta is called e.g. foo.exe.json, then foo.exe is the update itself
|
||||
const std::string binPath(udd + ZT_PATH_SEPARATOR_S + u->substr(0,u->length() - 5));
|
||||
const std::string metaHash(OSUtils::jsonBinFromHex(d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH]));
|
||||
if ((metaHash.length() == ZT_SHA512_DIGEST_LEN)&&(OSUtils::readFile(binPath.c_str(),d.bin))) {
|
||||
std::array<uint8_t,ZT_SHA512_DIGEST_LEN> sha512;
|
||||
SHA512::hash(sha512.data(),d.bin.data(),(unsigned int)d.bin.length());
|
||||
if (!memcmp(sha512.data(),metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct
|
||||
if ((metaHash.length() == 64)&&(OSUtils::readFile(binPath.c_str(),d.bin))) {
|
||||
std::array<uint8_t,64> sha512;
|
||||
SHA512(sha512.data(),d.bin.data(),(unsigned int)d.bin.length());
|
||||
if (!memcmp(sha512.data(),metaHash.data(),64)) { // double check that hash in JSON is correct
|
||||
d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional
|
||||
std::array<uint8_t,16> shakey;
|
||||
memcpy(shakey.data(),sha512.data(),16);
|
||||
|
@ -333,10 +333,10 @@ bool SoftwareUpdater::check(const int64_t now)
|
|||
const std::string binPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME);
|
||||
try {
|
||||
// (1) Check the hash itself to make sure the image is basically okay
|
||||
uint8_t sha512[ZT_SHA512_DIGEST_LEN];
|
||||
SHA512::hash(sha512,_download.data(),(unsigned int)_download.length());
|
||||
char hexbuf[(ZT_SHA512_DIGEST_LEN * 2) + 2];
|
||||
if (OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"") == Utils::hex(sha512,ZT_SHA512_DIGEST_LEN,hexbuf)) {
|
||||
uint8_t sha512[64];
|
||||
SHA512(sha512,_download.data(),(unsigned int)_download.length());
|
||||
char hexbuf[(64 * 2) + 2];
|
||||
if (OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"") == Utils::hex(sha512,64,hexbuf)) {
|
||||
// (2) Check signature by signing authority
|
||||
const std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE]));
|
||||
if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(),(unsigned int)_download.length(),sig.data(),(unsigned int)sig.length())) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 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: 2023-01-01
|
||||
* Change Date: 2025-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue