summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-08-28 15:09:49 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-08-28 15:09:49 -0400
commit3745377872fe89cc06fb08de9b998c64c31e765c (patch)
treeca024d1577b5ee43ac630a88157045a4257230cd /node
parent01a70d09db917ce475120854514ee48af43cc1b1 (diff)
downloadinfinitytier-3745377872fe89cc06fb08de9b998c64c31e765c.tar.gz
infinitytier-3745377872fe89cc06fb08de9b998c64c31e765c.zip
Filter work, add name and desc to netconf response, small compiler warning fix.
Diffstat (limited to 'node')
-rw-r--r--node/Filter.cpp144
-rw-r--r--node/Filter.hpp137
-rw-r--r--node/RuntimeEnvironment.hpp2
-rw-r--r--node/Utils.hpp40
4 files changed, 166 insertions, 157 deletions
diff --git a/node/Filter.cpp b/node/Filter.cpp
index a0412173..d41589d6 100644
--- a/node/Filter.cpp
+++ b/node/Filter.cpp
@@ -30,6 +30,8 @@
#include <string.h>
#include <stdint.h>
+#include <algorithm>
+
#include "RuntimeEnvironment.hpp"
#include "Logger.hpp"
#include "Filter.hpp"
@@ -40,6 +42,61 @@ namespace ZeroTier {
const char *const Filter::UNKNOWN_NAME = "(unknown)";
const Range<unsigned int> Filter::ANY;
+static inline Range<unsigned int> __parseRange(char *r)
+ throw(std::invalid_argument)
+{
+ char *saveptr = (char *)0;
+ unsigned int a = 0;
+ unsigned int b = 0;
+ unsigned int fn = 0;
+ for(char *f=Utils::stok(r,"-",&saveptr);(f);f=Utils::stok((char *)0,"-",&saveptr)) {
+ if (*f) {
+ switch(fn++) {
+ case 0:
+ if (*f != '*')
+ a = b = (unsigned int)strtoul(f,(char **)0,10);
+ break;
+ case 1:
+ if (*f != '*')
+ b = (unsigned int)strtoul(f,(char **)0,10);
+ break;
+ default:
+ throw std::invalid_argument("rule range must be <int>, <int>-<int>, or *");
+ }
+ }
+ }
+ return Range<unsigned int>(a,b);
+}
+
+Filter::Rule::Rule(const char *s)
+ throw(std::invalid_argument)
+{
+ char *saveptr = (char *)0;
+ char tmp[256];
+ if (!Utils::scopy(tmp,sizeof(tmp),s))
+ throw std::invalid_argument("rule string too long");
+ unsigned int fn = 0;
+ for(char *f=Utils::stok(tmp,";",&saveptr);(f);f=Utils::stok((char *)0,";",&saveptr)) {
+ if (*f) {
+ switch(fn++) {
+ case 0:
+ _etherType = __parseRange(f);
+ break;
+ case 1:
+ _protocol = __parseRange(f);
+ break;
+ case 2:
+ _port = __parseRange(f);
+ break;
+ default:
+ throw std::invalid_argument("rule string has unknown extra fields");
+ }
+ }
+ }
+ if (fn != 3)
+ throw std::invalid_argument("rule string must contain 3 fields");
+}
+
bool Filter::Rule::operator()(unsigned int etype,const void *data,unsigned int len) const
throw(std::invalid_argument)
{
@@ -166,7 +223,7 @@ std::string Filter::Rule::toString() const
s.append(buf);
break;
}
- s.push_back('/');
+ s.push_back(';');
switch(_protocol.magnitude()) {
case 0:
s.push_back('*');
@@ -180,7 +237,7 @@ std::string Filter::Rule::toString() const
s.append(buf);
break;
}
- s.push_back('/');
+ s.push_back(';');
switch(_port.magnitude()) {
case 0:
s.push_back('*');
@@ -198,37 +255,50 @@ std::string Filter::Rule::toString() const
return s;
}
-void Filter::add(const Rule &r,const Action &a)
+Filter::Filter(const char *s)
+ throw(std::invalid_argument)
{
- Mutex::Lock _l(_chain_m);
- for(std::vector<Entry>::iterator i(_chain.begin());i!=_chain.end();++i) {
- if (i->rule == r) {
- _chain.erase(i);
- break;
+ char tmp[16384];
+ if (!Utils::scopy(tmp,sizeof(tmp),s))
+ throw std::invalid_argument("filter string too long");
+ char *saveptr = (char *)0;
+ unsigned int fn = 0;
+ for(char *f=Utils::stok(tmp,"-",&saveptr);(f);f=Utils::stok((char *)0,"-",&saveptr)) {
+ try {
+ _rules.push_back(Rule(f));
+ ++fn;
+ } catch (std::invalid_argument &exc) {
+ char tmp[256];
+ sprintf(tmp,"invalid rule at index %u: %s",fn,exc.what());
+ throw std::invalid_argument(tmp);
}
}
- _chain.push_back(Entry(r,a));
+ std::sort(_rules.begin(),_rules.end());
}
-std::string Filter::toString(const char *sep) const
+std::string Filter::toString() const
{
- if (!sep)
- sep = ",";
-
std::string s;
- bool first = true;
- Mutex::Lock _l(_chain_m);
- for(std::vector<Entry>::const_iterator i(_chain.begin());i!=_chain.end();++i) {
- s.append(i->rule.toString());
- if (first)
- first = false;
- else s.append(sep);
+ for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
+ if (s.length() > 0)
+ s.push_back(',');
+ s.append(r->toString());
}
return s;
}
+void Filter::add(const Rule &r)
+{
+ for(std::vector<Rule>::iterator rr(_rules.begin());rr!=_rules.end();++rr) {
+ if (r == *rr)
+ return;
+ }
+ _rules.push_back(r);
+ std::sort(_rules.begin(),_rules.end());
+}
+
const char *Filter::etherTypeName(const unsigned int etherType)
throw()
{
@@ -335,38 +405,4 @@ const char *Filter::icmp6TypeName(const unsigned int icmp6Type)
return UNKNOWN_NAME;
}
-Filter::Action Filter::operator()(const RuntimeEnvironment *_r,unsigned int etherType,const void *frame,unsigned int len) const
-{
- Mutex::Lock _l(_chain_m);
-
- TRACE("starting match against %d rules",(int)_chain.size());
-
- int ruleNo = 0;
- for(std::vector<Entry>::const_iterator r(_chain.begin());r!=_chain.end();++r,++ruleNo) {
- try {
- if (r->rule(etherType,frame,len)) {
- TRACE("match: %s",r->rule.toString().c_str());
-
- switch(r->action) {
- case ACTION_ALLOW:
- case ACTION_DENY:
- return r->action;
- default:
- break;
- }
- } else {
- TRACE("no match: %s",r->rule.toString().c_str());
- }
- } catch (std::invalid_argument &exc) {
- LOG("filter: unable to parse packet on rule %s (%d): %s",r->rule.toString().c_str(),ruleNo,exc.what());
- return ACTION_UNPARSEABLE;
- } catch ( ... ) {
- LOG("filter: unable to parse packet on rule %s (%d): unknown exception",r->rule.toString().c_str(),ruleNo);
- return ACTION_UNPARSEABLE;
- }
- }
-
- return ACTION_ALLOW;
-}
-
} // namespace ZeroTier
diff --git a/node/Filter.hpp b/node/Filter.hpp
index ac493b28..517b81c6 100644
--- a/node/Filter.hpp
+++ b/node/Filter.hpp
@@ -29,13 +29,14 @@
#define _ZT_FILTER_HPP
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+
#include <string>
#include <vector>
#include <utility>
#include <stdexcept>
-#include "Mutex.hpp"
#include "Range.hpp"
/* Ethernet frame types that might be relevant to us */
@@ -125,7 +126,11 @@ namespace ZeroTier {
class RuntimeEnvironment;
/**
- * A simple Ethernet frame level filter supporting basic IP port DENY
+ * A simple Ethernet frame level filter
+ *
+ * This doesn't specify actions, since it's used as a deny filter. The rule
+ * in ZT1 is "that which is not explicitly prohibited is allowed." (Except for
+ * ethertypes, which are handled by a whitelist.)
*/
class Filter
{
@@ -145,8 +150,6 @@ public:
/**
* A filter rule
- *
- * This behaves as an immutable value object.
*/
class Rule
{
@@ -160,6 +163,15 @@ public:
}
/**
+ * Construct a rule from a string-serialized value
+ *
+ * @param s String formatted rule, such as returned by toString()
+ * @throws std::invalid_argument String formatted rule is not valid
+ */
+ Rule(const char *s)
+ throw(std::invalid_argument);
+
+ /**
* Construct a new rule
*
* @param etype Ethernet type or empty range for ANY
@@ -191,6 +203,8 @@ public:
throw(std::invalid_argument);
/**
+ * Serialize rule as string
+ *
* @return Human readable representation of rule
*/
std::string toString() const;
@@ -222,105 +236,36 @@ public:
Range<unsigned int> _port;
};
- /**
- * Action if a rule matches
- */
- enum Action
- {
- ACTION_DENY = 0,
- ACTION_ALLOW = 1,
- ACTION_UNPARSEABLE = 2
- };
+ Filter() {}
/**
- * Entry in filter chain
+ * @param s String-serialized filter representation
*/
- struct Entry
- {
- Entry() {}
- Entry(const Rule &r,const Action &a) :
- rule(r),
- action(a)
- {
- }
-
- Rule rule;
- Action action;
- };
-
- Filter() :
- _chain(),
- _chain_m()
- {
- }
-
- Filter(const Filter &f) :
- _chain(),
- _chain_m()
- {
- Mutex::Lock _l(f._chain_m);
- _chain = f._chain;
- }
-
- inline Filter &operator=(const Filter &f)
- {
- Mutex::Lock _l1(_chain_m);
- Mutex::Lock _l2(f._chain_m);
- _chain = f._chain;
- return *this;
- }
+ Filter(const char *s)
+ throw(std::invalid_argument);
/**
- * Remove all filter entries
+ * @return Comma-delimited list of string-format rules
*/
- inline void clear()
- {
- Mutex::Lock _l(_chain_m);
- _chain.clear();
- }
+ std::string toString() const;
/**
- * Append a rule/action pair to this chain
- *
- * If an identical rule already exists it is removed and a new entry is
- * added to the end with the new action. (Two identical rules with the
- * same action wouldn't make sense.)
+ * Add a rule to this filter
*
- * @param r Rule to add
- * @param a Action if rule matches
+ * @param r Rule to add to filter
*/
- void add(const Rule &r,const Action &a);
+ void add(const Rule &r);
- /**
- * @return Number of rules in filter chain
- */
- inline unsigned int length() const
- throw()
+ inline bool operator()(unsigned int etype,const void *data,unsigned int len) const
+ throw(std::invalid_argument)
{
- Mutex::Lock _l(_chain_m);
- return (unsigned int)_chain.size();
- }
-
- /**
- * @return Entry in filter chain or null entry if out of bounds
- */
- inline Entry operator[](const unsigned int i) const
- throw()
- {
- Mutex::Lock _l(_chain_m);
- if (i < _chain.size())
- return _chain[i];
- return Entry();
+ for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
+ if ((*r)(etype,data,len))
+ return true;
+ }
+ return false;
}
- /**
- * Get a string representation of this filter
- *
- * @param sep Separator between filter rules, or NULL for comma (default)
- * @return Human-readable string
- */
- std::string toString(const char *sep = (const char *)0) const;
-
static const char *etherTypeName(const unsigned int etherType)
throw();
static const char *ipProtocolName(const unsigned int ipp)
@@ -330,20 +275,8 @@ public:
static const char *icmp6TypeName(const unsigned int icmp6Type)
throw();
- /**
- * Match against an Ethernet frame
- *
- * @param _r Runtime environment
- * @param etherType Ethernet frame type
- * @param frame Ethernet frame data
- * @param len Length of frame in bytes
- * @return Action if matched or ACTION_ALLOW if not matched
- */
- Action operator()(const RuntimeEnvironment *_r,unsigned int etherType,const void *frame,unsigned int len) const;
-
private:
- std::vector<Entry> _chain;
- Mutex _chain_m;
+ std::vector<Rule> _rules;
};
} // namespace ZeroTier
diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp
index c15551d0..4be4f367 100644
--- a/node/RuntimeEnvironment.hpp
+++ b/node/RuntimeEnvironment.hpp
@@ -64,9 +64,9 @@ public:
shutdownInProgress(false),
log((Logger *)0),
prng((CMWC4096 *)0),
- demarc((Demarc *)0),
multicaster((Multicaster *)0),
sw((Switch *)0),
+ demarc((Demarc *)0),
topology((Topology *)0),
sysEnv((SysEnv *)0),
nc((NodeConfig *)0)
diff --git a/node/Utils.hpp b/node/Utils.hpp
index 1a3adec6..79a2b04f 100644
--- a/node/Utils.hpp
+++ b/node/Utils.hpp
@@ -444,6 +444,46 @@ public:
static std::vector<std::string> split(const char *s,const char *const sep,const char *esc,const char *quot);
/**
+ * Tokenize a string
+ *
+ * @param str String to split
+ * @param delim Delimiters
+ * @param saveptr Pointer to a char * for temporary reentrant storage
+ */
+ static inline char *stok(char *str,const char *delim,char **saveptr)
+ throw()
+ {
+#ifdef __WINDOWS__
+ return strtok_s(str,delim,saveptr);
+#else
+ return strtok_r(str,delim,saveptr);
+#endif
+ }
+
+ /**
+ * Perform a safe C string copy
+ *
+ * @param dest Destination buffer
+ * @param len Length of buffer
+ * @param src Source string
+ * @return True on success, false on overflow (buffer will still be 0-terminated)
+ */
+ static inline bool scopy(char *dest,unsigned int len,const char *src)
+ throw()
+ {
+ if (!len)
+ return false; // sanity check
+ char *end = dest + len;
+ while ((*dest++ = *src++)) {
+ if (dest == end) {
+ dest[len - 1] = (char)0;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* Trim whitespace from the start and end of a string
*
* @param s String to trim