added camouflaging functionality and instrumentation
This commit is contained in:
parent
cdaf5e5468
commit
083b833bf8
16 changed files with 904 additions and 43 deletions
266
node/Switch.cpp
266
node/Switch.cpp
|
@ -22,6 +22,7 @@
|
|||
#include "../include/ZeroTierOne.h"
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Hashtable.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Node.hpp"
|
||||
|
@ -33,6 +34,8 @@
|
|||
#include "Trace.hpp"
|
||||
#include "Metrics.hpp"
|
||||
|
||||
#include "CamoPattern.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
Switch::Switch(const RuntimeEnvironment *renv) :
|
||||
|
@ -78,18 +81,32 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
{
|
||||
int32_t flowId = ZT_QOS_NO_FLOW;
|
||||
try {
|
||||
char buf[64];
|
||||
fromAddr.toIpString(buf);
|
||||
CT("INCOMING PACKET localSocket: %ld, IP: %s:%u, isDefaultRoute: %u", localSocket, buf, fromAddr.port(), fromAddr.isDefaultRoute());
|
||||
|
||||
Packet remotePacket(data, len);
|
||||
CT("PACKET CONTENTS:");
|
||||
remotePacket.dump();
|
||||
bool hadCamo = CamoPattern::stripCamo(remotePacket);
|
||||
if (hadCamo)
|
||||
{
|
||||
CT("PACKET HAS CAMO. CONTENTS WITHOUT CAMO:");
|
||||
remotePacket.dump();
|
||||
}
|
||||
|
||||
const int64_t now = RR->node->now();
|
||||
|
||||
const SharedPtr<Path> path(RR->topology->getPath(localSocket,fromAddr));
|
||||
path->received(now);
|
||||
|
||||
if (len == 13) {
|
||||
if (remotePacket.size() == 13) {
|
||||
/* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast
|
||||
* announcements on the LAN to solve the 'same network problem.' We
|
||||
* no longer send these, but we'll listen for them for a while to
|
||||
* locate peers with versions <1.0.4. */
|
||||
|
||||
const Address beaconAddr(reinterpret_cast<const char *>(data) + 8,5);
|
||||
const Address beaconAddr(remotePacket.destination());
|
||||
if (beaconAddr == RR->identity.address()) {
|
||||
return;
|
||||
}
|
||||
|
@ -103,15 +120,19 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP);
|
||||
outp.armor(peer->key(),true,peer->aesKeysIfSupported());
|
||||
Metrics::pkt_nop_out++;
|
||||
if (CamoPattern::isCamoRequired(beaconAddr, RR, hadCamo, true))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { // SECURITY: min length check is important since we do some C-style stuff below!
|
||||
if (reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) {
|
||||
if (reinterpret_cast<const uint8_t &>(remotePacket[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR]) == ZT_PACKET_FRAGMENT_INDICATOR) {
|
||||
// Handle fragment ----------------------------------------------------
|
||||
|
||||
Packet::Fragment fragment(data,len);
|
||||
Packet::Fragment fragment(remotePacket);
|
||||
const Address destination(fragment.destination());
|
||||
|
||||
if (destination != RR->identity.address()) {
|
||||
|
@ -128,6 +149,10 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) {
|
||||
// Don't know peer or no direct path -- so relay via someone upstream
|
||||
relayTo = RR->topology->getUpstreamPeer();
|
||||
if (CamoPattern::isCamoRequired(destination, RR, hadCamo, true))
|
||||
{
|
||||
CamoPattern::applyCamo(fragment);
|
||||
}
|
||||
if (relayTo) {
|
||||
relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true);
|
||||
}
|
||||
|
@ -184,8 +209,8 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
} else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important!
|
||||
// Handle packet head -------------------------------------------------
|
||||
|
||||
const Address destination(reinterpret_cast<const uint8_t *>(data) + 8,ZT_ADDRESS_LENGTH);
|
||||
const Address source(reinterpret_cast<const uint8_t *>(data) + 13,ZT_ADDRESS_LENGTH);
|
||||
const Address destination(remotePacket.destination());
|
||||
const Address source(remotePacket.source());
|
||||
|
||||
if (source == RR->identity.address()) {
|
||||
return;
|
||||
|
@ -196,12 +221,14 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
return;
|
||||
}
|
||||
|
||||
Packet packet(data,len);
|
||||
|
||||
if (packet.hops() < ZT_RELAY_MAX_HOPS) {
|
||||
packet.incrementHops();
|
||||
if (remotePacket.hops() < ZT_RELAY_MAX_HOPS) {
|
||||
remotePacket.incrementHops();
|
||||
SharedPtr<Peer> relayTo = RR->topology->getPeer(tPtr,destination);
|
||||
if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) {
|
||||
if (CamoPattern::isCamoRequired(destination, RR, hadCamo, true))
|
||||
{
|
||||
CamoPattern::applyCamo(remotePacket);
|
||||
}
|
||||
if ((relayTo)&&(relayTo->sendDirect(tPtr,remotePacket.data(),remotePacket.size(),now,false))) {
|
||||
if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) {
|
||||
const SharedPtr<Peer> sourcePeer(RR->topology->getPeer(tPtr,source));
|
||||
if (sourcePeer) {
|
||||
|
@ -211,7 +238,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
} else {
|
||||
relayTo = RR->topology->getUpstreamPeer();
|
||||
if ((relayTo)&&(relayTo->address() != source)) {
|
||||
if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) {
|
||||
if (relayTo->sendDirect(tPtr,remotePacket.data(),remotePacket.size(),now,true)) {
|
||||
const SharedPtr<Peer> sourcePeer(RR->topology->getPeer(tPtr,source));
|
||||
if (sourcePeer) {
|
||||
relayTo->introduce(tPtr,now,sourcePeer);
|
||||
|
@ -220,19 +247,10 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if ((reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
|
||||
} else if ((reinterpret_cast<const uint8_t &>(remotePacket[ZT_PACKET_IDX_FLAGS]) & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
|
||||
// Packet is the head of a fragmented packet series
|
||||
|
||||
const uint64_t packetId = (
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[0]) << 56) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[1]) << 48) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[2]) << 40) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[3]) << 32) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[4]) << 24) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[5]) << 16) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[6]) << 8) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(data)[7])
|
||||
);
|
||||
const uint64_t packetId = remotePacket.packetId();
|
||||
|
||||
RXQueueEntry *const rq = _findRXQueueEntry(packetId);
|
||||
Mutex::Lock rql(rq->lock);
|
||||
|
@ -242,7 +260,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
rq->flowId = flowId;
|
||||
rq->timestamp = now;
|
||||
rq->packetId = packetId;
|
||||
rq->frag0.init(data,len,path,now);
|
||||
rq->frag0.init(remotePacket,path,now);
|
||||
rq->totalFragments = 0;
|
||||
rq->haveFragments = 1;
|
||||
rq->complete = false;
|
||||
|
@ -252,7 +270,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) {
|
||||
// We have all fragments -- assemble and process full Packet
|
||||
|
||||
rq->frag0.init(data,len,path,now);
|
||||
rq->frag0.init(remotePacket,path,now);
|
||||
for(unsigned int f=1;f<rq->totalFragments;++f) {
|
||||
rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength());
|
||||
}
|
||||
|
@ -264,12 +282,12 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre
|
|||
}
|
||||
} else {
|
||||
// Still waiting on more fragments, but keep the head
|
||||
rq->frag0.init(data,len,path,now);
|
||||
rq->frag0.init(remotePacket,path,now);
|
||||
}
|
||||
} // else this is a duplicate head, ignore
|
||||
} else {
|
||||
// Packet is unfragmented, so just process it
|
||||
IncomingPacket packet(data,len,path,now);
|
||||
IncomingPacket packet(remotePacket,path,now);
|
||||
if (!packet.tryDecode(RR,tPtr,flowId)) {
|
||||
RXQueueEntry *const rq = _nextRXQueueEntry();
|
||||
Mutex::Lock rql(rq->lock);
|
||||
|
@ -1127,6 +1145,199 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId)
|
|||
return false;
|
||||
}
|
||||
|
||||
#define NEWOUT
|
||||
#ifdef NEWOUT
|
||||
void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path> viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId)
|
||||
{
|
||||
unsigned int mtu = ZT_DEFAULT_PHYSMTU;
|
||||
uint64_t trustedPathId = 0;
|
||||
RR->topology->getOutboundPathInfo(viaPath->address(),mtu,trustedPathId);
|
||||
|
||||
char buf[64];
|
||||
|
||||
Address destination = packet.destination();
|
||||
destination.toString(buf);
|
||||
|
||||
Identity destinationIdentity;
|
||||
|
||||
RR->topology->getIdentity(&destinationIdentity, destination);
|
||||
CT("OUTGOING PACKET ZT ADDRESS: %s, isUpstream: %b, isProhibitedEndpoint: %b", buf, RR->topology->isUpstream(destinationIdentity), RR->topology->isProhibitedEndpoint(destination, InetAddress()));
|
||||
|
||||
|
||||
ZT_PeerRole role = RR->topology->role(destination);
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case ZT_PEER_ROLE_PLANET:
|
||||
strcpy(buf, "PLANET");
|
||||
break;
|
||||
case ZT_PEER_ROLE_MOON:
|
||||
strcpy(buf, "MOON");
|
||||
break;
|
||||
case ZT_PEER_ROLE_LEAF:
|
||||
strcpy(buf, "LEAF");
|
||||
break;
|
||||
default:
|
||||
strcpy(buf, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
|
||||
CT("DESTINATION ROLE: %s", buf);
|
||||
|
||||
switch(packet.verb())
|
||||
{
|
||||
case Packet::VERB_NOP:
|
||||
strcpy(buf, "NOP");
|
||||
break;
|
||||
case Packet::VERB_HELLO:
|
||||
strcpy(buf, "HELLO");
|
||||
break;
|
||||
case Packet::VERB_ERROR:
|
||||
strcpy(buf, "ERROR");
|
||||
break;
|
||||
case Packet::VERB_OK:
|
||||
strcpy(buf, "OK");
|
||||
break;
|
||||
case Packet::VERB_WHOIS:
|
||||
strcpy(buf, "WHOIS");
|
||||
break;
|
||||
case Packet::VERB_RENDEZVOUS:
|
||||
strcpy(buf, "RENDEZVOUS");
|
||||
break;
|
||||
case Packet::VERB_FRAME:
|
||||
strcpy(buf, "FRAME");
|
||||
break;
|
||||
case Packet::VERB_EXT_FRAME:
|
||||
strcpy(buf, "EXT_FRAME");
|
||||
break;
|
||||
case Packet::VERB_ECHO:
|
||||
strcpy(buf, "ECHO");
|
||||
break;
|
||||
case Packet::VERB_MULTICAST_LIKE:
|
||||
strcpy(buf, "MULTICAST_LIKE");
|
||||
break;
|
||||
case Packet::VERB_NETWORK_CREDENTIALS:
|
||||
strcpy(buf, "NETWORK_CREDENTIALS");
|
||||
break;
|
||||
case Packet::VERB_NETWORK_CONFIG_REQUEST:
|
||||
strcpy(buf, "NETWORK_CONFIG_REQUEST");
|
||||
break;
|
||||
case Packet::VERB_NETWORK_CONFIG:
|
||||
strcpy(buf, "NETWORK_CONFIG");
|
||||
break;
|
||||
case Packet::VERB_MULTICAST_GATHER:
|
||||
strcpy(buf, "MULTICAST_GATHER");
|
||||
break;
|
||||
case Packet::VERB_MULTICAST_FRAME:
|
||||
strcpy(buf, "MULTICAST_FRAME");
|
||||
break;
|
||||
case Packet::VERB_PUSH_DIRECT_PATHS:
|
||||
strcpy(buf, "PUSH_DIRECT_PATHS");
|
||||
break;
|
||||
case Packet::VERB_ACK:
|
||||
strcpy(buf, "ACK");
|
||||
break;
|
||||
case Packet::VERB_QOS_MEASUREMENT:
|
||||
strcpy(buf, "QOS_MEASUREMENT");
|
||||
break;
|
||||
case Packet::VERB_USER_MESSAGE:
|
||||
strcpy(buf, "USER_MESSAGE");
|
||||
break;
|
||||
case Packet::VERB_REMOTE_TRACE:
|
||||
strcpy(buf, "REMOTE_TRACE");
|
||||
break;
|
||||
case Packet::VERB_PATH_NEGOTIATION_REQUEST:
|
||||
strcpy(buf, "PATH_NEGOTIATION_REQUEST");
|
||||
break;
|
||||
default:
|
||||
strcpy(buf, "UNKNOWN");
|
||||
break;
|
||||
};
|
||||
|
||||
CT("PACKET VERB: %s", buf);
|
||||
|
||||
bool isController = false;
|
||||
{
|
||||
Mutex::Lock _l(RR->node->_networks_m);
|
||||
Hashtable<uint64_t, SharedPtr<Network>>::Iterator i(RR->node->_networks);
|
||||
uint64_t * k = (uint64_t *)0;
|
||||
SharedPtr<Network> *v = (SharedPtr<Network> *)0;
|
||||
while(i.next(k, v))
|
||||
{
|
||||
if (destination == ((*v)->controller()))
|
||||
{
|
||||
isController = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CT("isController: %b", isController);
|
||||
|
||||
if (userSpecifiedMtu > 0) {
|
||||
mtu = userSpecifiedMtu;
|
||||
}
|
||||
|
||||
bool isCamoRequired = CamoPattern::isCamoRequired(destination, RR);
|
||||
|
||||
unsigned int camoSize = isCamoRequired ? ZT_PROTO_ADDITIONAL_CAMO_LENGTH : 0;
|
||||
unsigned int packetSizeCamo = packet.size() + camoSize;
|
||||
unsigned int chunkSize = std::min(packetSizeCamo, mtu);
|
||||
bool isFragmented = chunkSize < (packetSizeCamo);
|
||||
packet.setFragmented(isFragmented);
|
||||
|
||||
CT("PACKET CONTENTS:");
|
||||
packet.dump();
|
||||
if (trustedPathId) {
|
||||
packet.setTrusted(trustedPathId);
|
||||
} else {
|
||||
if (!packet.isEncrypted()) {
|
||||
packet.armor(peer->key(),encrypt,peer->aesKeysIfSupported());
|
||||
}
|
||||
RR->node->expectReplyTo(packet.packetId());
|
||||
}
|
||||
CT("PACKET CONTENTS AFTER ENCRYPTION:");
|
||||
packet.dump();
|
||||
|
||||
peer->recordOutgoingPacket(viaPath, packet.packetId(), packet.payloadLength(), packet.verb(), flowId, now);
|
||||
|
||||
if (!isFragmented)
|
||||
{
|
||||
CT("UNFRAGMENTED BRANCH");
|
||||
if (isCamoRequired)
|
||||
{
|
||||
CamoPattern::applyCamo(packet);
|
||||
}
|
||||
viaPath->send(RR,tPtr,packet.data(),chunkSize,now);
|
||||
}
|
||||
else
|
||||
{
|
||||
CT("FRAGMENTED BRANCH");
|
||||
// Too big for one packet, fragment it
|
||||
unsigned int minFragmentSize = ZT_PROTO_MIN_FRAGMENT_LENGTH + camoSize;
|
||||
unsigned int fragStart = 0;
|
||||
unsigned int remaining = packet.size();
|
||||
unsigned int fragSize = mtu - minFragmentSize;
|
||||
unsigned int fragsRemaining = (remaining / (fragSize));
|
||||
if ((fragsRemaining * fragSize) < remaining) {
|
||||
++fragsRemaining;
|
||||
}
|
||||
const unsigned int totalFragments = fragsRemaining;
|
||||
|
||||
for(unsigned int fno=0;fno<totalFragments;fno++) {
|
||||
chunkSize = std::min(remaining, fragSize);
|
||||
Packet::Fragment frag(packet,fragStart,chunkSize,fno,totalFragments);
|
||||
if (isCamoRequired)
|
||||
{
|
||||
CamoPattern::applyCamo(frag);
|
||||
}
|
||||
viaPath->send(RR,tPtr,frag.data(),frag.size(),now);
|
||||
fragStart += chunkSize;
|
||||
remaining -= chunkSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path> viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId)
|
||||
{
|
||||
unsigned int mtu = ZT_DEFAULT_PHYSMTU;
|
||||
|
@ -1171,6 +1382,7 @@ void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Switch::_recordOutgoingPacketMetrics(const Packet &p) {
|
||||
switch (p.verb()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue