diff --git a/Makefile b/Makefile index a0a897a45..faf263418 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ distclean: FORCE rust-bindgen: FORCE cargo install bindgen - rm -f rust-zerotier-core/src/bindings/capi.rs + rm -f rust-zerotier-core/src/capi.rs rust-zerotier-service/src/osdep.rs bindgen --no-doc-comments --no-layout-tests --no-derive-debug core/zerotier.h >rust-zerotier-core/src/capi.rs bindgen --no-doc-comments --no-layout-tests --no-derive-debug osdep/rust-osdep.h >rust-zerotier-service/src/osdep.rs diff --git a/osdep/CMakeLists.txt b/osdep/CMakeLists.txt index 9f39148a6..1443dcf32 100644 --- a/osdep/CMakeLists.txt +++ b/osdep/CMakeLists.txt @@ -2,15 +2,12 @@ cmake_minimum_required(VERSION 3.0) project(zt_osdep) set(src - Arp.cpp EthernetTap.cpp ManagedRoute.cpp - NeighborDiscovery.cpp OSUtils.cpp ) set(headers - Arp.hpp BlockingQueue.hpp EthernetTap.hpp ManagedRoute.hpp diff --git a/osdep/rust-osdep.h b/osdep/rust-osdep.h index 5a522ef4d..71e5dfd62 100644 --- a/osdep/rust-osdep.h +++ b/osdep/rust-osdep.h @@ -1,20 +1,12 @@ #ifdef __APPLE__ #include #include -#include -#include #include -#include #include -#include -#include #include #include #include -#include -#include #include -#include #include #include #include @@ -33,4 +25,10 @@ #include #include #include +#ifndef SIOCAUTOCONF_START +#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ +#endif +#ifndef SIOCAUTOCONF_STOP +#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ +#endif #endif diff --git a/rust-zerotier-core/src/buffer.rs b/rust-zerotier-core/src/buffer.rs index 67eb97185..e3cbd5f58 100644 --- a/rust-zerotier-core/src/buffer.rs +++ b/rust-zerotier-core/src/buffer.rs @@ -12,8 +12,7 @@ /****/ use std::os::raw::c_void; - -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; /// A reusable buffer for I/O to/from the ZeroTier core. /// The core allocates and manages a pool of these. This provides a Rust diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs index 643050e56..86df3c7bf 100644 --- a/rust-zerotier-core/src/certificate.rs +++ b/rust-zerotier-core/src/certificate.rs @@ -22,7 +22,7 @@ use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; /// Maximum length of a string in a certificate (mostly for the certificate name fields). pub const CERTIFICATE_MAX_STRING_LENGTH: isize = ztcore::ZT_CERTIFICATE_MAX_STRING_LENGTH as isize; diff --git a/rust-zerotier-core/src/endpoint.rs b/rust-zerotier-core/src/endpoint.rs index cd79d9875..6ce5408de 100644 --- a/rust-zerotier-core/src/endpoint.rs +++ b/rust-zerotier-core/src/endpoint.rs @@ -19,7 +19,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; #[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] pub enum EndpointType { diff --git a/rust-zerotier-core/src/fingerprint.rs b/rust-zerotier-core/src/fingerprint.rs index 05c517a7f..03ba35ceb 100644 --- a/rust-zerotier-core/src/fingerprint.rs +++ b/rust-zerotier-core/src/fingerprint.rs @@ -16,7 +16,7 @@ use std::mem::MaybeUninit; use std::os::raw::{c_char, c_int}; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; #[derive(PartialEq, Eq)] pub struct Fingerprint { diff --git a/rust-zerotier-core/src/identity.rs b/rust-zerotier-core/src/identity.rs index f679f9349..3b9a68cbb 100644 --- a/rust-zerotier-core/src/identity.rs +++ b/rust-zerotier-core/src/identity.rs @@ -18,7 +18,7 @@ use std::os::raw::*; use num_traits::{FromPrimitive, ToPrimitive}; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; #[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] pub enum IdentityType { diff --git a/rust-zerotier-core/src/inetaddress.rs b/rust-zerotier-core/src/inetaddress.rs index caadabe46..cb66d87f7 100644 --- a/rust-zerotier-core/src/inetaddress.rs +++ b/rust-zerotier-core/src/inetaddress.rs @@ -20,7 +20,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; // 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 diff --git a/rust-zerotier-core/src/locator.rs b/rust-zerotier-core/src/locator.rs index 94ef08388..82057bae0 100644 --- a/rust-zerotier-core/src/locator.rs +++ b/rust-zerotier-core/src/locator.rs @@ -15,7 +15,7 @@ use std::ffi::CString; use std::os::raw::{c_char, c_int, c_uint}; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; pub struct Locator { pub(crate) capi: *const ztcore::ZT_Locator, diff --git a/rust-zerotier-core/src/node.rs b/rust-zerotier-core/src/node.rs index 0b96f79e8..95dbeda9b 100644 --- a/rust-zerotier-core/src/node.rs +++ b/rust-zerotier-core/src/node.rs @@ -26,7 +26,7 @@ use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; const NODE_BACKGROUND_MAX_DELAY: i64 = 500; diff --git a/rust-zerotier-core/src/path.rs b/rust-zerotier-core/src/path.rs index 24a160d30..d0eec97d9 100644 --- a/rust-zerotier-core/src/path.rs +++ b/rust-zerotier-core/src/path.rs @@ -12,9 +12,8 @@ /****/ use serde::{Deserialize, Serialize}; - -use crate::bindings::capi as ztcore; use crate::Endpoint; +use crate::capi as ztcore; #[derive(Serialize, Deserialize)] pub struct Path { diff --git a/rust-zerotier-core/src/peer.rs b/rust-zerotier-core/src/peer.rs index 5e3b811c6..aa3b655f1 100644 --- a/rust-zerotier-core/src/peer.rs +++ b/rust-zerotier-core/src/peer.rs @@ -12,9 +12,8 @@ /****/ use serde::{Deserialize, Serialize}; - use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; #[derive(Serialize, Deserialize)] pub struct Peer { diff --git a/rust-zerotier-core/src/virtualnetworkconfig.rs b/rust-zerotier-core/src/virtualnetworkconfig.rs index 28bf2eeec..c6f70308a 100644 --- a/rust-zerotier-core/src/virtualnetworkconfig.rs +++ b/rust-zerotier-core/src/virtualnetworkconfig.rs @@ -16,7 +16,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::FromPrimitive; use crate::*; -use crate::bindings::capi as ztcore; +use crate::capi as ztcore; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/rust-zerotier-service/Cargo.lock b/rust-zerotier-service/Cargo.lock index 1fde2d064..783d3c7aa 100644 --- a/rust-zerotier-service/Cargo.lock +++ b/rust-zerotier-service/Cargo.lock @@ -1380,7 +1380,9 @@ dependencies = [ "clap", "futures", "hex", - "libc", + "lazy_static", + "num-derive", + "num-traits", "num_cpus", "serde", "serde_json", diff --git a/rust-zerotier-service/Cargo.toml b/rust-zerotier-service/Cargo.toml index c2d319a18..1013eb77f 100644 --- a/rust-zerotier-service/Cargo.toml +++ b/rust-zerotier-service/Cargo.toml @@ -18,9 +18,9 @@ futures = "0.3" clap = { version = "2", features = ["default"] } chrono = "0.4" hex = "0.4" - -[target."cfg(unix)".dependencies] -libc = "0.2.82" +lazy_static = "1" +num-traits = "0.2" +num-derive = "0.3" [target."cfg(windows)".dependencies] winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] } diff --git a/rust-zerotier-service/src/fastudpsocket.rs b/rust-zerotier-service/src/fastudpsocket.rs index 13e603e4d..377ec9982 100644 --- a/rust-zerotier-service/src/fastudpsocket.rs +++ b/rust-zerotier-service/src/fastudpsocket.rs @@ -14,6 +14,9 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use zerotier_core::{Buffer, InetAddress, InetAddressFamily}; +use num_traits::cast::AsPrimitive; +use std::os::raw::c_int; +use crate::osdep as osdep; // // A very low-level fast UDP socket that uses thread-per-core semantics to @@ -31,7 +34,7 @@ use winapi::um::winsock2 as winsock2; pub type FastUDPRawOsSocket = winsock2::SOCKET; #[cfg(unix)] -pub type FastUDPRawOsSocket = libc::c_int; +pub type FastUDPRawOsSocket = c_int; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // bind_udp_socket() implementations for each platform @@ -43,76 +46,76 @@ fn bind_udp_socket(_: &str, address: &InetAddress) -> Result { - af = libc::AF_INET; - sa_len = std::mem::size_of::() as libc::socklen_t; + af = osdep::AF_INET; + sa_len = std::mem::size_of::() as osdep::socklen_t; }, InetAddressFamily::IPv6 => { - af = libc::AF_INET6; - sa_len = std::mem::size_of::() as libc::socklen_t; + af = osdep::AF_INET6; + sa_len = std::mem::size_of::() as osdep::socklen_t; }, _ => { return Err("unrecognized address family"); } }; - let s = libc::socket(af, libc::SOCK_DGRAM, 0); + let s = osdep::socket(af.as_(), osdep::SOCK_DGRAM.as_(), 0); if s < 0 { return Err("unable to create socket"); } - let mut fl: libc::c_int; - let fl_size = std::mem::size_of::() as libc::socklen_t; - let mut setsockopt_results: libc::c_int = 0; + let mut fl: c_int; + let fl_size = std::mem::size_of::() 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 |= libc::setsockopt(s, libc::SOL_SOCKET, libc::SO_REUSEPORT, (&mut fl as *mut libc::c_int).cast(), fl_size); + 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 |= libc::setsockopt(s, libc::SOL_SOCKET, libc::SO_REUSEADDR, (&mut fl as *mut libc::c_int).cast(), fl_size); + //setsockopt_results |= osdep::setsockopt(s, osdep::SOL_SOCKET, osdep::SO_REUSEADDR, (&mut fl as *mut c_int).cast(), fl_size); fl = 1; - setsockopt_results |= libc::setsockopt(s, libc::SOL_SOCKET, libc::SO_BROADCAST, (&mut fl as *mut libc::c_int).cast(), fl_size); + 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 |= libc::setsockopt(s, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, (&mut fl as *mut libc::c_int).cast(), fl_size); - if af == libc::AF_INET6 { + 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 |= libc::setsockopt(s, libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, (&mut fl as *mut libc::c_int).cast(), fl_size); + setsockopt_results |= osdep::setsockopt(s, osdep::IPPROTO_IPV6.as_(), osdep::IPV6_V6ONLY.as_(), (&mut fl as *mut c_int).cast(), fl_size); } if setsockopt_results != 0 { - libc::close(s); + 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 == libc::AF_INET { + if af == osdep::AF_INET { fl = 0; - libc::setsockopt(s, libc::IPPROTO_IP, 0x4000 /* IP_DF */, (&mut fl as *mut libc::c_int).cast(), fl_size); + osdep::setsockopt(s, osdep::IPPROTO_IP.as_(), 0x4000 /* IP_DF */, (&mut fl as *mut c_int).cast(), fl_size); } - if af == libc::AF_INET6 { + if af == osdep::AF_INET6 { fl = 0; - libc::setsockopt(s, libc::IPPROTO_IPV6, 62 /* IPV6_DONTFRAG */, (&mut fl as *mut libc::c_int).cast(), fl_size); + osdep::setsockopt(s, osdep::IPPROTO_IPV6.as_(), 62 /* IPV6_DONTFRAG */, (&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 libc::setsockopt(s, libc::SOL_SOCKET, libc::SO_RCVBUF, (&mut fl as *mut libc::c_int).cast(), fl_size) == 0 { + if osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_RCVBUF.as_(), (&mut fl as *mut c_int).cast(), fl_size) == 0 { break; } fl -= 65536; } fl = 1048576; while fl >= 131072 { - if libc::setsockopt(s, libc::SOL_SOCKET, libc::SO_SNDBUF, (&mut fl as *mut libc::c_int).cast(), fl_size) == 0 { + if osdep::setsockopt(s, osdep::SOL_SOCKET.as_(), osdep::SO_SNDBUF.as_(), (&mut fl as *mut c_int).cast(), fl_size) == 0 { break; } fl -= 65536; } - if libc::bind(s, (address as *const InetAddress).cast(), sa_len) != 0 { - //libc::perror(std::ptr::null()); - libc::close(s); + if osdep::bind(s, (address as *const InetAddress).cast(), sa_len) != 0 { + //osdep::perror(std::ptr::null()); + osdep::close(s); return Err("bind to address failed"); } @@ -142,13 +145,13 @@ pub struct FastUDPSocket pub fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &InetAddress, data: *const u8, len: usize, packet_ttl: i32) { unsafe { if packet_ttl <= 0 { - libc::sendto(*socket, data.cast(), len as libc::size_t, 0, (to_address as *const InetAddress).cast(), std::mem::size_of::() as libc::socklen_t); + osdep::sendto(*socket, data.cast(), len as osdep::size_t, 0, (to_address as *const InetAddress).cast(), std::mem::size_of::() as osdep::socklen_t); } else { - let mut ttl = packet_ttl as libc::c_int; - libc::setsockopt(*socket, libc::IPPROTO_IP, libc::IP_TTL, (&mut ttl as *mut libc::c_int).cast(), std::mem::size_of::() as libc::socklen_t); - libc::sendto(*socket, data.cast(), len as libc::size_t, 0, (to_address as *const InetAddress).cast(), std::mem::size_of::() as libc::socklen_t); + 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::() as osdep::socklen_t); + osdep::sendto(*socket, data.cast(), len as osdep::size_t, 0, (to_address as *const InetAddress).cast(), std::mem::size_of::() as osdep::socklen_t); ttl = 255; - libc::setsockopt(*socket, libc::IPPROTO_IP, libc::IP_TTL, (&mut ttl as *mut libc::c_int).cast(), std::mem::size_of::() as libc::socklen_t); + osdep::setsockopt(*socket, osdep::IPPROTO_IP.as_(), osdep::IP_TTL.as_(), (&mut ttl as *mut c_int).cast(), std::mem::size_of::() as osdep::socklen_t); } } } @@ -162,8 +165,8 @@ pub fn fast_udp_socket_sendto(socket: &FastUDPRawOsSocket, to_address: &InetAddr #[inline(always)] fn fast_udp_socket_recvfrom(socket: &FastUDPRawOsSocket, buf: &mut Buffer, from_address: &mut InetAddress) -> i32 { unsafe { - let mut addrlen = std::mem::size_of::() as libc::socklen_t; - libc::recvfrom(*socket, buf.as_mut_ptr().cast(), Buffer::CAPACITY as libc::size_t, 0, (from_address as *mut InetAddress).cast(), &mut addrlen) as i32 + let mut addrlen = std::mem::size_of::() as osdep::socklen_t; + osdep::recvfrom(*socket, buf.as_mut_ptr().cast(), Buffer::CAPACITY as osdep::size_t, 0, (from_address as *mut InetAddress).cast(), &mut addrlen) as i32 } } @@ -256,17 +259,17 @@ impl Drop for FastUDPSock self.thread_run.store(false, Ordering::Relaxed); for s in self.sockets.iter() { unsafe { - libc::sendto(*s, tmp.as_ptr().cast(), 0, 0, (&self.bind_address as *const InetAddress).cast(), std::mem::size_of::() as libc::socklen_t); + osdep::sendto(*s, tmp.as_ptr().cast(), 0, 0, (&self.bind_address as *const InetAddress).cast(), std::mem::size_of::() as osdep::socklen_t); } } for s in self.sockets.iter() { unsafe { - libc::shutdown(*s, libc::SHUT_RDWR); + osdep::shutdown(*s, osdep::SHUT_RDWR.as_()); } } for s in self.sockets.iter() { unsafe { - libc::close(*s); + osdep::close(*s); } } while !self.threads.is_empty() { diff --git a/rust-zerotier-service/src/physicallink.rs b/rust-zerotier-service/src/physicallink.rs index 96914ae52..b4228e8e0 100644 --- a/rust-zerotier-service/src/physicallink.rs +++ b/rust-zerotier-service/src/physicallink.rs @@ -15,6 +15,7 @@ use zerotier_core::InetAddress; use std::ffi::CStr; use std::ptr::{null_mut, copy_nonoverlapping}; use std::mem::size_of; +use crate::osdep as osdep; pub struct PhysicalLink { pub address: InetAddress, @@ -25,16 +26,16 @@ impl PhysicalLink { #[cfg(unix)] pub fn map(mut f: F) { unsafe { - let mut ifap: *mut libc::ifaddrs = null_mut(); - if libc::getifaddrs((&mut ifap as *mut *mut libc::ifaddrs).cast()) == 0 { + let mut ifap: *mut osdep::ifaddrs = null_mut(); + if osdep::getifaddrs((&mut ifap as *mut *mut osdep::ifaddrs).cast()) == 0 { let mut i = ifap; while !i.is_null() { if !(*i).ifa_addr.is_null() { let mut a = InetAddress::new(); - if (*(*i).ifa_addr).sa_family == libc::AF_INET as u8 { - copy_nonoverlapping((*i).ifa_addr.cast::(), (&mut a as *mut InetAddress).cast::(), size_of::()); - } else if (*(*i).ifa_addr).sa_family == libc::AF_INET6 as u8 { - copy_nonoverlapping((*i).ifa_addr.cast::(), (&mut a as *mut InetAddress).cast::(), size_of::()); + if (*(*i).ifa_addr).sa_family == osdep::AF_INET as u8 { + copy_nonoverlapping((*i).ifa_addr.cast::(), (&mut a as *mut InetAddress).cast::(), size_of::()); + } else if (*(*i).ifa_addr).sa_family == osdep::AF_INET6 as u8 { + copy_nonoverlapping((*i).ifa_addr.cast::(), (&mut a as *mut InetAddress).cast::(), size_of::()); } else { continue; } @@ -46,7 +47,7 @@ impl PhysicalLink { } i = (*i).ifa_next; } - libc::freeifaddrs(ifap.cast()); + osdep::freeifaddrs(ifap.cast()); } } } diff --git a/rust-zerotier-service/src/vnp/mac_feth_tap.rs b/rust-zerotier-service/src/vnp/mac_feth_tap.rs index 42b86560f..137ff5648 100644 --- a/rust-zerotier-service/src/vnp/mac_feth_tap.rs +++ b/rust-zerotier-service/src/vnp/mac_feth_tap.rs @@ -1,10 +1,142 @@ +use crate::osdep as osdep; use crate::vnp::Port; +use std::error::Error; +use std::os::raw::c_int; +use std::ffi::CString; +use std::thread::JoinHandle; +use std::sync::Mutex; +use std::cell::Cell; +use zerotier_core::NetworkId; +use lazy_static::lazy_static; +use crate::physicallink::PhysicalLink; + +const BPF_BUFFER_SIZE: usize = 131072; pub struct MacFethTap { + network_id: u64, + device_name: String, + peer_device_name: String, + bpf_fd: c_int, + bpf_read_thread: Cell>>, +} + +// Rust implementation of the following macro from Darwin sys/bpf.h: +// #define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) +// ... and also ... +// #define BPF_ALIGNMENT sizeof(int32_t) +#[inline(always)] +#[allow(non_snake_case)] +pub fn BPF_WORDALIGN(x: isize) -> isize { + (((x + 3) as usize) & (!(3 as usize))) as isize +} + +lazy_static! { + static ref MAC_FETH_GLOBAL_LOCK: Mutex = Mutex::new(0_i32); } impl MacFethTap { - pub fn new() -> MacFethTap { - MacFethTap{} + /// Create a new MacFethTap with a function to call for Ethernet frames. + /// The function F should return as quickly as possible. It should pass copies + /// of frames elsewhere if anything needs to be done with them. The slice it's + /// given will not remain valid after it returns. + pub fn new(nwid: &NetworkId, eth_frame_func: F) -> Result { + let _one_at_a_time = unsafe { MAC_FETH_GLOBAL_LOCK.lock().unwrap() }; + + if unsafe { osdep::getuid() } != 0 { + return Err(String::from("ZeroTier MacFethTap must run as root")); + } + + let mut device_name: String; + let mut peer_device_name: String; + let mut device_feth_ctr = nwid.0 ^ (nwid.0 >> 32) ^ (nwid.0 >> 48); + let mut device_alloc_tries = 0; + loop { + let device_feth_no = 100 + (device_feth_ctr % 4900); + device_name = format!("feth{}", device_feth_no); + peer_device_name = format!("feth{}", device_feth_no + 5000); + let mut already_allocated = false; + PhysicalLink::map(|link: PhysicalLink| { + if link.device.eq(&device_name) || link.device.eq(&peer_device_name) { + already_allocated = true; + } + }); + if !already_allocated { + break; + } + + device_alloc_tries += 1; + if device_alloc_tries >= 4899 { + return Err(String::from("unable to find unallocated 'feth' device")); + } + device_feth_ctr += 1; + } + + let mut bpf_no: u32 = 1; // start at 1 since some software hard-codes /dev/bpf0 + let mut bpf_fd: c_int = -1; + loop { + let bpf_dev = CString::new(format!("/dev/bpf{}", bpf_no)).unwrap(); + let bpf_dev = bpf_dev.as_bytes_with_nul(); + bpf_fd = unsafe { osdep::open(bpf_dev.as_ptr().cast(), osdep::O_RDWR as c_int) }; + if bpf_fd >= 0 { + break; + } + bpf_no += 1; + if bpf_no > 1000 { + return Err(String::from("unable to open /dev/bpf## where attempted ## from 1 to 1000")); + } + } + + let bpf_fd_copy = bpf_fd; + let t = std::thread::Builder::new().stack_size(zerotier_core::RECOMMENDED_THREAD_STACK_SIZE).spawn(move || { + let mut buf: [u8; BPF_BUFFER_SIZE] = [0_u8; BPF_BUFFER_SIZE]; + let hdr_struct_size = std::mem::size_of::() as isize; + loop { + let n = unsafe { osdep::read(bpf_fd_copy, buf.as_mut_ptr().cast(), BPF_BUFFER_SIZE as osdep::size_t) } as isize; + if n >= 0 { + let mut p: isize = 0; + while (p + hdr_struct_size) < n { + unsafe { + let h = buf.as_ptr().offset(p).cast::(); + let hdrlen = (*h).bh_hdrlen as isize; + let caplen = (*h).bh_caplen as isize; + let pktlen = hdrlen + caplen; + if caplen > 0 && (p + pktlen) <= n { + eth_frame_func(std::slice::from_raw_parts(buf.as_ptr().offset(p + hdrlen), caplen as usize)); + } + p += BPF_WORDALIGN(pktlen); + } + } + } else { + break; + } + } + }); + if t.is_err() { + unsafe { osdep::close(bpf_fd); } + return Err(String::from("unable to start thread")); + } + + Ok(MacFethTap { + network_id: nwid.0, + device_name: device_name, + peer_device_name: peer_device_name, + bpf_fd: bpf_fd, + bpf_read_thread: Cell::new(Some(t.unwrap())) + }) + } +} + +impl Drop for MacFethTap { + fn drop(&mut self) { + if self.bpf_fd >= 0 { + unsafe { + osdep::shutdown(self.bpf_fd, osdep::SHUT_RDWR as c_int); + osdep::close(self.bpf_fd); + } + } + let t = self.bpf_read_thread.replace(None); + if t.is_some() { + let _ = t.unwrap().join(); + } } } diff --git a/rust-zerotier-service/src/vnp/mod.rs b/rust-zerotier-service/src/vnp/mod.rs index 4105071c0..5f0af71da 100644 --- a/rust-zerotier-service/src/vnp/mod.rs +++ b/rust-zerotier-service/src/vnp/mod.rs @@ -6,7 +6,7 @@ mod mac_feth_tap; pub trait Port { fn set_enabled(&self, enabled: bool); fn is_enabled(&self, ) -> bool; - fn set_ips(&self, zerotier_core::InetAddress: &ip); + fn set_ips(&self, ip: &zerotier_core::InetAddress); fn ips(&self) -> Vec; fn device_name(&self) -> String; fn routing_device_name(&self) -> String;