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.

This commit is contained in:
Adam Ierymenko 2021-02-25 10:49:35 -05:00
parent 7cc0314bd4
commit 0f49c7510b
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
20 changed files with 373 additions and 801 deletions

View file

@ -837,6 +837,21 @@ int ZT_InetAddress_isV6(const ZT_InetAddress *ia)
return (int)(reinterpret_cast<const ZeroTier::InetAddress *>(ia))->isV6();
}
unsigned int ZT_InetAddress_ipBytes(const ZT_InetAddress *ia, void *buf)
{
if (ia) {
switch(reinterpret_cast<const ZeroTier::InetAddress *>(ia)->as.sa.sa_family) {
case AF_INET:
ZeroTier::Utils::copy<4>(buf, &(reinterpret_cast<const ZeroTier::InetAddress *>(ia)->as.sa_in.sin_addr.s_addr));
return 4;
case AF_INET6:
ZeroTier::Utils::copy<16>(buf, reinterpret_cast<const ZeroTier::InetAddress *>(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))

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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.)
*/

View file

@ -15,6 +15,8 @@
#include <stdlib.h>
#include <string.h>
/********************************************************************************************************************/
#ifdef __APPLE__
#include <unistd.h>
#include <fcntl.h>
@ -67,6 +69,29 @@ extern const unsigned long c_SIOCAUTOCONF_STOP;
/********************************************************************************************************************/
#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/if_addr.h>
#include <linux/if_ether.h>
#include <ifaddrs.h>
#endif /* __linux__ */
/********************************************************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif

View file

@ -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);
}

View file

@ -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 {

View file

@ -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<SocketAddr> {
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 {

View file

@ -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",
]

View file

@ -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"] }

View file

@ -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);
}

View file

@ -105,7 +105,7 @@ Advanced Operations:
· export <serial> [path] Export a certificate from this node
· delete <serial|ALL> 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 <address> may be specified as a 10-digit short ZeroTier address, a
fingerprint containing both an address and a SHA384 hash, or an identity.

View file

@ -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<FastUDPRawOsSocket, &'static str> {
unsafe {
let af;
@ -60,17 +57,20 @@ fn bind_udp_socket(_: &str, address: &InetAddress) -> Result<FastUDPRawOsSocket,
InetAddressFamily::IPv4 => {
af = osdep::AF_INET;
sa_len = std::mem::size_of::<osdep::sockaddr_in>() as osdep::socklen_t;
},
}
InetAddressFamily::IPv6 => {
af = osdep::AF_INET6;
sa_len = std::mem::size_of::<osdep::sockaddr_in6>() 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<FastUDPRawOsSocket,
let fl_size = std::mem::size_of::<c_int>() 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<FastUDPRawOsSocket,
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// A multi-threaded (or otherwise fast) UDP socket that binds to both IPv4 and IPv6 addresses.
pub(crate) struct FastUDPSocket {
threads: Vec<std::thread::JoinHandle<()>>,
@ -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<F: Fn(&FastUDPRawOsSocket, &InetAddress, Buffer) + Send + Sync + Clone + 'static>(device_name: &str, address: &InetAddress, handler: F) -> Result<FastUDPSocket, String> {
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);

View file

@ -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;

View file

@ -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<S: AsRef<str>>(&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<S: AsRef<str>>(&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);
}
}

View file

@ -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

View file

@ -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<String>,
log: Arc<Log>,
pub(crate) struct Service {
pub auth_token: Arc<String>,
pub log: Arc<Log>,
_local_config: Arc<Mutex<Arc<LocalConfig>>>, // Arc -> shared Mutex container so it can be changed globally
run: Arc<AtomicBool>,
online: Arc<AtomicBool>,
store: Arc<Store>,
node: Weak<Node<Service, Network>>, // weak since Node itself may hold a reference to this
pub online: Arc<AtomicBool>,
pub store: Arc<Store>,
pub node: Weak<Node<Service, Network>>, // weak since Node itself may hold a reference to this
}
impl NodeEventHandler<Network> for Service {
@ -67,18 +66,22 @@ impl NodeEventHandler<Network> 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<Network> 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<Network> for Service {
}
impl Service {
#[inline(always)]
fn web_api_status(&self, remote: Option<SocketAddr>, method: Method, headers: HeaderMap, post_data: Bytes) -> Box<dyn Reply> {
Box::new(StatusCode::BAD_REQUEST)
}
#[inline(always)]
fn web_api_network(&self, network_str: String, remote: Option<SocketAddr>, method: Method, headers: HeaderMap, post_data: Bytes) -> Box<dyn Reply> {
Box::new(StatusCode::BAD_REQUEST)
}
#[inline(always)]
fn web_api_peer(&self, peer_str: String, remote: Option<SocketAddr>, method: Method, headers: HeaderMap, post_data: Bytes) -> Box<dyn Reply> {
Box::new(StatusCode::BAD_REQUEST)
}
#[inline(always)]
fn local_config(&self) -> Arc<LocalConfig> {
self._local_config.lock().unwrap().clone()
@ -187,7 +181,7 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> 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<Store>, auth_token: Option<String>) -> 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<InetAddress, FastUDPSocket> = BTreeMap::new();
let (mut interrupt_tx, mut interrupt_rx) = futures::channel::mpsc::channel::<()>(1);
@ -240,47 +232,45 @@ pub(crate) fn run(store: &Arc<Store>, auth_token: Option<String>) -> 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<SocketAddr>, 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<SocketAddr>, 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<SocketAddr>, 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<SocketAddr>, 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<SocketAddr>, 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<SocketAddr>, 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<Store>, auth_token: Option<String>) -> 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<Store>, auth_token: Option<String>) -> 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<Store>, auth_token: Option<String>) -> 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.

View file

@ -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<Store> {
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.

View file

@ -12,7 +12,6 @@
/****/
use std::collections::BTreeSet;
use std::os::raw::c_ulong;
use std::ptr::null_mut;
use zerotier_core::{MAC, MulticastGroup};

View file

@ -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<Service>) -> Result<WebListener, dyn std::error::Error> {
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<Body>| -> Result<Response<Body>, 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;
}
}