Docs, formatting.

This commit is contained in:
Adam Ierymenko 2021-11-01 17:59:01 -04:00
parent bf482e06ea
commit 08e15bb92b
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
19 changed files with 167 additions and 136 deletions

View file

@ -7,5 +7,5 @@ edition = "2018"
rand_core = "^0"
aes-gmac-siv = { path = "../aes-gmac-siv" }
gcrypt = "^0"
x25519-dalek = "^1"
ed25519-dalek = "^1"
x25519-dalek = { version = "^1", features = ["u64_backend"] }
ed25519-dalek = { version = "^1", features = ["u64_backend"] }

View file

@ -24,7 +24,6 @@ impl C25519KeyPair {
C25519KeyPair(sk, pk)
}
#[inline(always)]
pub fn from_bytes(public_key: &[u8], secret_key: &[u8]) -> Option<C25519KeyPair> {
if public_key.len() == 32 && secret_key.len() == 32 {
let pk: [u8; 32] = public_key.try_into().unwrap();
@ -44,7 +43,6 @@ impl C25519KeyPair {
pub fn secret_bytes(&self) -> Secret<{ C25519_SECRET_KEY_SIZE }> { Secret(self.0.to_bytes()) }
/// Execute ECDH agreement and return a raw (un-hashed) shared secret key.
#[inline(always)]
pub fn agree(&self, their_public: &[u8]) -> Secret<{ C25519_SHARED_SECRET_SIZE }> {
let pk: [u8; 32] = their_public.try_into().unwrap();
let pk = x25519_dalek::PublicKey::from(pk);
@ -63,7 +61,6 @@ impl Ed25519KeyPair {
Ed25519KeyPair(ed25519_dalek::Keypair::generate(&mut rng))
}
#[inline(always)]
pub fn from_bytes(public_bytes: &[u8], secret_bytes: &[u8]) -> Option<Ed25519KeyPair> {
if public_bytes.len() == ED25519_PUBLIC_KEY_SIZE && secret_bytes.len() == ED25519_SECRET_KEY_SIZE {
let pk = ed25519_dalek::PublicKey::from_bytes(public_bytes);
@ -87,7 +84,6 @@ impl Ed25519KeyPair {
#[inline(always)]
pub fn secret_bytes(&self) -> Secret<{ ED25519_SECRET_KEY_SIZE }> { Secret(self.0.secret.to_bytes()) }
#[inline(always)]
pub fn sign(&self, msg: &[u8]) -> [u8; ED25519_SIGNATURE_SIZE] {
let mut h = ed25519_dalek::Sha512::new();
let _ = h.write_all(msg);
@ -96,7 +92,6 @@ impl Ed25519KeyPair {
/// Create a signature with the first 32 bytes of the SHA512 hash appended.
/// ZeroTier does this for legacy reasons, but it's ignored in newer versions.
#[inline(always)]
pub fn sign_zt(&self, msg: &[u8]) -> [u8; 96] {
let mut h = ed25519_dalek::Sha512::new();
let _ = h.write_all(msg);
@ -110,7 +105,6 @@ impl Ed25519KeyPair {
}
}
#[inline(always)]
pub fn ed25519_verify(public_key: &[u8], signature: &[u8], msg: &[u8]) -> bool {
if public_key.len() == 32 && signature.len() >= 64 {
ed25519_dalek::PublicKey::from_bytes(public_key).map_or(false, |pk| {

View file

@ -15,7 +15,6 @@ impl SHA512 {
h
}
#[inline(always)]
pub fn hmac(key: &[u8], msg: &[u8]) -> [u8; SHA512_HASH_SIZE] {
let mut m = gcrypt::mac::Mac::new(gcrypt::mac::Algorithm::HmacSha512).unwrap();
let _ = m.set_key(key);
@ -68,7 +67,6 @@ impl SHA384 {
h
}
#[inline(always)]
pub fn hmac(key: &[u8], msg: &[u8]) -> [u8; SHA384_HASH_SIZE] {
let mut m = gcrypt::mac::Mac::new(gcrypt::mac::Algorithm::HmacSha384).unwrap();
let _ = m.set_key(key);

View file

@ -11,5 +11,19 @@ pub fn zt_kbkdf_hmac_sha384(key: &[u8], label: u8, context: u8, iter: u32) -> Se
// HMAC'd message is: preface | iteration[4], preface[2], label, 0x00, context, hash size[4]
// See: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf
Secret(SHA384::hmac(key, &[(iter >> 24) as u8, (iter >> 16) as u8, (iter >> 8) as u8, iter as u8, b'Z', b'T', label, 0, context, 0, 0, 0x01, 0x80]))
Secret(SHA384::hmac(key, &[
(iter >> 24) as u8,
(iter >> 16) as u8,
(iter >> 8) as u8,
iter as u8,
b'Z',
b'T',
label,
0,
context,
0,
0,
0x01,
0x80
]))
}

View file

@ -5,7 +5,6 @@ pub const POLY1305_ONE_TIME_KEY_SIZE: usize = 32;
pub const POLY1305_MAC_SIZE: usize = 16;
impl Poly1305 {
#[inline(always)]
pub fn new(key: &[u8]) -> Option<Poly1305> {
if key.len() == 32 {
gcrypt::mac::Mac::new(gcrypt::mac::Algorithm::Poly1305).map_or(None, |mut poly| {

View file

@ -5,7 +5,6 @@ impl Salsa {
/// Initialize Salsa cipher.
/// Key must be 32 bytes and iv must be 8 bytes. If r12 is true the 12-round
/// variant of Salsa will be used, otherwise 20 rounds are used.
#[inline(always)]
pub fn new(key: &[u8], iv: &[u8], r12: bool) -> Option<Salsa> {
if key.len() == 32 && iv.len() == 8 {
gcrypt::cipher::Cipher::new(if r12 { gcrypt::cipher::Algorithm::Salsa20r12 } else { gcrypt::cipher::Algorithm::Salsa20 }, gcrypt::cipher::Mode::Stream).map_or(None, |mut salsa| {

View file

@ -128,16 +128,12 @@ pub(crate) struct U64PassThroughHasher(u64);
impl U64PassThroughHasher {
#[inline(always)]
pub fn new() -> Self {
Self(0)
}
pub fn new() -> Self { Self(0) }
}
impl std::hash::Hasher for U64PassThroughHasher {
#[inline(always)]
fn finish(&self) -> u64 {
self.0
}
fn finish(&self) -> u64 { self.0 }
#[inline(always)]
fn write(&mut self, _: &[u8]) {
@ -145,21 +141,15 @@ impl std::hash::Hasher for U64PassThroughHasher {
}
#[inline(always)]
fn write_u64(&mut self, i: u64) {
self.0 += i;
}
fn write_u64(&mut self, i: u64) { self.0 += i; }
#[inline(always)]
fn write_i64(&mut self, i: i64) {
self.0 += i as u64;
}
fn write_i64(&mut self, i: i64) { self.0 += i as u64; }
}
impl std::hash::BuildHasher for U64PassThroughHasher {
type Hasher = Self;
#[inline(always)]
fn build_hasher(&self) -> Self::Hasher {
Self(0)
}
fn build_hasher(&self) -> Self::Hasher { Self(0) }
}

View file

@ -24,6 +24,10 @@ impl<const L: usize> Default for Buffer<L> {
const OVERFLOW_ERR_MSG: &'static str = "overflow";
impl<const L: usize> Buffer<L> {
pub const CAPACITY: usize = L;
pub const fn capacity(&self) -> usize { L }
#[inline(always)]
pub fn new() -> Self { Self(0, [0_u8; L]) }
@ -47,6 +51,12 @@ impl<const L: usize> Buffer<L> {
#[inline(always)]
pub fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.1[0..self.0] }
#[inline(always)]
pub fn as_ptr(&self) -> *const u8 { self.1.as_ptr() }
#[inline(always)]
pub fn as_mut_ptr(&mut self) -> *mut u8 { self.1.as_mut_ptr() }
/// Get all bytes after a given position.
#[inline(always)]
pub fn as_bytes_starting_at(&self, start: usize) -> std::io::Result<&[u8]> {

View file

@ -28,3 +28,4 @@ pub use inetaddress::InetAddress;
pub use locator::Locator;
pub use peer::Peer;
pub use path::Path;
pub use node::{PacketBuffer, PacketBufferPool, PacketBufferFactory};

View file

@ -5,7 +5,8 @@ use std::time::Duration;
use dashmap::DashMap;
use parking_lot::Mutex;
use zerotier_core_crypto::random::{SecureRandom, next_u64_secure};
use zerotier_core_crypto::random::{next_u64_secure, SecureRandom};
use crate::error::InvalidParameterError;
use crate::util::gate::IntervalGate;
use crate::util::pool::{Pool, Pooled};
@ -14,12 +15,18 @@ use crate::vl1::buffer::{Buffer, PooledBufferFactory};
use crate::vl1::path::Path;
use crate::vl1::peer::Peer;
use crate::vl1::protocol::*;
use crate::vl1::whoisqueue::{WhoisQueue, QueuedPacket};
use crate::vl1::rootset::RootSet;
use crate::vl1::whoisqueue::{QueuedPacket, WhoisQueue};
/// Standard packet buffer type including pool container.
pub type PacketBuffer = Pooled<Buffer<{ PACKET_SIZE_MAX }>, PooledBufferFactory<{ PACKET_SIZE_MAX }>>;
/// Factory type to supply to a new PacketBufferPool.
pub type PacketBufferFactory = PooledBufferFactory<{ PACKET_SIZE_MAX }>;
/// Source for instances of PacketBuffer
pub type PacketBufferPool = Pool<Buffer<{ PACKET_SIZE_MAX }>, PacketBufferFactory>;
/// Callback interface and call context for calls to the node (for VL1).
///
/// Every non-trivial call takes a reference to this, which it passes all the way through
@ -132,7 +139,7 @@ pub struct Node {
roots: Mutex<Vec<Arc<Peer>>>,
root_sets: Mutex<Vec<RootSet>>,
whois: WhoisQueue,
buffer_pool: Pool<Buffer<{ PACKET_SIZE_MAX }>, PooledBufferFactory<{ PACKET_SIZE_MAX }>>,
buffer_pool: Arc<PacketBufferPool>,
secure_prng: SecureRandom,
fips_mode: bool,
}
@ -174,12 +181,18 @@ impl Node {
roots: Mutex::new(Vec::new()),
root_sets: Mutex::new(Vec::new()),
whois: WhoisQueue::new(),
buffer_pool: Pool::new(64, PooledBufferFactory),
buffer_pool: Arc::new(PacketBufferPool::new(64, PooledBufferFactory)),
secure_prng: SecureRandom::get(),
fips_mode: false,
})
}
#[inline(always)]
pub fn get_packet_buffer(&self) -> PacketBuffer { self.buffer_pool.get() }
#[inline(always)]
pub fn packet_buffer_pool(&self) -> &Arc<PacketBufferPool> { &self.buffer_pool }
#[inline(always)]
pub fn address(&self) -> Address { self.identity.address() }
@ -189,10 +202,6 @@ impl Node {
#[inline(always)]
pub fn locator(&self) -> Option<Arc<Locator>> { self.locator.lock().clone() }
/// Get a reusable packet buffer.
/// The buffer will automatically be returned to the pool if it is dropped.
pub fn get_packet_buffer(&self) -> PacketBuffer { self.buffer_pool.get() }
/// Get a peer by address.
pub fn peer(&self, a: Address) -> Option<Arc<Peer>> { self.peers.get(&a).map(|peer| peer.value().clone()) }

View file

@ -1,3 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c)2021 ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::collections::HashMap;
use std::sync::atomic::{AtomicI64, Ordering};

View file

@ -1,3 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c)2021 ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::convert::TryInto;
use std::mem::MaybeUninit;
use std::ptr::copy_nonoverlapping;
@ -298,7 +306,7 @@ impl Peer {
if (verb & VERB_FLAG_COMPRESSED) != 0 {
let mut decompressed_payload = node.get_packet_buffer();
let _ = decompressed_payload.append_u8(verb);
let dlen = lz4_flex::block::decompress_into(&payload.as_bytes()[1..], &mut decompressed_payload.as_bytes_mut(), 1);
let dlen = lz4_flex::block::decompress_into(&payload.as_bytes()[1..], &mut decompressed_payload.as_bytes_mut());
if dlen.is_ok() {
decompressed_payload.set_size(dlen.unwrap());
payload = decompressed_payload;

View file

@ -1,3 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c)2021 ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::mem::MaybeUninit;
use crate::vl1::Address;

View file

@ -1,3 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c)2021 ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::hash::{Hash, Hasher};
use std::io::Write;

View file

@ -1,3 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c)2021 ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::collections::{HashMap, LinkedList};
use parking_lot::Mutex;

View file

@ -17,9 +17,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
use num_traits::cast::AsPrimitive;
use zerotier_core::{Buffer, InetAddress, InetAddressFamily};
use crate::osdep as osdep;
use zerotier_network_hypervisor::vl1::{InetAddress, PacketBuffer, PacketBufferPool};
/*
* This is a threaded UDP socket listener for high performance. The fastest way to receive UDP
@ -27,9 +25,6 @@ use crate::osdep as osdep;
* for each thread using options like SO_REUSEPORT and concurrent packet listening.
*/
#[cfg(windows)]
use winapi::um::winsock2 as winsock2;
#[cfg(windows)]
pub(crate) type FastUDPRawOsSocket = winsock2::SOCKET;
@ -40,89 +35,85 @@ pub(crate) type FastUDPRawOsSocket = c_int;
fn bind_udp_socket(_device_name: &str, address: &InetAddress) -> Result<FastUDPRawOsSocket, &'static str> {
unsafe {
let (af, sa_len) = match address.family() {
InetAddressFamily::IPv4 => (osdep::AF_INET, std::mem::size_of::<osdep::sockaddr_in>() as osdep::socklen_t),
InetAddressFamily::IPv6 => (osdep::AF_INET6, std::mem::size_of::<osdep::sockaddr_in6>() as osdep::socklen_t),
InetAddressFamily::IPv4 => (libc::AF_INET, std::mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
InetAddressFamily::IPv6 => (libc::AF_INET6, std::mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
_ => {
return Err("unrecognized address family");
}
};
#[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);
let s = libc::socket(af.as_(), libc::SOCK_DGRAM, 0);
if s < 0 {
return Err("unable to create socket");
}
let mut fl: c_int;
let fl_size = std::mem::size_of::<c_int>() as osdep::socklen_t;
let fl_size = std::mem::size_of::<c_int>() as libc::socklen_t;
let mut setsockopt_results: c_int = 0;
fl = 1;
setsockopt_results |= osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_REUSEPORT.as_(), (&mut fl as *mut c_int).cast(), fl_size);
setsockopt_results |= libc::setsockopt(s, libc::SOL_SOCKET.as_(), libc::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);
//setsockopt_results |= libc::setsockopt(s, libc::SOL_SOCKET, libc::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);
if af == osdep::AF_INET6 {
setsockopt_results |= libc::setsockopt(s, libc::SOL_SOCKET.as_(), libc::SO_BROADCAST.as_(), (&mut fl as *mut c_int).cast(), fl_size);
if af == libc::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);
setsockopt_results |= libc::setsockopt(s, libc::IPPROTO_IPV6.as_(), libc::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)
setsockopt_results |= libc::setsockopt(s, libc::SOL_SOCKET.as_(), libc::SO_NOSIGPIPE.as_(), (&mut fl as *mut c_int).cast(), fl_size)
}
#[cfg(target_os = "linux")] {
if !_device_name.is_empty() {
let _ = std::ffi::CString::new(_device_name).map(|dn| {
let dnb = dn.as_bytes_with_nul();
let _ = osdep::setsockopt(s.as_(), osdep::SOL_SOCKET.as_(), osdep::SO_BINDTODEVICE.as_(), dnb.as_ptr().cast(), (dnb.len() - 1).as_());
let _ = libc::setsockopt(s.as_(), libc::SOL_SOCKET.as_(), libc::SO_BINDTODEVICE.as_(), dnb.as_ptr().cast(), (dnb.len() - 1).as_());
});
}
}
if setsockopt_results != 0 {
osdep::close(s);
libc::close(s);
return Err("setsockopt() failed");
}
if af == osdep::AF_INET {
if af == libc::AF_INET {
#[cfg(not(target_os = "linux"))] {
fl = 0;
osdep::setsockopt(s, osdep::IPPROTO_IP.as_(), osdep::IP_DF.as_(), (&mut fl as *mut c_int).cast(), fl_size);
libc::setsockopt(s, libc::IPPROTO_IP.as_(), libc::IP_DF.as_(), (&mut fl as *mut c_int).cast(), fl_size);
}
#[cfg(target_os = "linux")] {
fl = osdep::IP_PMTUDISC_DONT as c_int;
osdep::setsockopt(s, osdep::IPPROTO_IP.as_(), osdep::IP_MTU_DISCOVER.as_(), (&mut fl as *mut c_int).cast(), fl_size);
fl = libc::IP_PMTUDISC_DONT as c_int;
libc::setsockopt(s, libc::IPPROTO_IP.as_(), libc::IP_MTU_DISCOVER.as_(), (&mut fl as *mut c_int).cast(), fl_size);
}
}
if af == osdep::AF_INET6 {
if af == libc::AF_INET6 {
fl = 0;
osdep::setsockopt(s, osdep::IPPROTO_IPV6.as_(), osdep::IPV6_DONTFRAG.as_(), (&mut fl as *mut c_int).cast(), fl_size);
libc::setsockopt(s, libc::IPPROTO_IPV6.as_(), libc::IPV6_DONTFRAG.as_(), (&mut fl as *mut c_int).cast(), fl_size);
}
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 {
if libc::setsockopt(s, libc::SOL_SOCKET.as_(), libc::SO_RCVBUF.as_(), (&mut fl as *mut c_int).cast(), fl_size) == 0 {
break;
}
fl -= 65536;
}
fl = 1048576;
while fl >= 131072 {
if osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_SNDBUF.as_(), (&mut fl as *mut c_int).cast(), fl_size) == 0 {
if libc::setsockopt(s, libc::SOL_SOCKET.as_(), libc::SO_SNDBUF.as_(), (&mut fl as *mut c_int).cast(), fl_size) == 0 {
break;
}
fl -= 65536;
}
if osdep::bind(s, (address as *const InetAddress).cast(), sa_len) != 0 {
osdep::close(s);
if libc::bind(s, (address as *const InetAddress).cast(), sa_len) != 0 {
libc::close(s);
return Err("bind to address failed");
}
@ -141,30 +132,19 @@ pub(crate) struct FastUDPSocket {
#[cfg(unix)]
#[inline(always)]
fn fast_udp_socket_close(socket: &FastUDPRawOsSocket) {
unsafe {
osdep::close(*socket);
}
}
#[cfg(windows)]
#[inline(always)]
fn fast_udp_socket_close(socket: &FastUDPRawOsSocket) {
unsafe {
osdep::close(*socket);
}
unsafe { libc::close(*socket); }
}
#[inline(always)]
pub(crate) fn fast_udp_socket_to_i64(socket: &FastUDPRawOsSocket) -> i64 {
(*socket) as i64
}
pub(crate) fn fast_udp_socket_to_i64(socket: &FastUDPRawOsSocket) -> i64 { (*socket) as i64 }
#[inline(always)]
pub(crate) fn fast_udp_socket_from_i64(socket: i64) -> Option<FastUDPRawOsSocket> {
if socket >= 0 {
return Some(socket as FastUDPRawOsSocket);
Some(socket as FastUDPRawOsSocket)
} else {
None
}
None
}
/// Send to a raw UDP socket with optional packet TTL.
@ -172,38 +152,38 @@ pub(crate) fn fast_udp_socket_from_i64(socket: i64) -> Option<FastUDPRawOsSocket
/// in ZeroTier right now to do escalating TTL probes for IPv4 NAT traversal.
#[cfg(unix)]
#[inline(always)]
pub(crate) fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &InetAddress, data: *const u8, len: usize, packet_ttl: i32) {
pub(crate) fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &InetAddress, data: &[u8], packet_ttl: i32) {
unsafe {
if packet_ttl <= 0 {
osdep::sendto(*socket, data.cast(), len.as_(), 0, (to_address as *const InetAddress).cast(), std::mem::size_of::<InetAddress>().as_());
libc::sendto(*socket, data.as_ptr().cast(), data.len().as_(), 0, (to_address as *const InetAddress).cast(), std::mem::size_of::<InetAddress>().as_());
} else {
let mut ttl = packet_ttl as c_int;
osdep::setsockopt(*socket, osdep::IPPROTO_IP.as_(), osdep::IP_TTL.as_(), (&mut ttl as *mut c_int).cast(), std::mem::size_of::<c_int>().as_());
osdep::sendto(*socket, data.cast(), len.as_(), 0, (to_address as *const InetAddress).cast(), std::mem::size_of::<InetAddress>().as_());
libc::setsockopt(*socket, libc::IPPROTO_IP.as_(), libc::IP_TTL.as_(), (&mut ttl as *mut c_int).cast(), std::mem::size_of::<c_int>().as_());
libc::sendto(*socket, data.as_ptr().cast(), data.len().as_(), 0, (to_address as *const InetAddress).cast(), std::mem::size_of::<InetAddress>().as_());
ttl = 255;
osdep::setsockopt(*socket, osdep::IPPROTO_IP.as_(), osdep::IP_TTL.as_(), (&mut ttl as *mut c_int).cast(), std::mem::size_of::<c_int>().as_());
libc::setsockopt(*socket, libc::IPPROTO_IP.as_(), libc::IP_TTL.as_(), (&mut ttl as *mut c_int).cast(), std::mem::size_of::<c_int>().as_());
}
}
}
#[cfg(windows)]
#[inline(always)]
pub(crate) fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &InetAddress, data: &[u8], packet_ttl: i32) {}
#[cfg(unix)]
#[inline(always)]
fn fast_udp_socket_recvfrom(socket: &FastUDPRawOsSocket, buf: &mut Buffer, from_address: &mut InetAddress) -> i32 {
fn fast_udp_socket_recvfrom(socket: &FastUDPRawOsSocket, buf: &mut PacketBuffer, from_address: &mut InetAddress) -> isize {
unsafe {
let mut addrlen = std::mem::size_of::<InetAddress>() as osdep::socklen_t;
osdep::recvfrom(*socket, buf.as_mut_ptr().cast(), Buffer::CAPACITY.as_(), 0, (from_address as *mut InetAddress).cast(), &mut addrlen) as i32
let mut addrlen = std::mem::size_of::<InetAddress>() as libc::socklen_t;
let s = libc::recvfrom(*socket, buf.as_mut_ptr().cast(), buf.capacity().as_(), 0, (from_address as *mut InetAddress).cast(), &mut addrlen) as isize;
if s > 0 {
buf.set_size_unchecked(s as usize);
}
s
}
}
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());
pub fn new<F: Fn(&FastUDPRawOsSocket, &InetAddress, PacketBuffer) + Send + Sync + Clone + 'static>(device_name: &str, address: &InetAddress, packet_buffer_pool: &Arc<PacketBufferPool>, handler: F) -> Result<Self, String> {
let thread_count = num_cpus::get_physical().max(1);
let mut s = FastUDPSocket {
let mut s = Self {
thread_run: Arc::new(AtomicBool::new(true)),
threads: Vec::new(),
sockets: Vec::new(),
@ -221,15 +201,15 @@ impl FastUDPSocket {
let thread_run = s.thread_run.clone();
let handler_copy = handler.clone();
let packet_buffer_pool_copy = packet_buffer_pool.clone();
s.threads.push(std::thread::Builder::new().stack_size(zerotier_core::RECOMMENDED_THREAD_STACK_SIZE).spawn(move || {
let mut from_address = InetAddress::new();
while thread_run.load(Ordering::Relaxed) {
let mut buf = Buffer::new();
let read_length = fast_udp_socket_recvfrom(&thread_socket, &mut buf, &mut from_address);
if read_length > 0 {
buf.set_len(read_length as usize);
let mut buf = packet_buffer_pool_copy.get_packet_buffer();
let s = fast_udp_socket_recvfrom(&thread_socket, &mut buf, &mut from_address);
if s > 0 {
handler_copy(&thread_socket, &from_address, buf);
} else if read_length < 0 {
} else if s < 0 {
break;
}
}
@ -249,22 +229,16 @@ impl FastUDPSocket {
Ok(s)
}
/// Get a slice of all raw sockets used.
#[inline(always)]
pub fn all_sockets(&self) -> &[FastUDPRawOsSocket] {
self.sockets.as_slice()
}
/// Send from this socket.
/// This actually picks a thread's socket and sends from it. Since all
/// are bound to the same IP:port which one is chosen doesn't matter.
/// Sockets are thread safe.
#[inline(always)]
pub fn send(&self, to_address: &InetAddress, data: *const u8, len: usize, packet_ttl: i32) {
fast_udp_socket_sendto(self.sockets.get(0).unwrap(), to_address, data, len, packet_ttl);
pub fn send(&self, to_address: &InetAddress, data: &[u8], packet_ttl: i32) {
fast_udp_socket_sendto(self.sockets.get(0).unwrap(), to_address, data, packet_ttl);
}
/// Get a raw socket that can be used to send UDP packets.
#[inline(always)]
pub fn raw_socket(&self) -> FastUDPRawOsSocket {
*self.sockets.get(0).unwrap()
@ -274,7 +248,7 @@ impl FastUDPSocket {
impl Drop for FastUDPSocket {
#[cfg(windows)]
fn drop(&mut self) {
// TODO
todo!()
}
#[cfg(unix)]
@ -283,17 +257,17 @@ impl Drop for FastUDPSocket {
self.thread_run.store(false, Ordering::Relaxed);
for s in self.sockets.iter() {
unsafe {
osdep::sendto(*s, tmp.as_ptr().cast(), 0, 0, (&self.bind_address as *const InetAddress).cast(), std::mem::size_of::<InetAddress>() as osdep::socklen_t);
libc::sendto(*s, tmp.as_ptr().cast(), 0, 0, (&self.bind_address as *const InetAddress).cast(), std::mem::size_of::<InetAddress>() as osdep::socklen_t);
}
}
for s in self.sockets.iter() {
unsafe {
osdep::shutdown(*s, osdep::SHUT_RDWR.as_());
libc::shutdown(*s, libc::SHUT_RDWR.as_());
}
}
for s in self.sockets.iter() {
unsafe {
osdep::close(*s);
libc::close(*s);
}
}
while !self.threads.is_empty() {
@ -306,19 +280,21 @@ impl Drop for FastUDPSocket {
mod tests {
use std::sync::atomic::{AtomicU32, Ordering};
use zerotier_core::{Buffer, InetAddress};
use zerotier_network_hypervisor::vl1::{PacketBuffer, PacketBufferPool, PacketBufferFactory};
use crate::fastudpsocket::*;
#[test]
fn test_udp_bind_and_transfer() {
{
let pool = Arc::new(PacketBufferPool::new(64, PacketBufferFactory));
let ba0 = InetAddress::new_from_string("127.0.0.1/23333");
assert!(ba0.is_some());
let ba0 = ba0.unwrap();
let cnt0 = Arc::new(AtomicU32::new(0));
let cnt0c = cnt0.clone();
let s0 = FastUDPSocket::new("", &ba0, move |sock: &FastUDPRawOsSocket, _: &InetAddress, data: Buffer| {
let s0 = FastUDPSocket::new("", &ba0, &pool, move |sock: &FastUDPRawOsSocket, _: &InetAddress, data: PacketBuffer| {
cnt0c.fetch_add(1, Ordering::Relaxed);
});
assert!(s0.is_ok());
@ -329,7 +305,7 @@ mod tests {
let ba1 = ba1.unwrap();
let cnt1 = Arc::new(AtomicU32::new(0));
let cnt1c = cnt1.clone();
let s1 = FastUDPSocket::new("", &ba1, move |sock: &FastUDPRawOsSocket, _: &InetAddress, data: Buffer| {
let s1 = FastUDPSocket::new("", &ba1, &pool, move |sock: &FastUDPRawOsSocket, _: &InetAddress, data: PacketBuffer| {
cnt1c.fetch_add(1, Ordering::Relaxed);
});
assert!(s1.is_ok());
@ -337,13 +313,13 @@ mod tests {
let data_bytes = [0_u8; 1024];
loop {
s0.send(&ba1, data_bytes.as_ptr(), data_bytes.len(), 0);
s1.send(&ba0, data_bytes.as_ptr(), data_bytes.len(), 0);
s0.send(&ba1, &data_bytes, 0);
s1.send(&ba0, &data_bytes, 0);
if cnt0.load(Ordering::Relaxed) > 10000 && cnt1.load(Ordering::Relaxed) > 10000 {
break;
}
}
}
//println!("FastUDPSocket shutdown successful");
println!("FastUDPSocket shutdown successful");
}
}

View file

@ -16,9 +16,9 @@ use std::ptr::{copy_nonoverlapping, null_mut};
use zerotier_network_hypervisor::vl1::InetAddress;
fn s6_addr_as_ptr<A>(a: &A) -> *const A {
a as *const A
}
#[allow(unused)]
#[inline(always)]
fn s6_addr_as_ptr<A>(a: &A) -> *const A { a as *const A }
/// Call supplied function or closure for each physical IP address in the system.
#[cfg(unix)]

View file

@ -13,21 +13,20 @@
use std::cell::Cell;
use std::convert::Infallible;
use std::sync::Arc;
use std::net::SocketAddr;
#[cfg(target_os = "linux")]
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
use hyper::{Body, Request, Response, StatusCode, Method};
use digest_auth::{AuthContext, AuthorizationHeader, Charset, WwwAuthenticateHeader};
use hyper::{Body, Method, Request, Response, StatusCode};
use hyper::server::Server;
use hyper::service::{make_service_fn, service_fn};
use tokio::task::JoinHandle;
use digest_auth::{AuthContext, AuthorizationHeader, Charset, WwwAuthenticateHeader};
use crate::service::Service;
use crate::api;
use crate::utils::{decrypt_http_auth_nonce, ms_since_epoch, create_http_auth_nonce};
#[cfg(target_os = "linux")]
use std::os::unix::io::AsRawFd;
use crate::service::Service;
use crate::utils::{create_http_auth_nonce, decrypt_http_auth_nonce, ms_since_epoch};
const HTTP_MAX_NONCE_AGE_MS: i64 = 30000;
@ -158,7 +157,7 @@ impl HttpListener {
unsafe {
let _ = std::ffi::CString::new(_device_name).map(|dn| {
let dnb = dn.as_bytes_with_nul();
let _ = crate::osdep::setsockopt(sock as std::os::raw::c_int, crate::osdep::SOL_SOCKET as std::os::raw::c_int, crate::osdep::SO_BINDTODEVICE as std::os::raw::c_int, dnb.as_ptr().cast(), (dnb.len() - 1) as crate::osdep::socklen_t);
let _ = libc::setsockopt(sock as std::os::raw::c_int, libc::SOL_SOCKET as std::os::raw::c_int, libc::SO_BINDTODEVICE as std::os::raw::c_int, dnb.as_ptr().cast(), (dnb.len() - 1) as libc::socklen_t);
});
}
}

View file

@ -12,9 +12,11 @@
/****/
use std::collections::BTreeMap;
use zerotier_core::{InetAddress, Address, NetworkId};
use serde::{Deserialize, Serialize};
use zerotier_network_hypervisor::vl1::{Address, InetAddress};
pub const UNASSIGNED_PRIVILEGED_PORTS: [u16; 299] = [
4,
6,