NetworkConfigMaster.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2011-2015 ZeroTier Networks
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #include "Constants.hpp"
  28. #include "NetworkConfigMaster.hpp"
  29. #ifdef ZT_ENABLE_NETCONF_MASTER
  30. #include <stdint.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <time.h>
  35. #include <sys/time.h>
  36. #include <sys/types.h>
  37. #include <algorithm>
  38. #include <utility>
  39. #include "RuntimeEnvironment.hpp"
  40. #include "Switch.hpp"
  41. #include "Packet.hpp"
  42. #include "NetworkConfig.hpp"
  43. #include "Utils.hpp"
  44. #include "Node.hpp"
  45. #include "Logger.hpp"
  46. #include "Topology.hpp"
  47. #include "Peer.hpp"
  48. #include "CertificateOfMembership.hpp"
  49. // Redis timeout in seconds
  50. #define ZT_NETCONF_REDIS_TIMEOUT 10
  51. namespace ZeroTier {
  52. NetworkConfigMaster::NetworkConfigMaster(
  53. const RuntimeEnvironment *renv,
  54. const char *redisHost,
  55. unsigned int redisPort,
  56. const char *redisPassword,
  57. unsigned int redisDatabaseNumber) :
  58. _lock(),
  59. _redisHost(redisHost),
  60. _redisPassword((redisPassword) ? redisPassword : ""),
  61. _redisPort(redisPort),
  62. _redisDatabaseNumber(redisDatabaseNumber),
  63. RR(renv),
  64. _rc((redisContext *)0)
  65. {
  66. }
  67. NetworkConfigMaster::~NetworkConfigMaster()
  68. {
  69. Mutex::Lock _l(_lock);
  70. if (_rc)
  71. redisFree(_rc);
  72. }
  73. void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uint64_t packetId,const Address &member,uint64_t nwid,const Dictionary &metaData,uint64_t haveTimestamp)
  74. {
  75. char memberKey[128],nwids[24],addrs[16],nwKey[128],revKey[128];
  76. Dictionary memberRecord;
  77. std::string revision,tmps2;
  78. Mutex::Lock _l(_lock);
  79. Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
  80. Utils::snprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)member.toInt());
  81. Utils::snprintf(memberKey,sizeof(memberKey),"zt1:network:%s:member:%s:~",nwids,addrs);
  82. Utils::snprintf(nwKey,sizeof(nwKey),"zt1:network:%s:~",nwids);
  83. Utils::snprintf(revKey,sizeof(revKey),"zt1:network:%s:revision",nwids);
  84. TRACE("netconf: %s : %s if > %llu",nwids,addrs,(unsigned long long)haveTimestamp);
  85. // Check to make sure network itself exists and is valid
  86. if (!_hget(nwKey,"id",tmps2)) {
  87. LOG("netconf: Redis error retrieving %s/id",nwKey);
  88. return;
  89. }
  90. if (tmps2 != nwids) {
  91. TRACE("netconf: network %s not found",nwids);
  92. Packet outp(member,RR->identity.address(),Packet::VERB_ERROR);
  93. outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
  94. outp.append(packetId);
  95. outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
  96. outp.append(nwid);
  97. RR->sw->send(outp,true);
  98. return;
  99. }
  100. // Get network revision
  101. if (!_get(revKey,revision)) {
  102. LOG("netconf: Redis error retrieving %s",revKey);
  103. return;
  104. }
  105. if (!revision.length())
  106. revision = "0";
  107. // Get network member record for this peer
  108. if (!_hgetall(memberKey,memberRecord)) {
  109. LOG("netconf: Redis error retrieving %s",memberKey);
  110. return;
  111. }
  112. // If there is no member record, init a new one -- for public networks this
  113. // auto-authorizes, and for private nets it makes the peer show up in the UI
  114. // so the admin can authorize or delete/hide it.
  115. if ((memberRecord.size() == 0)||(memberRecord.get("id","") != addrs)||(memberRecord.get("nwid","") != nwids)) {
  116. if (!_initNewMember(nwid,member,metaData,memberRecord))
  117. return;
  118. }
  119. if (memberRecord.getBoolean("authorized")) {
  120. // Get current netconf and netconf timestamp
  121. uint64_t ts = memberRecord.getHexUInt("netconfTimestamp",0);
  122. std::string netconf(memberRecord.get("netconf",""));
  123. // Update statistics for this node
  124. Dictionary upd;
  125. upd.setHex("netconfClientTimestamp",haveTimestamp);
  126. if (fromAddr)
  127. upd.set("lastAt",fromAddr.toString());
  128. upd.setHex("lastSeen",Utils::now());
  129. _hmset(memberKey,upd);
  130. // Attempt to generate netconf for this node if there isn't
  131. // one or it's not in step with the network's revision.
  132. if (((ts == 0)||(netconf.length() == 0))||(memberRecord.get("netconfRevision","") != revision)) {
  133. if (!_generateNetconf(nwid,member,metaData,netconf,ts))
  134. return;
  135. }
  136. // If the netconf we have (or just generated) is newer than what
  137. // the client reports that it has, send it. Otherwise we just
  138. // ignore the message since the client is up to date.
  139. if (ts > haveTimestamp) {
  140. TRACE("netconf: sending %u bytes of netconf data to %s",netconf.length(),addrs);
  141. Packet outp(member,RR->identity.address(),Packet::VERB_OK);
  142. outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
  143. outp.append(packetId);
  144. outp.append(nwid);
  145. outp.append((uint16_t)netconf.length());
  146. outp.append(netconf.data(),netconf.length());
  147. outp.compress();
  148. if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { // sanity check -- this would be weird
  149. TRACE("netconf: compressed packet exceeds ZT_PROTO_MAX_PACKET_LENGTH!");
  150. return;
  151. }
  152. RR->sw->send(outp,true);
  153. }
  154. } else {
  155. TRACE("netconf: access denied for %s on %s",addrs,nwids);
  156. Packet outp(member,RR->identity.address(),Packet::VERB_ERROR);
  157. outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
  158. outp.append(packetId);
  159. outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
  160. outp.append(nwid);
  161. RR->sw->send(outp,true);
  162. }
  163. }
  164. bool NetworkConfigMaster::_reconnect()
  165. {
  166. struct timeval tv;
  167. if (_rc)
  168. redisFree(_rc);
  169. tv.tv_sec = ZT_NETCONF_REDIS_TIMEOUT;
  170. tv.tv_usec = 0;
  171. _rc = redisConnectWithTimeout(_redisHost.c_str(),_redisPort,tv);
  172. if (!_rc)
  173. return false;
  174. if (_rc->err) {
  175. redisFree(_rc);
  176. _rc = (redisContext *)0;
  177. return false;
  178. }
  179. redisSetTimeout(_rc,tv); // necessary???
  180. // TODO: support AUTH and SELECT !!!
  181. return true;
  182. }
  183. bool NetworkConfigMaster::_hgetall(const char *key,Dictionary &hdata)
  184. {
  185. if (!_rc) {
  186. if (!_reconnect())
  187. return false;
  188. }
  189. redisReply *reply = (redisReply *)redisCommand(_rc,"HGETALL %s",key);
  190. if (!reply) {
  191. if (_reconnect())
  192. return _hgetall(key,hdata);
  193. return false;
  194. }
  195. hdata.clear();
  196. if (reply->type == REDIS_REPLY_ARRAY) {
  197. for(long i=0;i<reply->elements;) {
  198. try {
  199. const char *k = reply->element[i]->str;
  200. if (++i >= reply->elements)
  201. break;
  202. if ((k)&&(reply->element[i]->str))
  203. hdata[k] = reply->element[i]->str;
  204. ++i;
  205. } catch ( ... ) {
  206. break; // memory safety
  207. }
  208. }
  209. }
  210. freeReplyObject(reply);
  211. return true;
  212. }
  213. bool NetworkConfigMaster::_hmset(const char *key,const Dictionary &hdata)
  214. {
  215. const char *hargv[1024];
  216. if (!hdata.size())
  217. return true;
  218. if (!_rc) {
  219. if (!_reconnect())
  220. return false;
  221. }
  222. hargv[0] = "HMSET";
  223. hargv[1] = key;
  224. int hargc = 2;
  225. for(Dictionary::const_iterator i(hdata.begin());i!=hdata.end();++i) {
  226. if (hargc >= 1024)
  227. break;
  228. hargv[hargc++] = i->first.c_str();
  229. hargv[hargc++] = i->second.c_str();
  230. }
  231. redisReply *reply = (redisReply *)redisCommandArgv(_rc,hargc,hargv,(const size_t *)0);
  232. if (!reply) {
  233. if (_reconnect())
  234. return _hmset(key,hdata);
  235. return false;
  236. }
  237. if (reply->type == REDIS_REPLY_ERROR) {
  238. freeReplyObject(reply);
  239. return false;
  240. }
  241. freeReplyObject(reply);
  242. return true;
  243. }
  244. bool NetworkConfigMaster::_hget(const char *key,const char *hashKey,std::string &value)
  245. {
  246. if (!_rc) {
  247. if (!_reconnect())
  248. return false;
  249. }
  250. redisReply *reply = (redisReply *)redisCommand(_rc,"HGET %s %s",key,hashKey);
  251. if (!reply) {
  252. if (_reconnect())
  253. return _hget(key,hashKey,value);
  254. return false;
  255. }
  256. if (reply->type == REDIS_REPLY_STRING)
  257. value = reply->str;
  258. else value = "";
  259. freeReplyObject(reply);
  260. return true;
  261. }
  262. bool NetworkConfigMaster::_hset(const char *key,const char *hashKey,const char *value)
  263. {
  264. if (!_rc) {
  265. if (!_reconnect())
  266. return false;
  267. }
  268. redisReply *reply = (redisReply *)redisCommand(_rc,"HSET %s %s %s",key,hashKey,value);
  269. if (!reply) {
  270. if (_reconnect())
  271. return _hset(key,hashKey,value);
  272. return false;
  273. }
  274. if (reply->type == REDIS_REPLY_ERROR) {
  275. freeReplyObject(reply);
  276. return false;
  277. }
  278. freeReplyObject(reply);
  279. return true;
  280. }
  281. bool NetworkConfigMaster::_get(const char *key,std::string &value)
  282. {
  283. if (!_rc) {
  284. if (!_reconnect())
  285. return false;
  286. }
  287. redisReply *reply = (redisReply *)redisCommand(_rc,"GET %s",key);
  288. if (!reply) {
  289. if (_reconnect())
  290. return _get(key,value);
  291. return false;
  292. }
  293. if ((reply->type == REDIS_REPLY_STRING)&&(reply->str))
  294. value = reply->str;
  295. else value = "";
  296. freeReplyObject(reply);
  297. return true;
  298. }
  299. bool NetworkConfigMaster::_smembers(const char *key,std::vector<std::string> &sdata)
  300. {
  301. if (!_rc) {
  302. if (!_reconnect())
  303. return false;
  304. }
  305. redisReply *reply = (redisReply *)redisCommand(_rc,"SMEMBERS %s",key);
  306. if (!reply) {
  307. if (_reconnect())
  308. return _smembers(key,sdata);
  309. return false;
  310. }
  311. sdata.clear();
  312. if (reply->type == REDIS_REPLY_ARRAY) {
  313. for(long i=0;i<reply->elements;++i) {
  314. if (reply->element[i]->str)
  315. sdata.push_back(reply->element[i]->str);
  316. }
  317. }
  318. return true;
  319. }
  320. bool NetworkConfigMaster::_initNewMember(uint64_t nwid,const Address &member,const Dictionary &metaData,Dictionary &memberRecord)
  321. {
  322. char memberKey[256],nwids[24],addrs[16],nwKey[256];
  323. Dictionary networkRecord;
  324. Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
  325. Utils::snprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)member.toInt());
  326. Utils::snprintf(memberKey,sizeof(memberKey),"zt1:network:%s:member:%s:~",nwids,addrs);
  327. Utils::snprintf(nwKey,sizeof(nwKey),"zt1:network:%s:~",nwids);
  328. if (!_hgetall(nwKey,networkRecord)) {
  329. LOG("netconf: Redis error retrieving %s",nwKey);
  330. return false;
  331. }
  332. if (networkRecord.get("id","") != nwids) {
  333. TRACE("netconf: network %s not found (initNewMember)",nwids);
  334. return false;
  335. }
  336. memberRecord.clear();
  337. memberRecord["id"] = addrs;
  338. memberRecord["nwid"] = nwids;
  339. memberRecord["authorized"] = (networkRecord.getBoolean("private",true) ? "0" : "1"); // auto-authorize on public networks
  340. memberRecord.setHex("firstSeen",Utils::now());
  341. {
  342. SharedPtr<Peer> peer(RR->topology->getPeer(member));
  343. if (peer)
  344. memberRecord["identity"] = peer->identity().toString(false);
  345. }
  346. if (!_hmset(memberKey,memberRecord)) {
  347. LOG("netconf: Redis error storing %s for new member %s",memberKey,addrs);
  348. return false;
  349. }
  350. return true;
  351. }
  352. bool NetworkConfigMaster::_generateNetconf(uint64_t nwid,const Address &member,const Dictionary &metaData,std::string &netconf,uint64_t &ts)
  353. {
  354. char memberKey[256],nwids[24],addrs[16],tss[24],nwKey[256],revKey[128],abKey[128],ipaKey[128];
  355. Dictionary networkRecord,memberRecord,nc;
  356. std::string revision;
  357. Utils::snprintf(memberKey,sizeof(memberKey),"zt1:network:%s:member:%s:~",nwids,addrs);
  358. Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
  359. Utils::snprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)member.toInt());
  360. Utils::snprintf(nwKey,sizeof(nwKey),"zt1:network:%s:~",nwids);
  361. Utils::snprintf(revKey,sizeof(revKey),"zt1:network:%s:revision",nwids);
  362. Utils::snprintf(abKey,sizeof(revKey),"zt1:network:%s:activeBridges",nwids);
  363. Utils::snprintf(ipaKey,sizeof(revKey),"zt1:network:%s:ipAssignments",nwids);
  364. if (!_hgetall(nwKey,networkRecord)) {
  365. LOG("netconf: Redis error retrieving %s",nwKey);
  366. return false;
  367. }
  368. if (networkRecord.get("id","") != nwids) {
  369. TRACE("netconf: network %s not found (generateNetconf)",nwids);
  370. return false;
  371. }
  372. if (!_hgetall(memberKey,memberRecord)) {
  373. LOG("netconf: Redis error retrieving %s",memberKey);
  374. return false;
  375. }
  376. if (!_get(revKey,revision)) {
  377. LOG("netconf: Redis error retrieving %s",revKey);
  378. return false;
  379. }
  380. if (!revision.length())
  381. revision = "0";
  382. bool isPrivate = networkRecord.getBoolean("private",true);
  383. ts = Utils::now();
  384. Utils::snprintf(tss,sizeof(tss),"%llx",ts);
  385. // Core configuration
  386. nc[ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP] = tss;
  387. nc[ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID] = nwids;
  388. nc[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO] = addrs;
  389. nc[ZT_NETWORKCONFIG_DICT_KEY_PRIVATE] = isPrivate ? "1" : "0";
  390. nc[ZT_NETWORKCONFIG_DICT_KEY_NAME] = networkRecord.get("name",nwids);
  391. nc[ZT_NETWORKCONFIG_DICT_KEY_DESC] = networkRecord.get("desc","");
  392. nc[ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST] = networkRecord.getBoolean("enableBroadcast",true) ? "1" : "0";
  393. nc[ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING] = networkRecord.getBoolean("allowPassiveBridging",false) ? "1" : "0";
  394. nc[ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES] = networkRecord.get("etherTypes","");
  395. // Multicast options
  396. nc[ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES] = networkRecord.get("multicastRates","");
  397. uint64_t ml = networkRecord.getHexUInt("multicastLimit",0);
  398. if (ml > 0)
  399. nc.setHex(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,ml);
  400. // Active bridge configuration
  401. {
  402. std::string activeBridgeList;
  403. std::vector<std::string> activeBridgeSet;
  404. if (!_smembers(abKey,activeBridgeSet)) {
  405. LOG("netconf: Redis error retrieving set %s",abKey);
  406. return false;
  407. }
  408. std::sort(activeBridgeSet.begin(),activeBridgeSet.end());
  409. for(std::vector<std::string>::const_iterator i(activeBridgeSet.begin());i!=activeBridgeSet.end();++i) {
  410. if (i->length() == 10) {
  411. if (activeBridgeList.length() > 0)
  412. activeBridgeList.push_back(',');
  413. activeBridgeList.append(*i);
  414. }
  415. }
  416. if (activeBridgeList.length() > 0)
  417. nc[ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES] = activeBridgeList;
  418. }
  419. // IP address assignment and auto-assign using the ZeroTier-internal mechanism (not DHCP, etc.)
  420. {
  421. std::string ipAssignments(memberRecord.get("ipAssignments",""));
  422. // Get sorted, separated lists of IPv4 and IPv6 IP address assignments already present
  423. std::vector<InetAddress> ip4s,ip6s;
  424. {
  425. std::vector<std::string> ips(Utils::split(ipAssignments.c_str(),",","",""));
  426. for(std::vector<std::string>::iterator i(ips.begin());i!=ips.end();++i) {
  427. InetAddress a(*i);
  428. if (a.isV4())
  429. ip4s.push_back(a);
  430. else if (a.isV6())
  431. ip6s.push_back(a);
  432. }
  433. }
  434. std::sort(ip4s.begin(),ip4s.end());
  435. std::unique(ip4s.begin(),ip4s.end());
  436. std::sort(ip6s.begin(),ip6s.end());
  437. std::unique(ip6s.begin(),ip6s.end());
  438. // If IPv4 assignment mode is 'zt', send them to the client
  439. if (networkRecord.get("v4AssignMode","") == "zt") {
  440. // If we have no IPv4 addresses and we have an assignment pool, auto-assign
  441. if (ip4s.empty()) {
  442. InetAddress v4AssignPool(networkRecord.get("v4AssignPool",""));
  443. uint32_t pnet = Utils::ntoh(*((const uint32_t *)v4AssignPool.rawIpData()));
  444. unsigned int pbits = v4AssignPool.netmaskBits();
  445. if ((v4AssignPool.isV4())&&(pbits > 0)&&(pbits < 32)&&(pnet != 0)) {
  446. uint32_t pmask = 0xffffffff << (32 - pbits); // netmask over network part
  447. uint32_t invmask = ~pmask; // netmask over "random" part
  448. // Begin exploring the IP space by generating an IP from the ZeroTier address
  449. uint32_t first = (((uint32_t)(member.toInt() & 0xffffffffULL)) & invmask) | (pnet & pmask);
  450. if ((first & 0xff) == 0)
  451. first |= 1;
  452. else if ((first & 0xff) == 0xff)
  453. first &= 0xfe;
  454. // Start by trying this first IP
  455. uint32_t abcd = first;
  456. InetAddress ip;
  457. bool gotone = false;
  458. unsigned long sanityCounter = 0;
  459. do {
  460. // Convert to IPv4 InetAddress
  461. uint32_t abcdNetworkByteOrder = Utils::hton(abcd);
  462. ip.set(&abcdNetworkByteOrder,4,pbits);
  463. // Is 'ip' already assigned to another node?
  464. std::string assignment;
  465. if (!_hget(ipaKey,ip.toString().c_str(),assignment)) {
  466. LOG("netconf: Redis error checking IP allocation in %s",ipaKey);
  467. return false;
  468. }
  469. if ((assignment.length() != 10)||(assignment == member.toString())) {
  470. gotone = true;
  471. break; // not taken!
  472. }
  473. // If we made it here, the IP was taken so increment and mask and try again
  474. ++abcd;
  475. abcd &= invmask;
  476. abcd |= (pnet & pmask);
  477. if ((abcd & 0xff) == 0)
  478. abcd |= 1;
  479. else if ((abcd & 0xff) == 0xff)
  480. abcd &= 0xfe;
  481. // Don't spend insane amounts of time here -- if we have to try this hard, the user
  482. // needs to allocate a larger IP block.
  483. if (++sanityCounter >= 65535)
  484. break;
  485. } while (abcd != first); // keep going until we loop back around to 'first'
  486. // If we got one, add to IP list and claim in database
  487. if (gotone) {
  488. ip4s.push_back(ip);
  489. _hset(ipaKey,ip.toString().c_str(),member.toString().c_str());
  490. if (ipAssignments.length() > 0)
  491. ipAssignments.push_back(',');
  492. ipAssignments.append(ip.toString());
  493. _hset(memberKey,"ipAssignments",ipAssignments.c_str());
  494. } else {
  495. LOG("netconf: failed to allocate IP in %s for %s in network %s, need a larger pool!",v4AssignPool.toString().c_str(),addrs,nwids);
  496. }
  497. }
  498. }
  499. // Create comma-delimited list to send to client
  500. std::string v4s;
  501. for(std::vector<InetAddress>::iterator i(ip4s.begin());i!=ip4s.end();++i) {
  502. if (v4s.length() > 0)
  503. v4s.push_back(',');
  504. v4s.append(i->toString());
  505. }
  506. if (v4s.length())
  507. nc[ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC] = v4s;
  508. }
  509. if (networkRecord.get("v6AssignMode","") == "zt") {
  510. // TODO: IPv6 auto-assign ... not quite baked yet. :)
  511. std::string v6s;
  512. for(std::vector<InetAddress>::iterator i(ip6s.begin());i!=ip6s.end();++i) {
  513. if (v6s.length() > 0)
  514. v6s.push_back(',');
  515. v6s.append(i->toString());
  516. }
  517. if (v6s.length())
  518. nc[ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC] = v6s;
  519. }
  520. }
  521. // If this is a private network, generate a signed certificate of membership
  522. if (isPrivate) {
  523. CertificateOfMembership com(Utils::strToU64(revision.c_str()),1,nwid,member);
  524. if (com.sign(RR->identity)) // basically can't fail unless our identity is invalid
  525. nc[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP] = com.toString();
  526. else {
  527. LOG("netconf: failure signing certificate (identity problem?)");
  528. return false;
  529. }
  530. }
  531. // Sign netconf dictionary itself
  532. if (!nc.sign(RR->identity)) {
  533. LOG("netconf: failure signing dictionary (identity problem?)");
  534. return false;
  535. }
  536. // Convert to string-serialized form into result paramter
  537. netconf = nc.toString();
  538. // Record new netconf in database for re-use on subsequent repeat queries
  539. {
  540. Dictionary upd;
  541. upd["netconf"] = netconf;
  542. upd["netconfTimestamp"] = tss;
  543. upd["netconfRevision"] = revision;
  544. if (!_hmset(memberKey,upd)) {
  545. LOG("netconf: Redis error writing to key %s",memberKey);
  546. return false;
  547. }
  548. }
  549. return true;
  550. }
  551. } // namespace ZeroTier
  552. #endif // ZT_ENABLE_NETCONF_MASTER