It makes web requests, and fix some warnings.

This commit is contained in:
Adam Ierymenko 2021-03-18 20:47:02 -04:00
parent f5331b5bb9
commit 6df6a955ba
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
15 changed files with 358 additions and 42 deletions

View file

@ -24,6 +24,7 @@ struct prf_ra {
#include "../core/Mutex.hpp"
#include "../core/Containers.hpp"
#include "../core/SHA512.hpp"
#include "../core/AES.hpp"
#include "OSUtils.hpp"
#include "rust-osdep.h"
@ -139,4 +140,18 @@ void sha384(const void *in, unsigned int len, void *out)
void sha512(const void *in, unsigned int len, void *out)
{ ZeroTier::SHA512(out, in, len); }
static ZT_INLINE ZeroTier::AES _makeHttpAuthCipher() noexcept
{
uint8_t key[32];
ZeroTier::Utils::getSecureRandom(key, 32);
return ZeroTier::AES(key);
}
static const ZeroTier::AES HTTP_AUTH_CIPHER = _makeHttpAuthCipher();
void encryptHttpAuthNonce(void *block)
{ HTTP_AUTH_CIPHER.encrypt(block, block); }
void decryptHttpAuthNonce(void *block)
{ HTTP_AUTH_CIPHER.decrypt(block, block); }
} /* extern "C" */

View file

@ -108,6 +108,8 @@ extern void lockDownFile(const char *path, int isDir);
extern void getSecureRandom(void *buf, unsigned int len);
extern void sha384(const void *in, unsigned int len, void *out);
extern void sha512(const void *in, unsigned int len, void *out);
extern void encryptHttpAuthNonce(void *block);
extern void decryptHttpAuthNonce(void *block);
#ifdef __cplusplus
}

View file

@ -12,7 +12,7 @@
/****/
use std::ffi::CString;
use std::os::raw::{c_char, c_int, c_uint};
use std::os::raw::{c_int, c_uint};
use std::mem::MaybeUninit;
use std::ptr::null;

198
service/Cargo.lock generated
View file

@ -26,6 +26,15 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
dependencies = [
"byteorder",
]
[[package]]
name = "base64"
version = "0.13.0"
@ -38,7 +47,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e964e3e0a930303c7c0bdb28ebf691dd98d9eee4b8b68019d2c995710b58a18"
dependencies = [
"base64",
"base64 0.13.0",
"serde",
]
@ -48,6 +57,22 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
dependencies = [
"byteorder",
"iovec",
]
[[package]]
name = "bytes"
version = "1.0.1"
@ -256,13 +281,24 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
[[package]]
name = "http"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0"
dependencies = [
"bytes 0.4.12",
"fnv",
"itoa",
]
[[package]]
name = "http"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747"
dependencies = [
"bytes",
"bytes 1.0.1",
"fnv",
"itoa",
]
@ -273,8 +309,8 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994"
dependencies = [
"bytes",
"http",
"bytes 1.0.1",
"http 0.2.3",
]
[[package]]
@ -295,11 +331,11 @@ version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe"
dependencies = [
"bytes",
"bytes 1.0.1",
"futures-channel",
"futures-core",
"futures-util",
"http",
"http 0.2.3",
"http-body",
"httparse",
"httpdate",
@ -312,12 +348,56 @@ dependencies = [
"want",
]
[[package]]
name = "hyperx"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a94cbc2c6f63028e5736ca4e811ae36d3990059c384cbe68298c66728a9776"
dependencies = [
"base64 0.10.1",
"bytes 0.4.12",
"http 0.1.21",
"httparse",
"language-tags",
"log",
"mime",
"percent-encoding",
"time",
"unicase 2.6.0",
]
[[package]]
name = "idna"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
"libc",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "language-tags"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -339,12 +419,24 @@ 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 = "mio"
version = "0.7.7"
@ -423,6 +515,12 @@ version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "percent-encoding"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
[[package]]
name = "pin-project"
version = "1.0.4"
@ -698,6 +796,21 @@ dependencies = [
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
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"
@ -757,6 +870,42 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "unicase"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
dependencies = [
"version_check 0.1.5",
]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check 0.9.3",
]
[[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.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.1.8"
@ -769,12 +918,35 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "url"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
dependencies = [
"idna",
"matches",
"percent-encoding",
]
[[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.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "want"
version = "0.3.0"
@ -822,6 +994,17 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "www-authenticate"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c62efb8259cda4e4c732287397701237b78daa4c43edcf3e613c8503a6c07dd"
dependencies = [
"hyperx",
"unicase 1.4.2",
"url",
]
[[package]]
name = "zeroize"
version = "0.9.3"
@ -832,7 +1015,7 @@ checksum = "45af6a010d13e4cf5b54c94ba5a2b2eba5596b9e46bf5875612d332a1f2b3f86"
name = "zerotier-core"
version = "0.1.0"
dependencies = [
"base64",
"base64 0.13.0",
"base64-serde",
"hex",
"num-derive",
@ -860,5 +1043,6 @@ dependencies = [
"socket2",
"tokio",
"winapi",
"www-authenticate",
"zerotier-core",
]

View file

@ -23,6 +23,7 @@ num-derive = "0"
hyper = { version = "0", features = ["http1", "runtime", "server", "client", "tcp", "stream"] }
socket2 = { version = "0", features = ["reuseport", "unix", "pair"] }
dialoguer = "0"
www-authenticate = "0"
[target."cfg(windows)".dependencies]
winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] }

View file

@ -0,0 +1,32 @@
/*
* 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::str::FromStr;
use std::sync::Arc;
use hyper::Uri;
use crate::store::Store;
pub(crate) fn run(store: Arc<Store>) -> i32 {
crate::webclient::command(store.clone(), move |client, uri| {
async move {
let mut res = client.get(uri).await?;
println!("status: {}", res.status().as_str());
let body = hyper::body::to_bytes(res.body_mut()).await?;
String::from_utf8(body.to_vec()).map(|body| {
println!("body: {}", body.as_str());
});
Ok(0)
}
})
}

View file

@ -233,7 +233,7 @@ impl FastUDPSocket {
let mut buf = Buffer::new();
let read_length = fast_udp_socket_recvfrom(&thread_socket, &mut buf, &mut from_address);
if read_length > 0 {
unsafe { buf.set_len(read_length as usize); }
buf.set_len(read_length as usize);
handler_copy(&thread_socket, &from_address, buf);
} else if read_length < 0 {
break;

View file

@ -48,12 +48,12 @@ pub(crate) fn for_each_address<F: FnMut(&InetAddress, &str)>(mut f: F) {
let mut netmask_bits: u16 = 0;
if !(*i).ifa_netmask.is_null() {
if sa_family == osdep::AF_INET as u8 {
let mut a = (*(*i).ifa_netmask.cast::<osdep::sockaddr_in>()).sin_addr.s_addr as u32;
let a = (*(*i).ifa_netmask.cast::<osdep::sockaddr_in>()).sin_addr.s_addr as u32;
netmask_bits = a.leading_ones() as u16;
} else if sa_family == osdep::AF_INET6 as u8 {
let a = s6_addr_as_ptr(&((*(*i).ifa_netmask.cast::<osdep::sockaddr_in6>()).sin6_addr)).cast::<u8>();
for i in 0..16 as isize {
let mut b = *a.offset(i);
let b = *a.offset(i);
if b == 0xff {
netmask_bits += 8;
} else {

View file

@ -71,7 +71,7 @@ impl Log {
let log_line = format!("{}[{}] {}{}\n", l.prefix.as_str(), chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(), pfx, s);
if !l.path.is_empty() {
if l.file.is_none() {
let mut f = OpenOptions::new().read(true).write(true).create(true).open(l.path.as_str());
let f = OpenOptions::new().read(true).write(true).create(true).open(l.path.as_str());
if f.is_err() {
return;
}
@ -94,7 +94,7 @@ impl Log {
let _ = std::fs::rename(l.path.as_str(), old_path.as_str());
let _ = std::fs::remove_file(l.path.as_str()); // should fail
let mut f = OpenOptions::new().read(true).write(true).create(true).open(l.path.as_str());
let f = OpenOptions::new().read(true).write(true).create(true).open(l.path.as_str());
if f.is_err() {
return;
}

View file

@ -22,6 +22,7 @@ mod network;
mod vnic;
mod service;
mod utils;
mod webclient;
mod weblistener;
#[allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, improper_ctypes)]
@ -291,9 +292,8 @@ fn main() {
.get_matches_from_safe(std::env::args());
if args.is_err() {
let e = args.err().unwrap();
match e.kind {
ErrorKind::HelpDisplayed => {}
_ => { print_help(); }
if e.kind != ErrorKind::HelpDisplayed {
print_help();
}
std::process::exit(1);
}
@ -306,22 +306,22 @@ fn main() {
};
std::process::exit(match cli_args.subcommand() {
("help", None) => {
("help", _) => {
print_help();
0
}
("version", None) => {
("version", _) => {
let ver = zerotier_core::version();
println!("{}.{}.{}", ver.0, ver.1, ver.2);
0
}
("status", None) => { 0 }
("status", _) => crate::commands::status::run(make_store(&cli_args)),
("set", Some(sub_cli_args)) => { 0 }
("peer", Some(sub_cli_args)) => { 0 }
("network", Some(sub_cli_args)) => { 0 }
("join", Some(sub_cli_args)) => { 0 }
("leave", Some(sub_cli_args)) => { 0 }
("service", None) => {
("service", _) => {
let store = make_store(&cli_args);
drop(cli_args); // free memory
service::run(store)

View file

@ -221,7 +221,6 @@ async fn run_async(store: Arc<Store>, log: Arc<Log>, local_config: Arc<LocalConf
let service = service; // make immutable after setting node
let mut local_config = service.local_config();
let _ = store.write_port(local_config.settings.primary_port);
let mut now: i64 = ms_since_epoch();
let mut loop_delay = zerotier_core::NODE_BACKGROUND_TASKS_MAX_INTERVAL;
@ -265,7 +264,6 @@ async fn run_async(store: Arc<Store>, log: Arc<Log>, local_config: Arc<LocalConf
if local_config.settings.primary_port != next_local_config.settings.primary_port {
local_web_listeners.0 = None;
local_web_listeners.1 = None;
store.write_port(next_local_config.settings.primary_port);
}
if local_config.settings.log.max_size != next_local_config.settings.log.max_size {
log.set_max_size(next_local_config.settings.log.max_size);
@ -373,7 +371,7 @@ async fn run_async(store: Arc<Store>, log: Arc<Log>, local_config: Arc<LocalConf
if addr.0.port() == local_config.settings.primary_port && !web_listeners.contains_key(addr.0) {
let sa = addr.0.to_socketaddr();
if sa.is_some() {
let wl = WebListener::new(addr.1.as_str(), sa.unwrap(), &service).map_or_else(|e| {
let wl = WebListener::new(addr.1.as_str(), sa.unwrap(), &service).await.map_or_else(|e| {
l!(log, "error creating HTTP listener at {}: {}", addr.0.to_string(), e.to_string());
}, |l| {
l!(log, "created HTTP listener at {}", addr.0.to_string());
@ -384,13 +382,17 @@ async fn run_async(store: Arc<Store>, log: Arc<Log>, local_config: Arc<LocalConf
}
if local_web_listeners.0.is_none() {
let _ = WebListener::new(loopback_dev_name.as_str(), SocketAddr::new(IpAddr::from(Ipv4Addr::LOCALHOST), local_config.settings.primary_port), &service).map(|wl| {
let _ = WebListener::new(loopback_dev_name.as_str(), SocketAddr::new(IpAddr::from(Ipv4Addr::LOCALHOST), local_config.settings.primary_port), &service).await.map(|wl| {
local_web_listeners.0 = Some(wl);
let _ = store.write_uri(format!("http://127.0.0.1:{}/", local_config.settings.primary_port).as_str());
});
}
if local_web_listeners.1.is_none() {
let _ = WebListener::new(loopback_dev_name.as_str(), SocketAddr::new(IpAddr::from(Ipv6Addr::LOCALHOST), local_config.settings.primary_port), &service).map(|wl| {
let _ = WebListener::new(loopback_dev_name.as_str(), SocketAddr::new(IpAddr::from(Ipv6Addr::LOCALHOST), local_config.settings.primary_port), &service).await.map(|wl| {
local_web_listeners.1 = Some(wl);
if local_web_listeners.0.is_none() {
let _ = store.write_uri(format!("http://[::1]:{}/", local_config.settings.primary_port).as_str());
}
});
}
if local_web_listeners.0.is_none() && local_web_listeners.1.is_none() {

View file

@ -249,26 +249,11 @@ impl Store {
self.write_file("local.conf", json.as_bytes())
}
/// Writes the primary port number bound to zerotier.port.
pub fn write_port(&self, port: u16) -> std::io::Result<()> {
let ps = port.to_string();
self.write_file("zerotier.port", ps.as_bytes())
}
/// Read zerotier.port and return port or 0 if not found or not readable.
pub fn read_port(&self) -> u16 {
self.read_file_str("zerotier.port").map_or_else(|_| {
0_u16
},|s| {
u16::from_str(s.trim()).unwrap_or(0_u16)
})
}
/// Write zerotier.pid file with current process's PID.
#[cfg(unix)]
pub fn write_pid(&self) -> std::io::Result<()> {
let pid = unsafe { crate::osdep::getpid() }.to_string();
self.write_file(self.base_path.join("zerotier.pid").to_str().unwrap(), pid.as_bytes())
self.write_file("zerotier.pid", pid.as_bytes())
}
/// Erase zerotier.pid if present.
@ -276,6 +261,26 @@ impl Store {
let _ = std::fs::remove_file(self.base_path.join("zerotier.pid"));
}
/// Write a string to zerotier.uri
pub fn write_uri(&self, uri: &str) -> std::io::Result<()> {
self.write_file("zerotier.uri", uri.as_bytes())
}
/// Load zerotier.uri if present
pub fn load_uri(&self) -> std::io::Result<hyper::Uri> {
let uri = String::from_utf8(self.read_file("zerotier.uri")?);
uri.map_or_else(|e| {
Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))
}, |uri| {
let uri = hyper::Uri::from_str(uri.trim());
uri.map_or_else(|e| {
Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))
}, |uri| {
Ok(uri)
})
})
}
/// Load a ZeroTier core object.
pub fn load_object(&self, obj_type: &StateObjectType, obj_id: &[u64]) -> std::io::Result<Vec<u8>> {
let obj_path = self.make_obj_path_internal(&obj_type, obj_id);

View file

@ -21,6 +21,7 @@ use std::path::Path;
use zerotier_core::{Identity, Locator};
use crate::osdep;
use crate::osdep::time;
#[inline(always)]
pub(crate) fn sha512<T: AsRef<[u8]>>(data: T) -> [u8; 64] {
@ -107,3 +108,33 @@ pub(crate) fn read_locator(input: &str) -> Result<Locator, String> {
parse_func(input)
}
}
/// Create a new HTTP authorization nonce by encrypting the current time.
/// The key used to encrypt the current time is random and is re-created for
/// each execution of the process. By decrypting this nonce when it is returned,
/// the client and server may check the age of a digest auth exchange.
pub(crate) fn create_http_auth_nonce(timestamp: u64) -> String {
let mut nonce_plaintext: [u64; 2] = [timestamp, 12345]; // the second u64 is arbitrary and unused
unsafe {
osdep::encryptHttpAuthNonce(nonce_plaintext.as_mut_ptr().cast());
hex::encode(*nonce_plaintext.as_ptr().cast::<[u8; 16]>())
}
}
/// Decrypt HTTP auth nonce encrypted by this process and return the timestamp.
/// This returns zero if the input was not valid.
pub(crate) fn decrypt_http_auth_nonce(nonce: &str) -> u64 {
let nonce = hex::decode(nonce.trim());
if nonce.is_err() {
return 0;
}
let mut nonce = nonce.unwrap();
if nonce.len() != 16 {
return 0;
}
unsafe {
osdep::decryptHttpAuthNonce(nonce.as_mut_ptr().cast());
let nonce = *nonce.as_ptr().cast::<[u64; 2]>();
nonce[0]
}
}

44
service/src/webclient.rs Normal file
View file

@ -0,0 +1,44 @@
/*
* 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::str::FromStr;
use std::time::Duration;
use hyper::Uri;
use std::sync::Arc;
use crate::store::Store;
use std::future::Future;
/// Launch the supplied function inside the tokio runtime.
/// The return value of this function should be the process exit code.
/// This is for implementation of commands that query the HTTP API, not HTTP
/// requests from a running server.
pub(crate) fn command<'a, R: Future<Output = hyper::Result<i32>>, F: FnOnce(Arc<hyper::Client<hyper::client::HttpConnector, hyper::Body>>, hyper::Uri) -> R>(store: Arc<Store>, func: F) -> i32 {
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
let code = rt.block_on(async move {
let uri = store.load_uri();
if uri.is_err() {
println!("ERROR: unable to read 'zerotier.uri' to get local HTTP API address.");
1
} else {
let f = func(Arc::new(hyper::Client::new()), uri.unwrap());
f.await.map_or_else(|e| {
println!("ERROR: HTTP request failed: {}", e.to_string());
1
}, |code| {
code
})
}
});
rt.shutdown_timeout(Duration::from_millis(10));
code
}

View file

@ -42,7 +42,7 @@ pub(crate) struct WebListener {
impl WebListener {
/// Create a new "background" TCP WebListener using the current tokio reactor async runtime.
pub fn new(_device_name: &str, addr: SocketAddr, service: &Service) -> Result<WebListener, Box<dyn std::error::Error>> {
pub async fn new(_device_name: &str, addr: SocketAddr, service: &Service) -> Result<WebListener, Box<dyn std::error::Error>> {
let listener = if addr.is_ipv4() {
let listener = socket2::Socket::new(socket2::Domain::ipv4(), socket2::Type::stream(), Some(socket2::Protocol::tcp()));
if listener.is_err() {