summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/Network.hpp30
-rw-r--r--node/Packet.hpp10
-rw-r--r--node/PacketDecoder.cpp106
-rw-r--r--node/PacketDecoder.hpp2
-rw-r--r--node/Peer.cpp2
5 files changed, 100 insertions, 50 deletions
diff --git a/node/Network.hpp b/node/Network.hpp
index b40afd45..0a89c848 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -372,21 +372,6 @@ public:
}
/**
- * Inject a frame into tap with local MAC as destination MAC (if it's created)
- *
- * @param from Origin MAC
- * @param etherType Ethernet frame type
- * @param data Frame data
- * @param len Frame length
- */
- inline void tapPut(const MAC &from,unsigned int etherType,const void *data,unsigned int len)
- {
- EthernetTap *t = _tap;
- if (t)
- t->put(from,t->mac(),etherType,data,len);
- }
-
- /**
* @return Tap device name or empty string if still initializing
*/
inline std::string tapDeviceName() const
@@ -401,6 +386,7 @@ public:
* @return Ethernet MAC address for this network's local interface
*/
inline const MAC &mac() const
+ throw()
{
return _mac;
}
@@ -417,6 +403,20 @@ public:
}
/**
+ * Shortcut for config()->permitsBridging(), returns false if no config
+ *
+ * @param peer Peer address to check
+ * @return True if peer can bridge other Ethernet nodes into this network or network is in permissive bridging mode
+ */
+ inline bool permitsBridging(const Address &peer) const
+ {
+ Mutex::Lock _l(_lock);
+ if (_config)
+ return _config->permitsBridging(peer);
+ return false;
+ }
+
+ /**
* @param mac MAC address
* @return ZeroTier address of bridge to this MAC or null address if not found
*/
diff --git a/node/Packet.hpp b/node/Packet.hpp
index e2de9f57..833e95f1 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -176,6 +176,16 @@
#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2)
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID 8
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2)
+
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_DEPTH 2
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_FIFO (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_PROPAGATION_DEPTH + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_DEPTH)
diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp
index 6091196e..c94caa3e 100644
--- a/node/PacketDecoder.cpp
+++ b/node/PacketDecoder.cpp
@@ -405,47 +405,44 @@ bool PacketDecoder::_doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr<P
return true;
}
+bool PacketDecoder::_incomingFrame(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
+{
+ if (network->isAllowed(peer->address())) {
+ if (network->config()->permitsEtherType(etherType)) {
+ network->tapPut(from,to,etherType,data,len);
+
+ /* Source moves "closer" to us in multicast propagation priority when
+ * we receive unicast frames from it. This is called "implicit social
+ * ordering" in other docs. */
+ _r->mc->bringCloser(network->id(),peer->address());
+ peer->receive(_r,_fromSock,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP,Utils::now());
+ } else {
+ TRACE("dropped %s from %s@%s: ethernet type %u not allowed on network %.16llx",Packet::verbString(verb()),from.toString().c_str(),peer->address().toString().c_str(),etherType,(unsigned long long)network->id());
+ }
+ } else {
+ TRACE("dropped %s from %s(%s): peer not a member of closed network %.16llx",Packet::verbString(verb()),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),network->id());
+
+ Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)verb());
+ outp.append(packetId());
+ outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
+ outp.append(network->id());
+ outp.armor(peer->key(),true);
+ _fromSock->send(_remoteAddress,outp.data(),outp.size());
+ }
+ return true;
+}
+
bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
{
try {
SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)));
if (network) {
- if (network->isAllowed(source())) {
- unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
- if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
- if (network->config()->permitsEtherType(etherType)) {
- network->tapPut(
- MAC(source(),network->id()),
- etherType,
- data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,
- size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD);
- } else {
- TRACE("dropped FRAME from %s: ethernet type %u not allowed on network %.16llx",source().toString().c_str(),etherType,(unsigned long long)network->id());
- return true;
- }
- } else return true; // ignore empty frames
-
- // Source moves "closer" to us in multicast propagation priority when
- // we receive unicast frames from it. This is called "implicit social
- // ordering" in other docs.
- _r->mc->bringCloser(network->id(),source());
- peer->receive(_r,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,Utils::now());
- } else {
- TRACE("dropped FRAME from %s(%s): sender not a member of closed network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),network->id());
-
- Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
- outp.append((unsigned char)Packet::VERB_FRAME);
- outp.append(packetId());
- outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
- outp.append(network->id());
- outp.armor(peer->key(),true);
- _fromSock->send(_remoteAddress,outp.data(),outp.size());
-
- return true;
- }
+ unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
+ if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD)
+ _incomingFrame(_r,peer,network,MAC(peer->address(),network->id()),network->mac(),etherType,data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD);
} else {
TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
- return true;
}
} catch (std::exception &ex) {
TRACE("dropped FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
@@ -457,6 +454,47 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer>
bool PacketDecoder::_doEXT_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
{
+ try {
+ SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID)));
+ if (network) {
+ const MAC to(field(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(ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM);
+ unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE);
+ if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
+ if ((!from)||(from.isMulticast())||(!to)) {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source or destination MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
+ return true;
+ }
+
+ if (from != MAC(peer->address(),network->id())) {
+ if (network->permitsBridging(peer->address())) {
+ network->learnBridgeRoute(from,peer->address());
+ } else {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id());
+ return true;
+ }
+ }
+
+ if (to != network->mac()) {
+ /* For security reasons we should block incoming bridge packets if
+ * we are not a bridge. Bridging is a two way street, and unwanted
+ * bridging might open doors to strange things on untrusted nets. */
+ if (!network->permitsBridging(_r->identity.address())) {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id());
+ return true;
+ }
+ }
+
+ _incomingFrame(_r,peer,network,from,to,etherType,data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD);
+ } else return true; // ignore empty frames
+ } else {
+ TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
+ }
+ } catch (std::exception &ex) {
+ TRACE("dropped EXT_FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
+ } catch ( ... ) {
+ TRACE("dropped EXT_FRAME from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
return true;
}
diff --git a/node/PacketDecoder.hpp b/node/PacketDecoder.hpp
index 0a16ceb3..3723fdda 100644
--- a/node/PacketDecoder.hpp
+++ b/node/PacketDecoder.hpp
@@ -58,6 +58,7 @@
namespace ZeroTier {
class RuntimeEnvironment;
+class Network;
/**
* Subclass of packet that handles the decoding of it
@@ -116,6 +117,7 @@ private:
bool _doOK(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
+ bool _incomingFrame(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer,const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
bool _doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doEXT_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
diff --git a/node/Peer.cpp b/node/Peer.cpp
index c0cdaf17..54e30a74 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -112,7 +112,7 @@ void Peer::receive(
}
}
- if (verb == Packet::VERB_FRAME)
+ if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME))
_lastUnicastFrame = now;
else if (verb == Packet::VERB_MULTICAST_FRAME)
_lastMulticastFrame = now;