mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-19 19:28:58 +00:00
More refactoring to clean up code, and add a gate function to make sure we do not handle OK packets we did not expect. This hardens up a few potential edge cases around security, since such messages might be used to e.g. pollute a cache and DOS under certain conditions.
This commit is contained in:
parent
16df2c3363
commit
0d4109a9f1
@ -1585,7 +1585,6 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes
|
|||||||
"\t\"upstream\": \"%.10llx\"," ZT_EOL_S
|
"\t\"upstream\": \"%.10llx\"," ZT_EOL_S
|
||||||
"\t\"current\": \"%.10llx\"," ZT_EOL_S
|
"\t\"current\": \"%.10llx\"," ZT_EOL_S
|
||||||
"\t\"receivedTimestamp\": %llu," ZT_EOL_S
|
"\t\"receivedTimestamp\": %llu," ZT_EOL_S
|
||||||
"\t\"remoteTimestamp\": %llu," ZT_EOL_S
|
|
||||||
"\t\"sourcePacketId\": \"%.16llx\"," ZT_EOL_S
|
"\t\"sourcePacketId\": \"%.16llx\"," ZT_EOL_S
|
||||||
"\t\"flags\": %llu," ZT_EOL_S
|
"\t\"flags\": %llu," ZT_EOL_S
|
||||||
"\t\"sourcePacketHopCount\": %u," ZT_EOL_S
|
"\t\"sourcePacketHopCount\": %u," ZT_EOL_S
|
||||||
@ -1606,7 +1605,6 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes
|
|||||||
(unsigned long long)report->upstream,
|
(unsigned long long)report->upstream,
|
||||||
(unsigned long long)report->current,
|
(unsigned long long)report->current,
|
||||||
(unsigned long long)OSUtils::now(),
|
(unsigned long long)OSUtils::now(),
|
||||||
(unsigned long long)report->remoteTimestamp,
|
|
||||||
(unsigned long long)report->sourcePacketId,
|
(unsigned long long)report->sourcePacketId,
|
||||||
(unsigned long long)report->flags,
|
(unsigned long long)report->flags,
|
||||||
report->sourcePacketHopCount,
|
report->sourcePacketHopCount,
|
||||||
|
@ -154,6 +154,11 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 8
|
#define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Circuit test report flag: upstream peer authorized in path (e.g. by network COM)
|
||||||
|
*/
|
||||||
|
#define ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH 0x0000000000000001ULL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of cluster members (and max member ID plus one)
|
* Maximum number of cluster members (and max member ID plus one)
|
||||||
*/
|
*/
|
||||||
@ -1218,18 +1223,13 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
|
|
||||||
/**
|
|
||||||
* Timestamp on remote device
|
|
||||||
*/
|
|
||||||
uint64_t remoteTimestamp;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 64-bit packet ID of packet received by the reporting device
|
* 64-bit packet ID of packet received by the reporting device
|
||||||
*/
|
*/
|
||||||
uint64_t sourcePacketId;
|
uint64_t sourcePacketId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flags (currently unused, will be zero)
|
* Flags
|
||||||
*/
|
*/
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
|
|
||||||
|
@ -156,6 +156,17 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||||||
RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
|
RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
|
||||||
|
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||||
|
if ((network)&&(network->recentlyAllowedOnNetwork(peer))) {
|
||||||
|
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
||||||
|
network->config().com.serialize(outp);
|
||||||
|
outp.append((uint8_t)0);
|
||||||
|
outp.armor(peer->key(),true);
|
||||||
|
_path->send(RR,outp.data(),outp.size(),RR->node->now());
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
|
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
|
||||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||||
if ((network)&&(network->controller() == peer->address()))
|
if ((network)&&(network->controller() == peer->address()))
|
||||||
@ -163,10 +174,12 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Packet::ERROR_UNWANTED_MULTICAST: {
|
case Packet::ERROR_UNWANTED_MULTICAST: {
|
||||||
uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
|
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||||
MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at<uint32_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14));
|
if ((network)&&(network->gate(peer,verb(),packetId()))) {
|
||||||
TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",nwid,peer->address().toString().c_str(),mg.toString().c_str());
|
MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at<uint32_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14));
|
||||||
RR->mc->remove(nwid,mg,peer->address());
|
TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str());
|
||||||
|
RR->mc->remove(network->id(),mg,peer->address());
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
@ -352,7 +365,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||||||
const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB];
|
const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB];
|
||||||
const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID);
|
const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID);
|
||||||
|
|
||||||
//TRACE("%s(%s): OK(%s)",source().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb));
|
if (!RR->node->expectingReplyTo(inRePacketId)) {
|
||||||
|
TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TRACE("%s(%s): OK(%s)",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb));
|
||||||
|
|
||||||
switch(inReVerb) {
|
switch(inReVerb) {
|
||||||
|
|
||||||
@ -424,10 +442,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||||||
|
|
||||||
case Packet::VERB_MULTICAST_GATHER: {
|
case Packet::VERB_MULTICAST_GATHER: {
|
||||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
|
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
|
||||||
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
|
SharedPtr<Network> network(RR->node->network(nwid));
|
||||||
//TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size());
|
if ((network)&&(network->gate(peer,verb(),packetId()))) {
|
||||||
const unsigned int count = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4);
|
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
|
||||||
RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS));
|
//TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size());
|
||||||
|
const unsigned int count = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4);
|
||||||
|
RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS));
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Packet::VERB_MULTICAST_FRAME: {
|
case Packet::VERB_MULTICAST_FRAME: {
|
||||||
@ -437,24 +458,26 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||||||
|
|
||||||
//TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags);
|
//TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags);
|
||||||
|
|
||||||
unsigned int offset = 0;
|
SharedPtr<Network> network(RR->node->network(nwid));
|
||||||
|
if (network) {
|
||||||
|
unsigned int offset = 0;
|
||||||
|
|
||||||
if ((flags & 0x01) != 0) { // deprecated but still used by older peers
|
if ((flags & 0x01) != 0) { // deprecated but still used by older peers
|
||||||
CertificateOfMembership com;
|
CertificateOfMembership com;
|
||||||
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS);
|
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS);
|
||||||
if (com) {
|
if (com)
|
||||||
SharedPtr<Network> network(RR->node->network(com.networkId()));
|
|
||||||
if (network)
|
|
||||||
network->addCredential(com);
|
network->addCredential(com);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ((flags & 0x02) != 0) {
|
if (network->gate(peer,verb(),packetId())) {
|
||||||
// OK(MULTICAST_FRAME) includes implicit gather results
|
if ((flags & 0x02) != 0) {
|
||||||
offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS;
|
// OK(MULTICAST_FRAME) includes implicit gather results
|
||||||
unsigned int totalKnown = at<uint32_t>(offset); offset += 4;
|
offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS;
|
||||||
unsigned int count = at<uint16_t>(offset); offset += 2;
|
unsigned int totalKnown = at<uint32_t>(offset); offset += 4;
|
||||||
RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown);
|
unsigned int count = at<uint16_t>(offset); offset += 2;
|
||||||
|
RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -515,27 +538,29 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||||||
bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
if (!RR->topology->isUpstream(peer->identity())) {
|
||||||
const SharedPtr<Peer> rendezvousWith(RR->topology->getPeer(with));
|
TRACE("RENDEZVOUS from %s ignored since source is not upstream",peer->address().toString().c_str());
|
||||||
if (rendezvousWith) {
|
} else {
|
||||||
const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
|
const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||||
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
|
const SharedPtr<Peer> rendezvousWith(RR->topology->getPeer(with));
|
||||||
if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
|
if (rendezvousWith) {
|
||||||
const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
|
const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
|
||||||
if (!RR->topology->isUpstream(peer->identity())) {
|
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
|
||||||
TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since peer is not upstream",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
|
||||||
} else if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) {
|
const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
|
||||||
RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls
|
if (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),atAddr)) {
|
||||||
rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now());
|
RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls
|
||||||
TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now());
|
||||||
|
TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
||||||
|
} else {
|
||||||
|
TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
|
TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_path->address().toString().c_str());
|
TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_path->address().toString().c_str(),with.toString().c_str());
|
|
||||||
}
|
}
|
||||||
peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false);
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
@ -549,25 +574,25 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||||||
try {
|
try {
|
||||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID);
|
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID);
|
||||||
const SharedPtr<Network> network(RR->node->network(nwid));
|
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||||
bool approved = false;
|
bool trustEstablished = false;
|
||||||
if (network) {
|
if (network) {
|
||||||
if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
|
if (!network->gate(peer,verb(),packetId())) {
|
||||||
if (!network->gate(peer,verb(),packetId())) {
|
TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id());
|
||||||
TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id());
|
} else {
|
||||||
} else {
|
trustEstablished = true;
|
||||||
|
if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
|
||||||
const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
|
const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
|
||||||
const MAC sourceMac(peer->address(),nwid);
|
const MAC sourceMac(peer->address(),nwid);
|
||||||
const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
|
const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
|
||||||
const uint8_t *const frameData = reinterpret_cast<const uint8_t *>(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
|
const uint8_t *const frameData = reinterpret_cast<const uint8_t *>(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
|
||||||
if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0)
|
if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0)
|
||||||
RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen);
|
RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen);
|
||||||
approved = true; // this means approved on the network in general, not this packet per se
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
|
TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
|
||||||
}
|
}
|
||||||
peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,approved);
|
peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished);
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
||||||
}
|
}
|
||||||
@ -580,23 +605,23 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
|
|||||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID);
|
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID);
|
||||||
const SharedPtr<Network> network(RR->node->network(nwid));
|
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||||
if (network) {
|
if (network) {
|
||||||
|
const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS];
|
||||||
|
|
||||||
|
unsigned int comLen = 0;
|
||||||
|
if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers
|
||||||
|
CertificateOfMembership com;
|
||||||
|
comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM);
|
||||||
|
if (com)
|
||||||
|
network->addCredential(com);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!network->gate(peer,verb(),packetId())) {
|
||||||
|
TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id());
|
||||||
|
peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
|
if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
|
||||||
const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS];
|
|
||||||
|
|
||||||
unsigned int comLen = 0;
|
|
||||||
if ((flags & 0x01) != 0) { // deprecated but still used by old peers
|
|
||||||
CertificateOfMembership com;
|
|
||||||
comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM);
|
|
||||||
if (com)
|
|
||||||
network->addCredential(com);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!network->gate(peer,verb(),packetId())) {
|
|
||||||
TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id());
|
|
||||||
peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned int etherType = at<uint16_t>(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE);
|
const unsigned int etherType = at<uint16_t>(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE);
|
||||||
const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO);
|
const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO);
|
||||||
const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM);
|
const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM);
|
||||||
@ -604,7 +629,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
|
|||||||
const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen);
|
const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen);
|
||||||
|
|
||||||
if ((!from)||(from.isMulticast())||(from == network->mac())) {
|
if ((!from)||(from.isMulticast())||(from == network->mac())) {
|
||||||
TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str());
|
TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC %s",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),from.toString().c_str());
|
||||||
peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
|
peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1139,6 +1164,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
|
|||||||
// Add length of second "additional fields" section.
|
// Add length of second "additional fields" section.
|
||||||
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
|
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
|
||||||
|
|
||||||
|
uint64_t reportFlags = 0;
|
||||||
|
|
||||||
// Check credentials (signature already verified)
|
// Check credentials (signature already verified)
|
||||||
if (originatorCredentialNetworkId) {
|
if (originatorCredentialNetworkId) {
|
||||||
SharedPtr<Network> network(RR->node->network(originatorCredentialNetworkId));
|
SharedPtr<Network> network(RR->node->network(originatorCredentialNetworkId));
|
||||||
@ -1147,6 +1174,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
|
|||||||
peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (network->gate(peer,verb(),packetId()))
|
||||||
|
reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH;
|
||||||
} else {
|
} else {
|
||||||
TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
|
TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
|
||||||
peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
|
||||||
@ -1188,7 +1217,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
|
|||||||
outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED);
|
outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED);
|
||||||
outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED);
|
outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED);
|
||||||
outp.append((uint16_t)0); // error code, currently unused
|
outp.append((uint16_t)0); // error code, currently unused
|
||||||
outp.append((uint64_t)0); // flags, currently unused
|
outp.append((uint64_t)reportFlags);
|
||||||
outp.append((uint64_t)packetId());
|
outp.append((uint64_t)packetId());
|
||||||
peer->address().appendTo(outp);
|
peer->address().appendTo(outp);
|
||||||
outp.append((uint8_t)hops());
|
outp.append((uint8_t)hops());
|
||||||
@ -1237,7 +1266,6 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S
|
|||||||
report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
|
report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
|
||||||
report.testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 8);
|
report.testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 8);
|
||||||
report.timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
|
report.timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
|
||||||
report.remoteTimestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 16);
|
|
||||||
report.sourcePacketId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 44);
|
report.sourcePacketId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 44);
|
||||||
report.flags = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 36);
|
report.flags = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 36);
|
||||||
report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58
|
report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58
|
||||||
|
@ -163,8 +163,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
if (_com) {
|
if (_com) {
|
||||||
const uint64_t a = _com.timestamp().first;
|
const uint64_t a = _com.timestamp().first;
|
||||||
const std::pair<uint64_t,uint64_t> b(nconf.com.timestamp());
|
if ((_blacklistBefore)&&(a <= _blacklistBefore))
|
||||||
return ((a <= b.first) ? ((b.first - a) <= ZT_PEER_ACTIVITY_TIMEOUT) : true);
|
return false;
|
||||||
|
const uint64_t b = nconf.com.timestamp().first;
|
||||||
|
return ((a <= b) ? ((b - a) <= ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA) : true);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -253,6 +253,7 @@ void Multicaster::send(
|
|||||||
outp.append((uint32_t)gatherLimit);
|
outp.append((uint32_t)gatherLimit);
|
||||||
if (com)
|
if (com)
|
||||||
com->serialize(outp);
|
com->serialize(outp);
|
||||||
|
RR->node->expectReplyTo(outp.packetId());
|
||||||
RR->sw->send(outp,true);
|
RR->sw->send(outp,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1054,6 +1054,7 @@ void Network::requestConfiguration()
|
|||||||
} else {
|
} else {
|
||||||
outp.append((unsigned char)0,16);
|
outp.append((unsigned char)0,16);
|
||||||
}
|
}
|
||||||
|
RR->node->expectReplyTo(outp.packetId());
|
||||||
outp.compress();
|
outp.compress();
|
||||||
RR->sw->send(outp,true);
|
RR->sw->send(outp,true);
|
||||||
|
|
||||||
@ -1092,6 +1093,15 @@ bool Network::gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Network::recentlyAllowedOnNetwork(const SharedPtr<Peer> &peer) const
|
||||||
|
{
|
||||||
|
Mutex::Lock _l(_lock);
|
||||||
|
const Membership *m = _memberships.get(peer->address());
|
||||||
|
if (m)
|
||||||
|
return m->recentlyAllowedOnNetwork(_config);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Network::clean()
|
void Network::clean()
|
||||||
{
|
{
|
||||||
const uint64_t now = RR->node->now();
|
const uint64_t now = RR->node->now();
|
||||||
|
@ -257,6 +257,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId);
|
bool gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param peer Peer to check
|
||||||
|
* @return True if peer has recently been a valid member of this network
|
||||||
|
*/
|
||||||
|
bool recentlyAllowedOnNetwork(const SharedPtr<Peer> &peer) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform cleanup and possibly save state
|
* Perform cleanup and possibly save state
|
||||||
*/
|
*/
|
||||||
|
@ -75,6 +75,9 @@ Node::Node(
|
|||||||
{
|
{
|
||||||
_online = false;
|
_online = false;
|
||||||
|
|
||||||
|
memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr));
|
||||||
|
memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo));
|
||||||
|
|
||||||
// Use Salsa20 alone as a high-quality non-crypto PRNG
|
// Use Salsa20 alone as a high-quality non-crypto PRNG
|
||||||
{
|
{
|
||||||
char foo[32];
|
char foo[32];
|
||||||
|
@ -44,6 +44,10 @@
|
|||||||
#define TRACE(f,...) {}
|
#define TRACE(f,...) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Bit mask for "expecting reply" hash
|
||||||
|
#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255
|
||||||
|
#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -250,6 +254,33 @@ public:
|
|||||||
void postCircuitTestReport(const ZT_CircuitTestReport *report);
|
void postCircuitTestReport(const ZT_CircuitTestReport *report);
|
||||||
void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
|
void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register that we are expecting a reply to a packet ID
|
||||||
|
*
|
||||||
|
* @param packetId Packet ID to expect reply to
|
||||||
|
*/
|
||||||
|
inline void expectReplyTo(const uint64_t packetId)
|
||||||
|
{
|
||||||
|
const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
|
||||||
|
_expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = packetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a given packet ID is something we are expecting a reply to
|
||||||
|
*
|
||||||
|
* @param packetId Packet ID to check
|
||||||
|
* @return True if we're expecting a reply
|
||||||
|
*/
|
||||||
|
inline bool expectingReplyTo(const uint64_t packetId) const
|
||||||
|
{
|
||||||
|
const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
|
||||||
|
for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) {
|
||||||
|
if (_expectingRepliesTo[bucket][i] == packetId)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline SharedPtr<Network> _network(uint64_t nwid) const
|
inline SharedPtr<Network> _network(uint64_t nwid) const
|
||||||
{
|
{
|
||||||
@ -266,6 +297,9 @@ private:
|
|||||||
|
|
||||||
void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P
|
void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P
|
||||||
|
|
||||||
|
uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1];
|
||||||
|
uint64_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1];
|
||||||
|
|
||||||
ZT_DataStoreGetFunction _dataStoreGetFunction;
|
ZT_DataStoreGetFunction _dataStoreGetFunction;
|
||||||
ZT_DataStorePutFunction _dataStorePutFunction;
|
ZT_DataStorePutFunction _dataStorePutFunction;
|
||||||
ZT_WirePacketSendFunction _wirePacketSendFunction;
|
ZT_WirePacketSendFunction _wirePacketSendFunction;
|
||||||
|
@ -91,6 +91,7 @@ void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toA
|
|||||||
//TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str());
|
//TRACE(">>MC %.16llx -> %s",(unsigned long long)this,toAddr.toString().c_str());
|
||||||
_packet.newInitializationVector();
|
_packet.newInitializationVector();
|
||||||
_packet.setDestination(toAddr2);
|
_packet.setDestination(toAddr2);
|
||||||
|
RR->node->expectReplyTo(_packet.packetId());
|
||||||
RR->sw->send(_packet,true);
|
RR->sw->send(_packet,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -965,7 +965,7 @@ public:
|
|||||||
* <[2] 16-bit reporter OS/platform or 0 if not specified>
|
* <[2] 16-bit reporter OS/platform or 0 if not specified>
|
||||||
* <[2] 16-bit reporter architecture or 0 if not specified>
|
* <[2] 16-bit reporter architecture or 0 if not specified>
|
||||||
* <[2] 16-bit error code (set to 0, currently unused)>
|
* <[2] 16-bit error code (set to 0, currently unused)>
|
||||||
* <[8] 64-bit report flags (set to 0, currently unused)>
|
* <[8] 64-bit report flags>
|
||||||
* <[8] 64-bit packet ID of received CIRCUIT_TEST packet>
|
* <[8] 64-bit packet ID of received CIRCUIT_TEST packet>
|
||||||
* <[5] upstream ZeroTier address from which CIRCUIT_TEST was received>
|
* <[5] upstream ZeroTier address from which CIRCUIT_TEST was received>
|
||||||
* <[1] 8-bit packet hop count of received CIRCUIT_TEST>
|
* <[1] 8-bit packet hop count of received CIRCUIT_TEST>
|
||||||
@ -980,6 +980,9 @@ public:
|
|||||||
* <[5] ZeroTier address of next hop>
|
* <[5] ZeroTier address of next hop>
|
||||||
* <[...] current best direct path address, if any, 0 if none>
|
* <[...] current best direct path address, if any, 0 if none>
|
||||||
*
|
*
|
||||||
|
* Report flags:
|
||||||
|
* 0x1 - Upstream peer in circuit test path allowed in path (e.g. network COM valid)
|
||||||
|
*
|
||||||
* Circuit test reports can be sent by hops in a circuit test to report
|
* Circuit test reports can be sent by hops in a circuit test to report
|
||||||
* back results. They should include information about the sender as well
|
* back results. They should include information about the sender as well
|
||||||
* as about the paths to which next hops are being sent.
|
* as about the paths to which next hops are being sent.
|
||||||
|
@ -266,6 +266,7 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u
|
|||||||
atAddress.serialize(outp);
|
atAddress.serialize(outp);
|
||||||
outp.append((uint64_t)RR->topology->worldId());
|
outp.append((uint64_t)RR->topology->worldId());
|
||||||
outp.append((uint64_t)RR->topology->worldTimestamp());
|
outp.append((uint64_t)RR->topology->worldTimestamp());
|
||||||
|
RR->node->expectReplyTo(outp.packetId());
|
||||||
outp.armor(_key,false); // HELLO is sent in the clear
|
outp.armor(_key,false); // HELLO is sent in the clear
|
||||||
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
|
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
|
||||||
}
|
}
|
||||||
@ -274,6 +275,7 @@ void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &at
|
|||||||
{
|
{
|
||||||
if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) {
|
if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) {
|
||||||
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
|
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
|
||||||
|
RR->node->expectReplyTo(outp.packetId());
|
||||||
outp.armor(_key,true);
|
outp.armor(_key,true);
|
||||||
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
|
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
|
||||||
} else {
|
} else {
|
||||||
|
@ -734,13 +734,12 @@ unsigned long Switch::doTimerTasks(uint64_t now)
|
|||||||
|
|
||||||
Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted)
|
Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted)
|
||||||
{
|
{
|
||||||
SharedPtr<Peer> root(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
|
SharedPtr<Peer> upstream(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
|
||||||
if (root) {
|
if (upstream) {
|
||||||
Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS);
|
Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS);
|
||||||
addr.appendTo(outp);
|
addr.appendTo(outp);
|
||||||
outp.armor(root->key(),true);
|
RR->node->expectReplyTo(outp.packetId());
|
||||||
if (root->sendDirect(outp.data(),outp.size(),RR->node->now(),true))
|
send(outp,true);
|
||||||
return root->address();
|
|
||||||
}
|
}
|
||||||
return Address();
|
return Address();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user