Check network ethernet type whitelist instead of hard-coded ethernet types.

This commit is contained in:
Adam Ierymenko 2013-08-28 16:01:27 -04:00
parent 8e1b897f0a
commit 55616388ea
5 changed files with 83 additions and 28 deletions

View File

@ -150,10 +150,8 @@ SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t
SharedPtr<Network> nw(new Network());
nw->_ready = false; // disable handling of Ethernet frames during construct
nw->_r = renv;
nw->_rlLimit.bytesPerSecond = ZT_MULTICAST_DEFAULT_BYTES_PER_SECOND;
nw->_rlLimit.maxBalance = ZT_MULTICAST_DEFAULT_RATE_MAX_BALANCE;
nw->_rlLimit.minBalance = ZT_MULTICAST_DEFAULT_RATE_MIN_BALANCE;
nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
memset(nw->_etWhitelist,0,sizeof(nw->_etWhitelist));
nw->_id = id;
nw->_lastConfigUpdate = 0;
nw->_destroyOnDelete = false;
@ -177,6 +175,11 @@ void Network::setConfiguration(const Network::Config &conf)
_tap->setIps(conf.staticAddresses());
_tap->setDisplayName((std::string("ZeroTier One [") + conf.name() + "]").c_str());
memset(_etWhitelist,0,sizeof(_etWhitelist));
std::set<unsigned int> wl(conf.etherTypes());
for(std::set<unsigned int>::const_iterator t(wl.begin());t!=wl.end();++t)
_etWhitelist[*t / 8] |= (unsigned char)(1 << (*t % 8));
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + toString() + ".conf");
if (!Utils::writeFile(confPath.c_str(),conf.toString())) {
LOG("error: unable to write network configuration file at: %s",confPath.c_str());

View File

@ -267,6 +267,24 @@ public:
return (get("isOpen","0") == "1");
}
/**
* @return Network ethertype whitelist
*/
inline std::set<unsigned int> etherTypes() const
{
char tmp[16384];
char *saveptr = (char *)0;
std::set<unsigned int> et;
if (!Utils::scopy(tmp,sizeof(tmp),get("etherTypes","").c_str()))
return et; // sanity check
for(char *f=Utils::stok(tmp,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
unsigned int t = Utils::stoui(f);
if (t)
et.insert(t);
}
return et;
}
/**
* @return All static addresses / netmasks, IPv4 or IPv6
*/
@ -445,22 +463,17 @@ public:
Status status() const;
/**
* Invoke multicast rate limiter gate for a given address
*
* @param addr Address to check
* @param bytes Bytes address wishes to send us / propagate
* @return True if allowed, false if overshot rate limit
* @param etherType Ethernet frame type
* @return True if network permits this type
*/
inline bool multicastRateGate(const Address &addr,unsigned int bytes)
inline bool permitsEtherType(unsigned int etherType) const
throw()
{
Mutex::Lock _l(_lock);
std::map<Address,RateLimiter>::iterator rl(_multicastRateLimiters.find(addr));
if (rl == _multicastRateLimiters.end()) {
RateLimiter &newrl = _multicastRateLimiters[addr];
newrl.init(ZT_MULTICAST_DEFAULT_RATE_PRELOAD);
return newrl.gate(_rlLimit,(double)bytes);
}
return rl->second.gate(_rlLimit,(double)bytes);
if (!etherType)
return false;
else if (etherType > 65535)
return false;
else return ((_etWhitelist[etherType / 8] & (unsigned char)(1 << (etherType % 8))) != 0);
}
private:
@ -469,9 +482,6 @@ private:
const RuntimeEnvironment *_r;
// Rate limits for this network
RateLimiter::Limit _rlLimit;
// Tap and tap multicast memberships
EthernetTap *_tap;
std::set<MulticastGroup> _multicastGroups;
@ -486,6 +496,9 @@ private:
Config _configuration;
Certificate _myCertificate;
// Ethertype whitelist bit field, set from config, for really fast lookup
unsigned char _etWhitelist[65536 / 8];
uint64_t _id;
volatile uint64_t _lastConfigUpdate;
volatile bool _destroyOnDelete;

View File

@ -418,10 +418,10 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer>
if (network) {
if (network->isAllowed(source())) {
unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
if ((etherType != ZT_ETHERTYPE_ARP)&&(etherType != ZT_ETHERTYPE_IPV4)&&(etherType != ZT_ETHERTYPE_IPV6)) {
TRACE("dropped FRAME from %s: unsupported ethertype",source().toString().c_str());
} else if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
if (network->permitsEtherType(etherType)) {
network->tap().put(source().toMAC(),network->tap().mac(),etherType,data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD);
} else if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
TRACE("dropped FRAME from %s: ethernet type %u not allowed on network %.16llx",source().toString().c_str(),etherType,(unsigned long long)network->id());
}
} else {
TRACE("dropped FRAME from %s(%s): not a member of closed network %llu",source().toString().c_str(),_remoteAddress.toString().c_str(),network->id());
@ -509,8 +509,8 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
return true;
}
if (++hops >= ZT_MULTICAST_PROPAGATION_DEPTH) {
TRACE("dropped MULTICAST_FRAME from original submitter %s, received from %s(%s): max depth reached",originalSubmitterAddress.toString().c_str(),source().toString().c_str(),_remoteAddress.toString().c_str());
if (!network->permitsEtherType(etherType)) {
LOG("dropped MULTICAST_FRAME from original submitter %s, received from %s(%s): ethernet type %s not allowed on network %.16llx",originalSubmitterAddress.toString().c_str(),source().toString().c_str(),_remoteAddress.toString().c_str(),Filter::etherTypeName(etherType),(unsigned long long)network->id());
return true;
}
@ -533,6 +533,11 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
_r->multicaster->addToDedupHistory(mccrc,now);
}
if (++hops >= ZT_MULTICAST_PROPAGATION_DEPTH) {
TRACE("not propagating MULTICAST_FRAME from original submitter %s, received from %s(%s): max depth reached",originalSubmitterAddress.toString().c_str(),source().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
Address upstream(source()); // save this since we might mangle it below
Multicaster::MulticastBloomFilter bloom(field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_BLOOM_FILTER,ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES));
SharedPtr<Peer> propPeers[ZT_MULTICAST_PROPAGATION_BREADTH];

View File

@ -85,13 +85,14 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
LOG("ignored tap: %s -> %s %s (bridging is not (yet?) supported)",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType));
return;
}
if (to == network->tap().mac()) {
LOG("%s: frame received from self, ignoring (bridge loop?)",network->tap().deviceName().c_str());
LOG("%s: frame received from self, ignoring (bridge loop? OS bug?)",network->tap().deviceName().c_str());
return;
}
if ((etherType != ZT_ETHERTYPE_ARP)&&(etherType != ZT_ETHERTYPE_IPV4)&&(etherType != ZT_ETHERTYPE_IPV6)) {
LOG("ignored tap: %s -> %s %s (not a supported etherType)",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType));
if (!network->permitsEtherType(etherType)) {
LOG("ignored tap: %s -> %s: ethernet type %s not allowed on network %.16llx",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType),(unsigned long long)network->id());
return;
}

View File

@ -31,6 +31,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <string>
@ -460,6 +461,38 @@ public:
#endif
}
// String to int converters (and hex string to int)
static inline unsigned int stoui(const char *s)
throw()
{
return (unsigned int)strtoul(s,(char **)0,10);
}
static inline unsigned long stoul(const char *s)
throw()
{
return strtoul(s,(char **)0,10);
}
static inline unsigned long long stoull(const char *s)
throw()
{
return strtoull(s,(char **)0,10);
}
static inline unsigned int hstoui(const char *s)
throw()
{
return (unsigned int)strtoul(s,(char **)0,16);
}
static inline unsigned long hstoul(const char *s)
throw()
{
return strtoul(s,(char **)0,16);
}
static inline unsigned long long hstoull(const char *s)
throw()
{
return strtoull(s,(char **)0,16);
}
/**
* Perform a safe C string copy
*