|
@@ -0,0 +1,362 @@
|
|
|
+/*
|
|
|
+ * ZeroTier One - Global Peer to Peer Ethernet
|
|
|
+ * Copyright (C) 2011-2014 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 <stdlib.h>
|
|
|
+#include <stdint.h>
|
|
|
+
|
|
|
+#include <string>
|
|
|
+#include <map>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
+#include "node/Constants.hpp"
|
|
|
+#include "node/Node.hpp"
|
|
|
+#include "node/Utils.hpp"
|
|
|
+#include "node/Address.hpp"
|
|
|
+#include "node/Identity.hpp"
|
|
|
+#include "node/Thread.hpp"
|
|
|
+#include "node/CMWC4096.hpp"
|
|
|
+
|
|
|
+#include "testnet/SimNet.hpp"
|
|
|
+#include "testnet/SimNetSocketManager.hpp"
|
|
|
+#include "testnet/TestEthernetTap.hpp"
|
|
|
+#include "testnet/TestEthernetTapFactory.hpp"
|
|
|
+#include "testnet/TestRoutingTable.hpp"
|
|
|
+
|
|
|
+#ifdef __WINDOWS__
|
|
|
+#include <windows.h>
|
|
|
+#else
|
|
|
+#include <unistd.h>
|
|
|
+#include <sys/stat.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+using namespace ZeroTier;
|
|
|
+
|
|
|
+class SimNode
|
|
|
+{
|
|
|
+public:
|
|
|
+ SimNode(SimNet &net,const std::string &hp,const char *rootTopology,bool issn,const InetAddress &addr) :
|
|
|
+ home(hp),
|
|
|
+ tapFactory(),
|
|
|
+ routingTable(),
|
|
|
+ socketManager(net.newEndpoint(addr)),
|
|
|
+ node(home.c_str(),&tapFactory,&routingTable,socketManager,false,rootTopology),
|
|
|
+ reasonForTermination(Node::NODE_RUNNING),
|
|
|
+ supernode(issn)
|
|
|
+ {
|
|
|
+ thread = Thread::start(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ ~SimNode()
|
|
|
+ {
|
|
|
+ node.terminate(Node::NODE_NORMAL_TERMINATION,"SimNode shutdown");
|
|
|
+ Thread::join(thread);
|
|
|
+ }
|
|
|
+
|
|
|
+ void threadMain()
|
|
|
+ throw()
|
|
|
+ {
|
|
|
+ reasonForTermination = node.run();
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string home;
|
|
|
+ TestEthernetTapFactory tapFactory;
|
|
|
+ TestRoutingTable routingTable;
|
|
|
+ SimNetSocketManager *socketManager;
|
|
|
+ Node node;
|
|
|
+ Node::ReasonForTermination reasonForTermination;
|
|
|
+ bool supernode;
|
|
|
+ Thread thread;
|
|
|
+};
|
|
|
+
|
|
|
+static std::string basePath;
|
|
|
+static SimNet net;
|
|
|
+static std::map< Address,SimNode * > nodes;
|
|
|
+static std::map< InetAddress,Address > usedIps;
|
|
|
+static CMWC4096 prng;
|
|
|
+static std::string rootTopology;
|
|
|
+
|
|
|
+// Converts an address into a fake IP not already claimed.
|
|
|
+// Be sure to call only once, as this claims the IP before returning it.
|
|
|
+static InetAddress inetAddressFromZeroTierAddress(const Address &addr)
|
|
|
+{
|
|
|
+ uint32_t ip = (uint32_t)(addr.toInt() & 0xffffffff);
|
|
|
+ for(;;) {
|
|
|
+ if (((ip >> 24) & 0xff) >= 240) {
|
|
|
+ ip &= 0x00ffffff;
|
|
|
+ ip |= (((ip >> 24) & 0xff) % 240) << 24;
|
|
|
+ }
|
|
|
+ if (((ip >> 24) & 0xff) == 0)
|
|
|
+ ip |= 0x01000000;
|
|
|
+ if (((ip & 0xff) == 0)||((ip & 0xff) == 255))
|
|
|
+ ip ^= 0x00000001;
|
|
|
+ InetAddress inaddr(Utils::hton(ip),9993);
|
|
|
+ if (usedIps.find(inaddr) == usedIps.end()) {
|
|
|
+ usedIps[inaddr] = addr;
|
|
|
+ return inaddr;
|
|
|
+ }
|
|
|
+ ++ip; // keep looking sequentially for an unclaimed IP
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static Identity makeNodeHome(bool super)
|
|
|
+{
|
|
|
+ Identity id;
|
|
|
+ id.generate();
|
|
|
+
|
|
|
+ std::string path(basePath + ZT_PATH_SEPARATOR_S + (super ? "S" : "N") + id.address().toString());
|
|
|
+
|
|
|
+#ifdef __WINDOWS__
|
|
|
+ CreateDirectoryA(path.c_str(),NULL);
|
|
|
+#else
|
|
|
+ mkdir(path.c_str(),0700);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (!Utils::writeFile((path + ZT_PATH_SEPARATOR_S + "identity.secret"),id.toString(true)))
|
|
|
+ return Identity();
|
|
|
+ if (!Utils::writeFile((path + ZT_PATH_SEPARATOR_S + "identity.public"),id.toString(false)))
|
|
|
+ return Identity();
|
|
|
+
|
|
|
+ return id;
|
|
|
+}
|
|
|
+
|
|
|
+// Instantiates supernodes by scanning for S########## subdirectories
|
|
|
+static std::vector<Address> initSupernodes()
|
|
|
+{
|
|
|
+ Dictionary supernodes;
|
|
|
+ std::vector< std::pair<Identity,InetAddress> > snids;
|
|
|
+ std::map<std::string,bool> dir(Utils::listDirectory(basePath.c_str()));
|
|
|
+
|
|
|
+ for(std::map<std::string,bool>::iterator d(dir.begin());d!=dir.end();++d) {
|
|
|
+ if ((d->first.length() == 11)&&(d->second)&&(d->first[0] == 'S')) {
|
|
|
+ std::string idbuf;
|
|
|
+ if (Utils::readFile((basePath + ZT_PATH_SEPARATOR_S + d->first + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),idbuf)) {
|
|
|
+ Identity id(idbuf);
|
|
|
+ if (id) {
|
|
|
+ InetAddress inaddr(inetAddressFromZeroTierAddress(id.address()));
|
|
|
+ snids.push_back(std::pair<Identity,InetAddress>(id,inaddr));
|
|
|
+
|
|
|
+ Dictionary snd;
|
|
|
+ snd["id"] = id.toString(false);
|
|
|
+ snd["udp"] = inaddr.toString();
|
|
|
+ snd["desc"] = id.address().toString();
|
|
|
+ snd["dns"] = inaddr.toIpString();
|
|
|
+ supernodes[id.address().toString()] = snd.toString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Dictionary rtd;
|
|
|
+ rtd["supernodes"] = supernodes.toString();
|
|
|
+ rtd["noupdate"] = "1";
|
|
|
+ rootTopology = rtd.toString();
|
|
|
+
|
|
|
+ std::vector<Address> newNodes;
|
|
|
+
|
|
|
+ for(std::vector< std::pair<Identity,InetAddress> >::iterator i(snids.begin());i!=snids.end();++i) {
|
|
|
+ SimNode *n = new SimNode(net,(basePath + ZT_PATH_SEPARATOR_S + "S" + i->first.address().toString()),rootTopology.c_str(),true,i->second);
|
|
|
+ nodes[id.address()] = n;
|
|
|
+ newNodes.push_back(id.address());
|
|
|
+ }
|
|
|
+
|
|
|
+ return newNodes;
|
|
|
+}
|
|
|
+
|
|
|
+// Instantiates any not-already-instantiated regular nodes
|
|
|
+static std::vector<Address> scanForNewNodes()
|
|
|
+{
|
|
|
+ std::vector<Address> newNodes;
|
|
|
+ std::map<std::string,bool> dir(Utils::listDirectory(basePath.c_str()));
|
|
|
+
|
|
|
+ for(std::map<std::string,bool>::iterator d(dir.begin());d!=dir.end();++d) {
|
|
|
+ if ((d->first.length() == 11)&&(d->second)&&(d->first[0] == 'N')) {
|
|
|
+ Address na(d->first.c_str() + 1);
|
|
|
+ if (nodes.find(na) == nodes.end()) {
|
|
|
+ InetAddress inaddr(inetAddressFromZeroTierAddress(na));
|
|
|
+
|
|
|
+ SimNode *n = new SimNode(net,(basePath + ZT_PATH_SEPARATOR_S + d->first),rootTopology.c_str(),false,inaddr);
|
|
|
+ nodes[na] = n;
|
|
|
+
|
|
|
+ newNodes.push_back(na);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return newNodes;
|
|
|
+}
|
|
|
+
|
|
|
+static void doHelp(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+ printf("---------- help"ZT_EOL_S);
|
|
|
+ printf("---------- mksn <number of supernodes>"ZT_EOL_S);
|
|
|
+ printf("---------- mkn <number of normal nodes>"ZT_EOL_S);
|
|
|
+ printf("---------- list"ZT_EOL_S);
|
|
|
+ printf("---------- join <address/*> <network ID>"ZT_EOL_S);
|
|
|
+ printf("---------- leave <address/*> <network ID>"ZT_EOL_S);
|
|
|
+ printf("---------- listnetworks <address/*>"ZT_EOL_S);
|
|
|
+ printf("---------- listpeers <address/*>"ZT_EOL_S);
|
|
|
+ printf("---------- alltoall"ZT_EOL_S);
|
|
|
+ printf("---------- quit"ZT_EOL_S)
|
|
|
+}
|
|
|
+
|
|
|
+static void doMKSN(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+ if (cmd.size() < 2) {
|
|
|
+ doHelp(cmd);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (nodes.size() > 0) {
|
|
|
+ printf("---------- mksn error: mksn can only be called once (network already exists)"ZT_EOL_S,(unsigned int)nodes.size());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ int count = Utils::strToInt(cmd[1].c_str());
|
|
|
+ for(int i=0;i<count;++i) {
|
|
|
+ Identity id(makeNodeHome(true));
|
|
|
+ printf("%s identity created"ZT_EOL_S,id.address().toString().c_str());
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<Address> nodes(initSupernodes());
|
|
|
+ for(std::vector<Address>::iterator a(nodes.begin());a!=nodes.end();++a)
|
|
|
+ printf("%s started (supernode)"ZT_EOL_S,a->toString().c_str());
|
|
|
+
|
|
|
+ printf("---------- root topology is: %s"ZT_EOL_S,rootTopology.c_str());
|
|
|
+}
|
|
|
+
|
|
|
+static void doMKN(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+ if (cmd.size() < 2) {
|
|
|
+ doHelp(cmd);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (nodes.size() == 0) {
|
|
|
+ printf("---------- mkn error: use mksn to create supernodes first."ZT_EOL_S);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void doList(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void doJoin(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void doLeave(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void doListNetworks(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void doListPeers(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void doAllToAll(const std::vector<std::string> &cmd)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc,char **argv)
|
|
|
+{
|
|
|
+ char linebuf[1024];
|
|
|
+
|
|
|
+ if (argc <= 1) {
|
|
|
+ fprintf(stderr,"Usage: %s <base path for temporary node home directories>"ZT_EOL_S,argv[0]);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ basePath = argv[1];
|
|
|
+#ifdef __WINDOWS__
|
|
|
+ CreateDirectoryA(basePath.c_str(),NULL);
|
|
|
+#else
|
|
|
+ mkdir(basePath.c_str(),0700);
|
|
|
+#endif
|
|
|
+
|
|
|
+ printf("*** ZeroTier One Version %s -- Headless Network Simulator ***"ZT_EOL_S,Node::versionString());
|
|
|
+ printf(ZT_EOL_S);
|
|
|
+
|
|
|
+ {
|
|
|
+ printf("---------- scanning '%s' for existing network..."ZT_EOL_S);
|
|
|
+ std::vector<Address> snodes(initSupernodes());
|
|
|
+ if (snodes.empty()) {
|
|
|
+ printf("---------- no existing network found; use 'mksn' to create one."ZT_EOL_S);
|
|
|
+ } else {
|
|
|
+ for(std::vector<Address>::iterator a(snodes.begin());a!=snodes.end();++a)
|
|
|
+ printf("%s started (supernode)"ZT_EOL_S,a->toString().c_str());
|
|
|
+ printf("---------- root topology is: %s"ZT_EOL_S,rootTopology.c_str());
|
|
|
+ std::vector<Address> nodes(scanForNewNodes());
|
|
|
+ for(std::vector<Address>::iterator a(nodes.begin());a!=nodes.end();++a)
|
|
|
+ printf("%s started (normal peer)"ZT_EOL_S,a->toString().c_str());
|
|
|
+ printf("---------- %u peers and %u supernodes loaded!"ZT_EOL_S,(unsigned int)nodes.size(),(unsigned int)snodes.size());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ printf(ZT_EOL_S);
|
|
|
+
|
|
|
+ printf("Type 'help' for help."ZT_EOL_S);
|
|
|
+ printf(ZT_EOL_S);
|
|
|
+
|
|
|
+ for(;;) {
|
|
|
+ printf(">> ");
|
|
|
+ fflush(stdout);
|
|
|
+ if (!fgets(linebuf,sizeof(linebuf),stdin))
|
|
|
+ break;
|
|
|
+ std::vector<std::string> cmd(Utils::split(linebuf," \r\n\t","\\","\""));
|
|
|
+ if (cmd.size() == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (cmd[0] == "quit")
|
|
|
+ break;
|
|
|
+ else if (cmd[0] == "help")
|
|
|
+ doHelp(cmd);
|
|
|
+ else if (cmd[0] == "mksn")
|
|
|
+ doMKSN(cmd);
|
|
|
+ else if (cmd[0] == "mkn")
|
|
|
+ doMKN(cmd);
|
|
|
+ else if (cmd[0] == "join")
|
|
|
+ doJoin(cmd);
|
|
|
+ else if (cmd[0] == "leave")
|
|
|
+ doLeave(cmd);
|
|
|
+ else if (cmd[0] == "listnetworks")
|
|
|
+ doListNetworks(cmd);
|
|
|
+ else if (cmd[0] == "listpeers")
|
|
|
+ doListPeers(cmd);
|
|
|
+ else if (cmd[0] == "alltoall")
|
|
|
+ doAllToAll(cmd);
|
|
|
+ else doHelp(cmd);
|
|
|
+ }
|
|
|
+
|
|
|
+ for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) {
|
|
|
+ printf("%s shutting down..."ZT_EOL_S,n->first.toString().c_str());
|
|
|
+ delete n->second;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|