|
@@ -47,6 +47,7 @@
|
|
|
#include "Dictionary.hpp"
|
|
|
#include "Identity.hpp"
|
|
|
#include "InetAddress.hpp"
|
|
|
+#include "BandwidthAccount.hpp"
|
|
|
|
|
|
namespace ZeroTier {
|
|
|
|
|
@@ -85,24 +86,10 @@ public:
|
|
|
class Certificate : private Dictionary
|
|
|
{
|
|
|
public:
|
|
|
- Certificate()
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- Certificate(const char *s) :
|
|
|
- Dictionary(s)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- Certificate(const std::string &s) :
|
|
|
- Dictionary(s)
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- inline std::string toString() const
|
|
|
- {
|
|
|
- return Dictionary::toString();
|
|
|
- }
|
|
|
+ Certificate() {}
|
|
|
+ Certificate(const char *s) : Dictionary(s) {}
|
|
|
+ Certificate(const std::string &s) : Dictionary(s) {}
|
|
|
+ inline std::string toString() const { return Dictionary::toString(); }
|
|
|
|
|
|
inline void setNetworkId(uint64_t id)
|
|
|
{
|
|
@@ -193,58 +180,159 @@ public:
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
- * A network configuration for a given node
|
|
|
+ * Preload and rates of accrual for multicast group bandwidth limits
|
|
|
+ *
|
|
|
+ * Key is multicast group in lower case hex format: MAC (without :s) /
|
|
|
+ * ADI (hex). Value is a comma-delimited list of: preload, min, max,
|
|
|
+ * rate of accrual for bandwidth accounts. A key called '*' indicates
|
|
|
+ * the default for unlisted groups.
|
|
|
*/
|
|
|
- class Config : private Dictionary
|
|
|
+ class MulticastRates : private Dictionary
|
|
|
{
|
|
|
public:
|
|
|
- Config()
|
|
|
+ /**
|
|
|
+ * Preload and accrual parameter tuple
|
|
|
+ */
|
|
|
+ struct Rate
|
|
|
{
|
|
|
- }
|
|
|
+ Rate() {}
|
|
|
+ Rate(double pl,double minr,double maxr,double bps)
|
|
|
+ {
|
|
|
+ preload = pl;
|
|
|
+ accrual.bytesPerSecond = bps;
|
|
|
+ accrual.maxBalance = maxr;
|
|
|
+ accrual.minBalance = minr;
|
|
|
+ }
|
|
|
|
|
|
- Config(const char *s) :
|
|
|
- Dictionary(s)
|
|
|
- {
|
|
|
- }
|
|
|
+ double preload;
|
|
|
+ BandwidthAccount::Accrual accrual;
|
|
|
+ };
|
|
|
+
|
|
|
+ MulticastRates() {}
|
|
|
+ MulticastRates(const char *s) : Dictionary(s) {}
|
|
|
+ MulticastRates(const std::string &s) : Dictionary(s) {}
|
|
|
+ inline std::string toString() const { return Dictionary::toString(); }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A very minimal default rate, fast enough for ARP
|
|
|
+ */
|
|
|
+ static const Rate GLOBAL_DEFAULT_RATE;
|
|
|
|
|
|
- Config(const std::string &s) :
|
|
|
- Dictionary(s)
|
|
|
+ /**
|
|
|
+ * @return Default rate, or GLOBAL_DEFAULT_RATE if not specified
|
|
|
+ */
|
|
|
+ Rate defaultRate() const
|
|
|
{
|
|
|
+ Rate r;
|
|
|
+ const_iterator dfl(find("*"));
|
|
|
+ if (dfl == end())
|
|
|
+ return GLOBAL_DEFAULT_RATE;
|
|
|
+ return _toRate(dfl->second);
|
|
|
}
|
|
|
|
|
|
- inline bool containsAllFields() const
|
|
|
+ /**
|
|
|
+ * Get the rate for a given multicast group
|
|
|
+ *
|
|
|
+ * @param mg Multicast group
|
|
|
+ * @return Rate or default() rate if not specified
|
|
|
+ */
|
|
|
+ Rate get(const MulticastGroup &mg) const
|
|
|
{
|
|
|
- return (contains("nwid")&&contains("peer"));
|
|
|
+ const_iterator r(find(mg.toString()));
|
|
|
+ if (r == end())
|
|
|
+ return defaultRate();
|
|
|
+ return _toRate(r->second);
|
|
|
}
|
|
|
|
|
|
- inline std::string toString() const
|
|
|
+ private:
|
|
|
+ static inline Rate _toRate(const std::string &s)
|
|
|
{
|
|
|
- return Dictionary::toString();
|
|
|
+ char tmp[16384];
|
|
|
+ Utils::scopy(tmp,sizeof(tmp),s.c_str());
|
|
|
+ Rate r;
|
|
|
+ r.preload = 0.0;
|
|
|
+ r.accrual.bytesPerSecond = 0.0;
|
|
|
+ r.accrual.maxBalance = 0.0;
|
|
|
+ r.accrual.minBalance = 0.0;
|
|
|
+ char *saveptr = (char *)0;
|
|
|
+ unsigned int fn = 0;
|
|
|
+ for(char *f=Utils::stok(tmp,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
|
|
|
+ switch(fn++) {
|
|
|
+ case 0:
|
|
|
+ r.preload = Utils::strToDouble(f);
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ r.accrual.minBalance = Utils::strToDouble(f);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ r.accrual.maxBalance = Utils::strToDouble(f);
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ r.accrual.bytesPerSecond = Utils::strToDouble(f);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return r;
|
|
|
}
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A network configuration for a given node
|
|
|
+ *
|
|
|
+ * Configuration fields:
|
|
|
+ *
|
|
|
+ * nwid=<hex network ID> (required)
|
|
|
+ * name=short name
|
|
|
+ * desc=long(er) description
|
|
|
+ * com=Certificate (serialized dictionary)
|
|
|
+ * mr=MulticastRates (serialized dictionary)
|
|
|
+ * o=open network? (1 or 0, default false if missing)
|
|
|
+ * et=ethertype whitelist (comma-delimited list of ethertypes in decimal)
|
|
|
+ * v4s=IPv4 static assignments / netmasks (comma-delimited)
|
|
|
+ * v6s=IPv6 static assignments / netmasks (comma-delimited)
|
|
|
+ */
|
|
|
+ class Config : private Dictionary
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ Config() {}
|
|
|
+ Config(const char *s) : Dictionary(s) {}
|
|
|
+ Config(const std::string &s) : Dictionary(s) {}
|
|
|
+ inline std::string toString() const { return Dictionary::toString(); }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @return True if configuration is valid and contains required fields
|
|
|
+ */
|
|
|
+ inline operator bool() const throw() { return (find("nwid") != end()); }
|
|
|
|
|
|
+ /**
|
|
|
+ * @return Network ID
|
|
|
+ * @throws std::invalid_argument Network ID field missing
|
|
|
+ */
|
|
|
inline uint64_t networkId() const
|
|
|
throw(std::invalid_argument)
|
|
|
{
|
|
|
-#ifdef __WINDOWS__
|
|
|
- return _strtoui64(get("nwid").c_str(),(char **)0,16);
|
|
|
-#else
|
|
|
- return strtoull(get("nwid").c_str(),(char **)0,16);
|
|
|
-#endif
|
|
|
+ return Utils::hexStrToU64(get("nwid").c_str());
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Get this network's short name, or its ID in hex if unspecified
|
|
|
+ *
|
|
|
+ * @return Short name of this network (e.g. "earth")
|
|
|
+ */
|
|
|
inline std::string name() const
|
|
|
{
|
|
|
- if (contains("name"))
|
|
|
- return get("name");
|
|
|
- char buf[32];
|
|
|
- Utils::snprintf(buf,sizeof(buf),"%.16llx",(unsigned long long)networkId());
|
|
|
- return std::string(buf);
|
|
|
+ const_iterator n(find("name"));
|
|
|
+ if (n == end())
|
|
|
+ return get("nwid");
|
|
|
+ return n->second;
|
|
|
}
|
|
|
|
|
|
- inline Address peerAddress() const
|
|
|
- throw(std::invalid_argument)
|
|
|
+ /**
|
|
|
+ * @return Long description of network or empty string if not present
|
|
|
+ */
|
|
|
+ inline std::string desc() const
|
|
|
{
|
|
|
- return Address(get("peer"));
|
|
|
+ return get("desc",std::string());
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -258,12 +346,28 @@ public:
|
|
|
else return Certificate(cm->second);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @return Multicast rates for this network
|
|
|
+ */
|
|
|
+ inline MulticastRates multicastRates() const
|
|
|
+ {
|
|
|
+ const_iterator mr(find("mr"));
|
|
|
+ if (mr == end())
|
|
|
+ return MulticastRates();
|
|
|
+ else return MulticastRates(mr->second);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* @return True if this is an open non-access-controlled network
|
|
|
*/
|
|
|
inline bool isOpen() const
|
|
|
{
|
|
|
- return (get("isOpen","0") == "1");
|
|
|
+ const_iterator o(find("o"));
|
|
|
+ if (o == end())
|
|
|
+ return false;
|
|
|
+ else if (!o->second.length())
|
|
|
+ return false;
|
|
|
+ else return (o->second[0] == '1');
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -274,10 +378,10 @@ public:
|
|
|
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
|
|
|
+ if (!Utils::scopy(tmp,sizeof(tmp),get("et","").c_str()))
|
|
|
+ return et; // sanity check, packet can't really be that big
|
|
|
for(char *f=Utils::stok(tmp,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) {
|
|
|
- unsigned int t = Utils::stoui(f);
|
|
|
+ unsigned int t = Utils::strToUInt(f);
|
|
|
if (t)
|
|
|
et.insert(t);
|
|
|
}
|
|
@@ -290,10 +394,10 @@ public:
|
|
|
inline std::set<InetAddress> staticAddresses() const
|
|
|
{
|
|
|
std::set<InetAddress> sa;
|
|
|
- std::vector<std::string> ips(Utils::split(get("ipv4Static","").c_str(),",","",""));
|
|
|
+ std::vector<std::string> ips(Utils::split(get("v4s","").c_str(),",","",""));
|
|
|
for(std::vector<std::string>::const_iterator i(ips.begin());i!=ips.end();++i)
|
|
|
sa.insert(InetAddress(*i));
|
|
|
- ips = Utils::split(get("ipv6Static","").c_str(),",","","");
|
|
|
+ ips = Utils::split(get("v6s","").c_str(),",","","");
|
|
|
for(std::vector<std::string>::const_iterator i(ips.begin());i!=ips.end();++i)
|
|
|
sa.insert(InetAddress(*i));
|
|
|
return sa;
|
|
@@ -462,6 +566,8 @@ public:
|
|
|
Status status() const;
|
|
|
|
|
|
/**
|
|
|
+ * Determine whether frames of a given ethernet type are allowed on this network
|
|
|
+ *
|
|
|
* @param etherType Ethernet frame type
|
|
|
* @return True if network permits this type
|
|
|
*/
|
|
@@ -475,17 +581,26 @@ public:
|
|
|
else return ((_etWhitelist[etherType / 8] & (unsigned char)(1 << (etherType % 8))) != 0);
|
|
|
}
|
|
|
|
|
|
+ inline bool updateAndCheckMulticastBalance(const Address &a,const MulticastGroup &mg,unsigned int bytes)
|
|
|
+ {
|
|
|
+ Mutex::Lock _l(_lock);
|
|
|
+ std::map< std::pair<Address,MulticastGroup>,BandwidthAccount >::iterator bal(_multicastRateAccounts.find(std::pair<Address,MulticastGroup>(a,mg)));
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
|
|
|
void _restoreState();
|
|
|
|
|
|
const RuntimeEnvironment *_r;
|
|
|
|
|
|
- // Tap and tap multicast memberships
|
|
|
+ // Multicast bandwidth accounting for peers on this network
|
|
|
+ std::map< std::pair<Address,MulticastGroup>,BandwidthAccount > _multicastRateAccounts;
|
|
|
+
|
|
|
+ // Tap and tap multicast memberships for this node on this network
|
|
|
EthernetTap *_tap;
|
|
|
std::set<MulticastGroup> _multicastGroups;
|
|
|
|
|
|
- // Membership certificates supplied by peers
|
|
|
+ // Membership certificates supplied by other peers on this network
|
|
|
std::map<Address,Certificate> _membershipCertificates;
|
|
|
|
|
|
// Configuration from network master node
|