diff options
Diffstat (limited to 'node/Network.hpp')
-rw-r--r-- | node/Network.hpp | 344 |
1 files changed, 223 insertions, 121 deletions
diff --git a/node/Network.hpp b/node/Network.hpp index 17eed4bd..95b5483a 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -1,6 +1,6 @@ /* * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ + * Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/ * * 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 @@ -14,6 +14,14 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * -- + * + * You can be released from the requirements of the license by purchasing + * a commercial license. Buying such a license is mandatory as soon as you + * develop commercial closed-source software that incorporates or links + * directly against ZeroTier software without disclosing the source code + * of your own application. */ #ifndef ZT_NETWORK_HPP @@ -30,7 +38,6 @@ #include <stdexcept> #include "Constants.hpp" -#include "NonCopyable.hpp" #include "Hashtable.hpp" #include "Address.hpp" #include "Mutex.hpp" @@ -40,22 +47,24 @@ #include "MAC.hpp" #include "Dictionary.hpp" #include "Multicaster.hpp" +#include "Membership.hpp" #include "NetworkConfig.hpp" #include "CertificateOfMembership.hpp" +#define ZT_NETWORK_MAX_INCOMING_UPDATES 3 +#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1) + namespace ZeroTier { class RuntimeEnvironment; class Peer; -class _MulticastAnnounceAll; /** * A virtual LAN */ -class Network : NonCopyable +class Network { friend class SharedPtr<Network>; - friend class _MulticastAnnounceAll; // internal function object public: /** @@ -64,56 +73,102 @@ public: static const MulticastGroup BROADCAST; /** + * Compute primary controller device ID from network ID + */ + static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); } + + /** * Construct a new network * * Note that init() should be called immediately after the network is * constructed to actually configure the port. * * @param renv Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param nwid Network ID * @param uptr Arbitrary pointer used by externally-facing API (for user use) + * @param nconf Network config, if known */ - Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr); + Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr,const NetworkConfig *nconf); ~Network(); - /** - * @return Network ID - */ - inline uint64_t id() const throw() { return _id; } - - /** - * @return Address of network's controller (most significant 40 bits of ID) - */ - inline Address controller() const throw() { return Address(_id >> 24); } + inline uint64_t id() const { return _id; } + inline Address controller() const { return Address(_id >> 24); } + inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } + inline bool hasConfig() const { return (_config); } + inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } + inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); } + inline const NetworkConfig &config() const { return _config; } + inline const MAC &mac() const { return _mac; } /** - * @param nwid Network ID - * @return Address of network's controller + * Apply filters to an outgoing packet + * + * This applies filters from our network config and, if that doesn't match, + * our capabilities in ascending order of capability ID. Additional actions + * such as TEE may be taken, and credentials may be pushed, so this is not + * side-effect-free. It's basically step one in sending something over VL2. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) + * @param ztSource Source ZeroTier address + * @param ztDest Destination ZeroTier address + * @param macSource Ethernet layer source address + * @param macDest Ethernet layer destination address + * @param frameData Ethernet frame data + * @param frameLen Ethernet frame payload length + * @param etherType 16-bit ethernet type ID + * @param vlanId 16-bit VLAN ID + * @return True if packet should be sent, false if dropped or redirected */ - static inline Address controllerFor(uint64_t nwid) throw() { return Address(nwid >> 24); } + bool filterOutgoingPacket( + void *tPtr, + const bool noTee, + const Address &ztSource, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId); /** - * @return Multicast group memberships for this network's port (local, not learned via bridging) + * Apply filters to an incoming packet + * + * This applies filters from our network config and, if that doesn't match, + * the peer's capabilities in ascending order of capability ID. If there is + * a match certain actions may be taken such as sending a copy of the packet + * to a TEE or REDIRECT target. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param sourcePeer Source Peer + * @param ztDest Destination ZeroTier address + * @param macSource Ethernet layer source address + * @param macDest Ethernet layer destination address + * @param frameData Ethernet frame data + * @param frameLen Ethernet frame payload length + * @param etherType 16-bit ethernet type ID + * @param vlanId 16-bit VLAN ID + * @return 0 == drop, 1 == accept, 2 == accept even if bridged */ - inline std::vector<MulticastGroup> multicastGroups() const - { - Mutex::Lock _l(_lock); - return _myMulticastGroups; - } - - /** - * @return All multicast groups including learned groups that are behind any bridges we're attached to - */ - inline std::vector<MulticastGroup> allMulticastGroups() const - { - Mutex::Lock _l(_lock); - return _allMulticastGroups(); - } + int filterIncomingPacket( + void *tPtr, + const SharedPtr<Peer> &sourcePeer, + const Address &ztDest, + const MAC &macSource, + const MAC &macDest, + const uint8_t *frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId); /** + * Check whether we are subscribed to a multicast group + * * @param mg Multicast group - * @param includeBridgedGroups If true, also include any groups we've learned via bridging + * @param includeBridgedGroups If true, also check groups we've learned via bridging * @return True if this network endpoint / peer is a member */ bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const; @@ -121,9 +176,10 @@ public: /** * Subscribe to a multicast group * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param mg New multicast group */ - void multicastSubscribe(const MulticastGroup &mg); + void multicastSubscribe(void *tPtr,const MulticastGroup &mg); /** * Unsubscribe from a multicast group @@ -133,29 +189,30 @@ public: void multicastUnsubscribe(const MulticastGroup &mg); /** - * Announce multicast groups to a peer if that peer is authorized on this network + * Handle an inbound network config chunk * - * @param peer Peer to try to announce multicast groups to - * @return True if peer was authorized and groups were announced - */ - bool tryAnnounceMulticastGroupsTo(const SharedPtr<Peer> &peer); - - /** - * Apply a NetworkConfig to this network + * This is called from IncomingPacket to handle incoming network config + * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies + * each chunk and once assembled applies the configuration. * - * @param conf Configuration in NetworkConfig form - * @return True if configuration was accepted + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param packetId Packet ID or 0 if none (e.g. via cluster path) + * @param source Address of sender of chunk or NULL if none (e.g. via cluster path) + * @param chunk Buffer containing chunk + * @param ptr Index of chunk and related fields in packet + * @return Update ID if update was fully assembled and accepted or 0 otherwise */ - bool applyConfiguration(const NetworkConfig &conf); + uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr); /** - * Set or update this network's configuration + * Set network configuration * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param nconf Network configuration - * @param saveToDisk IF true (default), write config to disk - * @return 0 -- rejected, 1 -- accepted but not new, 2 -- accepted new config + * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. + * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new */ - int setConfiguration(const NetworkConfig &nconf,bool saveToDisk); + int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk); /** * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this @@ -167,7 +224,7 @@ public: } /** - * Set netconf failure to 'not found' -- called by PacketDecider when controller reports this + * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this */ inline void setNotFound() { @@ -177,151 +234,194 @@ public: /** * Causes this network to request an updated configuration from its master node now + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call */ - void requestConfiguration(); + void requestConfiguration(void *tPtr); /** + * Determine whether this peer is permitted to communicate on this network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param peer Peer to check - * @return True if peer is allowed to communicate on this network */ - inline bool isAllowed(const SharedPtr<Peer> &peer) const - { - Mutex::Lock _l(_lock); - return _isAllowed(peer); - } + bool gate(void *tPtr,const SharedPtr<Peer> &peer); /** - * Perform cleanup and possibly save state + * Check whether a given peer has recently had an association with this network + * + * This checks whether a peer has communicated with us recently about this + * network and has possessed a valid certificate of membership. This may return + * true even if the peer has been offline for a while or no longer has a valid + * certificate of membership but had one recently. + * + * @param addr Peer address + * @return True if peer has recently associated */ - void clean(); + bool recentlyAssociatedWith(const Address &addr); /** - * @return Time of last updated configuration or 0 if none + * Do periodic cleanup and housekeeping tasks */ - inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; } + void clean(); /** - * @return Status of this network + * Push state to members such as multicast group memberships and latest COM (if needed) + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call */ - inline ZT_VirtualNetworkStatus status() const + inline void sendUpdatesToMembers(void *tPtr) { Mutex::Lock _l(_lock); - return _status(); + _sendUpdatesToMembers(tPtr,(const MulticastGroup *)0); } /** - * @param ec Buffer to fill with externally-visible network configuration + * Find the node on this network that has this MAC behind it (if any) + * + * @param mac MAC address + * @return ZeroTier address of bridge to this MAC */ - inline void externalConfig(ZT_VirtualNetworkConfig *ec) const + inline Address findBridgeTo(const MAC &mac) const { Mutex::Lock _l(_lock); - _externalConfig(ec); + const Address *const br = _remoteBridgeRoutes.get(mac); + return ((br) ? *br : Address()); } /** - * Get current network config + * Set a bridge route * - * This returns a const reference to the network config in place, which is safe - * to concurrently access but *may* change during access. Normally this isn't a - * problem, but if it is use configCopy(). + * @param mac MAC address of destination + * @param addr Bridge this MAC is reachable behind + */ + void learnBridgeRoute(const MAC &mac,const Address &addr); + + /** + * Learn a multicast group that is bridged to our tap device * - * @return Network configuration (may be a null config if we don't have one yet) + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param mg Multicast group + * @param now Current time */ - inline const NetworkConfig &config() const { return _config; } + void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now); /** - * @return A thread-safe copy of our NetworkConfig instead of a const reference + * Validate a credential and learn it if it passes certificate and other checks */ - inline NetworkConfig configCopy() const + Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com); + + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap) { + if (cap.networkId() != _id) + return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - return _config; + return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap); } /** - * @return True if this network has a valid config + * Validate a credential and learn it if it passes certificate and other checks */ - inline bool hasConfig() const { return (_config); } + inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag) + { + if (tag.networkId() != _id) + return Membership::ADD_REJECTED; + Mutex::Lock _l(_lock); + return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag); + } /** - * @return Ethernet MAC address for this network's local interface + * Validate a credential and learn it if it passes certificate and other checks */ - inline const MAC &mac() const throw() { return _mac; } + Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev); /** - * Find the node on this network that has this MAC behind it (if any) - * - * @param mac MAC address - * @return ZeroTier address of bridge to this MAC + * Validate a credential and learn it if it passes certificate and other checks */ - inline Address findBridgeTo(const MAC &mac) const + inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo) { + if (coo.networkId() != _id) + return Membership::ADD_REJECTED; Mutex::Lock _l(_lock); - const Address *const br = _remoteBridgeRoutes.get(mac); - if (br) - return *br; - return Address(); + return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo); } /** - * Set a bridge route - * - * @param mac MAC address of destination - * @param addr Bridge this MAC is reachable behind - */ - void learnBridgeRoute(const MAC &mac,const Address &addr); - - /** - * Learn a multicast group that is bridged to our tap device + * Force push credentials (COM, etc.) to a peer now * - * @param mg Multicast group + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param to Destination peer address * @param now Current time */ - void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now); + inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now) + { + Mutex::Lock _l(_lock); + _membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true); + } /** * Destroy this network * - * This causes the network to disable itself, destroy its tap device, and on - * delete to delete all trace of itself on disk and remove any persistent tap - * device instances. Call this when a network is being removed from the system. + * This sets the network to completely remove itself on delete. This also prevents the + * call of the normal port shutdown event on delete. */ void destroy(); /** - * @return Pointer to user PTR (modifiable user ptr used in API) + * Get this network's config for export via the ZT core API + * + * @param ec Buffer to fill with externally-visible network configuration */ - inline void **userPtr() throw() { return &_uPtr; } + inline void externalConfig(ZT_VirtualNetworkConfig *ec) const + { + Mutex::Lock _l(_lock); + _externalConfig(ec); + } - inline bool operator==(const Network &n) const throw() { return (_id == n._id); } - inline bool operator!=(const Network &n) const throw() { return (_id != n._id); } - inline bool operator<(const Network &n) const throw() { return (_id < n._id); } - inline bool operator>(const Network &n) const throw() { return (_id > n._id); } - inline bool operator<=(const Network &n) const throw() { return (_id <= n._id); } - inline bool operator>=(const Network &n) const throw() { return (_id >= n._id); } + /** + * @return Externally usable pointer-to-pointer exported via the core API + */ + inline void **userPtr() { return &_uPtr; } private: ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked - bool _isAllowed(const SharedPtr<Peer> &peer) const; - void _announceMulticastGroups(); - void _announceMulticastGroupsTo(const SharedPtr<Peer> &peer,const std::vector<MulticastGroup> &allMulticastGroups) const; + bool _gate(const SharedPtr<Peer> &peer); + void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup); + void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups); std::vector<MulticastGroup> _allMulticastGroups() const; + Membership &_membership(const Address &a); - const RuntimeEnvironment *RR; + const RuntimeEnvironment *const RR; void *_uPtr; - uint64_t _id; + const uint64_t _id; + uint64_t _lastAnnouncedMulticastGroupsUpstream; MAC _mac; // local MAC address - volatile bool _portInitialized; + bool _portInitialized; std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap) Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) NetworkConfig _config; - volatile uint64_t _lastConfigUpdate; + uint64_t _lastConfigUpdate; - volatile bool _destroyed; + struct _IncomingConfigChunk + { + _IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); } + uint64_t ts; + uint64_t updateId; + uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; + unsigned long haveChunks; + unsigned long haveBytes; + Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> data; + }; + _IncomingConfigChunk _incomingConfigChunks[ZT_NETWORK_MAX_INCOMING_UPDATES]; + + bool _destroyed; enum { NETCONF_FAILURE_NONE, @@ -329,7 +429,9 @@ private: NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED } _netconfFailure; - volatile int _portError; // return value from port config callback + int _portError; // return value from port config callback + + Hashtable<Address,Membership> _memberships; Mutex _lock; |