From 53c7f61f985bdaba2aff3f055e21a8b4f63a1b2c Mon Sep 17 00:00:00 2001 From: Kees Bos Date: Sun, 5 Jul 2015 13:27:27 +0200 Subject: Fix for output of empty (no members) network --- controller/SqliteNetworkController.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 700b3561..79bf75b6 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -1394,8 +1394,11 @@ unsigned int SqliteNetworkController::_doCPGet( sqlite3_reset(_sListNetworkMembers); sqlite3_bind_text(_sListNetworkMembers,1,nwids,16,SQLITE_STATIC); + responseBody.append("{"); + bool firstMember = true; while (sqlite3_step(_sListNetworkMembers) == SQLITE_ROW) { - responseBody.append((responseBody.length() > 0) ? ",\"" : "{\""); + responseBody.append(firstMember ? "\"" : ",\""); + firstMember = false; responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,0)); responseBody.append("\":"); responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,1)); -- cgit v1.2.3 From e2a2993b186c521f9521d1a9adeb150d27c15629 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 22 Jul 2015 14:01:49 -0700 Subject: Add a Log table to log queries for debugging and security logging. No JSON API support for querying the log yet, but will probably come via /network/###/member/###/log/... or something. --- controller/SqliteNetworkController.cpp | 32 +++++++++++++++++++++++++++++--- controller/SqliteNetworkController.hpp | 3 +++ controller/schema.sql | 11 +++++++++++ controller/schema.sql.c | 11 +++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 79bf75b6..85dbed00 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -142,6 +142,7 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) : // Prepare statement will fail if Config table doesn't exist, which means our DB // needs to be initialized. if (sqlite3_exec(_db,ZT_NETCONF_SCHEMA_SQL"INSERT INTO Config (k,v) VALUES ('schemaVersion',"ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR");",0,0,0) != SQLITE_OK) { + //printf("%s\n",sqlite3_errmsg(_db)); sqlite3_close(_db); throw std::runtime_error("SqliteNetworkController cannot initialize database and/or insert schemaVersion into Config table"); } @@ -199,16 +200,20 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) : ||(sqlite3_prepare_v2(_db,"DELETE FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sDeleteMember,(const char **)0) != SQLITE_OK) /* Gateway */ - ||(sqlite3_prepare_v2(_db,"SELECT ip,ipVersion,metric FROM Gateway WHERE networkId = ? ORDER BY metric ASC",-1,&_sGetGateways,(const char **)0) != SQLITE_OK) + ||(sqlite3_prepare_v2(_db,"SELECT \"ip\",ipVersion,metric FROM Gateway WHERE networkId = ? ORDER BY metric ASC",-1,&_sGetGateways,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"DELETE FROM Gateway WHERE networkId = ?",-1,&_sDeleteGateways,(const char **)0) != SQLITE_OK) - ||(sqlite3_prepare_v2(_db,"INSERT INTO Gateway (networkId,ip,ipVersion,metric) VALUES (?,?,?,?)",-1,&_sCreateGateway,(const char **)0) != SQLITE_OK) + ||(sqlite3_prepare_v2(_db,"INSERT INTO Gateway (networkId,\"ip\",ipVersion,metric) VALUES (?,?,?,?)",-1,&_sCreateGateway,(const char **)0) != SQLITE_OK) + + /* Log */ + ||(sqlite3_prepare_v2(_db,"INSERT INTO \"Log\" (networkId,nodeId,\"ts\",\"authorized\",fromAddr) VALUES (?,?,?,?,?)",-1,&_sPutLog,(const char **)0) != SQLITE_OK) + ||(sqlite3_prepare_v2(_db,"SELECT \"ts\",\"authorized\",fromAddr FROM \"Log\" WHERE networkId = ? AND nodeId = ? AND \"ts\" >= ? ORDER BY \"ts\" ASC",-1,&_sGetMemberLog,(const char **)0) != SQLITE_OK) /* Config */ ||(sqlite3_prepare_v2(_db,"SELECT \"v\" FROM \"Config\" WHERE \"k\" = ?",-1,&_sGetConfig,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"INSERT OR REPLACE INTO \"Config\" (\"k\",\"v\") VALUES (?,?)",-1,&_sSetConfig,(const char **)0) != SQLITE_OK) ) { - //printf("!!! %s\n",sqlite3_errmsg(_db)); + //printf("%s\n",sqlite3_errmsg(_db)); sqlite3_close(_db); throw std::runtime_error("SqliteNetworkController unable to initialize one or more prepared statements"); } @@ -283,6 +288,8 @@ SqliteNetworkController::~SqliteNetworkController() sqlite3_finalize(_sIncrementMemberRevisionCounter); sqlite3_finalize(_sGetConfig); sqlite3_finalize(_sSetConfig); + sqlite3_finalize(_sPutLog); + sqlite3_finalize(_sGetMemberLog); sqlite3_close(_db); } } @@ -387,6 +394,25 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co sqlite3_step(_sIncrementMemberRevisionCounter); } + // Add log entry + { + std::string fa; + if (fromAddr) { + fa = fromAddr.toString(); + if (fa.length() > 64) + fa = fa.substr(0,64); + } + sqlite3_reset(_sPutLog); + sqlite3_bind_text(_sPutLog,1,network.id,16,SQLITE_STATIC); + sqlite3_bind_text(_sPutLog,2,member.nodeId,10,SQLITE_STATIC); + sqlite3_bind_int64(_sPutLog,3,(long long)OSUtils::now()); + sqlite3_bind_int(_sPutLog,4,member.authorized ? 1 : 0); + if (fa.length() > 0) + sqlite3_bind_text(_sPutLog,5,fa.c_str(),-1,SQLITE_STATIC); + else sqlite3_bind_null(_sPutLog,5); + sqlite3_step(_sPutLog); + } + // Check member authorization if (!member.authorized) diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 8b39f7d9..bae11519 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -97,6 +97,7 @@ private: std::string _dbPath; std::string _instanceId; + sqlite3 *_db; sqlite3_stmt *_sGetNetworkById; @@ -141,6 +142,8 @@ private: sqlite3_stmt *_sIncrementMemberRevisionCounter; sqlite3_stmt *_sGetConfig; sqlite3_stmt *_sSetConfig; + sqlite3_stmt *_sPutLog; + sqlite3_stmt *_sGetMemberLog; Mutex _lock; }; diff --git a/controller/schema.sql b/controller/schema.sql index e85785b7..024a5229 100644 --- a/controller/schema.sql +++ b/controller/schema.sql @@ -65,6 +65,17 @@ CREATE TABLE Member ( CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge); CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision); +CREATE TABLE Log ( + networkId char(16) NOT NULL, + nodeId char(10) NOT NULL, + ts integer NOT NULL, + authorized integer NOT NULL, + fromAddr varchar(64) +); + +CREATE INDEX Log_networkId_nodeId ON Log(networkId, nodeId); +CREATE INDEX Log_ts ON Log(ts); + CREATE TABLE Relay ( networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, address char(10) NOT NULL, diff --git a/controller/schema.sql.c b/controller/schema.sql.c index efeb280c..ac0213bc 100644 --- a/controller/schema.sql.c +++ b/controller/schema.sql.c @@ -66,6 +66,17 @@ "CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);\n"\ "CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision);\n"\ "\n"\ +"CREATE TABLE Log (\n"\ +" networkId char(16) NOT NULL,\n"\ +" nodeId char(10) NOT NULL,\n"\ +" ts integer NOT NULL,\n"\ +" authorized integer NOT NULL,\n"\ +" fromAddr varchar(64)\n"\ +");\n"\ +"\n"\ +"CREATE INDEX Log_networkId_nodeId ON Log(networkId, nodeId);\n"\ +"CREATE INDEX Log_ts ON Log(ts);\n"\ +"\n"\ "CREATE TABLE Relay (\n"\ " networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\ " address char(10) NOT NULL,\n"\ -- cgit v1.2.3 From b41079ddf9836d0aa4375ee7f93764706d3e265e Mon Sep 17 00:00:00 2001 From: Nelson Chen Date: Wed, 22 Jul 2015 22:40:43 -0700 Subject: Update Application Mac Menu. Small MacGap leftover. Hide ZeroTier One, not MacGap. Just a papercut. --- ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib b/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib index 61dafbcc..dd67a86a 100644 --- a/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib +++ b/ext/mac-ui-macgap1-wrapper/src/MacGap/en.lproj/MainMenu.xib @@ -125,7 +125,7 @@ - Hide MacGap + Hide ZeroTier One h 1048576 2147483647 -- cgit v1.2.3 From 3ba54c7e3559359abd8d4734aa969829309a9dab Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 23 Jul 2015 09:50:10 -0700 Subject: Eliminate some poorly thought out optimizations from the netconf/controller interaction, and go ahead and bump version to 1.0.4. For a while in 1.0.3 -dev I was trying to optimize out repeated network controller requests by using a ratcheting mechanism. If the client received a network config that was indeed different from the one it had, it would respond by instantlly requesting it again. Not sure what I was thinking. It's fundamentally unsafe to respond to a message with another message of the same type -- it risks a race condition. In this case that's exactly what could happen. It just isn't worth the added complexity to avoid a tiny, tiny amount of network overhead, so I've taken this whole path out. A few extra bytes every two minutes isn't worth fretting about, but as I recall the reason for this optimization was to save CPU on the controller. This can be achieved by just caching responses in memory *there* and serving those same responses back out if they haven't changed. I think I developed that 'ratcheting' stuff before I went full time on this. It's hard to develop stuff like this without hours of sustained focus. --- controller/SqliteNetworkController.cpp | 33 +++++++++++++++++---------------- node/IncomingPacket.cpp | 31 +++++++------------------------ node/Network.cpp | 13 ++++++++++++- node/NetworkConfig.cpp | 23 ++++++++--------------- node/NetworkConfig.hpp | 26 +++++++------------------- node/NetworkController.hpp | 7 +++---- version.h | 2 +- 7 files changed, 55 insertions(+), 80 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 85dbed00..f6489640 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -296,6 +296,12 @@ SqliteNetworkController::~SqliteNetworkController() NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary &metaData,uint64_t haveRevision,Dictionary &netconf) { + // Decode some stuff from metaData + const unsigned int clientMajorVersion = (unsigned int)metaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0); + const unsigned int clientMinorVersion = (unsigned int)metaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0); + const unsigned int clientRevision = (unsigned int)metaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0); + const bool clientIs104 = (Utils::compareVersion(clientMajorVersion,clientMinorVersion,clientRevision,1,0,4) >= 0); + Mutex::Lock _l(_lock); // Note: we can't reuse prepared statements that return const char * pointers without @@ -418,13 +424,6 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co if (!member.authorized) return NetworkController::NETCONF_QUERY_ACCESS_DENIED; - // If netconf is unchanged from client reported revision, just tell client they're up to date - - // Temporarily disabled -- old version didn't do this, and we'll go ahead and - // test more thoroughly before enabling this optimization. - //if ((haveRevision > 0)&&(haveRevision == network.revision)) - // return NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER; - // Create and sign netconf netconf.clear(); @@ -581,7 +580,8 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co if ((ipNetmaskBits <= 0)||(ipNetmaskBits > 32)) continue; - switch((IpAssignmentType)sqlite3_column_int(_sGetIpAssignmentsForNode,0)) { + const IpAssignmentType ipt = (IpAssignmentType)sqlite3_column_int(_sGetIpAssignmentsForNode,0); + switch(ipt) { case ZT_IP_ASSIGNMENT_TYPE_ADDRESS: haveStaticIpAssignment = true; break; @@ -592,13 +592,15 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co continue; } - // We send both routes and IP assignments -- client knows which is - // which by whether address ends in all zeroes after netmask. - char tmp[32]; - Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d.%d/%d",(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15],ipNetmaskBits); - if (v4s.length()) - v4s.push_back(','); - v4s.append(tmp); + // 1.0.4 or newer clients support network routes in addition to IPs. + // Older clients only support IP address / netmask entries. + if ((clientIs104)||(ipt == ZT_IP_ASSIGNMENT_TYPE_ADDRESS)) { + char tmp[32]; + Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d.%d/%d",(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15],ipNetmaskBits); + if (v4s.length()) + v4s.push_back(','); + v4s.append(tmp); + } } if (!haveStaticIpAssignment) { @@ -1388,7 +1390,6 @@ unsigned int SqliteNetworkController::_doCPGet( const char *result = ""; switch(this->doNetworkConfigRequest(InetAddress(),sigid,memid,nwid,Dictionary(),hr,netconf)) { case NetworkController::NETCONF_QUERY_OK: result = "OK"; break; - case NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER: result = "OK_BUT_NOT_NEWER"; break; case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: result = "OBJECT_NOT_FOUND"; break; case NetworkController::NETCONF_QUERY_ACCESS_DENIED: result = "ACCESS_DENIED"; break; case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: result = "INTERNAL_SERVER_ERROR"; break; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index ae99352e..c3d8cc6d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -392,28 +392,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p const unsigned int dictlen = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN); const std::string dict((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,dictlen),dictlen); if (dict.length()) { - if (nw->setConfiguration(Dictionary(dict)) == 2) { // 2 == accepted and actually new - /* If this configuration was indeed new, we do another - * controller request with its revision. We do this in - * order to (a) tell the network controller we got it (it - * won't send a duplicate if ts == current), and (b) - * get another one if the controller is changing rapidly - * until we finally have the final version. - * - * Note that we don't do this for network controllers with - * versions <= 1.0.3, since those regenerate a new controller - * with a new revision every time. In that case this double - * confirmation would create a race condition. */ - const SharedPtr nc(nw->config2()); - if ((peer->atLeastVersion(1,0,3))&&(nc)&&(nc->revision() > 0)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append((uint64_t)nw->id()); - outp.append((uint16_t)0); // no meta-data - outp.append((uint64_t)nc->revision()); - outp.armor(peer->key(),true); - RR->node->putPacket(_remoteAddress,outp.data(),outp.size()); - } - } + nw->setConfiguration(Dictionary(dict)); TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str()); } } @@ -692,6 +671,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons if (RR->localNetworkController) { Dictionary netconf; switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,haveRevision,netconf)) { + case NetworkController::NETCONF_QUERY_OK: { const std::string netconfStr(netconf.toString()); if (netconfStr.length() > 0xffff) { // sanity check since field ix 16-bit @@ -712,8 +692,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons } } } break; - case NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER: // nothing to do -- netconf has not changed - break; + case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); @@ -723,6 +702,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.armor(peer->key(),true); RR->node->putPacket(_remoteAddress,outp.data(),outp.size()); } break; + case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); @@ -732,12 +712,15 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.armor(peer->key(),true); RR->node->putPacket(_remoteAddress,outp.data(),outp.size()); } break; + case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: TRACE("NETWORK_CONFIG_REQUEST failed: internal error: %s",netconf.get("error","(unknown)").c_str()); break; + default: TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()"); break; + } } else { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); diff --git a/node/Network.cpp b/node/Network.cpp index adc8e1b8..549219d7 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -38,6 +38,8 @@ #include "Buffer.hpp" #include "NetworkController.hpp" +#include "../version.h" + namespace ZeroTier { const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0); @@ -255,9 +257,18 @@ void Network::requestConfiguration() } TRACE("requesting netconf for network %.16llx from controller %s",(unsigned long long)_id,controller().toString().c_str()); + + // TODO: in the future we will include things like join tokens here, etc. + Dictionary metaData; + metaData.setHex(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,ZEROTIER_ONE_VERSION_MAJOR); + metaData.setHex(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,ZEROTIER_ONE_VERSION_MINOR); + metaData.setHex(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,ZEROTIER_ONE_VERSION_REVISION); + std::string mds(metaData.toString()); + Packet outp(controller(),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append((uint64_t)_id); - outp.append((uint16_t)0); // no meta-data + outp.append((uint16_t)mds.length()); + outp.append((const void *)mds.data(),(unsigned int)mds.length()); { Mutex::Lock _l(_lock); if (_config) diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index ba4d338b..7898646c 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -47,7 +47,6 @@ SharedPtr NetworkConfig::createTestNetworkConfig(const Address &s nc->_private = false; nc->_enableBroadcast = true; nc->_name = "ZT_TEST_NETWORK"; - nc->_description = "Built-in dummy test network"; // Make up a V4 IP from 'self' in the 10.0.0.0/8 range -- no // guarantee of uniqueness but collisions are unlikely. @@ -111,7 +110,6 @@ void NetworkConfig::_fromDictionary(const Dictionary &d) _name = d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME); if (_name.length() > ZT1_MAX_NETWORK_SHORT_NAME_LENGTH) throw std::invalid_argument("network short name too long (max: 255 characters)"); - _description = d.get(ZT_NETWORKCONFIG_DICT_KEY_DESC,std::string()); // In dictionary IPs are split into V4 and V6 addresses, but we don't really // need that so merge them here. @@ -132,26 +130,22 @@ void NetworkConfig::_fromDictionary(const Dictionary &d) case AF_INET: if ((!addr.netmaskBits())||(addr.netmaskBits() > 32)) continue; - else if (addr.isNetwork()) { - // TODO: add route to network -- this is a route without an IP assignment - continue; - } break; case AF_INET6: if ((!addr.netmaskBits())||(addr.netmaskBits() > 128)) continue; - else if (addr.isNetwork()) { - // TODO: add route to network -- this is a route without an IP assignment - continue; - } break; default: // ignore unrecognized address types or junk/empty fields continue; } - _staticIps.push_back(addr); + if (addr.isNetwork()) + _localRoutes.push_back(addr); + else _staticIps.push_back(addr); } - if (_staticIps.size() > ZT1_MAX_ZT_ASSIGNED_ADDRESSES) - throw std::invalid_argument("too many ZT-assigned IP addresses or routes"); + if (_localRoutes.size() > ZT1_MAX_ZT_ASSIGNED_ADDRESSES) throw std::invalid_argument("too many ZT-assigned routes"); + if (_staticIps.size() > ZT1_MAX_ZT_ASSIGNED_ADDRESSES) throw std::invalid_argument("too many ZT-assigned IP addresses"); + std::sort(_localRoutes.begin(),_localRoutes.end()); + _localRoutes.erase(std::unique(_localRoutes.begin(),_localRoutes.end()),_localRoutes.end()); std::sort(_staticIps.begin(),_staticIps.end()); _staticIps.erase(std::unique(_staticIps.begin(),_staticIps.end()),_staticIps.end()); @@ -201,7 +195,7 @@ bool NetworkConfig::operator==(const NetworkConfig &nc) const if (_private != nc._private) return false; if (_enableBroadcast != nc._enableBroadcast) return false; if (_name != nc._name) return false; - if (_description != nc._description) return false; + if (_localRoutes != nc._localRoutes) return false; if (_staticIps != nc._staticIps) return false; if (_gateways != nc._gateways) return false; if (_activeBridges != nc._activeBridges) return false; @@ -211,4 +205,3 @@ bool NetworkConfig::operator==(const NetworkConfig &nc) const } } // namespace ZeroTier - diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 5c7cdd7c..6111e65b 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -47,59 +47,48 @@ namespace ZeroTier { +// Fields for meta-data sent with network config requests +#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION "majv" +#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION "minv" +#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION "revv" + // These dictionary keys are short so they don't take up much room in // netconf response packets. // integer(hex)[,integer(hex),...] #define ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES "et" - // network ID #define ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID "nwid" - // integer(hex) #define ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP "ts" - // integer(hex) #define ZT_NETWORKCONFIG_DICT_KEY_REVISION "r" - // address of member #define ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO "id" - // integer(hex) #define ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT "ml" - // 0/1 #define ZT_NETWORKCONFIG_DICT_KEY_PRIVATE "p" - // text #define ZT_NETWORKCONFIG_DICT_KEY_NAME "n" - // text #define ZT_NETWORKCONFIG_DICT_KEY_DESC "d" - // IP/bits[,IP/bits,...] // Note that IPs that end in all zeroes are routes with no assignment in them. #define ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC "v4s" - // IP/bits[,IP/bits,...] // Note that IPs that end in all zeroes are routes with no assignment in them. #define ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC "v6s" - // serialized CertificateOfMembership #define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP "com" - // 0/1 #define ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST "eb" - // 0/1 #define ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING "pb" - // node[,node,...] #define ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES "ab" - // node;IP/port[,node;IP/port] #define ZT_NETWORKCONFIG_DICT_KEY_RELAYS "rl" - // IP/metric[,IP/metric,...] #define ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS "gw" @@ -158,7 +147,7 @@ public: inline bool isPublic() const throw() { return (!_private); } inline bool isPrivate() const throw() { return _private; } inline const std::string &name() const throw() { return _name; } - inline const std::string &description() const throw() { return _description; } + inline const std::vector &localRoutes() const throw() { return _localRoutes; } inline const std::vector &staticIps() const throw() { return _staticIps; } inline const std::vector &gateways() const throw() { return _gateways; } inline const std::vector
&activeBridges() const throw() { return _activeBridges; } @@ -194,7 +183,7 @@ private: bool _private; bool _enableBroadcast; std::string _name; - std::string _description; + std::vector _localRoutes; std::vector _staticIps; std::vector _gateways; std::vector
_activeBridges; @@ -207,4 +196,3 @@ private: } // namespace ZeroTier #endif - diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index 265ee3d4..bef884de 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -52,10 +52,9 @@ public: enum ResultCode { NETCONF_QUERY_OK = 0, - NETCONF_QUERY_OK_BUT_NOT_NEWER = 1, - NETCONF_QUERY_OBJECT_NOT_FOUND = 2, - NETCONF_QUERY_ACCESS_DENIED = 3, - NETCONF_QUERY_INTERNAL_SERVER_ERROR = 4 + NETCONF_QUERY_OBJECT_NOT_FOUND = 1, + NETCONF_QUERY_ACCESS_DENIED = 2, + NETCONF_QUERY_INTERNAL_SERVER_ERROR = 3 }; NetworkController() {} diff --git a/version.h b/version.h index f7b253a7..62f8fb69 100644 --- a/version.h +++ b/version.h @@ -41,6 +41,6 @@ /** * Revision */ -#define ZEROTIER_ONE_VERSION_REVISION 3 +#define ZEROTIER_ONE_VERSION_REVISION 4 #endif -- cgit v1.2.3 From b3516c599bb0beb4b4827f28da472972344379c6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 23 Jul 2015 10:10:17 -0700 Subject: Add a rate limiting circuit breaker to the network controller to prevent flooding attacks and race conditions. --- controller/SqliteNetworkController.cpp | 13 +++++++++++++ controller/SqliteNetworkController.hpp | 2 ++ node/IncomingPacket.cpp | 3 +++ node/NetworkController.hpp | 3 ++- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index f6489640..bdf337ec 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -64,6 +64,10 @@ // API version reported via JSON control plane #define ZT_NETCONF_CONTROLLER_API_VERSION 1 +// Drop requests for a given peer and network ID that occur more frequently +// than this (ms). +#define ZT_NETCONF_MIN_REQUEST_PERIOD 5000 + namespace ZeroTier { namespace { @@ -316,6 +320,15 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR; } + // Check rate limit + + { + uint64_t &lrt = _lastRequestTime[std::pair(identity.address(),nwid)]; + uint64_t lrt2 = lrt; + if (((lrt = OSUtils::now()) - lrt2) <= ZT_NETCONF_MIN_REQUEST_PERIOD) + return NetworkController::NETCONF_QUERY_IGNORE; + } + NetworkRecord network; memset(&network,0,sizeof(network)); Utils::snprintf(network.id,sizeof(network.id),"%.16llx",(unsigned long long)nwid); diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index bae11519..002493ec 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -98,6 +98,8 @@ private: std::string _dbPath; std::string _instanceId; + std::map< std::pair,uint64_t > _lastRequestTime; + sqlite3 *_db; sqlite3_stmt *_sGetNetworkById; diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c3d8cc6d..76c47933 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -717,6 +717,9 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons TRACE("NETWORK_CONFIG_REQUEST failed: internal error: %s",netconf.get("error","(unknown)").c_str()); break; + case NetworkController::NETCONF_QUERY_IGNORE: + break; + default: TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()"); break; diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index bef884de..ee481a62 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -54,7 +54,8 @@ public: NETCONF_QUERY_OK = 0, NETCONF_QUERY_OBJECT_NOT_FOUND = 1, NETCONF_QUERY_ACCESS_DENIED = 2, - NETCONF_QUERY_INTERNAL_SERVER_ERROR = 3 + NETCONF_QUERY_INTERNAL_SERVER_ERROR = 3, + NETCONF_QUERY_IGNORE = 4 }; NetworkController() {} -- cgit v1.2.3 From a493fc23f4305f80d93f0879324aa87f536a1a90 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 23 Jul 2015 13:05:18 -0700 Subject: Fix for make-linux: detect whether CC/CXX were explicitly overridden, and if not then use the gcc/clang selection logic. Otherwise ?= breaks this. --- make-linux.mk | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/make-linux.mk b/make-linux.mk index c56f3569..d1e0c955 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -18,8 +18,14 @@ # # Automagically pick clang or gcc, with preference for clang -CC?=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) -CXX?=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) +# This is only done if we have not overridden these with an environment or CLI variable +ifeq ($(origin CC),default) + CC=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) +endif +ifeq ($(origin CXX),default) + CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) +endif + INCLUDES= DEFS= LDLIBS?= -- cgit v1.2.3 From d647a587a1c920cdf58ce77872280e4e4ec9cca9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 23 Jul 2015 17:18:20 -0700 Subject: (1) Fix updating of network revision counter on member change. (2) Go back to timestamp as certificate revision number. This is simpler and more robust than using the network revision number for this and forcing network revision fast-forward, which could cause some peers to fall off the horizon when you don't want them to. --- controller/SqliteNetworkController.cpp | 17 +++++++++++++++-- include/ZeroTierOne.h | 11 ----------- node/Constants.hpp | 4 ++-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index bdf337ec..b41c7ef5 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -66,7 +66,7 @@ // Drop requests for a given peer and network ID that occur more frequently // than this (ms). -#define ZT_NETCONF_MIN_REQUEST_PERIOD 5000 +#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000 namespace ZeroTier { @@ -689,7 +689,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co // TODO: IPv6 auto-assign once it's supported in UI if (network.isPrivate) { - CertificateOfMembership com(network.revision,ZT1_CERTIFICATE_OF_MEMBERSHIP_REVISION_MAX_DELTA,nwid,identity.address()); + CertificateOfMembership com(OSUtils::now(),ZT_NETWORK_AUTOCONF_DELAY + (ZT_NETWORK_AUTOCONF_DELAY / 2),nwid,identity.address()); if (com.sign(signingId)) // basically can't fail unless our identity is invalid netconf[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP] = com.toString(); else { @@ -757,6 +757,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( char addrs[24]; Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address); + int64_t addToNetworkRevision = 0; + int64_t memberRowId = 0; sqlite3_reset(_sGetMember); sqlite3_bind_text(_sGetMember,1,nwids,16,SQLITE_STATIC); @@ -780,6 +782,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( sqlite3_reset(_sIncrementMemberRevisionCounter); sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC); sqlite3_step(_sIncrementMemberRevisionCounter); + addToNetworkRevision = 1; } json_value *j = json_parse(body.c_str(),body.length()); @@ -799,6 +802,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( sqlite3_reset(_sIncrementMemberRevisionCounter); sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC); sqlite3_step(_sIncrementMemberRevisionCounter); + addToNetworkRevision = 1; } } else if (!strcmp(j->u.object.values[k].name,"activeBridge")) { if (j->u.object.values[k].value->type == json_boolean) { @@ -812,6 +816,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( sqlite3_reset(_sIncrementMemberRevisionCounter); sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC); sqlite3_step(_sIncrementMemberRevisionCounter); + addToNetworkRevision = 1; } } else if (!strcmp(j->u.object.values[k].name,"ipAssignments")) { if (j->u.object.values[k].value->type == json_array) { @@ -855,6 +860,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( } } } + addToNetworkRevision = 1; } } @@ -863,6 +869,13 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST( json_value_free(j); } + if ((addToNetworkRevision > 0)&&(revision > 0)) { + sqlite3_reset(_sSetNetworkRevision); + sqlite3_bind_int64(_sSetNetworkRevision,1,revision + addToNetworkRevision); + sqlite3_bind_text(_sSetNetworkRevision,2,nwids,16,SQLITE_STATIC); + sqlite3_step(_sSetNetworkRevision); + } + return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType); } // else 404 diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 7ae524a8..dc2243f2 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -105,17 +105,6 @@ extern "C" { */ #define ZT1_MAX_PEER_NETWORK_PATHS 4 -/** - * Maximum number of revisions over which a network COM can differ and still be in-horizon (agree) - * - * This is the default max delta for the revision field in COMs issued - * by network controllers, and is defined here for documentation purposes. - * When a network is changed so as to de-authorize a member, its revision - * should be incremented by this number. Otherwise all other changes that - * materially affect the network should result in increment by one. - */ -#define ZT1_CERTIFICATE_OF_MEMBERSHIP_REVISION_MAX_DELTA 16 - /** * Feature flag: ZeroTier One was built to be thread-safe -- concurrent processXXX() calls are okay */ diff --git a/node/Constants.hpp b/node/Constants.hpp index d15fef13..c192381c 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -158,7 +158,7 @@ /** * Maximum number of packet fragments we'll support - * + * * The actual spec allows 16, but this is the most we'll support right * now. Packets with more than this many fragments are dropped. */ @@ -216,7 +216,7 @@ /** * Maximum number of ZT hops allowed (this is not IP hops/TTL) - * + * * The protocol allows up to 7, but we limit it to something smaller. */ #define ZT_RELAY_MAX_HOPS 3 -- cgit v1.2.3 From d57ea671d7d10b242def3b6d43832906275adff9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Jul 2015 09:59:17 -0700 Subject: Add version to log. --- controller/SqliteNetworkController.cpp | 89 ++++++++++++++-------------------- controller/SqliteNetworkController.hpp | 1 + controller/schema.sql | 1 + controller/schema.sql.c | 1 + 4 files changed, 39 insertions(+), 53 deletions(-) diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index b41c7ef5..50be5b34 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -209,8 +209,9 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) : ||(sqlite3_prepare_v2(_db,"INSERT INTO Gateway (networkId,\"ip\",ipVersion,metric) VALUES (?,?,?,?)",-1,&_sCreateGateway,(const char **)0) != SQLITE_OK) /* Log */ - ||(sqlite3_prepare_v2(_db,"INSERT INTO \"Log\" (networkId,nodeId,\"ts\",\"authorized\",fromAddr) VALUES (?,?,?,?,?)",-1,&_sPutLog,(const char **)0) != SQLITE_OK) - ||(sqlite3_prepare_v2(_db,"SELECT \"ts\",\"authorized\",fromAddr FROM \"Log\" WHERE networkId = ? AND nodeId = ? AND \"ts\" >= ? ORDER BY \"ts\" ASC",-1,&_sGetMemberLog,(const char **)0) != SQLITE_OK) + ||(sqlite3_prepare_v2(_db,"INSERT INTO \"Log\" (networkId,nodeId,\"ts\",\"authorized\",\"version\",fromAddr) VALUES (?,?,?,?,?,?)",-1,&_sPutLog,(const char **)0) != SQLITE_OK) + ||(sqlite3_prepare_v2(_db,"SELECT \"ts\",\"authorized\",\"version\",fromAddr FROM \"Log\" WHERE networkId = ? AND nodeId = ? AND \"ts\" >= ? ORDER BY \"ts\" ASC",-1,&_sGetMemberLog,(const char **)0) != SQLITE_OK) + ||(sqlite3_prepare_v2(_db,"SELECT \"ts\",\"authorized\",\"version\",fromAddr FROM \"Log\" WHERE networkId = ? AND nodeId = ? ORDER BY \"ts\" DESC LIMIT 10",-1,&_sGetRecentMemberLog,(const char **)0) != SQLITE_OK) /* Config */ ||(sqlite3_prepare_v2(_db,"SELECT \"v\" FROM \"Config\" WHERE \"k\" = ?",-1,&_sGetConfig,(const char **)0) != SQLITE_OK) @@ -294,6 +295,7 @@ SqliteNetworkController::~SqliteNetworkController() sqlite3_finalize(_sSetConfig); sqlite3_finalize(_sPutLog); sqlite3_finalize(_sGetMemberLog); + sqlite3_finalize(_sGetRecentMemberLog); sqlite3_close(_db); } } @@ -415,6 +417,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co // Add log entry { + char ver[16]; std::string fa; if (fromAddr) { fa = fromAddr.toString(); @@ -426,9 +429,13 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co sqlite3_bind_text(_sPutLog,2,member.nodeId,10,SQLITE_STATIC); sqlite3_bind_int64(_sPutLog,3,(long long)OSUtils::now()); sqlite3_bind_int(_sPutLog,4,member.authorized ? 1 : 0); + if ((clientMajorVersion > 0)||(clientMinorVersion > 0)||(clientRevision > 0)) { + Utils::snprintf(ver,sizeof(ver),"%u.%u.%u",clientMajorVersion,clientMinorVersion,clientRevision); + sqlite3_bind_text(_sPutLog,5,ver,-1,SQLITE_STATIC); + } else sqlite3_bind_null(_sPutLog,5); if (fa.length() > 0) - sqlite3_bind_text(_sPutLog,5,fa.c_str(),-1,SQLITE_STATIC); - else sqlite3_bind_null(_sPutLog,5); + sqlite3_bind_text(_sPutLog,6,fa.c_str(),-1,SQLITE_STATIC); + else sqlite3_bind_null(_sPutLog,6); sqlite3_step(_sPutLog); } @@ -1386,57 +1393,33 @@ unsigned int SqliteNetworkController::_doCPGet( responseBody.push_back('"'); } - responseBody.append("]"); - - /* It's possible to get the actual netconf dictionary by including these - * three URL arguments. The member identity must be the string - * serialized identity of this member, and the signing identity must be - * the full secret identity of this network controller. The have revision - * is optional but would designate the revision our hypothetical client - * already has. - * - * This is primarily for testing and is not used in production. It makes - * it easy to test the entire network controller via its JSON API. - * - * If these arguments are included, three more object fields are returned: - * 'netconf', 'netconfResult', and 'netconfResultMessage'. These are all - * string fields and contain the actual netconf dictionary, the query - * result code, and any verbose message e.g. an error description. */ - std::map::const_iterator memids(urlArgs.find("memberIdentity")); - std::map::const_iterator sigids(urlArgs.find("signingIdentity")); - std::map::const_iterator hrs(urlArgs.find("haveRevision")); - if ((memids != urlArgs.end())&&(sigids != urlArgs.end())) { - Dictionary netconf; - Identity memid,sigid; - try { - if (memid.fromString(memids->second)&&sigid.fromString(sigids->second)&&sigid.hasPrivate()) { - uint64_t hr = 0; - if (hrs != urlArgs.end()) - hr = Utils::strToU64(hrs->second.c_str()); - const char *result = ""; - switch(this->doNetworkConfigRequest(InetAddress(),sigid,memid,nwid,Dictionary(),hr,netconf)) { - case NetworkController::NETCONF_QUERY_OK: result = "OK"; break; - case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: result = "OBJECT_NOT_FOUND"; break; - case NetworkController::NETCONF_QUERY_ACCESS_DENIED: result = "ACCESS_DENIED"; break; - case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: result = "INTERNAL_SERVER_ERROR"; break; - default: result = "(unrecognized result code)"; break; - } - responseBody.append(",\n\t\"netconf\": \""); - responseBody.append(_jsonEscape(netconf.toString().c_str())); - responseBody.append("\",\n\t\"netconfResult\": \""); - responseBody.append(result); - responseBody.append("\",\n\t\"netconfResultMessage\": \""); - responseBody.append(_jsonEscape(netconf["error"].c_str())); - responseBody.append("\""); - } else { - responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"invalid member or signing identity\""); - } - } catch ( ... ) { - responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"unexpected exception\""); - } + responseBody.append("],\n\t\"recentLog\": ["); + + sqlite3_reset(_sGetRecentMemberLog); + sqlite3_bind_text(_sGetRecentMemberLog,1,nwids,16,SQLITE_STATIC); + sqlite3_bind_text(_sGetRecentMemberLog,2,addrs,10,SQLITE_STATIC); + bool firstLog = true; + while (sqlite3_step(_sGetRecentMemberLog) == SQLITE_ROW) { + responseBody.append(firstLog ? "{" : ",{"); + firstLog = false; + responseBody.append("\"ts\":"); + responseBody.append(reinterpret_cast(sqlite3_column_text(_sGetRecentMemberLog,0))); + responseBody.append((sqlite3_column_int(_sGetRecentMemberLog,1) == 0) ? ",\"authorized\":false,\"version\":" : ",\"authorized\":true,\"version\":"); + const char *ver = reinterpret_cast(sqlite3_column_text(_sGetRecentMemberLog,2)); + if ((ver)&&(ver[0])) { + responseBody.push_back('"'); + responseBody.append(_jsonEscape(ver)); + responseBody.append("\",\"fromAddr\":"); + } else responseBody.append("null,\"fromAddr\":"); + const char *fa = reinterpret_cast(sqlite3_column_text(_sGetRecentMemberLog,3)); + if ((fa)&&(fa[0])) { + responseBody.push_back('"'); + responseBody.append(_jsonEscape(fa)); + responseBody.append("\"}"); + } else responseBody.append("null}"); } - responseBody.append("\n}\n"); + responseBody.append("]\n}\n"); responseContentType = "application/json"; return 200; diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 002493ec..adfe0991 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -146,6 +146,7 @@ private: sqlite3_stmt *_sSetConfig; sqlite3_stmt *_sPutLog; sqlite3_stmt *_sGetMemberLog; + sqlite3_stmt *_sGetRecentMemberLog; Mutex _lock; }; diff --git a/controller/schema.sql b/controller/schema.sql index 024a5229..398d63ac 100644 --- a/controller/schema.sql +++ b/controller/schema.sql @@ -70,6 +70,7 @@ CREATE TABLE Log ( nodeId char(10) NOT NULL, ts integer NOT NULL, authorized integer NOT NULL, + version varchar(16), fromAddr varchar(64) ); diff --git a/controller/schema.sql.c b/controller/schema.sql.c index ac0213bc..fa83f880 100644 --- a/controller/schema.sql.c +++ b/controller/schema.sql.c @@ -71,6 +71,7 @@ " nodeId char(10) NOT NULL,\n"\ " ts integer NOT NULL,\n"\ " authorized integer NOT NULL,\n"\ +" version varchar(16),\n"\ " fromAddr varchar(64)\n"\ ");\n"\ "\n"\ -- cgit v1.2.3 From dba91eaa096d85992bf37a6c19dbead8104d9088 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Jul 2015 13:17:41 -0700 Subject: Apply same Linux compiler-picker logic to Mac. --- make-mac.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/make-mac.mk b/make-mac.mk index 1bc842ce..02d42252 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -1,5 +1,9 @@ -CC?=clang -CXX?=clang++ +ifeq ($(origin CC),default) + CC=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) +endif +ifeq ($(origin CXX),default) + CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) +endif INCLUDES=-I/usr/local/include DEFS= -- cgit v1.2.3 From 7a15d8a7e3fb4934200887666afdf17afb1178e5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Jul 2015 14:50:44 -0700 Subject: Fix leaving of networks to actually call Network::destroy(). --- node/Node.cpp | 1 + osdep/OSUtils.hpp | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/node/Node.cpp b/node/Node.cpp index ebe0527e..d40ceab9 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -316,6 +316,7 @@ ZT1_ResultCode Node::leave(uint64_t nwid) for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) { if (n->first != nwid) newn.push_back(*n); + else n->second->destroy(); } _networks.swap(newn); return ZT1_RESULT_OK; diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index bfe9b68a..5de35eba 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -121,10 +121,10 @@ public: /** * Set modes on a file to something secure - * + * * This locks a file so that only the owner can access it. What it actually * does varies by platform. - * + * * @param path Path to lock * @param isDir True if this is a directory */ @@ -252,4 +252,3 @@ private: } // namespace ZeroTier #endif - -- cgit v1.2.3 From e30ba3e1382b50aa8f393132204f8f27ccfb03f9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Jul 2015 16:43:05 -0700 Subject: Eliminate some aggressive port scanning NAT-t behavior that has proven ineffective. --- node/Switch.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index cf4fe249..3d9ef5b1 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -451,7 +451,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) { unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - { // Aggressive NAT traversal time! + { Mutex::Lock _l(_contactQueue_m); for(std::list::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { if (now >= qi->fireAtTime) { @@ -460,26 +460,17 @@ unsigned long Switch::doTimerTasks(uint64_t now) _contactQueue.erase(qi++); continue; } else { - // Nope, nothing yet. Time to kill some kittens. if (qi->strategyIteration == 0) { // First strategy: send packet directly (we already tried this but try again) qi->peer->attemptToContactAt(RR,qi->inaddr,now); - } else if (qi->strategyIteration <= 9) { - // Strategies 1-9: try escalating ports + } else if (qi->strategyIteration <= 4) { + // Strategies 1-4: try escalating ports InetAddress tmpaddr(qi->inaddr); int p = (int)qi->inaddr.port() + qi->strategyIteration; if (p < 0xffff) { tmpaddr.setPort((unsigned int)p); qi->peer->attemptToContactAt(RR,tmpaddr,now); } else qi->strategyIteration = 9; - } else if (qi->strategyIteration <= 18) { - // Strategies 10-18: try ports below - InetAddress tmpaddr(qi->inaddr); - int p = (int)qi->inaddr.port() - (qi->strategyIteration - 9); - if (p >= 1024) { - tmpaddr.setPort((unsigned int)p); - qi->peer->attemptToContactAt(RR,tmpaddr,now); - } else qi->strategyIteration = 18; } else { // All strategies tried, expire entry _contactQueue.erase(qi++); -- cgit v1.2.3 From f0003ea92277039f70dd6f16920dd2db9fb2fb1e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Jul 2015 17:02:43 -0700 Subject: Push remote surface as reported by peers along with known interface direct paths to assist with (some) NAT traversal. (trying this, may back out if not effective) --- node/Peer.cpp | 19 +++++++++++++++++++ node/SelfAwareness.hpp | 14 ++++++++++++++ node/Topology.hpp | 8 ++++---- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index 73c20228..804e6e39 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -33,6 +33,7 @@ #include "Switch.hpp" #include "Network.hpp" #include "AntiRecursion.hpp" +#include "SelfAwareness.hpp" #include @@ -229,6 +230,24 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ _lastDirectPathPush = now; std::vector dps(RR->node->directPaths()); + + /* Also push paths reported to us by non-root-server peers. This assists + * with NAT traversal behind NATs that engage in strange or randomized + * port assignment behavior. */ + std::vector
rootAddresses(RR->topology->rootAddresses()); + std::vector< std::pair > surface(RR->sa->getReportedSurface()); + for(std::vector< std::pair >::const_iterator s(surface.begin());s!=surface.end();++s) { + bool alreadyHave = false; + for(std::vector::const_iterator p(dps.begin());p!=dps.end();++p) { + if (p->address() == s->second) { + alreadyHave = true; + break; + } + } + if ((!alreadyHave)&&(std::find(rootAddresses.begin(),rootAddresses.end(),s->first) == rootAddresses.end())) + dps.push_back(Path(s->second,0,Path::TRUST_NORMAL)); + } + #ifdef ZT_TRACE { std::string ps; diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 4780fa5b..9fcefa62 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -29,6 +29,7 @@ #define ZT_SELFAWARENESS_HPP #include +#include #include "InetAddress.hpp" #include "Address.hpp" @@ -65,6 +66,19 @@ public: */ void clean(uint64_t now); + /** + * @return List of external surface addresses as reported by peers + */ + inline std::vector< std::pair > getReportedSurface() const + { + std::vector< std::pair > r; + Mutex::Lock _l(_phy_m); + r.reserve(_phy.size()); + for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();) + r.push_back(std::pair(p->first.reporter,p->second.mySurface)); + return r; + } + private: struct PhySurfaceKey { diff --git a/node/Topology.hpp b/node/Topology.hpp index c878bcc6..1c5cca00 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -86,7 +86,7 @@ public: /** * Get a peer from its address - * + * * @param zta ZeroTier address of peer * @return Peer or NULL if not found */ @@ -103,7 +103,7 @@ public: /** * Get the current favorite root server - * + * * @return Root server with lowest latency or NULL if none */ inline SharedPtr getBestRoot() @@ -113,11 +113,11 @@ public: /** * Get the best root server, avoiding root servers listed in an array - * + * * This will get the best root server (lowest latency, etc.) but will * try to avoid the listed root servers, only using them if no others * are available. - * + * * @param avoid Nodes to avoid * @param avoidCount Number of nodes to avoid * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available -- cgit v1.2.3 From fadb2919625f72b7f0fbff17478ac467a86e657b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Jul 2015 17:14:49 -0700 Subject: Fix infinite loop typo. --- node/SelfAwareness.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 9fcefa62..1b160a3f 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -72,10 +72,12 @@ public: inline std::vector< std::pair > getReportedSurface() const { std::vector< std::pair > r; - Mutex::Lock _l(_phy_m); - r.reserve(_phy.size()); - for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();) - r.push_back(std::pair(p->first.reporter,p->second.mySurface)); + { + Mutex::Lock _l(_phy_m); + r.reserve(_phy.size()); + for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();++p) + r.push_back(std::pair(p->first.reporter,p->second.mySurface)); + } return r; } -- cgit v1.2.3 From e99eda4a4a178bbdbb419791587b581431061439 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Jul 2015 17:28:13 -0700 Subject: Fix IP scoping bug, and disable remotely reported surface push... not helping. :( --- node/InetAddress.cpp | 2 +- node/Peer.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index 91bfbed6..1942c4cd 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -74,7 +74,7 @@ InetAddress::IpScope InetAddress::ipScope() const if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12 break; case 0xc0: - if ((ip & 0xffff0000) == 0xc9a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16 + if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16 break; case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) default: diff --git a/node/Peer.cpp b/node/Peer.cpp index 804e6e39..ab3d61a6 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -226,15 +226,13 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) { - if ((((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force))) { + if ((true)||(((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force))) { _lastDirectPathPush = now; std::vector dps(RR->node->directPaths()); - /* Also push paths reported to us by non-root-server peers. This assists - * with NAT traversal behind NATs that engage in strange or randomized - * port assignment behavior. */ - std::vector
rootAddresses(RR->topology->rootAddresses()); + // Push peer-reported surface -- tried this and it didn't help much with difficult NATs so commenting out. + /* std::vector< std::pair > surface(RR->sa->getReportedSurface()); for(std::vector< std::pair >::const_iterator s(surface.begin());s!=surface.end();++s) { bool alreadyHave = false; @@ -244,9 +242,10 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ break; } } - if ((!alreadyHave)&&(std::find(rootAddresses.begin(),rootAddresses.end(),s->first) == rootAddresses.end())) + if (!alreadyHave) dps.push_back(Path(s->second,0,Path::TRUST_NORMAL)); } + */ #ifdef ZT_TRACE { -- cgit v1.2.3 From 821f1f366e468d1ff2f45a9e871ccec04b80fd3f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 27 Jul 2015 17:34:58 -0700 Subject: Fix to NAT escalation sequence. --- node/Switch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index 3d9ef5b1..18935ce5 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -470,7 +470,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) if (p < 0xffff) { tmpaddr.setPort((unsigned int)p); qi->peer->attemptToContactAt(RR,tmpaddr,now); - } else qi->strategyIteration = 9; + } else qi->strategyIteration = 5; } else { // All strategies tried, expire entry _contactQueue.erase(qi++); -- cgit v1.2.3 From 40d5c79b62e7ca7f6da7697e720fb0eb49a26125 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 10:29:25 -0700 Subject: Enable SO_NO_CHECK if available to skip UDP checksum on packet send for slight performance improvement. We do our own cryptographically secure authentication so UDP checksum is worthless. --- osdep/Http.cpp | 2 +- osdep/Phy.hpp | 12 ++++++++++-- selftest.cpp | 2 +- service/OneService.cpp | 2 +- tcp-proxy/tcp-proxy.cpp | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/osdep/Http.cpp b/osdep/Http.cpp index cd3cf137..d491b062 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -232,7 +232,7 @@ unsigned int Http::_do( handler.error = false; handler.done = false; - Phy phy(&handler,true); + Phy phy(&handler,true,true); bool instantConnect = false; handler.phy = &phy; diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index ec01625b..5afd715b 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -144,7 +144,7 @@ private: fd_set _readfds; fd_set _writefds; #if defined(_WIN32) || defined(_WIN64) - fd_set _exceptfds; + fd_set _exceptfds; #endif long _nfds; @@ -152,13 +152,15 @@ private: ZT_PHY_SOCKFD_TYPE _whackSendSocket; bool _noDelay; + bool _noCheck; public: /** * @param handler Pointer of type HANDLER_PTR_TYPE to handler * @param noDelay If true, disable TCP NAGLE algorithm on TCP sockets + * @param noCheck If true, attempt to set UDP SO_NO_CHECK option to disable sending checksums */ - Phy(HANDLER_PTR_TYPE handler,bool noDelay) : + Phy(HANDLER_PTR_TYPE handler,bool noDelay,bool noCheck) : _handler(handler) { FD_ZERO(&_readfds); @@ -202,6 +204,7 @@ public: _whackReceiveSocket = pipes[0]; _whackSendSocket = pipes[1]; _noDelay = noDelay; + _noCheck = noCheck; } ~Phy() @@ -296,6 +299,11 @@ public: #endif #ifdef IP_MTU_DISCOVER f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f)); +#endif +#ifdef SO_NO_CHECK + if (_noCheck) { + f = 1; setsockopt(s,SOL_SOCKET,SO_NO_CHECK,(void *)&f,sizeof(f)); + } #endif } #endif // Windows or not diff --git a/selftest.cpp b/selftest.cpp index cf20fdf3..714964cb 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -696,7 +696,7 @@ static int testPhy() std::cout << "[phy] Creating phy endpoint..." << std::endl; TestPhyHandlers testPhyHandlers; - testPhyInstance = new Phy(&testPhyHandlers,false); + testPhyInstance = new Phy(&testPhyHandlers,false,true); std::cout << "[phy] Binding UDP listen socket to 127.0.0.1/60002... "; PhySocket *udpListenSock = testPhyInstance->udpBind((const struct sockaddr *)&bindaddr); diff --git a/service/OneService.cpp b/service/OneService.cpp index d582a893..b83cd83f 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -404,7 +404,7 @@ public: #ifdef ZT_ENABLE_NETWORK_CONTROLLER _controller((_homePath + ZT_PATH_SEPARATOR_S + ZT1_CONTROLLER_DB_PATH).c_str()), #endif - _phy(this,false), + _phy(this,false,true), _overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""), _node((Node *)0), _controlPlane((ControlPlane *)0), diff --git a/tcp-proxy/tcp-proxy.cpp b/tcp-proxy/tcp-proxy.cpp index 6acf7b42..70c0281a 100644 --- a/tcp-proxy/tcp-proxy.cpp +++ b/tcp-proxy/tcp-proxy.cpp @@ -297,7 +297,7 @@ int main(int argc,char **argv) srand(time((time_t *)0)); TcpProxyService svc; - Phy phy(&svc,false); + Phy phy(&svc,false,true); svc.phy = &phy; svc.udpPortCounter = 1023; -- cgit v1.2.3 From dda376c9eb0800b824f423db30399d93e89cb162 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:16:43 -0700 Subject: Nuke some abandoned code. --- node/Peer.cpp | 16 ---------------- node/SelfAwareness.hpp | 15 --------------- 2 files changed, 31 deletions(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index ab3d61a6..2bfd421f 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -231,22 +231,6 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ std::vector dps(RR->node->directPaths()); - // Push peer-reported surface -- tried this and it didn't help much with difficult NATs so commenting out. - /* - std::vector< std::pair > surface(RR->sa->getReportedSurface()); - for(std::vector< std::pair >::const_iterator s(surface.begin());s!=surface.end();++s) { - bool alreadyHave = false; - for(std::vector::const_iterator p(dps.begin());p!=dps.end();++p) { - if (p->address() == s->second) { - alreadyHave = true; - break; - } - } - if (!alreadyHave) - dps.push_back(Path(s->second,0,Path::TRUST_NORMAL)); - } - */ - #ifdef ZT_TRACE { std::string ps; diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 1b160a3f..4eede592 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -66,21 +66,6 @@ public: */ void clean(uint64_t now); - /** - * @return List of external surface addresses as reported by peers - */ - inline std::vector< std::pair > getReportedSurface() const - { - std::vector< std::pair > r; - { - Mutex::Lock _l(_phy_m); - r.reserve(_phy.size()); - for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();++p) - r.push_back(std::pair(p->first.reporter,p->second.mySurface)); - } - return r; - } - private: struct PhySurfaceKey { -- cgit v1.2.3 From b31071463cafda54afbf6f01d37aa7451b217b12 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:28:47 -0700 Subject: Try another NAT traversal improvement. --- node/Constants.hpp | 3 +++ node/IncomingPacket.cpp | 2 +- node/SelfAwareness.cpp | 15 +++++++++++++++ node/SelfAwareness.hpp | 5 +++++ node/Switch.cpp | 19 ++++++++++++++----- node/Switch.hpp | 4 ++-- 6 files changed, 40 insertions(+), 8 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index c192381c..31a4c313 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -296,6 +296,9 @@ /** * Delay between initial direct NAT-t packet and more aggressive techniques + * + * This may also be a delay before sending the first packet if we determine + * that we should wait for the remote to initiate rendezvous first. */ #define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000 diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 76c47933..b1fda8ef 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -488,7 +488,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); peer->received(RR,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); - RR->sw->contact(withPeer,atAddr); + RR->sw->rendezvous(withPeer,atAddr); } else { TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index 00015788..716cf7f3 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -147,4 +147,19 @@ void SelfAwareness::clean(uint64_t now) } } +bool SelfAwareness::areGlobalIPv4PortsRandomized() const +{ + int port = 0; + Mutex::Lock _l(_phy_m); + for(std::map< PhySurfaceKey,PhySurfaceEntry >::const_iterator p(_phy.begin());p!=_phy.end();++p) { + if ((p->first.scope == InetAddress::IP_SCOPE_GLOBAL)&&(p->second.mySurface.ss_family == AF_INET)) { + const int tmp = (int)p->second.mySurface.port(); + if ((port)&&(tmp != port)) + return true; + else port = tmp; + } + } + return false; +} + } // namespace ZeroTier diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 4eede592..d3b79d18 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -66,6 +66,11 @@ public: */ void clean(uint64_t now); + /** + * @return True if our external (global scope) IPv4 ports appear to be randomized by a NAT device + */ + bool areGlobalIPv4PortsRandomized() const; + private: struct PhySurfaceKey { diff --git a/node/Switch.cpp b/node/Switch.cpp index 18935ce5..a580078e 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -43,6 +43,7 @@ #include "Topology.hpp" #include "Peer.hpp" #include "AntiRecursion.hpp" +#include "SelfAwareness.hpp" #include "Packet.hpp" namespace ZeroTier { @@ -385,15 +386,23 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) return true; } -void Switch::contact(const SharedPtr &peer,const InetAddress &atAddr) +void Switch::rendezvous(const SharedPtr &peer,const InetAddress &atAddr) { TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); const uint64_t now = RR->node->now(); - // Attempt to contact directly - peer->attemptToContactAt(RR,atAddr,now); - - // If we have not punched through after this timeout, open refreshing can of whupass + /* Attempt direct contact now unless we are IPv4 and our external ports + * appear to be randomized by a NAT device. In that case, we should let + * the other side send a message first. Why? If the other side is also + * randomized and symmetric, we are probably going to fail. But if the + * other side is "port restricted" but otherwise sane, us sending a + * packet first may actually close the remote's outgoing port to us! + * This assists with NAT-t in cases where one side is symmetric and the + * other is full cone but port restricted. */ + if ((atAddr.ss_family != AF_INET)||(!RR->sa->areGlobalIPv4PortsRandomized())) + peer->attemptToContactAt(RR,atAddr,now); + + // After 1s, try again and perhaps try more NAT-t strategies { Mutex::Lock _l(_contactQueue_m); _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,atAddr)); diff --git a/node/Switch.hpp b/node/Switch.hpp index e7f1523a..ac85606e 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -136,12 +136,12 @@ public: bool unite(const Address &p1,const Address &p2,bool force); /** - * Send NAT traversal messages to peer at the given candidate address + * Attempt NAT traversal to peer at a given physical address * * @param peer Peer to contact * @param atAddr Address of peer */ - void contact(const SharedPtr &peer,const InetAddress &atAddr); + void rendezvous(const SharedPtr &peer,const InetAddress &atAddr); /** * Request WHOIS on a given address -- cgit v1.2.3 From 17bfd4d55e96390147e2804b81c08985816ac4cd Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:32:34 -0700 Subject: Add TRACE for NAT-t debugging. --- node/Switch.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index a580078e..6f4659d5 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -399,8 +399,11 @@ void Switch::rendezvous(const SharedPtr &peer,const InetAddress &atAddr) * packet first may actually close the remote's outgoing port to us! * This assists with NAT-t in cases where one side is symmetric and the * other is full cone but port restricted. */ - if ((atAddr.ss_family != AF_INET)||(!RR->sa->areGlobalIPv4PortsRandomized())) + if ((atAddr.ss_family != AF_INET)||(!RR->sa->areGlobalIPv4PortsRandomized())) { peer->attemptToContactAt(RR,atAddr,now); + } else { + TRACE("behind randomizing symmetric NAT -- delaying initial message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); + } // After 1s, try again and perhaps try more NAT-t strategies { -- cgit v1.2.3 From 708aac1ea73a01fd81997a7215824dab832ba3d3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:43:09 -0700 Subject: Remove some left over debug code, and fix attempt to send to self if we are an active bridge. --- node/Multicaster.cpp | 16 ++++++++++------ node/Peer.cpp | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 33424e4a..489c170b 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -211,9 +211,11 @@ void Multicaster::send( unsigned int count = 0; for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { - out.sendOnly(RR,*ast); - if (++count >= limit) - break; + if (*ast != RR->identity.address()) { + out.sendOnly(RR,*ast); + if (++count >= limit) + break; + } } unsigned long idx = 0; @@ -264,9 +266,11 @@ void Multicaster::send( unsigned int count = 0; for(std::vector
::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) { - out.sendAndLog(RR,*ast); - if (++count >= limit) - break; + if (*ast != RR->identity.address()) { + out.sendAndLog(RR,*ast); + if (++count >= limit) + break; + } } unsigned long idx = 0; diff --git a/node/Peer.cpp b/node/Peer.cpp index 2bfd421f..3cf0ec4e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -226,7 +226,7 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) { - if ((true)||(((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force))) { + if (((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) { _lastDirectPathPush = now; std::vector dps(RR->node->directPaths()); -- cgit v1.2.3 From b69afa010ee04924b36cd9b605e8f37ed917f0b2 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:50:01 -0700 Subject: Disable type punning on ARM by ifdef. --- node/Constants.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/node/Constants.hpp b/node/Constants.hpp index 31a4c313..901237ce 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -60,6 +60,13 @@ #include #endif +// Disable type punning on ARM architecture -- some ARM chips throw SIGBUS on unaligned access +#if defined(__arm__) || defined(__ARMEL__) +#ifndef ZT_NO_TYPE_PUNNING +#define ZT_NO_TYPE_PUNNING +#endif +#endif + #if defined(__FreeBSD__) || defined(__OpenBSD__) #ifndef __UNIX_LIKE__ #define __UNIX_LIKE__ -- cgit v1.2.3 From d2bfdfa6e79e54ba1d5127a75a56f7ec57415cf9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 11:57:18 -0700 Subject: Play with NAT-t tweaks some more. --- node/Switch.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index 6f4659d5..247b2d18 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -391,24 +391,15 @@ void Switch::rendezvous(const SharedPtr &peer,const InetAddress &atAddr) TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); const uint64_t now = RR->node->now(); - /* Attempt direct contact now unless we are IPv4 and our external ports - * appear to be randomized by a NAT device. In that case, we should let - * the other side send a message first. Why? If the other side is also - * randomized and symmetric, we are probably going to fail. But if the - * other side is "port restricted" but otherwise sane, us sending a - * packet first may actually close the remote's outgoing port to us! - * This assists with NAT-t in cases where one side is symmetric and the - * other is full cone but port restricted. */ - if ((atAddr.ss_family != AF_INET)||(!RR->sa->areGlobalIPv4PortsRandomized())) { + if ((atAddr.ss_family == AF_INET)&&(RR->sa->areGlobalIPv4PortsRandomized())) { peer->attemptToContactAt(RR,atAddr,now); } else { TRACE("behind randomizing symmetric NAT -- delaying initial message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); } - // After 1s, try again and perhaps try more NAT-t strategies { Mutex::Lock _l(_contactQueue_m); - _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,atAddr)); + _contactQueue.push_back(ContactQueueEntry(peer,now + (ZT_NAT_T_TACTICAL_ESCALATION_DELAY / 2),atAddr)); } } @@ -473,10 +464,10 @@ unsigned long Switch::doTimerTasks(uint64_t now) continue; } else { if (qi->strategyIteration == 0) { - // First strategy: send packet directly (we already tried this but try again) + // First strategy: send packet directly to destination qi->peer->attemptToContactAt(RR,qi->inaddr,now); } else if (qi->strategyIteration <= 4) { - // Strategies 1-4: try escalating ports + // Strategies 1-4: try escalating ports for symmetric NATs that remap sequentially InetAddress tmpaddr(qi->inaddr); int p = (int)qi->inaddr.port() + qi->strategyIteration; if (p < 0xffff) { -- cgit v1.2.3 From 4564dd95ffa287b3752a59378137c59773d51ef9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 12:00:50 -0700 Subject: Revert... no luck with any of that. --- node/Switch.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index 247b2d18..bf9308b0 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -390,16 +390,10 @@ void Switch::rendezvous(const SharedPtr &peer,const InetAddress &atAddr) { TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); const uint64_t now = RR->node->now(); - - if ((atAddr.ss_family == AF_INET)&&(RR->sa->areGlobalIPv4PortsRandomized())) { - peer->attemptToContactAt(RR,atAddr,now); - } else { - TRACE("behind randomizing symmetric NAT -- delaying initial message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str()); - } - + peer->attemptToContactAt(RR,atAddr,now); { Mutex::Lock _l(_contactQueue_m); - _contactQueue.push_back(ContactQueueEntry(peer,now + (ZT_NAT_T_TACTICAL_ESCALATION_DELAY / 2),atAddr)); + _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,atAddr)); } } -- cgit v1.2.3 From 5986d837384d5794286ee6954bc433eb0d7cc668 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 12:04:14 -0700 Subject: Kill more kittens. --- node/Constants.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index 901237ce..b7aa9817 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -253,10 +253,10 @@ /** * How frequently to send a zero-byte UDP keepalive packet * - * There are NATs with timeouts as short as 30 seconds, so this turns out + * There are NATs with timeouts as short as 20 seconds, so this turns out * to be needed. */ -#define ZT_NAT_KEEPALIVE_DELAY 25000 +#define ZT_NAT_KEEPALIVE_DELAY 19000 /** * Delay between scans of the topology active peer DB for peers that need ping -- cgit v1.2.3 From 21e6850722539d4ff72b6c5841da47356233bb67 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 12:18:59 -0700 Subject: Cancel NAT-t attempts if peer is no longer "alive" --- node/Switch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index bf9308b0..02881331 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -452,8 +452,8 @@ unsigned long Switch::doTimerTasks(uint64_t now) Mutex::Lock _l(_contactQueue_m); for(std::list::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { if (now >= qi->fireAtTime) { - if (qi->peer->hasActiveDirectPath(now)) { - // We've successfully NAT-t'd, so cancel attempt + if ((!qi->peer->alive(now))||(qi->peer->hasActiveDirectPath(now))) { + // Cancel attempt if we've already connected or peer is no longer "alive" _contactQueue.erase(qi++); continue; } else { -- cgit v1.2.3 From eea8d58afa6ceb0fd04d6d82c551ff9f81a0ffe7 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 12:39:03 -0700 Subject: docs,cleanup --- node/Switch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index 02881331..989f497a 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -448,7 +448,7 @@ unsigned long Switch::doTimerTasks(uint64_t now) { unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - { + { // Iterate through NAT traversal strategies for entries in contact queue Mutex::Lock _l(_contactQueue_m); for(std::list::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) { if (now >= qi->fireAtTime) { -- cgit v1.2.3 From fe6d5b1402307e1be80e6d78b765cf5175288c1f Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 14:32:02 -0700 Subject: UPNP/NAT-PMP support with libminiupnpc (if built with it) -- GitHub issue #64 --- make-mac.mk | 19 +++-- osdep/UPNPClient.cpp | 192 +++++++++++++++++++++++++++++++++++++++++++++++++ osdep/UPNPClient.hpp | 84 ++++++++++++++++++++++ service/OneService.cpp | 21 +++++- 4 files changed, 308 insertions(+), 8 deletions(-) create mode 100644 osdep/UPNPClient.cpp create mode 100644 osdep/UPNPClient.hpp diff --git a/make-mac.mk b/make-mac.mk index 02d42252..55b117e6 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -11,7 +11,7 @@ LIBS= ARCH_FLAGS=-arch x86_64 include objects.mk -OBJS+=osdep/OSXEthernetTap.o +OBJS+=osdep/OSXEthernetTap.o # Disable codesign since open source users will not have ZeroTier's certs CODESIGN=echo @@ -21,7 +21,8 @@ CODESIGN_INSTALLER_CERT= # For internal use only -- signs everything with ZeroTier's developer cert ifeq ($(ZT_OFFICIAL_RELEASE),1) - DEFS+=-DZT_OFFICIAL_RELEASE -DZT_AUTO_UPDATE + DEFS+=-DZT_OFFICIAL_RELEASE -DZT_AUTO_UPDATE + ZT_USE_MINIUPNPC=1 CODESIGN=codesign PRODUCTSIGN=productsign CODESIGN_APP_CERT="Developer ID Application: ZeroTier Networks LLC (8ZD9JUCZ4V)" @@ -29,19 +30,25 @@ ifeq ($(ZT_OFFICIAL_RELEASE),1) endif ifeq ($(ZT_AUTO_UPDATE),1) - DEFS+=-DZT_AUTO_UPDATE + DEFS+=-DZT_AUTO_UPDATE +endif + +ifeq ($(ZT_USE_MINIUPNPC),1) + DEFS+=-DZT_USE_MINIUPNPC + LIBS+=/usr/local/lib/libminiupnpc.a + OBJS+=osdep/UPNPClient.o endif # Build with ZT_ENABLE_NETWORK_CONTROLLER=1 to build with the Sqlite network controller ifeq ($(ZT_ENABLE_NETWORK_CONTROLLER),1) - DEFS+=-DZT_ENABLE_NETWORK_CONTROLLER + DEFS+=-DZT_ENABLE_NETWORK_CONTROLLER LIBS+=-L/usr/local/lib -lsqlite3 - OBJS+=controller/SqliteNetworkController.o + OBJS+=controller/SqliteNetworkController.o endif # Debug mode -- dump trace output, build binary with -g ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE + DEFS+=-DZT_TRACE CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) STRIP=echo # The following line enables optimization for the crypto code, since diff --git a/osdep/UPNPClient.cpp b/osdep/UPNPClient.cpp new file mode 100644 index 00000000..20aa9d39 --- /dev/null +++ b/osdep/UPNPClient.cpp @@ -0,0 +1,192 @@ +/* + * 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/ + */ + +#ifdef ZT_USE_MINIUPNPC + +// Uncomment to dump debug messages +//#define ZT_UPNP_TRACE 1 + +// Uncomment to build a main() for ad-hoc testing +//#define ZT_UPNP_TEST 1 + +#include +#include +#include + +#include "../node/Utils.hpp" +#include "UPNPClient.hpp" + +#include +#include + +namespace ZeroTier { + +class UPNPClientImpl +{ +public: + UPNPClientImpl(int localUdpPortToMap) : + run(true), + localPort(localUdpPortToMap) + { + } + + void threadMain() + throw() + { + char lanaddr[4096]; + char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P + char inport[16]; + char outport[16]; + struct UPNPUrls urls; + struct IGDdatas data; + +#ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: started for UDP port %d"ZT_EOL_S,localPort); +#endif + + unsigned int tryPortStart = 0; + Utils::getSecureRandom(&tryPortStart,sizeof(tryPortStart)); + tryPortStart = (tryPortStart % (65535 - 1025)) + 1025; + + while (run) { + { + int upnpError = 0; + UPNPDev *devlist = upnpDiscover(2000,(const char *)0,(const char *)0,0,0,&upnpError); + if (devlist) { +#ifdef ZT_UPNP_TRACE + { + UPNPDev *dev = devlist; + while (dev) { + fprintf(stderr,"UPNPClient: found device at URL '%s': %s"ZT_EOL_S,dev->descURL,dev->st); + dev = dev->pNext; + } + } +#endif + + memset(lanaddr,0,sizeof(lanaddr)); + memset(externalip,0,sizeof(externalip)); + memset(&urls,0,sizeof(urls)); + memset(&data,0,sizeof(data)); + Utils::snprintf(inport,sizeof(inport),"%d",localPort); + + if ((UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) { +#ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: my LAN IP address: %s"ZT_EOL_S,lanaddr); +#endif + if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) { +#ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: my external IP address: %s"ZT_EOL_S,externalip); +#endif + + for(int tries=0;tries<64;++tries) { + int tryPort = (int)tryPortStart + tries; + if (tryPort >= 65535) + tryPort = (tryPort - 65535) + 1025; + Utils::snprintf(outport,sizeof(outport),"%u",tryPort); + + int mapResult = 0; + if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,"ZeroTier","UDP",(const char *)0,ZT_UPNP_LEASE_DURATION)) == UPNPCOMMAND_SUCCESS) { + #ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: reserved external port: %s"ZT_EOL_S,outport); + #endif + { + Mutex::Lock sl(surface_l); + surface.clear(); + InetAddress tmp(externalip); + tmp.setPort(tryPort); + surface.push_back(tmp); + } + break; + } else { + #ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: UPNP_AddAnyPortMapping(%s) failed: %d"ZT_EOL_S,outport,mapResult); + #endif + Thread::sleep(1000); + } + } + } else { +#ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: UPNP_GetExternalIPAddress failed"ZT_EOL_S); +#endif + } + } else { +#ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: UPNP_GetValidIGD failed"ZT_EOL_S); +#endif + } + + freeUPNPDevlist(devlist); + } else { +#ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: upnpDiscover error code: %d"ZT_EOL_S,upnpError); +#endif + } + } + +#ifdef ZT_UPNP_TRACE + fprintf(stderr,"UPNPClient: rescanning in %d ms"ZT_EOL_S,ZT_UPNP_CLIENT_REFRESH_DELAY); +#endif + Thread::sleep(ZT_UPNP_CLIENT_REFRESH_DELAY); + } + delete this; + } + + volatile bool run; + int localPort; + Mutex surface_l; + std::vector surface; +}; + +UPNPClient::UPNPClient(int localUdpPortToMap) +{ + _impl = new UPNPClientImpl(localUdpPortToMap); + Thread::start(_impl); +} + +UPNPClient::~UPNPClient() +{ + _impl->run = false; +} + +std::vector UPNPClient::get() const +{ + Mutex::Lock _l(_impl->surface_l); + return _impl->surface; +} + +} // namespace ZeroTier + +#ifdef ZT_UPNP_TEST +int main(int argc,char **argv) +{ + ZeroTier::UPNPClient *client = new ZeroTier::UPNPClient(12345); + ZeroTier::Thread::sleep(0xffffffff); // wait forever + return 0; +} +#endif + +#endif // ZT_USE_MINIUPNPC diff --git a/osdep/UPNPClient.hpp b/osdep/UPNPClient.hpp new file mode 100644 index 00000000..28b9979d --- /dev/null +++ b/osdep/UPNPClient.hpp @@ -0,0 +1,84 @@ +/* + * 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_UPNPCLIENT_HPP +#define ZT_UPNPCLIENT_HPP + +#ifdef ZT_USE_MINIUPNPC + +#include + +#include "../node/Constants.hpp" +#include "../node/InetAddress.hpp" +#include "../node/Mutex.hpp" +#include "Thread.hpp" + +/** + * How frequently should we refresh our UPNP/NAT-PnP/whatever state? + */ +#define ZT_UPNP_CLIENT_REFRESH_DELAY 600000 + +/** + * UPNP lease duration in seconds (as string) + */ +#define ZT_UPNP_LEASE_DURATION "3600" + +namespace ZeroTier { + +class UPNPClientImpl; + +/** + * UPnP/NAT-PnP daemon thread + */ +class UPNPClient +{ + friend class UPNPClientImpl; + +public: + /** + * Create and start UPNP client service + * + * @param localUdpPortToMap Port we want visible to the outside world + */ + UPNPClient(int localUdpPortToMap); + + ~UPNPClient(); + + /** + * @return All current external mappings for our port + */ + std::vector get() const; + +private: + UPNPClientImpl *_impl; +}; + +} // namespace ZeroTier + +#endif // ZT_USE_MINIUPNPC + +#endif diff --git a/service/OneService.cpp b/service/OneService.cpp index b83cd83f..05fdfb90 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -54,6 +54,7 @@ #include "../osdep/OSUtils.hpp" #include "../osdep/Http.hpp" #include "../osdep/BackgroundResolver.hpp" +#include "../osdep/UPNPClient.hpp" #include "OneService.hpp" #include "ControlPlane.hpp" @@ -415,6 +416,9 @@ public: _tcpFallbackTunnel((TcpConnection *)0), _termReason(ONE_STILL_RUNNING), _port(port), +#ifdef ZT_USE_MINIUPNPC + _upnpClient((int)port), +#endif _run(true) { struct sockaddr_in in4; @@ -511,7 +515,7 @@ public: _lastRestart = clockShouldBe; uint64_t lastTapMulticastGroupCheck = 0; uint64_t lastTcpFallbackResolve = 0; - uint64_t lastLocalInterfaceAddressCheck = 0; + uint64_t lastLocalInterfaceAddressCheck = (OSUtils::now() - ZT1_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give UPnP time to configure and other things time to settle #ifdef ZT_AUTO_UPDATE uint64_t lastSoftwareUpdateCheck = 0; #endif // ZT_AUTO_UPDATE @@ -576,9 +580,18 @@ public: ztDevices.push_back(t->second->deviceName()); } + _node->clearLocalInterfaceAddresses(); + +#ifdef ZT_USE_MINIUPNPC + std::vector upnpAddresses(_upnpClient.get()); + for(std::vector::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) { + printf("Adding UPNP address: %s\n",ext->toString().c_str()); + _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext)),0,ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); + } +#endif + struct ifaddrs *ifatbl = (struct ifaddrs *)0; if ((getifaddrs(&ifatbl) == 0)&&(ifatbl)) { - _node->clearLocalInterfaceAddresses(); struct ifaddrs *ifa = ifatbl; while (ifa) { if ((ifa->ifa_name)&&(ifa->ifa_addr)) { @@ -1242,6 +1255,10 @@ private: unsigned int _port; +#ifdef ZT_USE_MINIUPNPC + UPNPClient _upnpClient; +#endif + bool _run; Mutex _run_m; }; -- cgit v1.2.3 From 569c5e77fdd247f59d48d1732dbea6a69bc7d6b3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 14:48:26 -0700 Subject: Add binary build of libminiupnpc for Mac x64. --- ext/bin/miniupnpc/Changelog.txt | 633 +++++++++++++++++++++ ext/bin/miniupnpc/LICENSE | 27 + ext/bin/miniupnpc/README.md | 4 + ext/bin/miniupnpc/VERSION | 1 + ext/bin/miniupnpc/include/miniupnpc/codelength.h | 54 ++ .../miniupnpc/include/miniupnpc/connecthostport.h | 18 + .../miniupnpc/include/miniupnpc/igd_desc_parse.h | 49 ++ ext/bin/miniupnpc/include/miniupnpc/minisoap.h | 15 + ext/bin/miniupnpc/include/miniupnpc/minissdpc.h | 15 + ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h | 154 +++++ .../include/miniupnpc/miniupnpc_declspec.h | 21 + .../miniupnpc/include/miniupnpc/miniupnpcstrings.h | 23 + .../miniupnpc/include/miniupnpc/miniupnpctypes.h | 19 + ext/bin/miniupnpc/include/miniupnpc/miniwget.h | 30 + ext/bin/miniupnpc/include/miniupnpc/minixml.h | 37 ++ .../miniupnpc/include/miniupnpc/portlistingparse.h | 65 +++ ext/bin/miniupnpc/include/miniupnpc/receivedata.h | 19 + ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h | 348 +++++++++++ ext/bin/miniupnpc/include/miniupnpc/upnperrors.h | 26 + .../miniupnpc/include/miniupnpc/upnpreplyparse.h | 63 ++ ext/bin/miniupnpc/mac-x64/libminiupnpc.a | Bin 0 -> 95616 bytes make-mac.mk | 8 +- service/OneService.cpp | 4 +- 23 files changed, 1628 insertions(+), 5 deletions(-) create mode 100644 ext/bin/miniupnpc/Changelog.txt create mode 100644 ext/bin/miniupnpc/LICENSE create mode 100644 ext/bin/miniupnpc/README.md create mode 100644 ext/bin/miniupnpc/VERSION create mode 100644 ext/bin/miniupnpc/include/miniupnpc/codelength.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/connecthostport.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/minisoap.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/minissdpc.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/miniwget.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/minixml.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/receivedata.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/upnperrors.h create mode 100644 ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h create mode 100644 ext/bin/miniupnpc/mac-x64/libminiupnpc.a diff --git a/ext/bin/miniupnpc/Changelog.txt b/ext/bin/miniupnpc/Changelog.txt new file mode 100644 index 00000000..bb2abb7e --- /dev/null +++ b/ext/bin/miniupnpc/Changelog.txt @@ -0,0 +1,633 @@ +$Id: Changelog.txt,v 1.208 2015/07/15 12:18:59 nanard Exp $ +miniUPnP client Changelog. + +2015/07/15: + Check malloc/calloc + +2015/06/16: + update getDevicesFromMiniSSDPD() to process longer minissdpd + responses + +2015/05/22: + add searchalltypes param to upnpDiscoverDevices() + increments API_VERSION to 13 + +2015/04/30: + upnpc: output version on the terminal + +2015/04/27: + _BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE + fix CMakeLists.txt COMPILE_DEFINITIONS + fix getDevicesFromMiniSSDPD() not setting scope_id + improve -r command of upnpc command line tool + +2014/11/17: + search all : + upnpDiscoverDevices() / upnpDiscoverAll() functions + listdevices executable + increment API_VERSION to 12 + validate igd_desc_parse + +2014/11/13: + increment API_VERSION to 11 + +2014/11/05: + simplified function GetUPNPUrls() + +2014/09/11: + use remoteHost arg of DeletePortMapping + +2014/09/06: + Fix python3 build + +2014/07/01: + Fix parsing of IGD2 root descriptions + +2014/06/10: + rename LIBSPEC to MINIUPNP_LIBSPEC + +2014/05/15: + Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange + +2014/02/05: + handle EINPROGRESS after connect() + +2014/02/03: + minixml now handle XML comments + +VERSION 1.9 : released 2014/01/31 + +2014/01/31: + added argument remoteHost to UPNP_GetSpecificPortMappingEntry() + increment API_VERSION to 10 + +2013/12/09: + --help and -h arguments in upnpc.c + +2013/10/07: + fixed potential buffer overrun in miniwget.c + Modified UPNP_GetValidIGD() to check for ExternalIpAddress + +2013/08/01: + define MAXHOSTNAMELEN if not already done + +2013/06/06: + update upnpreplyparse to allow larger values (128 chars instead of 64) + +2013/05/14: + Update upnpreplyparse to take into account "empty" elements + validate upnpreplyparse.c code with "make check" + +2013/05/03: + Fix Solaris build thanks to Maciej Małecki + +2013/04/27: + Fix testminiwget.sh for BSD + +2013/03/23: + Fixed Makefile for *BSD + +2013/03/11: + Update Makefile to use JNAerator version 0.11 + +2013/02/11: + Fix testminiwget.sh for use with dash + Use $(DESTDIR) in Makefile + +VERSION 1.8 : released 2013/02/06 + +2012/10/16: + fix testminiwget with no IPv6 support + +2012/09/27: + Rename all include guards to not clash with C99 + (7.1.3 Reserved identifiers). + +2012/08/30: + Added -e option to upnpc program (set description for port mappings) + +2012/08/29: + Python 3 support (thanks to Christopher Foo) + +2012/08/11: + Fix a memory link in UPNP_GetValidIGD() + Try to handle scope id in link local IPv6 URL under MS Windows + +2012/07/20: + Disable HAS_IP_MREQN on DragonFly BSD + +2012/06/28: + GetUPNPUrls() now inserts scope into link-local IPv6 addresses + +2012/06/23: + More error return checks in upnpc.c + #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id + parseURL() now parses IPv6 addresses scope + new parameter for miniwget() : IPv6 address scope + increment API_VERSION to 9 + +2012/06/20: + fixed CMakeLists.txt + +2012/05/29 + Improvements in testminiwget.sh + +VERSION 1.7 : released 2012/05/24 + +2012/05/01: + Cleanup settings of CFLAGS in Makefile + Fix signed/unsigned integer comparaisons + +2012/04/20: + Allow to specify protocol with TCP or UDP for -A option + +2012/04/09: + Only try to fetch XML description once in UPNP_GetValidIGD() + Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. + +2012/04/05: + minor improvements to minihttptestserver.c + +2012/03/15: + upnperrors.c returns valid error string for unrecognized error codes + +2012/03/08: + make minihttptestserver listen on loopback interface instead of 0.0.0.0 + +2012/01/25: + Maven installation thanks to Alexey Kuznetsov + +2012/01/21: + Replace WIN32 macro by _WIN32 + +2012/01/19: + Fixes in java wrappers thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc + Make and install .deb packages (python) thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc + +2012/01/07: + The multicast interface can now be specified by name with IPv4. + +2012/01/02: + Install man page + +2011/11/25: + added header to Port Mappings list in upnpc.c + +2011/10/09: + Makefile : make clean now removes jnaerator generated files. + MINIUPNPC_VERSION in miniupnpc.h (updated by make) + +2011/09/12: + added rootdescURL to UPNPUrls structure. + +VERSION 1.6 : released 2011/07/25 + +2011/07/25: + Update doc for version 1.6 release + +2011/06/18: + Fix for windows in miniwget.c + +2011/06/04: + display remote host in port mapping listing + +2011/06/03: + Fix in make install : there were missing headers + +2011/05/26: + Fix the socket leak in miniwget thanks to Richard Marsh. + Permit to add leaseduration in -a command. Display lease duration. + +2011/05/15: + Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 + +2011/05/09: + add a test in testminiwget.sh. + more error checking in miniwget.c + +2011/05/06: + Adding some tool to test and validate miniwget.c + simplified and debugged miniwget.c + +2011/04/11: + moving ReceiveData() to a receivedata.c file. + parsing presentation url + adding IGD v2 WANIPv6FirewallControl commands + +2011/04/10: + update of miniupnpcmodule.c + comments in miniwget.c, update in testminiwget + Adding errors codes from IGD v2 + new functions in upnpc.c for IGD v2 + +2011/04/09: + Support for litteral ip v6 address in miniwget + +2011/04/08: + Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 + Updating APIVERSION + Supporting IPV6 in upnpDiscover() + Adding a -6 option to upnpc command line tool + +2011/03/18: + miniwget/parseURL() : return an error when url param is null. + fixing GetListOfPortMappings() + +2011/03/14: + upnpDiscover() now reporting an error code. + improvements in comments. + +2011/03/11: + adding miniupnpcstrings.h.cmake and CMakeLists.txt files. + +2011/02/15: + Implementation of GetListOfPortMappings() + +2011/02/07: + updates to minixml to support character data starting with spaces + minixml now support CDATA + upnpreplyparse treats specificaly + change in simpleUPnPcommand to return the buffer (simplification) + +2011/02/06: + Added leaseDuration argument to AddPortMapping() + Starting to implement GetListOfPortMappings() + +2011/01/11: + updating wingenminiupnpcstrings.c + +2011/01/04: + improving updateminiupnpcstrings.sh + +VERSION 1.5 : released 2011/01/01 + +2010/12/21: + use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo + +2010/12/11: + Improvements on getHTTPResponse() code. + +2010/12/09: + new code for miniwget that handle Chunked transfer encoding + using getHTTPResponse() in SOAP call code + Adding MANIFEST.in for 'python setup.py bdist_rpm' + +2010/11/25: + changes to minissdpc.c to compile under Win32. + see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 + +2010/09/17: + Various improvement to Makefile from Michał Górny + +2010/08/05: + Adding the script "external-ip.sh" from Reuben Hawkins + +2010/06/09: + update to python module to match modification made on 2010/04/05 + update to Java test code to match modification made on 2010/04/05 + all UPNP_* function now return an error if the SOAP request failed + at HTTP level. + +2010/04/17: + Using GetBestRoute() under win32 in order to find the + right interface to use. + +2010/04/12: + Retrying with HTTP/1.1 if HTTP/1.0 failed. see + http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 + +2010/04/07: + avoid returning duplicates in upnpDiscover() + +2010/04/05: + Create a connecthostport.h/.c with connecthostport() function + and use it in miniwget and miniupnpc. + Use getnameinfo() instead of inet_ntop or inet_ntoa + Work to make miniupnpc IPV6 compatible... + Add java test code. + Big changes in order to support device having both WANIPConnection + and WANPPPConnection. + +2010/04/04: + Use getaddrinfo() instead of gethostbyname() in miniwget. + +2010/01/06: + #define _DARWIN_C_SOURCE for Mac OS X + +2009/12/19: + Improve MinGW32 build + +2009/12/11: + adding a MSVC9 project to build the static library and executable + +2009/12/10: + Fixing some compilation stuff for Windows/MinGW + +2009/12/07: + adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS + some fixes for Windows when using virtual ethernet adapters (it is the + case with VMWare installed). + +2009/12/04: + some fixes for AmigaOS compilation + Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked + transfer encoding) + +2009/12/03: + updating printIDG and testigddescparse.c for debug. + modifications to compile under AmigaOS + adding a testminiwget program + Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked + transfer encoding + +2009/11/26: + fixing updateminiupnpcstrings.sh to take into account + which command that does not return an error code. + +VERSION 1.4 : released 2009/10/30 + +2009/10/16: + using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. + +2009/10/10: + Some fixes for compilation under Solaris + compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 + +2009/09/21: + fixing the code to ignore EINTR during connect() calls. + +2009/08/07: + Set socket timeout for connect() + Some cleanup in miniwget.c + +2009/08/04: + remove multiple redirections with -d in upnpc.c + Print textual error code in upnpc.c + Ignore EINTR during the connect() and poll() calls. + +2009/07/29: + fix in updateminiupnpcstrings.sh if OS name contains "/" + Sending a correct value for MX: field in SSDP request + +2009/07/20: + Change the Makefile to compile under Mac OS X + Fixed a stackoverflow in getDevicesFromMiniSSDPD() + +2009/07/09: + Compile under Haiku + generate miniupnpcstrings.h.in from miniupnpcstrings.h + +2009/06/04: + patching to compile under CygWin and cross compile for minGW + +VERSION 1.3 : + +2009/04/17: + updating python module + Use strtoull() when using C99 + +2009/02/28: + Fixed miniwget.c for compiling under sun + +2008/12/18: + cleanup in Makefile (thanks to Paul de Weerd) + minissdpc.c : win32 compatibility + miniupnpc.c : changed xmlns prefix from 'm' to 'u' + Removed NDEBUG (using DEBUG) + +2008/10/14: + Added the ExternalHost argument to DeletePortMapping() + +2008/10/11: + Added the ExternalHost argument to AddPortMapping() + Put a correct User-Agent: header in HTTP requests. + +VERSION 1.2 : + +2008/10/07: + Update docs + +2008/09/25: + Integrated sameport patch from Dario Meloni : Added a "sameport" + argument to upnpDiscover(). + +2008/07/18: + small modif to make Clang happy :) + +2008/07/17: + #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... + +2008/07/14: + include declspec.h in installation (to /usr/include/miniupnpc) + +VERSION 1.1 : + +2008/07/04: + standard options for install/ln instead of gnu-specific stuff. + +2008/07/03: + now builds a .dll and .lib with win32. (mingw32) + +2008/04/28: + make install now install the binary of the upnpc tool + +2008/04/27: + added testupnpigd.py + added error strings for miniupnpc "internal" errors + improved python module error/exception reporting. + +2008/04/23: + Completely rewrite igd_desc_parse.c in order to be compatible with + Linksys WAG200G + Added testigddescparse + updated python module + +VERSION 1.0 : + +2008/02/21: + put some #ifdef DEBUG around DisplayNameValueList() + +2008/02/18: + Improved error reporting in upnpcommands.c + UPNP_GetStatusInfo() returns LastConnectionError + +2008/02/16: + better error handling in minisoap.c + improving display of "valid IGD found" in upnpc.c + +2008/02/03: + Fixing UPNP_GetValidIGD() + improved make install :) + +2007/12/22: + Adding upnperrors.c/h to provide a strupnperror() function + used to translate UPnP error codes to string. + +2007/12/19: + Fixing getDevicesFromMiniSSDPD() + improved error reporting of UPnP functions + +2007/12/18: + It is now possible to specify a different location for MiniSSDPd socket. + working with MiniSSDPd is now more efficient. + python module improved. + +2007/12/16: + improving error reporting + +2007/12/13: + Try to improve compatibility by using HTTP/1.0 instead of 1.1 and + XML a bit different for SOAP. + +2007/11/25: + fixed select() call for linux + +2007/11/15: + Added -fPIC to CFLAG for better shared library code. + +2007/11/02: + Fixed a potential socket leak in miniwget2() + +2007/10/16: + added a parameter to upnpDiscover() in order to allow the use of another + interface than the default multicast interface. + +2007/10/12: + Fixed the creation of symbolic link in Makefile + +2007/10/08: + Added man page + +2007/10/02: + fixed memory bug in GetUPNPUrls() + +2007/10/01: + fixes in the Makefile + Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. + Added SONAME in the shared library to please debian :) + fixed MS Windows compilation (minissdpd is not available under MS Windows). + +2007/09/25: + small change to Makefile to be able to install in a different location + (default is /usr) + +2007/09/24: + now compiling both shared and static library + +2007/09/19: + Cosmetic changes on upnpc.c + +2007/09/02: + adapting to new miniSSDPd (release version ?) + +2007/08/31: + Usage of miniSSDPd to skip discovery process. + +2007/08/27: + fixed python module to allow compilation with Python older than Python 2.4 + +2007/06/12: + Added a python module. + +2007/05/19: + Fixed compilation under MinGW + +2007/05/15: + fixed a memory leak in AddPortMapping() + Added testupnpreplyparse executable to check the parsing of + upnp soap messages + minixml now ignore namespace prefixes. + +2007/04/26: + upnpc now displays external ip address with -s or -l + +2007/04/11: + changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" + +2007/03/19: + cleanup in miniwget.c + +2007/03/01: + Small typo fix... + +2007/01/30: + Now parsing the HTTP header from SOAP responses in order to + get content-length value. + +2007/01/29: + Fixed the Soap Query to speedup the HTTP request. + added some Win32 DLL stuff... + +2007/01/27: + Fixed some WIN32 compatibility issues + +2006/12/14: + Added UPNPIGD_IsConnected() function in miniupnp.c/.h + Added UPNP_GetValidIGD() in miniupnp.c/.h + cleaned upnpc.c main(). now using UPNP_GetValidIGD() + +2006/12/07: + Version 1.0-RC1 released + +2006/12/03: + Minor changes to compile under SunOS/Solaris + +2006/11/30: + made a minixml parser validator program + updated minixml to handle attributes correctly + +2006/11/22: + Added a -r option to the upnpc sample thanks to Alexander Hubmann. + +2006/11/19: + Cleanup code to make it more ANSI C compliant + +2006/11/10: + detect and display local lan address. + +2006/11/04: + Packets and Bytes Sent/Received are now unsigned int. + +2006/11/01: + Bug fix thanks to Giuseppe D'Angelo + +2006/10/31: + C++ compatibility for .h files. + Added a way to get ip Address on the LAN used to reach the IGD. + +2006/10/25: + Added M-SEARCH to the services in the discovery process. + +2006/10/22: + updated the Makefile to use makedepend, added a "make install" + update Makefile + +2006/10/20: + fixing the description url parsing thanks to patch sent by + Wayne Dawe. + Fixed/translated some comments. + Implemented a better discover process, first looking + for IGD then for root devices (as some devices only reply to + M-SEARCH for root devices). + +2006/09/02: + added freeUPNPDevlist() function. + +2006/08/04: + More command line arguments checking + +2006/08/01: + Added the .bat file to compile under Win32 with minGW32 + +2006/07/31: + Fixed the rootdesc parser (igd_desc_parse.c) + +2006/07/20: + parseMSEARCHReply() is now returning the ST: line as well + starting changes to detect several UPnP devices on the network + +2006/07/19: + using GetCommonLinkProperties to get down/upload bitrate + diff --git a/ext/bin/miniupnpc/LICENSE b/ext/bin/miniupnpc/LICENSE new file mode 100644 index 00000000..cb5a0604 --- /dev/null +++ b/ext/bin/miniupnpc/LICENSE @@ -0,0 +1,27 @@ +MiniUPnPc +Copyright (c) 2005-2015, Thomas BERNARD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/ext/bin/miniupnpc/README.md b/ext/bin/miniupnpc/README.md new file mode 100644 index 00000000..c3d538ba --- /dev/null +++ b/ext/bin/miniupnpc/README.md @@ -0,0 +1,4 @@ +libminiupnpc binaries +====== + +This is a binary build of [libminiupnpc](http://miniupnp.free.fr) for certain architectures to faciliate easy building. Where possible the build flags were set for improved security by enabling options like stack protector (a.k.a. stack canary), ASLR support, etc. diff --git a/ext/bin/miniupnpc/VERSION b/ext/bin/miniupnpc/VERSION new file mode 100644 index 00000000..2e0e38c6 --- /dev/null +++ b/ext/bin/miniupnpc/VERSION @@ -0,0 +1 @@ +1.9 diff --git a/ext/bin/miniupnpc/include/miniupnpc/codelength.h b/ext/bin/miniupnpc/include/miniupnpc/codelength.h new file mode 100644 index 00000000..f5f8e30f --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/codelength.h @@ -0,0 +1,54 @@ +/* $Id: codelength.h,v 1.5 2015/07/09 12:40:18 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2015 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef CODELENGTH_H_INCLUDED +#define CODELENGTH_H_INCLUDED + +/* Encode length by using 7bit per Byte : + * Most significant bit of each byte specifies that the + * following byte is part of the code */ + +/* n : unsigned + * p : unsigned char * + */ +#define DECODELENGTH(n, p) n = 0; \ + do { n = (n << 7) | (*p & 0x7f); } \ + while((*(p++)&0x80) && (n<(1<<25))); + +/* n : unsigned + * READ : function/macro to read one byte (unsigned char) + */ +#define DECODELENGTH_READ(n, READ) \ + n = 0; \ + do { \ + unsigned char c; \ + READ(c); \ + n = (n << 7) | (c & 0x07f); \ + if(!(c&0x80)) break; \ + } while(n<(1<<25)); + +/* n : unsigned + * p : unsigned char * + * p_limit : unsigned char * + */ +#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ + n = 0; \ + do { \ + if((p) >= (p_limit)) break; \ + n = (n << 7) | (*(p) & 0x7f); \ + } while((*((p)++)&0x80) && (n<(1<<25))); + + +/* n : unsigned + * p : unsigned char * + */ +#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ + if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ + if(n>=16384) *(p++) = (n >> 14) | 0x80; \ + if(n>=128) *(p++) = (n >> 7) | 0x80; \ + *(p++) = n & 0x7f; + +#endif /* CODELENGTH_H_INCLUDED */ diff --git a/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h b/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h new file mode 100644 index 00000000..56941d6f --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/connecthostport.h @@ -0,0 +1,18 @@ +/* $Id: connecthostport.h,v 1.3 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2010-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef CONNECTHOSTPORT_H_INCLUDED +#define CONNECTHOSTPORT_H_INCLUDED + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port, + unsigned int scope_id); + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h b/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h new file mode 100644 index 00000000..0de546b6 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/igd_desc_parse.h @@ -0,0 +1,49 @@ +/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef IGD_DESC_PARSE_H_INCLUDED +#define IGD_DESC_PARSE_H_INCLUDED + +/* Structure to store the result of the parsing of UPnP + * descriptions of Internet Gateway Devices */ +#define MINIUPNPC_URL_MAXSIZE (128) +struct IGDdatas_service { + char controlurl[MINIUPNPC_URL_MAXSIZE]; + char eventsuburl[MINIUPNPC_URL_MAXSIZE]; + char scpdurl[MINIUPNPC_URL_MAXSIZE]; + char servicetype[MINIUPNPC_URL_MAXSIZE]; + /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ +}; + +struct IGDdatas { + char cureltname[MINIUPNPC_URL_MAXSIZE]; + char urlbase[MINIUPNPC_URL_MAXSIZE]; + char presentationurl[MINIUPNPC_URL_MAXSIZE]; + int level; + /*int state;*/ + /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ + struct IGDdatas_service CIF; + /* "urn:schemas-upnp-org:service:WANIPConnection:1" + * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ + struct IGDdatas_service first; + /* if both WANIPConnection and WANPPPConnection are present */ + struct IGDdatas_service second; + /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ + struct IGDdatas_service IPv6FC; + /* tmp */ + struct IGDdatas_service tmp; +}; + +void IGDstartelt(void *, const char *, int); +void IGDendelt(void *, const char *, int); +void IGDdata(void *, const char *, int); +#ifdef DEBUG +void printIGD(struct IGDdatas *); +#endif /* DEBUG */ + +#endif /* IGD_DESC_PARSE_H_INCLUDED */ diff --git a/ext/bin/miniupnpc/include/miniupnpc/minisoap.h b/ext/bin/miniupnpc/include/miniupnpc/minisoap.h new file mode 100644 index 00000000..14c859d1 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/minisoap.h @@ -0,0 +1,15 @@ +/* $Id: minisoap.h,v 1.5 2012/09/27 15:42:10 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ +#ifndef MINISOAP_H_INCLUDED +#define MINISOAP_H_INCLUDED + +/*int httpWrite(int, const char *, int, const char *);*/ +int soapPostSubmit(int, const char *, const char *, unsigned short, + const char *, const char *, const char *); + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h b/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h new file mode 100644 index 00000000..915b0026 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/minissdpc.h @@ -0,0 +1,15 @@ +/* $Id: minissdpc.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2007 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINISSDPC_H_INCLUDED +#define MINISSDPC_H_INCLUDED + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h new file mode 100644 index 00000000..0eeabc23 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h @@ -0,0 +1,154 @@ +/* $Id: miniupnpc.h,v 1.42 2015/07/21 13:16:55 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPC_H_INCLUDED +#define MINIUPNPC_H_INCLUDED + +#include "miniupnpc_declspec.h" +#include "igd_desc_parse.h" + +/* error codes : */ +#define UPNPDISCOVER_SUCCESS (0) +#define UPNPDISCOVER_UNKNOWN_ERROR (-1) +#define UPNPDISCOVER_SOCKET_ERROR (-101) +#define UPNPDISCOVER_MEMORY_ERROR (-102) + +/* versions : */ +#define MINIUPNPC_VERSION "1.9.20150721" +#define MINIUPNPC_API_VERSION 13 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structures definitions : */ +struct UPNParg { const char * elt; const char * val; }; + +char * +simpleUPnPcommand(int, const char *, const char *, + const char *, struct UPNParg *, + int *); + +struct UPNPDev { + struct UPNPDev * pNext; + char * descURL; + char * st; + unsigned int scope_id; + char buffer[2]; +}; + +/* upnpDiscover() + * discover UPnP devices on the network. + * The discovered devices are returned as a chained list. + * It is up to the caller to free the list with freeUPNPDevlist(). + * delay (in millisecond) is the maximum time for waiting any device + * response. + * If available, device list will be obtained from MiniSSDPd. + * Default path for minissdpd socket will be used if minissdpdsock argument + * is NULL. + * If multicastif is not NULL, it will be used instead of the default + * multicast interface for sending SSDP discover packets. + * If sameport is not null, SSDP packets will be sent from the source port + * 1900 (same as destination port) otherwise system assign a source port. + * "searchalltypes" parameter is useful when searching several types, + * if 0, the discovery will stop with the first type returning results. */ +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverAll(int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevice(const char * device, int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevices(const char * const deviceTypes[], + int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error, + int searchalltypes); + +/* freeUPNPDevlist() + * free list returned by upnpDiscover() */ +MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); + +/* parserootdesc() : + * parse root XML description of a UPnP device and fill the IGDdatas + * structure. */ +MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); + +/* structure used to get fast access to urls + * controlURL: controlURL of the WANIPConnection + * ipcondescURL: url of the description of the WANIPConnection + * controlURL_CIF: controlURL of the WANCommonInterfaceConfig + * controlURL_6FC: controlURL of the WANIPv6FirewallControl + */ +struct UPNPUrls { + char * controlURL; + char * ipcondescURL; + char * controlURL_CIF; + char * controlURL_6FC; + char * rootdescURL; +}; + +/* UPNP_GetValidIGD() : + * return values : + * 0 = NO IGD found + * 1 = A valid connected IGD has been found + * 2 = A valid IGD has been found but it reported as + * not connected + * 3 = an UPnP device has been found but was not recognized as an IGD + * + * In any non zero return case, the urls and data structures + * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to + * free allocated memory. + */ +MINIUPNP_LIBSPEC int +UPNP_GetValidIGD(struct UPNPDev * devlist, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * When succeding, urls, data, and lanaddr arguments are set. + * return value : + * 0 - Not ok + * 1 - OK */ +MINIUPNP_LIBSPEC int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +MINIUPNP_LIBSPEC void +GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, + const char *, unsigned int); + +MINIUPNP_LIBSPEC void +FreeUPNPUrls(struct UPNPUrls *); + +/* return 0 or 1 */ +MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h new file mode 100644 index 00000000..40adb922 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpc_declspec.h @@ -0,0 +1,21 @@ +#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED +#define MINIUPNPC_DECLSPEC_H_INCLUDED + +#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) + /* for windows dll */ + #ifdef MINIUPNP_EXPORTS + #define MINIUPNP_LIBSPEC __declspec(dllexport) + #else + #define MINIUPNP_LIBSPEC __declspec(dllimport) + #endif +#else + #if defined(__GNUC__) && __GNUC__ >= 4 + /* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ + #define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) + #else + #define MINIUPNP_LIBSPEC + #endif +#endif + +#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ + diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h new file mode 100644 index 00000000..80a1d757 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpcstrings.h @@ -0,0 +1,23 @@ +/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPCSTRINGS_H_INCLUDED +#define MINIUPNPCSTRINGS_H_INCLUDED + +#define OS_STRING "Darwin/14.4.0" +#define MINIUPNPC_VERSION_STRING "1.9" + +#if 0 +/* according to "UPnP Device Architecture 1.0" */ +#define UPNP_VERSION_STRING "UPnP/1.0" +#else +/* according to "UPnP Device Architecture 1.1" */ +#define UPNP_VERSION_STRING "UPnP/1.1" +#endif + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h b/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h new file mode 100644 index 00000000..591c32fb --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/miniupnpctypes.h @@ -0,0 +1,19 @@ +/* $Id: miniupnpctypes.h,v 1.2 2012/09/27 15:42:10 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef MINIUPNPCTYPES_H_INCLUDED +#define MINIUPNPCTYPES_H_INCLUDED + +#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) +#define UNSIGNED_INTEGER unsigned long long +#define STRTOUI strtoull +#else +#define UNSIGNED_INTEGER unsigned int +#define STRTOUI strtoul +#endif + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/miniwget.h b/ext/bin/miniupnpc/include/miniupnpc/miniwget.h new file mode 100644 index 00000000..d6db71a8 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/miniwget.h @@ -0,0 +1,30 @@ +/* $Id: miniwget.h,v 1.10 2015/07/21 13:16:55 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef MINIWGET_H_INCLUDED +#define MINIWGET_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size); + +MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int); + +MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int); + +int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/minixml.h b/ext/bin/miniupnpc/include/miniupnpc/minixml.h new file mode 100644 index 00000000..9f43aa48 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/minixml.h @@ -0,0 +1,37 @@ +/* $Id: minixml.h,v 1.7 2012/09/27 15:42:10 nanard Exp $ */ +/* minimal xml parser + * + * Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef MINIXML_H_INCLUDED +#define MINIXML_H_INCLUDED +#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) + +/* if a callback function pointer is set to NULL, + * the function is not called */ +struct xmlparser { + const char *xmlstart; + const char *xmlend; + const char *xml; /* pointer to current character */ + int xmlsize; + void * data; + void (*starteltfunc) (void *, const char *, int); + void (*endeltfunc) (void *, const char *, int); + void (*datafunc) (void *, const char *, int); + void (*attfunc) (void *, const char *, int, const char *, int); +}; + +/* parsexml() + * the xmlparser structure must be initialized before the call + * the following structure members have to be initialized : + * xmlstart, xmlsize, data, *func + * xml is for internal usage, xmlend is computed automatically */ +void parsexml(struct xmlparser *); + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h b/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h new file mode 100644 index 00000000..661ad1fa --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/portlistingparse.h @@ -0,0 +1,65 @@ +/* $Id: portlistingparse.h,v 1.11 2015/07/21 13:16:55 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011-2015 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#ifndef PORTLISTINGPARSE_H_INCLUDED +#define PORTLISTINGPARSE_H_INCLUDED + +#include "miniupnpc_declspec.h" +/* for the definition of UNSIGNED_INTEGER */ +#include "miniupnpctypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* sample of PortMappingEntry : + + 202.233.2.1 + 2345 + TCP + 2345 + 192.168.1.137 + 1 + dooom + 345 + + */ +typedef enum { PortMappingEltNone, + PortMappingEntry, NewRemoteHost, + NewExternalPort, NewProtocol, + NewInternalPort, NewInternalClient, + NewEnabled, NewDescription, + NewLeaseTime } portMappingElt; + +struct PortMapping { + struct PortMapping * l_next; /* list next element */ + UNSIGNED_INTEGER leaseTime; + unsigned short externalPort; + unsigned short internalPort; + char remoteHost[64]; + char internalClient[64]; + char description[64]; + char protocol[4]; + unsigned char enabled; +}; + +struct PortMappingParserData { + struct PortMapping * l_head; /* list head */ + portMappingElt curelt; +}; + +MINIUPNP_LIBSPEC void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata); + +MINIUPNP_LIBSPEC void +FreePortListing(struct PortMappingParserData * pdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/bin/miniupnpc/include/miniupnpc/receivedata.h b/ext/bin/miniupnpc/include/miniupnpc/receivedata.h new file mode 100644 index 00000000..0520a11d --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/receivedata.h @@ -0,0 +1,19 @@ +/* $Id: receivedata.h,v 1.4 2012/09/27 15:42:10 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2011-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef RECEIVEDATA_H_INCLUDED +#define RECEIVEDATA_H_INCLUDED + +/* Reads data from the specified socket. + * Returns the number of bytes read if successful, zero if no bytes were + * read or if we timed out. Returns negative if there was an error. */ +int receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id); + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h b/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h new file mode 100644 index 00000000..22eda5e3 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h @@ -0,0 +1,348 @@ +/* $Id: upnpcommands.h,v 1.31 2015/07/21 13:16:55 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef UPNPCOMMANDS_H_INCLUDED +#define UPNPCOMMANDS_H_INCLUDED + +#include "upnpreplyparse.h" +#include "portlistingparse.h" +#include "miniupnpc_declspec.h" +#include "miniupnpctypes.h" + +/* MiniUPnPc return codes : */ +#define UPNPCOMMAND_SUCCESS (0) +#define UPNPCOMMAND_UNKNOWN_ERROR (-1) +#define UPNPCOMMAND_INVALID_ARGS (-2) +#define UPNPCOMMAND_HTTP_ERROR (-3) +#define UPNPCOMMAND_INVALID_RESPONSE (-4) +#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) + +#ifdef __cplusplus +extern "C" { +#endif + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype); + +/* UPNP_GetStatusInfo() + * status and lastconnerror are 64 byte buffers + * Return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +MINIUPNP_LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror); + +/* UPNP_GetConnectionTypeInfo() + * argument connectionType is a 64 character buffer + * Return Values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +MINIUPNP_LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType); + +/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. + * if the third arg is not null the value is copied to it. + * at least 16 bytes must be available + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * possible UPnP Errors : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. */ +MINIUPNP_LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, + const char * servicetype, + char * extIpAdd); + +/* UPNP_GetLinkLayerMaxBitRates() + * call WANCommonInterfaceConfig:1#GetCommonLinkProperties + * + * return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +MINIUPNP_LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char* controlURL, + const char* servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp); + +/* UPNP_AddPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 718 ConflictInMappingEntry - The port mapping entry specified conflicts + * with a mapping assigned previously to another client + * 724 SamePortValuesRequired - Internal and External port values + * must be the same + * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports + * permanent lease times on port mappings + * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard + * and cannot be a specific IP address or DNS name + * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and + * cannot be a specific port value + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ +MINIUPNP_LIBSPEC int +UPNP_AddPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration); + +/* UPNP_AddAnyPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ +MINIUPNP_LIBSPEC int +UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration, + char * reservedPort); + +/* UPNP_DeletePortMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array */ +MINIUPNP_LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost); + +/* UPNP_DeletePortRangeMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 730 PortMappingNotFound - This error message is returned if no port + * mapping is found in the specified range. + * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ +MINIUPNP_LIBSPEC int +UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, + const char * extPortStart, const char * extPortEnd, + const char * proto, + const char * manage); + +/* UPNP_GetPortMappingNumberOfEntries() + * not supported by all routers */ +MINIUPNP_LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char* controlURL, + const char* servicetype, + unsigned int * num); + +/* UPNP_GetSpecificPortMappingEntry() + * retrieves an existing port mapping + * params : + * in extPort + * in proto + * in remoteHost + * out intClient (16 bytes) + * out intPort (6 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out leaseDuration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * List of possible UPnP errors for _GetSpecificPortMappingEntry : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array. + */ +MINIUPNP_LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * extPort, + const char * proto, + const char * remoteHost, + char * intClient, + char * intPort, + char * desc, + char * enabled, + char * leaseDuration); + +/* UPNP_GetGenericPortMappingEntry() + * params : + * in index + * out extPort (6 bytes) + * out intClient (16 bytes) + * out intPort (6 bytes) + * out protocol (4 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out rHost (64 bytes) + * out duration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * Possible UPNP Error codes : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds + */ +MINIUPNP_LIBSPEC int +UPNP_GetGenericPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * index, + char * extPort, + char * intClient, + char * intPort, + char * protocol, + char * desc, + char * enabled, + char * rHost, + char * duration); + +/* UPNP_GetListOfPortMappings() Available in IGD v2 + * + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + * consistent. + */ +MINIUPNP_LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, + const char * servicetype, + const char * startPort, + const char * endPort, + const char * protocol, + const char * numberOfPorts, + struct PortMappingParserData * data); + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +MINIUPNP_LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed); + +MINIUPNP_LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + int * opTimeout); + +MINIUPNP_LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + const char * leaseTime, + char * uniqueID); + +MINIUPNP_LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime); + +MINIUPNP_LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); + +MINIUPNP_LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking); + +MINIUPNP_LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h b/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h new file mode 100644 index 00000000..3115aee5 --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/upnperrors.h @@ -0,0 +1,26 @@ +/* $Id: upnperrors.h,v 1.6 2015/07/21 13:16:55 nanard Exp $ */ +/* (c) 2007-2015 Thomas Bernard + * All rights reserved. + * MiniUPnP Project. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef UPNPERRORS_H_INCLUDED +#define UPNPERRORS_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* strupnperror() + * Return a string description of the UPnP error code + * or NULL for undefinded errors */ +MINIUPNP_LIBSPEC const char * strupnperror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h b/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h new file mode 100644 index 00000000..6badd15b --- /dev/null +++ b/ext/bin/miniupnpc/include/miniupnpc/upnpreplyparse.h @@ -0,0 +1,63 @@ +/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2013 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef UPNPREPLYPARSE_H_INCLUDED +#define UPNPREPLYPARSE_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +struct NameValue { + struct NameValue * l_next; + char name[64]; + char value[128]; +}; + +struct NameValueParserData { + struct NameValue * l_head; + char curelt[64]; + char * portListing; + int portListingLength; + int topelt; + const char * cdata; + int cdatalen; +}; + +/* ParseNameValue() */ +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data); + +/* ClearNameValueList() */ +void +ClearNameValueList(struct NameValueParserData * pdata); + +/* GetValueFromNameValueList() */ +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name); + +#if 0 +/* GetValueFromNameValueListIgnoreNS() */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name); +#endif + +/* DisplayNameValueList() */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/ext/bin/miniupnpc/mac-x64/libminiupnpc.a b/ext/bin/miniupnpc/mac-x64/libminiupnpc.a new file mode 100644 index 00000000..3c2e528d Binary files /dev/null and b/ext/bin/miniupnpc/mac-x64/libminiupnpc.a differ diff --git a/make-mac.mk b/make-mac.mk index 55b117e6..707d517c 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -5,7 +5,7 @@ ifeq ($(origin CXX),default) CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) endif -INCLUDES=-I/usr/local/include +INCLUDES= DEFS= LIBS= ARCH_FLAGS=-arch x86_64 @@ -13,6 +13,9 @@ ARCH_FLAGS=-arch x86_64 include objects.mk OBJS+=osdep/OSXEthernetTap.o +# Comment out to disable building against shipped libminiupnpc binary for Mac +ZT_USE_MINIUPNPC=1 + # Disable codesign since open source users will not have ZeroTier's certs CODESIGN=echo PRODUCTSIGN=echo @@ -35,7 +38,8 @@ endif ifeq ($(ZT_USE_MINIUPNPC),1) DEFS+=-DZT_USE_MINIUPNPC - LIBS+=/usr/local/lib/libminiupnpc.a + INCLUDES+=-Iext/bin/miniupnpc/include + LIBS+=ext/bin/miniupnpc/mac-x64/libminiupnpc.a OBJS+=osdep/UPNPClient.o endif diff --git a/service/OneService.cpp b/service/OneService.cpp index 05fdfb90..06e37a45 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -584,10 +584,8 @@ public: #ifdef ZT_USE_MINIUPNPC std::vector upnpAddresses(_upnpClient.get()); - for(std::vector::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) { - printf("Adding UPNP address: %s\n",ext->toString().c_str()); + for(std::vector::const_iterator ext(upnpAddresses.begin());ext!=upnpAddresses.end();++ext) _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext)),0,ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL); - } #endif struct ifaddrs *ifatbl = (struct ifaddrs *)0; -- cgit v1.2.3 From 5097aae7161856193d0c9df46fa1fbb5802f5141 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 14:50:24 -0700 Subject: Add miniupnpc to third party libs. --- AUTHORS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 4900aab5..b286e7ca 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,3 +39,6 @@ digital signature algorithm, and Poly1305 MAC algorithm, all by Daniel J. Bernstein (public domain)
http://cr.yp.to/ + + * MiniUPNPC by Thomas Bernard [BSD] + http://miniupnp.free.fr -- cgit v1.2.3 From ebe5c526bb6ca2b28f8175d2d00e30e0715379a6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 15:05:04 -0700 Subject: libminiupnpc.a for arm6l --- ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a | Bin 0 -> 62698 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a diff --git a/ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a b/ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a new file mode 100644 index 00000000..4983f628 Binary files /dev/null and b/ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a differ -- cgit v1.2.3 From 559e384130407db3a507f8edff0a442258529937 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 15:37:18 -0700 Subject: Linux make support for libminiupnpc. --- ext/bin/miniupnpc/linux-arm32/libminiupnpc.a | Bin 0 -> 62698 bytes ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a | Bin 62698 -> 0 bytes make-linux.mk | 26 ++++++++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 ext/bin/miniupnpc/linux-arm32/libminiupnpc.a delete mode 100644 ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a diff --git a/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a b/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a new file mode 100644 index 00000000..4983f628 Binary files /dev/null and b/ext/bin/miniupnpc/linux-arm32/libminiupnpc.a differ diff --git a/ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a b/ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a deleted file mode 100644 index 4983f628..00000000 Binary files a/ext/bin/miniupnpc/linux-arm6l/libminiupnpc.a and /dev/null differ diff --git a/make-linux.mk b/make-linux.mk index d1e0c955..7697e3ac 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -26,6 +26,8 @@ ifeq ($(origin CXX),default) CXX=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) endif +UNAME_M=$(shell uname -m) + INCLUDES= DEFS= LDLIBS?= @@ -36,6 +38,30 @@ OBJS+=osdep/LinuxEthernetTap.o # "make official" is a shortcut for this ifeq ($(ZT_OFFICIAL_RELEASE),1) DEFS+=-DZT_OFFICIAL_RELEASE + ZT_USE_MINIUPNPC=1 +endif + +ifeq ($(ZT_USE_MINIUPNPC),1) + DEFS+=-DZT_USE_MINIUPNPC + INCLUDES+=-Iext/bin/miniupnpc/include +ifeq ($(UNAME_M),armv6l) + MINIUPNPC_LIB=ext/bin/miniupnpc/linux-arm32/libminiupnpc.a +endif +ifeq ($(UNAME_M),armv7l) + MINIUPNPC_LIB=ext/bin/miniupnpc/linux-arm32/libminiupnpc.a +endif +ifeq ($(UNAME_M),x86_64) + MINIUPNPC_LIB=ext/bin/miniupnpc/linux-x64/libminiupnpc.a +endif +ifeq ($(UNAME_M),i386) + MINIUPNPC_LIB=ext/bin/miniupnpc/linux-x86/libminiupnpc.a +endif +ifeq ($(UNAME_M),i686) + MINIUPNPC_LIB=ext/bin/miniupnpc/linux-x86/libminiupnpc.a +endif + MINIUPNPC_LIB?=-lminiupnpc + LDLIBS+=$(MINIUPNPC_LIB) + OBJS+=osdep/UPNPClient.o endif # Build with ZT_ENABLE_NETWORK_CONTROLLER=1 to build with the Sqlite network controller -- cgit v1.2.3 From 7df4eb69b596594b7dfe0acda455c413117c8981 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 24 Jul 2015 17:49:56 -0700 Subject: Linux x64 libminiupnpc.a --- ext/bin/miniupnpc/linux-x64/libminiupnpc.a | Bin 0 -> 87942 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ext/bin/miniupnpc/linux-x64/libminiupnpc.a diff --git a/ext/bin/miniupnpc/linux-x64/libminiupnpc.a b/ext/bin/miniupnpc/linux-x64/libminiupnpc.a new file mode 100644 index 00000000..270366e0 Binary files /dev/null and b/ext/bin/miniupnpc/linux-x64/libminiupnpc.a differ -- cgit v1.2.3 From 3c54187c4019f29ed35a42ad3af06c38e16236ac Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 15:56:37 -0700 Subject: Linux x86 libminiupnpc.a --- ext/bin/miniupnpc/linux-x86/libminiupnpc.a | Bin 0 -> 67782 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ext/bin/miniupnpc/linux-x86/libminiupnpc.a diff --git a/ext/bin/miniupnpc/linux-x86/libminiupnpc.a b/ext/bin/miniupnpc/linux-x86/libminiupnpc.a new file mode 100644 index 00000000..99cbef21 Binary files /dev/null and b/ext/bin/miniupnpc/linux-x86/libminiupnpc.a differ -- cgit v1.2.3 From 14264c2d6f7d20b15081a1db5e8ca4b978d935a0 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 16:50:18 -0700 Subject: Add miniupnpc builds for Windows, fix some Windows build warnings. --- ext/bin/miniupnpc/windows-x64/miniupnpc.lib | Bin 0 -> 731616 bytes ext/bin/miniupnpc/windows-x86/miniupnpc.lib | Bin 0 -> 702786 bytes ext/installfiles/windows/ZeroTier One.aip | 6 +-- osdep/Phy.hpp | 2 +- osdep/UPNPClient.cpp | 10 +++- windows/ZeroTierOne/ZeroTierOne.vcxproj | 46 ++++++++++++----- windows/ZeroTierOne/ZeroTierOne.vcxproj.filters | 63 ++++++++++++++++++++++++ 7 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 ext/bin/miniupnpc/windows-x64/miniupnpc.lib create mode 100644 ext/bin/miniupnpc/windows-x86/miniupnpc.lib diff --git a/ext/bin/miniupnpc/windows-x64/miniupnpc.lib b/ext/bin/miniupnpc/windows-x64/miniupnpc.lib new file mode 100644 index 00000000..e05fefc8 Binary files /dev/null and b/ext/bin/miniupnpc/windows-x64/miniupnpc.lib differ diff --git a/ext/bin/miniupnpc/windows-x86/miniupnpc.lib b/ext/bin/miniupnpc/windows-x86/miniupnpc.lib new file mode 100644 index 00000000..a7fe4191 Binary files /dev/null and b/ext/bin/miniupnpc/windows-x86/miniupnpc.lib differ diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index ff7ee219..61755698 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -23,7 +23,7 @@ - + @@ -87,8 +87,8 @@ - - + + diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index 5afd715b..2ea68b9d 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -781,7 +781,7 @@ public: // Causes entry to be deleted from list in poll(), ignored elsewhere sws.type = ZT_PHY_SOCKET_CLOSED; - if (sws.sock >= _nfds) { + if ((long)sws.sock >= (long)_nfds) { long nfds = (long)_whackSendSocket; if ((long)_whackReceiveSocket > nfds) nfds = (long)_whackReceiveSocket; diff --git a/osdep/UPNPClient.cpp b/osdep/UPNPClient.cpp index 20aa9d39..ceecb3a3 100644 --- a/osdep/UPNPClient.cpp +++ b/osdep/UPNPClient.cpp @@ -40,8 +40,14 @@ #include "../node/Utils.hpp" #include "UPNPClient.hpp" -#include -#include +#ifdef __WINDOWS__ +#ifndef MINIUPNP_STATICLIB +#define MINIUPNP_STATICLIB +#endif +#endif + +#include "../ext/bin/miniupnpc/include/miniupnpc/miniupnpc.h" +#include "../ext/bin/miniupnpc/include/miniupnpc/upnpcommands.h" namespace ZeroTier { diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 554669b6..14bf7c3e 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -47,6 +47,7 @@ + true @@ -61,6 +62,22 @@ + + + + + + + + + + + + + + + + @@ -108,6 +125,7 @@ + @@ -193,12 +211,13 @@ Level3 Disabled true - $(SolutionDir)\ext\bin\libcrypto\include - NOMINMAX;ZT_TRACE;%(PreprocessorDefinitions) + + + NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;%(PreprocessorDefinitions) true - wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + $(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -207,12 +226,13 @@ Level3 Disabled true - $(SolutionDir)\ext\bin\libcrypto\include - NOMINMAX;ZT_TRACE;%(PreprocessorDefinitions) + + + NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;%(PreprocessorDefinitions) true - wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + $(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -223,8 +243,9 @@ true true true - $(SolutionDir)\ext\bin\libcrypto\include - ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;NOMINMAX;%(PreprocessorDefinitions) + + + ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded NoExtensions true @@ -236,7 +257,7 @@ true true true - wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + $(SolutionDir)..\ext\bin\miniupnpc\windows-x86\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false @@ -247,8 +268,9 @@ true true true - $(SolutionDir)\ext\bin\libcrypto\include - ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;NOMINMAX;%(PreprocessorDefinitions) + + + ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded NotSet true @@ -260,7 +282,7 @@ true true true - wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) + $(SolutionDir)..\ext\bin\miniupnpc\windows-x64\miniupnpc.lib;wsock32.lib;ws2_32.lib;newdev.lib;Iphlpapi.lib;Rpcrt4.lib;%(AdditionalDependencies) false diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index f36b5dc0..abaa8547 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -70,6 +70,15 @@ {bf604491-14c4-4a74-81a6-6105d07c5c7c} + + {5939db69-ab17-47c6-97fb-185e2c678737} + + + {3666f510-b6da-47cb-8039-56441f2dac3e} + + + {1a47071e-e51b-4535-89ae-858946f03118} + @@ -177,6 +186,9 @@ Source Files\osdep + + Source Files\osdep + @@ -347,6 +359,57 @@ Header Files\node + + Header Files\osdep + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + + + Header Files\ext\bin\miniupnpc\include + -- cgit v1.2.3 From e3983f8a574f4bb4b54bba5995c5f8be0ac78957 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 16:51:46 -0700 Subject: Get rid of -I on Mac and Linux since we include miniupnpc headers by direct path reference. --- make-linux.mk | 1 - make-mac.mk | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/make-linux.mk b/make-linux.mk index 7697e3ac..2ef9b985 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -43,7 +43,6 @@ endif ifeq ($(ZT_USE_MINIUPNPC),1) DEFS+=-DZT_USE_MINIUPNPC - INCLUDES+=-Iext/bin/miniupnpc/include ifeq ($(UNAME_M),armv6l) MINIUPNPC_LIB=ext/bin/miniupnpc/linux-arm32/libminiupnpc.a endif diff --git a/make-mac.mk b/make-mac.mk index 707d517c..c0b3f89d 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -14,7 +14,7 @@ include objects.mk OBJS+=osdep/OSXEthernetTap.o # Comment out to disable building against shipped libminiupnpc binary for Mac -ZT_USE_MINIUPNPC=1 +ZT_USE_MINIUPNPC?=1 # Disable codesign since open source users will not have ZeroTier's certs CODESIGN=echo @@ -38,7 +38,6 @@ endif ifeq ($(ZT_USE_MINIUPNPC),1) DEFS+=-DZT_USE_MINIUPNPC - INCLUDES+=-Iext/bin/miniupnpc/include LIBS+=ext/bin/miniupnpc/mac-x64/libminiupnpc.a OBJS+=osdep/UPNPClient.o endif -- cgit v1.2.3 From 2599b1bacc2b34ca797eca76d079262f34c93366 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 17:10:56 -0700 Subject: Add CLI support for /explicit/urls (automatically outputs JSON in this case), and some cleanup. --- one.cpp | 20 ++++++++++++++++++-- service/OneService.hpp | 2 -- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/one.cpp b/one.cpp index c4970ab8..d6345919 100644 --- a/one.cpp +++ b/one.cpp @@ -256,7 +256,23 @@ static int cli(int argc,char **argv) requestHeaders["X-ZT1-Auth"] = authToken; - if ((command == "info")||(command == "status")) { + if ((command.length() > 0)&&(command[0] == '/')) { + unsigned int scode = Http::GET( + 1024 * 1024 * 16, + 60000, + (const struct sockaddr *)&addr, + command.c_str(), + requestHeaders, + responseHeaders, + responseBody); + if (scode == 200) { + printf("%s",cliFixJsonCRs(responseBody).c_str()); + return 0; + } else { + printf("%u %s %s"ZT_EOL_S,scode,command.c_str(),responseBody.c_str()); + return 1; + } + } else if ((command == "info")||(command == "status")) { unsigned int scode = Http::GET( 1024 * 1024 * 16, 60000, @@ -363,7 +379,7 @@ static int cli(int argc,char **argv) else if ((!strcmp(jpath->u.object.values[kk].name,"active"))&&(jpath->u.object.values[kk].value->type == json_boolean)) active = (jpath->u.object.values[kk].value->u.boolean != 0); } - if (paddr) { + if ((paddr)&&((active)||(fixed))) { int64_t now = (int64_t)OSUtils::now(); if (lastSend > 0) lastSend = now - lastSend; diff --git a/service/OneService.hpp b/service/OneService.hpp index 7964958c..7a4f7827 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -106,8 +106,6 @@ public: * The terminate() method may be called from a signal handler or another * thread to terminate execution. Otherwise this will not return unless * another condition terminates execution such as a fatal error. - * - * @param */ virtual ReasonForTermination run() = 0; -- cgit v1.2.3 From 7578b5629849f6c286c353dce713b0816b1cc4a9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 28 Jul 2015 17:22:59 -0700 Subject: docs --- include/ZeroTierOne.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index dc2243f2..8583aa3a 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -967,11 +967,15 @@ void ZT1_Node_freeQueryResult(ZT1_Node *node,void *qr); * Take care that these are never ZeroTier interface addresses, otherwise * strange things might happen or they simply won't work. * + * Addresses can also be added here if they are the result of a UPnP or + * NAT-PMP port mapping or other discovery or mapping means. + * * This returns a boolean indicating whether or not the address was * accepted. ZeroTier will only communicate over certain address types * and (for IP) address classes. Thus it's safe to just dump your OS's * entire remote IP list (excluding ZeroTier interface IPs) into here - * and let ZeroTier determine which addresses it will use. + * and let ZeroTier determine which addresses it will use. It will + * reject bad, empty, and unusable addresses. * * @param addr Local interface address * @param metric Local interface metric -- cgit v1.2.3