mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-26 17:03:43 +02:00
Docs, formatting.
This commit is contained in:
parent
bf482e06ea
commit
08e15bb92b
19 changed files with 167 additions and 136 deletions
|
@ -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"] }
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
]))
|
||||
}
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -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]> {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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()) }
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue