From a9a370587780d7d0d0e68e850c8e64f4ded419b0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Apr 2015 12:43:10 -0700 Subject: [PATCH 01/10] TCP tunneling implementation -- not tested yet and no initiation yet. --- service/OneService.cpp | 320 +++++++++++++++++++++++++++-------------- 1 file changed, 210 insertions(+), 110 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index a04d46dff..554d59bf6 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -113,17 +113,20 @@ static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageComplete }; -struct HttpConnection +struct TcpConnection { - bool server; - bool writing; + enum { + TCP_HTTP_INCOMING, + TCP_HTTP_OUTGOING, // not currently used + TCP_TUNNEL_OUTGOING // fale-SSL outgoing tunnel -- HTTP-related fields are not used + } type; + bool shouldKeepAlive; OneServiceImpl *parent; PhySocket *sock; InetAddress from; http_parser parser; unsigned long messageSize; - unsigned long writePtr; uint64_t lastActivity; std::string currentHeaderField; @@ -132,7 +135,9 @@ struct HttpConnection std::string url; std::string status; std::map< std::string,std::string > headers; - std::string body; // also doubles as send queue for writes out to the socket + std::string body; + + std::string writeBuf; }; class OneServiceImpl : public OneService @@ -281,8 +286,8 @@ public: } try { - while (!_httpConnections.empty()) - _phy.close(_httpConnections.begin()->first); + while (!_tcpConections.empty()) + _phy.close(_tcpConections.begin()->first); } catch ( ... ) {} { @@ -336,13 +341,13 @@ public: ZT1_ResultCode rc = _node->processWirePacket( OSUtils::now(), (const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big - 0, + 0, // desperation == 0, direct UDP data, len, &_nextBackgroundTaskDeadline); if (ZT1_ResultCode_isFatal(rc)) { char tmp[256]; - Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket(%d)",(int)rc); + Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); Mutex::Lock _l(_termReason_m); _termReason = ONE_UNRECOVERABLE_ERROR; _fatalErrorMessage = tmp; @@ -352,65 +357,162 @@ public: inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) { - // TODO: outgoing HTTP connection success/failure + if (!success) + return; + + // Outgoing connections are right now only tunnel connections + TcpConnection *tc = &(_tcpConections[sock]); + tc->type = TcpConnection::TCP_TUNNEL_OUTGOING; + tc->shouldKeepAlive = true; // unused + tc->parent = this; + tc->sock = sock; + // from and parser are not used + tc->messageSize = 0; // unused + tc->lastActivity = OSUtils::now(); + // HTTP stuff is not used + tc->writeBuf = ""; + *uptr = (void *)tc; + + // Send "hello" message + tc->writeBuf.push_back((char)0x17); + tc->writeBuf.push_back((char)0x03); + tc->writeBuf.push_back((char)0x03); // fake TLS 1.2 header + tc->writeBuf.push_back((char)0x00); + tc->writeBuf.push_back((char)0x04); // mlen == 4 + tc->writeBuf.push_back((char)ZEROTIER_ONE_VERSION_MAJOR); + tc->writeBuf.push_back((char)ZEROTIER_ONE_VERSION_MINOR); + tc->writeBuf.push_back((char)((ZEROTIER_ONE_VERSION_REVISION >> 8) & 0xff)); + tc->writeBuf.push_back((char)(ZEROTIER_ONE_VERSION_REVISION & 0xff)); + _phy.tcpSetNotifyWritable(sock,true); } inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) { - HttpConnection *htc = &(_httpConnections[sockN]); - htc->server = true; - htc->writing = false; - htc->shouldKeepAlive = true; - htc->parent = this; - htc->sock = sockN; - htc->from = from; - http_parser_init(&(htc->parser),HTTP_REQUEST); - htc->parser.data = (void *)htc; - htc->messageSize = 0; - htc->writePtr = 0; - htc->lastActivity = OSUtils::now(); - htc->currentHeaderField = ""; - htc->currentHeaderValue = ""; - htc->url = ""; - htc->status = ""; - htc->headers.clear(); - htc->body = ""; - *uptrN = (void *)htc; + // Incoming connections are TCP HTTP requests + TcpConnection *tc = &(_tcpConections[sockN]); + tc->type = TcpConnection::TCP_HTTP_INCOMING; + tc->shouldKeepAlive = true; + tc->parent = this; + tc->sock = sockN; + tc->from = from; + http_parser_init(&(tc->parser),HTTP_REQUEST); + tc->parser.data = (void *)tc; + tc->messageSize = 0; + tc->lastActivity = OSUtils::now(); + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; + tc->url = ""; + tc->status = ""; + tc->headers.clear(); + tc->body = ""; + tc->writeBuf = ""; + *uptrN = (void *)tc; } inline void phyOnTcpClose(PhySocket *sock,void **uptr) { - _httpConnections.erase(sock); + _tcpConections.erase(sock); } inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) { - HttpConnection *htc = reinterpret_cast(*uptr); - http_parser_execute(&(htc->parser),&HTTP_PARSER_SETTINGS,(const char *)data,len); - if ((htc->parser.upgrade)||(htc->parser.http_errno != HPE_OK)) - _phy.close(sock); + TcpConnection *tc = reinterpret_cast(*uptr); + switch(tc->type) { + case TcpConnection::TCP_HTTP_INCOMING: + case TcpConnection::TCP_HTTP_OUTGOING: + http_parser_execute(&(tc->parser),&HTTP_PARSER_SETTINGS,(const char *)data,len); + if ((tc->parser.upgrade)||(tc->parser.http_errno != HPE_OK)) { + _phy.close(sock); + return; + } + break; + case TcpConnection::TCP_TUNNEL_OUTGOING: + tc->body.append((const char *)data,len); + if (tc->body.length() > 65535) { + // sanity limit -- a message will never be this big since mlen is 16-bit + _phy.close(sock); + return; + } else if (tc->body.length() >= 5) { + const char *data = tc->body.data(); + const unsigned long mlen = ( ((((unsigned long)data[3]) & 0xff) << 8) | (((unsigned long)data[4]) & 0xff) ); + if (tc->body.length() >= (mlen + 5)) { + InetAddress from; + + unsigned long plen = mlen; // payload length, modified if there's an IP header + data += 5; + if (mlen == 4) { + // Hello message, which isn't sent by proxy and would be ignored by client + } else if (mlen) { + // Messages should contain IPv4 or IPv6 source IP address data + switch(data[0]) { + case 4: // IPv4 + if (plen >= 7) { + from.set((const void *)(data + 1),4,((((unsigned int)data[5]) & 0xff) << 8) | (((unsigned int)data[6]) & 0xff)); + data += 7; // type + 4 byte IP + 2 byte port + plen -= 7; + } + break; + case 6: // IPv6 + if (plen >= 19) { + from.set((const void *)(data + 1),16,((((unsigned int)data[17]) & 0xff) << 8) | (((unsigned int)data[18]) & 0xff)); + data += 19; // type + 16 byte IP + 2 byte port + plen -= 19; + } + break; + case 0: // none/omitted + break; + default: // invalid + _phy.close(sock); + return; + } + if (!from) { // missing IP header + _phy.close(sock); + return; + } + } + + ZT1_ResultCode rc = _node->processWirePacket( + OSUtils::now(), + (const struct sockaddr_storage *)&from, // Phy<> uses sockaddr_storage, so it'll always be that big + 1, // desperation == 1, TCP tunnel proxy + data, + plen, + &_nextBackgroundTaskDeadline); + if (ZT1_ResultCode_isFatal(rc)) { + char tmp[256]; + Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = tmp; + this->terminate(); + _phy.close(sock); + return; + } + + if (tc->body.length() > (mlen + 5)) + tc->body = tc->body.substr(mlen + 5); + else tc->body = ""; + } + } + break; + } } inline void phyOnTcpWritable(PhySocket *sock,void **uptr) { - HttpConnection *htc = reinterpret_cast(*uptr); - long sent = _phy.tcpSend(sock,htc->body.data() + htc->writePtr,(unsigned long)htc->body.length() - htc->writePtr,true); - if (sent < 0) { - return; // close handler will have been called, so everything's dead - } else { - htc->lastActivity = OSUtils::now(); - htc->writePtr += sent; - if (htc->writePtr >= htc->body.length()) { - _phy.tcpSetNotifyWritable(sock,false); - if (htc->shouldKeepAlive) { - htc->writing = false; - htc->writePtr = 0; - htc->body = ""; - } else { - _phy.close(sock); // will call close handler to delete from _httpConnections - } + TcpConnection *tc = reinterpret_cast(*uptr); + if (tc->writeBuf.length()) { + long sent = _phy.tcpSend(sock,tc->writeBuf.data(),tc->writeBuf.length(),true); + if (sent > 0) { + tc->lastActivity = OSUtils::now(); + if (sent == tc->writeBuf.length()) { + tc->writeBuf = ""; + _phy.tcpSetNotifyWritable(sock,false); + if (!tc->shouldKeepAlive) + _phy.close(sock); // will call close handler to delete from _tcpConections + } else tc->writeBuf = tc->writeBuf.substr(sent); } - } + } else _phy.tcpSetNotifyWritable(sock,false); // sanity check... shouldn't happen } inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwc) @@ -586,7 +688,7 @@ public: _node->processVirtualNetworkFrame(OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline); } - inline void onHttpRequestToServer(HttpConnection *htc) + inline void onHttpRequestToServer(TcpConnection *tc) { char tmpn[256]; std::string data; @@ -595,7 +697,7 @@ public: try { if (_controlPlane) - scode = _controlPlane->handleRequest(htc->from,htc->parser.method,htc->url,htc->headers,htc->body,data,contentType); + scode = _controlPlane->handleRequest(tc->from,tc->parser.method,tc->url,tc->headers,tc->body,data,contentType); else scode = 500; } catch ( ... ) { scode = 500; @@ -615,26 +717,24 @@ public: } Utils::snprintf(tmpn,sizeof(tmpn),"HTTP/1.1 %.3u %s\r\nCache-Control: no-cache\r\nPragma: no-cache\r\n",scode,scodestr); - htc->body.assign(tmpn); - htc->body.append("Content-Type: "); - htc->body.append(contentType); + tc->writeBuf.assign(tmpn); + tc->writeBuf.append("Content-Type: "); + tc->writeBuf.append(contentType); Utils::snprintf(tmpn,sizeof(tmpn),"\r\nContent-Length: %lu\r\n",(unsigned long)data.length()); - htc->body.append(tmpn); - if (!htc->shouldKeepAlive) - htc->body.append("Connection: close\r\n"); - htc->body.append("\r\n"); - if (htc->parser.method != HTTP_HEAD) - htc->body.append(data); + tc->writeBuf.append(tmpn); + if (!tc->shouldKeepAlive) + tc->writeBuf.append("Connection: close\r\n"); + tc->writeBuf.append("\r\n"); + if (tc->parser.method != HTTP_HEAD) + tc->writeBuf.append(data); - htc->writing = true; - htc->writePtr = 0; - _phy.tcpSetNotifyWritable(htc->sock,true); + _phy.tcpSetNotifyWritable(tc->sock,true); } - inline void onHttpResponseFromClient(HttpConnection *htc) + inline void onHttpResponseFromClient(TcpConnection *tc) { - if (!htc->shouldKeepAlive) - _phy.close(htc->sock); // will call close handler, which deletes from _httpConnections + if (!tc->shouldKeepAlive) + _phy.close(tc->sock); // will call close handler, which deletes from _tcpConections } private: @@ -671,7 +771,7 @@ private: std::map< uint64_t,std::vector > _tapAssignedIps; // ZeroTier assigned IPs, not user or dhcp assigned Mutex _taps_m; - std::map< PhySocket *,HttpConnection > _httpConnections; // no mutex for this since it's done in the main loop thread only + std::map< PhySocket *,TcpConnection > _tcpConections; // no mutex for this since it's done in the main loop thread only ReasonForTermination _termReason; std::string _fatalErrorMessage; @@ -699,83 +799,83 @@ static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC static int ShttpOnMessageBegin(http_parser *parser) { - HttpConnection *htc = reinterpret_cast(parser->data); - htc->currentHeaderField = ""; - htc->currentHeaderValue = ""; - htc->messageSize = 0; - htc->url = ""; - htc->status = ""; - htc->headers.clear(); - htc->body = ""; + TcpConnection *tc = reinterpret_cast(parser->data); + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; + tc->messageSize = 0; + tc->url = ""; + tc->status = ""; + tc->headers.clear(); + tc->body = ""; return 0; } static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) { - HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += (unsigned long)length; - if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; - htc->url.append(ptr,length); + tc->url.append(ptr,length); return 0; } static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) { - HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += (unsigned long)length; - if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; - htc->status.append(ptr,length); + tc->status.append(ptr,length); return 0; } static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) { - HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += (unsigned long)length; - if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; - if ((htc->currentHeaderField.length())&&(htc->currentHeaderValue.length())) { - htc->headers[htc->currentHeaderField] = htc->currentHeaderValue; - htc->currentHeaderField = ""; - htc->currentHeaderValue = ""; + if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) { + tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; } for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); + tc->currentHeaderField.push_back(OSUtils::toLower(ptr[i])); return 0; } static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) { - HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += (unsigned long)length; - if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; - htc->currentHeaderValue.append(ptr,length); + tc->currentHeaderValue.append(ptr,length); return 0; } static int ShttpOnHeadersComplete(http_parser *parser) { - HttpConnection *htc = reinterpret_cast(parser->data); - if ((htc->currentHeaderField.length())&&(htc->currentHeaderValue.length())) - htc->headers[htc->currentHeaderField] = htc->currentHeaderValue; + TcpConnection *tc = reinterpret_cast(parser->data); + if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) + tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; return 0; } static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) { - HttpConnection *htc = reinterpret_cast(parser->data); - htc->messageSize += (unsigned long)length; - if (htc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + TcpConnection *tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) return -1; - htc->body.append(ptr,length); + tc->body.append(ptr,length); return 0; } static int ShttpOnMessageComplete(http_parser *parser) { - HttpConnection *htc = reinterpret_cast(parser->data); - htc->shouldKeepAlive = (http_should_keep_alive(parser) != 0); - htc->lastActivity = OSUtils::now(); - if (htc->server) { - htc->parent->onHttpRequestToServer(htc); + TcpConnection *tc = reinterpret_cast(parser->data); + tc->shouldKeepAlive = (http_should_keep_alive(parser) != 0); + tc->lastActivity = OSUtils::now(); + if (tc->type == TcpConnection::TCP_HTTP_INCOMING) { + tc->parent->onHttpRequestToServer(tc); } else { - htc->parent->onHttpResponseFromClient(htc); + tc->parent->onHttpResponseFromClient(tc); } return 0; } From 288d73a4adc5452ffecb5675c6c52ce67aa00159 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 10:47:27 -0700 Subject: [PATCH 02/10] A few more refinements to TCP code, ready to integrate with "desperation" stuff and test. --- service/OneService.cpp | 51 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index 554d59bf6..3886c1573 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -439,10 +439,10 @@ public: InetAddress from; unsigned long plen = mlen; // payload length, modified if there's an IP header - data += 5; - if (mlen == 4) { + data += 5; // skip forward past pseudo-TLS junk and mlen + if (plen == 4) { // Hello message, which isn't sent by proxy and would be ignored by client - } else if (mlen) { + } else if (plen) { // Messages should contain IPv4 or IPv6 source IP address data switch(data[0]) { case 4: // IPv4 @@ -450,6 +450,9 @@ public: from.set((const void *)(data + 1),4,((((unsigned int)data[5]) & 0xff) << 8) | (((unsigned int)data[6]) & 0xff)); data += 7; // type + 4 byte IP + 2 byte port plen -= 7; + } else { + _phy.close(sock); + return; } break; case 6: // IPv6 @@ -457,38 +460,38 @@ public: from.set((const void *)(data + 1),16,((((unsigned int)data[17]) & 0xff) << 8) | (((unsigned int)data[18]) & 0xff)); data += 19; // type + 16 byte IP + 2 byte port plen -= 19; + } else { + _phy.close(sock); + return; } break; case 0: // none/omitted + ++data; + --plen; break; - default: // invalid + default: // invalid address type _phy.close(sock); return; } - if (!from) { // missing IP header + + ZT1_ResultCode rc = _node->processWirePacket( + OSUtils::now(), + (const struct sockaddr_storage *)&from, // Phy<> uses sockaddr_storage, so it'll always be that big + 1, // desperation == 1, TCP tunnel proxy + data, + plen, + &_nextBackgroundTaskDeadline); + if (ZT1_ResultCode_isFatal(rc)) { + char tmp[256]; + Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = tmp; + this->terminate(); _phy.close(sock); return; } } - - ZT1_ResultCode rc = _node->processWirePacket( - OSUtils::now(), - (const struct sockaddr_storage *)&from, // Phy<> uses sockaddr_storage, so it'll always be that big - 1, // desperation == 1, TCP tunnel proxy - data, - plen, - &_nextBackgroundTaskDeadline); - if (ZT1_ResultCode_isFatal(rc)) { - char tmp[256]; - Utils::snprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = tmp; - this->terminate(); - _phy.close(sock); - return; - } - if (tc->body.length() > (mlen + 5)) tc->body = tc->body.substr(mlen + 5); else tc->body = ""; From 226e0f8722179b3a08eb14ad34fe03d5b0720888 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 10:56:45 -0700 Subject: [PATCH 03/10] docs and Makefile for tcp-proxy --- tcp-proxy/Makefile | 7 +++++++ tcp-proxy/tcp-proxy.cpp | 27 +++++++++++++++++---------- 2 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 tcp-proxy/Makefile diff --git a/tcp-proxy/Makefile b/tcp-proxy/Makefile new file mode 100644 index 000000000..af4e71e3a --- /dev/null +++ b/tcp-proxy/Makefile @@ -0,0 +1,7 @@ +CXX=$(shell which clang++ g++ c++ 2>/dev/null | head -n 1) + +all: + $(CXX) -O3 -fno-rtti -o tcp-proxy tcp-proxy.cpp + +clean: + rm -f *.o tcp-proxy *.dSYM diff --git a/tcp-proxy/tcp-proxy.cpp b/tcp-proxy/tcp-proxy.cpp index 6837803f2..9e3f5d079 100644 --- a/tcp-proxy/tcp-proxy.cpp +++ b/tcp-proxy/tcp-proxy.cpp @@ -48,6 +48,8 @@ using namespace ZeroTier; /* + * ZeroTier TCP Proxy Server + * * This implements a simple packet encapsulation that is designed to look like * a TLS connection. It's not a TLS connection, but it sends TLS format record * headers. It could be extended in the future to implement a fake TLS @@ -60,21 +62,26 @@ using namespace ZeroTier; * <[2] payload length> - 16-bit length of payload in bytes * <[...] payload> - Message payload * - * The primary purpose of TCP sockets is to work over ports like HTTPS(443), - * allowing users behind particularly fascist firewalls to at least reach - * ZeroTier's supernodes. UDP is the preferred method of communication as - * encapsulating L2 and L3 protocols over TCP is inherently inefficient - * due to double-ACKs. So TCP is only used as a fallback. + * TCP is inherently inefficient for encapsulating Ethernet, since TCP and TCP + * like protocols over TCP lead to double-ACKs. So this transport is only used + * to enable access when UDP or other datagram protocols are not available. * - * New clients send a HELLO message consisting of a 4-byte message (too small - * for a ZT packet) containing: + * Clients send a greeting, which is a four-byte message that contains: * <[1] ZeroTier major version> * <[1] minor version> * <[2] revision> * - * Clients that have send a HELLO and that have a new enough version prepend - * each payload with the remote IP the message is destined for. This is in - * the same format as the IP portion of ZeroTier HELLO packets. + * If a client has sent a greeting, it uses the new version of this protocol + * in which every encapsulated ZT packet is prepended by an IP address where + * it should be forwarded (or where it came from for replies). This causes + * this proxy to act as a remote UDP socket similar to a socks proxy, which + * will allow us to move this function off the supernodes and onto dedicated + * proxy nodes. + * + * Older ZT clients that do not send this message get their packets relayed + * to/from 127.0.0.1:9993, which will allow them to talk to and relay via + * the ZT node on the same machine as the proxy. We'll only support this for + * as long as such nodes appear to be in the wild. */ struct TcpProxyService; From f3d7c9d681d6badff866c31041ba81e6fc2a882b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 15:16:21 -0700 Subject: [PATCH 04/10] Helps to index the array when enumerating a C array. --- service/ControlPlane.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index e40aad9b3..3604dd1e1 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -71,13 +71,13 @@ static std::string _jsonEnumerate(const ZT1_MulticastGroup *mg,unsigned int coun if (i > 0) buf.push_back(','); Utils::snprintf(tmp,sizeof(tmp),"\"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\\/%.8lx\"", - (unsigned int)((mg->mac >> 40) & 0xff), - (unsigned int)((mg->mac >> 32) & 0xff), - (unsigned int)((mg->mac >> 24) & 0xff), - (unsigned int)((mg->mac >> 16) & 0xff), - (unsigned int)((mg->mac >> 8) & 0xff), - (unsigned int)(mg->mac & 0xff), - mg->adi); + (unsigned int)((mg[i].mac >> 40) & 0xff), + (unsigned int)((mg[i].mac >> 32) & 0xff), + (unsigned int)((mg[i].mac >> 24) & 0xff), + (unsigned int)((mg[i].mac >> 16) & 0xff), + (unsigned int)((mg[i].mac >> 8) & 0xff), + (unsigned int)(mg[i].mac & 0xff), + (unsigned long)(mg[i].adi)); buf.append(tmp); } buf.push_back(']'); @@ -92,7 +92,7 @@ static std::string _jsonEnumerate(const struct sockaddr_storage *ss,unsigned int if (i > 0) buf.push_back(','); buf.push_back('"'); - buf.append(_jsonEscape(reinterpret_cast(ss)->toString())); + buf.append(_jsonEscape(reinterpret_cast(&(ss[i]))->toString())); buf.push_back('"'); } buf.push_back(']'); From 918fc8884b142452e350ff32beb90b34bbd442c1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 15:31:01 -0700 Subject: [PATCH 05/10] Update mktopology so it works again and can easily be used to create test dictionaries. --- root-topology/Makefile | 2 +- root-topology/mktopology.cpp | 47 ++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/root-topology/Makefile b/root-topology/Makefile index 58226fd0e..3ddd916f0 100644 --- a/root-topology/Makefile +++ b/root-topology/Makefile @@ -1,5 +1,5 @@ all: FORCE - g++ -o mktopology mktopology.cpp ../node/Utils.cpp ../node/Identity.cpp ../node/C25519.cpp ../node/Salsa20.cpp ../node/Dictionary.cpp ../node/SHA512.cpp + g++ -o mktopology mktopology.cpp ../osdep/OSUtils.cpp ../node/Utils.cpp ../node/InetAddress.cpp ../node/Identity.cpp ../node/C25519.cpp ../node/Salsa20.cpp ../node/Dictionary.cpp ../node/SHA512.cpp gcc -o bin2c bin2c.c official: FORCE diff --git a/root-topology/mktopology.cpp b/root-topology/mktopology.cpp index 2a551cf73..00ada7b76 100644 --- a/root-topology/mktopology.cpp +++ b/root-topology/mktopology.cpp @@ -6,7 +6,7 @@ #include #include -#include "../node/Utils.hpp" +#include "../osdep/OSUtils.hpp" #include "../node/Identity.hpp" #include "../node/Dictionary.hpp" @@ -17,47 +17,48 @@ int main(int argc,char **argv) std::string buf; // Read root-topology-authority.secret signing authority, must be symlinked and online - if (!Utils::readFile("root-topology-authority.secret",buf)) { - std::cerr << "Cannot read root-topology-authority.secret" << std::endl; - return 1; - } - Identity topologyAuthority(buf); + Identity topologyAuthority; + if (OSUtils::readFile("root-topology-authority.secret",buf)) + topologyAuthority.fromString(buf); + else std::cerr << "Warning: root-topology-authority.secret not found, creating unsigned topology." << std::endl; Dictionary topology; // Read template.dict to populate default fields in root topology // if this file exists. Otherwise we just start empty. buf.clear(); - if (Utils::readFile("template.dict",buf)) + if (OSUtils::readFile("template.dict",buf)) topology.fromString(buf); // Read all entries in supernodes/ that correspond to supernode entry dictionaries // and add them to topology under supernodes/ subkey. Dictionary supernodes; - std::map supernodeDictionaries(Utils::listDirectory("supernodes")); - for(std::map::iterator sn(supernodeDictionaries.begin());sn!=supernodeDictionaries.end();++sn) { - if ((sn->first.length() == 10)&&(!sn->second)) { + std::vector supernodeDictionaries(OSUtils::listDirectory("supernodes")); + for(std::vector::const_iterator sn(supernodeDictionaries.begin());sn!=supernodeDictionaries.end();++sn) { + if (sn->length() == 10) { buf.clear(); - if (!Utils::readFile((std::string("supernodes/")+sn->first).c_str(),buf)) { - std::cerr << "Cannot read supernodes/" << sn->first << std::endl; + if (!OSUtils::readFile((std::string("supernodes/")+(*sn)).c_str(),buf)) { + std::cerr << "Cannot read supernodes/" << *sn << std::endl; return 1; } - supernodes[sn->first] = buf; + supernodes[*sn] = buf; } } topology["supernodes"] = supernodes.toString(); - // Sign topology with root-topology-authority.secret - if (!topology.sign(topologyAuthority)) { - std::cerr << "Unable to sign!" << std::endl; - return 1; - } + if ((topologyAuthority)&&(topologyAuthority.hasPrivate())) { + // Sign topology with root-topology-authority.secret + if (!topology.sign(topologyAuthority,OSUtils::now())) { + std::cerr << "Unable to sign!" << std::endl; + return 1; + } - // Test signature to make sure signing worked - Dictionary test(topology.toString()); - if (!test.verify(topologyAuthority)) { - std::cerr << "Test verification of signed dictionary failed!" << std::endl; - return 1; + // Test signature to make sure signing worked + Dictionary test(topology.toString()); + if (!test.verify(topologyAuthority)) { + std::cerr << "Test verification of signed dictionary failed!" << std::endl; + return 1; + } } // Output to stdout From 9a34fde8a51f9218d4062336dddbb42fe19b6764 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 16:03:44 -0700 Subject: [PATCH 06/10] Make sure identity.public exists and stays in sync, cleanup extra new in Node, and test script for local testnets. --- node/Node.cpp | 22 ++++++------- node/Node.hpp | 4 +-- root-topology/test/README.md | 6 ++++ .../test/create-test-root-topology.sh | 31 +++++++++++++++++++ 4 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 root-topology/test/README.md create mode 100755 root-topology/test/create-test-root-topology.sh diff --git a/node/Node.cpp b/node/Node.cpp index e77a977eb..1661e9d1a 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -59,7 +59,8 @@ Node::Node( ZT1_VirtualNetworkConfigFunction virtualNetworkConfigFunction, ZT1_EventCallback eventCallback, const char *overrideRootTopology) : - RR(new RuntimeEnvironment(this)), + _RR(this), + RR(&_RR), _uPtr(uptr), _dataStoreGetFunction(dataStoreGetFunction), _dataStorePutFunction(dataStorePutFunction), @@ -86,19 +87,18 @@ Node::Node( TRACE("identity.secret not found, generating..."); RR->identity.generate(); idtmp = RR->identity.toString(true); - if (!dataStorePut("identity.secret",idtmp,true)) { - delete RR; + if (!dataStorePut("identity.secret",idtmp,true)) throw std::runtime_error("unable to write identity.secret"); - } - idtmp = RR->identity.toString(false); - if (!dataStorePut("identity.public",idtmp,false)) { - delete RR; - throw std::runtime_error("unable to write identity.public"); - } } RR->publicIdentityStr = RR->identity.toString(false); RR->secretIdentityStr = RR->identity.toString(true); + idtmp = dataStoreGet("identity.public"); + if (idtmp != RR->publicIdentityStr) { + if (!dataStorePut("identity.public",RR->publicIdentityStr,false)) + throw std::runtime_error("unable to write identity.public"); + } + try { RR->prng = new CMWC4096(); RR->sw = new Switch(RR); @@ -113,7 +113,6 @@ Node::Node( delete RR->mc; delete RR->sw; delete RR->prng; - delete RR; throw; } @@ -138,14 +137,13 @@ Node::Node( Node::~Node() { Mutex::Lock _l(_networks_m); - _networks.clear(); // delete these before we delete RR + _networks.clear(); delete RR->sa; delete RR->topology; delete RR->antiRec; delete RR->mc; delete RR->sw; delete RR->prng; - delete RR; } ZT1_ResultCode Node::processWirePacket( diff --git a/node/Node.hpp b/node/Node.hpp index 396e04c0f..70531bf85 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -38,6 +38,7 @@ #include "../include/ZeroTierOne.h" +#include "RuntimeEnvironment.hpp" #include "InetAddress.hpp" #include "Mutex.hpp" #include "MAC.hpp" @@ -52,8 +53,6 @@ namespace ZeroTier { -class RuntimeEnvironment; - /** * Implementation of Node object as defined in CAPI * @@ -229,6 +228,7 @@ public: #endif private: + RuntimeEnvironment _RR; RuntimeEnvironment *RR; void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P diff --git a/root-topology/test/README.md b/root-topology/test/README.md new file mode 100644 index 000000000..332f8297f --- /dev/null +++ b/root-topology/test/README.md @@ -0,0 +1,6 @@ +Test Root Topology Script +====== + +This builds a test-root-topology from any number of running test-supernode-# Docker containers. This can then be used with the (undocumented) -T (override root topology) option to run test networks under Docker. + +Once you have a local Docker test network running you can use iptables rules to simulate a variety of network pathologies, or you can just use it to test any new changes to the protocol or node behavior at some limited scale. diff --git a/root-topology/test/create-test-root-topology.sh b/root-topology/test/create-test-root-topology.sh new file mode 100755 index 000000000..032d9c2e5 --- /dev/null +++ b/root-topology/test/create-test-root-topology.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [ ! -e ../mktopology ]; then + echo 'Build ../mktopology first!' + exit 1 +fi + +echo 'Populating supernodes/* with all Docker test-supernode-* container IPs and identities...' + +rm -rf supernodes +mkdir supernodes + +for cid in `docker ps -f 'name=test-supernode-*' -q`; do + id=`docker exec $cid cat /var/lib/zerotier-one/identity.public` + ztaddr=`echo $id | cut -d : -f 1` + ip=`docker exec $cid ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'` + echo $cid $ztaddr $id $ip + echo "id=$id" >supernodes/$ztaddr + echo "udp=$ip/9993" >>supernodes/$ztaddr +done + +echo 'Creating test-root-topology...' + +rm -f test-root-topology +../mktopology >test-root-topology + +echo 'Done!' +echo +cat test-root-topology + +exit 0 From 3ac23165c78dc98c8e58180c58959624091fec00 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 16:04:17 -0700 Subject: [PATCH 07/10] Kill old testnet -- was useful in its time, but Docker make running real test networks locally stupid easy and a more realistic simulation. --- attic/testnet.cpp | 765 ----------------------- attic/testnet/MTQ.hpp | 181 ------ attic/testnet/README.md | 36 -- attic/testnet/SimNet.cpp | 68 -- attic/testnet/SimNet.hpp | 71 --- attic/testnet/SimNetSocketManager.cpp | 90 --- attic/testnet/SimNetSocketManager.hpp | 124 ---- attic/testnet/TestEthernetTap.cpp | 150 ----- attic/testnet/TestEthernetTap.hpp | 124 ---- attic/testnet/TestEthernetTapFactory.cpp | 79 --- attic/testnet/TestEthernetTapFactory.hpp | 91 --- 11 files changed, 1779 deletions(-) delete mode 100644 attic/testnet.cpp delete mode 100644 attic/testnet/MTQ.hpp delete mode 100644 attic/testnet/README.md delete mode 100644 attic/testnet/SimNet.cpp delete mode 100644 attic/testnet/SimNet.hpp delete mode 100644 attic/testnet/SimNetSocketManager.cpp delete mode 100644 attic/testnet/SimNetSocketManager.hpp delete mode 100644 attic/testnet/TestEthernetTap.cpp delete mode 100644 attic/testnet/TestEthernetTap.hpp delete mode 100644 attic/testnet/TestEthernetTapFactory.cpp delete mode 100644 attic/testnet/TestEthernetTapFactory.hpp diff --git a/attic/testnet.cpp b/attic/testnet.cpp deleted file mode 100644 index 5b175728e..000000000 --- a/attic/testnet.cpp +++ /dev/null @@ -1,765 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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/ - */ - -/* SEE: testnet/README.md */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#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 "node/Dictionary.hpp" - -#include "testnet/SimNet.hpp" -#include "testnet/SimNetSocketManager.hpp" -#include "testnet/TestEthernetTap.hpp" -#include "testnet/TestEthernetTapFactory.hpp" - -#ifdef __WINDOWS__ -#include -#else -#include -#include -#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(), - socketManager(net.newEndpoint(addr)), - node(home.c_str(),&tapFactory,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; - 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").c_str(),id.toString(true))) - return Identity(); - if (!Utils::writeFile((path + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),id.toString(false))) - return Identity(); - - return id; -} - -// Instantiates supernodes by scanning for S########## subdirectories -static std::vector
initSupernodes() -{ - Dictionary supernodes; - std::vector< std::pair > snids; - std::map dir(Utils::listDirectory(basePath.c_str())); - - for(std::map::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(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
newNodes; - - for(std::vector< std::pair >::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[i->first.address()] = n; - newNodes.push_back(i->first.address()); - } - - return newNodes; -} - -// Instantiates any not-already-instantiated regular nodes -static std::vector
scanForNewNodes() -{ - std::vector
newNodes; - std::map dir(Utils::listDirectory(basePath.c_str())); - - for(std::map::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 &cmd) -{ - printf("---------- help"ZT_EOL_S); - printf("---------- mksn "ZT_EOL_S); - printf("---------- mkn "ZT_EOL_S); - printf("---------- list"ZT_EOL_S); - printf("---------- join
"ZT_EOL_S); - printf("---------- leave
"ZT_EOL_S); - printf("---------- listnetworks
"ZT_EOL_S); - printf("---------- listpeers
"ZT_EOL_S); - printf("---------- unicast
[]"ZT_EOL_S); - printf("---------- multicast
[]"ZT_EOL_S); - printf("---------- quit"ZT_EOL_S); - printf("---------- ( * means all regular nodes, ** means including supernodes )"ZT_EOL_S); - printf("---------- ( . runs previous command again )"ZT_EOL_S); -} - -static void doMKSN(const std::vector &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); - return; - } - - int count = Utils::strToInt(cmd[1].c_str()); - for(int i=0;i nodes(initSupernodes()); - for(std::vector
::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 &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; - } - - int count = Utils::strToInt(cmd[1].c_str()); - for(int i=0;i nodes(scanForNewNodes()); - for(std::vector
::iterator a(nodes.begin());a!=nodes.end();++a) - printf("%s started (regular node)"ZT_EOL_S,a->toString().c_str()); -} - -static void doList(const std::vector &cmd) -{ - unsigned int peers = 0,supernodes = 0; - ZT1_Node_Status status; - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - n->second->node.status(&status); - if (status.initialized) { - printf("%s %c %s (%u peers, %u direct links)"ZT_EOL_S, - n->first.toString().c_str(), - n->second->supernode ? 'S' : 'N', - (status.online ? "ONLINE" : "OFFLINE"), - status.knownPeers, - status.directlyConnectedPeers); - if (n->second->supernode) - ++supernodes; - else ++peers; - } else printf("%s ? INITIALIZING (0 peers, 0 direct links)"ZT_EOL_S,n->first.toString().c_str()); - } - printf("---------- %u regular peers, %u supernodes"ZT_EOL_S,peers,supernodes); -} - -static void doJoin(const std::vector &cmd) -{ - if (cmd.size() < 3) { - doHelp(cmd); - return; - } - - std::vector
addrs; - if ((cmd[1] == "*")||(cmd[1] == "**")) { - bool includeSuper = (cmd[1] == "**"); - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - if ((includeSuper)||(!n->second->supernode)) - addrs.push_back(n->first); - } - } else addrs.push_back(Address(cmd[1])); - - uint64_t nwid = Utils::hexStrToU64(cmd[2].c_str()); - - for(std::vector
::iterator a(addrs.begin());a!=addrs.end();++a) { - std::map< Address,SimNode * >::iterator n(nodes.find(*a)); - if (n != nodes.end()) { - n->second->node.join(nwid); - printf("%s join %.16llx"ZT_EOL_S,n->first.toString().c_str(),(unsigned long long)nwid); - } - } -} - -static void doLeave(const std::vector &cmd) -{ - if (cmd.size() < 3) { - doHelp(cmd); - return; - } - - std::vector
addrs; - if ((cmd[1] == "*")||(cmd[1] == "**")) { - bool includeSuper = (cmd[1] == "**"); - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - if ((includeSuper)||(!n->second->supernode)) - addrs.push_back(n->first); - } - } else addrs.push_back(Address(cmd[1])); - - uint64_t nwid = Utils::hexStrToU64(cmd[2].c_str()); - - for(std::vector
::iterator a(addrs.begin());a!=addrs.end();++a) { - std::map< Address,SimNode * >::iterator n(nodes.find(*a)); - if (n != nodes.end()) { - n->second->node.leave(nwid); - printf("%s leave %.16llx"ZT_EOL_S,n->first.toString().c_str(),(unsigned long long)nwid); - } - } -} - -static void doListNetworks(const std::vector &cmd) -{ - if (cmd.size() < 2) { - doHelp(cmd); - return; - } - - std::vector
addrs; - if ((cmd[1] == "*")||(cmd[1] == "**")) { - bool includeSuper = (cmd[1] == "**"); - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - if ((includeSuper)||(!n->second->supernode)) - addrs.push_back(n->first); - } - } else addrs.push_back(Address(cmd[1])); - - printf("---------- "ZT_EOL_S); - - for(std::vector
::iterator a(addrs.begin());a!=addrs.end();++a) { - std::string astr(a->toString()); - std::map< Address,SimNode * >::iterator n(nodes.find(*a)); - if (n != nodes.end()) { - ZT1_Node_NetworkList *nl = n->second->node.listNetworks(); - if (nl) { - for(unsigned int i=0;inumNetworks;++i) { - printf("%s %s %s %s %s %ld %s %s ", - astr.c_str(), - nl->networks[i].nwidHex, - nl->networks[i].name, - nl->networks[i].macStr, - nl->networks[i].statusStr, - nl->networks[i].configAge, - (nl->networks[i].isPrivate ? "private" : "public"), - nl->networks[i].device); - if (nl->networks[i].numIps > 0) { - for(unsigned int j=0;jnetworks[i].numIps;++j) { - if (j > 0) - printf(","); - printf("%s/%d",nl->networks[i].ips[j].ascii,(int)nl->networks[i].ips[j].port); - } - } else printf("-"); - printf(ZT_EOL_S); - } - n->second->node.freeQueryResult(nl); - } - } - } -} - -static void doListPeers(const std::vector &cmd) -{ - if (cmd.size() < 2) { - doHelp(cmd); - return; - } - - std::vector
addrs; - if ((cmd[1] == "*")||(cmd[1] == "**")) { - bool includeSuper = (cmd[1] == "**"); - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - if ((includeSuper)||(!n->second->supernode)) - addrs.push_back(n->first); - } - } else addrs.push_back(Address(cmd[1])); - - printf("---------- "ZT_EOL_S); - - for(std::vector
::iterator a(addrs.begin());a!=addrs.end();++a) { - std::string astr(a->toString()); - std::map< Address,SimNode * >::iterator n(nodes.find(*a)); - if (n != nodes.end()) { - ZT1_Node_PeerList *pl = n->second->node.listPeers(); - if (pl) { - for(unsigned int i=0;inumPeers;++i) { - printf("%s %.10llx ",astr.c_str(),(unsigned long long)pl->peers[i].rawAddress); - if (pl->peers[i].numPaths == 0) - printf("-"); - else { - for(unsigned int j=0;jpeers[i].numPaths;++j) { - if (j > 0) - printf(","); - switch(pl->peers[i].paths[j].type) { - default: - printf("unknown;"); - break; - case ZT1_Node_PhysicalPath_TYPE_UDP: - printf("udp;"); - break; - case ZT1_Node_PhysicalPath_TYPE_TCP_OUT: - printf("tcp_out;"); - break; - case ZT1_Node_PhysicalPath_TYPE_TCP_IN: - printf("tcp_in;"); - break; - case ZT1_Node_PhysicalPath_TYPE_ETHERNET: - printf("eth;"); - break; - } - printf("%s/%d;%ld;%ld;%ld;%s", - pl->peers[i].paths[j].address.ascii, - (int)pl->peers[i].paths[j].address.port, - pl->peers[i].paths[j].lastSend, - pl->peers[i].paths[j].lastReceive, - pl->peers[i].paths[j].lastPing, - (pl->peers[i].paths[j].fixed ? "fixed" : (pl->peers[i].paths[j].active ? "active" : "inactive"))); - } - } - const char *rolestr; - switch(pl->peers[i].role) { - case ZT1_Node_Peer_SUPERNODE: rolestr = "SUPERNODE"; break; - case ZT1_Node_Peer_HUB: rolestr = "HUB"; break; - case ZT1_Node_Peer_NODE: rolestr = "NODE"; break; - default: rolestr = "?"; break; - } - printf(" %u %s %s"ZT_EOL_S, - pl->peers[i].latency, - ((pl->peers[i].remoteVersion[0]) ? pl->peers[i].remoteVersion : "-"), - rolestr); - } - n->second->node.freeQueryResult(pl); - } - } - } -} - -static void doUnicast(const std::vector &cmd) -{ - union { - uint64_t i[2]; - unsigned char data[2800]; - } pkt; - - if (cmd.size() < 5) { - doHelp(cmd); - return; - } - - uint64_t nwid = Utils::hexStrToU64(cmd[3].c_str()); - unsigned int frameLen = Utils::strToUInt(cmd[4].c_str()); - uint64_t tout = 2000; - if (cmd.size() >= 6) - tout = Utils::strToU64(cmd[5].c_str()) * 1000ULL; - - if (frameLen < 16) - frameLen = 16; - if (frameLen > 2800) - frameLen = 2800; - - std::vector
senders; - if ((cmd[1] == "*")||(cmd[1] == "**")) { - bool includeSuper = (cmd[1] == "**"); - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - if ((includeSuper)||(!n->second->supernode)) - senders.push_back(n->first); - } - } else senders.push_back(Address(cmd[1])); - - std::vector
receivers; - if ((cmd[2] == "*")||(cmd[2] == "**")) { - bool includeSuper = (cmd[2] == "**"); - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - if ((includeSuper)||(!n->second->supernode)) - receivers.push_back(n->first); - } - } else receivers.push_back(Address(cmd[2])); - - for(unsigned int i=0;i > sentPairs; - for(std::vector
::iterator s(senders.begin());s!=senders.end();++s) { - for(std::vector
::iterator r(receivers.begin());r!=receivers.end();++r) { - if (*s == *r) - continue; - - SimNode *sender = nodes[*s]; - SimNode *receiver = nodes[*r]; - TestEthernetTap *stap = sender->tapFactory.getByNwid(nwid); - TestEthernetTap *rtap = receiver->tapFactory.getByNwid(nwid); - - if ((stap)&&(rtap)) { - pkt.i[0] = s->toInt(); - pkt.i[1] = Utils::now(); - stap->injectPacketFromHost(stap->mac(),rtap->mac(),0xdead,pkt.data,frameLen); - printf("%s -> %s etherType 0xdead network %.16llx length %u"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),(unsigned long long)nwid,frameLen); - sentPairs.insert(std::pair(*s,*r)); - } else if (stap) { - printf("%s -> !%s (receiver not a member of %.16llx)"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),(unsigned long long)nwid); - } else if (rtap) { - printf("%s -> !%s (sender not a member of %.16llx)"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),(unsigned long long)nwid); - } else { - printf("%s -> !%s (neither party is a member of %.16llx)"ZT_EOL_S,s->toString().c_str(),r->toString().c_str(),(unsigned long long)nwid); - } - } - } - - printf("---------- waiting up to %llu seconds..."ZT_EOL_S,tout / 1000ULL); - - std::set< std::pair > receivedPairs; - TestEthernetTap::TestFrame frame; - uint64_t toutend = Utils::now() + tout; - do { - for(std::vector
::iterator r(receivers.begin());r!=receivers.end();++r) { - SimNode *receiver = nodes[*r]; - TestEthernetTap *rtap = receiver->tapFactory.getByNwid(nwid); - - if ((rtap)&&(rtap->getNextReceivedFrame(frame,5))) { - if ((frame.len == frameLen)&&(!memcmp(frame.data + 16,pkt.data + 16,frameLen - 16))) { - uint64_t ints[2]; - memcpy(ints,frame.data,16); - printf("%s <- %.10llx received test packet, length == %u, latency == %llums"ZT_EOL_S,r->toString().c_str(),(unsigned long long)ints[0],frame.len,(unsigned long long)(frame.timestamp - ints[1])); - receivedPairs.insert(std::pair(Address(ints[0]),*r)); - } else { - printf("%s !! got spurious packet, length == %u, etherType == 0x%.4x"ZT_EOL_S,r->toString().c_str(),frame.len,frame.etherType); - } - } - } - - Thread::sleep(100); - } while ((receivedPairs.size() < sentPairs.size())&&(Utils::now() < toutend)); - - for(std::vector
::iterator s(senders.begin());s!=senders.end();++s) { - for(std::vector
::iterator r(receivers.begin());r!=receivers.end();++r) { - if (*s == *r) - continue; - if ((sentPairs.count(std::pair(*s,*r)))&&(!receivedPairs.count(std::pair(*s,*r)))) { - printf("%s <- %s was never received (timed out)"ZT_EOL_S,r->toString().c_str(),s->toString().c_str()); - } - } - } - - printf("---------- sent %u, received %u"ZT_EOL_S,(unsigned int)sentPairs.size(),(unsigned int)receivedPairs.size()); -} - -static void doMulticast(const std::vector &cmd) -{ - union { - uint64_t i[2]; - unsigned char data[2800]; - } pkt; - - if (cmd.size() < 5) { - doHelp(cmd); - return; - } - - uint64_t nwid = Utils::hexStrToU64(cmd[3].c_str()); - unsigned int frameLen = Utils::strToUInt(cmd[4].c_str()); - uint64_t tout = 2000; - if (cmd.size() >= 6) - tout = Utils::strToU64(cmd[5].c_str()) * 1000ULL; - - if (frameLen < 16) - frameLen = 16; - if (frameLen > 2800) - frameLen = 2800; - - std::vector
senders; - if ((cmd[1] == "*")||(cmd[1] == "**")) { - bool includeSuper = (cmd[1] == "**"); - for(std::map< Address,SimNode * >::iterator n(nodes.begin());n!=nodes.end();++n) { - if ((includeSuper)||(!n->second->supernode)) - senders.push_back(n->first); - } - } else senders.push_back(Address(cmd[1])); - - MAC mcaddr; - if (cmd[2] == "*") - mcaddr = MAC(0xff,0xff,0xff,0xff,0xff,0xff); - else mcaddr.fromString(cmd[2].c_str()); - - if (!mcaddr.isMulticast()) { - printf("---------- %s is not a multicast MAC address"ZT_EOL_S,mcaddr.toString().c_str()); - return; - } - - for(unsigned int i=0;i::iterator s(senders.begin());s!=senders.end();++s) { - SimNode *sender = nodes[*s]; - TestEthernetTap *stap = sender->tapFactory.getByNwid(nwid); - - if (stap) { - pkt.i[0] = s->toInt(); - pkt.i[1] = Utils::now(); - stap->injectPacketFromHost(stap->mac(),mcaddr,0xdead,pkt.data,frameLen); - printf("%s -> %s etherType 0xdead network %.16llx length %u"ZT_EOL_S,s->toString().c_str(),mcaddr.toString().c_str(),(unsigned long long)nwid,frameLen); - } else { - printf("%s -> !%s (sender is not a member of %.16llx)"ZT_EOL_S,s->toString().c_str(),mcaddr.toString().c_str(),(unsigned long long)nwid); - } - } - - printf("---------- waiting %llu seconds..."ZT_EOL_S,tout / 1000ULL); - - unsigned int receiveCount = 0; - TestEthernetTap::TestFrame frame; - uint64_t toutend = Utils::now() + tout; - do { - for(std::map< Address,SimNode * >::iterator nn(nodes.begin());nn!=nodes.end();++nn) { - SimNode *receiver = nn->second; - TestEthernetTap *rtap = receiver->tapFactory.getByNwid(nwid); - - if ((rtap)&&(rtap->getNextReceivedFrame(frame,5))) { - if ((frame.len == frameLen)&&(!memcmp(frame.data + 16,pkt.data + 16,frameLen - 16))) { - uint64_t ints[2]; - memcpy(ints,frame.data,16); - printf("%s <- %.10llx received test packet, length == %u, latency == %llums"ZT_EOL_S,nn->first.toString().c_str(),(unsigned long long)ints[0],frame.len,(unsigned long long)(frame.timestamp - ints[1])); - ++receiveCount; - } else { - printf("%s !! got spurious packet, length == %u, etherType == 0x%.4x"ZT_EOL_S,nn->first.toString().c_str(),frame.len,frame.etherType); - } - } - } - - Thread::sleep(100); - } while (Utils::now() < toutend); - - printf("---------- test multicast received by %u peers"ZT_EOL_S,receiveCount); -} - -int main(int argc,char **argv) -{ - char linebuf[1024]; - - if (argc <= 1) { - fprintf(stderr,"Usage: %s "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,basePath.c_str()); - std::vector
snodes(initSupernodes()); - if (snodes.empty()) { - printf("---------- no existing network found; use 'mksn' to create one."ZT_EOL_S); - } else { - for(std::vector
::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
nodes(scanForNewNodes()); - for(std::vector
::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); - - std::vector cmd,prevCmd; - bool run = true; - while (run) { - printf(">> "); - fflush(stdout); - if (!fgets(linebuf,sizeof(linebuf),stdin)) - break; - - cmd = Utils::split(linebuf," \r\n\t","\\","\""); - - for(;;) { - if (cmd.size() == 0) - break; - else if (cmd[0] == "quit") - run = false; - 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] == "list") - doList(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] == "unicast") - doUnicast(cmd); - else if (cmd[0] == "multicast") - doMulticast(cmd); - else if ((cmd[0] == ".")&&(prevCmd.size() > 0)) { - cmd = prevCmd; - continue; - } else doHelp(cmd); - break; - } - - if ((cmd.size() > 0)&&(cmd[0] != ".")) - prevCmd = 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; -} diff --git a/attic/testnet/MTQ.hpp b/attic/testnet/MTQ.hpp deleted file mode 100644 index 9f4211884..000000000 --- a/attic/testnet/MTQ.hpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. 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/ - */ - -#ifndef ZT_MTQ_HPP -#define ZT_MTQ_HPP - -#include -#include - -#include - -#include "../node/Constants.hpp" -#include "../node/NonCopyable.hpp" -#include "../node/Utils.hpp" - -#ifdef __WINDOWS__ -#include -#else -#include -#include -#endif - -namespace ZeroTier { - -/** - * A synchronized multithreaded FIFO queue - * - * This is designed for a use case where one thread pushes, the - * other pops. - */ -template -class MTQ : NonCopyable -{ -public: - MTQ() - { -#ifdef __WINDOWS__ - _sem = CreateSemaphore(NULL,0,0x7fffffff,NULL); - InitializeCriticalSection(&_cs); -#else - pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); - pthread_cond_init(&_cond,(const pthread_condattr_t *)0); -#endif - } - - ~MTQ() - { -#ifdef __WINDOWS__ - CloseHandle(_sem); - DeleteCriticalSection(&_cs); -#else - pthread_cond_destroy(&_cond); - pthread_mutex_destroy(&_mh); -#endif - } - - /** - * Push something onto the end of the FIFO and signal waiting thread(s) - * - * @param v Value to push - */ - inline void push(const T &v) - { -#ifdef __WINDOWS__ - EnterCriticalSection(&_cs); - try { - _q.push(v); - LeaveCriticalSection(&_cs); - ReleaseSemaphore(_sem,1,NULL); - } catch ( ... ) { - LeaveCriticalSection(&_cs); - throw; - } -#else - pthread_mutex_lock(const_cast (&_mh)); - try { - _q.push(v); - pthread_mutex_unlock(const_cast (&_mh)); - pthread_cond_signal(const_cast (&_cond)); - } catch ( ... ) { - pthread_mutex_unlock(const_cast (&_mh)); - throw; - } -#endif - } - - /** - * Pop fron queue with optional timeout - * - * @param v Result parameter to set to next value - * @param ms Milliseconds timeout or 0 for none - * @return True if v was set to something, false on timeout - */ - inline bool pop(T &v,unsigned long ms = 0) - { -#ifdef __WINDOWS__ - if (ms > 0) - WaitForSingleObject(_sem,(DWORD)ms); - else WaitForSingleObject(_sem,INFINITE); - EnterCriticalSection(&_cs); - try { - if (_q.empty()) { - LeaveCriticalSection(&_cs); - return false; - } else { - v = _q.front(); - _q.pop(); - LeaveCriticalSection(&_cs); - return true; - } - } catch ( ... ) { - LeaveCriticalSection(&_cs); - throw; - } -#else - pthread_mutex_lock(const_cast (&_mh)); - try { - if (_q.empty()) { - if (ms > 0) { - uint64_t when = Utils::now() + (uint64_t)ms; - struct timespec ts; - ts.tv_sec = (unsigned long)(when / 1000); - ts.tv_nsec = (unsigned long)(when % 1000) * (unsigned long)1000000; - pthread_cond_timedwait(const_cast (&_cond),const_cast (&_mh),&ts); - } else { - pthread_cond_wait(const_cast (&_cond),const_cast (&_mh)); - } - if (_q.empty()) { - pthread_mutex_unlock(const_cast (&_mh)); - return false; - } - } - v = _q.front(); - _q.pop(); - pthread_mutex_unlock(const_cast (&_mh)); - return true; - } catch ( ... ) { - pthread_mutex_unlock(const_cast (&_mh)); - throw; - } -#endif - } - -private: - std::queue _q; -#ifdef __WINDOWS__ - HANDLE _sem; - CRITICAL_SECTION _cs; -#else - pthread_cond_t _cond; - pthread_mutex_t _mh; -#endif -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/testnet/README.md b/attic/testnet/README.md deleted file mode 100644 index 3d3b3b54c..000000000 --- a/attic/testnet/README.md +++ /dev/null @@ -1,36 +0,0 @@ -Headless Test Network -====== - -The code in testnet.cpp (in base) and here in testnet/ is for running headless ZeroTier One test networks. - -To build, type (from base) "make testnet". This will build the *zerotier-testnet* binary. Then run it with a directory to use for temporary node home directory storage as a parameter, e.g. "./zerotier-testnet /tmp/zttestnet". - -Type **help** for help. - -Right now the testnet simulates a perfect IP network and allows you to perform unicast and multicast tests. This is useful for verifying the basic correctness of everything under ideal conditions, and for smoke testing. In the future support for NAT emulation, packet loss, and other test features will be added to make this a more full-blown test suite. - -When you start the testnet for the first time, no nodes will exist. You have to create some. First, create supernodes with **mksn**. Create as many as you want. Once you've created supernodes (you can only do this once per testnet) you can create regular nodes with **mkn**. - -Once everything is created use **list** to check the status. - -Each node will create a couple threads, so if your OS imposes a limit this might cause some of your virtual nodes to stick in *INITIALIZING* status as shown in the **list** command. If this happens you might want to blow away the contents of your temp directory and try again with fewer nodes. - -Each node will get a home at the test path you specified, so quitting with **quit** and re-entering will reload the same test network. - -Next you'll need to join your nodes to a virtual ZeroTier network. ZeroTier supports a built-in "fake" public network with the ID **ffffffffffffffff**. This network is for testing and is convenient to use here. It's also possible to set up the netconf-master within one of your test nodes, but doing so is beyond the scope of this doc (for now, but if your clever you can probably figure it out). Verify by doing **listnetworks**. - -Now you can send some packets. Try: - - unicast * * ffffffffffffffff 24 60 - -That will do a unicast all-to-all test and report results. At first latencies might seem high, especially for a headless fake IP network. If you try it again you'll see them drop to zero or nearly so, since everyone will have executed a peer to peer connection. - - multicast * ffffffffffffffff 24 60 - -This will send a multicast packet to ff:ff:ff:ff:ff:ff (broadcast) and report back who receives it. You should see multicast propagation limited to 32 nodes, since this is the setting for multicast limit on the fake test network (and the default if not overridden in netconf). Multicast will show the same "warm up" behavior as unicast. - -Typing just "." will execute the same testnet command again. - -The first 10-digit field of each response is the ZeroTier node doing the sending or receiving. A prefix of "----------" is used for general responses to make everything line up neatly on the screen. We recommend using a wide terminal emulator. - -Enjoy! diff --git a/attic/testnet/SimNet.cpp b/attic/testnet/SimNet.cpp deleted file mode 100644 index c52c4fdf4..000000000 --- a/attic/testnet/SimNet.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 "SimNet.hpp" - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" - -namespace ZeroTier { - -SimNet::SimNet() -{ -} - -SimNet::~SimNet() -{ -} - -SimNetSocketManager *SimNet::newEndpoint(const InetAddress &addr) -{ - Mutex::Lock _l(_lock); - - if (_endpoints.size() >= ZT_SIMNET_MAX_TESTNET_SIZE) - return (SimNetSocketManager *)0; - if (_endpoints.find(addr) != _endpoints.end()) - return (SimNetSocketManager *)0; - - SimNetSocketManager *sm = new SimNetSocketManager(); - sm->_sn = this; - sm->_address = addr; - _endpoints[addr] = sm; - return sm; -} - -SimNetSocketManager *SimNet::get(const InetAddress &addr) -{ - Mutex::Lock _l(_lock); - std::map< InetAddress,SimNetSocketManager * >::iterator ep(_endpoints.find(addr)); - if (ep == _endpoints.end()) - return (SimNetSocketManager *)0; - return ep->second; -} - -} // namespace ZeroTier diff --git a/attic/testnet/SimNet.hpp b/attic/testnet/SimNet.hpp deleted file mode 100644 index 554df7546..000000000 --- a/attic/testnet/SimNet.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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/ - */ - -#ifndef ZT_SIMNET_HPP -#define ZT_SIMNET_HPP - -#include -#include - -#include "../node/Constants.hpp" -#include "../node/InetAddress.hpp" -#include "../node/Mutex.hpp" - -#include "SimNetSocketManager.hpp" - -#define ZT_SIMNET_MAX_TESTNET_SIZE 1048576 - -namespace ZeroTier { - -/** - * A simulated headless IP network for testing - */ -class SimNet -{ -public: - SimNet(); - ~SimNet(); - - /** - * @return New endpoint or NULL on failure - */ - SimNetSocketManager *newEndpoint(const InetAddress &addr); - - /** - * @param addr Address to look up - * @return Endpoint or NULL if none - */ - SimNetSocketManager *get(const InetAddress &addr); - -private: - std::map< InetAddress,SimNetSocketManager * > _endpoints; - Mutex _lock; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/testnet/SimNetSocketManager.cpp b/attic/testnet/SimNetSocketManager.cpp deleted file mode 100644 index 5b8b97a02..000000000 --- a/attic/testnet/SimNetSocketManager.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 "SimNetSocketManager.hpp" -#include "SimNet.hpp" - -#include "../node/Constants.hpp" -#include "../node/Socket.hpp" - -namespace ZeroTier { - -class SimNetSocket : public Socket -{ -public: - SimNetSocket(SimNetSocketManager *sm) : - Socket(ZT_SOCKET_TYPE_UDP_V4), - _parent(sm) {} - - virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen) - { - SimNetSocketManager *dest = _parent->net()->get(to); - if (dest) - dest->enqueue(_parent->address(),msg,msglen); - return true; // we emulate UDP, which has no delivery guarantee semantics - } - - SimNetSocketManager *_parent; -}; - -SimNetSocketManager::SimNetSocketManager() : - _sn((SimNet *)0), // initialized by SimNet - _mySocket(new SimNetSocket(this)) -{ -} - -SimNetSocketManager::~SimNetSocketManager() -{ -} - -bool SimNetSocketManager::send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen) -{ - if (tcp) - return false; // we emulate UDP - SimNetSocketManager *dest = _sn->get(to); - if (dest) - dest->enqueue(_address,msg,msglen); - return true; // we emulate UDP, which has no delivery guarantee semantics -} - -void SimNetSocketManager::poll(unsigned long timeout,void (*handler)(const SharedPtr &,void *,const InetAddress &,Buffer &),void *arg) -{ - std::pair< InetAddress,Buffer > msg; - if ((_inbox.pop(msg,timeout))&&(msg.second.size())) - handler(_mySocket,arg,msg.first,msg.second); -} - -void SimNetSocketManager::whack() -{ - _inbox.push(std::pair< InetAddress,Buffer >()); -} - -void SimNetSocketManager::closeTcpSockets() -{ -} - -} // namespace ZeroTier diff --git a/attic/testnet/SimNetSocketManager.hpp b/attic/testnet/SimNetSocketManager.hpp deleted file mode 100644 index b32372bfb..000000000 --- a/attic/testnet/SimNetSocketManager.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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/ - */ - -#ifndef ZT_SIMNETSOCKETMANAGER_HPP -#define ZT_SIMNETSOCKETMANAGER_HPP - -#include -#include -#include - -#include "../node/Constants.hpp" -#include "../node/SocketManager.hpp" -#include "../node/Mutex.hpp" - -#include "MTQ.hpp" - -namespace ZeroTier { - -class SimNet; - -/** - * Socket manager for an IP endpoint in a simulated network - */ -class SimNetSocketManager : public SocketManager -{ - friend class SimNet; - -public: - struct TransferStats - { - TransferStats() : received(0),sent(0) {} - unsigned long long received; - unsigned long long sent; - }; - - SimNetSocketManager(); - virtual ~SimNetSocketManager(); - - /** - * @return IP address of this simulated endpoint - */ - inline const InetAddress &address() const { return _address; } - - /** - * @return Local endpoint stats - */ - inline const TransferStats &totals() const { return _totals; } - - /** - * @param peer Peer IP address - * @return Transfer stats for this peer - */ - inline TransferStats stats(const InetAddress &peer) const - { - Mutex::Lock _l(_stats_m); - std::map< InetAddress,TransferStats >::const_iterator s(_stats.find(peer)); - if (s == _stats.end()) - return TransferStats(); - return s->second; - } - - /** - * @return Network to which this endpoint belongs - */ - inline SimNet *net() const { return _sn; } - - /** - * Enqueue data from another endpoint to be picked up on next poll() - * - * @param from Originating endpoint address - * @param data Data - * @param len Length of data in bytes - */ - inline void enqueue(const InetAddress &from,const void *data,unsigned int len) - { - _inbox.push(std::pair< InetAddress,Buffer >(from,Buffer(data,len))); - } - - virtual bool send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen); - virtual void poll(unsigned long timeout,void (*handler)(const SharedPtr &,void *,const InetAddress &,Buffer &),void *arg); - virtual void whack(); - virtual void closeTcpSockets(); - -private: - // These are set by SimNet after object creation - SimNet *_sn; - InetAddress _address; - - SharedPtr _mySocket; - TransferStats _totals; - - MTQ< std::pair< InetAddress,Buffer > > _inbox; - - std::map< InetAddress,TransferStats > _stats; - Mutex _stats_m; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/testnet/TestEthernetTap.cpp b/attic/testnet/TestEthernetTap.cpp deleted file mode 100644 index 9cd6df5d8..000000000 --- a/attic/testnet/TestEthernetTap.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 "TestEthernetTap.hpp" -#include "TestEthernetTapFactory.hpp" - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" - -#include -#include - -#ifdef __WINDOWS__ -#include -#else -#include -#endif - -namespace ZeroTier { - -TestEthernetTap::TestEthernetTap( - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *desiredDevice, - const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg) : - EthernetTap("TestEthernetTap",mac,mtu,metric), - _nwid(nwid), - _handler(handler), - _arg(arg), - _enabled(true) -{ - static volatile unsigned int testTapCounter = 0; - - char tmp[64]; - int pid = 0; -#ifdef __UNIX_LIKE__ - pid = (int)getpid(); -#endif -#ifdef __WINDOWS__ - pid = (int)_getpid(); -#endif - Utils::snprintf(tmp,sizeof(tmp),"test%dtap%d",pid,testTapCounter++); - _dev = tmp; - - _thread = Thread::start(this); -} - -TestEthernetTap::~TestEthernetTap() -{ - static const TestFrame zf; // use a static empty frame because of weirdo G++ warning bug... - _pq.push(zf); // empty frame terminates thread - Thread::join(_thread); -} - -void TestEthernetTap::setEnabled(bool en) -{ - _enabled = en; -} - -bool TestEthernetTap::enabled() const -{ - return _enabled; -} - -bool TestEthernetTap::addIP(const InetAddress &ip) -{ - return true; -} - -bool TestEthernetTap::removeIP(const InetAddress &ip) -{ - return true; -} - -std::set TestEthernetTap::ips() const -{ - return std::set(); -} - -void TestEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - _gq.push(TestFrame(from,to,data,etherType,len)); -} - -std::string TestEthernetTap::deviceName() const -{ - return _dev; -} - -void TestEthernetTap::setFriendlyName(const char *friendlyName) -{ -} - -bool TestEthernetTap::updateMulticastGroups(std::set &groups) -{ - return false; -} - -bool TestEthernetTap::injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - if ((len == 0)||(len > _mtu)) - return false; - _pq.push(TestFrame(from,to,data,etherType & 0xffff,len)); - return true; -} - -void TestEthernetTap::threadMain() - throw() -{ - TestFrame f; - for(;;) { - if (_pq.pop(f,0)) { - if (f.len) { - try { - _handler(_arg,f.from,f.to,f.etherType,Buffer<4096>(f.data,f.len)); - } catch ( ... ) {} - } else break; - } - } -} - -} // namespace ZeroTier diff --git a/attic/testnet/TestEthernetTap.hpp b/attic/testnet/TestEthernetTap.hpp deleted file mode 100644 index 280921187..000000000 --- a/attic/testnet/TestEthernetTap.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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/ - */ - -#ifndef ZT_TESTETHERNETTAP_HPP -#define ZT_TESTETHERNETTAP_HPP - -#include -#include -#include - -#include - -#include "../node/Constants.hpp" -#include "../node/EthernetTap.hpp" -#include "../node/Thread.hpp" -#include "../node/Mutex.hpp" - -#include "MTQ.hpp" - -namespace ZeroTier { - -class TestEthernetTapFactory; - -/** - * Dummy Ethernet tap - * - * This tap device prints the contents of packets it receives on stdout - * and also prints outgoing packets when they are injected. It does not - * connect to any real tap or other interface. It's useful for running - * test networks. - */ -class TestEthernetTap : public EthernetTap -{ -public: - struct TestFrame - { - TestFrame() : from(),to(),timestamp(0),etherType(0),len(0) {} - TestFrame(const MAC &f,const MAC &t,const void *d,unsigned int et,unsigned int l) : - from(f), - to(t), - timestamp(Utils::now()), - etherType(et), - len(l) - { - memcpy(data,d,l); - } - - MAC from; - MAC to; - uint64_t timestamp; - unsigned int etherType; - unsigned int len; - char data[4096]; - }; - - TestEthernetTap( - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *desiredDevice, - const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg); - - virtual ~TestEthernetTap(); - - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIP(const InetAddress &ip); - virtual bool removeIP(const InetAddress &ip); - virtual std::set ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual bool updateMulticastGroups(std::set &groups); - virtual bool injectPacketFromHost(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - - inline uint64_t nwid() const { return _nwid; } - inline bool getNextReceivedFrame(TestFrame &v,unsigned long timeout) { return _gq.pop(v,timeout); } - - void threadMain() - throw(); - -private: - uint64_t _nwid; - - void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &); - void *_arg; - Thread _thread; - std::string _dev; - volatile bool _enabled; - - MTQ _pq; - MTQ _gq; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/testnet/TestEthernetTapFactory.cpp b/attic/testnet/TestEthernetTapFactory.cpp deleted file mode 100644 index dfc5919eb..000000000 --- a/attic/testnet/TestEthernetTapFactory.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 "TestEthernetTapFactory.hpp" -#include "TestEthernetTap.hpp" - -namespace ZeroTier { - -TestEthernetTapFactory::TestEthernetTapFactory() -{ -} - -TestEthernetTapFactory::~TestEthernetTapFactory() -{ - Mutex::Lock _l1(_taps_m); - Mutex::Lock _l2(_tapsByMac_m); - Mutex::Lock _l3(_tapsByNwid_m); - for(std::set::iterator t(_taps.begin());t!=_taps.end();++t) - delete *t; -} - -EthernetTap *TestEthernetTapFactory::open( - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *desiredDevice, - const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg) -{ - TestEthernetTap *tap = new TestEthernetTap(mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg); - Mutex::Lock _l1(_taps_m); - Mutex::Lock _l2(_tapsByMac_m); - Mutex::Lock _l3(_tapsByNwid_m); - _taps.insert(tap); - _tapsByMac[mac] = tap; - _tapsByNwid[nwid] = tap; - return tap; -} - -void TestEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices) -{ - Mutex::Lock _l1(_taps_m); - Mutex::Lock _l2(_tapsByMac_m); - Mutex::Lock _l3(_tapsByNwid_m); - if (!tap) - return; - _taps.erase(tap); - _tapsByMac.erase(tap->mac()); - _tapsByNwid.erase(((TestEthernetTap *)tap)->nwid()); - delete tap; -} - -} // namespace ZeroTier diff --git a/attic/testnet/TestEthernetTapFactory.hpp b/attic/testnet/TestEthernetTapFactory.hpp deleted file mode 100644 index 0ef1619ab..000000000 --- a/attic/testnet/TestEthernetTapFactory.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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/ - */ - -#ifndef ZT_TESTETHERNETTAPFACTORY_HPP -#define ZT_TESTETHERNETTAPFACTORY_HPP - -#include -#include -#include - -#include "../node/EthernetTapFactory.hpp" -#include "../node/Mutex.hpp" -#include "../node/MAC.hpp" -#include "TestEthernetTap.hpp" - -namespace ZeroTier { - -class TestEthernetTapFactory : public EthernetTapFactory -{ -public: - TestEthernetTapFactory(); - virtual ~TestEthernetTapFactory(); - - virtual EthernetTap *open( - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *desiredDevice, - const char *friendlyName, - void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &), - void *arg); - - virtual void close(EthernetTap *tap,bool destroyPersistentDevices); - - inline TestEthernetTap *getByMac(const MAC &mac) const - { - Mutex::Lock _l(_tapsByMac_m); - std::map< MAC,TestEthernetTap * >::const_iterator t(_tapsByMac.find(mac)); - if (t == _tapsByMac.end()) - return (TestEthernetTap *)0; - return t->second; - } - - inline TestEthernetTap *getByNwid(uint64_t nwid) const - { - Mutex::Lock _l(_tapsByNwid_m); - std::map< uint64_t,TestEthernetTap * >::const_iterator t(_tapsByNwid.find(nwid)); - if (t == _tapsByNwid.end()) - return (TestEthernetTap *)0; - return t->second; - } - -private: - std::set< EthernetTap * > _taps; - Mutex _taps_m; - - std::map< MAC,TestEthernetTap * > _tapsByMac; - Mutex _tapsByMac_m; - - std::map< uint64_t,TestEthernetTap * > _tapsByNwid; - Mutex _tapsByNwid_m; -}; - -} // namespace ZeroTier - -#endif From 5185103692bdae6b4b14fe147c5354354450c1a3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 16:13:17 -0700 Subject: [PATCH 08/10] Fix to create-test-root-topology. --- .gitignore | 13 ++++--------- root-topology/test/create-test-root-topology.sh | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 27b3e1353..db660e147 100755 --- a/.gitignore +++ b/.gitignore @@ -34,13 +34,8 @@ .qmake.stash *.autosave /ZeroTier One.dmg +/root-topology/bin2c +/root-topology/mktopology /root-topology/*.secret -/testnet/local-testnet/n???? -/testnet/local-testnet/*/peers.persist -/testnet/local-testnet/*/authtoken.secret -/testnet/local-testnet/*/*.log -/testnet/local-testnet/*/*.old -/testnet/local-testnet/*/root-topology -/testnet/local-testnet/*/local.conf -/testnet/local-testnet/*/networks.d -/netconf/netconf.db +/root-topology/test/supernodes +/root-topology/test/test-root-topology diff --git a/root-topology/test/create-test-root-topology.sh b/root-topology/test/create-test-root-topology.sh index 032d9c2e5..86c0577cf 100755 --- a/root-topology/test/create-test-root-topology.sh +++ b/root-topology/test/create-test-root-topology.sh @@ -11,7 +11,7 @@ rm -rf supernodes mkdir supernodes for cid in `docker ps -f 'name=test-supernode-*' -q`; do - id=`docker exec $cid cat /var/lib/zerotier-one/identity.public` + id=`docker exec $cid cat /var/lib/zerotier-one/identity.secret | cut -d : -f 1-3` ztaddr=`echo $id | cut -d : -f 1` ip=`docker exec $cid ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'` echo $cid $ztaddr $id $ip From 9eb7698f0e75eb362c15668b2fdc1b4b2a9b8113 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 16:40:04 -0700 Subject: [PATCH 09/10] Learn external IP addresses on OK(HELLO) too. --- node/IncomingPacket.cpp | 49 ++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index a8d564bb8..f73b20afe 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -179,18 +179,17 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) Identity id; unsigned int destAddrPtr = id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY) + ZT_PROTO_VERB_HELLO_IDX_IDENTITY; - unsigned int destAddrType = ZT_PROTO_DEST_ADDRESS_TYPE_NONE; - if (destAddrPtr < size()) // ZeroTier One < 1.0.3 did not include this field - destAddrType = (*this)[destAddrPtr++]; - InetAddress destAddr; - switch(destAddrType) { - case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4: - destAddr.set(field(destAddrPtr,4),4,at(destAddrPtr + 4)); - break; - case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6: - destAddr.set(field(destAddrPtr,16),16,at(destAddrPtr + 16)); - break; + if (destAddrPtr < size()) { // ZeroTier One < 1.0.3 did not include this field + const unsigned int destAddrType = (*this)[destAddrPtr++]; + switch(destAddrType) { + case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4: + destAddr.set(field(destAddrPtr,4),4,at(destAddrPtr + 4)); + break; + case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6: + destAddr.set(field(destAddrPtr,16),16,at(destAddrPtr + 16)); + break; + } } if (source() != id.address()) { @@ -268,12 +267,13 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) peer->received(RR,_remoteAddress,_linkDesperation,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); + bool trusted = false; if (RR->topology->isSupernode(id.address())) { RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); - RR->sa->iam(id.address(),_remoteAddress,destAddr,true); - } else { - RR->sa->iam(id.address(),_remoteAddress,destAddr,false); + trusted = true; } + if (destAddr) + RR->sa->iam(id.address(),_remoteAddress,destAddr,trusted); Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); @@ -328,6 +328,20 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); + InetAddress destAddr; + unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; // dest address, if present, will start after 16-bit revision + if (destAddrPtr < size()) { // ZeroTier One < 1.0.3 did not include this field + const unsigned int destAddrType = (*this)[destAddrPtr++]; + switch(destAddrType) { + case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4: + destAddr.set(field(destAddrPtr,4),4,at(destAddrPtr + 4)); + break; + case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6: + destAddr.set(field(destAddrPtr,16),16,at(destAddrPtr + 16)); + break; + } + } + if (vProto < ZT_PROTO_VERSION_MIN) { TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str()); return true; @@ -338,8 +352,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); - if (RR->topology->isSupernode(peer->address())) + bool trusted = false; + if (RR->topology->isSupernode(peer->address())) { RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision); + trusted = true; + } + if (destAddr) + RR->sa->iam(peer->address(),_remoteAddress,destAddr,trusted); } break; case Packet::VERB_WHOIS: { From d3820049b82f756ba6c9c3390d4060ee1ad49925 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 30 Apr 2015 18:25:31 -0700 Subject: [PATCH 10/10] Add reported external address to OK(HELLO) TRACE to verify SN behavior. --- node/IncomingPacket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index f73b20afe..453e3945d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -347,7 +347,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p return true; } - TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency); + TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((destAddr) ? destAddr.toString().c_str() : "(none)")); peer->addDirectLatencyMeasurment(latency); peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);