Filter work, add name and desc to netconf response, small compiler warning fix.

This commit is contained in:
Adam Ierymenko 2013-08-28 15:09:49 -04:00
parent 01a70d09db
commit 3745377872
5 changed files with 199 additions and 193 deletions

View file

@ -81,29 +81,6 @@ static Mutex stdoutWriteLock;
static Connection *dbCon = (Connection *)0; static Connection *dbCon = (Connection *)0;
static char mysqlHost[64],mysqlPort[64],mysqlDatabase[64],mysqlUser[64],mysqlPassword[64]; static char mysqlHost[64],mysqlPort[64],mysqlDatabase[64],mysqlUser[64],mysqlPassword[64];
static void connectOrReconnect()
{
for(;;) {
delete dbCon;
try {
dbCon = new Connection(mysqlDatabase,mysqlHost,mysqlUser,mysqlPassword,(unsigned int)strtol(mysqlPort,(char **)0,10));
if (dbCon->connected()) {
fprintf(stderr,"(re?)-connected to mysql server successfully\n");
break;
} else {
fprintf(stderr,"unable to connect to database server (connection closed), trying again in 1s...\n");
usleep(1000000);
}
} catch (std::exception &exc) {
fprintf(stderr,"unable to connect to database server (%s), trying again in 1s...\n",exc.what());
usleep(1000000);
} catch ( ... ) {
fprintf(stderr,"unable to connect to database server (unknown exception), trying again in 1s...\n");
usleep(1000000);
}
}
}
int main(int argc,char **argv) int main(int argc,char **argv)
{ {
{ {
@ -140,7 +117,20 @@ int main(int argc,char **argv)
char buf[131072]; char buf[131072];
std::string dictBuf; std::string dictBuf;
connectOrReconnect(); try {
dbCon = new Connection(mysqlDatabase,mysqlHost,mysqlUser,mysqlPassword,(unsigned int)strtol(mysqlPort,(char **)0,10));
if (dbCon->connected()) {
fprintf(stderr,"connected to mysql server successfully\n");
break;
} else {
fprintf(stderr,"unable to connect to database server\n");
return -1;
}
} catch (std::exception &exc) {
fprintf(stderr,"unable to connect to database server: %s\n",exc.what());
return -1;
}
for(;;) { for(;;) {
for(int l=0;l<4;) { for(int l=0;l<4;) {
int n = (int)read(STDIN_FILENO,buf + l,4 - l); int n = (int)read(STDIN_FILENO,buf + l,4 - l);
@ -164,8 +154,10 @@ int main(int argc,char **argv)
Dictionary request(dictBuf); Dictionary request(dictBuf);
dictBuf = ""; dictBuf = "";
if (!dbCon->connected()) if (!dbCon->connected()) {
connectOrReconnect(); fprintf(stderr,"connection to database server lost\n");
return -1;
}
try { try {
const std::string &reqType = request.get("type"); const std::string &reqType = request.get("type");
@ -213,13 +205,16 @@ int main(int argc,char **argv)
} }
bool isOpen = false; bool isOpen = false;
std::string name,desc;
{ {
Query q = dbCon->query(); Query q = dbCon->query();
q << "SELECT isOpen FROM Network WHERE id = " << nwid; q << "SELECT name,desc,isOpen FROM Network WHERE id = " << nwid;
StoreQueryResult rs = q.store(); StoreQueryResult rs = q.store();
if (rs.num_rows() > 0) if (rs.num_rows() > 0) {
name = rs[0]["name"].c_str();
desc = rs[0]["desc"].c_str();
isOpen = ((int)rs[0]["isOpen"] > 0); isOpen = ((int)rs[0]["isOpen"] > 0);
else { } else {
Dictionary response; Dictionary response;
response["peer"] = peerIdentity.address().toString(); response["peer"] = peerIdentity.address().toString();
response["nwid"] = request.get("nwid"); response["nwid"] = request.get("nwid");
@ -243,6 +238,8 @@ int main(int argc,char **argv)
sprintf(buf,"%.16llx",(unsigned long long)nwid); sprintf(buf,"%.16llx",(unsigned long long)nwid);
netconf["nwid"] = buf; netconf["nwid"] = buf;
netconf["isOpen"] = (isOpen ? "1" : "0"); netconf["isOpen"] = (isOpen ? "1" : "0");
netconf["name"] = name;
netconf["desc"] = desc;
sprintf(buf,"%llx",(unsigned long long)Utils::now()); sprintf(buf,"%llx",(unsigned long long)Utils::now());
netconf["ts"] = buf; netconf["ts"] = buf;

View file

@ -30,6 +30,8 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <algorithm>
#include "RuntimeEnvironment.hpp" #include "RuntimeEnvironment.hpp"
#include "Logger.hpp" #include "Logger.hpp"
#include "Filter.hpp" #include "Filter.hpp"
@ -40,6 +42,61 @@ namespace ZeroTier {
const char *const Filter::UNKNOWN_NAME = "(unknown)"; const char *const Filter::UNKNOWN_NAME = "(unknown)";
const Range<unsigned int> Filter::ANY; 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 bool Filter::Rule::operator()(unsigned int etype,const void *data,unsigned int len) const
throw(std::invalid_argument) throw(std::invalid_argument)
{ {
@ -166,7 +223,7 @@ std::string Filter::Rule::toString() const
s.append(buf); s.append(buf);
break; break;
} }
s.push_back('/'); s.push_back(';');
switch(_protocol.magnitude()) { switch(_protocol.magnitude()) {
case 0: case 0:
s.push_back('*'); s.push_back('*');
@ -180,7 +237,7 @@ std::string Filter::Rule::toString() const
s.append(buf); s.append(buf);
break; break;
} }
s.push_back('/'); s.push_back(';');
switch(_port.magnitude()) { switch(_port.magnitude()) {
case 0: case 0:
s.push_back('*'); s.push_back('*');
@ -198,37 +255,50 @@ std::string Filter::Rule::toString() const
return s; 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); char tmp[16384];
for(std::vector<Entry>::iterator i(_chain.begin());i!=_chain.end();++i) { if (!Utils::scopy(tmp,sizeof(tmp),s))
if (i->rule == r) { throw std::invalid_argument("filter string too long");
_chain.erase(i); char *saveptr = (char *)0;
break; 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; std::string s;
bool first = true; for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
Mutex::Lock _l(_chain_m); if (s.length() > 0)
for(std::vector<Entry>::const_iterator i(_chain.begin());i!=_chain.end();++i) { s.push_back(',');
s.append(i->rule.toString()); s.append(r->toString());
if (first)
first = false;
else s.append(sep);
} }
return s; 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) const char *Filter::etherTypeName(const unsigned int etherType)
throw() throw()
{ {
@ -335,38 +405,4 @@ const char *Filter::icmp6TypeName(const unsigned int icmp6Type)
return UNKNOWN_NAME; 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 } // namespace ZeroTier

View file

@ -29,13 +29,14 @@
#define _ZT_FILTER_HPP #define _ZT_FILTER_HPP
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <utility> #include <utility>
#include <stdexcept> #include <stdexcept>
#include "Mutex.hpp"
#include "Range.hpp" #include "Range.hpp"
/* Ethernet frame types that might be relevant to us */ /* Ethernet frame types that might be relevant to us */
@ -125,7 +126,11 @@ namespace ZeroTier {
class RuntimeEnvironment; 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 class Filter
{ {
@ -145,8 +150,6 @@ public:
/** /**
* A filter rule * A filter rule
*
* This behaves as an immutable value object.
*/ */
class Rule class Rule
{ {
@ -159,6 +162,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 * Construct a new rule
* *
@ -191,6 +203,8 @@ public:
throw(std::invalid_argument); throw(std::invalid_argument);
/** /**
* Serialize rule as string
*
* @return Human readable representation of rule * @return Human readable representation of rule
*/ */
std::string toString() const; std::string toString() const;
@ -222,105 +236,36 @@ public:
Range<unsigned int> _port; Range<unsigned int> _port;
}; };
Filter() {}
/** /**
* Action if a rule matches * @param s String-serialized filter representation
*/ */
enum Action Filter(const char *s)
{ throw(std::invalid_argument);
ACTION_DENY = 0,
ACTION_ALLOW = 1,
ACTION_UNPARSEABLE = 2
};
/** /**
* Entry in filter chain * @return Comma-delimited list of string-format rules
*/ */
struct Entry std::string toString() const;
{
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;
}
/** /**
* Remove all filter entries * Add a rule to this filter
*/
inline void clear()
{
Mutex::Lock _l(_chain_m);
_chain.clear();
}
/**
* Append a rule/action pair to this chain
* *
* If an identical rule already exists it is removed and a new entry is * @param r Rule to add to filter
* added to the end with the new action. (Two identical rules with the
* same action wouldn't make sense.)
*
* @param r Rule to add
* @param a Action if rule matches
*/ */
void add(const Rule &r,const Action &a); void add(const Rule &r);
/** inline bool operator()(unsigned int etype,const void *data,unsigned int len) const
* @return Number of rules in filter chain throw(std::invalid_argument)
*/
inline unsigned int length() const
throw()
{ {
Mutex::Lock _l(_chain_m); for(std::vector<Rule>::const_iterator r(_rules.begin());r!=_rules.end();++r) {
return (unsigned int)_chain.size(); if ((*r)(etype,data,len))
return true;
} }
return false;
/**
* @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();
} }
/**
* 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) static const char *etherTypeName(const unsigned int etherType)
throw(); throw();
static const char *ipProtocolName(const unsigned int ipp) static const char *ipProtocolName(const unsigned int ipp)
@ -330,20 +275,8 @@ public:
static const char *icmp6TypeName(const unsigned int icmp6Type) static const char *icmp6TypeName(const unsigned int icmp6Type)
throw(); 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: private:
std::vector<Entry> _chain; std::vector<Rule> _rules;
Mutex _chain_m;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -64,9 +64,9 @@ public:
shutdownInProgress(false), shutdownInProgress(false),
log((Logger *)0), log((Logger *)0),
prng((CMWC4096 *)0), prng((CMWC4096 *)0),
demarc((Demarc *)0),
multicaster((Multicaster *)0), multicaster((Multicaster *)0),
sw((Switch *)0), sw((Switch *)0),
demarc((Demarc *)0),
topology((Topology *)0), topology((Topology *)0),
sysEnv((SysEnv *)0), sysEnv((SysEnv *)0),
nc((NodeConfig *)0) nc((NodeConfig *)0)

View file

@ -443,6 +443,46 @@ public:
*/ */
static std::vector<std::string> split(const char *s,const char *const sep,const char *esc,const char *quot); 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 * Trim whitespace from the start and end of a string
* *