Network membership certificate work in progress... does not build yet.

This commit is contained in:
Adam Ierymenko 2013-07-29 13:56:20 -04:00
parent e7b515c86c
commit a53cfc9096
12 changed files with 470 additions and 77 deletions

View file

@ -30,28 +30,37 @@
#include <string>
#include <set>
#include <map>
#include <vector>
#include <stdexcept>
#include "Constants.hpp"
#include "Utils.hpp"
#include "EthernetTap.hpp"
#include "Address.hpp"
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Constants.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
#include "RuntimeEnvironment.hpp"
#include "MulticastGroup.hpp"
#include "NonCopyable.hpp"
#include "MAC.hpp"
#include "Dictionary.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
namespace ZeroTier {
class RuntimeEnvironment;
class NodeConfig;
/**
* A virtual LAN
*
* Networks can be open or closed.
* Networks can be open or closed. Each network has an ID whose most
* significant 40 bits are the ZeroTier address of the node that should
* be contacted for network configuration. The least significant 24
* bits are arbitrary, allowing up to 2^24 networks per managing
* node.
*
* Open networks do not track membership. Anyone is allowed to communicate
* over them.
@ -69,7 +78,183 @@ class Network : NonCopyable
friend class SharedPtr<Network>;
friend class NodeConfig;
public:
/**
* A certificate of network membership
*/
class Certificate : private Dictionary
{
public:
Certificate()
{
}
Certificate(const char *s) :
Dictionary(s)
{
}
Certificate(const std::string &s) :
Dictionary(s)
{
}
/**
* @return Read-only underlying dictionary
*/
inline const Dictionary &dictionary() const { return *this; }
inline void setNetworkId(uint64_t id)
{
char buf[32];
sprintf(buf,"%llu",id);
(*this)["nwid"] = buf;
}
inline uint64_t networkId() const
throw(std::invalid_argument)
{
return strtoull(get("nwid").c_str(),(char **)0,10);
}
inline void setPeerAddress(Address &a)
{
(*this)["peer"] = a.toString();
}
inline Address peerAddress() const
throw(std::invalid_argument)
{
return Address(get("peer"));
}
/**
* Set the timestamp and max-delta
*
* @param ts Timestamp in ms since epoch
* @param maxDelta Maximum difference between two peers on the same network
*/
inline void setTimestamp(uint64_t ts,uint64_t maxDelta)
{
char foo[32];
sprintf(foo,"%llu",ts);
(*this)["ts"] = foo;
sprintf(foo,"%llu",maxDelta);
(*this)["~ts"] = foo;
}
/**
* Set or update the sig field to contain a signature
*
* @param with Signing identity -- the identity of this network's controller
*/
void sign(const Identity &with);
/**
* Check if another peer is indeed a current member of this network
*
* Fields with companion ~fields are compared with the defined maximum
* delta in this certificate. Fields without ~fields are compared for
* equality.
*
* This does not verify the certificate's signature! The signature
* must be verified first.
*
* @param mc Peer membership certificate
* @return True if mc's membership in this network is current
*/
bool qualifyMembership(const Certificate &mc) const;
};
/**
* A network configuration for a given node
*/
class Config : private Dictionary
{
public:
Config()
{
}
Config(const char *s) :
Dictionary(s)
{
}
Config(const std::string &s) :
Dictionary(s)
{
}
/**
* @return Certificate of membership for this network, or empty cert if none
*/
inline Certificate certificateOfMembership() const
{
return Certificate(get("com",""));
}
/**
* @return True if this is an open non-access-controlled network
*/
inline bool isOpen() const
{
return (get("isOpen","0") == "1");
}
/**
* @return All static addresses / netmasks, IPv4 or IPv6
*/
inline std::set<InetAddress> staticAddresses() const
{
std::set<InetAddress> sa;
std::vector<std::string> ips(Utils::split(get("ipv4Static","").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(),",","","");
for(std::vector<std::string>::const_iterator i(ips.begin());i!=ips.end();++i)
sa.insert(InetAddress(*i));
return sa;
}
/**
* Set static IPv4 and IPv6 addresses
*
* This sets the ipv4Static and ipv6Static fields to comma-delimited
* lists of assignments. The port field in InetAddress must be the
* number of bits in the netmask.
*
* @param begin Start of container or array of addresses (InetAddress)
* @param end End of container or array of addresses (InetAddress)
* @tparam I Type of container or array
*/
template<typename I>
inline void setStaticInetAddresses(const I &begin,const I &end)
{
std::string v4;
std::string v6;
for(I i(begin);i!=end;++i) {
if (i->isV4()) {
if (v4.length())
v4.push_back(',');
v4.append(i->toString());
} else if (i->isV6()) {
if (v6.length())
v6.push_back(',');
v6.append(i->toString());
}
}
if (v4.length())
(*this)["ipv4Static"] = v4;
else erase("ipv4Static");
if (v6.length())
(*this)["ipv6Static"] = v6;
else erase("ipv6Static");
}
};
private:
// Only NodeConfig can create, only SharedPtr can delete
Network(const RuntimeEnvironment *renv,uint64_t id)
throw(std::runtime_error);
@ -87,56 +272,22 @@ public:
inline EthernetTap &tap() throw() { return _tap; }
/**
* Get this network's members
*
* If this is an open network, membership isn't relevant and this doesn't
* mean much. If it's a closed network, frames will only be exchanged to/from
* members.
*
* @return Members of this network
* @return Address of network's controlling node
*/
inline std::set<Address> members() const
{
Mutex::Lock _l(_lock);
return _members;
}
/**
* @param addr Address to check
* @return True if address is a member
*/
inline bool isMember(const Address &addr) const
throw()
{
Mutex::Lock _l(_lock);
return (_members.count(addr) > 0);
}
/**
* Shortcut to check open() and then isMember()
*
* @param addr Address to check
* @return True if network is open or if address is a member
*/
inline bool isAllowed(const Address &addr) const
throw()
{
Mutex::Lock _l(_lock);
return ((_open)||(_members.count(addr) > 0));
}
inline Address controller() throw() { return Address(_id >> 24); }
/**
* @return True if network is open (no membership required)
*/
inline bool open() const
inline bool isOpen() const
throw()
{
Mutex::Lock _l(_lock);
return _open;
return _isOpen;
}
/**
* Update internal multicast group set and return true if changed
* Update multicast groups for this network's tap
*
* @return True if internal multicast group set has changed
*/
@ -147,7 +298,7 @@ public:
}
/**
* @return Latest set of multicast groups
* @return Latest set of multicast groups for this network's tap
*/
inline std::set<MulticastGroup> multicastGroups() const
{
@ -155,15 +306,32 @@ public:
return _multicastGroups;
}
/**
* Set or update this network's configuration
*
* This is called by PacketDecoder when an update comes over the wire, or
* internally when an old config is reloaded from disk.
*
* @param conf Configuration in key/value dictionary form
*/
void setConfiguration(const Config &conf);
/**
* Causes this network to request an updated configuration from its master node now
*/
void requestConfiguration();
private:
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
const RuntimeEnvironment *_r;
uint64_t _id;
EthernetTap _tap;
std::set<Address> _members;
std::set<MulticastGroup> _multicastGroups;
bool _open;
uint64_t _id;
bool _isOpen;
Mutex _lock;
AtomicCounter __refCount;