From 0f49c7510bb4337b5f37c6e603ba0e16cb949f1c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 25 Feb 2021 10:49:35 -0500 Subject: [PATCH] Swap out warp for simple hyper web server in Rust, and we will use web sockets for webby-style communication since WebRTC is a mess. --- core/CAPI.cpp | 15 + core/Endpoint.cpp | 126 ++--- core/Endpoint.hpp | 8 +- core/zerotier.h | 27 +- osdep/rust-osdep.h | 25 + rust-zerotier-core/build.rs | 8 +- rust-zerotier-core/src/endpoint.rs | 2 +- rust-zerotier-core/src/inetaddress.rs | 18 + rust-zerotier-service/Cargo.lock | 622 +-------------------- rust-zerotier-service/Cargo.toml | 3 +- rust-zerotier-service/build.rs | 8 +- rust-zerotier-service/src/cli.rs | 2 +- rust-zerotier-service/src/fastudpsocket.rs | 61 +- rust-zerotier-service/src/getifaddrs.rs | 2 - rust-zerotier-service/src/log.rs | 10 +- rust-zerotier-service/src/main.rs | 1 + rust-zerotier-service/src/service.rs | 130 ++--- rust-zerotier-service/src/store.rs | 4 +- rust-zerotier-service/src/vnic/common.rs | 1 - rust-zerotier-service/src/weblistener.rs | 101 ++++ 20 files changed, 373 insertions(+), 801 deletions(-) create mode 100644 rust-zerotier-service/src/weblistener.rs diff --git a/core/CAPI.cpp b/core/CAPI.cpp index 1a97f8466..62565ada2 100644 --- a/core/CAPI.cpp +++ b/core/CAPI.cpp @@ -837,6 +837,21 @@ int ZT_InetAddress_isV6(const ZT_InetAddress *ia) return (int)(reinterpret_cast(ia))->isV6(); } +unsigned int ZT_InetAddress_ipBytes(const ZT_InetAddress *ia, void *buf) +{ + if (ia) { + switch(reinterpret_cast(ia)->as.sa.sa_family) { + case AF_INET: + ZeroTier::Utils::copy<4>(buf, &(reinterpret_cast(ia)->as.sa_in.sin_addr.s_addr)); + return 4; + case AF_INET6: + ZeroTier::Utils::copy<16>(buf, reinterpret_cast(ia)->as.sa_in6.sin6_addr.s6_addr); + return 16; + } + } + return 0; +} + enum ZT_InetAddress_IpScope ZT_InetAddress_ipScope(const ZT_InetAddress *ia) { if (likely(ia != nullptr)) diff --git a/core/Endpoint.cpp b/core/Endpoint.cpp index c69424982..357a8fd89 100644 --- a/core/Endpoint.cpp +++ b/core/Endpoint.cpp @@ -16,35 +16,60 @@ namespace ZeroTier { +static ZT_INLINE char s_endpointTypeChar(const ZT_EndpointType t) +{ + switch(t) { + default: return '0'; + case ZT_ENDPOINT_TYPE_ZEROTIER: return 'z'; + case ZT_ENDPOINT_TYPE_ETHERNET: return 'e'; + case ZT_ENDPOINT_TYPE_WIFI_DIRECT: return 'd'; + case ZT_ENDPOINT_TYPE_BLUETOOTH: return 'b'; + case ZT_ENDPOINT_TYPE_IP: return 'i'; + case ZT_ENDPOINT_TYPE_IP_UDP: return 'u'; + case ZT_ENDPOINT_TYPE_IP_TCP: return 't'; + case ZT_ENDPOINT_TYPE_IP_TCP_WS: return 'w'; + } +} + +static ZT_INLINE ZT_EndpointType s_charEndpointType(const char c) +{ + switch(c) { + default: return ZT_ENDPOINT_TYPE_NIL; + case 'z': return ZT_ENDPOINT_TYPE_ZEROTIER; + case 'e': return ZT_ENDPOINT_TYPE_ETHERNET; + case 'd': return ZT_ENDPOINT_TYPE_WIFI_DIRECT; + case 'b': return ZT_ENDPOINT_TYPE_BLUETOOTH; + case 'i': return ZT_ENDPOINT_TYPE_IP; + case 'u': return ZT_ENDPOINT_TYPE_IP_UDP; + case 't': return ZT_ENDPOINT_TYPE_IP_TCP; + case 'w': return ZT_ENDPOINT_TYPE_IP_TCP_WS; + } +} + char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept { - static const char *const s_endpointTypeChars = "0123456789"; - static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow"); static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow"); + s[0] = s_endpointTypeChar(this->type); switch (this->type) { default: // ZT_ENDPOINT_TYPE_NIL - s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_NIL]; s[1] = 0; break; case ZT_ENDPOINT_TYPE_ZEROTIER: - s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_ZEROTIER]; s[1] = '/'; zt().toString(s + 2); break; case ZT_ENDPOINT_TYPE_ETHERNET: case ZT_ENDPOINT_TYPE_WIFI_DIRECT: case ZT_ENDPOINT_TYPE_BLUETOOTH: - s[0] = s_endpointTypeChars[this->type]; s[1] = '/'; eth().toString(s + 2); break; case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: - s[0] = s_endpointTypeChars[this->type]; + case ZT_ENDPOINT_TYPE_IP_TCP_WS: s[1] = '/'; ip().toString(s + 2); break; @@ -56,81 +81,46 @@ char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept bool Endpoint::fromString(const char *s) noexcept { memoryZero(this); - if ((!s) || (!*s)) + if ((!s) || (!*s)) { + // Empty strings are considered NIL endpoints. return true; - - // Locate first slash, colon, and dot to help classify input. - const char *slash = nullptr, *colon = nullptr, *dot = nullptr; - for(const char *p=s;;++p) { - const char c = *p; - if (c != 0) { - switch (c) { - case '/': - slash = p; - break; - case ':': - colon = p; - break; - case '.': - dot = p; - break; - } - } else break; - } - - if ((slash != nullptr) && (((colon == nullptr) && (dot == nullptr)) || (colon > slash) || (dot > slash))) { - // Detect a fully specified endpoint of the form type/ip/port or type/other, - // but don't detect ip/port as a fully specified endpoint. - char tmp[16]; - for (unsigned int i=0;i<16;++i) { - const char ss = s[i]; - if (ss == '/') { - tmp[i] = 0; - break; - } - tmp[i] = ss; - } - tmp[15] = 0; - this->type = (ZT_EndpointType)Utils::strToUInt(tmp); - - ++slash; - switch (this->type) { + } else if (s[1] == '/') { + // type/ADDRESS is a fully qualified endpoint. + this->type = s_charEndpointType(s[0]); + switch(this->type) { case ZT_ENDPOINT_TYPE_NIL: break; - case ZT_ENDPOINT_TYPE_ZEROTIER: { - Fingerprint tmpfp; - if (!tmpfp.fromString(slash)) + case ZT_ENDPOINT_TYPE_ZEROTIER: + if (!s[2]) return false; - this->value.fp = tmpfp; - } break; + break; case ZT_ENDPOINT_TYPE_ETHERNET: case ZT_ENDPOINT_TYPE_WIFI_DIRECT: case ZT_ENDPOINT_TYPE_BLUETOOTH: { + if (!s[2]) + return false; MAC tmpmac; - tmpmac.fromString(slash); + tmpmac.fromString(s + 2); this->value.mac = tmpmac.toInt(); } break; case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: - if (!asInetAddress(this->value.ss).fromString(slash)) + case ZT_ENDPOINT_TYPE_IP_TCP_WS: { + if (!s[2]) return false; - default: - return false; + if (!asInetAddress(this->value.ss).fromString(s + 2)) + return false; + } break; } - } else if (((colon != nullptr) || (dot != nullptr)) && (slash != nullptr)) { - // Parse raw IP/port strings as IP_UDP endpoints. - this->type = ZT_ENDPOINT_TYPE_IP_UDP; - if (!asInetAddress(this->value.ss).fromString(s)) - return false; } else { - // A naked '0' can be a NIL endpoint. - if (Utils::strToUInt(s) != (unsigned int)ZT_ENDPOINT_TYPE_NIL) + // IP/port is parsed as an IP_UDP endpoint for backward compatibility. + if (strchr(s, '/')) { + return asInetAddress(this->value.ss).fromString(s); + } else { return false; + } } - - return true; } int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept @@ -160,7 +150,7 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: // Other IP types get serialized as new version Endpoint instances with type. data[0] = 16 + (uint8_t)this->type; return 1 + asInetAddress(this->value.ss).marshal(data + 1); @@ -216,7 +206,7 @@ int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: return asInetAddress(this->value.ss).unmarshal(data + 1, len - 1); default: @@ -246,7 +236,7 @@ bool Endpoint::operator==(const Endpoint &ep) const noexcept case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: return ip() == ep.ip(); default: return true; @@ -268,7 +258,7 @@ bool Endpoint::operator<(const Endpoint &ep) const noexcept case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: return ip() < ep.ip(); default: return true; diff --git a/core/Endpoint.hpp b/core/Endpoint.hpp index e291e905b..200c7f2b0 100644 --- a/core/Endpoint.hpp +++ b/core/Endpoint.hpp @@ -116,7 +116,7 @@ public: case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: return true; default: return false; @@ -138,12 +138,12 @@ public: case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: switch (ep.type) { case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: return ip().ipsEqual(ep.ip()); default: break; @@ -193,7 +193,7 @@ public: case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_TCP: - case ZT_ENDPOINT_TYPE_IP_HTTP: + case ZT_ENDPOINT_TYPE_IP_TCP_WS: return ip().hashCode(); } } diff --git a/core/zerotier.h b/core/zerotier.h index 062c3ab10..b210c96b4 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -679,15 +679,15 @@ enum ZT_CredentialType */ enum ZT_EndpointType { - ZT_ENDPOINT_TYPE_NIL = 0, /* Nil/empty endpoint */ - ZT_ENDPOINT_TYPE_ZEROTIER = 1, /* ZeroTier relaying (address+fingerprint) */ - ZT_ENDPOINT_TYPE_ETHERNET = 2, /* Ethernet with ethertype 0x9993 */ - ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */ - ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */ - ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */ - ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP */ - ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */ - ZT_ENDPOINT_TYPE_IP_HTTP = 8 /* IP/HTTP encapsulation */ + ZT_ENDPOINT_TYPE_NIL = 0, /* Nil/empty endpoint */ + ZT_ENDPOINT_TYPE_ZEROTIER = 1, /* ZeroTier relaying (address+fingerprint) */ + ZT_ENDPOINT_TYPE_ETHERNET = 2, /* Ethernet with ethertype 0x9993 */ + ZT_ENDPOINT_TYPE_WIFI_DIRECT = 3, /* Ethernet using WiFi direct */ + ZT_ENDPOINT_TYPE_BLUETOOTH = 4, /* Bluetooth (same address type as Ethernet) */ + ZT_ENDPOINT_TYPE_IP = 5, /* Naked IP (protocol 193) */ + ZT_ENDPOINT_TYPE_IP_UDP = 6, /* IP/UDP */ + ZT_ENDPOINT_TYPE_IP_TCP = 7, /* IP/TCP */ + ZT_ENDPOINT_TYPE_IP_TCP_WS = 8 /* IP/TCP web sockets */ }; /** @@ -3021,6 +3021,15 @@ ZT_SDK_API int ZT_InetAddress_isV4(const ZT_InetAddress *ia); */ ZT_SDK_API int ZT_InetAddress_isV6(const ZT_InetAddress *ia); +/** + * Fill buffer with IP address bytes, return length in bytes + * + * @param ia InetAddress to access + * @param buf Buffer with at least 16 bytes of space (to hold IPv6) + * @return 0 on failure or nil, 4 if buf contains IPv4 IP, 16 if buf contains IPv6 IP + */ +ZT_SDK_API unsigned int ZT_InetAddress_ipBytes(const ZT_InetAddress *ia, void *buf); + /** * Classify the network scope of this IP address (local net, global, etc.) */ diff --git a/osdep/rust-osdep.h b/osdep/rust-osdep.h index e9ec3ab06..3116767e6 100644 --- a/osdep/rust-osdep.h +++ b/osdep/rust-osdep.h @@ -15,6 +15,8 @@ #include #include +/********************************************************************************************************************/ + #ifdef __APPLE__ #include #include @@ -67,6 +69,29 @@ extern const unsigned long c_SIOCAUTOCONF_STOP; /********************************************************************************************************************/ +#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* __linux__ */ + +/********************************************************************************************************************/ + #ifdef __cplusplus extern "C" { #endif diff --git a/rust-zerotier-core/build.rs b/rust-zerotier-core/build.rs index 788b9dafc..f5a806a82 100644 --- a/rust-zerotier-core/build.rs +++ b/rust-zerotier-core/build.rs @@ -1,6 +1,12 @@ +#[allow(unused_assignments)] fn main() { let d = env!("CARGO_MANIFEST_DIR"); println!("cargo:rustc-link-search=native={}/../build/core", d); println!("cargo:rustc-link-lib=static=zt_core"); - println!("cargo:rustc-link-lib=c++"); + + let mut cpplib = "c++"; + #[cfg(target_os = "linux")] { + cpplib = "stdc++"; + } + println!("cargo:rustc-link-lib={}", cpplib); } diff --git a/rust-zerotier-core/src/endpoint.rs b/rust-zerotier-core/src/endpoint.rs index 5a787bbad..c09f8f054 100644 --- a/rust-zerotier-core/src/endpoint.rs +++ b/rust-zerotier-core/src/endpoint.rs @@ -31,7 +31,7 @@ pub enum EndpointType { Ip = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP as isize, IpUdp = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_UDP as isize, IpTcp = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_TCP as isize, - IpHttp = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_HTTP as isize, + IpTcpWs = ztcore::ZT_EndpointType_ZT_ENDPOINT_TYPE_IP_TCP_WS as isize, } pub struct Endpoint { diff --git a/rust-zerotier-core/src/inetaddress.rs b/rust-zerotier-core/src/inetaddress.rs index b98fb9c27..b19dad79f 100644 --- a/rust-zerotier-core/src/inetaddress.rs +++ b/rust-zerotier-core/src/inetaddress.rs @@ -21,6 +21,7 @@ use num_traits::FromPrimitive; use crate::*; use crate::capi as ztcore; +use std::net::{SocketAddr, IpAddr, Ipv4Addr}; // WARNING: here be dragons! This defines an opaque blob in Rust that shadows // and is of the exact size as an opaque blob in C that shadows and is the @@ -246,6 +247,23 @@ impl InetAddress { } InetAddressFamily::Nil } + + /// Convert to std::net::SocketAddr for use with std::net APIs + pub fn to_socketaddr(&self) -> Option { + let mut buf: MaybeUninit<[u8; 16]> = MaybeUninit::uninit(); + let len; + let buf = unsafe { + len = ztcore::ZT_InetAddress_ipBytes(self.as_capi_ptr(), buf.as_mut_ptr().cast()); + buf.assume_init() + }; + if len == 4 { + Some(SocketAddr::new(IpAddr::from(Ipv4Addr::new(buf[0], buf[1], buf[2], buf[3])), self.port())) + } else if len == 16 { + Some(SocketAddr::new(IpAddr::from(buf), self.port())) + } else { + None + } + } } impl ToString for InetAddress { diff --git a/rust-zerotier-service/Cargo.lock b/rust-zerotier-service/Cargo.lock index 4b2bed581..22d704588 100644 --- a/rust-zerotier-service/Cargo.lock +++ b/rust-zerotier-service/Cargo.lock @@ -26,70 +26,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.3", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" - [[package]] name = "bytes" version = "1.0.1" @@ -137,52 +79,12 @@ dependencies = [ "vec_map", ] -[[package]] -name = "cpuid-bool" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.3", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "form_urlencoded" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" -dependencies = [ - "matches", - "percent-encoding", -] - [[package]] name = "futures" version = "0.3.12" @@ -278,47 +180,6 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.10.1+wasi-snapshot-preview1", -] - [[package]] name = "h2" version = "0.3.0" @@ -345,31 +206,6 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -[[package]] -name = "headers" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62689dc57c7456e69712607ffcbd0aa1dfcccf9af73727e9b25bc1825375cac3" -dependencies = [ - "base64", - "bitflags", - "bytes", - "headers-core", - "http", - "mime", - "sha-1 0.8.2", - "time", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - [[package]] name = "hermit-abi" version = "0.1.17" @@ -434,7 +270,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project 1.0.4", + "pin-project", "socket2", "tokio", "tower-service", @@ -442,17 +278,6 @@ dependencies = [ "want", ] -[[package]] -name = "idna" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "1.6.1" @@ -463,15 +288,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "input_buffer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" -dependencies = [ - "bytes", -] - [[package]] name = "itoa" version = "0.4.7" @@ -499,34 +315,12 @@ dependencies = [ "cfg-if 0.1.10", ] -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "mime_guess" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "mio" version = "0.7.7" @@ -551,21 +345,14 @@ dependencies = [ ] [[package]] -name = "multipart" -version = "0.17.1" +name = "net2" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand 0.7.3", - "safemem", - "tempfile", - "twoway", + "cfg-if 0.1.10", + "libc", + "winapi", ] [[package]] @@ -623,51 +410,13 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pin-project" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" -dependencies = [ - "pin-project-internal 0.4.27", -] - [[package]] name = "pin-project" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2" dependencies = [ - "pin-project-internal 1.0.4", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "pin-project-internal", ] [[package]] @@ -693,12 +442,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -720,12 +463,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.8" @@ -735,123 +472,12 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e" -dependencies = [ - "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.1", - "rand_hc 0.3.0", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.1", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" -dependencies = [ - "getrandom 0.2.2", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core 0.6.1", -] - -[[package]] -name = "redox_syscall" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" -dependencies = [ - "bitflags", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "serde" version = "1.0.119" @@ -883,43 +509,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - -[[package]] -name = "sha-1" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3cdf1b5e620a498ee6f2a171885ac7e22f0e12089ec4b3d22b84921792507c" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpuid-bool", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - [[package]] name = "signal-hook-registry" version = "1.3.0" @@ -963,20 +552,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "rand 0.8.2", - "redox_syscall", - "remove_dir_all", - "winapi", -] - [[package]] name = "term_size" version = "0.3.2" @@ -1007,21 +582,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tinyvec" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - [[package]] name = "tokio" version = "1.0.2" @@ -1051,35 +611,11 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-stream" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1a5f475f1b9d077ea1017ecbc60890fda8e54942d680ca0b1d2b47cfa2d861b" -dependencies = [ - "futures-util", - "log", - "pin-project 1.0.4", - "tokio", - "tungstenite", -] - [[package]] name = "tokio-util" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ae4751faa60b9f96dd8344d74592e5a17c0c9a220413dbc6942d14139bbfcc" +checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b" dependencies = [ "bytes", "futures-core", @@ -1087,7 +623,6 @@ dependencies = [ "log", "pin-project-lite", "tokio", - "tokio-stream", ] [[package]] @@ -1103,7 +638,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" dependencies = [ "cfg-if 1.0.0", - "log", "pin-project-lite", "tracing-core", ] @@ -1119,11 +653,11 @@ dependencies = [ [[package]] name = "tracing-futures" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 0.4.27", + "pin-project", "tracing", ] @@ -1133,67 +667,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "tungstenite" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" -dependencies = [ - "base64", - "byteorder", - "bytes", - "http", - "httparse", - "input_buffer", - "log", - "rand 0.8.2", - "sha-1 0.9.2", - "url", - "utf-8", -] - -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - -[[package]] -name = "typenum" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-width" version = "0.1.8" @@ -1206,36 +679,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -[[package]] -name = "url" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" - [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -[[package]] -name = "version_check" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - [[package]] name = "want" version = "0.3.0" @@ -1246,48 +695,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "warp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dafd0aac2818a94a34df0df1100a7356c493d8ede4393875fd0b5c51bb6bc80" -dependencies = [ - "bytes", - "futures", - "headers", - "http", - "hyper", - "log", - "mime", - "mime_guess", - "multipart", - "percent-encoding", - "pin-project 1.0.4", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tokio-util", - "tower-service", - "tracing", - "tracing-futures", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" - [[package]] name = "winapi" version = "0.3.9" @@ -1329,14 +736,15 @@ dependencies = [ "clap", "futures", "hex", + "hyper", "lazy_static", + "net2", "num-derive", "num-traits", "num_cpus", "serde", "serde_json", "tokio", - "warp", "winapi", "zerotier-core", ] diff --git a/rust-zerotier-service/Cargo.toml b/rust-zerotier-service/Cargo.toml index fda519f6c..feb514188 100644 --- a/rust-zerotier-service/Cargo.toml +++ b/rust-zerotier-service/Cargo.toml @@ -11,7 +11,6 @@ build = "build.rs" zerotier-core = { path = "../rust-zerotier-core" } num_cpus = "1" tokio = { version = "1", features = ["rt", "net", "time", "signal", "macros"] } -warp = "0" serde = { version = "1", features = ["derive"] } serde_json = "1" futures = "0" @@ -21,6 +20,8 @@ hex = "0" lazy_static = "1" num-traits = "0" num-derive = "0" +hyper = { version = "0", features = ["http1", "http2", "runtime", "server", "client", "tcp", "stream"] } +net2 = "0" [target."cfg(windows)".dependencies] winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] } diff --git a/rust-zerotier-service/build.rs b/rust-zerotier-service/build.rs index ff5ce3db2..7cd4e3811 100644 --- a/rust-zerotier-service/build.rs +++ b/rust-zerotier-service/build.rs @@ -1,8 +1,14 @@ +#[allow(unused_assignments)] fn main() { let d = env!("CARGO_MANIFEST_DIR"); println!("cargo:rustc-link-search=native={}/../build/core", d); println!("cargo:rustc-link-search=native={}/../build/osdep", d); println!("cargo:rustc-link-lib=static=zt_core"); println!("cargo:rustc-link-lib=static=zt_osdep"); - println!("cargo:rustc-link-lib=c++"); + + let mut cpplib = "c++"; + #[cfg(target_os = "linux")] { + cpplib = "stdc++"; + } + println!("cargo:rustc-link-lib={}", cpplib); } diff --git a/rust-zerotier-service/src/cli.rs b/rust-zerotier-service/src/cli.rs index 325fc1b5f..2198ee448 100644 --- a/rust-zerotier-service/src/cli.rs +++ b/rust-zerotier-service/src/cli.rs @@ -105,7 +105,7 @@ Advanced Operations: · export [path] Export a certificate from this node · delete Delete certificate from this node - · Command requires a running node and access to a local API token. +· Command requires a running node and access to a local API token. An
may be specified as a 10-digit short ZeroTier address, a fingerprint containing both an address and a SHA384 hash, or an identity. diff --git a/rust-zerotier-service/src/fastudpsocket.rs b/rust-zerotier-service/src/fastudpsocket.rs index 31d8d1332..730edd5e4 100644 --- a/rust-zerotier-service/src/fastudpsocket.rs +++ b/rust-zerotier-service/src/fastudpsocket.rs @@ -48,10 +48,7 @@ pub(crate) fn test_bind_udp(port: u16) -> (bool, bool) { (v4b.is_ok(), v6b.is_ok()) } -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// bind_udp_socket() implementations for each platform - -#[cfg(target_os = "macos")] +#[cfg(unix)] fn bind_udp_socket(_: &str, address: &InetAddress) -> Result { unsafe { let af; @@ -60,17 +57,20 @@ fn bind_udp_socket(_: &str, address: &InetAddress) -> Result { af = osdep::AF_INET; sa_len = std::mem::size_of::() as osdep::socklen_t; - }, + } InetAddressFamily::IPv6 => { af = osdep::AF_INET6; sa_len = std::mem::size_of::() as osdep::socklen_t; - }, + } _ => { return Err("unrecognized address family"); } }; - let s = osdep::socket(af.as_(), osdep::SOCK_DGRAM.as_(), 0); + #[cfg(not(target_os = "linux"))] + let s = osdep::socket(af.as_(), osdep::SOCK_DGRAM.as_(), 0); + #[cfg(target_os = "linux")] + let s = osdep::socket(af.as_(), 2, 0); if s < 0 { return Err("unable to create socket"); } @@ -79,37 +79,49 @@ fn bind_udp_socket(_: &str, address: &InetAddress) -> Result() as osdep::socklen_t; let mut setsockopt_results: c_int = 0; - // Set options that must succeed: reuse port for multithreading, enable broadcast, disable SIGPIPE, and - // for IPv6 sockets disable receipt of IPv4 packets. fl = 1; setsockopt_results |= osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_REUSEPORT.as_(), (&mut fl as *mut c_int).cast(), fl_size); //fl = 1; //setsockopt_results |= osdep::setsockopt(s, osdep::SOL_SOCKET, osdep::SO_REUSEADDR, (&mut fl as *mut c_int).cast(), fl_size); fl = 1; setsockopt_results |= osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_BROADCAST.as_(), (&mut fl as *mut c_int).cast(), fl_size); - fl = 1; - setsockopt_results |= osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_NOSIGPIPE.as_(), (&mut fl as *mut c_int).cast(), fl_size); if af == osdep::AF_INET6 { fl = 1; setsockopt_results |= osdep::setsockopt(s, osdep::IPPROTO_IPV6.as_(), osdep::IPV6_V6ONLY.as_(), (&mut fl as *mut c_int).cast(), fl_size); } + + #[cfg(any(target_os = "macos", target_os = "ios"))] { + fl = 1; + setsockopt_results |= osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_NOSIGPIPE.as_(), (&mut fl as *mut c_int).cast(), fl_size) + } + if setsockopt_results != 0 { osdep::close(s); return Err("setsockopt() failed"); } - // Enable UDP fragmentation, which should never really be needed but might make this work if - // somebody finds themselves on a weird network. These are okay if they fail. if af == osdep::AF_INET { - fl = 0; - osdep::setsockopt(s, osdep::IPPROTO_IP.as_(), 0x4000 /* IP_DF */, (&mut fl as *mut c_int).cast(), fl_size); - } - if af == osdep::AF_INET6 { - fl = 0; - osdep::setsockopt(s, osdep::IPPROTO_IPV6.as_(), 62 /* IPV6_DONTFRAG */, (&mut fl as *mut c_int).cast(), fl_size); + #[cfg(any(target_os = "macos", target_os = "ios"))] { + fl = 0; + osdep::setsockopt(s, osdep::IPPROTO_IP.as_(), 0x4000 /* IP_DF */, (&mut fl as *mut c_int).cast(), fl_size); + } + #[cfg(target_os = "linux")] { + fl = osdep::IP_PMTUDISC_DONT.as_(); + osdep::setsockopt(s, osdep::IPPROTO_IP.as_(), osdep::IP_MTU_DISCOVER.as_(), (&mut fl as *mut c_int).cast(), fl_size); + } + } + + if af == osdep::AF_INET6 { + #[cfg(any(target_os = "macos", target_os = "ios"))] { + fl = 0; + osdep::setsockopt(s, osdep::IPPROTO_IPV6.as_(), 62 /* IPV6_DONTFRAG */, (&mut fl as *mut c_int).cast(), fl_size); + } + #[cfg(target_os = "linux")] { + fl = 0; + osdep::setsockopt(s, osdep::IPPROTO_IPV6.as_(), osdep::IPV6_DONTFRAG.as_(), (&mut fl as *mut c_int).cast(), fl_size); + } } - // Set send and receive buffers to the largest acceptable value up to desired 1MiB. fl = 1048576; while fl >= 131072 { if osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_RCVBUF.as_(), (&mut fl as *mut c_int).cast(), fl_size) == 0 { @@ -135,8 +147,6 @@ fn bind_udp_socket(_: &str, address: &InetAddress) -> Result>, @@ -195,8 +205,7 @@ pub(crate) fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &I #[cfg(windows)] #[inline(always)] -pub(crate) fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &InetAddress, data: &[u8], packet_ttl: i32) { -} +pub(crate) fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &InetAddress, data: &[u8], packet_ttl: i32) {} #[cfg(unix)] #[inline(always)] @@ -211,11 +220,11 @@ impl FastUDPSocket { pub fn new(device_name: &str, address: &InetAddress, handler: F) -> Result { let thread_count = num_cpus::get_physical().min(num_cpus::get()); - let mut s = FastUDPSocket{ + let mut s = FastUDPSocket { thread_run: Arc::new(AtomicBool::new(true)), threads: Vec::new(), sockets: Vec::new(), - bind_address: address.clone() + bind_address: address.clone(), }; s.threads.reserve(thread_count); s.sockets.reserve(thread_count); diff --git a/rust-zerotier-service/src/getifaddrs.rs b/rust-zerotier-service/src/getifaddrs.rs index fa5afe505..8838ac63f 100644 --- a/rust-zerotier-service/src/getifaddrs.rs +++ b/rust-zerotier-service/src/getifaddrs.rs @@ -14,8 +14,6 @@ use std::mem::size_of; use std::ptr::{copy_nonoverlapping, null_mut}; -use num_traits::cast::AsPrimitive; - use zerotier_core::InetAddress; use crate::osdep as osdep; diff --git a/rust-zerotier-service/src/log.rs b/rust-zerotier-service/src/log.rs index 6c7acc466..49a3ba99a 100644 --- a/rust-zerotier-service/src/log.rs +++ b/rust-zerotier-service/src/log.rs @@ -11,14 +11,10 @@ */ /****/ -use std::cell::Cell; -use std::fmt::Display; use std::fs::{File, OpenOptions}; use std::io::{Seek, SeekFrom, Write, stderr}; use std::sync::Mutex; -use chrono::Datelike; - struct LogIntl { prefix: String, path: String, @@ -117,7 +113,7 @@ impl Log { } if l.log_to_stderr { - stderr().write_all(log_line.as_bytes()); + let _ = stderr().write_all(log_line.as_bytes()); } } } @@ -130,14 +126,14 @@ impl Log { pub fn debug>(&self, s: S) { let mut l = self.inner.lock().unwrap(); if l.debug { - self.log_internal(&mut (*l), s.as_ref(), "DEBUG"); + self.log_internal(&mut (*l), s.as_ref(), "DEBUG: "); } } pub fn fatal>(&self, s: S) { let mut l = self.inner.lock().unwrap(); let ss = s.as_ref(); - self.log_internal(&mut (*l), ss, "FATAL"); + self.log_internal(&mut (*l), ss, "FATAL: "); eprintln!("FATAL: {}", ss); } } diff --git a/rust-zerotier-service/src/main.rs b/rust-zerotier-service/src/main.rs index fa2a4a415..28b528d28 100644 --- a/rust-zerotier-service/src/main.rs +++ b/rust-zerotier-service/src/main.rs @@ -23,6 +23,7 @@ mod network; mod vnic; mod service; mod utils; +mod weblistener; #[allow(non_snake_case,non_upper_case_globals,non_camel_case_types,dead_code,improper_ctypes)] mod osdep; // bindgen generated diff --git a/rust-zerotier-service/src/service.rs b/rust-zerotier-service/src/service.rs index 2c861501c..9c9460a28 100644 --- a/rust-zerotier-service/src/service.rs +++ b/rust-zerotier-service/src/service.rs @@ -12,16 +12,15 @@ /****/ use std::collections::BTreeMap; -use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; use std::sync::{Arc, Mutex, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; -use futures::stream::StreamExt; -use warp::{Filter, Reply}; -use warp::http::{HeaderMap, Method, StatusCode}; -use warp::hyper::body::Bytes; +//use futures::stream::StreamExt; +//use warp::{Filter, Reply}; +//use warp::http::{HeaderMap, Method, StatusCode}; +//use warp::hyper::body::Bytes; use zerotier_core::*; use zerotier_core::trace::{TraceEvent, TraceEventLayer}; @@ -42,14 +41,14 @@ const CONFIG_CHECK_INTERVAL: i64 = 5000; /// threads are created (a rare event) so we only have to dereference each /// Arc once for common events like packet receipt. #[derive(Clone)] -struct Service { - auth_token: Arc, - log: Arc, +pub(crate) struct Service { + pub auth_token: Arc, + pub log: Arc, _local_config: Arc>>, // Arc -> shared Mutex container so it can be changed globally run: Arc, - online: Arc, - store: Arc, - node: Weak>, // weak since Node itself may hold a reference to this + pub online: Arc, + pub store: Arc, + pub node: Weak>, // weak since Node itself may hold a reference to this } impl NodeEventHandler for Service { @@ -67,18 +66,22 @@ impl NodeEventHandler for Service { d!(self.log, "node {} started up in data store '{}'", n.address().to_string(), self.store.base_path.to_str().unwrap()); }); }, + Event::Down => { d!(self.log, "node shutting down."); self.run.store(false, Ordering::Relaxed); }, + Event::Online => { d!(self.log, "node is online."); self.online.store(true, Ordering::Relaxed); }, + Event::Offline => { d!(self.log, "node is offline."); self.online.store(true, Ordering::Relaxed); }, + Event::Trace => { if !event_data.is_empty() { let _ = Dictionary::new_from_bytes(event_data).map(|tm| { @@ -98,13 +101,19 @@ impl NodeEventHandler for Service { }); } }, + Event::UserMessage => {}, } } #[inline(always)] fn state_put(&self, obj_type: StateObjectType, obj_id: &[u64], obj_data: &[u8]) -> std::io::Result<()> { - self.store.store_object(&obj_type, obj_id, obj_data) + if !obj_data.is_empty() { + self.store.store_object(&obj_type, obj_id, obj_data) + } else { + self.store.erase_object(&obj_type, obj_id); + Ok(()) + } } #[inline(always)] @@ -141,21 +150,6 @@ impl NodeEventHandler for Service { } impl Service { - #[inline(always)] - fn web_api_status(&self, remote: Option, method: Method, headers: HeaderMap, post_data: Bytes) -> Box { - Box::new(StatusCode::BAD_REQUEST) - } - - #[inline(always)] - fn web_api_network(&self, network_str: String, remote: Option, method: Method, headers: HeaderMap, post_data: Bytes) -> Box { - Box::new(StatusCode::BAD_REQUEST) - } - - #[inline(always)] - fn web_api_peer(&self, peer_str: String, remote: Option, method: Method, headers: HeaderMap, post_data: Bytes) -> Box { - Box::new(StatusCode::BAD_REQUEST) - } - #[inline(always)] fn local_config(&self) -> Arc { self._local_config.lock().unwrap().clone() @@ -187,7 +181,7 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { // Generate authtoken.secret from secure random bytes if not already set. let auth_token = auth_token.unwrap_or_else(|| -> String { d!(log, "authtoken.secret not found, generating new..."); - let mut rb = [0_u8; 64]; + let mut rb = [0_u8; 32]; unsafe { crate::osdep::getSecureRandom(rb.as_mut_ptr().cast(), 64) }; let mut generated_auth_token = String::new(); generated_auth_token.reserve(rb.len()); @@ -209,9 +203,7 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { } let auth_token = Arc::new(auth_token); - // From this point on we're in tokio / async. - let tokio_rt = tokio::runtime::Builder::new_current_thread().build().unwrap(); - tokio_rt.block_on(async { + let _ = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async { let mut udp_sockets: BTreeMap = BTreeMap::new(); let (mut interrupt_tx, mut interrupt_rx) = futures::channel::mpsc::channel::<()>(1); @@ -240,47 +232,45 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { loop { let mut local_config = service.local_config(); - d!(log, "starting local HTTP API server on 127.0.0.1 port {}", local_config.settings.primary_port); + /* + let web_service = warp::service(warp::any() + .and(warp::path::end().map(|| { warp::reply::with_status("404", StatusCode::NOT_FOUND) }) + .or(warp::path("status") + .and(warp::addr::remote()) + .and(warp::method()) + .and(warp::header::headers_cloned()) + .and(warp::body::content_length_limit(1048576)) + .and(warp::body::bytes()) + .map(move |remote: Option, method: Method, headers: HeaderMap, post_data: Bytes| { s0.web_api_status(remote, method, headers, post_data) })) + .or(warp::path!("network" / String) + .and(warp::addr::remote()) + .and(warp::method()) + .and(warp::header::headers_cloned()) + .and(warp::body::content_length_limit(1048576)) + .and(warp::body::bytes()) + .map(move |network_str: String, remote: Option, method: Method, headers: HeaderMap, post_data: Bytes| { s1.web_api_network(network_str, remote, method, headers, post_data) })) + .or(warp::path!("peer" / String) + .and(warp::addr::remote()) + .and(warp::method()) + .and(warp::header::headers_cloned()) + .and(warp::body::content_length_limit(1048576)) + .and(warp::body::bytes()) + .map(move |peer_str: String, remote: Option, method: Method, headers: HeaderMap, post_data: Bytes| { s2.web_api_peer(peer_str, remote, method, headers, post_data) })) + ) + ); + l!(log, "starting local HTTP API server on 127.0.0.1/{}", local_config.settings.primary_port); let (mut shutdown_tx, mut shutdown_rx) = futures::channel::oneshot::channel(); - let warp_server; - { - let s0 = service.clone(); - let s1 = service.clone(); - let s2 = service.clone(); - warp_server = warp::serve(warp::any() - .and(warp::path::end().map(|| { warp::reply::with_status("404", StatusCode::NOT_FOUND) }) - .or(warp::path("status") - .and(warp::addr::remote()) - .and(warp::method()) - .and(warp::header::headers_cloned()) - .and(warp::body::content_length_limit(1048576)) - .and(warp::body::bytes()) - .map(move |remote: Option, method: Method, headers: HeaderMap, post_data: Bytes| { s0.web_api_status(remote, method, headers, post_data) })) - .or(warp::path!("network" / String) - .and(warp::addr::remote()) - .and(warp::method()) - .and(warp::header::headers_cloned()) - .and(warp::body::content_length_limit(1048576)) - .and(warp::body::bytes()) - .map(move |network_str: String, remote: Option, method: Method, headers: HeaderMap, post_data: Bytes| { s1.web_api_network(network_str, remote, method, headers, post_data) })) - .or(warp::path!("peer" / String) - .and(warp::addr::remote()) - .and(warp::method()) - .and(warp::header::headers_cloned()) - .and(warp::body::content_length_limit(1048576)) - .and(warp::body::bytes()) - .map(move |peer_str: String, remote: Option, method: Method, headers: HeaderMap, post_data: Bytes| { s2.web_api_peer(peer_str, remote, method, headers, post_data) })) - ) - ).try_bind_with_graceful_shutdown((IpAddr::from([127_u8, 0_u8, 0_u8, 1_u8]), local_config.settings.primary_port), async { let _ = shutdown_rx.await; }); - } + let (s0, s1, s2) = (service.clone(), service.clone(), service.clone()); // clones to move to closures + let warp_server = warp::serve(web_service).try_bind_with_graceful_shutdown((IpAddr::from([127_u8, 0_u8, 0_u8, 1_u8]), local_config.settings.primary_port), async { let _ = shutdown_rx.await; }); if warp_server.is_err() { l!(log, "ERROR: local API http server failed to bind to port {} or failed to start: {}, restarting inner loop...", local_config.settings.primary_port, warp_server.err().unwrap().to_string()); break; } - let warp_server = tokio_rt.spawn(warp_server.unwrap().1); + let warp_server = tokio::spawn(warp_server.unwrap().1); + */ // Write zerotier.port which is used by the CLI to know how to reach the HTTP API. - store.write_port(local_config.settings.primary_port); + let _ = store.write_port(local_config.settings.primary_port); // The inner loop runs the web server in the "background" (async) while periodically // scanning for significant configuration changes. Some major changes may require @@ -369,7 +359,7 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { } } for k in udp_sockets_to_close.iter() { - d!(log, "unbinding UDP socket at {} (no longer appears to be present or port has changed)", k.to_string()); + l!(log, "unbinding UDP socket at {} (no longer appears to be present or port has changed)", k.to_string()); udp_sockets.remove(k); } @@ -379,9 +369,9 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { let _ = FastUDPSocket::new(addr.1.as_str(), addr.0, move |raw_socket: &FastUDPRawOsSocket, from_address: &InetAddress, data: Buffer| { // TODO: incoming packet handler }).map_or_else(|e| { - d!(log, "error binding UDP socket to {}: {}", addr.0.to_string(), e.to_string()); + l!(log, "error binding UDP socket to {}: {}", addr.0.to_string(), e.to_string()); }, |s| { - d!(log, "bound UDP socket at {}", addr.0.to_string()); + l!(log, "bound UDP socket at {}", addr.0.to_string()); udp_sockets.insert(addr.0.clone(), s); }); } @@ -432,8 +422,8 @@ pub(crate) fn run(store: &Arc, auth_token: Option) -> i32 { d!(log, "inner loop exited, shutting down local API HTTP server..."); // Gracefully shut down the local web server. - let _ = shutdown_tx.send(()); - let _ = warp_server.await; + //let _ = shutdown_tx.send(()); + //let _ = warp_server.await; // Sleep for a brief period of time to prevent thrashing if some invalid // state is hit that causes the inner loop to keep breaking. diff --git a/rust-zerotier-service/src/store.rs b/rust-zerotier-service/src/store.rs index cea2cc8f9..04aa505d0 100644 --- a/rust-zerotier-service/src/store.rs +++ b/rust-zerotier-service/src/store.rs @@ -11,7 +11,6 @@ */ /****/ -use std::error::Error; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; use std::sync::Mutex; @@ -49,6 +48,7 @@ impl Store { pub fn new(base_path: &str) -> std::io::Result { let bp = Path::new(base_path); + let _ = std::fs::create_dir_all(bp); let md = bp.metadata()?; if !md.is_dir() || md.permissions().readonly() { return Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "base path does not exist or is not writable")); @@ -235,7 +235,7 @@ impl Store { /// Erase zerotier.pid if present. pub fn erase_pid(&self) { - std::fs::remove_file(self.base_path.join("zerotier.pid")); + let _ = std::fs::remove_file(self.base_path.join("zerotier.pid")); } /// Load a ZeroTier core object. diff --git a/rust-zerotier-service/src/vnic/common.rs b/rust-zerotier-service/src/vnic/common.rs index 4067755dd..874a49fc9 100644 --- a/rust-zerotier-service/src/vnic/common.rs +++ b/rust-zerotier-service/src/vnic/common.rs @@ -12,7 +12,6 @@ /****/ use std::collections::BTreeSet; -use std::os::raw::c_ulong; use std::ptr::null_mut; use zerotier_core::{MAC, MulticastGroup}; diff --git a/rust-zerotier-service/src/weblistener.rs b/rust-zerotier-service/src/weblistener.rs new file mode 100644 index 000000000..6a7acc43b --- /dev/null +++ b/rust-zerotier-service/src/weblistener.rs @@ -0,0 +1,101 @@ +/* + * Copyright (c)2013-2021 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. + */ +/****/ + +use std::net::TcpListener; +use std::time::Duration; +use std::convert::Infallible; +use std::sync::Arc; + +use zerotier_core::InetAddress; +use hyper::{Request, Response, Body}; +use hyper::service::{make_service_fn, service_fn}; +use futures::Future; +use futures::future::{AbortHandle, abortable}; +use net2::TcpBuilder; + +use crate::service::Service; + +/// Listener for http connections to the API or for TCP P2P. +pub(crate) struct WebListener { + server: dyn Future, + abort_handle: AbortHandle, +} + +impl WebListener { + /// Create a new "background" TCP WebListener using the current tokio reactor async runtime. + pub fn new(_device_name: &str, addr: &InetAddress, service: Arc) -> Result { + let addr = addr.to_socketaddr(); + if addr.is_none() { + return Err(std::io::Error::new(std::io::ErrorKind::AddrNotAvailable, "invalid address")); + } + let addr = addr.unwrap(); + + let listener = if addr.is_ipv4() { + let l = TcpBuilder::new_v4(); + if l.is_err() { + return Err(l.err().unwrap()); + } + l.unwrap() + } else { + let l = TcpBuilder::new_v6(); + if l.is_err() { + return Err(l.err().unwrap()); + } + let l = l.unwrap(); + l.only_v6(true); + l + }; + let listener = listener.bind(addr); + if listener.is_err() { + return Err(listener.err().unwrap()); + } + let listener = listener.unwrap().listen(128); + if listener.is_err() { + return Err(listener.err().unwrap()); + } + let listener = listener.unwrap(); + + let builder = hyper::server::Server::from_tcp(listener); + if builder.is_err() { + return Err(builder.err().unwrap()); + } + let builder = builder.unwrap() + .executor(tokio::spawn) + .http1_half_close(false) + .http1_keepalive(true) + .http1_max_buf_size(131072) + .http2_keep_alive_interval(Duration::from_secs(30)) + .http2_keep_alive_timeout(Duration::from_secs(90)) + .http2_adaptive_window(true) + .http2_max_frame_size(131072) + .http2_max_concurrent_streams(16); + + let (server, abort_handle) = abortable(builder.serve(make_service_fn(|_| async move { + Ok::<_, Infallible>(service_fn(|req: Request| -> Result, Infallible> async move { + Ok(Response::new("Hello, World".into())) + })) + }))); + + Ok(WebListener { + server, + abort_handle, + }) + } +} + +impl Drop for WebListener { + fn drop(&mut self) { + self.abort_handle.abort(); + self.server.await; + } +}