Skip to content

Commit

Permalink
Add functionality to enable or disable networks (and interfaces) (fixes
Browse files Browse the repository at this point in the history
zerotier#659)

This is non-production ready code that adds the ability to disable certain networks.

This adds two new CLI commands (and corresponding HTTP endpoints):

zerotier-cli enable <network>  - Enables a network
zerotier-cli disable <network> - Disables a network

A disabled network gets loaded briefly on startup, but will be torn down immediatly after
startup. A disabled network behaves like the user left the network, except that config
data and the (Windows) network interface is still retained (in an offline state). Joining
or leaving a disabled network won't work. In order to rejoin a disabled network, it must
be re-enabled instead (disabling & enabling also auto-leaves/joins networks as appropriate).

Disabled networks remain disabled, even across restarts, until enabled again via the
appropriate command.

Note:
- The code has not been tested much and may not conform to quality standards
- No changes have been made to the (Windows) GUI application. This feature can only be
used via the CLI and *not* via the (Windows) GUI.

This is an adapted version of commit 1dbbeb2, rebased on ZeroTier 1.6.7
  • Loading branch information
GermanCoding committed Oct 18, 2021
1 parent 5d555ca commit 5091b90
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 48 deletions.
7 changes: 6 additions & 1 deletion include/ZeroTierOne.h
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,12 @@ enum ZT_VirtualNetworkStatus
/**
* ZeroTier core version too old
*/
ZT_NETWORK_STATUS_CLIENT_TOO_OLD = 5
ZT_NETWORK_STATUS_CLIENT_TOO_OLD = 5,

/**
* The network is disabled by local config setting
*/
ZT_NETWORK_DISABLED = 6
};

/**
Expand Down
5 changes: 5 additions & 0 deletions node/Network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,9 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
memset(&ctmp, 0, sizeof(ZT_VirtualNetworkConfig));
_externalConfig(&ctmp);
_portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
if (_portError == -1001) {
destroy();
}
_portInitialized = true;
}
}
Expand Down Expand Up @@ -1371,6 +1374,8 @@ ZT_VirtualNetworkStatus Network::_status() const
{
// assumes _lock is locked
if (_portError)
if (_portError == -1001)
return ZT_NETWORK_DISABLED;
return ZT_NETWORK_STATUS_PORT_ERROR;
switch(_netconfFailure) {
case NETCONF_FAILURE_ACCESS_DENIED:
Expand Down
13 changes: 9 additions & 4 deletions node/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,13 @@ ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr)
SharedPtr<Network> &nw = _networks[nwid];
if (!nw)
nw = SharedPtr<Network>(new Network(RR,tptr,nwid,uptr,(const NetworkConfig *)0));
if (nw->status() == ZT_NETWORK_DISABLED) {
leave(nwid, &uptr, tptr, false);
}
return ZT_RESULT_OK;
}

ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr, bool permanent)
{
ZT_VirtualNetworkConfig ctmp;
void **nUserPtr = (void **)0;
Expand All @@ -403,12 +406,13 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
return ZT_RESULT_OK;
if (uptr)
*uptr = (*nw)->userPtr();

(*nw)->externalConfig(&ctmp);
(*nw)->destroy();
nUserPtr = (*nw)->userPtr();
}

if (nUserPtr)
if (nUserPtr && permanent)
RR->node->configureVirtualNetworkPort(tptr,nwid,nUserPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);

{
Expand All @@ -418,7 +422,8 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)

uint64_t tmp[2];
tmp[0] = nwid; tmp[1] = 0;
RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp);
if(permanent)
RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp);

return ZT_RESULT_OK;
}
Expand Down Expand Up @@ -862,7 +867,7 @@ enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tpt
enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->leave(nwid,uptr,tptr);
return reinterpret_cast<ZeroTier::Node *>(node)->leave(nwid,uptr,tptr, true);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
Expand Down
2 changes: 1 addition & 1 deletion node/Node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class Node : public NetworkController::Sender
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 leave(uint64_t nwid,void **uptr,void *tptr, bool permanent);
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);
Expand Down
62 changes: 62 additions & 0 deletions one.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ static void cliPrintHelp(const char *pn,FILE *out)
fprintf(out," listnetworks - List all networks" ZT_EOL_S);
fprintf(out," join <network ID> - Join a network" ZT_EOL_S);
fprintf(out," leave <network ID> - Leave a network" ZT_EOL_S);
fprintf(out," enable <network> - Enables a network" ZT_EOL_S);
fprintf(out," disable <network> - Disables a network" ZT_EOL_S);
fprintf(out," set <network ID> <setting> - Set a network setting" ZT_EOL_S);
fprintf(out," get <network ID> <setting> - Get a network setting" ZT_EOL_S);
fprintf(out," listmoons - List moons (federated root sets)" ZT_EOL_S);
Expand Down Expand Up @@ -858,6 +860,66 @@ static int cli(int argc,char **argv)
printf("%u %s %s" ZT_EOL_S,scode,command.c_str(),responseBody.c_str());
return 1;
}
} else if (command == "enable") {
if (arg1.length() != 16) {
printf("invalid network id" ZT_EOL_S);
return 2;
}
requestHeaders["Content-Type"] = "application/json";
requestHeaders["Content-Length"] = "2";
unsigned int scode = Http::POST(
1024 * 1024 * 16,
60000,
(const struct sockaddr*)&addr,
(std::string("/enable/") + arg1).c_str(),
requestHeaders,
"{}",
2,
responseHeaders,
responseBody);
if (scode == 200) {
if (json) {
printf("%s", cliFixJsonCRs(responseBody).c_str());
}
else {
printf("200 enable OK" ZT_EOL_S);
}
return 0;
}
else {
printf("%u %s %s" ZT_EOL_S, scode, command.c_str(), responseBody.c_str());
return 1;
}
} else if (command == "disable") {
if (arg1.length() != 16) {
printf("invalid network id" ZT_EOL_S);
return 2;
}
requestHeaders["Content-Type"] = "application/json";
requestHeaders["Content-Length"] = "2";
unsigned int scode = Http::POST(
1024 * 1024 * 16,
60000,
(const struct sockaddr*)&addr,
(std::string("/disable/") + arg1).c_str(),
requestHeaders,
"{}",
2,
responseHeaders,
responseBody);
if (scode == 200) {
if (json) {
printf("%s", cliFixJsonCRs(responseBody).c_str());
}
else {
printf("200 disable OK" ZT_EOL_S);
}
return 0;
}
else {
printf("%u %s %s" ZT_EOL_S, scode, command.c_str(), responseBody.c_str());
return 1;
}
} else if (command == "listmoons") {
const unsigned int scode = Http::GET(1024 * 1024 * 16,60000,(const struct sockaddr *)&addr,"/moon",requestHeaders,responseHeaders,responseBody);

Expand Down
141 changes: 99 additions & 42 deletions service/OneService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ static void _networkToJson(nlohmann::json &nj,const ZT_VirtualNetworkConfig *nc,
nj["allowGlobal"] = localSettings.allowGlobal;
nj["allowDefault"] = localSettings.allowDefault;
nj["allowDNS"] = localSettings.allowDNS;
nj["disabled"] = localSettings.disabled;

nlohmann::json aa = nlohmann::json::array();
for(unsigned int i=0;i<nc->assignedAddressCount;++i) {
Expand Down Expand Up @@ -532,6 +533,7 @@ class OneServiceImpl : public OneService
settings.allowGlobal = false;
settings.allowDefault = false;
settings.allowDNS = false;
settings.disabled = false;
memset(&config, 0, sizeof(ZT_VirtualNetworkConfig));
}

Expand Down Expand Up @@ -1146,22 +1148,22 @@ class OneServiceImpl : public OneService
Mutex::Lock _l(_nets_m);

std::map<uint64_t,NetworkState>::iterator n(_nets.find(nwid));
if (n == _nets.end())
return false;
n->second.settings = settings;
if (n != _nets.end())
n->second.settings = settings;

char nlcpath[4096];
OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_networksPath.c_str(),nwid);
FILE *out = fopen(nlcpath,"w");
if (out) {
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);
fprintf(out,"allowManaged=%d\n",(int)settings.allowManaged);
fprintf(out,"allowGlobal=%d\n",(int)settings.allowGlobal);
fprintf(out,"allowDefault=%d\n",(int)settings.allowDefault);
fprintf(out,"allowDNS=%d\n",(int)settings.allowDNS);
fprintf(out, "disabled=%d\n", (int)settings.disabled);
fclose(out);
}

if (n->second.tap)
if (n->second.tap && n != _nets.end())
syncManagedStuff(n->second,true,true,true);

return true;
Expand Down Expand Up @@ -1563,6 +1565,42 @@ class OneServiceImpl : public OneService
} else scode = 500;

} else scode = 404;
}
else if (ps[0] == "enable") {
if (ps.size() == 2) {
uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
NetworkSettings state;
if (loadNetworkConfig(wantnw, state)) {
state.disabled = false;
setNetworkSettings(wantnw, state);
_node->join(wantnw, (void*)0, (void*)0);
scode = 200;
} else scode = 404;
}
}
else if (ps[0] == "disable") {
if (ps.size() == 2) {
uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
ZT_VirtualNetworkList* nws = _node->networks();
if (nws) {
for (unsigned long i = 0; i < nws->networkCount; ++i) {
if (nws->networks[i].nwid == wantnw) {
OneService::NetworkSettings localSettings;
getNetworkSettings(nws->networks[i].nwid, localSettings);
localSettings.disabled = true;
setNetworkSettings(nws->networks[i].nwid, localSettings);
auto network = _node->network(wantnw);
if (network) {
nodeVirtualNetworkConfigFunction(wantnw, network->userPtr(), ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN, 0);
}
_node->leave(wantnw, (void**)0, (void*)0, false);
scode = 200;
break;
}
}
_node->freeQueryResult((void*)nws);
} else scode = 500;
}
} else {
if (_controller)
scode = _controller->handleControlPlaneHttpPOST(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
Expand All @@ -1586,7 +1624,7 @@ class OneServiceImpl : public OneService
uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
for(unsigned long i=0;i<nws->networkCount;++i) {
if (nws->networks[i].nwid == wantnw) {
_node->leave(wantnw,(void **)0,(void *)0);
_node->leave(wantnw,(void **)0,(void *)0, true);
res["result"] = true;
scode = 200;
break;
Expand Down Expand Up @@ -2367,6 +2405,50 @@ class OneServiceImpl : public OneService
inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {}

inline bool loadNetworkConfig(uint64_t nwid, NetworkSettings& s)
{
char nlcpath[256];
OSUtils::ztsnprintf(nlcpath, sizeof(nlcpath), "%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf", _homePath.c_str(), nwid);
std::string nlcbuf;
if (OSUtils::readFile(nlcpath, nlcbuf)) {
Dictionary<4096> nc;
nc.load(nlcbuf.c_str());
Buffer<1024> allowManaged;
if (nc.get("allowManaged", allowManaged) && allowManaged.size() != 0) {
std::string addresses(allowManaged.begin(), allowManaged.size());
if (allowManaged.size() <= 5) { // untidy parsing for backward compatibility
if (allowManaged[0] == '1' || allowManaged[0] == 't' || allowManaged[0] == 'T') {
s.allowManaged = true;
}
else {
s.allowManaged = false;
}
}
else {
// this should be a list of IP addresses
s.allowManaged = true;
size_t pos = 0;
while (true) {
size_t nextPos = addresses.find(',', pos);
std::string address = addresses.substr(pos, (nextPos == std::string::npos ? addresses.size() : nextPos) - pos);
s.allowManagedWhitelist.push_back(InetAddress(address.c_str()));
if (nextPos == std::string::npos) break;
pos = nextPos + 1;
}
}
}
else {
s.allowManaged = true;
}
s.allowGlobal = nc.getB("allowGlobal", false);
s.allowDefault = nc.getB("allowDefault", false);
s.allowDNS = nc.getB("allowDNS", false);
s.disabled = nc.getB("disabled", false);
return true;
}
return false;
}

inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwc)
{
Mutex::Lock _l(_nets_m);
Expand All @@ -2392,39 +2474,14 @@ class OneServiceImpl : public OneService
(void *)this);
*nuptr = (void *)&n;

char nlcpath[256];
OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid);
std::string nlcbuf;
if (OSUtils::readFile(nlcpath,nlcbuf)) {
Dictionary<4096> nc;
nc.load(nlcbuf.c_str());
Buffer<1024> allowManaged;
if (nc.get("allowManaged", allowManaged) && !allowManaged.size() == 0) {
std::string addresses (allowManaged.begin(), allowManaged.size());
if (allowManaged.size() <= 5) { // untidy parsing for backward compatibility
if (allowManaged[0] == '1' || allowManaged[0] == 't' || allowManaged[0] == 'T') {
n.settings.allowManaged = true;
} else {
n.settings.allowManaged = false;
}
} else {
// this should be a list of IP addresses
n.settings.allowManaged = true;
size_t pos = 0;
while (true) {
size_t nextPos = addresses.find(',', pos);
std::string address = addresses.substr(pos, (nextPos == std::string::npos ? addresses.size() : nextPos) - pos);
n.settings.allowManagedWhitelist.push_back(InetAddress(address.c_str()));
if (nextPos == std::string::npos) break;
pos = nextPos + 1;
}
}
} else {
n.settings.allowManaged = true;
}
n.settings.allowGlobal = nc.getB("allowGlobal", false);
n.settings.allowDefault = nc.getB("allowDefault", false);
n.settings.allowDNS = nc.getB("allowDNS", false);
loadNetworkConfig(nwid, n.settings);

if (n.settings.disabled) {
// Network is disabled, pretend init has failed and signal via return code
n.tap.reset();
_nets.erase(nwid);
// Tell network to tear down via specific error code
return -1001;
}
} catch (std::exception &exc) {
#ifdef __WINDOWS__
Expand Down
5 changes: 5 additions & 0 deletions service/OneService.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ class OneService
* Allow configuration of DNS for the network
*/
bool allowDNS;

/**
* A disabled network will not be loaded, but does still exist and can be re-enabled without destroying and re-creating network adapters on Windows
*/
bool disabled;
};

/**
Expand Down

0 comments on commit 5091b90

Please sign in to comment.