diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-08-28 15:09:49 -0400 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-08-28 15:09:49 -0400 |
commit | 3745377872fe89cc06fb08de9b998c64c31e765c (patch) | |
tree | ca024d1577b5ee43ac630a88157045a4257230cd /node | |
parent | 01a70d09db917ce475120854514ee48af43cc1b1 (diff) | |
download | infinitytier-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.cpp | 144 | ||||
-rw-r--r-- | node/Filter.hpp | 137 | ||||
-rw-r--r-- | node/RuntimeEnvironment.hpp | 2 | ||||
-rw-r--r-- | node/Utils.hpp | 40 |
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 |