/* * Copyright (c)2019 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * * Change Date: 2026-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. */ /****/ #ifndef ZT_LINUX_NETLINK_HPP #define ZT_LINUX_NETLINK_HPP #include "../node/Constants.hpp" #ifdef __LINUX__ #include #include #include #include #include #include #include //#include #include "../node/InetAddress.hpp" #include "../node/MAC.hpp" #include "Thread.hpp" #include "../node/Hashtable.hpp" #include "../node/Mutex.hpp" namespace ZeroTier { /** * Interface with Linux's RTNETLINK */ class LinuxNetLink { private: LinuxNetLink(); ~LinuxNetLink(); public: struct Route { InetAddress target; InetAddress via; InetAddress src; int ifidx; inline bool operator==(const Route &r) const { return ((target == r.target)&&(via == r.via)&&(src == r.src)&&(ifidx == r.ifidx)); } inline bool operator!=(const Route &r) const { return (!(*this == r)); } inline bool operator<(const Route &r) const { if (target < r.target) { return true; } else if (target == r.target) { if (via < r.via) { return true; } else if (via == r.via) { if (src < r.src) { return true; } else if (src == r.src) { return (ifidx < r.ifidx); } } } return false; } inline bool operator>(const Route &r) const { return (r < *this); } inline bool operator<=(const Route &r) const { return !(r < *this); } inline bool operator>=(const Route &r) const { return !(*this < r); } }; static LinuxNetLink& getInstance() { static LinuxNetLink instance; return instance; } LinuxNetLink(LinuxNetLink const&) = delete; void operator=(LinuxNetLink const&) = delete; void addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); void delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); void addAddress(const InetAddress &addr, const char *iface); void removeAddress(const InetAddress &addr, const char *iface); bool routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname); void threadMain() throw(); private: int _doRecv(int fd); void _processMessage(struct nlmsghdr *nlp, int nll); void _routeAdded(struct nlmsghdr *nlp); void _routeDeleted(struct nlmsghdr *nlp); void _linkAdded(struct nlmsghdr *nlp); void _linkDeleted(struct nlmsghdr *nlp); void _ipAddressAdded(struct nlmsghdr *nlp); void _ipAddressDeleted(struct nlmsghdr *nlp); void _requestInterfaceList(); void _requestIPv4Routes(); void _requestIPv6Routes(); int _indexForInterface(const char *iface); void _setSocketTimeout(int fd, int seconds = 1); Thread _t; bool _running; uint32_t _seq; std::map< InetAddress,std::set > _routes; Mutex _routes_m; struct iface_entry { iface_entry() { memset(this,0,sizeof(iface_entry)); } int index; char ifacename[16]; // IFNAMSIZ on Linux == 16 char mac[18]; char mac_bin[6]; unsigned int mtu; }; Hashtable _interfaces; Mutex _if_m; // socket communication vars; int _fd; struct sockaddr_nl _la; }; } #endif #endif // ZT_LINUX_NETLINK_HPPS