From 387039456d9dd0a3a7b20017aaa71188c63903af Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Mon, 20 Jul 2020 14:34:19 -0700 Subject: [PATCH 01/15] Pass 1 at adding DNS to controller --- controller/EmbeddedNetworkController.cpp | 44 ++++++++++++++++++ include/ZeroTierOne.h | 29 ++++++++++++ node/DNS.hpp | 59 ++++++++++++++++++++++++ node/NetworkConfig.cpp | 16 +++++++ node/NetworkConfig.hpp | 17 ++++++- 5 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 node/DNS.hpp diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index b2bd7bfb9..b6621f29a 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1029,6 +1029,30 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( } } + if (b.count("dns")) { + json &dns = b["dns"]; + if (dns.is_array()) { + json nda = json::array(); + for(unsigned int i=0;idnsCount = 0; + for(unsigned int p=0; p < dns.size(); ++p) { + json &d = dns[p]; + if (d.is_object()) { + std::string domain = OSUtils::jsonString(d["domain"],""); + memcpy(nc->dns[nc->dnsCount].domain, domain.c_str(), domain.size()); + json &addrArray = d["servers"]; + if (addrArray.is_array()) { + for(unsigned int j = 0; j < addrArray.size() && j < ZT_MAX_DNS_SERVERS; ++j) { + json &addr = addrArray[j]; + nc->dns[nc->dnsCount].server_addr[j] = InetAddress(OSUtils::jsonString(addr,"").c_str()); + } + } + ++nc->dnsCount; + } + } + } // Issue a certificate of ownership for all static IPs if (nc->staticIpCount) { diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index c93b4dbf8..8ff9ba2f4 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -125,6 +125,11 @@ extern "C" { */ #define ZT_MAX_NETWORK_ROUTES 32 +/** + * Maximum number of pushed DNS configurations on a network + */ +#define ZT_MAX_NETWORK_DNS 32 + /** * Maximum number of statically assigned IP addresses per network endpoint using ZT address management (not DHCP) */ @@ -195,6 +200,11 @@ extern "C" { */ #define ZT_PATH_LINK_QUALITY_MAX 0xff +/** + * Maximum number of DNS servers per domain + */ +#define ZT_MAX_DNS_SERVERS 4 + /** * Packet characteristics flag: packet direction, 1 if inbound 0 if outbound */ @@ -984,6 +994,15 @@ typedef struct uint16_t metric; } ZT_VirtualNetworkRoute; +/** + * DNS configuration to be pushed on a virtual network + */ +typedef struct +{ + char domain[128]; + struct sockaddr_storage server_addr[ZT_MAX_DNS_SERVERS]; +} ZT_VirtualNetworkDNS; + /** * An Ethernet multicast group */ @@ -1198,6 +1217,16 @@ typedef struct uint64_t mac; /* MAC in lower 48 bits */ uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */ } multicastSubscriptions[ZT_MAX_MULTICAST_SUBSCRIPTIONS]; + + /** + * Number of ZT-pushed DNS configuraitons + */ + unsigned int dnsCount; + + /** + * Network specific DNS configuration + */ + ZT_VirtualNetworkDNS dns[ZT_MAX_NETWORK_DNS]; } ZT_VirtualNetworkConfig; /** diff --git a/node/DNS.hpp b/node/DNS.hpp new file mode 100644 index 000000000..ff685d32d --- /dev/null +++ b/node/DNS.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c)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 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +#ifndef ZT_DNS_HPP +#define ZT_DNS_HPP +#include +#include +#include + +#include "Buffer.hpp" +#include "InetAddress.hpp" +#include "../include/ZeroTierOne.h" + +namespace ZeroTier { + +/** + * DNS data serealization methods + */ +class DNS { +public: + template + static inline void serializeDNS(Buffer &b, const ZT_VirtualNetworkDNS *dns, unsigned int dnsCount) + { + for(unsigned int i = 0; i < dnsCount; ++i) { + b.append(dns[i].domain, 128); + for(unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { + InetAddress tmp(dns[i].server_addr[j]); + tmp.serialize(b); + } + } + } + + template + static inline void deserializeDNS(const Buffer &b, unsigned int &p, ZT_VirtualNetworkDNS *dns, const unsigned int dnsCount) + { + for(unsigned int i = 0; i < dnsCount; ++i) { + char *d = (char*)b.data()+p; + memcpy(dns[i].domain, d, 128); + p += 128; + for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { + p += reinterpret_cast(&(dns[i].server_addr[j]))->deserialize(b, p); + } + } + } +}; + +} + +#endif // ZT_DNS_HPP diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 97985c7af..503d7400a 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -176,6 +176,15 @@ bool NetworkConfig::toDictionary(Dictionary &d,b } } + tmp->clear(); + if (dnsCount > 0) { + tmp->append(dnsCount); + DNS::serializeDNS(*tmp, dns, dnsCount); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) return false; + } + } + delete tmp; } catch ( ... ) { delete tmp; @@ -354,6 +363,13 @@ bool NetworkConfig::fromDictionary(const Dictionaryrules,this->ruleCount,ZT_MAX_NETWORK_RULES); } + + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) { + unsigned int p = 0; + this->dnsCount = tmp->at(p); + p += sizeof(unsigned int); + DNS::deserializeDNS(*tmp, p, dns, (this->dnsCount <= ZT_MAX_NETWORK_DNS) ? this->dnsCount : ZT_MAX_NETWORK_DNS); + } } //printf("~~~\n%s\n~~~\n",d.data()); diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 8311a0743..1daf98d01 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -26,6 +26,7 @@ #include "Constants.hpp" #include "Buffer.hpp" +#include "DNS.hpp" #include "InetAddress.hpp" #include "MulticastGroup.hpp" #include "Address.hpp" @@ -175,6 +176,8 @@ namespace ZeroTier { #define ZT_NETWORKCONFIG_DICT_KEY_TAGS "TAG" // tags (binary blobs) #define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP "COO" +// dns (binary blobs) +#define ZT_NETWORKCONFIG_DICT_KEY_DNS "DNS" // Legacy fields -- these are obsoleted but are included when older clients query @@ -229,13 +232,15 @@ public: capabilities(), tags(), certificatesOfOwnership(), - type(ZT_NETWORK_TYPE_PRIVATE) + type(ZT_NETWORK_TYPE_PRIVATE), + dnsCount(0) { 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(dns, 0, sizeof(ZT_VirtualNetworkDNS)*ZT_MAX_NETWORK_DNS); } /** @@ -589,6 +594,16 @@ public: * Certificate of membership (for private networks) */ CertificateOfMembership com; + + /** + * Number of ZT-pushed DNS configurations + */ + unsigned int dnsCount; + + /** + * ZT pushed DNS configuration + */ + ZT_VirtualNetworkDNS dns[ZT_MAX_NETWORK_DNS]; }; } // namespace ZeroTier From d098a99d098851f515dd536ed08baad06e484d63 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Fri, 31 Jul 2020 11:42:03 -0700 Subject: [PATCH 02/15] fix memory init issue and another place where dns data needs to be copied --- .gitignore | 1 + node/DNS.hpp | 1 + node/Network.cpp | 6 ++++++ osdep/EthernetTap.hpp | 1 + osdep/MacEthernetTap.cpp | 5 +++++ osdep/MacEthernetTap.hpp | 1 + osdep/MacKextEthernetTap.cpp | 5 +++++ osdep/MacKextEthernetTap.hpp | 2 ++ service/OneService.cpp | 29 +++++++++++++++++++++++++---- 9 files changed, 47 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 62a6c6a17..584bdb6c1 100755 --- a/.gitignore +++ b/.gitignore @@ -121,3 +121,4 @@ __pycache__ attic/world/*.c25519 attic/world/mkworld workspace/ +workspace2/ diff --git a/node/DNS.hpp b/node/DNS.hpp index ff685d32d..a770859d8 100644 --- a/node/DNS.hpp +++ b/node/DNS.hpp @@ -43,6 +43,7 @@ public: template static inline void deserializeDNS(const Buffer &b, unsigned int &p, ZT_VirtualNetworkDNS *dns, const unsigned int dnsCount) { + memset(dns, 0, sizeof(ZT_VirtualNetworkDNS)*ZT_MAX_NETWORK_DNS); for(unsigned int i = 0; i < dnsCount; ++i) { char *d = (char*)b.data()+p; memcpy(dns[i].domain, d, 128); diff --git a/node/Network.cpp b/node/Network.cpp index cfdbb3764..76b322af6 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -586,6 +586,7 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u if (!_portInitialized) { ZT_VirtualNetworkConfig ctmp; + memset(&ctmp, 0, sizeof(ZT_VirtualNetworkConfig)); _externalConfig(&ctmp); _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); _portInitialized = true; @@ -1426,6 +1427,11 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const ec->multicastSubscriptions[i].mac = _myMulticastGroups[i].mac().toInt(); ec->multicastSubscriptions[i].adi = _myMulticastGroups[i].adi(); } + + ec->dnsCount = _config.dnsCount; + if (ec->dnsCount > 0) { + memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS)); + } } void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) diff --git a/osdep/EthernetTap.hpp b/osdep/EthernetTap.hpp index db52e6b43..d8de16886 100644 --- a/osdep/EthernetTap.hpp +++ b/osdep/EthernetTap.hpp @@ -53,6 +53,7 @@ public: virtual void setFriendlyName(const char *friendlyName) = 0; virtual void scanMulticastGroups(std::vector &added,std::vector &removed) = 0; virtual void setMtu(unsigned int mtu) = 0; + virtual void setDns(const char *domain, const std::vector &servers) = 0; }; } // namespace ZeroTier diff --git a/osdep/MacEthernetTap.cpp b/osdep/MacEthernetTap.cpp index 028f85568..3db0b3ff7 100644 --- a/osdep/MacEthernetTap.cpp +++ b/osdep/MacEthernetTap.cpp @@ -452,6 +452,11 @@ void MacEthernetTap::threadMain() } } +void MacEthernetTap::setDns(const char *domain, const std::vector &servers) +{ + +} + } // namespace ZeroTier #endif // __APPLE__ diff --git a/osdep/MacEthernetTap.hpp b/osdep/MacEthernetTap.hpp index 6d5ce8941..7945bb408 100644 --- a/osdep/MacEthernetTap.hpp +++ b/osdep/MacEthernetTap.hpp @@ -56,6 +56,7 @@ public: virtual void setFriendlyName(const char *friendlyName); virtual void scanMulticastGroups(std::vector &added,std::vector &removed); virtual void setMtu(unsigned int mtu); + virtual void setDns(const char *domain, const std::vector &servers); void threadMain() throw(); diff --git a/osdep/MacKextEthernetTap.cpp b/osdep/MacKextEthernetTap.cpp index 2325d5943..a04c2ac9b 100644 --- a/osdep/MacKextEthernetTap.cpp +++ b/osdep/MacKextEthernetTap.cpp @@ -687,4 +687,9 @@ void MacKextEthernetTap::threadMain() } } +void MacKextEthernetTap::setDns(const char *domain, const std::vector &servers) +{ + +} + } // namespace ZeroTier diff --git a/osdep/MacKextEthernetTap.hpp b/osdep/MacKextEthernetTap.hpp index f1a6f36fd..d7ea53028 100644 --- a/osdep/MacKextEthernetTap.hpp +++ b/osdep/MacKextEthernetTap.hpp @@ -56,6 +56,8 @@ public: virtual void setFriendlyName(const char *friendlyName); virtual void scanMulticastGroups(std::vector &added,std::vector &removed); virtual void setMtu(unsigned int mtu); + virtual void setDns(const char *domain, const std::vector &servers); + void threadMain() throw(); diff --git a/service/OneService.cpp b/service/OneService.cpp index c5d8076d4..ff8c37c95 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -501,6 +501,7 @@ public: settings.allowManaged = true; settings.allowGlobal = false; settings.allowDefault = false; + memset(&config, 0, sizeof(ZT_VirtualNetworkConfig)); } std::shared_ptr tap; @@ -831,7 +832,7 @@ public: Mutex::Lock _l(_nets_m); for(std::map::iterator n(_nets.begin());n!=_nets.end();++n) { if (n->second.tap) - syncManagedStuff(n->second,false,true); + syncManagedStuff(n->second,false,true,false); } } } @@ -1117,7 +1118,7 @@ public: } if (n->second.tap) - syncManagedStuff(n->second,true,true); + syncManagedStuff(n->second,true,true,true); return true; } @@ -1864,7 +1865,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]; @@ -1984,6 +1985,26 @@ public: #endif } } + + if (syncDns) { + char buf[128]; + if (n.config.dnsCount > ZT_MAX_NETWORK_DNS) { + fprintf(stderr, "ERROR: %d records > max %d. Skipping DNS\n", n.config.dnsCount, ZT_MAX_NETWORK_DNS); + return; + } + fprintf(stderr, "Syncing %d DNS configurations\n", n.config.dnsCount); + for (int i = 0; i < n.config.dnsCount; ++i) { + if (strlen(n.config.dns[i].domain) != 0) { + fprintf(stderr, "Syncing DNS for domain: %s\n", n.config.dns[i].domain); + for (int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { + InetAddress a(n.config.dns[i].server_addr[j]); + if (a.isV4() || a.isV6()) { + fprintf(stderr, "\t Server %d: %s\n", j+1, a.toIpString(buf)); + } + } + } + } + } } // ========================================================================= @@ -2333,7 +2354,7 @@ public: Sleep(10); } #endif - syncManagedStuff(n,true,true); + syncManagedStuff(n,true,true,true); n.tap->setMtu(nwc->mtu); } else { _nets.erase(nwid); From 2e52a1eebfc26321ca1e6473384e5ef8e74ab3fc Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 4 Aug 2020 09:45:45 -0700 Subject: [PATCH 03/15] forgot a couple queries in postgres. trying to pull dns of member not network in embedded network controller also some debug logging --- controller/EmbeddedNetworkController.cpp | 6 +- controller/PostgreSQL.cpp | 101 +++++++++++++++++++++++ service/OneService.cpp | 2 +- 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index b6621f29a..f37e4f776 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1416,7 +1416,9 @@ void EmbeddedNetworkController::_request( json &tags = network["tags"]; json &memberCapabilities = member["capabilities"]; json &memberTags = member["tags"]; - json &dns = member["dns"]; + json &dns = network["dns"]; + + fprintf(stderr, "DNS Config for Network ID %.16llx: %s\n", nwid, OSUtils::jsonDump(dns, 2).c_str()); if (metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,0) <= 0) { // Old versions with no rules engine support get an allow everything rule. @@ -1727,6 +1729,8 @@ void EmbeddedNetworkController::_request( ++nc->dnsCount; } } + } else { + dns = json::array(); } // Issue a certificate of ownership for all static IPs diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index 0f5fde77b..b8e01e200 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -430,6 +430,46 @@ void PostgreSQL::initializeNetworks(PGconn *conn) config["routes"].push_back(route); } + r2 = PQexecParams(conn, + "SELECT domain, servers FROM ztc_network_dns WHERE network_id = $1", + 1, + NULL, + nwidparam, + NULL, + NULL, + 0); + + if (PQresultStatus(r2) != PGRES_TUPLES_OK) { + fprintf(stderr, "ERROR: Error retrieving DNS settings for network: %s\n", PQresultErrorMessage(r2)); + PQclear(r2); + PQclear(res); + exit(1); + } + + n = PQntuples(r2); + config["dns"] = json::array(); + for (int j = 0; j < n; ++j) { + + json obj; + std::string domain = PQgetvalue(r2, j, 0); + std::string serverList = PQgetvalue(r2, j, 1); + auto servers = json::array(); + if (serverList.rfind("{",0) != std::string::npos) { + serverList = serverList.substr(1, serverList.size()-2); + fprintf(stderr, "Server List: %s\n", serverList.c_str()); + std::stringstream ss(serverList); + while(ss.good()) { + std::string server; + std::getline(ss, server, ','); + servers.push_back(server); + } + } + obj["domain"] = domain; + obj["servers"] = servers; + config["dns"].push_back(obj); + } + fprintf(stderr, "%s\n", OSUtils::jsonDump(config["dns"], 2).c_str()); + PQclear(r2); _networkChanged(empty, config, false); @@ -1424,6 +1464,67 @@ void PostgreSQL::commitThread() continue; } + + res = PQexecParams(conn, + "DELETE FROM ztc_network_dns WHERE network_id = $1", + 1, + NULL, + params, + NULL, + NULL, + 0); + + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating dns: %s\n", PQresultErrorMessage(res)); + PQclear(res); + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + + auto dns = (*config)["dns"]; + err = false; + for (auto i = dns.begin(); i < dns.end(); ++i) { + std::string domain = (*i)["domain"]; + std::stringstream servers; + servers << "{"; + for (auto j = dns["servers"].begin(); j < dns["servers"].end(); ++j) { + servers << *j; + if ( (j+1) != dns["servers"].end()) { + servers << ","; + } + } + servers << "}"; + + const char *p[3] = { + id.c_str(), + domain.c_str(), + servers.str().c_str() + }; + + res = PQexecParams(conn, "INSERT INTO ztc_network_dns (network_id, domain, servers) VALUES ($1, $2, $3)", + 3, + NULL, + p, + NULL, + NULL, + 0); + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr, "ERROR: Error updating DNS: %s\n", PQresultErrorMessage(res)); + PQclear(res); + err = true; + break; + } + PQclear(res); + } + if (err) { + PQclear(PQexec(conn, "ROLLBACK")); + delete config; + config = nullptr; + continue; + } + res = PQexec(conn, "COMMIT"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "ERROR: Error committing network update: %s\n", PQresultErrorMessage(res)); diff --git a/service/OneService.cpp b/service/OneService.cpp index ff8c37c95..d9239a16c 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1992,7 +1992,7 @@ public: fprintf(stderr, "ERROR: %d records > max %d. Skipping DNS\n", n.config.dnsCount, ZT_MAX_NETWORK_DNS); return; } - fprintf(stderr, "Syncing %d DNS configurations\n", n.config.dnsCount); + fprintf(stderr, "Syncing %d DNS configurations for network [%.16llx]\n", n.config.dnsCount, n.config.nwid); for (int i = 0; i < n.config.dnsCount; ++i) { if (strlen(n.config.dns[i].domain) != 0) { fprintf(stderr, "Syncing DNS for domain: %s\n", n.config.dns[i].domain); From 88a3c685fb5a4e756a1d6e280a5780c56c810a93 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 4 Aug 2020 13:52:57 -0700 Subject: [PATCH 04/15] latest --- controller/DB.cpp | 7 +++++++ controller/EmbeddedNetworkController.cpp | 4 ++++ node/Network.cpp | 1 + service/OneService.cpp | 15 +++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/controller/DB.cpp b/controller/DB.cpp index dfa4fa094..a1a72f408 100644 --- a/controller/DB.cpp +++ b/controller/DB.cpp @@ -48,6 +48,8 @@ void DB::initNetwork(nlohmann::json &network) { "type","ACTION_ACCEPT" } }}; } + if (!network.count("dns")) network["dns"] = nlohmann::json::array(); + network["objtype"] = "network"; } @@ -110,6 +112,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network) std::lock_guard l2(nw->lock); network = nw->config; } + fprintf(stderr, "DB::get(uint64_t,json): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -132,6 +135,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem return false; member = m->second; } + fprintf(stderr, "DB::get(uint64_t,json,uint64_t,mjson): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -155,6 +159,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem return false; member = m->second; } + fprintf(stderr, "DB::get(uint64_t,json,uint64_t,mjson,summary): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -175,6 +180,7 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vectormembers.begin();m!=nw->members.end();++m) members.push_back(m->second); } + fprintf(stderr, "DB::get(uint64_t,json,members): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -305,6 +311,7 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool { if (networkConfig.is_object()) { const std::string ids = networkConfig["id"]; + fprintf(stderr, "DB::_networkChanged(): %s\n", OSUtils::jsonDump(networkConfig["dns"]).c_str()); const uint64_t networkId = Utils::hexStrToU64(ids.c_str()); if (networkId) { std::shared_ptr<_Network> nw; diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index f37e4f776..b525895bd 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1390,6 +1390,7 @@ void EmbeddedNetworkController::_request( nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); + std::string rtt(OSUtils::jsonString(member["remoteTraceTarget"],"")); if (rtt.length() == 10) { nc->remoteTraceTarget = Address(Utils::hexStrToU64(rtt.c_str())); @@ -1713,9 +1714,11 @@ void EmbeddedNetworkController::_request( } if(dns.is_array()) { + fprintf(stderr, "dns is array of size %d\n", dns.size()); nc->dnsCount = 0; for(unsigned int p=0; p < dns.size(); ++p) { json &d = dns[p]; + fprintf(stderr, "%s\n", OSUtils::jsonDump(d, 2).c_str()); if (d.is_object()) { std::string domain = OSUtils::jsonString(d["domain"],""); memcpy(nc->dns[nc->dnsCount].domain, domain.c_str(), domain.size()); @@ -1730,6 +1733,7 @@ void EmbeddedNetworkController::_request( } } } else { + fprintf(stderr, "dns is NOT an array\n"); dns = json::array(); } diff --git a/node/Network.cpp b/node/Network.cpp index 76b322af6..97642fa18 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1429,6 +1429,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } ec->dnsCount = _config.dnsCount; + fprintf(stderr, "Network::_externalConfig dnsCount: %d\n", ec->dnsCount); if (ec->dnsCount > 0) { memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS)); } diff --git a/service/OneService.cpp b/service/OneService.cpp index d9239a16c..f48e90640 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -231,6 +231,21 @@ static void _networkToJson(nlohmann::json &nj,const ZT_VirtualNetworkConfig *nc, mca.push_back(m); } nj["multicastSubscriptions"] = mca; + + nj["dns"] = nlohmann::json::array(); + for(unsigned int i=0;idnsCount;++i) { + nlohmann::json m; + m["domain"] = nc->dns[i].domain; + m["servers"] = nlohmann::json::array(); + for(int j=0;jdns[i].server_addr[j]); + if (a.isV4() || a.isV6()) { + char buf[256]; + m["servers"].push_back(a.toIpString(buf)); + } + } + } } static void _peerToJson(nlohmann::json &pj,const ZT_Peer *peer) From d2708daa8eb3d37cffb553a38d4c616db618a7ee Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 4 Aug 2020 14:33:18 -0700 Subject: [PATCH 05/15] debug output --- controller/PostgreSQL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index b8e01e200..8463c13a8 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -468,7 +468,7 @@ void PostgreSQL::initializeNetworks(PGconn *conn) obj["servers"] = servers; config["dns"].push_back(obj); } - fprintf(stderr, "%s\n", OSUtils::jsonDump(config["dns"], 2).c_str()); + fprintf(stderr, "%s: %s\n", OSUtils::jsonString(config["nwid"], "").c_str(), OSUtils::jsonDump(config["dns"], 2).c_str()); PQclear(r2); From 302ac8fefe67284bcdcc81c50fe3ed2419e96b78 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 5 Aug 2020 14:26:11 -0700 Subject: [PATCH 06/15] DNS config support on macOS --- make-mac.mk | 8 +++-- osdep/MacDNSHelper.hpp | 20 +++++++++++ osdep/MacDNSHelper.mm | 72 ++++++++++++++++++++++++++++++++++++++++ osdep/MacEthernetTap.cpp | 62 ++++++++++++++++++++++++++++++++++ osdep/MacEthernetTap.hpp | 3 ++ service/OneService.cpp | 3 ++ 6 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 osdep/MacDNSHelper.hpp create mode 100644 osdep/MacDNSHelper.mm diff --git a/make-mac.mk b/make-mac.mk index ada65ff77..acf17dd42 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -25,10 +25,10 @@ TIMESTAMP=$(shell date +"%Y%m%d%H%M") DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE) include objects.mk -ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o ext/http-parser/http_parser.o +ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o osdep/MacDNSHelper.o ext/http-parser/http_parser.o ifeq ($(ZT_CONTROLLER),1) - LIBS+=-L/usr/local/opt/libpq/lib -lpq ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a + LIBS+=-L/usr/local/opt/libpq/lib -lpq ext/redis-plus-plus-1.1.1/install/macos/lib/libredis++.a ext/hiredis-0.14.1/lib/macos/libhiredis.a -framework SystemConfiguration -framework CoreFoundation DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER_USE_REDIS -DZT_CONTROLLER INCLUDES+=-I/usr/local/opt/libpq/include -Iext/hiredis-0.14.1/include/ -Iext/redis-plus-plus-1.1.1/install/macos/include/sw/ @@ -97,7 +97,11 @@ mac-agent: FORCE $(CC) -Ofast -o MacEthernetTapAgent osdep/MacEthernetTapAgent.c $(CODESIGN) -f -s $(CODESIGN_APP_CERT) MacEthernetTapAgent +osdep/MacDNSHelper.o: osdep/MacDNSHelper.mm + $(CXX) $(CXXFLAGS) -c osdep/MacDNSHelper.mm -o osdep/MacDNSHelper.o + one: $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent + $(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) # $(STRIP) zerotier-one ln -sf zerotier-one zerotier-idtool diff --git a/osdep/MacDNSHelper.hpp b/osdep/MacDNSHelper.hpp new file mode 100644 index 000000000..de45a8507 --- /dev/null +++ b/osdep/MacDNSHelper.hpp @@ -0,0 +1,20 @@ +#ifndef MAC_DNS_HELPER +#define MAC_DNS_HELPER + +#include +#include "../node/InetAddress.hpp" + +namespace ZeroTier { + +class MacDNSHelper +{ +public: + static void doTheThing(); + + static void setDNS(uint64_t nwid, const char *domain, const std::vector &servers); + static void removeDNS(uint64_t nwid); +}; + +} + +#endif diff --git a/osdep/MacDNSHelper.mm b/osdep/MacDNSHelper.mm new file mode 100644 index 000000000..75b5fd560 --- /dev/null +++ b/osdep/MacDNSHelper.mm @@ -0,0 +1,72 @@ +#include "MacDNSHelper.hpp" + +#include + +#include + +namespace ZeroTier { + +void MacDNSHelper::doTheThing() +{ + fprintf(stderr, "\n\nDOING THE THING!!\n\n"); +} + +void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vector &servers) +{ + SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL); + + CFStringRef *s = new CFStringRef[4]; + for (unsigned int i = 0; i < servers.size(); ++i) { + char buf[64]; + ZeroTier::InetAddress a = servers[i]; + const char *ipStr = a.toIpString(buf); + s[i] = CFStringCreateWithCString(NULL, ipStr, kCFStringEncodingUTF8); + } + + CFArrayRef serverArray = CFArrayCreate(NULL, (const void**)s, servers.size(), &kCFTypeArrayCallBacks); + + CFStringRef keys[2]; + keys[0] = CFSTR("SupplementalMatchDomains"); + keys[1] = CFSTR("ServerAddresses"); + + CFStringRef cfdomain = CFStringCreateWithCString(NULL, domain, kCFStringEncodingUTF8); + CFArrayRef domainArray = CFArrayCreate(NULL, (const void**)&cfdomain, 1, &kCFTypeArrayCallBacks); + + CFTypeRef values[2]; + values[0] = domainArray; + values[1] = serverArray; + + CFDictionaryRef dict = CFDictionaryCreate(NULL, + (const void**)keys, (const void**)values, 2, &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFShow(dict); + + char buf[256] = {0}; + sprintf(buf, "State:/Network/Service/%.16llx/DNS", nwid); + CFStringRef key = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); + CFArrayRef list = SCDynamicStoreCopyKeyList(ds, key); + + CFIndex i = 0, j = CFArrayGetCount(list); + bool ret = TRUE; + if (j <= 0) { + fprintf(stderr, "Key '%s' does not exist. Creating.\n", buf); + ret &= SCDynamicStoreAddValue(ds, key, dict); + } else { + fprintf(stderr, "Key '%s' already exists. Updating DNS config.\n", buf); + ret &= SCDynamicStoreSetValue(ds, (CFStringRef)CFArrayGetValueAtIndex(list, i), dict); + } + if (ret) { + fprintf(stderr, "DNS written successfully\n"); + } else { + fprintf(stderr, "Error writing DNS configuration\n"); + } + + delete[] s; +} + +void MacDNSHelper::removeDNS(uint64_t nwid) +{ + +} + +} \ No newline at end of file diff --git a/osdep/MacEthernetTap.cpp b/osdep/MacEthernetTap.cpp index 3db0b3ff7..a48de6758 100644 --- a/osdep/MacEthernetTap.cpp +++ b/osdep/MacEthernetTap.cpp @@ -21,6 +21,7 @@ #include "OSUtils.hpp" #include "MacEthernetTap.hpp" #include "MacEthernetTapAgent.h" +#include "MacDNSHelper.hpp" #include #include @@ -54,6 +55,7 @@ #include #include #include +#include static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); @@ -454,7 +456,67 @@ void MacEthernetTap::threadMain() void MacEthernetTap::setDns(const char *domain, const std::vector &servers) { + MacDNSHelper::doTheThing(); + MacDNSHelper::setDNS(this->_nwid, domain, servers); + // _removeDnsConfig(domain, servers); + // _addDnsConfig(domain, servers); +} +void MacEthernetTap::_removeDnsConfig(const char *domain, const std::vector &servers) +{ + std::string tmpfile = std::tmpnam(nullptr); + std::FILE *remf = std::fopen(tmpfile.c_str(), "w"); + char buf[4096] = {0}; + sprintf(buf, "remove State:/Network/Service/%.16llx/DNS\n", _nwid); + std::fputs(buf, remf); + std::fflush(remf); + std::fclose(remf); + fprintf(stderr, "wrote tmpfile %s\n", tmpfile.c_str()); + long cpid = (long)vfork(); + if (cpid == 0) { + char cmd[1024] = {0}; + sprintf(cmd, "/usr/sbin/scutil < %s", tmpfile.c_str()); + ::execl("/bin/sh", "-c", cmd); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode,0); + if (exitcode) { + throw std::runtime_error("scutil dns config remove error"); + } + } +} + +void MacEthernetTap::_addDnsConfig(const char *domain, const std::vector &servers) +{ + std::string tmpfile = std::tmpnam(nullptr); + std::FILE *addf = std::fopen(tmpfile.c_str(), "w"); + char buf[4096] = {0}; + sprintf(buf, "d.init\n"); + sprintf(buf, "d.add ServerAddresses *"); + for (auto it = servers.begin(); it != servers.end(); ++it) { + char ipbuf[128] = {0}; + sprintf(buf, " %s", it->toIpString(buf)); + } + sprintf(buf, "\n"); + sprintf(buf, "d.add SupplementalMatchDomains * %s\n", domain); + sprintf(buf, "set State:/Network/Service/%.16llx/DNS", _nwid); + std::fputs(buf, addf); + std::fflush(addf); + std::fclose(addf); + fprintf(stderr, "wrote add tmpfile %s\n", tmpfile.c_str()); + long cpid = (long)vfork(); + if (cpid == 0) { + char cmd[1024]; + sprintf(cmd, "'/usr/bin/scutil < %s'", tmpfile.c_str()); + fprintf(stderr, "%s\n", cmd); + ::execl("/bin/sh", "-c", cmd); + } else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + if (exitcode) { + throw std::runtime_error("scutil dns config add error"); + } + } } } // namespace ZeroTier diff --git a/osdep/MacEthernetTap.hpp b/osdep/MacEthernetTap.hpp index 7945bb408..9ffbdee56 100644 --- a/osdep/MacEthernetTap.hpp +++ b/osdep/MacEthernetTap.hpp @@ -62,6 +62,9 @@ public: throw(); private: + void _removeDnsConfig(const char *domain, const std::vector &servers); + void _addDnsConfig(const char *domain, const std::vector &servers); + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; diff --git a/service/OneService.cpp b/service/OneService.cpp index f48e90640..8b09d236a 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2011,12 +2011,15 @@ public: for (int i = 0; i < n.config.dnsCount; ++i) { if (strlen(n.config.dns[i].domain) != 0) { fprintf(stderr, "Syncing DNS for domain: %s\n", n.config.dns[i].domain); + std::vector servers; for (int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { InetAddress a(n.config.dns[i].server_addr[j]); if (a.isV4() || a.isV6()) { fprintf(stderr, "\t Server %d: %s\n", j+1, a.toIpString(buf)); + servers.push_back(a); } } + n.tap->setDns(n.config.dns[i].domain, servers); } } } From d6e3164ea10a98a6d65eaac1ef7f1faf142fde37 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 5 Aug 2020 14:42:09 -0700 Subject: [PATCH 07/15] remove initial attempt at dns config via scutil --- osdep/MacEthernetTap.cpp | 59 ---------------------------------------- osdep/MacEthernetTap.hpp | 3 -- 2 files changed, 62 deletions(-) diff --git a/osdep/MacEthernetTap.cpp b/osdep/MacEthernetTap.cpp index a48de6758..fb49bad61 100644 --- a/osdep/MacEthernetTap.cpp +++ b/osdep/MacEthernetTap.cpp @@ -458,65 +458,6 @@ void MacEthernetTap::setDns(const char *domain, const std::vector & { MacDNSHelper::doTheThing(); MacDNSHelper::setDNS(this->_nwid, domain, servers); - // _removeDnsConfig(domain, servers); - // _addDnsConfig(domain, servers); -} - -void MacEthernetTap::_removeDnsConfig(const char *domain, const std::vector &servers) -{ - std::string tmpfile = std::tmpnam(nullptr); - std::FILE *remf = std::fopen(tmpfile.c_str(), "w"); - char buf[4096] = {0}; - sprintf(buf, "remove State:/Network/Service/%.16llx/DNS\n", _nwid); - std::fputs(buf, remf); - std::fflush(remf); - std::fclose(remf); - fprintf(stderr, "wrote tmpfile %s\n", tmpfile.c_str()); - long cpid = (long)vfork(); - if (cpid == 0) { - char cmd[1024] = {0}; - sprintf(cmd, "/usr/sbin/scutil < %s", tmpfile.c_str()); - ::execl("/bin/sh", "-c", cmd); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid, &exitcode,0); - if (exitcode) { - throw std::runtime_error("scutil dns config remove error"); - } - } -} - -void MacEthernetTap::_addDnsConfig(const char *domain, const std::vector &servers) -{ - std::string tmpfile = std::tmpnam(nullptr); - std::FILE *addf = std::fopen(tmpfile.c_str(), "w"); - char buf[4096] = {0}; - sprintf(buf, "d.init\n"); - sprintf(buf, "d.add ServerAddresses *"); - for (auto it = servers.begin(); it != servers.end(); ++it) { - char ipbuf[128] = {0}; - sprintf(buf, " %s", it->toIpString(buf)); - } - sprintf(buf, "\n"); - sprintf(buf, "d.add SupplementalMatchDomains * %s\n", domain); - sprintf(buf, "set State:/Network/Service/%.16llx/DNS", _nwid); - std::fputs(buf, addf); - std::fflush(addf); - std::fclose(addf); - fprintf(stderr, "wrote add tmpfile %s\n", tmpfile.c_str()); - long cpid = (long)vfork(); - if (cpid == 0) { - char cmd[1024]; - sprintf(cmd, "'/usr/bin/scutil < %s'", tmpfile.c_str()); - fprintf(stderr, "%s\n", cmd); - ::execl("/bin/sh", "-c", cmd); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid, &exitcode, 0); - if (exitcode) { - throw std::runtime_error("scutil dns config add error"); - } - } } } // namespace ZeroTier diff --git a/osdep/MacEthernetTap.hpp b/osdep/MacEthernetTap.hpp index 9ffbdee56..7945bb408 100644 --- a/osdep/MacEthernetTap.hpp +++ b/osdep/MacEthernetTap.hpp @@ -62,9 +62,6 @@ public: throw(); private: - void _removeDnsConfig(const char *domain, const std::vector &servers); - void _addDnsConfig(const char *domain, const std::vector &servers); - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); void *_arg; uint64_t _nwid; From b9a1719cb175a1d9fa4225ed799ff3b28c038c16 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 5 Aug 2020 14:42:19 -0700 Subject: [PATCH 08/15] Let's make sure to clean up our memory --- osdep/MacDNSHelper.mm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osdep/MacDNSHelper.mm b/osdep/MacDNSHelper.mm index 75b5fd560..b5fc28f07 100644 --- a/osdep/MacDNSHelper.mm +++ b/osdep/MacDNSHelper.mm @@ -61,12 +61,29 @@ void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vector Date: Wed, 5 Aug 2020 14:49:45 -0700 Subject: [PATCH 09/15] Remove dns config on shutdown Also add calls to MacDNSHelper to the kext tap --- osdep/MacEthernetTap.cpp | 2 ++ osdep/MacKextEthernetTap.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osdep/MacEthernetTap.cpp b/osdep/MacEthernetTap.cpp index fb49bad61..ae07e66a3 100644 --- a/osdep/MacEthernetTap.cpp +++ b/osdep/MacEthernetTap.cpp @@ -202,6 +202,8 @@ MacEthernetTap::MacEthernetTap( MacEthernetTap::~MacEthernetTap() { + MacDNSHelper::removeDNS(_nwid); + Mutex::Lock _gl(globalTapCreateLock); ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit Thread::join(_thread); diff --git a/osdep/MacKextEthernetTap.cpp b/osdep/MacKextEthernetTap.cpp index a04c2ac9b..ea26b53c1 100644 --- a/osdep/MacKextEthernetTap.cpp +++ b/osdep/MacKextEthernetTap.cpp @@ -43,6 +43,8 @@ #include #include +#include "MacDNSHelper.hpp" + // OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!? struct prf_ra { u_char onlink : 1; @@ -441,6 +443,8 @@ MacKextEthernetTap::MacKextEthernetTap( MacKextEthernetTap::~MacKextEthernetTap() { + MacDNSHelper::removeDNS(_nwid); + ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit Thread::join(_thread); @@ -689,7 +693,7 @@ void MacKextEthernetTap::threadMain() void MacKextEthernetTap::setDns(const char *domain, const std::vector &servers) { - + MacDNSHelper::setDNS(_nwid, domain, servers); } } // namespace ZeroTier From 6868e98904803a060e6a09f0bcecdc42f64ae9aa Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 5 Aug 2020 16:04:02 -0700 Subject: [PATCH 10/15] Get stuff building on Windows Been a minute since any of this has been updated --- controller/EmbeddedNetworkController.cpp | 2 +- osdep/WindowsEthernetTap.cpp | 5 +++++ osdep/WindowsEthernetTap.hpp | 1 + windows/ZeroTierOne/ZeroTierOne.vcxproj | 7 +++++-- .../ZeroTierOne/ZeroTierOne.vcxproj.filters | 18 ++++++++++++------ 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index b525895bd..ad1db6244 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -585,7 +585,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( responseBody.reserve((members.size() + 2) * 32); std::string mid; for(auto member=members.begin();member!=members.end();++member) { - mid = (*member)["id"]; + mid = OSUtils::jsonString((*member)["id"], ""); char tmp[128]; OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s\"%s\":%llu",(responseBody.length() > 1) ? "," : "",mid.c_str(),(unsigned long long)OSUtils::jsonInt((*member)["revision"],0)); responseBody.append(tmp); diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index fb4b498d1..60421198a 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -1290,4 +1290,9 @@ void WindowsEthernetTap::_syncIps() } } +void WindowsEthernetTap::setDns(const char* domain, const std::vector& servers) +{ + +} + } // namespace ZeroTier diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index ea08b2fc0..c03c1e414 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -97,6 +97,7 @@ public: virtual void setFriendlyName(const char *friendlyName); virtual void scanMulticastGroups(std::vector &added,std::vector &removed); virtual void setMtu(unsigned int mtu); + virtual void setDns(const char* domain, const std::vector &servers); inline const NET_LUID &luid() const { return _deviceLuid; } inline const GUID &guid() const { return _deviceGuid; } diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index a91ed7d1a..6759bebf7 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -33,7 +33,6 @@ - @@ -51,6 +50,8 @@ + + MaxSpeed MaxSpeed @@ -135,7 +136,6 @@ - @@ -162,6 +162,8 @@ + + @@ -240,6 +242,7 @@ true v142 MultiByte + false Application diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index 78e088c73..d2aba50dc 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -264,9 +264,6 @@ Source Files\controller - - Source Files\controller - Source Files\controller @@ -276,6 +273,12 @@ Source Files\osdep + + Source Files\node + + + Source Files\node + @@ -515,9 +518,6 @@ Header Files\controller - - Header Files\controller - Header Files\controller @@ -530,6 +530,12 @@ Header Files\osdep + + Header Files\node + + + Header Files\node + From d9c4e644de8d3686ee146211f4d68b0bdf802332 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Tue, 11 Aug 2020 18:55:42 -0700 Subject: [PATCH 11/15] Windows DNS --- osdep/WinDNSHelper.cpp | 359 ++++++++++++++++++ osdep/WinDNSHelper.hpp | 24 ++ osdep/WindowsEthernetTap.cpp | 28 +- windows/ZeroTierOne/ZeroTierOne.vcxproj | 7 +- .../ZeroTierOne/ZeroTierOne.vcxproj.filters | 15 +- 5 files changed, 427 insertions(+), 6 deletions(-) create mode 100644 osdep/WinDNSHelper.cpp create mode 100644 osdep/WinDNSHelper.hpp diff --git a/osdep/WinDNSHelper.cpp b/osdep/WinDNSHelper.cpp new file mode 100644 index 000000000..ec4c5152f --- /dev/null +++ b/osdep/WinDNSHelper.cpp @@ -0,0 +1,359 @@ +#include "WinDNSHelper.hpp" + +#include +#include + +#include +#include +#include +#include + +#define MAX_KEY_LENGTH 255 +#define MAX_VALUE_NAME 16383 + +namespace ZeroTier +{ + +BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey) +{ + LPTSTR lpEnd; + LONG lResult; + DWORD dwSize; + TCHAR szName[MAX_PATH]; + HKEY hKey; + FILETIME ftWrite; + + // First, see if we can delete the key without having + // to recurse. + + lResult = RegDeleteKey(hKeyRoot, lpSubKey); + + if (lResult == ERROR_SUCCESS) + return TRUE; + + lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); + + if (lResult != ERROR_SUCCESS) + { + if (lResult == ERROR_FILE_NOT_FOUND) { + printf("Key not found.\n"); + return TRUE; + } + else { + printf("Error opening key.\n"); + return FALSE; + } + } + + // Check for an ending slash and add one if it is missing. + + lpEnd = lpSubKey + lstrlen(lpSubKey); + + if (*(lpEnd - 1) != TEXT('\\')) + { + *lpEnd = TEXT('\\'); + lpEnd++; + *lpEnd = TEXT('\0'); + } + + // Enumerate the keys + + dwSize = MAX_PATH; + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + if (lResult == ERROR_SUCCESS) + { + do { + + *lpEnd = TEXT('\0'); + StringCchCat(lpSubKey, MAX_PATH * 2, szName); + + if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) { + break; + } + + dwSize = MAX_PATH; + + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, + NULL, NULL, &ftWrite); + + } while (lResult == ERROR_SUCCESS); + } + + lpEnd--; + *lpEnd = TEXT('\0'); + + RegCloseKey(hKey); + + // Try again to delete the key. + + lResult = RegDeleteKey(hKeyRoot, lpSubKey); + + if (lResult == ERROR_SUCCESS) + return TRUE; + + return FALSE; +} + +//************************************************************* +// +// RegDelnode() +// +// Purpose: Deletes a registry key and all its subkeys / values. +// +// Parameters: hKeyRoot - Root key +// lpSubKey - SubKey to delete +// +// Return: TRUE if successful. +// FALSE if an error occurs. +// +//************************************************************* + +BOOL RegDelnode(HKEY hKeyRoot, LPCTSTR lpSubKey) +{ + TCHAR szDelKey[MAX_PATH * 2]; + + StringCchCopy(szDelKey, MAX_PATH * 2, lpSubKey); + return RegDelnodeRecurse(hKeyRoot, szDelKey); + +} +std::vector getSubKeys(const char* key) +{ + std::vector subkeys; + HKEY hKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, + key, + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) { + + TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name + DWORD cbName; // size of name string + TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name + DWORD cchClassName = MAX_PATH; // size of class string + DWORD cSubKeys = 0; // number of subkeys + DWORD cbMaxSubKey; // longest subkey size + DWORD cchMaxClass; // longest class string + DWORD cValues; // number of values for key + DWORD cchMaxValue; // longest value name + DWORD cbMaxValueData; // longest value data + DWORD cbSecurityDescriptor; // size of security descriptor + FILETIME ftLastWriteTime; // last write time + + DWORD i, retCode; + + TCHAR achValue[MAX_VALUE_NAME]; + DWORD cchValue = MAX_VALUE_NAME; + + retCode = RegQueryInfoKey( + hKey, // key handle + achClass, // buffer for class name + &cchClassName, // size of class string + NULL, // reserved + &cSubKeys, // number of subkeys + &cbMaxSubKey, // longest subkey size + &cchMaxClass, // longest class string + &cValues, // number of values for this key + &cchMaxValue, // longest value name + &cbMaxValueData, // longest value data + &cbSecurityDescriptor, // security descriptor + &ftLastWriteTime); // last write time + + fprintf(stderr, "num subkeys: %d\n", cSubKeys); + for (i = 0; i < cSubKeys; ++i) { + cbName = MAX_KEY_LENGTH; + retCode = RegEnumKeyEx( + hKey, + i, + achKey, + &cbName, + NULL, + NULL, + NULL, + &ftLastWriteTime); + if (retCode == ERROR_SUCCESS) { + subkeys.push_back(achKey); + } + } + } + RegCloseKey(hKey); + return subkeys; +} + +std::vector getValueList(const char* key) { + std::vector values; + HKEY hKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, + key, + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) { + + TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name + DWORD cbName; // size of name string + TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name + DWORD cchClassName = MAX_PATH; // size of class string + DWORD cSubKeys = 0; // number of subkeys + DWORD cbMaxSubKey; // longest subkey size + DWORD cchMaxClass; // longest class string + DWORD cValues; // number of values for key + DWORD cchMaxValue; // longest value name + DWORD cbMaxValueData; // longest value data + DWORD cbSecurityDescriptor; // size of security descriptor + FILETIME ftLastWriteTime; // last write time + + DWORD i, retCode; + + TCHAR achValue[MAX_VALUE_NAME]; + DWORD cchValue = MAX_VALUE_NAME; + + retCode = RegQueryInfoKey( + hKey, // key handle + achClass, // buffer for class name + &cchClassName, // size of class string + NULL, // reserved + &cSubKeys, // number of subkeys + &cbMaxSubKey, // longest subkey size + &cchMaxClass, // longest class string + &cValues, // number of values for this key + &cchMaxValue, // longest value name + &cbMaxValueData, // longest value data + &cbSecurityDescriptor, // security descriptor + &ftLastWriteTime); // last write time + + fprintf(stderr, "Num values: %d\n", cValues); + for (i = 0, retCode = ERROR_SUCCESS; i < cValues; ++i) { + cchValue = MAX_VALUE_NAME; + achValue[0] = '\0'; + retCode = RegEnumValue( + hKey, + i, + achValue, + &cchValue, + NULL, + NULL, + NULL, + NULL); + if (retCode == ERROR_SUCCESS) { + values.push_back(achValue); + } + } + } + RegCloseKey(hKey); + return values; +} + +std::pair WinDNSHelper::hasDNSConfig(uint64_t nwid) +{ + char networkStr[20] = { 0 }; + sprintf(networkStr, "%.16llx", nwid); + + const char* baseKey = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig"; + auto subkeys = getSubKeys(baseKey); + for (auto it = subkeys.begin(); it != subkeys.end(); ++it) { + char sub[MAX_KEY_LENGTH] = { 0 }; + sprintf(sub, "%s\\%s", baseKey, it->c_str()); + fprintf(stderr, "Checking key: %s\n", sub); + auto dnsRecords = getValueList(sub); + for (auto it2 = dnsRecords.begin(); it2 != dnsRecords.end(); ++it2) { + fprintf(stderr, "\t%s\n", it2->c_str()); + if ((*it2) == "Comment") { + HKEY hKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, + sub, + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) { + + char buf[16384] = { 0 }; + DWORD size = sizeof(buf); + DWORD retCode = RegGetValueA( + HKEY_LOCAL_MACHINE, + sub, + it2->c_str(), + RRF_RT_REG_SZ, + NULL, + &buf, + &size); + if (retCode == ERROR_SUCCESS) { + if (std::string(networkStr) == std::string(buf)) { + RegCloseKey(hKey); + return std::make_pair(true, std::string(sub)); + } + } + else { + + } + } + RegCloseKey(hKey); + } + } + } + + return std::make_pair(false, std::string()); +} + +void WinDNSHelper::setDNS(uint64_t nwid, const char* domain, const std::vector& servers) +{ + auto hasConfig = hasDNSConfig(nwid); + + std::stringstream ss; + for (auto it = servers.begin(); it != servers.end(); ++it) { + char ipaddr[256] = { 0 }; + ss << it->toIpString(ipaddr); + if ((it + 1) != servers.end()) { + ss << ";"; + } + } + std::string serverValue = ss.str(); + + if (hasConfig.first) { + // update existing config + HKEY dnsKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, hasConfig.second.c_str(), 0, KEY_READ | KEY_WRITE, &dnsKey) == ERROR_SUCCESS) { + auto retCode = RegSetKeyValueA(dnsKey, NULL, "GenericDNSServers", REG_SZ, serverValue.data(), (DWORD)serverValue.length()); + if (retCode != ERROR_SUCCESS) { + fprintf(stderr, "Error writing dns servers: %d\n", retCode); + } + } + } else { + // add new config + const char* baseKey = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig"; + GUID guid; + CoCreateGuid(&guid); + wchar_t guidTmp[128] = { 0 }; + char guidStr[128] = { 0 }; + StringFromGUID2(guid, guidTmp, 128); + wcstombs(guidStr, guidTmp, 128); + char fullKey[MAX_KEY_LENGTH] = { 0 }; + sprintf(fullKey, "%s\\%s", baseKey, guidStr); + HKEY dnsKey; + RegCreateKeyA(HKEY_LOCAL_MACHINE, fullKey, &dnsKey); + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, fullKey, 0, KEY_READ | KEY_WRITE, &dnsKey) == ERROR_SUCCESS) { + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + RegSetKeyValueA(dnsKey, NULL, "Comment", REG_SZ, nwString, strlen(nwString)); + + DWORD configOpts = 8; + RegSetKeyValueA(dnsKey, NULL, "ConfigOptions", REG_DWORD, &configOpts, sizeof(DWORD)); + RegSetKeyValueA(dnsKey, NULL, "DisplayName", REG_SZ, "", 0); + RegSetKeyValueA(dnsKey, NULL, "GenericDNSServers", REG_SZ, serverValue.data(), serverValue.length()); + RegSetKeyValueA(dnsKey, NULL, "IPSECCARestriction", REG_SZ, "", 0); + std::string d = "." + std::string(domain); + RegSetKeyValueA(dnsKey, NULL, "Name", REG_MULTI_SZ, d.data(), d.length()); + DWORD version = 2; + RegSetKeyValueA(dnsKey, NULL, "Version", REG_DWORD, &version, sizeof(DWORD)); + } + } +} + +void WinDNSHelper::removeDNS(uint64_t nwid) +{ + auto hasConfig = hasDNSConfig(nwid); + if (hasConfig.first) { + RegDelnode(HKEY_LOCAL_MACHINE, hasConfig.second.c_str()); + } +} + +} \ No newline at end of file diff --git a/osdep/WinDNSHelper.hpp b/osdep/WinDNSHelper.hpp new file mode 100644 index 000000000..c42ba0775 --- /dev/null +++ b/osdep/WinDNSHelper.hpp @@ -0,0 +1,24 @@ +#ifndef WIN_DNS_HELPER_H_ +#define WIN_DNS_HELPER_H_ + +#include +#include +#include "../node/InetAddress.hpp" + + +namespace ZeroTier +{ + +class WinDNSHelper +{ +public: + static void setDNS(uint64_t nwid, const char* domain, const std::vector& servers); + static void removeDNS(uint64_t nwid); + +private: + static std::pair hasDNSConfig(uint64_t nwid); +}; + +} + +#endif \ No newline at end of file diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 60421198a..17aa99116 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -44,6 +44,7 @@ #include "OSUtils.hpp" #include "..\windows\TapDriver6\tap-windows.h" +#include "WinDNSHelper.hpp" #include @@ -473,6 +474,29 @@ WindowsEthernetTap::WindowsEthernetTap( char data[1024]; char tag[24]; + // Initialize COM + HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) { + throw std::runtime_error("WinEthernetTap: COM initialization failed"); + } + + hres = CoInitializeSecurity( + NULL, + -1, + NULL, + NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, + EOAC_NONE, + NULL + ); + if (FAILED(hres)) { + CoUninitialize(); + throw std::runtime_error("WinEthernetTap: Failed to initialize security"); + } + + // We "tag" registry entries with the network ID to identify persistent devices OSUtils::ztsnprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid); @@ -646,6 +670,8 @@ WindowsEthernetTap::WindowsEthernetTap( WindowsEthernetTap::~WindowsEthernetTap() { + WinDNSHelper::removeDNS(_nwid); + CoUninitialize(); _run = false; ReleaseSemaphore(_injectSemaphore,1,NULL); Thread::join(_thread); @@ -1292,7 +1318,7 @@ void WindowsEthernetTap::_syncIps() void WindowsEthernetTap::setDns(const char* domain, const std::vector& servers) { - + WinDNSHelper::setDNS(_nwid, domain, servers); } } // namespace ZeroTier diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 6759bebf7..69036aa0a 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -101,6 +101,7 @@ + true @@ -136,6 +137,7 @@ + @@ -207,6 +209,7 @@ + @@ -370,7 +373,7 @@ true - wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wbemuuid.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false "notelemetry.obj" %(AdditionalOptions) @@ -459,7 +462,7 @@ false true true - wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + wbemuuid.lib;wsock32.lib;ws2_32.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index d2aba50dc..6abe49c0d 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -90,9 +90,6 @@ Source Files\service - - Source Files\osdep - Source Files\osdep @@ -279,6 +276,12 @@ Source Files\node + + Source Files\osdep + + + Source Files\osdep + @@ -536,6 +539,12 @@ Header Files\node + + Header Files\controller + + + Header Files\osdep + From 137d05e79902f9ddabc148701c77d4f7a5f7ceaa Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 12 Aug 2020 09:14:10 -0700 Subject: [PATCH 12/15] add setDNS stubs for linux/bsd --- osdep/BSDEthernetTap.hpp | 1 + osdep/LinuxEthernetTap.hpp | 1 + osdep/NetBSDEthernetTap.hpp | 1 + 3 files changed, 3 insertions(+) diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index d99cebef3..134168176 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -54,6 +54,7 @@ public: virtual void setFriendlyName(const char *friendlyName); virtual void scanMulticastGroups(std::vector &added,std::vector &removed); virtual void setMtu(unsigned int mtu); + virtual void setDns(const char *domain, const std::vector &servers) {} void threadMain() throw(); diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index 7503c5231..58c75f709 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -54,6 +54,7 @@ public: virtual void setFriendlyName(const char *friendlyName); virtual void scanMulticastGroups(std::vector &added,std::vector &removed); virtual void setMtu(unsigned int mtu); + virtual void setDns(const char *domain, const std::vector &servers) {} void threadMain() throw(); diff --git a/osdep/NetBSDEthernetTap.hpp b/osdep/NetBSDEthernetTap.hpp index 534712e45..9c00c0e25 100644 --- a/osdep/NetBSDEthernetTap.hpp +++ b/osdep/NetBSDEthernetTap.hpp @@ -53,6 +53,7 @@ public: virtual std::string deviceName() const; virtual void setFriendlyName(const char *friendlyName); virtual void scanMulticastGroups(std::vector &added,std::vector &removed); + virtual void setDns(const char *domain, const std::vector &servers) {} void threadMain() throw(); From 30b18d925f793aeac589b57dd036f596c96d20b2 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 12 Aug 2020 09:16:18 -0700 Subject: [PATCH 13/15] clean up some debug logging --- osdep/MacDNSHelper.hpp | 2 -- osdep/MacDNSHelper.mm | 11 +---------- osdep/MacEthernetTap.cpp | 1 - osdep/WinDNSHelper.cpp | 6 ------ 4 files changed, 1 insertion(+), 19 deletions(-) diff --git a/osdep/MacDNSHelper.hpp b/osdep/MacDNSHelper.hpp index de45a8507..7a2902fa5 100644 --- a/osdep/MacDNSHelper.hpp +++ b/osdep/MacDNSHelper.hpp @@ -9,8 +9,6 @@ namespace ZeroTier { class MacDNSHelper { public: - static void doTheThing(); - static void setDNS(uint64_t nwid, const char *domain, const std::vector &servers); static void removeDNS(uint64_t nwid); }; diff --git a/osdep/MacDNSHelper.mm b/osdep/MacDNSHelper.mm index b5fc28f07..1cfe1b265 100644 --- a/osdep/MacDNSHelper.mm +++ b/osdep/MacDNSHelper.mm @@ -6,11 +6,6 @@ namespace ZeroTier { -void MacDNSHelper::doTheThing() -{ - fprintf(stderr, "\n\nDOING THE THING!!\n\n"); -} - void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vector &servers) { SCDynamicStoreRef ds = SCDynamicStoreCreate(NULL, CFSTR("zerotier"), NULL, NULL); @@ -49,15 +44,11 @@ void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vector &servers) { - MacDNSHelper::doTheThing(); MacDNSHelper::setDNS(this->_nwid, domain, servers); } diff --git a/osdep/WinDNSHelper.cpp b/osdep/WinDNSHelper.cpp index ec4c5152f..6bcd2b476 100644 --- a/osdep/WinDNSHelper.cpp +++ b/osdep/WinDNSHelper.cpp @@ -36,11 +36,9 @@ BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey) if (lResult != ERROR_SUCCESS) { if (lResult == ERROR_FILE_NOT_FOUND) { - printf("Key not found.\n"); return TRUE; } else { - printf("Error opening key.\n"); return FALSE; } } @@ -160,7 +158,6 @@ std::vector getSubKeys(const char* key) &cbSecurityDescriptor, // security descriptor &ftLastWriteTime); // last write time - fprintf(stderr, "num subkeys: %d\n", cSubKeys); for (i = 0; i < cSubKeys; ++i) { cbName = MAX_KEY_LENGTH; retCode = RegEnumKeyEx( @@ -222,7 +219,6 @@ std::vector getValueList(const char* key) { &cbSecurityDescriptor, // security descriptor &ftLastWriteTime); // last write time - fprintf(stderr, "Num values: %d\n", cValues); for (i = 0, retCode = ERROR_SUCCESS; i < cValues; ++i) { cchValue = MAX_VALUE_NAME; achValue[0] = '\0'; @@ -254,10 +250,8 @@ std::pair WinDNSHelper::hasDNSConfig(uint64_t nwid) for (auto it = subkeys.begin(); it != subkeys.end(); ++it) { char sub[MAX_KEY_LENGTH] = { 0 }; sprintf(sub, "%s\\%s", baseKey, it->c_str()); - fprintf(stderr, "Checking key: %s\n", sub); auto dnsRecords = getValueList(sub); for (auto it2 = dnsRecords.begin(); it2 != dnsRecords.end(); ++it2) { - fprintf(stderr, "\t%s\n", it2->c_str()); if ((*it2) == "Comment") { HKEY hKey; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, From 058d88831122756b119a73c94296f25a638acd2e Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 12 Aug 2020 10:00:09 -0700 Subject: [PATCH 14/15] More debug logging cleanup --- controller/DB.cpp | 5 ----- controller/EmbeddedNetworkController.cpp | 5 ----- controller/PostgreSQL.cpp | 2 -- 3 files changed, 12 deletions(-) diff --git a/controller/DB.cpp b/controller/DB.cpp index a1a72f408..775daf1a5 100644 --- a/controller/DB.cpp +++ b/controller/DB.cpp @@ -112,7 +112,6 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network) std::lock_guard l2(nw->lock); network = nw->config; } - fprintf(stderr, "DB::get(uint64_t,json): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -135,7 +134,6 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem return false; member = m->second; } - fprintf(stderr, "DB::get(uint64_t,json,uint64_t,mjson): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -159,7 +157,6 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem return false; member = m->second; } - fprintf(stderr, "DB::get(uint64_t,json,uint64_t,mjson,summary): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -180,7 +177,6 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vectormembers.begin();m!=nw->members.end();++m) members.push_back(m->second); } - fprintf(stderr, "DB::get(uint64_t,json,members): %s %s\n", OSUtils::jsonString(network["nwid"],"").c_str(), OSUtils::jsonDump(network["dns"], 2).c_str()); return true; } @@ -311,7 +307,6 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool { if (networkConfig.is_object()) { const std::string ids = networkConfig["id"]; - fprintf(stderr, "DB::_networkChanged(): %s\n", OSUtils::jsonDump(networkConfig["dns"]).c_str()); const uint64_t networkId = Utils::hexStrToU64(ids.c_str()); if (networkId) { std::shared_ptr<_Network> nw; diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index ad1db6244..a505c3edb 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1419,8 +1419,6 @@ void EmbeddedNetworkController::_request( json &memberTags = member["tags"]; json &dns = network["dns"]; - fprintf(stderr, "DNS Config for Network ID %.16llx: %s\n", nwid, OSUtils::jsonDump(dns, 2).c_str()); - if (metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,0) <= 0) { // Old versions with no rules engine support get an allow everything rule. // Since rules are enforced bidirectionally, newer versions *will* still @@ -1714,11 +1712,9 @@ void EmbeddedNetworkController::_request( } if(dns.is_array()) { - fprintf(stderr, "dns is array of size %d\n", dns.size()); nc->dnsCount = 0; for(unsigned int p=0; p < dns.size(); ++p) { json &d = dns[p]; - fprintf(stderr, "%s\n", OSUtils::jsonDump(d, 2).c_str()); if (d.is_object()) { std::string domain = OSUtils::jsonString(d["domain"],""); memcpy(nc->dns[nc->dnsCount].domain, domain.c_str(), domain.size()); @@ -1733,7 +1729,6 @@ void EmbeddedNetworkController::_request( } } } else { - fprintf(stderr, "dns is NOT an array\n"); dns = json::array(); } diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index 8463c13a8..81908c46b 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -456,7 +456,6 @@ void PostgreSQL::initializeNetworks(PGconn *conn) auto servers = json::array(); if (serverList.rfind("{",0) != std::string::npos) { serverList = serverList.substr(1, serverList.size()-2); - fprintf(stderr, "Server List: %s\n", serverList.c_str()); std::stringstream ss(serverList); while(ss.good()) { std::string server; @@ -468,7 +467,6 @@ void PostgreSQL::initializeNetworks(PGconn *conn) obj["servers"] = servers; config["dns"].push_back(obj); } - fprintf(stderr, "%s: %s\n", OSUtils::jsonString(config["nwid"], "").c_str(), OSUtils::jsonDump(config["dns"], 2).c_str()); PQclear(r2); From c0c215c83c75d76aad3aafa337d69d876c13f5cf Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 12 Aug 2020 13:08:47 -0700 Subject: [PATCH 15/15] single dns config per network --- controller/EmbeddedNetworkController.cpp | 25 +++---- controller/PostgreSQL.cpp | 87 ++++++++---------------- include/ZeroTierOne.h | 12 +--- node/DNS.hpp | 28 ++++---- node/Network.cpp | 6 +- node/NetworkConfig.cpp | 13 ++-- node/NetworkConfig.hpp | 4 +- osdep/MacDNSHelper.mm | 1 - service/OneService.cpp | 47 +++++-------- 9 files changed, 76 insertions(+), 147 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index a505c3edb..ad42fabb1 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1711,25 +1711,18 @@ void EmbeddedNetworkController::_request( } } - if(dns.is_array()) { - nc->dnsCount = 0; - for(unsigned int p=0; p < dns.size(); ++p) { - json &d = dns[p]; - if (d.is_object()) { - std::string domain = OSUtils::jsonString(d["domain"],""); - memcpy(nc->dns[nc->dnsCount].domain, domain.c_str(), domain.size()); - json &addrArray = d["servers"]; - if (addrArray.is_array()) { - for(unsigned int j = 0; j < addrArray.size() && j < ZT_MAX_DNS_SERVERS; ++j) { - json &addr = addrArray[j]; - nc->dns[nc->dnsCount].server_addr[j] = InetAddress(OSUtils::jsonString(addr,"").c_str()); - } - } - ++nc->dnsCount; + if(dns.is_object()) { + std::string domain = OSUtils::jsonString(dns["domain"],""); + memcpy(nc->dns.domain, domain.c_str(), domain.size()); + json &addrArray = dns["servers"]; + if (addrArray.is_array()) { + for(unsigned int j = 0; j < addrArray.size() && j < ZT_MAX_DNS_SERVERS; ++j) { + json &addr = addrArray[j]; + nc->dns.server_addr[j] = InetAddress(OSUtils::jsonString(addr,"").c_str()); } } } else { - dns = json::array(); + dns = json::object(); } // Issue a certificate of ownership for all static IPs diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index 81908c46b..44ba2ae5d 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -447,12 +447,12 @@ void PostgreSQL::initializeNetworks(PGconn *conn) } n = PQntuples(r2); - config["dns"] = json::array(); - for (int j = 0; j < n; ++j) { - + if (n > 1) { + fprintf(stderr, "ERROR: invalid number of DNS configurations for network %s. Must be 0 or 1\n", nwid.c_str()); + } else if (n == 1) { json obj; - std::string domain = PQgetvalue(r2, j, 0); - std::string serverList = PQgetvalue(r2, j, 1); + std::string domain = PQgetvalue(r2, 0, 0); + std::string serverList = PQgetvalue(r2, 0, 1); auto servers = json::array(); if (serverList.rfind("{",0) != std::string::npos) { serverList = serverList.substr(1, serverList.size()-2); @@ -465,7 +465,7 @@ void PostgreSQL::initializeNetworks(PGconn *conn) } obj["domain"] = domain; obj["servers"] = servers; - config["dns"].push_back(obj); + config["dns"] = obj; } PQclear(r2); @@ -1461,67 +1461,38 @@ void PostgreSQL::commitThread() config = nullptr; continue; } + auto dns = (*config)["dns"]; + std::string domain = dns["domain"]; + std::stringstream servers; + servers << "{"; + for (auto j = dns["servers"].begin(); j < dns["servers"].end(); ++j) { + servers << *j; + if ( (j+1) != dns["servers"].end()) { + servers << ","; + } + } + servers << "}"; + const char *p[3] = { + id.c_str(), + domain.c_str(), + servers.str().c_str() + }; - res = PQexecParams(conn, - "DELETE FROM ztc_network_dns WHERE network_id = $1", - 1, + res = PQexecParams(conn, "INSERT INTO ztc_network_dns (network_id, domain, servers) VALUES ($1, $2, $3) ON CONFLICT (network_id) DO UPDATE SET domain = EXCLUDED.domain, servers = EXCLUDED.servers", + 3, NULL, - params, + p, NULL, NULL, 0); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - fprintf(stderr, "ERROR: Error updating dns: %s\n", PQresultErrorMessage(res)); + fprintf(stderr, "ERROR: Error updating DNS: %s\n", PQresultErrorMessage(res)); PQclear(res); - PQclear(PQexec(conn, "ROLLBACK")); - delete config; - config = nullptr; - continue; - } - - auto dns = (*config)["dns"]; - err = false; - for (auto i = dns.begin(); i < dns.end(); ++i) { - std::string domain = (*i)["domain"]; - std::stringstream servers; - servers << "{"; - for (auto j = dns["servers"].begin(); j < dns["servers"].end(); ++j) { - servers << *j; - if ( (j+1) != dns["servers"].end()) { - servers << ","; - } - } - servers << "}"; - - const char *p[3] = { - id.c_str(), - domain.c_str(), - servers.str().c_str() - }; - - res = PQexecParams(conn, "INSERT INTO ztc_network_dns (network_id, domain, servers) VALUES ($1, $2, $3)", - 3, - NULL, - p, - NULL, - NULL, - 0); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - fprintf(stderr, "ERROR: Error updating DNS: %s\n", PQresultErrorMessage(res)); - PQclear(res); - err = true; - break; - } - PQclear(res); - } - if (err) { - PQclear(PQexec(conn, "ROLLBACK")); - delete config; - config = nullptr; - continue; + err = true; + break; } + PQclear(res); res = PQexec(conn, "COMMIT"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 82ae5edfd..f7e6ef6dc 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -125,11 +125,6 @@ extern "C" { */ #define ZT_MAX_NETWORK_ROUTES 32 -/** - * Maximum number of pushed DNS configurations on a network - */ -#define ZT_MAX_NETWORK_DNS 32 - /** * Maximum number of statically assigned IP addresses per network endpoint using ZT address management (not DHCP) */ @@ -1339,16 +1334,11 @@ typedef struct uint64_t mac; /* MAC in lower 48 bits */ uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */ } multicastSubscriptions[ZT_MAX_MULTICAST_SUBSCRIPTIONS]; - - /** - * Number of ZT-pushed DNS configuraitons - */ - unsigned int dnsCount; /** * Network specific DNS configuration */ - ZT_VirtualNetworkDNS dns[ZT_MAX_NETWORK_DNS]; + ZT_VirtualNetworkDNS dns; } ZT_VirtualNetworkConfig; /** diff --git a/node/DNS.hpp b/node/DNS.hpp index a770859d8..ceb81e33f 100644 --- a/node/DNS.hpp +++ b/node/DNS.hpp @@ -29,28 +29,24 @@ namespace ZeroTier { class DNS { public: template - static inline void serializeDNS(Buffer &b, const ZT_VirtualNetworkDNS *dns, unsigned int dnsCount) + static inline void serializeDNS(Buffer &b, const ZT_VirtualNetworkDNS *dns) { - for(unsigned int i = 0; i < dnsCount; ++i) { - b.append(dns[i].domain, 128); - for(unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { - InetAddress tmp(dns[i].server_addr[j]); - tmp.serialize(b); - } + 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 - static inline void deserializeDNS(const Buffer &b, unsigned int &p, ZT_VirtualNetworkDNS *dns, const unsigned int dnsCount) + static inline void deserializeDNS(const Buffer &b, unsigned int &p, ZT_VirtualNetworkDNS *dns) { - memset(dns, 0, sizeof(ZT_VirtualNetworkDNS)*ZT_MAX_NETWORK_DNS); - for(unsigned int i = 0; i < dnsCount; ++i) { - char *d = (char*)b.data()+p; - memcpy(dns[i].domain, d, 128); - p += 128; - for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { - p += reinterpret_cast(&(dns[i].server_addr[j]))->deserialize(b, p); - } + char *d = (char*)b.data()+p; + memset(dns, 0, sizeof(ZT_VirtualNetworkDNS)); + memcpy(dns->domain, d, 128); + p += 128; + for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { + p += reinterpret_cast(&(dns->server_addr[j]))->deserialize(b, p); } } }; diff --git a/node/Network.cpp b/node/Network.cpp index 97642fa18..3fe489a29 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1428,11 +1428,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const ec->multicastSubscriptions[i].adi = _myMulticastGroups[i].adi(); } - ec->dnsCount = _config.dnsCount; - fprintf(stderr, "Network::_externalConfig dnsCount: %d\n", ec->dnsCount); - if (ec->dnsCount > 0) { - memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS)); - } + memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS)); } void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 503d7400a..c793462d8 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -177,12 +177,9 @@ bool NetworkConfig::toDictionary(Dictionary &d,b } tmp->clear(); - if (dnsCount > 0) { - tmp->append(dnsCount); - DNS::serializeDNS(*tmp, dns, dnsCount); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) return false; - } + DNS::serializeDNS(*tmp, &dns); + if (tmp->size()) { + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) return false; } delete tmp; @@ -366,9 +363,7 @@ bool NetworkConfig::fromDictionary(const DictionarydnsCount = tmp->at(p); - p += sizeof(unsigned int); - DNS::deserializeDNS(*tmp, p, dns, (this->dnsCount <= ZT_MAX_NETWORK_DNS) ? this->dnsCount : ZT_MAX_NETWORK_DNS); + DNS::deserializeDNS(*tmp, p, &dns); } } diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 1daf98d01..6e66720e8 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -240,7 +240,7 @@ public: 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)*ZT_MAX_NETWORK_DNS); + memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS)); } /** @@ -603,7 +603,7 @@ public: /** * ZT pushed DNS configuration */ - ZT_VirtualNetworkDNS dns[ZT_MAX_NETWORK_DNS]; + ZT_VirtualNetworkDNS dns; }; } // namespace ZeroTier diff --git a/osdep/MacDNSHelper.mm b/osdep/MacDNSHelper.mm index 1cfe1b265..c50de7915 100644 --- a/osdep/MacDNSHelper.mm +++ b/osdep/MacDNSHelper.mm @@ -34,7 +34,6 @@ void MacDNSHelper::setDNS(uint64_t nwid, const char *domain, const std::vectordnsCount;++i) { - nlohmann::json m; - m["domain"] = nc->dns[i].domain; - m["servers"] = nlohmann::json::array(); - for(int j=0;jdns[i].server_addr[j]); - if (a.isV4() || a.isV6()) { - char buf[256]; - m["servers"].push_back(a.toIpString(buf)); - } + nlohmann::json m; + m["domain"] = nc->dns.domain; + m["servers"] = nlohmann::json::array(); + for(int j=0;jdns.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) @@ -2002,25 +2001,15 @@ public: } if (syncDns) { - char buf[128]; - if (n.config.dnsCount > ZT_MAX_NETWORK_DNS) { - fprintf(stderr, "ERROR: %d records > max %d. Skipping DNS\n", n.config.dnsCount, ZT_MAX_NETWORK_DNS); - return; - } - fprintf(stderr, "Syncing %d DNS configurations for network [%.16llx]\n", n.config.dnsCount, n.config.nwid); - for (int i = 0; i < n.config.dnsCount; ++i) { - if (strlen(n.config.dns[i].domain) != 0) { - fprintf(stderr, "Syncing DNS for domain: %s\n", n.config.dns[i].domain); - std::vector servers; - for (int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { - InetAddress a(n.config.dns[i].server_addr[j]); - if (a.isV4() || a.isV6()) { - fprintf(stderr, "\t Server %d: %s\n", j+1, a.toIpString(buf)); - servers.push_back(a); - } + if (strlen(n.config.dns.domain) != 0) { + std::vector 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[i].domain, servers); } + n.tap->setDns(n.config.dns.domain, servers); } } }