mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-26 17:03:43 +02:00
Rust builds again, and doing Mac tap in rust.
This commit is contained in:
parent
29fa689f0b
commit
01a98a7f69
20 changed files with 205 additions and 75 deletions
2
Makefile
2
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
#ifdef __APPLE__
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -33,4 +25,10 @@
|
|||
#include <netinet6/in6_var.h>
|
||||
#include <netinet6/nd6.h>
|
||||
#include <ifaddrs.h>
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
4
rust-zerotier-service/Cargo.lock
generated
4
rust-zerotier-service/Cargo.lock
generated
|
@ -1380,7 +1380,9 @@ dependencies = [
|
|||
"clap",
|
||||
"futures",
|
||||
"hex",
|
||||
"libc",
|
||||
"lazy_static",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"num_cpus",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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<FastUDPRawOsSocket,
|
|||
let sa_len;
|
||||
match address.family() {
|
||||
InetAddressFamily::IPv4 => {
|
||||
af = libc::AF_INET;
|
||||
sa_len = std::mem::size_of::<libc::sockaddr_in>() as libc::socklen_t;
|
||||
af = osdep::AF_INET;
|
||||
sa_len = std::mem::size_of::<osdep::sockaddr_in>() as osdep::socklen_t;
|
||||
},
|
||||
InetAddressFamily::IPv6 => {
|
||||
af = libc::AF_INET6;
|
||||
sa_len = std::mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t;
|
||||
af = osdep::AF_INET6;
|
||||
sa_len = std::mem::size_of::<osdep::sockaddr_in6>() 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::<libc::c_int>() as libc::socklen_t;
|
||||
let mut setsockopt_results: libc::c_int = 0;
|
||||
let mut fl: c_int;
|
||||
let fl_size = std::mem::size_of::<c_int>() as osdep::socklen_t;
|
||||
let mut setsockopt_results: c_int = 0;
|
||||
|
||||
// Set options that must succeed: reuse port for multithreading, enable broadcast, disable SIGPIPE, and
|
||||
// for IPv6 sockets disable receipt of IPv4 packets.
|
||||
fl = 1;
|
||||
setsockopt_results |= 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<H: FastUDPSocketPacketHandler + Send + Sync + 'static>
|
|||
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::<InetAddress>() 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::<InetAddress>() 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::<libc::c_int>() 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::<InetAddress>() 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::<c_int>() 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::<InetAddress>() 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::<libc::c_int>() 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::<c_int>() 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::<InetAddress>() 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::<InetAddress>() 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<H: FastUDPSocketPacketHandler + Send + Sync + 'static> 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::<InetAddress>() as libc::socklen_t);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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() {
|
||||
|
|
|
@ -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<F: FnMut(PhysicalLink)>(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::<u8>(), (&mut a as *mut InetAddress).cast::<u8>(), size_of::<libc::sockaddr_in>());
|
||||
} else if (*(*i).ifa_addr).sa_family == libc::AF_INET6 as u8 {
|
||||
copy_nonoverlapping((*i).ifa_addr.cast::<u8>(), (&mut a as *mut InetAddress).cast::<u8>(), size_of::<libc::sockaddr_in6>());
|
||||
if (*(*i).ifa_addr).sa_family == osdep::AF_INET as u8 {
|
||||
copy_nonoverlapping((*i).ifa_addr.cast::<u8>(), (&mut a as *mut InetAddress).cast::<u8>(), size_of::<osdep::sockaddr_in>());
|
||||
} else if (*(*i).ifa_addr).sa_family == osdep::AF_INET6 as u8 {
|
||||
copy_nonoverlapping((*i).ifa_addr.cast::<u8>(), (&mut a as *mut InetAddress).cast::<u8>(), size_of::<osdep::sockaddr_in6>());
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
@ -46,7 +47,7 @@ impl PhysicalLink {
|
|||
}
|
||||
i = (*i).ifa_next;
|
||||
}
|
||||
libc::freeifaddrs(ifap.cast());
|
||||
osdep::freeifaddrs(ifap.cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Option<JoinHandle<()>>>,
|
||||
}
|
||||
|
||||
// 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<i32> = 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<F: Fn(&[u8]) + Send + Sync + 'static>(nwid: &NetworkId, eth_frame_func: F) -> Result<MacFethTap, String> {
|
||||
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::<osdep::bpf_hdr>() 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::<osdep::bpf_hdr>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<zerotier_core::InetAddress>;
|
||||
fn device_name(&self) -> String;
|
||||
fn routing_device_name(&self) -> String;
|
||||
|
|
Loading…
Add table
Reference in a new issue