Skip to content

Instantly share code, notes, and snippets.

@denandz
Created September 16, 2021 11:01
Show Gist options
  • Save denandz/d09ffe67e468baa5609cc6975848d960 to your computer and use it in GitHub Desktop.
Save denandz/d09ffe67e468baa5609cc6975848d960 to your computer and use it in GitHub Desktop.
Additional logging and attack functionality for ZeroTier security testing
diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp
index 10cb0863..cb4b01f0 100644
--- a/node/CertificateOfMembership.cpp
+++ b/node/CertificateOfMembership.cpp
@@ -150,17 +150,22 @@ void CertificateOfMembership::fromString(const char *s)
bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const
{
+ fprintf(stderr,"CertificateOfMembership::agreesWith\n");
unsigned int myidx = 0;
unsigned int otheridx = 0;
- if ((_qualifierCount == 0)||(other._qualifierCount == 0))
+ if ((_qualifierCount == 0)||(other._qualifierCount == 0)){
+ fprintf(stderr,"CertificateOfMembership::agreesWith no qualifiers %u %u\n", _qualifierCount, other._qualifierCount);
return false;
+ }
while (myidx < _qualifierCount) {
// Fail if we're at the end of other, since this means the field is
// missing.
- if (otheridx >= other._qualifierCount)
+ if (otheridx >= other._qualifierCount){
+ fprintf(stderr,"CertificateOfMembership::agreesWith otheridx >= other._qualifierCount\n");
return false;
+ }
// Seek to corresponding tuple in other, ignoring tuples that
// we may not have. If we run off the end of other, the tuple is
@@ -206,8 +211,10 @@ bool CertificateOfMembership::sign(const Identity &with)
int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const
{
- if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS))
- return -1;
+ if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)){
+ fprintf(stderr,"CertificateOfMembership::verify - not signed by network controller\n");
+ return -1;
+}
const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
if (!id) {
@@ -222,7 +229,13 @@ int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) con
buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
}
- return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
+ int ret = (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
+ if(ret == 0){
+ fprintf(stderr,"CertificateOfMembership::verify - id.verify succeeded\n");
+ } else {
+ fprintf(stderr,"CertificateOfMembership::verify - id.verify failed\n");
+ }
+
+ return ret;
}
-
} // namespace ZeroTier
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index d1f0f51d..81da02e4 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -43,6 +43,7 @@ namespace ZeroTier {
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t flowId)
{
const Address sourceAddress(source());
+ fprintf(stderr,"IncomingPacket::tryDecode()\n");
try {
// Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
@@ -139,6 +140,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
switch(errorCode) {
case Packet::ERROR_OBJ_NOT_FOUND:
+ fprintf(stderr,"_doERROR - ERROR_OBJ_NOT_FOUND\n");
// Object not found, currently only meaningful from network controllers.
if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
@@ -148,6 +150,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
break;
case Packet::ERROR_UNSUPPORTED_OPERATION:
+ fprintf(stderr,"_doERROR - ERROR_UNSUPPORTED_OPERATION\n");
// This can be sent in response to any operation, though right now we only
// consider it meaningful from network controllers. This would indicate
// that the queried node does not support acting as a controller.
@@ -159,12 +162,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
break;
case Packet::ERROR_IDENTITY_COLLISION:
+ fprintf(stderr,"_doERROR - ERROR_IDENTITY_COLLISION\n");
// FIXME: for federation this will need a payload with a signature or something.
if (RR->topology->isUpstream(peer->identity()))
RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
break;
case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
+ fprintf(stderr,"_doERROR - ERROR_NEED_MEMBERSHIP_CERTIFICATE\n");
// Peers can send this in response to frames if they do not have a recent enough COM from us
networkId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
const SharedPtr<Network> network(RR->node->network(networkId));
@@ -174,6 +179,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
} break;
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
+ fprintf(stderr,"_doERROR - ERROR_NETWORK_ACCESS_DENIED_\n");
// Network controller: network access denied.
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
if ((network)&&(network->controller() == peer->address()))
@@ -181,6 +187,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
} break;
case Packet::ERROR_UNWANTED_MULTICAST: {
+ fprintf(stderr,"_doERROR - ERROR_UNWANTED_MULTICAST\n");
// Members of networks can use this error to indicate that they no longer
// want to receive multicasts on a given channel.
networkId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
@@ -510,6 +517,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
} break;
case Packet::VERB_WHOIS:
+ fprintf(stderr, "_doOK() Handling WHOIS Reply\n");
if (RR->topology->isUpstream(peer->identity())) {
const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY);
RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr<Peer>(new Peer(RR,RR->identity,id))));
@@ -726,8 +734,11 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID);
const SharedPtr<Network> network(RR->node->network(nwid));
bool trustEstablished = false;
+ fprintf(stderr,"IncomingPacket::doFRAME()\n");
if (network) {
+ fprintf(stderr,"IncomingPacket::doFRAME() - passed network id check\n");
if (network->gate(tPtr,peer)) {
+ fprintf(stderr,"IncomingPacket::doFRAME() - passed network gate check\n");
trustEstablished = true;
if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
@@ -889,25 +900,34 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
bool trustEstablished = false;
SharedPtr<Network> network;
+
+ fprintf(stderr, "_doNETWORK_CREDENTIALS\n");
+
unsigned int p = ZT_PACKET_IDX_PAYLOAD;
while ((p < size())&&((*this)[p] != 0)) {
p += com.deserialize(*this,p);
if (com) {
+ fprintf(stderr, "_doNETWORK_CREDENTIALS: got com: %s\n", com.toString().c_str());
network = RR->node->network(com.networkId());
if (network) {
+ fprintf(stderr, "_doNETWORK_CREDENTIALS: calling addCredential()\n");
switch (network->addCredential(tPtr,com)) {
case Membership::ADD_REJECTED:
+ fprintf(stderr, "_doNETWORK_CREDENTIALS REJECTED\n");
break;
case Membership::ADD_ACCEPTED_NEW:
case Membership::ADD_ACCEPTED_REDUNDANT:
+ fprintf(stderr, "_doNETWORK_CREDENTIALS TRUSTED\n");
trustEstablished = true;
break;
case Membership::ADD_DEFERRED_FOR_WHOIS:
+ fprintf(stderr, "_doNETWORK_CREDENTIALS DEFERRED FOR WHOIS\n");
return false;
}
}
}
}
+
++p; // skip trailing 0 after COMs if present
if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations
diff --git a/node/Membership.cpp b/node/Membership.cpp
index 4f829ecb..08c272b9 100644
--- a/node/Membership.cpp
+++ b/node/Membership.cpp
@@ -104,28 +104,36 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com)
{
+ fprintf(stderr, "Membership:addCredenital\n");
const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) {
+ fprintf(stderr, "Membership:addCredenital: revoked\n");
RR->t->credentialRejected(tPtr,com,"revoked");
return ADD_REJECTED;
}
const int64_t oldts = _com.timestamp();
if (newts < oldts) {
+ fprintf(stderr, "Membership:addCredenital: old\n");
RR->t->credentialRejected(tPtr,com,"old");
return ADD_REJECTED;
}
- if ((newts == oldts)&&(_com == com))
+ if ((newts == oldts)&&(_com == com)){
+ fprintf(stderr, "Membership:addCredenital: redundant\n");
return ADD_ACCEPTED_REDUNDANT;
+ }
switch(com.verify(RR,tPtr)) {
default:
+ fprintf(stderr, "Membership:addCredenital: rejected by verify()\n");
RR->t->credentialRejected(tPtr,com,"invalid");
return ADD_REJECTED;
case 0:
+ fprintf(stderr, "Membership:addCredenital: accepted\n");
_com = com;
return ADD_ACCEPTED_NEW;
case 1:
+ fprintf(stderr, "Membership:addCredenital: deferred for whois\n");
return ADD_DEFERRED_FOR_WHOIS;
}
}
diff --git a/node/Membership.hpp b/node/Membership.hpp
index 47698771..2e4313c0 100644
--- a/node/Membership.hpp
+++ b/node/Membership.hpp
@@ -95,8 +95,13 @@ public:
*/
inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
{
+ fprintf(stderr, "isAllowedOnNetwork\n");
if (nconf.isPublic()) return true;
- if (_com.timestamp() <= _comRevocationThreshold) return false;
+ fprintf(stderr, "isAllowedOnNetwork _com.timestamp() %ld _comRevocationThreshold %ld\n", _com.timestamp(), _comRevocationThreshold);
+ if (_com.timestamp() <= _comRevocationThreshold){
+ fprintf(stderr, "isAllowedOnNetwork - revoked\n");
+ return false;
+ }
return nconf.com.agreesWith(_com);
}
diff --git a/node/Network.cpp b/node/Network.cpp
index 914c96bc..54f2d290 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -1221,14 +1221,21 @@ void Network::requestConfiguration(void *tPtr)
bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
{
+ fprintf(stderr,"Network::gate\n");
const int64_t now = RR->node->now();
Mutex::Lock _l(_lock);
try {
if (_config) {
+ fprintf(stderr,"Network::gate got _config\n");
Membership *m = _memberships.get(peer->address());
+ if(m){
+ fprintf(stderr, "Network::gate got m\n");
+ }
if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config))) ) {
- if (!m)
+ fprintf(stderr,"Network::gate m is allowed on network\n");
+ if (!m){
m = &(_membership(peer->address()));
+ }
if (m->multicastLikeGate(now)) {
_announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups());
}
@@ -1324,8 +1331,12 @@ void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int
Membership::AddCredentialResult Network::addCredential(void *tPtr,const CertificateOfMembership &com)
{
- if (com.networkId() != _id)
+ fprintf(stderr,"Network::addCredential: %s\n", com.toString().c_str());
+ if (com.networkId() != _id){
+ fprintf(stderr,"Network::addCredential: ADD_REJECTED\n");
return Membership::ADD_REJECTED;
+ }
+
Mutex::Lock _l(_lock);
return _membership(com.issuedTo()).addCredential(RR,tPtr,_config,com);
}
diff --git a/node/Network.hpp b/node/Network.hpp
index b20d8b66..27a7b194 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -352,6 +352,9 @@ public:
inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now)
{
Mutex::Lock _l(_lock);
+ char tmp[32];
+ to.toString(tmp);
+ fprintf(stderr, "pushCredentialsNow to %s\n", tmp);
_membership(to).pushCredentials(RR,tPtr,now,to,_config);
}
diff --git a/node/Node.hpp b/node/Node.hpp
index 2bbd3b47..630ceb97 100644
--- a/node/Node.hpp
+++ b/node/Node.hpp
@@ -63,6 +63,10 @@ public:
// Public API Functions ----------------------------------------------------
+ RuntimeEnvironment * getRuntime(){
+ return RR;
+ }
+
ZT_ResultCode processWirePacket(
void *tptr,
int64_t now,
diff --git a/node/Switch.cpp b/node/Switch.cpp
index b2040455..3f0ba77e 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -866,6 +866,9 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt,int32_t flowId)
void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr)
{
+ char tmp[1024];
+ addr.toString(tmp);
+ fprintf(stderr,"requestWhois for: %s\n", tmp);
if (addr == RR->identity.address())
return;
diff --git a/one.cpp b/one.cpp
index 06278174..b695568d 100644
--- a/one.cpp
+++ b/one.cpp
@@ -2035,6 +2035,7 @@ public:
returnValue = 1;
break;
case OneService::ONE_IDENTITY_COLLISION: {
+ fprintf(stderr,"COLLISION DETECTED\n");
delete zt1Service;
zt1Service = (OneService *)0;
std::string oldid;
diff --git a/service/OneService.cpp b/service/OneService.cpp
index 6f75dbdf..79c7f1f4 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -41,6 +41,8 @@
#include "../node/SHA512.hpp"
#include "../node/Bond.hpp"
#include "../node/Peer.hpp"
+#include "../node/Topology.hpp"
+#include "../node/Switch.hpp"
#include "../osdep/Phy.hpp"
#include "../osdep/OSUtils.hpp"
@@ -1416,6 +1418,85 @@ public:
} else scode = 404;
_node->freeQueryResult((void *)pl);
} else scode = 500;
+ } else if (ps[0] == "dowhois") {
+ char tmp[2048];
+ memset(tmp, 0x00, sizeof(tmp));
+ if (ps.size() == 2) {
+ uint64_t wantp = Utils::hexStrToU64(ps[1].c_str());
+ Address targetaddress = Address(wantp);
+
+ RuntimeEnvironment * RR = _node->getRuntime();
+
+ targetaddress.toString(tmp);
+ RR->sw->requestWhois(0x0,OSUtils::now(),targetaddress);
+
+ snprintf(tmp, sizeof(tmp), "WHOIS sent");
+ }
+ else {
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"Please supply address to WHOIS");
+
+ }
+
+ res["res"] = tmp;
+ scode = 501;
+ } else if (ps[0] == "domembershiperror") {
+ char tmp[2048];
+ memset(tmp, 0x00, sizeof(tmp));
+ if (ps.size() == 3) {
+ uint64_t wantp = Utils::hexStrToU64(ps[1].c_str());
+ uint64_t network = Utils::hexStrToU64(ps[2].c_str());
+ Address targetaddress = Address(wantp);
+ uint64_t pid = 0x43210; // garbage pid
+
+ RuntimeEnvironment * RR = _node->getRuntime();
+
+ Packet outp(targetaddress,RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((uint8_t)Packet::VERB_HELLO);
+ outp.append((uint64_t)pid);
+ outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
+ outp.append(network);
+ RR->sw->send(0x0, outp, true);
+ snprintf(tmp, sizeof(tmp), "Error sent to 0x%lx for network 0x%lx", wantp, network);
+ }
+ else {
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"Please supply peer and network address to send ERRORs to");
+ }
+
+ res["res"] = tmp;
+ scode = 501;
+ } else if (ps[0] == "doframe") {
+ char tmp[2048];
+ memset(tmp, 0x00, sizeof(tmp));
+ if (ps.size() == 3) {
+ /*unsigned char arp[] = {
+ 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x52, 0x54, 0x00, 0xc1,
+ 0xc1, 0x88, 0xc0, 0xa8, 0x7a, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0xa8, 0x7a, 0x01
+ };
+ unsigned int arp_len = 28;*/
+ unsigned char arp[] = { 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42};
+ unsigned int arp_len = 8;
+
+ uint64_t wantp = Utils::hexStrToU64(ps[1].c_str());
+ uint64_t network = Utils::hexStrToU64(ps[2].c_str());
+ Address targetaddress = Address(wantp);
+
+ RuntimeEnvironment * RR = _node->getRuntime();
+
+ Packet outp(targetaddress,RR->identity.address(),Packet::VERB_FRAME);
+ outp.append(network);
+ outp.append((uint16_t)ZT_ETHERTYPE_ARP);
+ outp.append(arp,arp_len);
+
+ RR->sw->send(0x0, outp, true);
+ snprintf(tmp, sizeof(tmp), "Frame sent");
+ }
+ else {
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"Please supply peer and network address for doframe");
+ }
+
+ res["res"] = tmp;
+ scode = 501;
} else if (ps[0] == "bonds") {
ZT_PeerList *pl = _node->peers();
if (pl) {
@@ -1555,6 +1636,30 @@ public:
} else scode = 500;
} else scode = 404;
+ } else if (ps[0] == "sendcom") {
+ char tmp[2048];
+ memset(tmp, 0x00, sizeof(tmp));
+ if (ps.size() == 3) {
+ uint64_t wantp = Utils::hexStrToU64(ps[1].c_str());
+ Address targetaddress = Address(wantp);
+
+ CertificateOfMembership com;
+ com.fromString(body.c_str());
+ RuntimeEnvironment * RR = _node->getRuntime();
+
+ Packet outp(targetaddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
+ com.serialize(outp);
+ outp.append((uint8_t)0x00);
+ RR->sw->send(0x0, outp, true);
+
+ snprintf(tmp, sizeof(tmp), "COM sent");
+ }
+ else {
+ OSUtils::ztsnprintf(tmp,sizeof(tmp),"Please supply target peer address and COM string in the POST body.");
+ }
+
+ res["res"] = tmp;
+ scode = 501;
} else {
if (_controller)
scode = _controller->handleControlPlaneHttpPOST(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment