From 6b113c827063972d43bf55d25b6baa66374992ac Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Wed, 26 Feb 2025 09:55:08 -0800 Subject: [PATCH 1/8] Add auto-detection of platform integer size in prometheus --- .../core/include/prometheus/counter.h | 13 ++++++++++++- .../core/include/prometheus/gauge.h | 10 ++++++++++ .../simpleapi/include/prometheus/simpleapi.h | 15 +++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/ext/prometheus-cpp-lite-1.0/core/include/prometheus/counter.h b/ext/prometheus-cpp-lite-1.0/core/include/prometheus/counter.h index 5d8053739..bd309c43a 100644 --- a/ext/prometheus-cpp-lite-1.0/core/include/prometheus/counter.h +++ b/ext/prometheus-cpp-lite-1.0/core/include/prometheus/counter.h @@ -25,7 +25,18 @@ namespace prometheus { /// /// The class is thread-safe. No concurrent call to any API of this type causes /// a data race. - template + +#include + +#if UINTPTR_MAX == 0xffFFffFF +// 32-bit platform +template +#elif UINTPTR_MAX == 0xffFFffFFffFFffFF +// 64-bit platform +template +#else +#error Unknown platform - does not look either like 32-bit or 64-bit +#endif class Counter : public Metric { std::atomic value{ 0 }; diff --git a/ext/prometheus-cpp-lite-1.0/core/include/prometheus/gauge.h b/ext/prometheus-cpp-lite-1.0/core/include/prometheus/gauge.h index fcda14631..2e4a4db8b 100644 --- a/ext/prometheus-cpp-lite-1.0/core/include/prometheus/gauge.h +++ b/ext/prometheus-cpp-lite-1.0/core/include/prometheus/gauge.h @@ -23,7 +23,17 @@ namespace prometheus { /// /// The class is thread-safe. No concurrent call to any API of this type causes /// a data race. + #include + + #if UINTPTR_MAX == 0xffFFffFF + // 32-bit + template + #elif UINTPTR_MAX == 0xffFFffFFffFFffFF + // 64-bit template + #else + #error Unknown platform - does not look either like 32-bit or 64-bit + #endif class Gauge : public Metric { std::atomic value { 0 }; diff --git a/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h b/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h index bf2ec4832..12e115844 100644 --- a/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h +++ b/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h @@ -15,6 +15,17 @@ #include #include #include +#include + +#if UINTPTR_MAX == 0xffFFffFF +// 32-bit +typedef uint32_tmetric_size; +#elif UINTPTR_MAX == 0xffFFffFFffFFffFF +// 64-bit +typedef uint64_t metric_size; +#else +#error Unknown platform - does not look either like 32-bit or 64-bit +#endif namespace prometheus { namespace simpleapi { @@ -46,7 +57,7 @@ namespace prometheus { public: - using Metric = Counter; + using Metric = Counter; using Family = Metric::Family; private: @@ -82,7 +93,7 @@ namespace prometheus { public: - using Metric = Gauge; + using Metric = Gauge; using Family = Metric::Family; private: From 3e7aacf301eab14f87ff3c8adff7685f3925ad30 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Wed, 26 Feb 2025 09:56:08 -0800 Subject: [PATCH 2/8] Expose routing() method in httplib so changes can be made in OneService --- ext/cpp-httplib/httplib.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/cpp-httplib/httplib.h b/ext/cpp-httplib/httplib.h index dfdd260ab..862e97e9e 100644 --- a/ext/cpp-httplib/httplib.h +++ b/ext/cpp-httplib/httplib.h @@ -917,6 +917,8 @@ public: std::function new_task_queue; + bool routing(Request &req, Response &res, Stream &strm); + protected: bool process_request(Stream &strm, bool close_connection, bool &connection_closed, @@ -949,7 +951,6 @@ private: int bind_internal(const std::string &host, int port, int socket_flags); bool listen_internal(); - bool routing(Request &req, Response &res, Stream &strm); bool handle_file_request(const Request &req, Response &res, bool head = false); bool dispatch_request(Request &req, Response &res, From cd191778c2b3a684625ff080d8750cd2d6cbecff Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Wed, 26 Feb 2025 10:27:23 -0800 Subject: [PATCH 3/8] Add custom management plane for 3rd party vendors --- make-linux.mk | 20 +- one.cpp | 31 ++- osdep/Binder.hpp | 22 ++ osdep/EthernetTap.cpp | 5 + osdep/ExtOsdep.cpp | 534 +++++++++++++++++++++++++++++++++++++++++ osdep/ExtOsdep.hpp | 198 +++++++++++++++ osdep/ManagedRoute.cpp | 10 + service/OneService.cpp | 63 ++++- 8 files changed, 874 insertions(+), 9 deletions(-) create mode 100644 osdep/ExtOsdep.cpp create mode 100644 osdep/ExtOsdep.hpp diff --git a/make-linux.mk b/make-linux.mk index efc1badf6..30eae3299 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -16,8 +16,13 @@ DESTDIR?= EXTRA_DEPS?= include objects.mk -ONE_OBJS+=osdep/LinuxEthernetTap.o -ONE_OBJS+=osdep/LinuxNetLink.o +ifeq ($(ZT_EXTOSDEP),1) + ONE_OBJS+=osdep/ExtOsdep.o + override DEFS += -DZT_EXTOSDEP +else + ONE_OBJS+=osdep/LinuxEthernetTap.o + ONE_OBJS+=osdep/LinuxNetLink.o +endif # for central controller buildsk TIMESTAMP=$(shell date +"%Y%m%d%H%M") @@ -275,6 +280,10 @@ ifeq ($(CC_MACH),loongarch64) override DEFS+=-DZT_NO_TYPE_PUNNING endif +ifeq ($(ZT_EXTOSDEP), 1) + ZT_SSO_SUPPORTED=0 +endif + # Fail if system architecture could not be determined ifeq ($(ZT_ARCHITECTURE),999) ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $(CC_MACH)) @@ -339,8 +348,11 @@ ifeq ($(ZT_ARCHITECTURE),3) override CXXFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm ZT_USE_ARM32_NEON_ASM_CRYPTO=0 else - override CFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s - override CXXFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -fexceptions -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s + ifeq ($(ZT_EXTOSDEP), 0) + override CFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s + override CXXFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -fexceptions -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s + override DEFS+=-DZT_NO_PEER_METRICS + endif ZT_USE_ARM32_NEON_ASM_CRYPTO=0 endif endif diff --git a/one.cpp b/one.cpp index 2e4e63847..61cc65f86 100644 --- a/one.cpp +++ b/one.cpp @@ -57,6 +57,7 @@ #include #include #include +#include "osdep/ExtOsdep.hpp" #ifndef ZT_NO_CAPABILITIES #include #include @@ -2110,6 +2111,17 @@ int main(int argc,char **argv) signal(SIGQUIT,&_sighandlerQuit); signal(SIGINT,&_sighandlerQuit); +#ifdef ZT_EXTOSDEP + int extosdepFd1 = -1; + int extosdepFd2 = -1; + for(int i=1;i mfd) mfd = STDOUT_FILENO; if (STDERR_FILENO > mfd) mfd = STDERR_FILENO; - for(int f=mfd+1;f<1024;++f) + for(int f=mfd+1;f<1024;++f) { +#ifdef ZT_EXTOSDEP + if (f == extosdepFd1 || f == extosdepFd2) continue; +#endif // ZT_EXTOSDEP ::close(f); + } } bool runAsDaemon = false; @@ -2224,7 +2240,9 @@ int main(int argc,char **argv) return 0; } break; #endif // __WINDOWS__ - +#ifdef ZT_EXTOSDEP + case 'x': break; +#endif case 'h': case '?': default: @@ -2354,6 +2372,15 @@ int main(int argc,char **argv) } #endif // __UNIX_LIKE__ +#ifdef ZT_EXTOSDEP + if (extosdepFd1 < 0) { + fprintf(stderr, "no extosdepFd specified\n"); + OSUtils::rm(pidPath.c_str()); + return 1; + } + ExtOsdep::init(extosdepFd1, extosdepFd2); +#endif + _OneServiceRunner thr(argv[0],homeDir,port); thr.threadMain(); //Thread::join(Thread::start(&thr)); diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index 23e6393af..5ed26ff5d 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -53,6 +53,7 @@ #include "../node/Utils.hpp" #include "OSUtils.hpp" #include "Phy.hpp" +#include "../osdep/ExtOsdep.hpp" #include #include @@ -136,6 +137,25 @@ class Binder { bool interfacesEnumerated = true; if (explicitBind.empty()) { +#ifdef ZT_EXTOSDEP + std::map addrs; + interfacesEnumerated = ExtOsdep::getBindAddrs(addrs); + for (auto &a : addrs) { + auto ip = a.first; + switch(ip.ipScope()) { + default: break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for(int x=0;x<(int)portCount;++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip,a.second)); + } + break; + } + } +#else // ZT_EXTOSDEP #ifdef __WINDOWS__ char aabuf[32768]; @@ -386,6 +406,8 @@ class Binder { #endif #endif + +#endif // ZT_EXTOSDEP } else { for (std::vector::const_iterator i(explicitBind.begin()); i != explicitBind.end(); ++i) { diff --git a/osdep/EthernetTap.cpp b/osdep/EthernetTap.cpp index 6cfc3a9b3..6ef292cf1 100644 --- a/osdep/EthernetTap.cpp +++ b/osdep/EthernetTap.cpp @@ -32,6 +32,7 @@ #endif // __APPLE__ #ifdef __LINUX__ +#include "ExtOsdep.hpp" #include "LinuxEthernetTap.hpp" #endif // __LINUX__ @@ -94,7 +95,11 @@ std::shared_ptr EthernetTap::newInstance( #endif // __APPLE__ #ifdef __LINUX__ +#ifdef ZT_EXTOSDEP + return std::shared_ptr(new ExtOsdepTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); +#else return std::shared_ptr(new LinuxEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); +#endif // ZT_EXTOSDEP #endif // __LINUX__ #ifdef __WINDOWS__ diff --git a/osdep/ExtOsdep.cpp b/osdep/ExtOsdep.cpp new file mode 100644 index 000000000..9ea03340e --- /dev/null +++ b/osdep/ExtOsdep.cpp @@ -0,0 +1,534 @@ +#include +#include +#include +#include +#include "ExtOsdep.hpp" +#include +#include "../node/AtomicCounter.hpp" + +#define ZT_TAP_BUF_SIZE 16384 + +namespace ZeroTier { + +static int eodFd = -1; +static Mutex eodMutex; +static int eodMgmtFd = -1; + +struct EodRoute { + InetAddress target; + InetAddress via; + InetAddress src; + std::string ifname; +}; +static std::list allRoutes; + +template static void __eodSend(const T &t) { + write(eodFd, &t, sizeof(t)); +} + +static void strncpyx(char *dest, const char *src, size_t n) { + strncpy(dest, src, n); + if (n > 1) dest[n - 1] = 0; +} + +static int __eodWait(unsigned char msg, unsigned char *d, unsigned l, + unsigned maxl = 0, int *recvfd = nullptr) { + if (!maxl) maxl = l; + auto start = times(NULL); + while (1) { + msghdr mh; + iovec iov; + struct { + size_t cmsg_len; + int cmsg_level; + int cmsg_type; + int fd; + } __attribute__((packed)) cmsg; + memset(&mh, 0, sizeof(mh)); + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + if (recvfd) { + mh.msg_control = &cmsg; + mh.msg_controllen = sizeof(cmsg); + } + iov.iov_base = d; + iov.iov_len = maxl; + + int r = recvmsg(eodFd, &mh, MSG_TRUNC | MSG_CMSG_CLOEXEC); + if (r > 0) { + if (recvfd && mh.msg_controllen >= sizeof(cmsg) + && cmsg.cmsg_len == sizeof(cmsg) + && cmsg.cmsg_level == SOL_SOCKET + && cmsg.cmsg_type == SCM_RIGHTS) { + *recvfd = cmsg.fd; + fprintf(stderr, "eodWait: received fd %d\n", *recvfd); + } + + if (d[0] != msg) { + fprintf(stderr, "eodWait: wrong msg, expected %u got %u\n", msg, d[0]); + return -1; + } + if ((unsigned)r < l || (unsigned)r > maxl) { + fprintf(stderr, "eodWait: wrong len, expected %u got %d\n", l, r); + return -1; + } + return r; + } + if (times(NULL) - start > 500) { + fprintf(stderr, "eodWait: timeout\n"); + return -1; + } + usleep(100000); + } +} + +template static bool __eodWait(unsigned msg, T &t) { + return __eodWait(msg, (unsigned char *)&t, sizeof(T)) == (int)sizeof(T); +} + +template static bool __eodXchg(const M &m, unsigned rm, R &r) { + __eodSend(m); + return __eodWait(rm, r); +} + +template static bool eodXchg(const M &m, unsigned rm, R &r) { + Mutex::Lock l(eodMutex); + return __eodXchg(m, rm, r); +} + +void ExtOsdep::init(int fd1, int fd2) { + eodFd = fd1; + eodMgmtFd = fd2; + fcntl(eodMgmtFd,F_SETFL,O_NONBLOCK); +} + +void ExtOsdep::started(int *f, void **cp) { + *f = eodMgmtFd; + *cp = (void *)eodMgmtFd; + + unsigned char msg = ZT_EOD_MSG_STARTED; + Mutex::Lock l(eodMutex); + __eodSend(msg); +} + +static std::string mgmtrd; +static std::string mgmtwr; + +bool ExtOsdep::mgmtWritable(void *cookie) { + if (cookie != (void *)eodMgmtFd) return false; + if (mgmtwr.size() == 0) return true; + auto sz = write(eodMgmtFd, mgmtwr.data(), mgmtwr.size()); + if (sz <= 0) return false; + mgmtwr.erase(mgmtwr.begin(), mgmtwr.begin() + sz); + return mgmtwr.empty(); +} + +bool ExtOsdep::mgmtRecv(void *cookie, void *data, unsigned long len, + std::function cb) { + if (cookie != (void *)eodMgmtFd) return false; + mgmtrd.append((char *)data, len); + while (1) { + auto req = (zt_eod_mgmt_req *)mgmtrd.data(); + if (mgmtrd.size() < sizeof(*req)) break; + unsigned reqsz = sizeof(*req) + req->pathlen + req->datalen; + if (mgmtrd.size() < reqsz) break; + + std::string resp; + char *p = (char *)req->data; + zt_eod_mgmt_reply rep; + rep.scode = cb(req->method, std::string(p, p + req->pathlen), + std::string(p + req->pathlen, p + req->pathlen + req->datalen), resp); + rep.datalen = resp.size(); + + mgmtrd.erase(mgmtrd.begin(), mgmtrd.begin() + reqsz); + + mgmtwr.append((char *)&rep, sizeof(rep)); + mgmtwr.append(resp); + + auto sz = write(eodMgmtFd, mgmtwr.data(), mgmtwr.size()); + if (sz > 0) mgmtwr.erase(mgmtwr.begin(), mgmtwr.begin() + sz); + } + return !mgmtwr.empty(); +} + +void ExtOsdep::routeAddDel(bool add, const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname) { + Mutex::Lock l(eodMutex); + + std::string ifn; + if (ifname) ifn = ifname; + if (add) { + for (auto x = allRoutes.begin(); x != allRoutes.end(); ++x) { + if (x->target == target && x->via == via + && x->src == src && x->ifname == ifn) return; + } + allRoutes.push_back({target, via, src, ifn}); + } + else { + bool found = false; + for (auto x = allRoutes.begin(); x != allRoutes.end(); ++x) { + if (x->target == target && x->via == via + && x->src == src && x->ifname == ifn) { + allRoutes.erase(x); + found = true; + break; + } + } + if (!found) return; + } + + zt_eod_msg_route req; + memset(&req, 0, sizeof(req)); + req.cmd = add ? ZT_EOD_MSG_ADDROUTE : ZT_EOD_MSG_DELROUTE; + req.afi = target.isV4() ? 1 : 2; + req.dstlen = target.netmaskBits(); + memcpy(req.dst, target.rawIpData(), target.isV4() ? 4 : 16); + if (ifname) strncpyx(req.dev, ifname, sizeof(req.dev)); + if (via) memcpy(req.gw, via.rawIpData(), target.isV4() ? 4 : 16); + if (src) memcpy(req.src, src.rawIpData(), target.isV4() ? 4 : 16); + + unsigned char resp; + __eodXchg(req, add ? ZT_EOD_MSG_ADDROUTERESP : ZT_EOD_MSG_DELROUTERESP, resp); +} + +bool ExtOsdep::getBindAddrs(std::map &ret) { + Mutex::Lock l(eodMutex); + + unsigned char req = ZT_EOD_MSG_GETBINDADDRS; + __eodSend(req); + + zt_eod_msg_getbindaddrsresp *resp; + unsigned char buf[ZT_EOD_MAXMSGSIZE]; + int r = __eodWait(ZT_EOD_MSG_GETBINDADDRSRESP, (unsigned char *)buf, sizeof(*resp), sizeof(buf)); + if (r < (int)sizeof(*resp)) return false; + + int c = (r - (int)sizeof(*resp)) / sizeof(resp->addrs[0]); + resp = (zt_eod_msg_getbindaddrsresp *)buf; + for (int i = 0; i < c; ++i) { + ret[InetAddress(resp->addrs[i].data, resp->addrs[i].afi == 1 ? 4 : 16, resp->addrs[i].len)] + = resp->addrs[i].ifname; + } + + return resp->result; +} + +ExtOsdepTap::ExtOsdepTap( + const char *homePath, + const MAC &mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char *friendlyName, + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void *arg) : + _handler(handler), + _arg(arg), + _nwid(nwid), + _mac(mac), + _homePath(homePath), + _mtu(mtu), + _fd(0), + _enabled(true), + _run(true) + { + zt_eod_msg_addtap req; + req.cmd = ZT_EOD_MSG_ADDTAP; + req.nwid = nwid; + req.mtu = mtu; + req.metric = metric; + strncpyx(req.fname, friendlyName, sizeof(req.fname)); + mac.copyTo(req.mac, 6); + + zt_eod_msg_addtapresp resp; + + Mutex::Lock l(eodMutex); + __eodSend(req); + _fd = -1; + if (__eodWait(ZT_EOD_MSG_ADDTAPRESP, (unsigned char *)&resp, sizeof(resp), sizeof(resp), &_fd) != sizeof(resp)) + throw std::runtime_error(std::string("could not create TAP")); + + _dev = resp.name; + if (_dev.empty() || _fd < 0) + throw std::runtime_error(std::string("could not create TAP")); + + fcntl(_fd,F_SETFL,O_NONBLOCK); + + // processing shamelessly copied from LinuxEthernetTap + (void)::pipe(_shutdownSignalPipe); + for(unsigned int t=0;t<2;++t) { + _tapReaderThread[t] = std::thread([this, t]{ + fd_set readfds,nullfds; + int n,nfds,r; + void *buf = nullptr; + std::vector buffers; + + if (!_run) + return; + + FD_ZERO(&readfds); + FD_ZERO(&nullfds); + nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; + + r = 0; + for(;;) { + FD_SET(_shutdownSignalPipe[0],&readfds); + FD_SET(_fd,&readfds); + select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); + + if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread + break; + + if (FD_ISSET(_fd,&readfds)) { + for(;;) { // read until there are no more packets, then return to outer select() loop + if (!buf) { + // To reduce use of the mutex, we keep a local buffer vector and + // swap (which is a pointer swap) with the global one when it's + // empty. This retrieves a batch of buffers to use. + if (buffers.empty()) { + std::lock_guard l(_buffers_l); + buffers.swap(_buffers); + } + if (buffers.empty()) { + buf = malloc(ZT_TAP_BUF_SIZE); + if (!buf) + break; + } else { + buf = buffers.back(); + buffers.pop_back(); + } + } + + n = (int)::read(_fd,reinterpret_cast(buf) + r,ZT_TAP_BUF_SIZE - r); + if (n > 0) { + // Some tap drivers like to send the ethernet frame and the + // payload in two chunks, so handle that by accumulating + // data until we have at least a frame. + r += n; + if (r > 14) { + if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms + r = _mtu + 14; + + if (_enabled && _tapqsize.load() < 1000) { + ++_tapqsize; + _tapq.post(std::pair(buf,r)); + buf = nullptr; + } + + r = 0; + } + } else { + r = 0; + break; + } + } + } + } + }); + } + + _tapProcessorThread = std::thread([this] { + MAC to,from; + std::pair qi; + while (_tapq.get(qi)) { + --_tapqsize; + uint8_t *const b = reinterpret_cast(qi.first); + if (b) { + to.setTo(b, 6); + from.setTo(b + 6, 6); + unsigned int etherType = Utils::ntoh(((const uint16_t *)b)[6]); + _handler(_arg, nullptr, _nwid, from, to, etherType, 0, (const void *)(b + 14),(unsigned int)(qi.second - 14)); + { + std::lock_guard l(_buffers_l); + if (_buffers.size() < 128) + _buffers.push_back(qi.first); + else free(qi.first); + } + } else break; + } + }); +} + +ExtOsdepTap::~ExtOsdepTap() { + _run = false; + + (void)::write(_shutdownSignalPipe[1],"\0",1); // causes reader thread(s) to exit + _tapq.post(std::pair(nullptr,0)); // causes processor thread to exit + + _tapReaderThread[0].join(); + _tapReaderThread[1].join(); + _tapProcessorThread.join(); + + ::close(_fd); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); + + for(std::vector::iterator i(_buffers.begin());i!=_buffers.end();++i) + free(*i); + std::vector< std::pair > dv(_tapq.drain()); + for(std::vector< std::pair >::iterator i(dv.begin());i!=dv.end();++i) { + if (i->first) + free(i->first); + } + + zt_eod_msg_deltap req; + req.cmd = ZT_EOD_MSG_DELTAP; + strcpy(req.name, _dev.c_str()); + + unsigned char resp; + eodXchg(req, ZT_EOD_MSG_DELTAPRESP, resp); +} + +void ExtOsdepTap::setEnabled(bool en) { + _enabled = en; +} + +bool ExtOsdepTap::enabled() const { + return _enabled; +} + +void ExtOsdepTap::doRemoveIp(const InetAddress &ip) { + zt_eod_msg_ip req; + req.cmd = ZT_EOD_MSG_DELIP; + strcpy(req.name, _dev.c_str()); + req.afi = ip.isV4() ? 1 : 2; + req.len = ip.netmaskBits(); + memcpy(req.data, ip.rawIpData(), ip.isV4() ? 4 : 16); + + unsigned char resp; + __eodXchg(req, ZT_EOD_MSG_DELIPRESP, resp); +} + +bool ExtOsdepTap::addIp(const InetAddress &ip) { + Mutex::Lock l(eodMutex); + + for(auto i = allIps.begin();i!=allIps.end();++i) { + if (*i == ip) return true; + if (i->ipsEqual(ip)) doRemoveIp(*i); + } + + zt_eod_msg_ip req; + req.cmd = ZT_EOD_MSG_ADDIP; + strcpy(req.name, _dev.c_str()); + req.afi = ip.isV4() ? 1 : 2; + req.len = ip.netmaskBits(); + memcpy(req.data, ip.rawIpData(), ip.isV4() ? 4 : 16); + + unsigned char resp; + __eodXchg(req, ZT_EOD_MSG_ADDIPRESP, resp); + + allIps.push_back(ip); + + return true; +} +bool ExtOsdepTap::addIps(std::vector ips) { + return false; +} +bool ExtOsdepTap::removeIp(const InetAddress &ip) { + Mutex::Lock l(eodMutex); + for(auto i = allIps.begin();i!=allIps.end();++i) { + if (*i == ip) { + doRemoveIp(*i); + return true; + } + } + return false; +} +std::vector ExtOsdepTap::ips() const { + std::vector ret; + + Mutex::Lock l(eodMutex); + + zt_eod_msg_getips req; + req.cmd = ZT_EOD_MSG_GETIPS; + strcpy(req.name, _dev.c_str()); + __eodSend(req); + + zt_eod_msg_getipsresp *resp; + unsigned char buf[ZT_EOD_MAXMSGSIZE]; + int r = __eodWait(ZT_EOD_MSG_GETIPSRESP, (unsigned char *)buf, sizeof(*resp), sizeof(buf)); + if (r < (int)sizeof(*resp)) return ret; + + int c = (r - (int)sizeof(*resp)) / sizeof(resp->addrs[0]); + resp = (zt_eod_msg_getipsresp *)buf; + for (int i = 0; i < c; ++i) { + ret.push_back(InetAddress(resp->addrs[i].data, resp->addrs[i].afi == 1 ? 4 : 16, resp->addrs[i].len)); + } + + return ret; +} +void ExtOsdepTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) { + char putBuf[ZT_MAX_MTU + 64]; + if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { + to.copyTo(putBuf,6); + from.copyTo(putBuf + 6,6); + *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); + memcpy(putBuf + 14,data,len); + len += 14; + (void)::write(_fd,putBuf,len); + } +} +std::string ExtOsdepTap::deviceName() const { + return _dev; +} +void ExtOsdepTap::setFriendlyName(const char *friendlyName) {} + +void ExtOsdepTap::scanMulticastGroups(std::vector &added,std::vector &removed) { + char *ptr,*ptr2; + unsigned char mac[6]; + std::vector newGroups; + + int fd = ::open("/proc/net/dev_mcast",O_RDONLY); + if (fd > 0) { + char buf[131072]; + int n = (int)::read(fd,buf,sizeof(buf)); + if ((n > 0)&&(n < (int)sizeof(buf))) { + buf[n] = (char)0; + for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) { + int fno = 0; + char *devname = (char *)0; + char *mcastmac = (char *)0; + for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) { + if (fno == 1) + devname = f; + else if (fno == 4) + mcastmac = f; + ++fno; + } + if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6)) + newGroups.push_back(MulticastGroup(MAC(mac,6),0)); + } + } + ::close(fd); + } + + std::vector allIps(ips()); + for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + + std::sort(newGroups.begin(),newGroups.end()); + newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); + + for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { + if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) + added.push_back(*m); + } + for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { + if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) + removed.push_back(*m); + } + + _multicastGroups.swap(newGroups); +} +void ExtOsdepTap::setMtu(unsigned int mtu) { + if (mtu == _mtu) return; + _mtu = mtu; + + zt_eod_msg_setmtu req; + req.cmd = ZT_EOD_MSG_SETMTU; + strcpy(req.name, _dev.c_str()); + req.mtu = mtu; + + unsigned char resp; + eodXchg(req, ZT_EOD_MSG_SETMTURESP, resp); +} + +} // namespace ZeroTier diff --git a/osdep/ExtOsdep.hpp b/osdep/ExtOsdep.hpp new file mode 100644 index 000000000..a224c467d --- /dev/null +++ b/osdep/ExtOsdep.hpp @@ -0,0 +1,198 @@ +#ifndef ZT_EXTOSDEP_HPP +#define ZT_EXTOSDEP_HPP + +#ifdef ZT_EXTOSDEP + +#define ZT_EOD_MAXMSGSIZE (64 * 1024) + +#define ZT_EOD_MSG_STARTED 1 // no data +#define ZT_EOD_MSG_ADDTAP 2 +#define ZT_EOD_MSG_ADDTAPRESP 3 +#define ZT_EOD_MSG_DELTAP 4 +#define ZT_EOD_MSG_DELTAPRESP 5 // no data +#define ZT_EOD_MSG_SETMTU 6 +#define ZT_EOD_MSG_SETMTURESP 7 +#define ZT_EOD_MSG_ADDIP 8 +#define ZT_EOD_MSG_ADDIPRESP 9 +#define ZT_EOD_MSG_DELIP 10 +#define ZT_EOD_MSG_DELIPRESP 11 +#define ZT_EOD_MSG_GETIPS 12 +#define ZT_EOD_MSG_GETIPSRESP 13 +#define ZT_EOD_MSG_GETBINDADDRS 14 +#define ZT_EOD_MSG_GETBINDADDRSRESP 15 +#define ZT_EOD_MSG_ADDROUTE 16 +#define ZT_EOD_MSG_ADDROUTERESP 17 +#define ZT_EOD_MSG_DELROUTE 18 +#define ZT_EOD_MSG_DELROUTERESP 19 + +struct zt_eod_msg_addtap { + unsigned char cmd; + uint64_t nwid; + uint32_t mtu; + uint32_t metric; + char fname[128]; + unsigned char mac[6]; +} __attribute__((packed)); + +struct zt_eod_msg_addtapresp { + unsigned char cmd; + char name[16]; +} __attribute__((packed)); + +struct zt_eod_msg_deltap { + unsigned char cmd; + char name[16]; +} __attribute__((packed)); + +struct zt_eod_msg_setmtu { + unsigned char cmd; + char name[16]; + unsigned mtu; +} __attribute__((packed)); + +struct zt_eod_msg_ip { + unsigned char cmd; + char name[16]; + unsigned char afi; // 1 ip, 2 ip6 + unsigned char len; // bits in mask + unsigned char data[16]; +} __attribute__((packed)); + +struct zt_eod_msg_getips { + unsigned char cmd; + char name[16]; +} __attribute__((packed)); + +struct zt_eod_msg_getipsresp { + unsigned char cmd; + struct addr { + unsigned char afi; + unsigned char len; + unsigned char data[16]; + } __attribute__((packed)) addrs[0]; +} __attribute__((packed)); +#define ZT_EOD_GETIPSRESP_MAXADDRS ((ZT_EOD_MAXMSGSIZE - sizeof(zt_eod_msg_getipsresp)) / sizeof(zt_eod_msg_getipsresp::addr)) + +struct zt_eod_msg_getbindaddrsresp { + unsigned char cmd; + unsigned char result; + struct addr { + unsigned char afi; + unsigned char len; + unsigned char data[16]; + char ifname[16]; + } __attribute__((packed)) addrs[0]; +} __attribute__((packed)); +#define ZT_EOD_GETBINDADDRSRESP_MAXADDRS ((ZT_EOD_MAXMSGSIZE - sizeof(zt_eod_msg_getbindaddrsresp)) / sizeof(zt_eod_msg_getbindaddrsresp::addr)) + +struct zt_eod_msg_route { + unsigned char cmd; + unsigned char afi; // 1 ip, 2 ip6 + unsigned char dstlen; + unsigned char dst[16]; + unsigned char gw[16]; + char dev[16]; + unsigned char src[16]; +} __attribute__((packed)); + +struct zt_eod_mgmt_req { + uint32_t method; + uint32_t pathlen; + uint32_t datalen; + unsigned char data[0]; +} __attribute__((packed)); + +struct zt_eod_mgmt_reply { + uint32_t scode; + uint32_t datalen; + unsigned char data[0]; +} __attribute__((packed)); + +#ifndef ZT_EXTOSDEP_IFACEONLY + +#include "../node/InetAddress.hpp" +#include "../node/MAC.hpp" +#include "Thread.hpp" +#include "../node/Hashtable.hpp" +#include "../node/Mutex.hpp" +#include "../node/AtomicCounter.hpp" +#include "EthernetTap.hpp" +#include "BlockingQueue.hpp" +#include +#include +#include +#include +#include + +namespace ZeroTier { + +class ExtOsdep { +public: + static void init(int, int); + static void started(int *, void **); + + static void routeAddDel(bool, const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); + static bool getBindAddrs(std::map &); + + static bool mgmtRecv(void *cookie, void *data, unsigned long len, + std::function); + static bool mgmtWritable(void *); +}; + +class ExtOsdepTap : public EthernetTap +{ +public: + ExtOsdepTap( + const char *homePath, + const MAC &mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char *friendlyName, + void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), + void *arg); + + virtual ~ExtOsdepTap(); + + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual bool addIp(const InetAddress &ip); + virtual bool addIps(std::vector ips); + virtual bool removeIp(const InetAddress &ip); + virtual std::vector ips() const; + virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + virtual std::string deviceName() const; + virtual void setFriendlyName(const char *friendlyName); + virtual void scanMulticastGroups(std::vector &added,std::vector &removed); + virtual void setMtu(unsigned int mtu); + virtual void setDns(const char *domain, const std::vector &servers) {} +private: + void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); + void *_arg; + uint64_t _nwid; + MAC _mac; + std::string _homePath; + std::string _dev; + std::vector _multicastGroups; + unsigned int _mtu; + int _fd; + int _shutdownSignalPipe[2]; + std::atomic_bool _enabled; + std::atomic_bool _run; + std::thread _tapReaderThread[2]; + std::thread _tapProcessorThread; + std::mutex _buffers_l; + std::vector _buffers; + BlockingQueue< std::pair > _tapq; + AtomicCounter _tapqsize; + + std::vector allIps; + void doRemoveIp(const InetAddress &); +}; + +} // namespace ZeroTier + +#endif // ZT_EXTOSDEP_IFACEONLY +#endif // ZT_EXTOSDEP + +#endif diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 9be2eda11..e65ffac40 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -51,6 +51,7 @@ #include "ManagedRoute.hpp" #ifdef __LINUX__ +#include "ExtOsdep.hpp" #include "LinuxNetLink.hpp" #endif @@ -550,6 +551,10 @@ bool ManagedRoute::sync() #ifdef __LINUX__ // ---------------------------------------------------------- +#ifdef ZT_EXTOSDEP + _applied[_target] = false; + ExtOsdep::routeAddDel(true, _target, _via, _src, _device); +#else if ((leftt)&&(!LinuxNetLink::getInstance().routeIsSet(leftt,_via,_src,_device))) { _applied[leftt] = false; // boolean unused LinuxNetLink::getInstance().addRoute(leftt, _via, _src, _device); @@ -558,6 +563,7 @@ bool ManagedRoute::sync() _applied[rightt] = false; // boolean unused LinuxNetLink::getInstance().addRoute(rightt, _via, _src, _device); } +#endif // ZT_EXTOSDEP #endif // __LINUX__ ---------------------------------------------------------- @@ -609,7 +615,11 @@ void ManagedRoute::remove() #ifdef __LINUX__ // ---------------------------------------------------------- //_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device); +#ifdef ZT_EXTOSDEP + ExtOsdep::routeAddDel(false, r->first,_via,_src,(_via) ? (const char *)0 : _device); +#else LinuxNetLink::getInstance().delRoute(r->first,_via,_src,(_via) ? (const char *)0 : _device); +#endif // ZT_EXTOSDEP #endif // __LINUX__ ---------------------------------------------------------- #ifdef __WINDOWS__ // -------------------------------------------------------- diff --git a/service/OneService.cpp b/service/OneService.cpp index 594ff02de..4beee1ad7 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -55,6 +55,7 @@ #include "../osdep/Binder.hpp" #include "../osdep/ManagedRoute.hpp" #include "../osdep/BlockingQueue.hpp" +#include "../osdep/ExtOsdep.hpp" #include "OneService.hpp" #include "SoftwareUpdater.hpp" @@ -1125,6 +1126,15 @@ public: } #endif +#ifdef ZT_EXTOSDEP + { + int mgmtfd; + void *mgmtcookie; + ExtOsdep::started(&mgmtfd, &mgmtcookie); + _phy.wrapSocket(mgmtfd, mgmtcookie); + } +#endif + // Delete legacy iddb.d if present (cleanup) OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str()); @@ -2165,7 +2175,6 @@ public: auto statusGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { ZT_NodeStatus status; _node->status(&status); - auto out = json::object(); char tmp[256] = {}; @@ -2335,7 +2344,9 @@ public: _controller->configureHTTPControlPlane(_controlPlane, _controlPlaneV6, setContent); } +#ifndef ZT_EXTOSDEP _controlPlane.set_pre_routing_handler(authCheck); +#endif // ZT_EXTOSDEP _controlPlaneV6.set_pre_routing_handler(authCheck); #if ZT_DEBUG==1 @@ -2351,6 +2362,7 @@ public: exit(-1); } +#ifndef ZT_EXTOSDEP bool v4controlPlaneBound = false; _controlPlane.set_address_family(AF_INET); if(_controlPlane.bind_to_port("0.0.0.0", _primaryPort)) { @@ -2391,6 +2403,7 @@ public: fprintf(stderr, "ERROR: Could not bind control plane. Exiting...\n"); exit(-1); } +#endif // ZT_EXTOSDEP } // Must be called after _localConfig is read or modified @@ -3162,8 +3175,52 @@ public: inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} - inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} - inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} + inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) { +#ifdef ZT_EXTOSDEP + if (ExtOsdep::mgmtRecv(*uptr, data, len, [&](unsigned method, const std::string &path, const std::string &data, std::string &resp) { + // fprintf(stderr, "mgmtRecv: %u %s %s\n", method, path.c_str(), data.c_str()); + httplib::Request req; + httplib::Response res; + req.path = "/" + path; + if (method == 1) req.method = "GET"; + else if (method == 3) req.method = "POST"; + else if (method == 0) req.method = "DELETE"; + struct S : public httplib::Stream { + const char *ptr; + unsigned size; + S(const std::string &s) : ptr(s.c_str()), size(s.size()) {} + virtual bool is_readable() const { return true; } + virtual bool is_writable() const { return true; } + virtual ssize_t read(char *p, size_t sz) { + // fprintf(stderr, "S::read %d\n", (int)size); + if (sz > (size_t)size) sz = size; + memcpy(p, ptr, sz); + size -= (unsigned)sz; + ptr += sz; + return (ssize_t)sz; + } + virtual ssize_t write(const char *ptr, size_t size) { + // fprintf(stderr, "S::write %d\n", (int)size); + return size; + } + virtual void get_remote_ip_and_port(std::string &ip, int &port) const {} + virtual void get_local_ip_and_port(std::string &ip, int &port) const {}; + virtual socket_t socket() const { return 0; } + }; + S s(data); + + bool x = _controlPlane.routing(req, res, s); + // fprintf(stderr, "mgmtRecv: done, x %d status %u body %s\n", x, res.status, res.body.c_str()); + resp = res.body; + return res.status; + })) _phy.setNotifyWritable(sock,true); +#endif + } + inline void phyOnUnixWritable(PhySocket *sock,void **uptr) { +#ifdef ZT_EXTOSDEP + if (ExtOsdep::mgmtWritable(*uptr)) _phy.setNotifyWritable(sock,false); +#endif + } inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwc) { From 269c8d415ae5813c75d5a1ffd9958be94acb249b Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Wed, 26 Feb 2025 11:16:03 -0800 Subject: [PATCH 4/8] Style match --- osdep/ExtOsdep.cpp | 612 ++++++++++++++++++++++++++------------------- osdep/ExtOsdep.hpp | 153 +++++++----- 2 files changed, 437 insertions(+), 328 deletions(-) diff --git a/osdep/ExtOsdep.cpp b/osdep/ExtOsdep.cpp index 9ea03340e..47543ae4d 100644 --- a/osdep/ExtOsdep.cpp +++ b/osdep/ExtOsdep.cpp @@ -1,11 +1,26 @@ -#include -#include -#include -#include +/* + * 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. + */ +/****/ + #include "ExtOsdep.hpp" -#include + #include "../node/AtomicCounter.hpp" +#include +#include +#include +#include +#include + #define ZT_TAP_BUF_SIZE 16384 namespace ZeroTier { @@ -22,18 +37,24 @@ struct EodRoute { }; static std::list allRoutes; -template static void __eodSend(const T &t) { +template static void __eodSend(const T& t) +{ write(eodFd, &t, sizeof(t)); } -static void strncpyx(char *dest, const char *src, size_t n) { +static void strncpyx(char* dest, const char* src, size_t n) +{ strncpy(dest, src, n); - if (n > 1) dest[n - 1] = 0; + if (n > 1) { + dest[n - 1] = 0; + } } -static int __eodWait(unsigned char msg, unsigned char *d, unsigned l, - unsigned maxl = 0, int *recvfd = nullptr) { - if (!maxl) maxl = l; +static int __eodWait(unsigned char msg, unsigned char* d, unsigned l, unsigned maxl = 0, int* recvfd = nullptr) +{ + if (! maxl) { + maxl = l; + } auto start = times(NULL); while (1) { msghdr mh; @@ -56,10 +77,7 @@ static int __eodWait(unsigned char msg, unsigned char *d, unsigned l, int r = recvmsg(eodFd, &mh, MSG_TRUNC | MSG_CMSG_CLOEXEC); if (r > 0) { - if (recvfd && mh.msg_controllen >= sizeof(cmsg) - && cmsg.cmsg_len == sizeof(cmsg) - && cmsg.cmsg_level == SOL_SOCKET - && cmsg.cmsg_type == SCM_RIGHTS) { + if (recvfd && mh.msg_controllen >= sizeof(cmsg) && cmsg.cmsg_len == sizeof(cmsg) && cmsg.cmsg_level == SOL_SOCKET && cmsg.cmsg_type == SCM_RIGHTS) { *recvfd = cmsg.fd; fprintf(stderr, "eodWait: received fd %d\n", *recvfd); } @@ -82,29 +100,34 @@ static int __eodWait(unsigned char msg, unsigned char *d, unsigned l, } } -template static bool __eodWait(unsigned msg, T &t) { - return __eodWait(msg, (unsigned char *)&t, sizeof(T)) == (int)sizeof(T); +template static bool __eodWait(unsigned msg, T& t) +{ + return __eodWait(msg, (unsigned char*)&t, sizeof(T)) == (int)sizeof(T); } -template static bool __eodXchg(const M &m, unsigned rm, R &r) { +template static bool __eodXchg(const M& m, unsigned rm, R& r) +{ __eodSend(m); return __eodWait(rm, r); } -template static bool eodXchg(const M &m, unsigned rm, R &r) { +template static bool eodXchg(const M& m, unsigned rm, R& r) +{ Mutex::Lock l(eodMutex); return __eodXchg(m, rm, r); } -void ExtOsdep::init(int fd1, int fd2) { +void ExtOsdep::init(int fd1, int fd2) +{ eodFd = fd1; eodMgmtFd = fd2; - fcntl(eodMgmtFd,F_SETFL,O_NONBLOCK); + fcntl(eodMgmtFd, F_SETFL, O_NONBLOCK); } -void ExtOsdep::started(int *f, void **cp) { +void ExtOsdep::started(int* f, void** cp) +{ *f = eodMgmtFd; - *cp = (void *)eodMgmtFd; + *cp = (void*)eodMgmtFd; unsigned char msg = ZT_EOD_MSG_STARTED; Mutex::Lock l(eodMutex); @@ -114,66 +137,85 @@ void ExtOsdep::started(int *f, void **cp) { static std::string mgmtrd; static std::string mgmtwr; -bool ExtOsdep::mgmtWritable(void *cookie) { - if (cookie != (void *)eodMgmtFd) return false; - if (mgmtwr.size() == 0) return true; +bool ExtOsdep::mgmtWritable(void* cookie) +{ + if (cookie != (void*)eodMgmtFd) { + return false; + } + if (mgmtwr.size() == 0) { + return true; + } auto sz = write(eodMgmtFd, mgmtwr.data(), mgmtwr.size()); - if (sz <= 0) return false; + if (sz <= 0) { + return false; + } mgmtwr.erase(mgmtwr.begin(), mgmtwr.begin() + sz); return mgmtwr.empty(); } -bool ExtOsdep::mgmtRecv(void *cookie, void *data, unsigned long len, - std::function cb) { - if (cookie != (void *)eodMgmtFd) return false; - mgmtrd.append((char *)data, len); +bool ExtOsdep::mgmtRecv(void* cookie, void* data, unsigned long len, std::function cb) +{ + if (cookie != (void*)eodMgmtFd) { + return false; + } + mgmtrd.append((char*)data, len); while (1) { - auto req = (zt_eod_mgmt_req *)mgmtrd.data(); - if (mgmtrd.size() < sizeof(*req)) break; + auto req = (zt_eod_mgmt_req*)mgmtrd.data(); + if (mgmtrd.size() < sizeof(*req)) { + break; + } unsigned reqsz = sizeof(*req) + req->pathlen + req->datalen; - if (mgmtrd.size() < reqsz) break; + if (mgmtrd.size() < reqsz) { + break; + } std::string resp; - char *p = (char *)req->data; + char* p = (char*)req->data; zt_eod_mgmt_reply rep; - rep.scode = cb(req->method, std::string(p, p + req->pathlen), - std::string(p + req->pathlen, p + req->pathlen + req->datalen), resp); + rep.scode = cb(req->method, std::string(p, p + req->pathlen), std::string(p + req->pathlen, p + req->pathlen + req->datalen), resp); rep.datalen = resp.size(); mgmtrd.erase(mgmtrd.begin(), mgmtrd.begin() + reqsz); - mgmtwr.append((char *)&rep, sizeof(rep)); + mgmtwr.append((char*)&rep, sizeof(rep)); mgmtwr.append(resp); auto sz = write(eodMgmtFd, mgmtwr.data(), mgmtwr.size()); - if (sz > 0) mgmtwr.erase(mgmtwr.begin(), mgmtwr.begin() + sz); + if (sz > 0) { + mgmtwr.erase(mgmtwr.begin(), mgmtwr.begin() + sz); + } } - return !mgmtwr.empty(); + return ! mgmtwr.empty(); } -void ExtOsdep::routeAddDel(bool add, const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname) { +void ExtOsdep::routeAddDel(bool add, const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifname) +{ Mutex::Lock l(eodMutex); std::string ifn; - if (ifname) ifn = ifname; + if (ifname) { + ifn = ifname; + } if (add) { for (auto x = allRoutes.begin(); x != allRoutes.end(); ++x) { - if (x->target == target && x->via == via - && x->src == src && x->ifname == ifn) return; + if (x->target == target && x->via == via && x->src == src && x->ifname == ifn) { + return; + } } - allRoutes.push_back({target, via, src, ifn}); + allRoutes.push_back({ target, via, src, ifn }); } else { bool found = false; for (auto x = allRoutes.begin(); x != allRoutes.end(); ++x) { - if (x->target == target && x->via == via - && x->src == src && x->ifname == ifn) { + if (x->target == target && x->via == via && x->src == src && x->ifname == ifn) { allRoutes.erase(x); found = true; break; } } - if (!found) return; + if (! found) { + return; + } } zt_eod_msg_route req; @@ -182,54 +224,62 @@ void ExtOsdep::routeAddDel(bool add, const InetAddress &target, const InetAddres req.afi = target.isV4() ? 1 : 2; req.dstlen = target.netmaskBits(); memcpy(req.dst, target.rawIpData(), target.isV4() ? 4 : 16); - if (ifname) strncpyx(req.dev, ifname, sizeof(req.dev)); - if (via) memcpy(req.gw, via.rawIpData(), target.isV4() ? 4 : 16); - if (src) memcpy(req.src, src.rawIpData(), target.isV4() ? 4 : 16); + if (ifname) { + strncpyx(req.dev, ifname, sizeof(req.dev)); + } + if (via) { + memcpy(req.gw, via.rawIpData(), target.isV4() ? 4 : 16); + } + if (src) { + memcpy(req.src, src.rawIpData(), target.isV4() ? 4 : 16); + } unsigned char resp; __eodXchg(req, add ? ZT_EOD_MSG_ADDROUTERESP : ZT_EOD_MSG_DELROUTERESP, resp); } -bool ExtOsdep::getBindAddrs(std::map &ret) { +bool ExtOsdep::getBindAddrs(std::map& ret) +{ Mutex::Lock l(eodMutex); unsigned char req = ZT_EOD_MSG_GETBINDADDRS; __eodSend(req); - zt_eod_msg_getbindaddrsresp *resp; + zt_eod_msg_getbindaddrsresp* resp; unsigned char buf[ZT_EOD_MAXMSGSIZE]; - int r = __eodWait(ZT_EOD_MSG_GETBINDADDRSRESP, (unsigned char *)buf, sizeof(*resp), sizeof(buf)); - if (r < (int)sizeof(*resp)) return false; + int r = __eodWait(ZT_EOD_MSG_GETBINDADDRSRESP, (unsigned char*)buf, sizeof(*resp), sizeof(buf)); + if (r < (int)sizeof(*resp)) { + return false; + } int c = (r - (int)sizeof(*resp)) / sizeof(resp->addrs[0]); - resp = (zt_eod_msg_getbindaddrsresp *)buf; + resp = (zt_eod_msg_getbindaddrsresp*)buf; for (int i = 0; i < c; ++i) { - ret[InetAddress(resp->addrs[i].data, resp->addrs[i].afi == 1 ? 4 : 16, resp->addrs[i].len)] - = resp->addrs[i].ifname; + ret[InetAddress(resp->addrs[i].data, resp->addrs[i].afi == 1 ? 4 : 16, resp->addrs[i].len)] = resp->addrs[i].ifname; } return resp->result; } ExtOsdepTap::ExtOsdepTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _mac(mac), - _homePath(homePath), - _mtu(mtu), - _fd(0), - _enabled(true), - _run(true) - { + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg) + : _handler(handler) + , _arg(arg) + , _nwid(nwid) + , _mac(mac) + , _homePath(homePath) + , _mtu(mtu) + , _fd(0) + , _enabled(true) + , _run(true) +{ zt_eod_msg_addtap req; req.cmd = ZT_EOD_MSG_ADDTAP; req.nwid = nwid; @@ -243,131 +293,147 @@ ExtOsdepTap::ExtOsdepTap( Mutex::Lock l(eodMutex); __eodSend(req); _fd = -1; - if (__eodWait(ZT_EOD_MSG_ADDTAPRESP, (unsigned char *)&resp, sizeof(resp), sizeof(resp), &_fd) != sizeof(resp)) + if (__eodWait(ZT_EOD_MSG_ADDTAPRESP, (unsigned char*)&resp, sizeof(resp), sizeof(resp), &_fd) != sizeof(resp)) { throw std::runtime_error(std::string("could not create TAP")); + } _dev = resp.name; - if (_dev.empty() || _fd < 0) + if (_dev.empty() || _fd < 0) { throw std::runtime_error(std::string("could not create TAP")); + } - fcntl(_fd,F_SETFL,O_NONBLOCK); + fcntl(_fd, F_SETFL, O_NONBLOCK); - // processing shamelessly copied from LinuxEthernetTap - (void)::pipe(_shutdownSignalPipe); - for(unsigned int t=0;t<2;++t) { - _tapReaderThread[t] = std::thread([this, t]{ - fd_set readfds,nullfds; - int n,nfds,r; - void *buf = nullptr; - std::vector buffers; + (void)::pipe(_shutdownSignalPipe); + for (unsigned int t = 0; t < 2; ++t) { + _tapReaderThread[t] = std::thread([this, t] { + fd_set readfds, nullfds; + int n, nfds, r; + void* buf = nullptr; + std::vector buffers; - if (!_run) - return; + if (! _run) { + return; + } - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; + FD_ZERO(&readfds); + FD_ZERO(&nullfds); + nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1; - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); + r = 0; + for (;;) { + FD_SET(_shutdownSignalPipe[0], &readfds); + FD_SET(_fd, &readfds); + select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0); - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; + if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) { // writes to shutdown pipe terminate thread + break; + } - if (FD_ISSET(_fd,&readfds)) { - for(;;) { // read until there are no more packets, then return to outer select() loop - if (!buf) { - // To reduce use of the mutex, we keep a local buffer vector and - // swap (which is a pointer swap) with the global one when it's - // empty. This retrieves a batch of buffers to use. - if (buffers.empty()) { - std::lock_guard l(_buffers_l); - buffers.swap(_buffers); - } - if (buffers.empty()) { - buf = malloc(ZT_TAP_BUF_SIZE); - if (!buf) - break; - } else { - buf = buffers.back(); - buffers.pop_back(); - } - } + if (FD_ISSET(_fd, &readfds)) { + for (;;) { // read until there are no more packets, then return to outer select() loop + if (! buf) { + // To reduce use of the mutex, we keep a local buffer vector and + // swap (which is a pointer swap) with the global one when it's + // empty. This retrieves a batch of buffers to use. + if (buffers.empty()) { + std::lock_guard l(_buffers_l); + buffers.swap(_buffers); + } + if (buffers.empty()) { + buf = malloc(ZT_TAP_BUF_SIZE); + if (! buf) { + break; + } + } + else { + buf = buffers.back(); + buffers.pop_back(); + } + } - n = (int)::read(_fd,reinterpret_cast(buf) + r,ZT_TAP_BUF_SIZE - r); - if (n > 0) { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; + n = (int)::read(_fd, reinterpret_cast(buf) + r, ZT_TAP_BUF_SIZE - r); + if (n > 0) { + // Some tap drivers like to send the ethernet frame and the + // payload in two chunks, so handle that by accumulating + // data until we have at least a frame. + r += n; + if (r > 14) { + if (r > ((int)_mtu + 14)) { // sanity check for weird TAP behavior on some platforms + r = _mtu + 14; + } - if (_enabled && _tapqsize.load() < 1000) { + if (_enabled && _tapqsize.load() < 1000) { ++_tapqsize; - _tapq.post(std::pair(buf,r)); - buf = nullptr; - } + _tapq.post(std::pair(buf, r)); + buf = nullptr; + } - r = 0; - } - } else { - r = 0; - break; - } - } - } - } - }); - } + r = 0; + } + } + else { + r = 0; + break; + } + } + } + } + }); + } - _tapProcessorThread = std::thread([this] { - MAC to,from; - std::pair qi; - while (_tapq.get(qi)) { + _tapProcessorThread = std::thread([this] { + MAC to, from; + std::pair qi; + while (_tapq.get(qi)) { --_tapqsize; - uint8_t *const b = reinterpret_cast(qi.first); - if (b) { - to.setTo(b, 6); - from.setTo(b + 6, 6); - unsigned int etherType = Utils::ntoh(((const uint16_t *)b)[6]); - _handler(_arg, nullptr, _nwid, from, to, etherType, 0, (const void *)(b + 14),(unsigned int)(qi.second - 14)); - { - std::lock_guard l(_buffers_l); - if (_buffers.size() < 128) - _buffers.push_back(qi.first); - else free(qi.first); - } - } else break; - } - }); + uint8_t* const b = reinterpret_cast(qi.first); + if (b) { + to.setTo(b, 6); + from.setTo(b + 6, 6); + unsigned int etherType = Utils::ntoh(((const uint16_t*)b)[6]); + _handler(_arg, nullptr, _nwid, from, to, etherType, 0, (const void*)(b + 14), (unsigned int)(qi.second - 14)); + { + std::lock_guard l(_buffers_l); + if (_buffers.size() < 128) { + _buffers.push_back(qi.first); + } + else { + free(qi.first); + } + } + } + else { + break; + } + } + }); } -ExtOsdepTap::~ExtOsdepTap() { - _run = false; +ExtOsdepTap::~ExtOsdepTap() +{ + _run = false; - (void)::write(_shutdownSignalPipe[1],"\0",1); // causes reader thread(s) to exit - _tapq.post(std::pair(nullptr,0)); // causes processor thread to exit + (void)::write(_shutdownSignalPipe[1], "\0", 1); // causes reader thread(s) to exit + _tapq.post(std::pair(nullptr, 0)); // causes processor thread to exit - _tapReaderThread[0].join(); - _tapReaderThread[1].join(); - _tapProcessorThread.join(); + _tapReaderThread[0].join(); + _tapReaderThread[1].join(); + _tapProcessorThread.join(); - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); + ::close(_fd); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); - for(std::vector::iterator i(_buffers.begin());i!=_buffers.end();++i) - free(*i); - std::vector< std::pair > dv(_tapq.drain()); - for(std::vector< std::pair >::iterator i(dv.begin());i!=dv.end();++i) { - if (i->first) - free(i->first); - } + for (std::vector::iterator i(_buffers.begin()); i != _buffers.end(); ++i) { + free(*i); + } + std::vector > dv(_tapq.drain()); + for (std::vector >::iterator i(dv.begin()); i != dv.end(); ++i) { + if (i->first) { + free(i->first); + } + } zt_eod_msg_deltap req; req.cmd = ZT_EOD_MSG_DELTAP; @@ -377,15 +443,18 @@ ExtOsdepTap::~ExtOsdepTap() { eodXchg(req, ZT_EOD_MSG_DELTAPRESP, resp); } -void ExtOsdepTap::setEnabled(bool en) { - _enabled = en; +void ExtOsdepTap::setEnabled(bool en) +{ + _enabled = en; } -bool ExtOsdepTap::enabled() const { - return _enabled; +bool ExtOsdepTap::enabled() const +{ + return _enabled; } -void ExtOsdepTap::doRemoveIp(const InetAddress &ip) { +void ExtOsdepTap::doRemoveIp(const InetAddress& ip) +{ zt_eod_msg_ip req; req.cmd = ZT_EOD_MSG_DELIP; strcpy(req.name, _dev.c_str()); @@ -397,13 +466,18 @@ void ExtOsdepTap::doRemoveIp(const InetAddress &ip) { __eodXchg(req, ZT_EOD_MSG_DELIPRESP, resp); } -bool ExtOsdepTap::addIp(const InetAddress &ip) { +bool ExtOsdepTap::addIp(const InetAddress& ip) +{ Mutex::Lock l(eodMutex); - for(auto i = allIps.begin();i!=allIps.end();++i) { - if (*i == ip) return true; - if (i->ipsEqual(ip)) doRemoveIp(*i); - } + for (auto i = allIps.begin(); i != allIps.end(); ++i) { + if (*i == ip) { + return true; + } + if (i->ipsEqual(ip)) { + doRemoveIp(*i); + } + } zt_eod_msg_ip req; req.cmd = ZT_EOD_MSG_ADDIP; @@ -419,20 +493,24 @@ bool ExtOsdepTap::addIp(const InetAddress &ip) { return true; } -bool ExtOsdepTap::addIps(std::vector ips) { +bool ExtOsdepTap::addIps(std::vector ips) +{ return false; } -bool ExtOsdepTap::removeIp(const InetAddress &ip) { + +bool ExtOsdepTap::removeIp(const InetAddress& ip) +{ Mutex::Lock l(eodMutex); - for(auto i = allIps.begin();i!=allIps.end();++i) { + for (auto i = allIps.begin(); i != allIps.end(); ++i) { if (*i == ip) { doRemoveIp(*i); return true; } - } + } return false; } -std::vector ExtOsdepTap::ips() const { +std::vector ExtOsdepTap::ips() const +{ std::vector ret; Mutex::Lock l(eodMutex); @@ -442,84 +520,100 @@ std::vector ExtOsdepTap::ips() const { strcpy(req.name, _dev.c_str()); __eodSend(req); - zt_eod_msg_getipsresp *resp; + zt_eod_msg_getipsresp* resp; unsigned char buf[ZT_EOD_MAXMSGSIZE]; - int r = __eodWait(ZT_EOD_MSG_GETIPSRESP, (unsigned char *)buf, sizeof(*resp), sizeof(buf)); - if (r < (int)sizeof(*resp)) return ret; + int r = __eodWait(ZT_EOD_MSG_GETIPSRESP, (unsigned char*)buf, sizeof(*resp), sizeof(buf)); + if (r < (int)sizeof(*resp)) { + return ret; + } int c = (r - (int)sizeof(*resp)) / sizeof(resp->addrs[0]); - resp = (zt_eod_msg_getipsresp *)buf; + resp = (zt_eod_msg_getipsresp*)buf; for (int i = 0; i < c; ++i) { ret.push_back(InetAddress(resp->addrs[i].data, resp->addrs[i].afi == 1 ? 4 : 16, resp->addrs[i].len)); } return ret; } -void ExtOsdepTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) { - char putBuf[ZT_MAX_MTU + 64]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - (void)::write(_fd,putBuf,len); - } +void ExtOsdepTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) +{ + char putBuf[ZT_MAX_MTU + 64]; + if ((_fd > 0) && (len <= _mtu) && (_enabled)) { + to.copyTo(putBuf, 6); + from.copyTo(putBuf + 6, 6); + *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType); + memcpy(putBuf + 14, data, len); + len += 14; + (void)::write(_fd, putBuf, len); + } } -std::string ExtOsdepTap::deviceName() const { +std::string ExtOsdepTap::deviceName() const +{ return _dev; } -void ExtOsdepTap::setFriendlyName(const char *friendlyName) {} - -void ExtOsdepTap::scanMulticastGroups(std::vector &added,std::vector &removed) { - char *ptr,*ptr2; - unsigned char mac[6]; - std::vector newGroups; - - int fd = ::open("/proc/net/dev_mcast",O_RDONLY); - if (fd > 0) { - char buf[131072]; - int n = (int)::read(fd,buf,sizeof(buf)); - if ((n > 0)&&(n < (int)sizeof(buf))) { - buf[n] = (char)0; - for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) { - int fno = 0; - char *devname = (char *)0; - char *mcastmac = (char *)0; - for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) { - if (fno == 1) - devname = f; - else if (fno == 4) - mcastmac = f; - ++fno; - } - if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6)) - newGroups.push_back(MulticastGroup(MAC(mac,6),0)); - } - } - ::close(fd); - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); +void ExtOsdepTap::setFriendlyName(const char* friendlyName) +{ } -void ExtOsdepTap::setMtu(unsigned int mtu) { - if (mtu == _mtu) return; + +void ExtOsdepTap::scanMulticastGroups(std::vector& added, std::vector& removed) +{ + char *ptr, *ptr2; + unsigned char mac[6]; + std::vector newGroups; + + int fd = ::open("/proc/net/dev_mcast", O_RDONLY); + if (fd > 0) { + char buf[131072]; + int n = (int)::read(fd, buf, sizeof(buf)); + if ((n > 0) && (n < (int)sizeof(buf))) { + buf[n] = (char)0; + for (char* l = strtok_r(buf, "\r\n", &ptr); (l); l = strtok_r((char*)0, "\r\n", &ptr)) { + int fno = 0; + char* devname = (char*)0; + char* mcastmac = (char*)0; + for (char* f = strtok_r(l, " \t", &ptr2); (f); f = strtok_r((char*)0, " \t", &ptr2)) { + if (fno == 1) { + devname = f; + } + else if (fno == 4) { + mcastmac = f; + } + ++fno; + } + if ((devname) && (! strcmp(devname, _dev.c_str())) && (mcastmac) && (Utils::unhex(mcastmac, mac, 6) == 6)) { + newGroups.push_back(MulticastGroup(MAC(mac, 6), 0)); + } + } + } + ::close(fd); + } + + std::vector allIps(ips()); + for (std::vector::iterator ip(allIps.begin()); ip != allIps.end(); ++ip) { + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + } + + std::sort(newGroups.begin(), newGroups.end()); + newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end()); + + for (std::vector::iterator m(newGroups.begin()); m != newGroups.end(); ++m) { + if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m)) { + added.push_back(*m); + } + } + for (std::vector::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) { + if (! std::binary_search(newGroups.begin(), newGroups.end(), *m)) { + removed.push_back(*m); + } + } + + _multicastGroups.swap(newGroups); +} +void ExtOsdepTap::setMtu(unsigned int mtu) +{ + if (mtu == _mtu) { + return; + } _mtu = mtu; zt_eod_msg_setmtu req; @@ -531,4 +625,4 @@ void ExtOsdepTap::setMtu(unsigned int mtu) { eodXchg(req, ZT_EOD_MSG_SETMTURESP, resp); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/ExtOsdep.hpp b/osdep/ExtOsdep.hpp index a224c467d..328d00619 100644 --- a/osdep/ExtOsdep.hpp +++ b/osdep/ExtOsdep.hpp @@ -1,3 +1,16 @@ +/* + * 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_EXTOSDEP_HPP #define ZT_EXTOSDEP_HPP @@ -5,25 +18,25 @@ #define ZT_EOD_MAXMSGSIZE (64 * 1024) -#define ZT_EOD_MSG_STARTED 1 // no data -#define ZT_EOD_MSG_ADDTAP 2 -#define ZT_EOD_MSG_ADDTAPRESP 3 -#define ZT_EOD_MSG_DELTAP 4 -#define ZT_EOD_MSG_DELTAPRESP 5 // no data -#define ZT_EOD_MSG_SETMTU 6 -#define ZT_EOD_MSG_SETMTURESP 7 -#define ZT_EOD_MSG_ADDIP 8 -#define ZT_EOD_MSG_ADDIPRESP 9 -#define ZT_EOD_MSG_DELIP 10 -#define ZT_EOD_MSG_DELIPRESP 11 -#define ZT_EOD_MSG_GETIPS 12 -#define ZT_EOD_MSG_GETIPSRESP 13 -#define ZT_EOD_MSG_GETBINDADDRS 14 +#define ZT_EOD_MSG_STARTED 1 // no data +#define ZT_EOD_MSG_ADDTAP 2 +#define ZT_EOD_MSG_ADDTAPRESP 3 +#define ZT_EOD_MSG_DELTAP 4 +#define ZT_EOD_MSG_DELTAPRESP 5 // no data +#define ZT_EOD_MSG_SETMTU 6 +#define ZT_EOD_MSG_SETMTURESP 7 +#define ZT_EOD_MSG_ADDIP 8 +#define ZT_EOD_MSG_ADDIPRESP 9 +#define ZT_EOD_MSG_DELIP 10 +#define ZT_EOD_MSG_DELIPRESP 11 +#define ZT_EOD_MSG_GETIPS 12 +#define ZT_EOD_MSG_GETIPSRESP 13 +#define ZT_EOD_MSG_GETBINDADDRS 14 #define ZT_EOD_MSG_GETBINDADDRSRESP 15 -#define ZT_EOD_MSG_ADDROUTE 16 -#define ZT_EOD_MSG_ADDROUTERESP 17 -#define ZT_EOD_MSG_DELROUTE 18 -#define ZT_EOD_MSG_DELROUTERESP 19 +#define ZT_EOD_MSG_ADDROUTE 16 +#define ZT_EOD_MSG_ADDROUTERESP 17 +#define ZT_EOD_MSG_DELROUTE 18 +#define ZT_EOD_MSG_DELROUTERESP 19 struct zt_eod_msg_addtap { unsigned char cmd; @@ -53,8 +66,8 @@ struct zt_eod_msg_setmtu { struct zt_eod_msg_ip { unsigned char cmd; char name[16]; - unsigned char afi; // 1 ip, 2 ip6 - unsigned char len; // bits in mask + unsigned char afi; // 1 ip, 2 ip6 + unsigned char len; // bits in mask unsigned char data[16]; } __attribute__((packed)); @@ -87,7 +100,7 @@ struct zt_eod_msg_getbindaddrsresp { struct zt_eod_msg_route { unsigned char cmd; - unsigned char afi; // 1 ip, 2 ip6 + unsigned char afi; // 1 ip, 2 ip6 unsigned char dstlen; unsigned char dst[16]; unsigned char gw[16]; @@ -110,89 +123,91 @@ struct zt_eod_mgmt_reply { #ifndef ZT_EXTOSDEP_IFACEONLY +#include "../node/AtomicCounter.hpp" +#include "../node/Hashtable.hpp" #include "../node/InetAddress.hpp" #include "../node/MAC.hpp" -#include "Thread.hpp" -#include "../node/Hashtable.hpp" #include "../node/Mutex.hpp" -#include "../node/AtomicCounter.hpp" -#include "EthernetTap.hpp" #include "BlockingQueue.hpp" +#include "EthernetTap.hpp" +#include "Thread.hpp" + #include -#include -#include #include +#include #include +#include namespace ZeroTier { class ExtOsdep { -public: + public: static void init(int, int); - static void started(int *, void **); + static void started(int*, void**); - static void routeAddDel(bool, const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); - static bool getBindAddrs(std::map &); + static void routeAddDel(bool, const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName); + static bool getBindAddrs(std::map&); - static bool mgmtRecv(void *cookie, void *data, unsigned long len, - std::function); - static bool mgmtWritable(void *); + static bool mgmtRecv(void* cookie, void* data, unsigned long len, std::function); + static bool mgmtWritable(void*); }; -class ExtOsdepTap : public EthernetTap -{ -public: +class ExtOsdepTap : public EthernetTap { + public: ExtOsdepTap( - const char *homePath, - const MAC &mac, + const char* homePath, + const MAC& mac, unsigned int mtu, unsigned int metric, uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); virtual ~ExtOsdepTap(); virtual void setEnabled(bool en); virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); + virtual bool addIp(const InetAddress& ip); virtual bool addIps(std::vector ips); - virtual bool removeIp(const InetAddress &ip); + virtual bool removeIp(const InetAddress& ip); virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len); virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); + virtual void setFriendlyName(const char* friendlyName); + virtual void scanMulticastGroups(std::vector& added, std::vector& removed); virtual void setMtu(unsigned int mtu); - virtual void setDns(const char *domain, const std::vector &servers) {} -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - MAC _mac; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; + virtual void setDns(const char* domain, const std::vector& servers) + { + } + + private: + void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int); + void* _arg; + uint64_t _nwid; + MAC _mac; + std::string _homePath; + std::string _dev; + std::vector _multicastGroups; + unsigned int _mtu; int _fd; - int _shutdownSignalPipe[2]; - std::atomic_bool _enabled; - std::atomic_bool _run; - std::thread _tapReaderThread[2]; - std::thread _tapProcessorThread; - std::mutex _buffers_l; - std::vector _buffers; - BlockingQueue< std::pair > _tapq; + int _shutdownSignalPipe[2]; + std::atomic_bool _enabled; + std::atomic_bool _run; + std::thread _tapReaderThread[2]; + std::thread _tapProcessorThread; + std::mutex _buffers_l; + std::vector _buffers; + BlockingQueue > _tapq; AtomicCounter _tapqsize; std::vector allIps; - void doRemoveIp(const InetAddress &); + void doRemoveIp(const InetAddress&); }; -} // namespace ZeroTier +} // namespace ZeroTier -#endif // ZT_EXTOSDEP_IFACEONLY -#endif // ZT_EXTOSDEP +#endif // ZT_EXTOSDEP_IFACEONLY +#endif // ZT_EXTOSDEP #endif From 05b60bd81868fefd67371498a9c70e93fb428f75 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 4 Mar 2025 10:25:06 -0800 Subject: [PATCH 5/8] Fix typo --- .../simpleapi/include/prometheus/simpleapi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h b/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h index 12e115844..73c340979 100644 --- a/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h +++ b/ext/prometheus-cpp-lite-1.0/simpleapi/include/prometheus/simpleapi.h @@ -19,7 +19,7 @@ #if UINTPTR_MAX == 0xffFFffFF // 32-bit -typedef uint32_tmetric_size; +typedef uint32_t metric_size; #elif UINTPTR_MAX == 0xffFFffFFffFFffFF // 64-bit typedef uint64_t metric_size; From 17abb5865116960ff69463f5f0238694ebf13ec0 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 4 Mar 2025 10:26:31 -0800 Subject: [PATCH 6/8] Add missing include to ExtOsDep.hpp --- osdep/ExtOsdep.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osdep/ExtOsdep.hpp b/osdep/ExtOsdep.hpp index 328d00619..f16893ced 100644 --- a/osdep/ExtOsdep.hpp +++ b/osdep/ExtOsdep.hpp @@ -16,6 +16,8 @@ #ifdef ZT_EXTOSDEP +#include + #define ZT_EOD_MAXMSGSIZE (64 * 1024) #define ZT_EOD_MSG_STARTED 1 // no data From 47e05d5a23f84bab873e2b49e20fd2d7db9cb30a Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 4 Mar 2025 10:34:57 -0800 Subject: [PATCH 7/8] Disable peer metrics for ExtOSDep builds --- make-linux.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/make-linux.mk b/make-linux.mk index 30eae3299..2087be694 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -351,6 +351,7 @@ ifeq ($(ZT_ARCHITECTURE),3) ifeq ($(ZT_EXTOSDEP), 0) override CFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s override CXXFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -fexceptions -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s + else override DEFS+=-DZT_NO_PEER_METRICS endif ZT_USE_ARM32_NEON_ASM_CRYPTO=0 From dcb4bc5ef44164f33cdc31b2d7af79162b8d91d6 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 4 Mar 2025 11:18:13 -0800 Subject: [PATCH 8/8] Fix path typo: 3rdpatry --- .../http-client-lite/CMakeLists.txt | 0 .../http-client-lite/LICENSE | 0 .../http-client-lite/README.md | 0 .../http-client-lite/examples/CMakeLists.txt | 0 .../examples/simple_request.cpp | 0 .../include/jdl/httpclientlite.h | 0 ext/prometheus-cpp-lite-1.0/CMakeLists.txt | 4 +- ext/prometheus-cpp-lite-1.0/README.md | 50 +++++++++++-------- 8 files changed, 32 insertions(+), 22 deletions(-) rename ext/prometheus-cpp-lite-1.0/{3rdpatry => 3rdparty}/http-client-lite/CMakeLists.txt (100%) rename ext/prometheus-cpp-lite-1.0/{3rdpatry => 3rdparty}/http-client-lite/LICENSE (100%) rename ext/prometheus-cpp-lite-1.0/{3rdpatry => 3rdparty}/http-client-lite/README.md (100%) rename ext/prometheus-cpp-lite-1.0/{3rdpatry => 3rdparty}/http-client-lite/examples/CMakeLists.txt (100%) rename ext/prometheus-cpp-lite-1.0/{3rdpatry => 3rdparty}/http-client-lite/examples/simple_request.cpp (100%) rename ext/prometheus-cpp-lite-1.0/{3rdpatry => 3rdparty}/http-client-lite/include/jdl/httpclientlite.h (100%) diff --git a/ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/CMakeLists.txt b/ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/CMakeLists.txt similarity index 100% rename from ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/CMakeLists.txt rename to ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/CMakeLists.txt diff --git a/ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/LICENSE b/ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/LICENSE similarity index 100% rename from ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/LICENSE rename to ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/LICENSE diff --git a/ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/README.md b/ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/README.md similarity index 100% rename from ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/README.md rename to ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/README.md diff --git a/ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/examples/CMakeLists.txt b/ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/examples/CMakeLists.txt similarity index 100% rename from ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/examples/CMakeLists.txt rename to ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/examples/CMakeLists.txt diff --git a/ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/examples/simple_request.cpp b/ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/examples/simple_request.cpp similarity index 100% rename from ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/examples/simple_request.cpp rename to ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/examples/simple_request.cpp diff --git a/ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/include/jdl/httpclientlite.h b/ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/include/jdl/httpclientlite.h similarity index 100% rename from ext/prometheus-cpp-lite-1.0/3rdpatry/http-client-lite/include/jdl/httpclientlite.h rename to ext/prometheus-cpp-lite-1.0/3rdparty/http-client-lite/include/jdl/httpclientlite.h diff --git a/ext/prometheus-cpp-lite-1.0/CMakeLists.txt b/ext/prometheus-cpp-lite-1.0/CMakeLists.txt index 390e9091a..899eca89d 100644 --- a/ext/prometheus-cpp-lite-1.0/CMakeLists.txt +++ b/ext/prometheus-cpp-lite-1.0/CMakeLists.txt @@ -5,7 +5,7 @@ option(PROMETHEUS_BUILD_EXAMPLES "Build with examples" OFF) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) -if(WIN32) +if(WIN32) # it prevent create Debug/ and Release folders in Visual Studio foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) @@ -25,7 +25,7 @@ add_subdirectory("./core") add_subdirectory("./simpleapi") -add_subdirectory("./3rdpatry/http-client-lite") +add_subdirectory("./3rdparty/http-client-lite") if(PROMETHEUS_BUILD_EXAMPLES) add_subdirectory("./examples") diff --git a/ext/prometheus-cpp-lite-1.0/README.md b/ext/prometheus-cpp-lite-1.0/README.md index 5aeae60d4..997e787d3 100644 --- a/ext/prometheus-cpp-lite-1.0/README.md +++ b/ext/prometheus-cpp-lite-1.0/README.md @@ -6,70 +6,81 @@ It is a tool for quickly adding metrics (and profiling) functionality to C++ pro 1. Written in pure C++, 2. Header-only, -2. Cross-platform, -3. Compiles with C ++ 11, C ++ 14, C ++ 17 standards, -4. Has no third-party dependencies, -5. Several APIs for use in your projects, -6. Saving metrics to a file (and then works with node_exporter) or sending via http (uses built-in header-only http-client-lite library), -7. Possiblity to use different types for storing metrics data (default is uint32_t, but you can use double or uint64_t types if you want), -8. Five types of metrics are supported: counter, gauge, summary, histogram and benchmark, +3. Cross-platform, +4. Compiles with C ++ 11, C ++ 14, C ++ 17 standards, +5. Has no third-party dependencies, +6. Several APIs for use in your projects, +7. Saving metrics to a file (and then works with node_exporter) or sending via http (uses built-in header-only http-client-lite library), +8. Possiblity to use different types for storing metrics data (default is uint32_t, but you can use double or uint64_t types if you want), +9. Five types of metrics are supported: counter, gauge, summary, histogram and benchmark, 10. Has detailed examples of use (see examples folder) ## How it differs from the [jupp0r/prometheus-cpp](https://github.com/jupp0r/prometheus-cpp) project: + 1. I need a simple header only wariant library without dependencies to write metrics to a .prom file, 2. I need the fastest possible work using integer values of counters (original project use only floating pointer values), 3. The origianl project have problems on compilers that do not know how to do LTO optimization, 4. I did not like the python style of the original project and the large amount of extra code in it and I wanted to make it lighter and more c++ classic. ## How to use it: + The library has two API: + 1. Complex API for those who want to control everything, 2. Simple API for those who want to quickly add metrics to their C ++ (and it is actually just a wrapper around the complex API). - ### Let's start with a simple API because it's simple: To add it to your C++ project add these lines to your CMakeLists.txt file: + ``` add_subdirectory("prometheus-cpp-lite/core") -add_subdirectory("prometheus-cpp-lite/3rdpatry/http-client-lite") +add_subdirectory("prometheus-cpp-lite/3rdparty/http-client-lite") add_subdirectory("prometheus-cpp-lite/simpleapi") target_link_libraries(your_target prometheus-cpp-simpleapi) ``` The simplest way to create a metric would be like this: -``` c++ + +```c++ prometheus::simpleapi::METRIC_metric_t metric1 { "metric1", "first simple metric without any tag" }; prometheus::simpleapi::METRIC_metric_t metric2 { "metric2", "second simple metric without any tag" }; ``` -where ```METRIC``` can be ```counter```, ```gauge```, ```summary```, ```histogram``` or ```benchmark```. + +where `METRIC` can be `counter`, `gauge`, `summary`, `histogram` or `benchmark`. If you want to access an existing metric again elsewhere in the code, you can do this: -``` c++ + +```c++ prometheus::simpleapi::METRIC_metric_t metric2_yet_another_link { "metric2", "" }; ``` + this works because when adding a metric, it checks whether there is already a metric with the same name and, if there is one, a link to it is returned. You can create a family of metrics (metrics with tags) as follows: -``` c++ + +```c++ prometheus::simpleapi::METRIC_family_t family { "metric_family", "metric family" }; prometheus::simpleapi::METRIC_metric_t metric1 { family.Add({{"name", "metric1"}}) }; prometheus::simpleapi::METRIC_metric_t metric2 { family.Add({{"name", "metric2"}}) }; ``` -where METRIC can be ```counter```, ```gauge```, ```summary```, ```histogram``` or ```benchmark```. + +where METRIC can be `counter`, `gauge`, `summary`, `histogram` or `benchmark`. Next, you can do the following things with metrics: -``` c++ + +```c++ metric++; // for increment it (only for counter and gauge metrics) metric += value; // for add value to metric (only for gauge metric) -metric -= value; // for sub value from metric (only for gauge metric) +metric -= value; // for sub value from metric (only for gauge metric) metric = value; // save current value (only gauge metrics) metric.start(); // start calculate time (only for benchmark metric) metric.stop(); // stop calculate time (only for benchmark metric) ``` You can change the settings of save (or send) metrics data as follows: -``` c++ + +```c++ prometheus::simpleapi::saver.set_delay(period_in_seconds); // change the period of saving (or sending) metrics data in seconds (5 seconds by default) prometheus::simpleapi::saver.set_out_file(filename); // change the name of the output file (metrics.prom by default) prometheus::simpleapi::saver.set_server_url(url); // change the name of prometheus server (unset by default) @@ -77,7 +88,7 @@ prometheus::simpleapi::saver.set_server_url(url); // change the name of ### Simple API complex example 1 (examples/simpleapi_example.cpp): -``` c++ +```c++ #include void main() { @@ -120,7 +131,7 @@ simple_counter_2 8 ### Simple API complex example 2 (examples/simpleapi_use_in_class_example.cpp): -``` c++ +```c++ #include using namespace prometheus::simpleapi; @@ -198,4 +209,3 @@ simple_benchmark_family{benchmark="2"} 1.48e-05 # TYPE simple_benchmark counter simple_benchmark 6.0503248 ``` -