/* * 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 . * * -- * * 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 #include #include #include #include #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 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 nw; std::map< uint64_t,SharedPtr >::iterator nwent(_networks.find(nwid)); if (nwent != _networks.end()) nw = nwent->second; else { try { nw = SharedPtr(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 allIps; const Json::Value &addresses = networks[ni]["_addresses"]; if (addresses.isArray()) { for(unsigned int ai=0;ai_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.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 &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::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