123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- /*
- * ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2013 ZeroTier Networks LLC
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
- #ifndef _ZT_NETWORK_HPP
- #define _ZT_NETWORK_HPP
- #include <stdint.h>
- #include <string>
- #include <set>
- #include <map>
- #include <vector>
- #include <algorithm>
- #include <stdexcept>
- #include "Constants.hpp"
- #include "Utils.hpp"
- #include "EthernetTap.hpp"
- #include "Address.hpp"
- #include "Mutex.hpp"
- #include "SharedPtr.hpp"
- #include "AtomicCounter.hpp"
- #include "MulticastGroup.hpp"
- #include "NonCopyable.hpp"
- #include "MAC.hpp"
- #include "Dictionary.hpp"
- #include "Identity.hpp"
- #include "InetAddress.hpp"
- #include "BandwidthAccount.hpp"
- #include "CertificateOfMembership.hpp"
- namespace ZeroTier {
- class RuntimeEnvironment;
- class NodeConfig;
- /**
- * A virtual LAN
- *
- * 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.
- *
- * Closed networks track membership by way of timestamped signatures. When
- * the network requests its configuration, one of the fields returned is
- * a signature for the identity of the peer on the network. This signature
- * includes a timestamp. When a peer communicates with other peers on a
- * closed network, it periodically (and pre-emptively) propagates this
- * signature to the peers with which it is communicating. Peers reject
- * packets with an error if no recent signature is on file.
- */
- class Network : NonCopyable
- {
- friend class SharedPtr<Network>;
- friend class NodeConfig;
- public:
- /**
- * 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 preload, maximum balance, and rate of accrual in
- * hex.
- */
- class MulticastRates : private Dictionary
- {
- public:
- /**
- * Preload and accrual parameter tuple
- */
- struct Rate
- {
- Rate() {}
- Rate(uint32_t pl,uint32_t maxb,uint32_t acc)
- {
- preload = pl;
- maxBalance = maxb;
- accrual = acc;
- }
- uint32_t preload;
- uint32_t maxBalance;
- uint32_t 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;
- /**
- * @return Default rate, or GLOBAL_DEFAULT_RATE if not specified
- */
- inline Rate defaultRate() const
- {
- Rate r;
- const_iterator dfl(find("*"));
- if (dfl == end())
- return GLOBAL_DEFAULT_RATE;
- return _toRate(dfl->second);
- }
- /**
- * Get the rate for a given multicast group
- *
- * @param mg Multicast group
- * @return Rate or default() rate if not specified
- */
- inline Rate get(const MulticastGroup &mg) const
- {
- const_iterator r(find(mg.toString()));
- if (r == end())
- return defaultRate();
- return _toRate(r->second);
- }
- private:
- static inline Rate _toRate(const std::string &s)
- {
- char tmp[16384];
- Utils::scopy(tmp,sizeof(tmp),s.c_str());
- Rate r(0,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 = (uint32_t)Utils::hexStrToULong(f);
- break;
- case 1:
- r.maxBalance = (uint32_t)Utils::hexStrToULong(f);
- break;
- case 2:
- r.accrual = (uint32_t)Utils::hexStrToULong(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=Serialized certificate of membership
- * mr=MulticastRates (serialized dictionary)
- * md=multicast propagation depth
- * mpb=multicast propagation prefix bits (2^mpb packets are sent by origin)
- * 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)
- *
- * Notes:
- *
- * If zero appears in the 'et' list, the sense is inverted. It becomes an
- * ethertype blacklist instead of a whitelist and anything not blacklisted
- * is permitted.
- */
- 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)
- {
- 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
- {
- const_iterator n(find("name"));
- if (n == end())
- return get("nwid");
- return n->second;
- }
- /**
- * @return Long description of network or empty string if not present
- */
- inline std::string desc() const
- {
- return get("desc",std::string());
- }
- /**
- * @return Certificate of membership for this network, or empty cert if none
- */
- inline CertificateOfMembership certificateOfMembership() const
- {
- const_iterator cm(find("com"));
- if (cm == end())
- return CertificateOfMembership();
- else return CertificateOfMembership(cm->second);
- }
- /**
- * @return True if this network emulates IPv4 ARP for assigned addresses
- */
- inline bool emulateArp() const
- {
- const_iterator e(find("eARP"));
- if (e == end())
- return false;
- else return (e->second == "1");
- }
- /**
- * @return True if this network emulates IPv6 NDP for assigned addresses
- */
- inline bool emulateNdp() const
- {
- const_iterator e(find("eNDP"));
- if (e == end())
- return false;
- else return (e->second == "1");
- }
- /**
- * @return ARP cache TTL in seconds or 0 for no ARP caching
- */
- inline unsigned int arpCacheTtl() const
- {
- const_iterator ttl(find("cARP"));
- if (ttl == end())
- return 0;
- return Utils::hexStrToUInt(ttl->second.c_str());
- }
- /**
- * @return NDP cache TTL in seconds or 0 for no NDP caching
- */
- inline unsigned int ndpCacheTtl() const
- {
- const_iterator ttl(find("cNDP"));
- if (ttl == end())
- return 0;
- return Utils::hexStrToUInt(ttl->second.c_str());
- }
- /**
- * @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 Number of bits in propagation prefix for this network
- */
- inline unsigned int multicastPrefixBits() const
- {
- const_iterator mpb(find("mpb"));
- if (mpb == end())
- return ZT_DEFAULT_MULTICAST_PREFIX_BITS;
- unsigned int tmp = Utils::hexStrToUInt(mpb->second.c_str());
- if (tmp)
- return tmp;
- else return ZT_DEFAULT_MULTICAST_PREFIX_BITS;
- }
- /**
- * @return Maximum multicast propagation depth for this network
- */
- inline unsigned int multicastDepth() const
- {
- const_iterator md(find("md"));
- if (md == end())
- return ZT_DEFAULT_MULTICAST_DEPTH;
- unsigned int tmp = Utils::hexStrToUInt(md->second.c_str());
- if (tmp)
- return tmp;
- else return ZT_DEFAULT_MULTICAST_DEPTH;
- }
- /**
- * @return True if this is an open non-access-controlled network
- */
- inline bool isOpen() const
- {
- const_iterator o(find("o"));
- if (o == end())
- return false;
- else if (!o->second.length())
- return false;
- else return (o->second[0] == '1');
- }
- /**
- * @return Network ethertype whitelist
- */
- inline std::set<unsigned int> etherTypes() const
- {
- char tmp[16384];
- char *saveptr = (char *)0;
- std::set<unsigned int> et;
- 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::hexStrToUInt(f);
- if (t)
- et.insert(t);
- }
- return et;
- }
- /**
- * @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("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("v6s","").c_str(),",","","");
- for(std::vector<std::string>::const_iterator i(ips.begin());i!=ips.end();++i)
- sa.insert(InetAddress(*i));
- return sa;
- }
- };
- /**
- * Status for networks
- */
- enum Status
- {
- NETWORK_WAITING_FOR_FIRST_AUTOCONF,
- NETWORK_OK,
- NETWORK_ACCESS_DENIED,
- NETWORK_NOT_FOUND
- };
- /**
- * @param s Status
- * @return String description
- */
- static const char *statusString(const Status s)
- throw();
- private:
- // Only NodeConfig can create, only SharedPtr can delete
- // Actual construction happens in newInstance()
- Network()
- throw() :
- _tap((EthernetTap *)0)
- {
- }
- ~Network();
- /**
- * Create a new Network instance and restore any saved state
- *
- * If there is no saved state, a dummy .conf is created on disk to remember
- * this network across restarts.
- *
- * @param renv Runtime environment
- * @param id Network ID
- * @return Reference counted pointer to new network
- * @throws std::runtime_error Unable to create tap device or other fatal error
- */
- static SharedPtr<Network> newInstance(const RuntimeEnvironment *renv,uint64_t id)
- throw(std::runtime_error);
- /**
- * Causes all persistent disk presence to be erased on delete
- */
- inline void destroyOnDelete()
- throw()
- {
- _destroyOnDelete = true;
- }
- public:
- /**
- * @return Network ID
- */
- inline uint64_t id() const throw() { return _id; }
- /**
- * @return Ethernet tap
- */
- inline EthernetTap &tap() throw() { return *_tap; }
- /**
- * @return Address of network's controlling node
- */
- inline Address controller() throw() { return Address(_id >> 24); }
- /**
- * @return Network ID in hexadecimal form
- */
- inline std::string idString()
- {
- char buf[64];
- Utils::snprintf(buf,sizeof(buf),"%.16llx",(unsigned long long)_id);
- return std::string(buf);
- }
- /**
- * @return True if network is open (no membership required)
- */
- inline bool isOpen() const
- throw()
- {
- Mutex::Lock _l(_lock);
- return _isOpen;
- }
- /**
- * @return True if this network emulates IPv4 ARP for assigned addresses
- */
- inline bool emulateArp() const
- throw()
- {
- Mutex::Lock _l(_lock);
- return _emulateArp;
- }
- /**
- * @return True if this network emulates IPv6 NDP for assigned addresses
- */
- inline bool emulateNdp() const
- throw()
- {
- Mutex::Lock _l(_lock);
- return _emulateNdp;
- }
- /**
- * Update multicast groups for this network's tap
- *
- * @return True if internal multicast group set has changed
- */
- inline bool updateMulticastGroups()
- {
- Mutex::Lock _l(_lock);
- return _tap->updateMulticastGroups(_multicastGroups);
- }
- /**
- * @return Latest set of multicast groups for this network's tap
- */
- inline std::set<MulticastGroup> multicastGroups() const
- {
- Mutex::Lock _l(_lock);
- 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
- * @param saveToDisk IF true (default), write config to disk
- */
- void setConfiguration(const Config &conf,bool saveToDisk = true);
- /**
- * Causes this network to request an updated configuration from its master node now
- */
- void requestConfiguration();
- /**
- * Add or update a membership certificate
- *
- * The certificate must already have been validated via signature checking.
- *
- * @param cert Certificate of membership
- */
- void addMembershipCertificate(const CertificateOfMembership &cert);
- /**
- * Push our membership certificate to a peer
- *
- * @param peer Destination peer address
- * @param force If true, push even if we've already done so within required time frame
- * @param now Current time
- */
- inline void pushMembershipCertificate(const Address &peer,bool force,uint64_t now)
- {
- Mutex::Lock _l(_lock);
- if (!_isOpen)
- _pushMembershipCertificate(peer,force,now);
- }
- /**
- * Push membership certificate to a packed zero-terminated array of addresses
- *
- * This pushes to all peers in peers[] (length must be a multiple of 5) until
- * len is reached or a null address is encountered.
- *
- * @param peers Packed array of 5-byte big-endian addresses
- * @param len Length of peers[] in total, MUST be a multiple of 5
- * @param force If true, push even if we've already done so within required time frame
- * @param now Current time
- */
- inline void pushMembershipCertificate(const void *peers,unsigned int len,bool force,uint64_t now)
- {
- Mutex::Lock _l(_lock);
- if (!_isOpen) {
- for(unsigned int i=0;i<len;i+=ZT_ADDRESS_LENGTH) {
- Address a((char *)peers + i,ZT_ADDRESS_LENGTH);
- if (a)
- _pushMembershipCertificate(a,force,now);
- else break;
- }
- }
- }
- /**
- * @param peer Peer address to check
- * @return True if peer is allowed to communicate on this network
- */
- bool isAllowed(const Address &peer) const;
- /**
- * Perform cleanup and possibly save state
- */
- void clean();
- /**
- * @return Time of last updated configuration or 0 if none
- */
- inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; }
- /**
- * Force this network's status to a particular state based on config reply
- */
- inline void forceStatusTo(const Status s)
- throw()
- {
- Mutex::Lock _l(_lock);
- _status = s;
- }
- /**
- * @return Status of this network
- */
- inline Status status() const
- throw()
- {
- Mutex::Lock _l(_lock);
- return _status;
- }
- /**
- * @return True if this network is in "OK" status and can accept traffic from us
- */
- inline bool isUp() const
- throw()
- {
- Mutex::Lock _l(_lock);
- return ((_status == NETWORK_OK)&&(_ready));
- }
- /**
- * 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
- */
- inline bool permitsEtherType(unsigned int etherType) const
- throw()
- {
- if (!etherType)
- return false;
- else if (etherType > 65535)
- return false;
- else if ((_etWhitelist[0] & 1)) // if type 0 is in the whitelist, sense is inverted from whitelist to blacklist
- return ((_etWhitelist[etherType / 8] & (unsigned char)(1 << (etherType & 7))) == 0);
- else return ((_etWhitelist[etherType / 8] & (unsigned char)(1 << (etherType & 7))) != 0);
- }
- /**
- * Update multicast balance for an address and multicast group, return whether packet is allowed
- *
- * @param a Address that wants to send/relay packet
- * @param mg Multicast group
- * @param bytes Size of packet
- * @return True if packet is within budget
- */
- inline bool updateAndCheckMulticastBalance(const Address &a,const MulticastGroup &mg,unsigned int bytes)
- {
- Mutex::Lock _l(_lock);
- std::pair<Address,MulticastGroup> k(a,mg);
- std::map< std::pair<Address,MulticastGroup>,BandwidthAccount >::iterator bal(_multicastRateAccounts.find(k));
- if (bal == _multicastRateAccounts.end()) {
- MulticastRates::Rate r(_mcRates.get(mg));
- bal = _multicastRateAccounts.insert(std::pair< std::pair<Address,MulticastGroup>,BandwidthAccount >(k,BandwidthAccount(r.preload,r.maxBalance,r.accrual))).first;
- }
- return bal->second.deduct(bytes);
- }
- /**
- * @param fromPeer Peer attempting to bridge other Ethernet peers onto network
- * @return True if this network allows bridging
- */
- inline bool permitsBridging(const Address &fromPeer) const
- throw()
- {
- return false; // TODO: bridging not implemented yet
- }
- /**
- * @return Bits in multicast restriciton prefix
- */
- inline unsigned int multicastPrefixBits() const throw() { return _multicastPrefixBits; }
- /**
- * @return Max depth (TTL) for a multicast frame
- */
- inline unsigned int multicastDepth() const throw() { return _multicastDepth; }
- private:
- static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
- void _pushMembershipCertificate(const Address &peer,bool force,uint64_t now);
- void _restoreState();
- void _dumpMulticastCerts();
- const RuntimeEnvironment *_r;
- // 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 other peers on this network
- std::map<Address,CertificateOfMembership> _membershipCertificates;
- // The last time we sent a membership certificate to a given peer
- std::map<Address,uint64_t> _lastPushedMembershipCertificate;
- // Configuration from network master node -- and some memoized fields from
- // the most recent _configuration we have.
- Config _configuration;
- CertificateOfMembership _myCertificate;
- MulticastRates _mcRates;
- std::set<InetAddress> _staticAddresses;
- bool _isOpen;
- bool _emulateArp;
- bool _emulateNdp;
- unsigned int _arpCacheTtl;
- unsigned int _ndpCacheTtl;
- unsigned int _multicastPrefixBits;
- unsigned int _multicastDepth;
- // Network status
- Status _status;
- // Ethertype whitelist bit field, set from config, for really fast lookup
- unsigned char _etWhitelist[65536 / 8];
- // Network ID -- master node is most significant 40 bits
- uint64_t _id;
- volatile uint64_t _lastConfigUpdate;
- volatile bool _destroyOnDelete;
- volatile bool _ready;
- Mutex _lock;
- AtomicCounter __refCount;
- };
- } // naemspace ZeroTier
- #endif
|