diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-07-04 16:56:19 -0400 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-07-04 16:56:19 -0400 |
commit | 150850b80012f852521c9935145cf966946334d5 (patch) | |
tree | c082369f2fef2515cfa2e4acf1b83250a3963158 /node/NodeConfig.cpp | |
download | infinitytier-150850b80012f852521c9935145cf966946334d5.tar.gz infinitytier-150850b80012f852521c9935145cf966946334d5.zip |
New git repository for release - version 0.2.0 tagged
Diffstat (limited to 'node/NodeConfig.cpp')
-rw-r--r-- | node/NodeConfig.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp new file mode 100644 index 00000000..47310050 --- /dev/null +++ b/node/NodeConfig.cpp @@ -0,0 +1,206 @@ +/* + * ZeroTier One - Global Peer to Peer Ethernet + * Copyright (C) 2012-2013 ZeroTier Networks LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#include <stdio.h> +#include <string.h> +#include <memory> +#include <string> + +#include <json/json.h> + +#include "NodeConfig.hpp" +#include "RuntimeEnvironment.hpp" +#include "Defaults.hpp" +#include "Utils.hpp" +#include "Logger.hpp" + +namespace ZeroTier { + +NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const std::string &url) : + _r(renv), + _lastAutoconfigure(0), + _lastAutoconfigureLastModified(), + _url(url), + _autoconfigureLock(), + _networks(), + _networks_m() +{ +} + +NodeConfig::~NodeConfig() +{ + _autoconfigureLock.lock(); // wait for any autoconfs to finish + _autoconfigureLock.unlock(); +} + +void NodeConfig::refreshConfiguration() +{ + _autoconfigureLock.lock(); // unlocked when handler gets called + + TRACE("refreshing autoconfigure URL %s (if modified since: '%s')",_url.c_str(),_lastAutoconfigureLastModified.c_str()); + + std::map<std::string,std::string> reqHeaders; + reqHeaders["X-ZT-ID"] = _r->identity.toString(false); + reqHeaders["X-ZT-OVSH"] = _r->ownershipVerificationSecretHash; + if (_lastAutoconfigureLastModified.length()) + reqHeaders["If-Modified-Since"] = _lastAutoconfigureLastModified; + + new Http::Request(Http::HTTP_METHOD_GET,_url,reqHeaders,std::string(),&NodeConfig::_CBautoconfHandler,this); +} + +void NodeConfig::__CBautoconfHandler(const std::string &lastModified,const std::string &body) +{ + try { + Json::Value root; + Json::Reader reader; + + std::string dec(_r->identity.decrypt(_r->configAuthority,body.data(),body.length())); + if (!dec.length()) { + LOG("autoconfigure from %s failed: data did not decrypt as from config authority %s",_url.c_str(),_r->configAuthority.address().toString().c_str()); + return; + } + TRACE("decrypted autoconf: %s",dec.c_str()); + + if (!reader.parse(dec,root,false)) { + LOG("autoconfigure from %s failed: JSON parse error: %s",_url.c_str(),reader.getFormattedErrorMessages().c_str()); + return; + } + + if (!root.isObject()) { + LOG("autoconfigure from %s failed: not a JSON object",_url.c_str()); + return; + } + + // Configure networks + const Json::Value &networks = root["_networks"]; + if (networks.isArray()) { + Mutex::Lock _l(_networks_m); + for(unsigned int ni=0;ni<networks.size();++ni) { + if (networks[ni].isObject()) { + const Json::Value &nwid_ = networks[ni]["id"]; + uint64_t nwid = nwid_.isNumeric() ? (uint64_t)nwid_.asUInt64() : (uint64_t)strtoull(networks[ni]["id"].asString().c_str(),(char **)0,10); + + if (nwid) { + SharedPtr<Network> nw; + std::map< uint64_t,SharedPtr<Network> >::iterator nwent(_networks.find(nwid)); + if (nwent != _networks.end()) + nw = nwent->second; + else { + try { + nw = SharedPtr<Network>(new Network(_r,nwid)); + _networks[nwid] = nw; + } catch (std::exception &exc) { + LOG("unable to create network %llu: %s",nwid,exc.what()); + } catch ( ... ) { + LOG("unable to create network %llu: unknown exception",nwid); + } + } + + if (nw) { + Mutex::Lock _l2(nw->_lock); + nw->_open = networks[ni]["isOpen"].asBool(); + + // Ensure that TAP device has all the right IP addresses + // TODO: IPv6 might work a tad differently + std::set<InetAddress> allIps; + const Json::Value &addresses = networks[ni]["_addresses"]; + if (addresses.isArray()) { + for(unsigned int ai=0;ai<addresses.size();++ai) { + if (addresses[ai].isString()) { + InetAddress addr(addresses[ai].asString()); + if (addr) { + TRACE("network %llu IP/netmask: %s",nwid,addr.toString().c_str()); + allIps.insert(addr); + } + } + } + } + nw->_tap.setIps(allIps); + + // NOTE: the _members field is optional for open networks, + // since members of open nets do not need to check membership + // of packet senders and mutlicasters. + const Json::Value &members = networks[ni]["_members"]; + nw->_members.clear(); + if (members.isArray()) { + for(unsigned int mi=0;mi<members.size();++mi) { + std::string rawAddr(Utils::unhex(members[mi].asString())); + if (rawAddr.length() == ZT_ADDRESS_LENGTH) { + Address addr(rawAddr.data()); + if ((addr)&&(!addr.isReserved())) { + TRACE("network %llu member: %s",nwid,addr.toString().c_str()); + nw->_members.insert(addr); + } + } + } + } + } + } else { + TRACE("ignored networks[%u], 'id' field missing"); + } + } else { + TRACE("ignored networks[%u], not a JSON object",ni); + } + } + } + + _lastAutoconfigure = Utils::now(); + _lastAutoconfigureLastModified = lastModified; + } catch (std::exception &exc) { + TRACE("exception parsing autoconf URL response: %s",exc.what()); + } catch ( ... ) { + TRACE("unexpected exception parsing autoconf URL response"); + } +} + +bool NodeConfig::_CBautoconfHandler(Http::Request *req,void *arg,const std::string &url,int code,const std::map<std::string,std::string> &headers,const std::string &body) +{ +#ifdef ZT_TRACE + const RuntimeEnvironment *_r = ((NodeConfig *)arg)->_r; +#endif + + if (code == 200) { + TRACE("200 got autoconfigure response from %s: %u bytes",url.c_str(),(unsigned int)body.length()); + + std::map<std::string,std::string>::const_iterator lm(headers.find("Last-Modified")); + if (lm != headers.end()) + ((NodeConfig *)arg)->__CBautoconfHandler(lm->second,body); + else ((NodeConfig *)arg)->__CBautoconfHandler(std::string(),body); + } else if (code == 304) { + TRACE("304 autoconfigure deferred, remote URL %s not modified",url.c_str()); + ((NodeConfig *)arg)->_lastAutoconfigure = Utils::now(); // still considered a success + } else if (code == 409) { // conflict, ID address in use by another ID + TRACE("%d autoconfigure failed from %s",code,url.c_str()); + } else { + TRACE("%d autoconfigure failed from %s",code,url.c_str()); + } + + ((NodeConfig *)arg)->_autoconfigureLock.unlock(); + return false; // causes Request to delete itself +} + +} // namespace ZeroTier |